In my question about tracking the python execution I was recommended to use pycallgraph so I decided to give it a try on following code:
#!/bin/env python
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 2, 100)
# The first call to plt.plot will automatically create
# the necessary figure and axes to achieve the desired plot.
plt.plot(x, x, label='linear')
# Subsequent calls to plt.plot re-use
# the current axes and each add another line.
plt.plot(x, x**2, label='quadratic')
plt.plot(x, x**3, label='cubic')
# Setting the title, legend, and axis labels also automatically
# use the current axes and set the title,
# create the legend, and label the axis respectively.
plt.xlabel('x label')
plt.ylabel('y label')
plt.title("Simple Plot")
plt.legend()
plt.show()
This code is from my another question where I've been asking about hierarchy in matplotlib, and I get the following answer:
If you're really keen to see how the auto creation is done - it's all
open source. You can see the call to plot() creates an Axes instance
by a call to gca() in the code here. This in turn calls gcf(), which
looks for a FigureManager (which is what actually maintains the
state). If one exists, it returns the figure it's managing, otherwise
it creates a new one using plt.figure(). Again, this process to some
degree inherits from matlab, where the initial call is usually figure
before any plotting operation.
First, I was trying pycallgraph with graphviz option, but it gives me following error:
$ pycallgraph graphviz -- matplotlib.py
libpath/shortest.c:324: triangulation failed
libpath/shortest.c:192: source point not in any triangle
Error: in routesplines, Pshortestpath failed
Segmentation fault
Traceback (most recent call last):
File "/usr/local/bin/pycallgraph", line 26, in <module>
exec(__file_content)
File "/usr/local/lib/python2.7/dist-packages/pycallgraph/pycallgraph.py", line 38, in __exit__
self.done()
File "/usr/local/lib/python2.7/dist-packages/pycallgraph/pycallgraph.py", line 81, in done
self.stop()
File "/usr/local/lib/python2.7/dist-packages/pycallgraph/pycallgraph.py", line 90, in generate
output.done()
File "/usr/local/lib/python2.7/dist-packages/pycallgraph/output/graphviz.py", line 112, in done
'code %(ret)i.' % locals())
pycallgraph.exceptions.PyCallGraphException: The command "dot -Tpng -opycallgraph.png /tmp/tmpObsZGK" failed with error code 35584.
Second I've tried to generate gephi format and it worked:
$ pycallgraph gephi -- matplotlib.py
When I've opened this in gephi I get huge graph (Nodes: 1062, Edges: 1362) which was almost useless and I cannot saw anything useful here. So I've tried limit the output:
$ pycallgraph --max-depth 5 gephi -- traceme.py
This gives me graph with 254 nodes and 251 edges which was basically also useless because I still cannot saw nothing useful here. So, I've decided to try following:
egrep -i 'gcf|gca|plot' pycallgraph.gdf
But it returns me nothing. Then I've started wondering what exactly is pycallgraph tracing and I've made this hello world:
#!/bin/env python
print "This line will be printed."
And I've run it with (graphviz):
pycallgraph graphviz -- hello_world.py
The output (read from png file that was generated) was:
__main__ ---> <module>
What tool can I use to get similar answer as I've referred? In another words, how can I know that this is the order of calling the functions: plot() -> gca() -> gcf()?
What is pycallgraph actually tracing?
Why hello world example is working with graphviz option but more complex example is working only with gephi option?
How to preserve the DOT format which is pycallgraph generating and passing to graphviz?
Related
I want to turn a series of matplotlib figures into an animation. However, whatever I do, I always receive error. I use Enthought Canopy 1.6.2 and Python 2.7.13 on Windows 10.
I have tried using videofig package. While it was good, I could not manage to save the mp4 file. Also, I believe using the source directly, i.e., matplotlib animation package would be more versatile for future uses. I checked a few answers, including 1, 2 and 3, yet none of them solved my problem.
The function I call is structured as follows.
def some_plotter(self, path, start_value, image_array)
some_unrelated_fig_functions()
im=plt.savefig(path, animated=True)
image_array.append([im])
plt.close("all")
The main code is as follows:
import matplotlib.animation as animation
image_array=[]
while(something):
some_obj.some_plotter(path, start_value, image_array)
fig = plt.figure()
ani = animation.ArtistAnimation(fig, image_array, interval=50, blit=True, repeat_delay=1000)
I receive the following error:
Traceback (most recent call last):
File "C:\Users\kocac\AppData\Local\Enthought\Canopy\edm\envs\User\lib\site-packages\matplotlib\cbook__init__.py", line 387, in process
proxy(*args, **kwargs)
File "C:\Users\kocac\AppData\Local\Enthought\Canopy\edm\envs\User\lib\site-packages\matplotlib\cbook__init__.py", line 227, in call
return mtd(*args, **kwargs)
File "C:\Users\kocac\AppData\Local\Enthought\Canopy\edm\envs\User\lib\site-packages\matplotlib\animation.py", line 1026, in _start
self._init_draw()
File "C:\Users\kocac\AppData\Local\Enthought\Canopy\edm\envs\User\lib\site-packages\matplotlib\animation.py", line 1557, in _init_draw
artist.set_visible(False)
AttributeError: 'NoneType' object has no attribute 'set_visible'
I had more similar lines to this, yet updating Matplotlib, following the suggestion at 3 reduced the error lines to 4. Yet I cannot proceed any longer. Note that saved images are perfectly fine so I am probably not doing anything wrong in the image creation.
How can I get rid of these errors? Where am I going wrong?
My current project requires a lot of evaluation. For convenience, I wrote a data class with Jupyter Notebook representations. My intention was to output different indicators as text (for copy & paste) and a boxplot as it is more descriptive in some cases.
To my surprise, (only) not calling show() or close() worked. However, this feels hacky to me. Thus my question: Is this behaviour intended? And why does it work?
To clarify what I'm wondering about, I expected this to happen regardless of calling show() or not:
I know, I could simply add a plot method to the data class and call that, but this really interests me.
Simplified version of the code:
class EvaluationResult:
def __init__(self, indicators, errors):
self.indicators = indicators
self.errors = errors
def _repr_html_(self):
return f"""
<b>Indicator A:</b> {self.indicators[1]:.3f}<br>
<b>Indicator B:</b> {self.indicators[2]:.3f}"""
def _repr_png_(self):
fig = plt.figure(figsize=(8, 2))
plt.boxplot(self.errors, whis=[5, 95],
showfliers=False, vert=False)
plt.title('Error distribution')
plt.tight_layout()
# return fig -- returning the figure is not mandatory
Versions: Python v3.6.4 | Jupyter Notebook v5.4.1 | IPython v6.2.1 | Matplotlib v2.2.2
Just to clarify something first - The plot was not generated because you returned a figure, but because you called the plt.boxplot() method. Simply running the following line in its own cell will auto-generate the plot inline without a call to plt.show()
plt.boxplot(errors, whis=[5, 95], showfliers=False, vert=False)
Here is a similar question which basically states that this is the default behavior.
I've always included the line %matplotlib inline in my notebook near the imports not knowing that it was the default behavior. I believe changing that line to %matplotlib notebook will change this behavior and force you to call plt.show() and plt.figure() when needed.
I was trying to update a figure in matplotlib after each time step of a simulation.
I have managed to do this with:
import time, math
import matplotlib
matplotlib.use(u'Qt4Agg') # use some backend
# (c.f. http://stackoverflow.com/a/21836184 for .use())
import matplotlib.pyplot as plt
plt.ion()
fig = plt.figure()
sub = fig.add_subplot(1, 1, 1)
x = [i/100. for i in range(-500, 500)]
sin = lambda x : [math.sin(i) for i in x]
axis, = sub.plot(x, sin(x), 'r')
shift = 0.1
while shift < 5:
shift += 0.01
x = [i+shift for i in x]
axis.set_ydata(sin(x))
plt.pause(0.0001) # was plt.draw()
During the course of coming up with this solution I was almost getting mad because the Qt4Agg backend did now work properly with the draw() command where now there is a plt.pause(0.0001) command.
Now it works, but I get the following warning:
``/usr/local/lib/python2.7/dist-packages/matplotlib/backend_bases.py:2399: MatplotlibDeprecationWarning: Using default event loop until function specific to this GUI is implemented
warnings.warn(str, mplDeprecation)``
I also tried the GTK3Agg backend, but I am not sure if the computers where we want to run the project support it. Most surprisingly this backend worked with plt.draw() (except for the fact that the window freezes) but throws the following warnings and errors when running it with plt.pause(0.0001):
/usr/local/lib/python2.7/dist-packages/matplotlib/backend_bases.py:2399: MatplotlibDeprecationWarning: Using default event loop until function specific to this GUI is implemented
warnings.warn(str, mplDeprecation)
Traceback (most recent call last):
File "subplot_demo.py", line 24, in <module>
plt.pause(0.0001) # was plt.draw()
File "/usr/local/lib/python2.7/dist-packages/matplotlib/pyplot.py", line 199, in pause
canvas.start_event_loop(interval)
File "/usr/local/lib/python2.7/dist-packages/matplotlib/backends/backend_gtk3.py", line 370, in start_event_loop
FigureCanvasBase.start_event_loop_default(self,timeout)
File "/usr/local/lib/python2.7/dist-packages/matplotlib/backend_bases.py", line 2407, in start_event_loop_default
self.flush_events()
File "/usr/local/lib/python2.7/dist-packages/matplotlib/backends/backend_gtk3.py", line 365, in flush_events
Gtk.main_iteration(True)
File "/usr/lib/python2.7/dist-packages/gi/types.py", line 43, in function
return info.invoke(*args, **kwargs)
TypeError: main_iteration() takes exactly 0 arguments (1 given)
I assume now that pause() is deprecated (as it proved also difficult to find some useful documentation about it) but still stick to it with the Qt4Agg backend as I am sure that PyQt4 will be installed on the target systems.
I now wonder: How do I correctly draw() with the Qt4Agg? The draw() call is not working, pause() deprecated - what can I do? (On a side note: What exactly went wrong in the pause()-call of the GTK3Agg backend?)
Some notes on versions:
Ubuntu: 12.04, Matplotlib: 1.4.3, Python: 2.7.3, GCC 4.6.3, PyQt: 4.8.1
I've narrowed down to this call:
fig.canvas.tostring_argb() #fig=matplotlib.pyplot.figure()
this function raises an AttributeError when I run the code as a python script.
AttributeError: 'FigureCanvasGTKAgg' object has no attribute 'renderer'
However, this code works properly if run in the ipython --pylab command line.
As far as I can tell from the documentation, the Agg renderer should work OK.
The context is that I'm trying to make a movie from figures, without saving the frames
to disk; as per this question. I'm using the approach that streams the pixel arrays
to ffmpeg (running as a separate process) to do this, I need the argb array of values from the frame.
Is there some configuration setting I can make to get matplotlib to work correctly from within a script?
Edit
Tried use('Agg') as per a comment; still fails; this is a minimal working example.
[dave#dave tools]$ python -c "import matplotlib; matplotlib.use('Agg'); import matplotlib.pyplot; fig=matplotlib.pyplot.figure(); fig.canvas.tostring_argb()"
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "/usr/lib64/python2.7/site-packages/matplotlib/backends/backend_agg.py", line 416, in tostring_argb
return self.renderer.tostring_argb()
AttributeError: FigureCanvasAgg instance has no attribute 'renderer'
I suspect that you have missed out the call to:
fig.canvas.draw()
before
fig.canvas.tostring_argb()
as
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot
fig=matplotlib.pyplot.figure()
fig.canvas.tostring_argb()
fails for me, but
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot
fig=matplotlib.pyplot.figure()
fig.canvas.draw()
fig.canvas.tostring_argb()
works.
I ended up installing and using the WXAgg backend; the Agg,and default GTKAgg, didn't work for me.
I ran into a python error that i have been trying to solve for several days now.
My program creates figures, saves and closes them which works fine except for this error. Usually it does not hinder the saving process but sometimes a picture is missing the lower part when saved. The odd thing is that this only happens every second time the loop reaches the savefig method, here is my code:
for num in np.arange(file_number):
plt.figure('abc' + str(num),figsize=(22,12),dpi=100)
#some plots are added to the figure
print 1
plt.savefig(os.path.join(savepath,filename),dpi=100)
print 2
plt.close()
print 3
I use the print commands to see where the error occurs. Here is the console output of spyder:
Reading file1.file
1
2
3
Reading file2.file
1
Traceback (most recent call last):
File "/usr/lib/pymodules/python2.7/matplotlib/backends/backend_qt4.py", line 151, in <lambda>
lambda: self.close_event())
File "/usr/lib/pymodules/python2.7/matplotlib/backend_bases.py", line 1564, in close_event
self.callbacks.process(s, event)
RuntimeError: underlying C/C++ object has been deleted
2
3
Reading file3.file
1
2
3
Reading file4.file
1
Traceback (most recent call last):
File "/usr/lib/pymodules/python2.7/matplotlib/backends/backend_qt4.py", line 151, in <lambda>
lambda: self.close_event())
File "/usr/lib/pymodules/python2.7/matplotlib/backend_bases.py", line 1564, in close_event
self.callbacks.process(s, event)
RuntimeError: underlying C/C++ object has been deleted
2
3
To my understanding, the error already occurs while saving the figure (every second time), although it works fine if i omit the close() command. In that case, my RAM is filled after about 70 files and sometimes i need to evaluate a couple of hundreds. That's why i need to include the close() command or something similar.
If you solve this (or improve my programing, i guess the way i did this saving and closing might be considered ugly) please help me.
How about change the backend to other options? For example:
import matplotlib as mpl
mpl.use( "agg" )
from matplotlib import pyplot as plt
import numpy as np
print plt.get_backend()
file_number = 100
for num in np.arange(file_number):
plt.figure('abc' + str(num),figsize=(22,12),dpi=100)
#some plots are added to the figure
print 1
plt.savefig("%d.png" % num,dpi=100)
print 2
plt.close()
print 3
I can't replicate your problem (partially because your example is not self contained), but I think you could look at going about solving the problem slightly different.
Since your figure definition (size, dpi, etc.) stays the same throughout the loop (and even if it didn't) you could look at producing just one figure, and updating it inside the loop:
import matplotlib as mpl
mpl.use( "tkagg" )
from matplotlib import pyplot as plt
import numpy as np
file_number = 1000
fig = plt.figure('abc', figsize=(22,12), dpi=100)
plt.show(block=False)
for num in np.arange(file_number):
fig.set_label('abc%s' % num)
# add an axes to the figure
ax = plt.axes()
#some plots are added to the figure (I just plotted a line)
plt.plot(range(num))
plt.savefig("%d.png" % num, dpi=100)
# draw the latest changes to the gui
plt.draw()
# remove the axes now that we have done what we want with it.
fig.delaxes(ax)
# put in a blocking show to wait for user interaction / closure.
plt.show()
Typically this isn't how you would do things (I would normally update the axes rather than add/remove one each time) but perhaps you have a good reason for doing it this way.
That should improve the performance significantly.