I have a piece of code that I have acquired from a collaborator in work. This piece of code produces a plot like the one seen below.
example image of a plot
It does this by referencing another function in another piece of code; which I do not want to alter in any way.
What I would like to do is to write a piece of code that saves this plot as a png file i.e. I am looking for a function that i can put the other function as a variable that would save it is as a png/ jpeg file.
Code:
Here is the code:
for file in files:
import matplotlib.pyplot as plt
connection = sqlite3.connect( file )
animalPool = AnimalPool( )
animalPool.loadAnimals( connection )
# show the mask of animals at frame 300
animalPool.showMask( 701 )
It is calling the following function:
def showMask(self, t ):
'''
show the mask of all animals in a figure
'''
fig, ax = plt.subplots()
ax.set_xlim(90, 420)
ax.set_ylim(-370, -40)
for animal in self.getAnimalList():
mask = animal.getBinaryDetectionMask( t )
mask.showMask( ax=ax )
plt.show()
I have already tried the matplotlib "savefig" function, but this just saves a blank image.
I am very new to coding, and am trying to learn on the fly, so if this question is not well worded or explained please let me know what is confusing, because I'm also learning how to ask questions about this kind of thing.
Functions that produce matplotlib plots should take a figure or axes as input and only optionally create those if needed. They should return the created objects for further use. Finally, they should not call plt.show(), or if they must, provide an opt-out option.
For example, for a single axes plotting function, it could look like
def plottingfunction(*arguments, ax=None, show=True):
if ax is None:
fig, ax = plt.subplots()
else:
fig = ax.figure
# do something with fig and ax here, e.g.
line, = ax.plot(*arguments)
if show:
plt.show()
return fig, ax, line
If you adhere to such structure, it's easy to do whatever you need to after calling the function
fig, _, _ = plottingfunction([1,2,3], [3,2,4], show=False)
fig.savefig("myplot.png")
plt.show()
Related
I would like to create a small function for my own work. However I would like to create something like porting existing plots into figures. Which goes like this:
import matplotlib.pyplot as PLT
ax1 = PLT.plot(array1)
ax2 ...
def multi_ax(array_of_ax ):
fig = PLT.figure()
for n in range(some_number):
ax = fig.add_subplot(x,y,n+1)
ax.replacing(array_of_ax[n], postions_of_array)
Is there way to fit this way? Thanks in advance.
It isn't possible to move an axes from one figure to another; the axes is linked to the figure upon creation.
Instead, you'll have to first generate the figure, and then the axeses within that figure.
Due to the 2nd answer of this question I supposed the following code
import matplotlib.pyplot as plt
for i1 in range(2):
plt.figure(1)
f, ax = plt.subplots()
plt.plot((0,3), (2, 2), 'b')
for i2 in range(2):
plt.figure(2)
f, ax = plt.subplots()
plt.plot([1,2,3], [1,2,3], 'r')
plt.savefig('foo_{}_bar_{}.jpg'.format(i2, i1))
plt.close()
plt.figure(1)
plt.plot( [1,2,3],[1,2,3], 'r')
plt.savefig('bar_{}.jpg'.format(i1))
plt.close()
to create plots bar_0.jpg and bar_1.jpg showing a blue and a red line each.
However, figures look like
instead of
How can I achieve the desired behaviour?
Note that plots foo_*.jpg have to be closed and saved during handling of the bar plots.
You're already saving the Axes objects, so instead of calling the PyPlot plot function (which draws on the last created or activated Axes), use the objects' plot function:
ax.plot(...)
If you then give both a different name, say ax1 and ax2, you can draw on the one you like without interfering with the other. All plt. commands also exist as an Axes member function, but sometimes the name changes (plt.xticks becomes ax.set_xticks for example). See the documentation of Axes for details.
To save to figures, use the Figure objects in the same way:
f.savefig(...)
This API type is only just coming to Matlab, FYI, and will probably replace the old-fashioned "draw on the last active plot" behaviour in the future. The object-oriented approach here is more flexible with minimal overhead, so I strongly recommend you use it everywhere.
If unsure, better to make it explicit:
import matplotlib.pyplot as plt
for i1 in range(2):
fig1,ax1 = plt.subplots()
fig2,ax2 = plt.subplots()
ax1.plot([0,4],[2,2],'b')
for i2 in range(2):
ax2.plot([1,2,3],[1,2,3],'r')
fig2.savefig('abc{}.png'.format(2*i1+i2))
plt.figure(1)
ax1.plot([1,2,3],[1,2,3],'r')
fig1.savefig('cba{}.png'.format(i1))
What I am trying to do seems to be fairly straightforward, but I'm having a heck of a time trying to get it to work. I am simply trying to draw an image using imshow and then re-draw it periodically as new data arrives.
I've started out with this:
fig = figure()
ax = plt.axes(xlim=(0,200),ylim=(0,200))
myimg = ax.imshow(zeros((200,200),float))
Then I'm assuming I can call set_data like this to update the image:
myimg.set_data(newdata)
I've tried many other things, for example I've called ax.imshow(newdata) instead or I've tried using figure.show() after set_data().
You can simply call figure.canvas.draw() each time you append something new to the figure. This will refresh the plot.
from matplotlib import pyplot as plt
from builtins import input
fig = plt.figure()
ax = fig.gca()
fig.show()
block = False
for i in range(10):
ax.plot(i, i, 'ko')
fig.canvas.draw()
if block:
input('pause : press any key ...')
else:
plt.pause(0.1)
plt.close(fig)
I am trying to add multiple lines on a single figure without knowing the number of lines in advance. I currently have a class that has x and y values that are used for the line within a single session.
I am unsure how to add a new line for each new session within the same figure. Creating that association to be specific.
Within my main function I have the following code.
fig = plt.figure()
ax = fig.add_subplot(111)
line,= plt.figure().plot(0,0)
In my session class. I have the following code.
class Session:
x = []
y = []
# I think I should add a line here... but I am not sure
# how to make this association to the main.
For each session, it stores the x and y values and I can retrieve those values through methods. That part is easy but associating each line to the same graph is what I am having trouble at. How should I approach this problem?
You can call .plot() multiple times. I added an example of how to change the line color. I will leave the styling to you.
import matplotlib.pyplot as plt
fig = plt.Figure()
ax = fig.add_subplot(111)
colors = ('b','g','r','c','m','y','k','w',)
sessions = (sess1, sess2, sess3)
for sess, color in zip(sessions, colors):
ax.plot(sess.x, sess.y, color=color)
If you want to use, and/or re-use, a specific set of colors for all of your lines itertools.cycle makes short work of it:
import itertools as it
colors = ('b','g','r',)
sessions = (sess1, sess2, sess3, sess4, sess5, sess6)
for sess, color in zip(sessions, it.cycle(colors)):
ax.plot(sess.x, sess.y, color=color)
I have multiple lines to be drawn on the same axes, and each of them are dynamically updated (I use set_data), The issue being that i am not aware of the x and y limits of each of the lines. And axes.autoscale_view(True,True,True) / axes.set_autoscale_on(True) are not doing what they are supposed to. How do i auto scale my axes?
import matplotlib.pyplot as plt
fig = plt.figure()
axes = fig.add_subplot(111)
axes.set_autoscale_on(True)
axes.autoscale_view(True,True,True)
l1, = axes.plot([0,0.1,0.2],[1,1.1,1.2])
l2, = axes.plot([0,0.1,0.2],[-0.1,0,0.1])
#plt.show() #shows the auto scaled.
l2.set_data([0,0.1,0.2],[-1,-0.9,-0.8])
#axes.set_ylim([-2,2]) #this works, but i cannot afford to do this.
plt.draw()
plt.show() #does not show auto scaled
I have referred to these already, this , this.
In all cases I have come across, the x,y limits are known. I have multiple lines on the axes and their ranges change, keeping track of the ymax for the entire data is not practical
A little bit of exploring got me to this,
xmin,xmax,ymin,ymax = matplotlib.figure.FigureImage.get_extent(FigureImage)
But here again, i do not know how to access FigureImage from the Figure instance.
Using matplotlib 0.99.3
From the matplotlib docs for autoscale_view:
The data limits are not updated automatically when artist data are changed after the artist has been added to an Axes instance. In that case, use matplotlib.axes.Axes.relim() prior to calling autoscale_view.
So, you'll need to add two lines before your plt.draw() call after the set_data call:
axes.relim()
axes.autoscale_view(True,True,True)