BufferRegion is cleared by a call to clf() - python

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!

Related

colorbar in python generates large size in default

I had a large colorbar I'd like to shrink to match my plot size. So I followed these two threads, thread1 and thread2, tried the magic code
"colorbar(im,fraction=0.046, pad=0.04)".
However, it does not seem to work. I am wondering where I did wrong? Following is my code. I am totally new to python. Thanks.
from matplotlib.pyplot import imshow
from matplotlib.pyplot import colorbar
from matplotlib.pyplot import close
from numpy import zeros as zeros
close('all')
img = zeros((250, 800))
im = imshow(img, cmap='gray'); colorbar(im,fraction=0.046, pad=0.04)
The colorbar still looks large:
Importantly:
I'd prefer only to shorten the colorbar without making it thinner. Also, when the figure size changes, the colarbar can be size-changing accordingly.....like the MATLAB did, something like this:
when figure size changes, the colorbar resizes accordingly:
You can adjust the size of the colorbar with shrink within colorbar easily.
Have a look at this:
img = zeros((250, 800))
im = imshow(img, cmap='gray')
colorbar(im,fraction=0.046, pad=0.04,shrink=0.46)
Leads to:
See colorbar documentation for more information.

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

Semi-transparent 2d VTK text background

Simple question, but I've tried a few things and nothing seems to work.
I want to overlay some statistics onto a 3d VTK scene, using 2D vtkTextActors. This works fine, but the text is at times difficult to see, depending on what appears behind it in the 3D scene.
For this reason, I'd like to add a 2d, semi-transparent "box" behind my text actors to provide a darker background.
Which VTK object is appropriate for this? I've tried so far:
vtkLegendBoxActor: Not what I want, but I can use this with no text to display a semi-transparent box on screen. I cannot size it directly and I get warnings about not initialising some of the content.
vtkImageData: Tried manually creating image data and adding it to the scene; I believe it was placed within the 3d scene and not used as an overlay. If that's not the case then I couldn't get it to show at all.
vtkCornerAnnotation: Scales with window size, is fixed to a corner and the background opacity cannot be set AFAIK.
vtkTextActor: Cannot set a background color or opacity
Can anyone tell me how they might achieve what I'm after in VTK?
I've found a way to do this with vtkPolyMapper2D which seems to work okay. It seems to be a very stupid way to do this. If there is something more elegant, I'm all ears.
import vtk
extents = [[0,0],[620,0],[620,220],[0,220]]
polyPoints = vtk.vtkPoints()
for x, y in extents:
polyPoints.InsertNextPoint(x, y, 0)
num_corners = len(extents)
polyCells = vtk.vtkCellArray()
polyCells.InsertNextCell(num_corners + 1)
for i in range(0, num_corners):
polyCells.InsertCellPoint(i)
polyCells.InsertCellPoint(0) ## Rejoin at the end
poly_profile = vtk.vtkPolyData()
poly_profile.SetPoints(polyPoints)
poly_profile.SetPolys(polyCells) ## Goes solid
cut_triangles = vtk.vtkTriangleFilter()
cut_triangles.SetInput(poly_profile)
_poly_mapper = vtk.vtkPolyDataMapper2D()
_poly_mapper.SetInput(poly_profile)
_poly_mapper.SetInputConnection(cut_triangles.GetOutputPort())
_actor = vtk.vtkActor2D()
_actor.SetMapper(_poly_mapper)
_actor.GetProperty().SetColor([0.1,0.1,0.1])
_actor.GetProperty().SetOpacity(0.5)
#Add to renderer as normal
just use vtktexture, vtkimagedata & add your own image as texture background to the vtkrenderer by reducing the opacity like a watermark. thats it

Categories

Resources