Generating a plot grid out of existing Figure objects in Matplotlib [duplicate] - python

This question already has an answer here:
Embed matplotlib figure in larger figure
(1 answer)
Closed 8 years ago.
How can I use a matplotlib Figure object as a subplot? Specifically, I have a function that creates a matplotlib Figure object, and I would like to include this as a subplot in another Figure.
In short, here's stripped-down pseudocode for what I've tried:
fig1 = plt.figure(1, facecolor='white')
figa = mySeparatePlottingFunc(...)
figb = mySeparatePlottingFunc(...)
figc = mySeparatePlottingFunc(...)
figd = mySeparatePlottingFunc(...)
fig1.add_subplot(411, figure=figa)
fig1.add_subplot(412, figure=figb)
fig1.add_subplot(413, figure=figc)
fig1.add_subplot(414, figure=figd)
fig1.show()
Sadly, however, this fails. I know for a fact the individual plots returned from the function invocations are viable--I did a figa.show(),...,figd.show() to confirm that they are OK. What I get for the final line in the above code block--fig1.show()--is
a collection of four empty plots that have frames and x- and y- tickmarks/labels.
I've done quite a bit of googling around, and experimented extensively, but it's clear that I've missed something that is either really subtle, or embarrassingly obvious (I'll be happy for it to be the latter as long as I can get un-stuck).
Thanks for any advice you can offer!

You can't put a figure in a figure.
You should modify your plotting functions to take axes objects as an argument.
I am also unclear why the kwarg figure is there, I think it is an artifact of the way that inheritance works, the way that the documentation is auto-generated, and the way some of the getter/setter work is automated. If you note, it says figure is undocumented in the Figure documentation, so it might not do what you want;). If you dig down a bit, what that kwarg really controls is the figure that the created axes is attached too, which is not what you want.
In general, moving existing axes/artists between figures is not easy, there are too many bits of internal plumbing that need to be re-connected. I think it can be done, but will involving touching the internals and there is no guarantee that it will work with future versions or that you will get warning if the internals change in a way that will break it.
You need to your plotting functions to take an Axes object as argument. You can use a pattern like:
def myPlotting(..., ax=None):
if ax is None:
# your existing figure generating code
ax = gca()
so if you pass in an Axes object it gets drawn to (the new functionality you need), but if you don't all of your old code will work as expected.

Related

I use the subplot module to draw multiple subplots, But error with'list' object has no attribute'set_xlim' [duplicate]

