PathPatch object in julia with PyPlot - matplotlib

I was trying to reproduce this example from the matplotlib website using the PyPlot package for Julia. As far as I know, the PyPlot is essentialy the matplotlib.pyplot module, so I imported the other modules of matplotlib that I needed (with the #pyimport macro):
using PyCall
#pyimport matplotlib.path as mpath
#pyimport matplotlib.patches as mpatches
Then I proceed to define the path object:
Path = mpath.Path
but then I get:
fn (generic function with 1 method) .
As if I had defined a function. Moreover, when I assign the path_data I get the following error:
ERROR: type Function has no field MOVETO
Of course, that's due to Path, which Julia tries as a function and not as a type or something like that. As you might guess the same happens when I try to define the variable patch .
So, there are incompatibilities of modules from matplotlib different to pyplot for Julia since the expected objects (types) are taken as functions. This behaviour can be expected if it were different the PyPlot.jl file wouldn't be needed.
My questions are:
-Am I doing something wrong?
-Is there a simple way to make it works?
-Do you know another package for Julia in which I can define patches and work in a similar way to matplotlib?
I have in mind to do this kind of animations.
Thanks for your ideas.

You need to get the "raw" Python object for Path. By default, PyCall converts Python type objects into functions (which call the corresponding constructor), but then you cannot access static members of the class.
Instead, do e.g. Path = mpath.pymember("Path") to get the "raw" PyObject, and then you can do Path["MOVETO"] or Path[:MOVETO] to access the MOVETO member.
(This difficulty will hopefully go away in Julia 0.4 once something like https://github.com/JuliaLang/julia/pull/8008 gets merged (so that we can make PyObjects callable directly.)

Related

What wizardry is being used to display Matplotlib color maps in an ipython console?

I am working with Matplotlib color maps, and I also happen to be working with the Spyder IDE, which has an ipython console.
As you can see from the screen shot, the ipython console showed me a graphical representation of the color map object. This was unexpected and very helpful.
Normally I expect to see a string representation of an object, as you might see from the print() function call. Function calls to print() and repr() are shown, and they produce text, as is more typical.
I would like my own code to output this graphical representation when it is generating output. I have been poking through the matplotlib.colors.Colormap internals, and so far I haven't been able to figure out how. What is ipython doing? How can I do the same?
Thanks!
This rather seems like a ipython/jupyter feature. ipython detects the object and produces automatically a plot to preview the colormap.
Here using jupyter:
IPython looks if an object has a _repr_html_; if so, it calls it and displays the output as HTML. Here's an example (I ran this in Jupyter but it works the same as long as you're running IPython):
class MyCoolObject:
def _repr_html_(self):
return ("<h1>hello!</h1> <p>this is some html </p>"
"I can even put images:"
"<img src='https://upload.wikimedia.org/wikipedia"
"/commons/thumb/3/38/Jupyter_logo.svg"
"/44px-Jupyter_logo.svg.png'></img>")
MyCoolObject()
To add on to Eduardo's answer, from everything I've read adding a _repr_html_ method should make iPython display the object when you type it into the console. I also use spyder though, and could not get it to work the way I expected. This simple wrapper class should allow you to display any html:
class displayedHTML:
def __init__(self, html):
self.html = html
def _repr_html_(self):
return self.html
But as you can see it does not work for me, instead showing the (implicitly defined) __repr__ of the class.
In [2]: obj = displayedHTML("<h1>" + "hello world" + "</h1>")
In [3]: obj
Out[3]: <__main__.displayedHTML at 0x1e8cda8f0d0>
I was not able to find the reason why this does not work, but I found a workaround if you just want to display a matplotlib colormap in the console from code (like I did).
Since know the matplotlib object works correctly, we can just give it to the ipython display function:
from IPython.display import display #Included without import since IPython 5.4 and 6.1
viridis = matplotlib.cm.get_cmap('viridis')
display(viridis)
And for me this works...
not_allowed_to_insert_pictures_yet.jpg
Hope this helps!

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.

How to make a custom colormap using PyPlot (not matplotlib proper)

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)])

