-
-
Notifications
You must be signed in to change notification settings - Fork 317
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
Scene magic #10
Comments
Well the reason why I call it magic is that the way this seems to work with global objects doesn't seem like a convenience layer on first glance. e.g. in Plots i can be explicit about what I am referring to If feasible it would be nice if the global object stuff would be optional and a user can be very explicit when to do what with which scene. Or is this already possible? |
I agree here. I would like a way to avoid globals when possible, simply because it is required to make things like multithreading work. |
👍
I think it's fine if scene1 = Scene()
scene2 = Scene() Then I'd end up with 2 scene windows. Also given that |
oh, hah, just realized that |
No, but |
How about this: root = plot() # returns rootscene
# root contains a theme, from which all defaults get feeded
# root also contains all window signals
root = plot(root, rand(10), thickness = 1mm) # creates a new node, getting attached to root
root = plot(rand(10), thickness = 1mm) # equal to the above, since root will just be inserted
# -root
# -p1
# adds a new node to p1
p1 = plot!(p1, rand(10)) # takes defaults from kw_args and if not in there from root.theme
# root
# p1
# p2
root = plot!(root, rand(10), p1, color = :red) # takes defaults from kw_args, then p1, then root.theme
# root
# p1
# p2
# p3
# convenient way to access subplots
root[1] == p1
p1[1] == p2 && p2 == root[1][1]
root[2] == p3
hcombined = plot(root...) # equals to plot(root[1], root[2]) # equals to plot(p1, p3)
# hcombined
# subplot1
# p1
# P2
# subplot2
# p3
#=
┏━━━━━━━┳━━━━━┓
┃ p1 p2 ┃ p3 ┃
┗━━━━━━━┻━━━━━┛
=#
hcombined == hbox(root...) # horizontal concat layout
vcombined = vbox(root...) # vertical concat layout
p2 = pop!(root[1]) # delete the last plot from (root[1] == p1)
layouted = vbox(hbox(root[1], p2), root[2]) # vertical + horizontal layout combined
# pcombined
# subplot1 vertical
# subplot 2 horizontal
# p1
# subplot 3 horizontal
# p2
# subplot2 vertical
# p3
#=
┏━━━━┳━━━━┓
┃ p1 ┃ p2 ┃
┣━━━━┻━━━━┫
┃ p3 ┃
┗━━━━━━━━━┛
=#
p1 = root[1]
p3 = root[2]
layouted_axis = vbox(hbox(p1, plot(p2, axis = p2[:axis]), p3)) # vertical + horizontal layout combined
#=
┏━━━━┳━━━━┓
┃ p1 ┃ p2 ┃ # p1, p2 share the same axis object
┣━━━━┻━━━━┫
┃ p3 ┃
┗━━━━━━━━━┛
=#
# the above will all be backend independent!
display(layouted) # create the actual plot + window for the preferred + backend / display combo
disp = gl_display(resolution = ...) # explicitely chose a gl backend for display
display(disp, layouted)
display(layouted) # will use disp, the last created display |
This is interesting, but I am not sure you want to commit to an hcat vs vcat style for layouts because it seems like it would get confusing when you have that last kind of "two on top, on bottom", or going even further what about one in the middle, a long one on the right and left, and open space on top and bottom? And then changing sizes? Some long some thing? For example, what would these look like? http://docs.juliaplots.org/latest/layouts/#advanced-layouts It would be nice to have something easier for specifying such layouts, and the internal array that is used to hold the subplots seems like it could get quite messy trying to hold all of this information. Plots.jl's macro does this quite well and I hope we don't lose that. |
I see... vbox(hbox(p1, box(p2, height = 0.5rel)), box(p3, Rect(6mm, 5mm, 10mm, 15mm)) Well, that is just an idea. I used it in WebIO, which is inspired a bit by html I think, and I immediately liked it. Anyways, this is all surface syntax, so we might as well have both, or decide which one to drop ;) |
Hm, tiling a given square with (sub-)grids with absolute and relative guides and cell-joins is such an universal task that it should be it's own package. That also immediately enforces a modular design. |
I was thinking of css, I did not mention it because some people have mixed feelings ;-) |
Anyways, the layouting wasn't supposed to be the controversial part ;) I was rather trying to make sure that everyone is on board with the way to separate plots/display and creating the hierarchy. Although I can see how that would be less controversial, since it's pretty much what Plots.jl currently does. |
FWIW I like the Maybe I'm being dense, but I'm having a hard time following your first few examples of the You have: root = plot() # returns rootscene does r1 = plot()
r2 = plot() do then: root = plot(root, rand(10), thickness = 1mm) # creates a new node, getting attached to root
root = plot(rand(10), thickness = 1mm) # equal to the above, since root will just be inserted
# -root
# -p1 does when nesting plots: # adds a new node to p1
p1 = plot!(p1, rand(10)) # takes defaults from kw_args and if not in there from root.theme
# root
# p1
# p2 what does it mean for a plot to be nested inside another plot? I'm also a little unclear on what the difference between |
Yes! I want one root object, that contains infos like the theme etc.
This still points to the one root and creates a new plot object p1 attached to root. For displaying what the user expects, I thought it will make sense to always return the parent,.
This is supposed to be like in a scene graph. So e.g. the child will inherit translations/scales from the parent. I wanted to inherit all attributes here, but I realized that it will make it hard to opt out. So for inheriting attributes like color I want another signature. |
I see how that's confusing. I'm violating the conventions with returning the same root. |
Is there any way around the globals? I would propose something more like: s1 = Scene() # creates a scene with default theme
s2 = Scene(thickness=1mm) # creates a different scene with a new theme overriding the thickness
ax = axis(...) # assume this has some linspaces in it
push!(s1, ax)
push!(ax, lines(rand(10)) # adds a plot to the scene, as a child of the axis
push!(s2, lines(rand(10)) # add some lines with no axis
display(s1) # actually show the scene
display(s2) # show the other scene
display(s1) # show the first scene again This is obviously pretty verbose, so the p1 = plot(rand(10))
# equivalent to:
p1 = begin
s = Scene()
ax = axis(...) # compute axis from data
push!(s, ax)
push!(ax, line(rand(10))
s
end
# then you could add another line to the scene (probably with the same axis?) with:
plot!(p1, rand(10)) |
would those all open a new window? |
good question, I'm not sure. I think it would be nice to support multiple simultaneous windows, but it also seems reasonable for it to only support 1 scene at a time, so the first That way the only global state would be some reference to the currently-displayed scene (which would be loaded in the GPU, and handle input signals) |
If we want to support plots on multiple monitors from the same julia process, we would need a way to have multiple windows running simultaneously. I think pairing one (or more) scenes with a display object (which corresponds to a window) would make sense. However, the above three calls could still display both scenes on the same window, but could accept a separate argument if you want to plot a scene to the non-current window. |
I was also thinking recently that it might be weird or difficult to implement displaying the same scene in multiple windows simultaneously, so it seems very reasonable for the 1st and 3rd I think even if initially Makie only supports 1 window, it would be nice if the API would in principle support multiple windows and scenes. |
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Anshul Singhvi <[email protected]>
As @Evizero pointed out in JuliaPlots/Plots.jl#392:
I agree with that and I meant to discuss the magic we actually want here ;)
I have a few ideas and problems which I wanted to write down.
Scene()
open a new window? I'm thinking about having it create a new tab as wellscatter(name = :myname); scatter(name = :myname)
overwrite the first plot, while without having the same name they would get added with a unique default name (:scatter1, :scatter2, ...). I'm not sure if that isn't too quirky, and if that shouldn't mean thatScene()
without a new unique name shouldn't create a completely new scene! But I also want an easy way to replace a scene that is meant to take the same place. I could even reuse the GPU objects in that case, making the example even more efficient.The text was updated successfully, but these errors were encountered: