Julia: How to save a figure without plotting/displaying it in PyPlot? - matplotlib

I am using the PyPlot package in Julia to generate and save several figures. My current approach is to display the figure and then save it using savefig.
using PyPlot
a = rand(50,40)
imshow(a)
savefig("a.png")
Is there a way to save the figure without having to first display it?

Are you using the REPL or IJulia?
If you close the figure then it won't show you the plot. Is that what you want?
a = rand(50,40)
ioff() #turns off interactive plotting
fig = figure()
imshow(a)
close(fig)
If that doesn't work you might need to turn off interactive plotting using ioff() or change the matplotlib backend (pygui(:Agg)) (see here: Calling pylab.savefig without display in ipython)
Remember that most questions about plotting using PyPlot can be worked out by reading answers from the python community. And also using the docs at https://github.com/JuliaPy/PyPlot.jl to translate between the two :)

close() doesn't require any arguments so you can just call close() after saving the figure and create a new figure
using PyPlot
a = rand(50,40)
imshow(a)
savefig("a.png")
# call close
close()

Related

How to plot julia inline when using Jupyter in vscode?

I am trying to use Jupyter for Julia in vscode:
using PyPlot
a = [1,2]
b = [2,3]
fig=figure(1)
PyPlot.plot(a, b, linewidth=1)
PyPlot.scatter(a, b)
show()
When I run this a new window will pop up. What I want to do is to prevent it to pop up and see the picture below my codes. After doing some search it seems in Python you can solve it by %matplotlib inline, but how do I sovle it in Julia?
Try gcf() instead of show.
gcf yields the current PyPlot Figure object and it will be automatically rendered by Jupyter:

save pyplot figure "as figure" (not as image)

How can I save a figure using PyPlot in Julia, so that the figure can be reloaded as a figure later in Julia? (not as an image)
You can use serialize to store any Julia object. This beautifully works for plots as well.
Let us start by generating a plot:
using Plots
pyplot()
p = plot(rand(10));
using Serialization
Serialization.serialize("myfile.jld", p);
Note that you need a semicolon after plot command so it does not appear on the screen.
Let us now read the plot (to have a full test I ended the previous Julia session and started a new one):
using Plots
pyplot();
using Serialization
p2 = Serialization.deserialize("myfile.jld");
In order to display it now it is enough to type in REPL:
julia> p2
You might want also want to use plain PyPlot (I strongly recommend Plots for flexibility). In that case your best bet is to follow rules described in object-oriented API of Matplotlib:
using PyPlot
ioff()
fig = subplot()
fig.plot(rand(10))
fig.set_title("Hello world")
using Serialization
serialize("pp.jld", fig)
In order to plot de-serialize back the object:
using PyPlot
ioff()
using Serialization
fig = deserialize("pp.jld")
show()
Finally, note that the serialization is good only for short term storage. If anything changes (e.g. you update Julia packages) you might not be able to de-serialize the plot.
Hence another good alternative for processable plots are saving them to LaTeX or SVG format - both is possible in Julia.

Accessing backend specific functionality with Julia Plots

Plots is simple and powerful but sometimes I would like to have a little bit more control over individual elements of the plot to fine-tune its appearance.
Is it possible to update the plot object of the backend directly?
E.g., for the default pyplot backend, I tried
using Plots
p = plot(sin)
p.o[:axes][1][:xaxis][:set_ticks_position]("top")
but the plot does not change. Calling p.o[:show]() afterwards does not help, either.
In other words: Is there a way to use the PyPlot interface for a plot that was initially created with Plots?
Edit:
The changes to the PyPlot object become visible (also in the gui) when saving the figure:
using Plots
using PyPlot
p = Plots.plot(sin, top_margin=1cm)
gui() # not needed when using the REPL
gca()[:xaxis][:set_ticks_position]("top")
PyPlot.savefig("test.png")
Here, I used p.o[:axes][1] == gca(). One has to set top_margin=1cm because the plot area is not adjusted automatically (for my actual fine-tuning, this doesn't matter).
This also works for subsequent updates as long as only the PyPlot interface is used. E.g., after the following commands, the plot will have a red right border in addition to labels at the top:
gca()[:spines]["right"][:set_color]("red")
PyPlot.savefig("test.png")
However, when a Plots command like plot!(xlabel="foo") is used, all previous changes made with PyPlot are overwritten (which is not suprising).
The remaining question is how to update the gui interactively without having to call PyPlot.savefig explicitly.
No - the plot is a Plots object, not a PyPlot object. In your specific example you can do plot(sin, xmirror = true).
I'm trying to do the same but didn't find a solution to update an existing plot. But here is a partial answer: you can query information from the PyPlot axes object
julia> Plots.plot(sin, 1:4)
julia> Plots.PyPlot.plt[:xlim]()
(1.0,4.0)
julia> Plots.plot(sin, 20:24)
julia> ax = Plots.PyPlot.plt[:xlim]()
(20.0,24.0)
and it gets updated.

Add Compose context to pyplot axis or figure in julia

I have two different visualizations: a big plot (as PyPlot figure) and a worldmap (Compose context). Is there any possibility to combine those? (out of julia, without exporting both and then fiddling with some software).
I would like to do something like:
import PyPlot
using Compose
(fig, ax) = PyPlot.subplots(2,1)
ax[1][:plot]([1,2,3],[1,2,3])
composition = compose(compose(context(), circle()), fill("tomato"))
### magic command to add composition to ax[2]
In case there is no way to do it like this I will be greatefull for any other suggestions.
Thanks in advance!

Logarithmic scaling / colorbar in Julia using PyPlot (matplotlib)

I am using Julia 0.5 and the latest version of PyPlot.
I am printing an 2D-Array using plot.pcolorand it works pretty good. But now I have data that needs a logarithmic scaling. I searched on the web and what I found was an example using
plt.pcolor(X, Y, Z1, norm=LogNorm(vmin=Z1.min(), vmax=Z1.max()), cmap='PuBu_r')
But since LogNorm seems to be a python function ist doesn't work in Julia. Does anyone have an idea what I can hand over to norm=to get a logarithmic scaling?
An example would be:
using PyPlot
A = rand(20,20)
figure()
PyPlot.pcolor(A, cmap="PuBu_r")
colorbar()
Matplotlib fields and methods can be accessed using the
matplotlib[:colors][:LogNorm]
syntax (i.e. for the corresponding matplotlib.colors.LogNorm object).
UPDATE: Thank you for your mwe. Based on that example, I managed to make it work like this:
PyPlot.pcolor(A, norm=matplotlib[:colors][:LogNorm](vmin=minimum(A), vmax=maximum(A)), cmap="PuBu_r")