PyPlot Error in Julia: type PyObject has no field set_yscale

I am programming in Julia but using PyPloy library. I want to plot an histogram with log y-axis. But when I use the following code:
using PyPlot
List = [rand() for i = 1:100]
plt.hist(List)
plt.gca().set_yscale("log")
I get the following error:
type PyObject has no field set_yscale
while loading In[45], in expression starting on line 3
in getindex at /home/rm/.julia/v0.4/PyCall/src/PyCall.jl:642
in pysequence_query at /home/rm/.julia/v0.4/PyCall/src/conversions.jl:743
in pytype_query at /home/rm/.julia/v0.4/PyCall/src/conversions.jl:759
in convert at /home/rm/.julia/v0.4/PyCall/src/conversions.jl:808
in pycall at /home/rm/.julia/v0.4/PyCall/src/PyCall.jl:812
in fn at /home/rm/.julia/v0.4/PyCall/src/conversions.jl:181
in close_queued_figs at /home/rm/.julia/v0.4/PyPlot/src/PyPlot.jl:295
Is this a path error? If so, is there a simpler way to do a log-log plot with a different command?
Thanks in advance.
I feel like this should be more prominently explained in the documentation, but if you scroll down to the bottom of the Readme for PyCall (which PyPlot uses) it says:
Important: The biggest difference from Python is that object attributes/members are accessed with o[:attribute] rather than o.attribute, so that o.method(...) in Python is replaced by o[:method](...)
So, as #jverzani mentioned, after you call any module-level function from PyPlot that returns an object, that object is a PyObject and all of the attributes and methods have to be called using the bracket notation with a symbol.

matplotlib get rid of max_open_warning output

I wrote a script that calls functions from QIIME to build a bunch of plots among other things. Everything runs fine to completion, but matplotlib always throws the following feedback for every plot it creates (super annoying):
/usr/local/lib/python2.7/dist-packages/matplotlib/pyplot.py:412: RuntimeWarning: More than 20 figures have been opened. Figures created through the pyplot interface (matplotlib.pyplot.figure) are retained until explicitly closed and may consume too much memory. (To control this warning, see the rcParam figure.max_num_figures).
max_open_warning, RuntimeWarning)
I found this page which seems to explain how to fix this problem , but after I follow directions, nothing changes:
import matplotlib as mpl
mpl.rcParams[figure.max_open_warning'] = 0
I went into the file after calling matplotlib directly from python to see which rcparams file I should be investigating and manually changed the 20 to 0. Still no change. In case the documentation was incorrect, I also changed it to 1000, and still am getting the same warning messages.
I understand that this could be a problem for people running on computers with limited power, but that isn't a problem in my case. How can I make this feedback go away permanently?
Try setting it this way:
import matplotlib as plt
plt.rcParams.update({'figure.max_open_warning': 0})
Not sure exactly why this works, but it mirrors the way I have changed the font size in the past and seems to fix the warnings for me.
Another way I just tried and it worked:
import matplotlib as mpl
mpl.rc('figure', max_open_warning = 0)
When using Seaborn you can do it like this
import seaborn as sns
sns.set_theme(rc={'figure.max_open_warning': 0})
Check out this article which basically says to plt.close(fig1) after you're done with fig1. This way you don't have too many figs floating around in memory.
In Matplotlib, figure.max_open_warning is a configuration parameter that determines the maximum number of figures that can be opened before a warning is issued. By default, the value of this parameter is 20. This means that if you open more than 20 figures in a single Matplotlib session, you will see a warning message. You can change the value of this parameter by using the matplotlib.rcParams function. For example:
import matplotlib.pyplot as plt
plt.rcParams['figure.max_open_warning'] = 50
This will set the value of figure.max_open_warning to 50, so that you will see a warning message if you open more than 50 figures in a single Matplotlib session.