What is the difference between the Axes.plot() and pyplot.plot() methods? Does one use another as a subroutine?
It seems that my options for plotting are
line = plt.plot(data)
or
ax = plt.axes()
line = ax.plot(data)
or even
fig = plt.figure()
ax = fig.add_axes([0,0,1,1])
line = ax.plot(data)
Are there situations where it is preferable to use one over the other?
For drawing a single plot, the best practice is probably
fig = plt.figure()
plt.plot(data)
fig.show()
Now, lets take a look in to 3 examples from the question and explain what they do.
Takes the current figure and axes (if none exists it will create a new one) and plot into them.
line = plt.plot(data)
In your case, the behavior is same as before with explicitly stating the
axes for plot.
ax = plt.axes()
line = ax.plot(data)
This approach of using ax.plot(...) is a must, if you want to plot into multiple axes (possibly in one figure). For example when using a subplots.
Explicitly creates new figure - you will not add anything to previous one.
Explicitly creates a new axes with given rectangle shape and the rest is the
same as with 2.
fig = plt.figure()
ax = fig.add_axes([0,0,1,1])
line = ax.plot(data)
possible problem using figure.add_axes is that it may add a new axes object
to the figure, which will overlay the first one (or others). This happens if
the requested size does not match the existing ones.
There is essentially no difference. plt.plot will at some point (after making sure that there is a figure and an axes available to plot to) call the plot function from that axes instance.
So the main difference is rather at the user's side:
do you want to use the Matlab-like state machine approach, which may save some lines of code for simple plotting tasks? Then use pyplot.
do you want to have full control over the plotting using the more pythonic object oriented approach? Then use objects like axes explicitely.
You may want to read the matplotlib usage guide.
Pyplot's plotting methods can be applied to either the Pyplot root (pyplot.plot()) or an axes object (axes.plot()).
Calling a plotting function directly on the Pyplot library (pyplot.plot()) creates a default subplot (figure and axes). Calling it on an axes object (axes.plot()) requires that you to have created your own axes object already and puts the graph onto that customized plotting space.
While pyplot.plot() is easy to use, you have more control over your space (and better able to understand interaction with other libraries) if you create an axes object axes.plot().
Axes.plot() returns an axes object. Every axes object has a parent figure object. The axes object contains the methods for plotting, as well as most customization options, while the figure object stores all of the figure-level attributes and allow the plot to output as an image.
If you use pyplot.plot() method and want to start customizing your axes, you can find out the name of the default axes object it created by calling pyplot.gca() to "get current axes."
python plt.plot(): it will create many default subplots, will save many lines of code and is easy to understand.
Axes.plot(): using an axes object will give you a better ability to customize your plot space.
If this is still relevant, Matplotlib's official website has a clear answer on this issue. Go to "The object-oriented interface and pyplot interface".
This section clearly answers the question. Using 'fig, ax', i.e., object-oriented approach gives one more control for customizing our plot. Using 'pyplot', on the other hand leaves us with less control over our plot but the advantage is that it saves us from writing more lines of code and is easier and handy when dealing with single plot.
Official documentation of Matplotlib suggests that "which approach to use is solely an individual's choice and there is no preference of one over other. However, it is good to stick to one approach to maintain consistency."

Why can I create a plot using df.plot, but then modify the plot I see by calling the plt object?

Maybe I'm just missing something really straightforward here. But I know in pandas I can use the matplotlib plotting feature by simply doing dataframe.plot (info here).
But how is it that I can modify that EXACT plot by just using plt.title, plt.xlabel, plt.ylabel, etc.? it doesn't make sense to me. For reference, I'm following this tutorial
dataset.plot(x='MinTemp', y='MaxTemp', style='o')
plt.title('MinTemp vs MaxTemp')
plt.xlabel('MinTemp')
plt.ylabel('MaxTemp')
plt.show()
Does it have something to do with the fact that when I'm running .plot on a dataframe, I'm really creating a matplotlib.pyplot object?
Matplotlib has the concept of the current axes. Essentially what this means is that whenever you first do something that requires an axes object, one is created for you and becomes the default object that all of your future actions will be applied to until you change the current axes to something else. In your case, dataset.plot(x='MinTemp', y='MaxTemp', style='o') creates an axes object and sets it as the current axes. All of plt.title(), plt.xlabel(), and plt.ylabel() simply apply their changes to the current axes.

understanding (and finding) matplotlib source code

Here it appears that matplotlib's specgram returns 4 variables including the last which is a plot:
http://matplotlib.org/examples/pylab_examples/specgram_demo.html
But here it seems there is only 3 variables returned in the tuple:
https://github.com/matplotlib/matplotlib/blob/master/lib/matplotlib/mlab.py#L478
Where is the missing code to generate the specgram plot? Perhaps I am just confused on the difference between pylab and matplotlib. Either way, I can't find the source.
You're confusing the function that computes the data to be plotted with the function that plots the data.
mlab.specgram just computes the data, while the axes method specgram plots it.
Have a look at: https://github.com/matplotlib/matplotlib/blob/master/lib/matplotlib/axes/_axes.py#L5786
ipython is very useful for things like this. method_name? will display the relevant documentation and the location of the source file, while method_name?? will display the relevant code, as well.
Understanding where the source for a matplotlib function is can be a bit confusing. Basically, anything in matplotlib.pyplot is auto-generated. Essentially all of the plotting methods are actually methods of the Axes object.
Hopefully that gets you started. If no one else gives a better answer, I'll elaborate more in a bit, when I have more time.

