I am working with matplotlib to generate some graphs but I do not know the difference between these two ways of showing an image. I already read some documentation about it but I do not understand yet.
First way:
import matplotlib.pyplot as plt
plt.figure()
plt.plot(x, y)
plt.show()
Second way:
import matplotlib.pyplot as plt
graph = plt.figure()
plt.plot(x, y)
graph.show()
I think this two ways do not do the same thing but it is not clear to me.
Could someone explain it step by step for the two ways?
Simplified, plt.show() will start an event loop and create a graphical representation for each figure that is active inside the pyplot state.
In contrast, fig.show(), where fig is a figure instance, would show only this figure. Since it would also not block, it is (only) useful in interactive sessions; else the figure would be closed directly after showing it due to the script exiting.
In the usual case you would hence prefer plt.show(). This does not prevent you from using the object-oriented interface. A recommended way of creating and showing a figure is hence,
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot(x, y)
plt.show()
For two windows you can just repeat the plotting,
import matplotlib.pyplot as plt
fig1, ax1 = plt.subplots()
ax1.plot(x1, y1)
fig2, ax2 = plt.subplots()
ax2.plot(x2, y2)
plt.show()
Matplotlib has two styles of API implemented. One is object based (graph.show()) and the other is procedural (plt.show()) and looks a lot like the Matlab plotting API.
The procedural API works on the current figure and/or set of axes. You can always getting the current figure with plt.gcf() and the current axes with plt.gca().
There are occasionally some slight differences in syntax here and there. For example, if you want to set the x axis limits:
plt.xlim([0, 10])
or
ax = plt.gca()
ax.set_xlim([0, 10])
plt.figure returns an object that is assigned with graph = plt.figure() to graph . this is used when specific characteristics of this object ( the plot ) are intended to be changed, now the object can be refered to by its instance graph ( object-based plotting )
you use this i.e. if you want to access the axes of the graph or labels, subplots, ...
see https://python4mpia.github.io/plotting/advanced.html for object-based plotting
to manipulate the plot object you have to get a reference to it ( handle ) and this is done by graph = plt.figure() ( cf Object-Oriented Programming )
Related
I want to plot a graph with one logarithmic axis using matplotlib.
I've been reading the docs, but can't figure out the syntax. I know that it's probably something simple like 'scale=linear' in the plot arguments, but I can't seem to get it right
Sample program:
import pylab
import matplotlib.pyplot as plt
a = [pow(10, i) for i in range(10)]
fig = plt.figure()
ax = fig.add_subplot(2, 1, 1)
line, = ax.plot(a, color='blue', lw=2)
pylab.show()
You can use the Axes.set_yscale method. That allows you to change the scale after the Axes object is created. That would also allow you to build a control to let the user pick the scale if you needed to.
The relevant line to add is:
ax.set_yscale('log')
You can use 'linear' to switch back to a linear scale. Here's what your code would look like:
import pylab
import matplotlib.pyplot as plt
a = [pow(10, i) for i in range(10)]
fig = plt.figure()
ax = fig.add_subplot(2, 1, 1)
line, = ax.plot(a, color='blue', lw=2)
ax.set_yscale('log')
pylab.show()
First of all, it's not very tidy to mix pylab and pyplot code. What's more, pyplot style is preferred over using pylab.
Here is a slightly cleaned up code, using only pyplot functions:
from matplotlib import pyplot
a = [ pow(10,i) for i in range(10) ]
pyplot.subplot(2,1,1)
pyplot.plot(a, color='blue', lw=2)
pyplot.yscale('log')
pyplot.show()
The relevant function is pyplot.yscale(). If you use the object-oriented version, replace it by the method Axes.set_yscale(). Remember that you can also change the scale of X axis, using pyplot.xscale() (or Axes.set_xscale()).
Check my question What is the difference between ‘log’ and ‘symlog’? to see a few examples of the graph scales that matplotlib offers.
if you want to change the base of logarithm, just add:
plt.yscale('log',base=2)
Before Matplotlib 3.3, you would have to use basex/basey as the bases of log
You simply need to use semilogy instead of plot:
from pylab import *
import matplotlib.pyplot as pyplot
a = [ pow(10,i) for i in range(10) ]
fig = pyplot.figure()
ax = fig.add_subplot(2,1,1)
line, = ax.semilogy(a, color='blue', lw=2)
show()
I know this is slightly off-topic, since some comments mentioned the ax.set_yscale('log') to be "nicest" solution I thought a rebuttal could be due. I would not recommend using ax.set_yscale('log') for histograms and bar plots. In my version (0.99.1.1) i run into some rendering problems - not sure how general this issue is. However both bar and hist has optional arguments to set the y-scale to log, which work fine.
references:
http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.bar
http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.hist
So if you are simply using the unsophisticated API, like I often am (I use it in ipython a lot), then this is simply
yscale('log')
plot(...)
Hope this helps someone looking for a simple answer! :).
I am creating PDFs of an array of axes. Sometimes the page is not full, ie not all axes have data. In this case, I want the unused axes not to show on the PDF. But I want the layout to be the same as if they were being used. I'm using tight_layout() to get non-overlapping axes and ylabels.
The following code shows first the case where the axes are used, then what happens if I delete the unused ones (tight_layout does not work properly), and then, if I instead just set them not to be visible, tight_layout() fails with a
AttributeError: 'NoneType' object has no attribute 'is_bbox'
error.
import numpy as np
import matplotlib.pyplot as plt
def prep_figure():
plt.close('all')
fig, axs = plt.subplots(4,3, figsize=(11,8.5))
axs=np.concatenate(axs)
for ii in range(5):
axs[ii].plot([1,2,3],[-10,-1,-10])
axs[ii].set_ylabel('ylabel')
axs[ii].set_xlabel('xlabel')
return fig,axs
fig,axs=prep_figure()
plt.tight_layout()
plt.show()
plt.savefig('tmp.pdf', )
# Try deleting extra axes
fig,axs=prep_figure()
for ii in range(5,12):
fig.delaxes(axs[ii])
plt.tight_layout()
plt.show()
plt.savefig('tmpd.pdf', )
# Try hiding extra axes
fig,axs=prep_figure()
for ii in range(5,12):
axs[ii].set_visible(False)
plt.tight_layout()
plt.show()
plt.savefig('tmph.pdf', )
I want the layout of the first version, but without the extra axes visible.
You could create the axes independently of the figure. I would also recommend this method because you have more control over the axes, for example you could have different shaped axes.
Code:
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
for ii in range(5):
ax = fig.add_subplot(4,3,ii+1)
ax.scatter(np.random.random(5),np.random.random(5))
ax.set_xlabel('xlabel')
ax.set_ylabel('ylabel')
fig.tight_layout()
fig.show()
Result:
The second case of deleting the axes works fine if it is used on its own (without the code from the first case executed) and if the figure is first saved and then shown,
fig,axs=prep_figure()
for ii in range(5,12):
fig.delaxes(axs[ii])
plt.tight_layout()
plt.savefig('tmpd.pdf', )
plt.show()
The third case works fine if again, the figure is saved before showing it, and instead of making it invisible, turning the axes off via ax.axis("off").
fig,axs=prep_figure()
for ii in range(5,12):
axs[ii].axis("off")
plt.tight_layout()
plt.savefig('tmph.pdf', )
plt.show()
The created pdf is the same in both cases:
I have a big unresolved question about the matplotlib Python module.
If I create a figure called [Figure1], with 2 axes [Ax1, Ax2], and another figure [Figure2], is there a function or method that will allow me to export the Ax1 object from Figure1 and redraw it to the Figure2 object?
In general axes are bound to a figure. The reason is, that matplotlib usually performs some operations in the background to make them look nice in the figure.
There are some hacky ways around this, also this one, but the general consensus seems to be that one should avoid trying to copy axes.
On the other hand this need not be a problem or a restriction at all.
You can always define a function which does the plotting and use this on several figures like so:
import matplotlib.pyplot as plt
def plot1(ax, **kwargs):
x = range(5)
y = [5,4,5,1,2]
ax.plot(x,y, c=kwargs.get("c", "r"))
ax.set_xlim((0,5))
ax.set_title(kwargs.get("title", "Some title"))
# do some more specific stuff with your axes
#create a figure
fig, (ax1, ax2) = plt.subplots(1,2)
# add the same plot to it twice
plot1(ax1)
plot1(ax2, c="b", title="Some other title")
plt.savefig(__file__+".png")
plt.close("all")
# add the same plot to a different figure
fig, ax1 = plt.subplots(1,1)
plot1(ax1)
plt.show()
I'm trying to show multiple figures at once, but with an offset so I don't have to move the first figure to check that it showed all the figures (plots).
So here's an example:
from pylab import *
figure(0)
plot()
figure(1)
plot()
show()
These figures are shown on top of each other, but I want them to look like this when I run my program:
EDIT:
Any suggestions?
I usually do this with Figure.add_subplot:
fig = figure(0)
ax = fig.add_subplot(211)
ax.plot(...)
ax = fig.add_subplot(212)
ax.plot(...)
show()
If you're wondering what the magic 211 and 212 mean, see this question.
If you're using the tkagg backend, you can do:
import matplotlib.pyplot as plt
for i in range(5):
fig = plt.figure()
fig.canvas._tkcanvas.master.geometry('800x600+{:d}+{:d}'.format(70*i,70*i))
plt.show()
I think that the same treatment could be used for others backends...
Regards
I created a software to do signal analyses. There are multiple functions, and each finally display a complex figure containing labels, plot, axhspan, axvspan etc... Usually, these functions are called individually. Everyone of my functions returns a figure object, that I can save in pdf for example.
def Myfunction1(self):
fig = pyplot.figure()
...do somestuff, create my figure
pyplot.show()
fig.savefig('C:\MyFigurefolder\figure1.pdf', dpi=300)
return fig
def Myfunction2(self):
fig = pyplot.figure()
...do some other stuff, create my 2nd figure
pyplot.show()
fig.savefig('C:\MyFigurefolder\figure2.pdf', dpi=300)
return fig
Now, I would like to create a kind of "summary figure", by doing a metaanalyses, and pooling multiple figures together, and saving them in a final pdf.
I don't really know how I should do that. Is there a way to use whole figure objects, (or maybe the multiple individual pdf) to do my figure?
Something like:
def FinalFigure(self):
final = A_Kind_Of_Layout_Or_A_Figure_or_something
a=self.Myfunction1()
b=self.Myfunction2()
Action_to_arrange_a_and_b_like_gridspec
final.savefig('C:\MyFigurefolder\FinalFigure.pdf', dpi=300)
You may combine several plots with matplotlib.pyplot.subplot. For more control on the layout, check out the GridSpec.
Edit: As requested, a short example from the linked tutorial:
A gridspec instance provides array-like (2d or 1d) indexing that returns the SubplotSpec instance. For, SubplotSpec that spans multiple cells, use slice.
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
gs = gridspec.GridSpec(3, 3)
ax1 = plt.subplot(gs[0, :])
ax2 = plt.subplot(gs[1,:-1])
ax3 = plt.subplot(gs[1:, -1])
ax4 = plt.subplot(gs[-1,0])
ax5 = plt.subplot(gs[-1,-2])