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!
Related
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.
The method plt.hist() in pyplot has a way to create a 'step-like' plot style when calling
plt.hist(data, histtype='step')
but the 'ordinary' methods that plot raw data without processing (plt.plot(), plt.scatter(), etc.) apparently do not have style options to obtain the same result. My goal is to plot a given set of points using that style, without making histogram of these points.
Is that achievable with standard library methods for plotting a given 2-D set of points?
I also think that there is at least one hack (generating a fake distribution which would have histogram equal to our data) and a 'low-level' solution to draw each segment manually, but none of these ways seems favorable.
Maybe you are looking for drawstyle="steps".
import numpy as np; np.random.seed(42)
import matplotlib.pyplot as plt
data = np.cumsum(np.random.randn(10))
plt.plot(data, drawstyle="steps")
plt.show()
Note that this is slightly different from histograms, because the lines do not go to zero at the ends.
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.
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")
Working in IJulia. Desperately trying to make a custom colormap.
Tried the line:
matplotlib.colors.ListedColormap([(1,0,0),(0,1,0),(0,0,1)],"A")
which resulted in the following error
type PyObject has no field colors while loading In[16], in expression starting on line 1
which apparently means that I cannot use matplotlib directly, but only the functions which are in PyPlot.
I cannot involve matplotlib with an import (as this is invalid in IJulia).
I have noted that others have had help on similar problems, but that doesn't solve mine.
By using the PyCall package which PyPlot is using to wrap matplotlib you can obtain a colormap like this:
using PyCall
#pyimport matplotlib.colors as matcolors
cmap = matcolors.ListedColormap([(1,0,0),(0,1,0),(0,0,1)],"A")
In order to access fields in a PyObject you need to index the object with a symbol like:
cmap[:set_over]((0,0,0))
This is equivalent to: cmap.set_over((0,0,0)) in python. For other good examples of how to plot different kinds of plots using PyPlot, see these examples: https://gist.github.com/gizmaa/7214002
You don't need to use PyCall to call Python directly (although this is, of course, an option). You can also just use the PyPlot constructors for ColorMap to construct a colormap from (r,g,b) arrays or an array of colors as defined in the Julia Color package. See the PyPlot ColorMap documentation. For example:
using PyPlot, Color
ColorMap("A", [RGB(1,0,0),RGB(0,1,0),RGB(0,0,1)])