After creating an array of matplotlib.figure.Figure, how do I draw them as subplots of One figure? [duplicate]

This question already has an answer here:
Embed matplotlib figure in larger figure
(1 answer)
Closed 8 years ago.
How can I use a matplotlib Figure object as a subplot? Specifically, I have a function that creates a matplotlib Figure object, and I would like to include this as a subplot in another Figure.
In short, here's stripped-down pseudocode for what I've tried:
fig1 = plt.figure(1, facecolor='white')
figa = mySeparatePlottingFunc(...)
figb = mySeparatePlottingFunc(...)
figc = mySeparatePlottingFunc(...)
figd = mySeparatePlottingFunc(...)
fig1.add_subplot(411, figure=figa)
fig1.add_subplot(412, figure=figb)
fig1.add_subplot(413, figure=figc)
fig1.add_subplot(414, figure=figd)
fig1.show()
Sadly, however, this fails. I know for a fact the individual plots returned from the function invocations are viable--I did a figa.show(),...,figd.show() to confirm that they are OK. What I get for the final line in the above code block--fig1.show()--is
a collection of four empty plots that have frames and x- and y- tickmarks/labels.
I've done quite a bit of googling around, and experimented extensively, but it's clear that I've missed something that is either really subtle, or embarrassingly obvious (I'll be happy for it to be the latter as long as I can get un-stuck).
Thanks for any advice you can offer!
You can't put a figure in a figure.
You should modify your plotting functions to take axes objects as an argument.
I am also unclear why the kwarg figure is there, I think it is an artifact of the way that inheritance works, the way that the documentation is auto-generated, and the way some of the getter/setter work is automated. If you note, it says figure is undocumented in the Figure documentation, so it might not do what you want;). If you dig down a bit, what that kwarg really controls is the figure that the created axes is attached too, which is not what you want.
In general, moving existing axes/artists between figures is not easy, there are too many bits of internal plumbing that need to be re-connected. I think it can be done, but will involving touching the internals and there is no guarantee that it will work with future versions or that you will get warning if the internals change in a way that will break it.
You need to your plotting functions to take an Axes object as argument. You can use a pattern like:
def myPlotting(..., ax=None):
if ax is None:
# your existing figure generating code
ax = gca()
so if you pass in an Axes object it gets drawn to (the new functionality you need), but if you don't all of your old code will work as expected.

matplotlib set shared axis [duplicate]

This question already has answers here:
How to share x axes of two subplots after they have been created
(3 answers)
Closed 10 months ago.
Using matplotlib, it seems the only time to set the sharex or sharey axis parameters are during sub_plot creation (add_subplot(), subplot(), subplots()). For an axes class there are methods for getting axis sharing (get_shared_x_axes(), get_shared_y_axes()), but no corresponding methods for setting sharing. Maybe this is an API oversight, or perhaps it did not fit architecturally.
Is there a way to change the shared axis parameter?
For those that ask why: I'm using a matrix of plots dynamically, and can control this using view limits, but it just seems like there could be an easier way, and turning sharing on/off and using autoscale would be it.
Thanks.
Just to mention that a method for sharing axes after their creation does exist by now. For two axes ax1 and ax2 you can use
ax1.get_shared_x_axes().join(ax1, ax2)
See How share x axis of two subplots after they are created?.
The answer is that the way shared axes are set up is to share some of the internal state of the two axes. It is a tad tricky to get right and the code to do it on-the-fly (both linking and unlinking) doesn't exist in the library yet.
See this PR for work on-going work on un-linking axes. Help testing and developing this feature would be appreciated.
As of v3.3 there exist the new Axes.sharex, Axes.sharey methods:
ax1.sharex(ax2)
ax1.sharey(ax3)

Categories