How do I test that PyVista successfully plotted a figure? - python

I am generating 3D meshes in PyVista, and I would like to update my integration test suite to ensure that it successfully shows my plots.
I'm hoping to adapt the methodology described here, to work with PyVista. Unfortunately, I can't find any results for any equivalent function to plt.gcf() in PyVista.
Does anyone know of a workaround?

There's a few ways of doing this. First, pyvista returns a instance of pyvista.plotting.renderer.CameraPosition upon a successful plot. For example:
>>> import pyvista
>>> sphere = pyvista.Sphere()
>>> cpos = sphere.plot(off_screen=True)
>>> print(type(cpos))
<class 'pyvista.plotting.renderer.CameraPosition'>
Since it's necessary to setup a plot and renderer to properly display a plot, getting a return camera position means that your plot was successful.
Alternatively, you can save the screenshot and check that the file exists:
import os
import pyvista
sphere = pyvista.Sphere()
cpos = sphere.plot(off_screen=True, screenshot='tmp.png')
assert os.path.isfile('tmp.png')
You could also check the content of the saved image as well (or potentially file size)

Related

Update/Refresh matplotlib plots on second monitor

At the moment I am working with Spyder and doing my plotting with matplotlib. I have two monitors, one for development and another for (data) browsing and other stuff. Since I am doing some calculations and my code often changes, I often (re)execute the code and have a look at the plots to check if the results are valid.
Is there any way to place my matplotlib plots on a second monitor and refresh them from the main monitor?
I have already searched for a solution but could not find anything. It would be really helpful for me!
Here's some additional information:
OS: Ubuntu 14.04 (64 Bit)
Spyder-Version: 2.3.2
Matplotlib-Version: 1.3.1.-1.4.2.
I know it's an old question but I came across a similar problem and found this question. I managed to move my plots to a second display using the QT4Agg backend.
import matplotlib.pyplot as plt
plt.switch_backend('QT4Agg')
# a little hack to get screen size; from here [1]
mgr = plt.get_current_fig_manager()
mgr.full_screen_toggle()
py = mgr.canvas.height()
px = mgr.canvas.width()
mgr.window.close()
# hack end
x = [i for i in range(0,10)]
plt.figure()
plt.plot(x)
figManager = plt.get_current_fig_manager()
# if px=0, plot will display on 1st screen
figManager.window.move(px, 0)
figManager.window.showMaximized()
figManager.window.setFocus()
plt.show()
[1] answer from #divenex: How do you set the absolute position of figure windows with matplotlib?
This has to do with matplotlib, not Spyder. Placing the location of a figure explicitly appears to be one of those things for which there's really just workarounds ... see the answers to the question here. That's an old question, but I'm not sure there's been change since then (any matplotlib devs, feel free to correct me!).
The second monitor shouldn't make any difference, it sounds like the issue is just that the figure is being replaced with a new one.
Fortunately you can update figures you've moved to where you want them pretty easily, by using the object interface specifically, and updating the Axes object without creating a new figure. An example is below:
import matplotlib.pyplot as plt
import numpy as np
# Create the figure and axes, keeping the object references
fig = plt.figure()
ax = fig.add_subplot(111)
p, = ax.plot(np.linspace(0,1))
# First display
plt.show()
# Some time to let you look at the result and move/resize the figure
plt.pause(3)
# Replace the contents of the Axes without making a new window
ax.cla()
p, = ax.plot(2*np.linspace(0,1)**2)
# Since the figure is shown already, use draw() to update the display
plt.draw()
plt.pause(3)
# Or you can get really fancy and simply replace the data in the plot
p.set_data(np.linspace(-1,1), 10*np.linspace(-1,1)**3)
ax.set_xlim(-1,1)
ax.set_ylim(-1,1)
plt.draw()

Differences between figure saved and figure displayed

I am creating a plot with matplotlib. Once I have the figure I am showing it inside a layout in my MainWindow, and the figure looks like this one:
Which looks good and everything is ok.
The problem is that, before showing it I am savin the figure with fig.savefig('EvolLine.png')
And the figure saved looks different. Then when I try to use this saved figure in a PDF file it does not look good.
Here it is the saved figure:
In addition, if I save the figure manually using the tool from the tool bar in the plot, then the saved figure looks good again.
I do not why if I save the figure "programatically" it looks bad, like compressed.
So how could I programatically save the figure and make it look like in the display??.
EDIT:
If that helps, this is the process that I am doing to save and plot:
fig = generateFigure(someData)
fig.savefig('EvolLine.png')
MyCanvas = FigureCanvas(fig)
navi_toolbar = NavigationToolbar(MyCanvas, self)
self.ui.verticalLayoutGraph4_3.addWidget(navi_toolbar)
self.ui.verticalLayoutGraph4_3.addWidget(MyCanvas)
#just to test
fig.savefig('EvolLine_AfterPlot.png')
Your problem is that when showing your figure in your program you are controlling the aspect ratio, meaning that the x-ticks do not overlap. However when saving the figure you are allowing matplotlib to automatically guess what it should be doing, and it's getting this wrong.
You can use fig.set_size_inches() to control the aspect ratio by setting an appropriate size, the code below demonstrates this as well as shows the different results.
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0,100,1000)
y = np.sin(x)
plt.plot(x,y)
plt.xticks(range(0,100,2))
fig = plt.gcf()
fig.set_size_inches(16,4)
plt.savefig('filename.png')
Original
Fixed

matplotlib: releasing memory after plot is done

