I would actually like to change that. The core of Interact (Widgets + Observables) is independent of web things and I hope could serve as a general basis.
Thanks for good reporting. I’m a simple Julia user, and have tried to understand the Plots syntax. I’m interested in Makie, but don’t have a clear idea of its role:
- Is Makie a replacement of Plots as a meta plotting package? In other words: will Makie need backends like Plots does?
- Is the plan to make Plots statements workable for Makie (
plot()
,plot!()
,linewidth=…
,xlabel=()
, etc.), or should one just as well get used to Makie commands? - Is there/will there be support for LaTeX style commands for specifying math typography?
I really appreciate your hard work! Good/fast graphics is essential for Julia’s success!
-
Makie can have backends - so if you read my post above you see that a GR backend was implemented at vizcon. But the relationship to them is different - the backends just handle the drawing, and Makie is thus not a meta-package as such, it’s fully standalone.
-
I think it’s safe to say now that the syntax will stay somewhat different from that of Plots. But it’s fairly similar.
-
I’d be surprised if not but don’t know.
One thing that I like about Matlab’s graphics, and which I could never quite figure out in Plots.jl, is that you can easily get access to the various plot objects (lines, axes, text, figures, legends, etc. etc.), and then manipulate them directly. This is extremely convenient, and lets me pass off, e.g. a line object, to some function that can update it whenever, without caring about which figure it belongs to or anything else.
In Plots.jl the only way of interfacing with graphics elements, that I could find, was through the entire plot object, which remains quite opaque to me. For example, mutating the linestyle or getting/changing the data of one single line among many, after having plotted it, was something I failed at. Or retrieving a handle to, say, “the red, dotted, line” in some axis, which you can accomplish with findobj
in Matlab.
Whenever I tried to explore the ‘plot object’ in Plots.jl I got nowhere, unable to find the lines and tick marks or colorbar, etc.
Did I miss something big (I never did get very familiar with Plots.jl)? And do you think that a future design will include graphics objects, similar to Matlab or Matlplotlib?
My uneducated guess why this is hard, is that Plots.jl is, as has been mentioned, a meta-package, and has to interface with a lot of different backends, which again own the actual plot objects. I can see how that makes it difficult, or even nearly impossible to expose very fine grained control over individual graphics elements.
But is this something that is likely to be different in a future Plots.jl/Makie.jl high-level package, or is the functionality I’m looking for rather something that can only be accessible by directly working with a lower-level, backend package?
Possibly the latter, but what is it that you want to accomplish? I don’t use Matlab, but an example would be useful.
My understanding is that the issue is between two different approaches of making plots in practice. Say I get the plot somewhat right, but I still want to tweak it a bit more: in a cartoon example I do plot(x, y, color = :blue)
but I actually wanted it to be red. I could either
- Edit my plot function call and try again (Plots approach)
- Edit the plot object directly (possible in Matlab, less so in Plots)
It’s a bit of a preference of style, with some performance considerations: if the plot also computed some heavy statistics I do not want to recompute them just to tune the colorscheme.
I think here there’s a different design philosophy between Matlab, Plots and Makie (I haven’t used Matlab in a while, but I think it’s really 3 distinct approaches).
In Plots you can mutate some things after the plot is done (say xlabel!
or things like that) but it’s not supported in general. The reason (at least my understanding of it) is that there is a rather sophisticated pipeline that consumes all attributes and deduces some attributes from the initial ones. So if I were to change p[1][1][:seriescolor]
after the plot is done, this wouldn’t really have an effect, because for example the overall seriescolor only affects the line as :linecolor
defaults to it, so there actually is no way to know how the plot would change without re-running the pipeline. This precludes approach 2) for making plots and makes creating animations less smooth as we need to rerun the pipeline for every frame. This was one of the major design difference that justified the Makie project.
Makie is quite different in that there is in some sense a “pipeline” (less complex than in Plots), in that some things may depend on others, but it is done via Observables
and reactive programming so that the plot knows how to update if one attribute is changed.
For example if I do:
julia> p = Makie.scatter(rand(10), rand(10))
Now p
is a scene whose last plot is the scatter, so:
julia> p[end]
Scatter{...}
attributes:
colormap : Symbol
visible : Bool
scatter : Attributes
axis : Attributes
text : Attributes
axis2d : Attributes
linesegments : Attributes
camera : AbstractPlotting.Automatic
cam2d : Attributes
font : String
axis_type : AbstractPlotting.Automatic
annotations : Attributes
raw : Bool
clear : Bool
legend : Attributes
resolution : Tuple{Int64,Int64}
center : Bool
color : Symbol
show_legend : Bool
padding : Vec{3,Float32}
backgroundcolor : RGBA{Float32}
show_axis : Bool
scale_plot : Bool
limits : AbstractPlotting.Automatic
and now I’m free to edit these attributes at will:
julia> p[end].color
Observable{Any} with 1 listeners. Value:
:black
julia> p[end].color = :red
:red
And the plot will update without the need to be redrawn. An extra advantage is that the framework for updating things in real time that’s used here (Obsevables
) is the same as in Interact, so it’s in principle quite easy to get these updates from Interact
widgets. I could actually set the color to be a colorpicker
from Interact and the plot would update smoothly without being redrawn as soon as the user interacts with the color wheel.
I believe this was exactly one of the points of critique of Plots that Simon wanted to address with designing Makie.
Note that some of the “attributes” of the scatter plot are of type Attributes
(basically a dict of updating signals, technically Dict{Symbol, Observable}
). This means that there is a nested structure of attributes, so for everything regarding the axis, I would look into the axis
attributes and see which of those need to be changed.
Thanks for this very informative reply.
It actually sounds like Makie provides basically the sort of functionality I’m interested in. It sounds like it would be possible to just take p[i]
and pass it off to some function to manipulate.
I’m encouraged to hear that these concerns are a part of the design process. The reason I asked was that, despite browsing quite a few plotting discussions, I haven’t seen it brought up before. I haven’t even seen anyone asking about it on Discourse or stackoverflow, (though, naturally, I have missed a lot.)
Partly, it’s about performance. I’d like to avoid a lot of drawing being redone when changing very specific things in a complex plot.
But more fundamentally, it’s about separation of concerns (I think it’s called). It’s very convenient to be able to take a reference to a line, send it to some process, and just let it modify very specific properties, without it having to know anything about the rest of the plot.
As an example, I have a gui, where a user manipulates some parameter. Then some function would take that parameter value and the line reference and update the line’s data. All the other plot elements are then just a distraction, and makes the functionality of the ‘updater function’ less generic. In fact, this could be more generic, if I didn’t have to send a ‘line object’ at all. Ideally, I’d just send an array to be mutated, and that would be translated into a plotting update, if appropriate.
See the Makie docs - http://makie.juliaplots.org/stable/why-makie.html Some of that is out-of-date (e.g. we don’t have world age issues anymore) but I think it documents the thought process
Thanks. But, aren’t the Makie docs here http://makie.juliaplots.org/stable/ ?
Yes they were just offline when I went there - came back to fix the link.
Possibly I am missing something about the contexts, but in modern graphical frameworks,
- the rendering of a (static) plot on screen is usually the cheapest operation,
- it happens anyway for the whole plot when elements are changed (eg if I make the axes blue, it won’t just re-render those specific pixels).
I would usually do this by breaking up the code that generates the plot into smaller functions, with each doing one thing, and just (re)generate variants of a plot from various building blocks.
I guess this depends on the framework (or what counts as ‘modern’). In Matlab, at least, issuing a whole new plot
command is dramatically more expensive than
myline.YData(5) = 11
and makes the difference between a smooth live-update, and a slow mess.
I’m not sure if I understand this. But, I’m thinking of a situation where a plot has been produced by whatever complicated (or even unknown) process, and I want to let some other process update some arbitrary element. Having to use the original code seems quite limiting.
Oh, and the ‘other process’ should also be able to update whichever element I throw at it. Sometimes I give it the blue line to update, another time, the red line.
That’s exactly the principle behind Observables. You can do the same thing with the values that correspond to GUI controls. For example, suppose an “entry box” is linked to an Observable; any time you type something into the box and hit enter, it modifies the value stored in the Observable, which then notifies downstream consumers that only make use of the Observable and don’t have to know the details of the GUI toolkit.
One example is saving plots on disk in Matlab and reloading them later on. You can even have plots that colleagues sent you. Then if you want to standardise the font you can easily do it with a few lines of code. Of course it’s better to have a nice script that can generate the plot from scratch but in practice it’s not always the case.
This is already the case with Makie, i.e. you can do:
v = Observable(rand(100))
scatter(v)
and the plot will update when the observable updates. One of the challenges of the design that is being worked on in these days is how to allow the user to create recipes without worrying about Observables, so that this automated efficient updating also works in user recipes.
This is definitely an interesting point but we’d need a way to save the plot that “preserves the structure” in Makie. Naively trying to save the plot with JLD2 crashed my Julia session but maybe there are fixes.
Naively trying to save the plot with JLD2 crashed my Julia session but maybe there are fixes.
That’s of course a feature
Joke aside, I already pushed a fix to serialize a Makie scene to disc via Serializer.(de)serialize
- which works quite nicely, even for GUIs and interactions!
A fix for JLD2 shouldn’t be too hard (was it supporting closures though? Sadly, there are quite a few places where closures become part of the scene graph so we’d need to serialize them).