-
-
Notifications
You must be signed in to change notification settings - Fork 306
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement polar axis #2014
Implement polar axis #2014
Conversation
Compile Times benchmarkNote, that these numbers may fluctuate on the CI servers, so take them with a grain of salt. using time
This PR does not change the using time. ttfp time
This PR does not change the ttfp time. |
Haven't had a lot of time to look at it yet unfortunately, but I'm wondering how best to handle integration with existing methods that modify |
e0d0843
to
4f853e7
Compare
The theme should be mostly set, grids exist but ticks need to be plotted.
3bb0656
to
227b0b5
Compare
This reduces the amount of attribute expansions in the main code.
src/makielayout/blocks/polaraxis.jl
Outdated
function project_to_pixelspace(scene, points::AbstractVector{Point{N, T}}) where {N, T} | ||
to_ndim.( | ||
Ref(eltype(points)), | ||
Makie.project.( | ||
# obtain the camera of the Scene which will project to its screenspace | ||
Ref(Makie.camera(scene)), | ||
# go from dataspace (transformation applied to inputspace) to pixelspace | ||
Ref(:data), Ref(:pixel), | ||
# apply the transform to go from inputspace to dataspace | ||
Makie.apply_transform( | ||
scene.transformation.transform_func[], | ||
points | ||
) | ||
), | ||
Ref(0.0) | ||
) | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if it makes much of a difference but I think (val,)
is preferable over Ref(val)
in these cases because it doesn't allocate.
Also project(scene, apply_transform(f, point))
(or the lower level variants) should be used here and above. The variants that specify input and output space have some extra branching and matrix multiplications in them
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should really be a map(points) do p
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a difference between that and what's done here, aside from code cleanliness? Basically, I didn't want to call camera
and apply_transform
in an inner loop so did this instead.
Also, AFAIK since the transform_func is an Observable{Any}, having apply_transform in an inner loop takes a lot of time compared to having it outside.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
having apply_transform in an inner loop
You currently already do apply_transform(f, points)
, no? So it might as well already live outside the map/broadcast.
Also, I think symbols, types and numbers don't need a Ref
, since they're already treated as scalar by broadcast.
I'd also prefer convert(Vector{Point{N, T}}, ...)
since it's less complex, has a clearly defined return type and also doesn't copy if project already returns the correct type.
src/makielayout/blocks/polaraxis.jl
Outdated
function text_bbox(textstring::AbstractString, textsize::Union{AbstractVector, Number}, font, align, rotation, justification, lineheight, word_wrap_width = -1) | ||
glyph_collection = Makie.layout_text( | ||
textstring, textsize, | ||
font, align, rotation, justification, lineheight, | ||
RGBAf(0,0,0,0), RGBAf(0,0,0,0), 0f0, word_wrap_width | ||
) | ||
|
||
return Rect2f(Makie.boundingbox(glyph_collection, Point3f(0), Makie.to_rotation(rotation))) | ||
end | ||
|
||
function text_bbox(plot::Text) | ||
return text_bbox( | ||
plot.text[], | ||
plot.textsize[], | ||
plot.font[], | ||
plot.align[], | ||
plot.rotation[], | ||
plot.justification[], | ||
plot.lineheight[], | ||
RGBAf(0,0,0,0), RGBAf(0,0,0,0), 0f0, | ||
plot.word_wrap_width[] | ||
) | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's probably better to plot text first, and then use normal bounding boxes to update things. Otherwise changes and optimizations there might get left behind here. (I think right now it's more or less the same amount of work. plot first just needs to guard against infinite loops.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll definitely look further into the structure of text then. I was under the impression that everything got squashed into one GlyphCollection but could definitely be wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, if the GlyphCollection changes when position changes, then it's harder to lift off it, since I only care about the text extents of each segment - not their positions (at least for now). If we want a 100% tight bbox then it can be tried, but I would definitely like to do that later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, you're doing bboxes per string in a vector with that. If you're doing boundbox(p)
they'll get combined, but the glyph collections should be available per string.
GlyphCollection changes when position changes
glyph collections shouldn't trigger on plot.position
anymore. If they are we should clean that up, because there is no reason to mix them until the final rendering code.
Thanks for the detailed review @ffreyer! I'll probably have that last comment wrapped up tomorrow or so. It seems like the bounding boxes can be obtained by: ttp = (po::PolarAxis).blockscene.plots[end-2]
Makie.boundingbox(ttp.plots[1].plots[1][1][][1], Makie.to_rotation(ttp.plots[1].plots[1].rotation[])) although this is pretty fragile. The bboxes do seem to be independent of position, though. @adigitoleo, about your comment - now that theming is hooked up, I will create some setters for e.g. |
I'm not the biggest fan of |
Any recent update regarding this PR? This is the only recipe that is missing in order to migrate all my plots to Makie.jl |
Kind of lost track on this, if you've tested it are there any issues with it currently @juliohm? (beyond those already mentioned) |
Is this PR still alive? I would love to have polar axes in Makie... |
ah, I guess this kind of lost steam for a bit. I'll have to take a look at the code again. |
What needs to happen to get this PR moving? Unit tests and docs? |
They're just tricky to implement correctly given specific rendering requirements they have. For example, non-rectangular clipping masks, transformation-dependent rendering of primitives, handling of arbitrary axis types in certain code paths and more. |
+1 for this. Currently needing polar axes and using TikZ. Would be nice to use Makie. |
I've been playing around with this pr a bit, so I have some more thoughts: I agree with Julius that I'm wondering if it would be better to move grid lines and text to the transform aware scene. That would get rid off all the manual projections. For grid lines that should be no problem, but for text it might be a bit difficult to figure out the correct positioning. Though I think it's possible to derive the needed things from character boundingboxes (which should be mostly static), the scene area and limits. Note that you can (up to maybe unavoidable equal length problems) also specify text alignment freely as a vector: θtick_align[] = map(θtickpos) do p
s, c = sincos(p[2])
Point2f(0.5 - 0.5c, 0.5 - 0.5s)
end
...
text!(..., align = θtick_align) How should zooming work for this? Should translating work? I guess like |
Well you could potentially have a circle segment between some theta and some r.
We could go |
Just to provide a point of comparison, not necessarily saying we need to do the same, but matplotlib seems to only support zooming the way you suggest, with a static circular axis. See these docs and this screen capture: polar_mpl.mp4 |
Still need to implement tight tick spacing but I think it'll work.
Also figured out why this wasn't working. The alignment is pretty clean now, though the padding is still hard coded. Here's a screenshot with awkward tick steps and debug colors for clipping: I can push my changes here, but I changed quite a lot so maybe I should just start a continuation pr instead? Otherwise it might get hard/confusing to work with this one if my approach doesn't work/isn't good.
Yea I think that's probably the default we should go for too. |
Merged in #2990 |
Description
This PR implements a
PolarAxis
layoutable which should be able to serve as a template for a more generalNonlinearAxis
layoutable.polar_rotation_1.mp4
To-dos
plot!(po, ...)
MakieLayout.can_be_current_axis(::PolarAxis) = true
Type of change
Delete options that do not apply:
Checklist
Fixes #309, #521