I'd like to know the correct way to release memory after a plot is done since I'm getting a RuntimeError: Could not allocate memory for image error when plotting multiple images in a loop.
Currently I have the following commands in another code to supposedly do just that:
import matplotlib.pyplot as plt
# The code
.....
# Make plot
fig = plt.figure()
# Plotting stuff.
plt.imshow(...)
plt.plot(...)
plt.scatter(...)
# Save plot to file.
plt.savefig(...)
# Release memory.
plt.clf()
plt.close()
A comment in this answer states that the correct syntax is actually plt.close(fig) but the highest voted answer given here says that plt.clf() is enough and doesn't mention .close.
The questions are: what is(are) the correct command(s) to release memory after the plot is saved to file? Do I need both .clf and .close or is one of them enough?
I would like to suggest for you an alternate approach. Note that imshow returns a handle for you. Grab a reference on this, and use the set_data method on that object for subsequent iterations.
>>> h = plt.imshow(np.zeros([480, 640]))
>>> h
<matplotlib.image.AxesImage at 0x47a03d0>
>>> for img in my_imgs:
... h.set_data(img) #etc

BufferRegion is cleared by a call to clf()

I have an application in which I'd like to draw counties from a shapefile using Basemap. Drawing the county polygons is the bottleneck in the rendering, and since I'll be drawing the same region of the US (a bunch of times), I'd rather not have to draw all the polygons any more than I need to. So I had the idea to draw the counties to a figure with a transparent background, copy the axes to a pixel buffer using copy_from_bbox(), and restore the buffer using restore_region() when I need to draw the counties.
The basic code goes like this:
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
map = Basemap(...) # Create Basemap object
map.readshapefile("countyp020", 'counties', linewidth=0.5) # Draws the county lines
plt.gcf().patch.set_alpha(0.0)
plt.gca().patch.set_alpha(0.0)
# Copy to the pixel buffer (county_buffer is of type BufferRegion)
county_buffer = plt.gcf().canvas.copy_from_bbox(plt.gca().bbox)
plt.clf() # This line is problematic (see below)
# Plot my data here ...
# Restore the pixel buffer
plt.gcf().canvas.restore_region(county_buffer)
plt.gcf().canvas.blit(plt.gca().bbox) # Not sure if this line is necessary
plt.gcf().canvas.draw()
It works like a charm ... except for the line where I clear the figure. Clearing the figure between renderings apparently clears the BufferRegion object as well, and since I update the title and colorbar, I'd also like to clear the figure between renderings.
So my question is does anybody know a way to clear the figure and keep the pixel buffer intact? I haven't been able to find much documentation on BufferRegion, copy_from_bbox(), or restore_region(), so it's been a bit difficult to debug this. If there's no easy way around it, then does anybody know another way to do basically what I'm trying to do?
Thanks in advance!

Dendrogram generated by scipy-cluster does not show

I am using scipy-cluster to generate a hierarchical clustering on some data. As a final step of the application, I call the dendrogram function to plot the clustering. I am running on Mac OS X Snow Leopard using the built-in Python 2.6.1 and this matplotlib package. The program runs fine, but at the end the Rocket Ship icon (as I understand, this is the launcher for GUI applications in python) shows up and vanishes immediately without doing anything. Nothing is shown. If I add a 'raw_input' after the call, it just bounces up and down in the dock forever. If I run a simple sample application for matplotlib from the terminal it runs fine. Does anyone have any experiences on this?
I had the same issue on Ubuntu 10.04.
In order to get graphics to display from ipython interactive console, start it with "-pylab" switch, which enables the interactive use of matplotlib:
ipython -pylab
To get your graphics to display during the execution of a standalone script, use matplotlib.pyplot.show call. Here's an example from hcluster homepage, the first and last line are the significant bits here:
from matplotlib.pyplot import show
from hcluster import pdist, linkage, dendrogram
import numpy
from numpy.random import rand
X = rand(10,100)
X[0:5,:] *= 2
Y = pdist(X)
Z = linkage(Y)
dendrogram(Z)
show()
Invoking ipython with "-pylab" switch didn't make a difference for me.
(System: Fedora 13)
Though not ideal, my solution was to explicitly write the resulting figure as a file.
For example:
...
dendrogram(Z)
pylab.savefig( "temp.png" )
Hope this helps anyone who is running into the same issue.
Amendment: Be careful about simply using copy-and-paste with the hcluster package's brief tutorial, notably in that if you call pylab.savefig() after several types of dendrogram drawing shown in the tutorial, i.e.
distMat = # whatever distance matrix you have
dendrogram( linkage( distMat ) )
pylab.savefig( "exampleDendrogram.png" )
dendrogram( linkage( distMat, method="complete" ) ) #instead of default "single"
pylab.savefig( "exampleDendrogram.png" )
Then exampleDendrogram.png will contain both the single-linkage dendrogram and the complete-linkage dendrogram in the same figure, and they will likely cross-cross and look like a mess.
If you're as stupid as me, you'll spend 30-180 minutes in confusion about how to properly use hcluster, when it's actually just a matter of resetting matplotlib between dendrogram calls:
distMat = # whatever distance matrix you have
dendrogram( linkage( distMat ) )
pylab.savefig( "exampleDendrogram1.png" )
pylab.cla()
dendrogram( linkage( distMat, method="complete" ) ) #instead of default "single"
pylab.savefig( "exampleDendrogram2.png" )
Now, the resulting dendrogram image files will look like what you expected them to look like.
I have been facing the same problem. You can use one of the below methods
Use plt.show() :
use plt.show() after dedogram, this will show the plot
using plt.show
Use %matplotlib inline intially in jupyter notebook. this will show the plot after execution.
Using matplotlib inline

Categories

Resources