Overlay two plots *after* I have made plt.show() in Matplotlib - python

I am familiar with the idea of putting several plots in an overlay by calling the plot function several times
plt.plot(f1)
plt.plot(f2)
plt.plot(f2)
plt.show()
But what if I want to plot data that I have already put on a canvas?
i was thinking to use the matplotlib.lines.Line2D object returned by each plt.plot. If I store them in suitable variables then I can reuse them at a later time. But how do I get a plot out of these matplotlib.lines.Line2D? Maybe I am trying a doomed strategy
p3000=plt.plot([1,2,3])
and then
fig, ax = plt.subplots()
ax.add_line(p3000[0])
but I get RuntimeError: Can not put single artist in more than one figure
I have also tried get_xydata member but ti does not give the points in a form I am able to read.

Related

Python3 - Plotting the same matplotlib axes object on multiple figures?

I have a script which I'm adapting to include a GUI. In it, I create a plot with subplots (the arrangement of which depends on the number of plots - e.g. 4 plots go into a square rather than 4-across). That plot (with a subplot for each of the "targets" analyzed) gets saved to a .png.
In building the GUI, I'm writing up the 'results' frame and would like to show these individual subplots on their own tabs. I've written the code to lay out the frame how I want it, but in order to separate the subplots into their own plots, I need to draw the completed Axes object (e.g. the entire subplot for that target) onto a new figure in the frame.
Since the number of subplots isn't known before runtime, I already have my Axes objects/subplots in an array (/list?) axs, whose members are the individual Axes objects (each containing data points created with ax.scatter() and several lines and annotations created with ax.plot() and ax.annotate).
When I initially create the axes, I do so with
fig, axs = plt.subplots(num='Title', nrows=numrow, ncols=numcol,
figsize=[numcol*5, numrow*5],
subplot_kw={'adjustable':'box', 'aspect':1})
Is there a way to now take these axes and draw them onto a new figure (the one that will be contained in the 'results' frame of the GUI)? In my searches, I only came up with ways to plot multiple axes onto a single figure (i.e. how to use subplots()) but nothing came up on how I'd throw a pre-existing Axes object into a new figure that it wasn't originally associated with. I'd rather not re-draw the axes from scratch -- there's quite a bit of decoration and multiple datasets / lines plotted onto them already.
Any ideas? Happy to post code as requested, but since this more of a "How do I do this" than a "why doesn't my code work", I didn't post much of it.
Thank you!
I believe that's not possible and you will have to recreate the Axes objects inside the other figure. Which is just a matter of code reorganization. Note that your approach would not noticeably improve rendering performance. Matplotlib would have to re-render the Axes objects anyway, and that's the computationally expensive part. Creating the objects is relatively cheap.
What you're trying to do is pretty much this:
from matplotlib import pyplot
pyplot.ion()
figure1 = pyplot.figure()
axes = figure1.add_subplot()
axes.plot([0, 1], [0, 1])
figure2 = pyplot.figure()
figure2.add_axes(axes)
Which raises:
ValueError: The Axes must have been created in the present figure
And the documentation of add_axes() notes:
In rare circumstances, add_axes may be called with a single argument, an Axes instance already created in the present figure but not in the figure's list of Axes.
So that's a pretty clear indication that this is not a supported use case.

What is the meaning of colorbar.solids in Pyplot?

I am creating contour plots with matplotlib/pyplot and trying to print out a customized colorbar as well. I am also attempting to have the colorbar be printed in a completely separate image file from the plot.
sub_fig = plt.figure()
sub_ax = plt.axes()
sub_ax.axis("off")
#cs2 is a contourf object
sep_cb = plt.colorbar(cs2, cax=sub_ax)#, cax = new_figure.legend, ax=new_figure.legend, orientation="vertical")
sep_cb.shrink=0.5
sep_cb.fraction=.1
sep_cb.drawedges=True
# ~sep_cb.solids.set_edgecolor("white")
plt.savefig("colorbar_"+str(ii)+".png")
plt.clf()
So I am referring to the documentation here: https://matplotlib.org/api/_as_gen/matplotlib.pyplot.colorbar.html but I find that changing the settings does not change the appearance of my colorbar. What I want is actually to make it pretty small, and have the sections separated by some whitespace, with the values/ labels to the right. I can't shrink it, or make the values appear. No matter what, it appears like this:
colorbar
However, if I enable that sep_cb.solids line, I get some lines between the sections. But the only reason I even know about this is because of this section:
It is known that some vector graphics viewer (svg and pdf) renders white gaps between segments of the colorbar. This is due to bugs in the viewers not matplotlib. As a workaround the colorbar can be rendered with overlapping segments:
cbar = colorbar()
cbar.solids.set_edgecolor("face")
draw()
It seems that colorbar.solids can be used to set some options on the plot, but I cannot find any documentation on that directly, I don't even see it mentioned elsewhere on the page. Is this some basic pyplot thing I have managed to overlook? Any help would be appreciated, thank you.

Why does matplotlib have so many options for 'making' a plot?

So I have been using matplot for a while now, and one thing that confuses me how it handles subplots.
It can be done as such:
fig = plt.figure()
ax = fig.add_subplot(1,2,1)
Or. It could be done as such:
plt.subplots(1,2)
Or, one could do this instead:
plt.subplot(211)
Or of course, if we only need one plot we can immediately run
plt.plot(x,y) # or .scatter or whatever.
Why? Is there any actual reason why you should use one over the others?
Matplotlib is a Python library, that was significantly influenced by MatLab and aimed in part at former and current MatLab users, therefore has 2 types of syntax:
MatLab syntax, plt.sublot(211); plt.plot(); plt.colorbar();, that implies that every time you create a figure or subplot it is stored inside as last active object and all plotting and changing of parameters is applied to it. It is to make it comfortable to use for those, who transitioned from MatLab. The idea is you create an element and instantly apply all actions to it, then create next and never return to previous until you call plt.show .
Classic programming syntax with explicit object declaration and operations on said objects. It is comfortable for everyone else and allows one to go back to previously created objects (figures and axes) and make additional changes.
The matlab way makes it hard to work with multiple figures. (figure is an independent picture, axes is region of that picture that you plot data in) plt.show always shows the last figure you created, example:
plt.figure() #new figure created and stored as current active
Plt.subplot() #new axes created in current figure and stored as current axes
Plt.plot() #data plotted in current axes
Plt.subplot() #second axes added to figure and made current active
Plt.plot() #plot in current active that is second now
Plt.figure() #the new figure created, old can still be found with difficulty i believe,
#but current active is now different and plt.show will not show anything you plotted before.
But some people find it better for quick and dirty plotting.
You can transition between the 2 by using fig_1 = plt.gcf();, ax_1 = plt.gca(); which are get current figure and get current axes redpectively. There are also multiple ways to change appearance, one for matlab
plt.make_current_axes_without_ticks( param)
and one for oop languages (
fig=plt.figure;
ax=fig.add_axes();
axis=ax.y_axis();
yticks=axis.ticks();
yticks.set_visible(false);
or smth like that.
Multiple interfaces sure make learning it harder, but it makes easier to transition from other similar tools and make it less rigid, meaning sometimes there're very simple ways to make frequently used but convoluted changes. (See ticks example)

Creating two completely independent plots in matplotlib and going back and forth between them

I'd like to create two independent matplotlib plots within a python script, and potentially jump back and forth between them as I add lines, annotations, etc. to the various plots (for example, perhaps I call a function which adds lines to both plots, and then another function which adds the annotations).
I expect that by working off matplotlib examples I'd be able to figure out some solution that works, but I'd like to know what the preferred and cleanest way of doing this is. I tend to get confused about when I should be doing things like
fig,ax=plt.subplots()
and when I should be doing things like:
fig=plt.figure()
Furthermore, how should I be switching back and forth between plots. If I did something like
fig1,ax1=plt.subplots()
fig2,ax2=plt.subplots()
can I then just refer to these plots by doing something like:
ax1.plt.plot([some stuff])
ax2.plt.plot([otherstuff]
? I ask this because often in the matplotlib examples they don't refer to the plot like this after calling plt.subplot() but instead call commands like
plt.plot([stuff])
where presumably it doesn't matter that they didn't specify ax1 or ax2 because there's only one plot in the example. At the end I'd like to save both plots to file using something like
plt.savefig(....)
although I need, again, to be able to refer to both plots independently. So what's the proper way of implementing this?
If you want to be able to write code that clearly applies commands to distinct axes, you want to use the object oriented interface.
Actually, both of your first two examples are using this interface. The differences is that plt.subplots() will create both a figure object and a grid of axes, while plt.figure() just creates the figure.
The figure object has methods to create axes within it. So, these two blocks of code are equivalent:
fig, ax = plt.subplots()
and
fig = plt.figure()
ax = fig.add_subplot(111)
Generally, the latter approach is only going to be more useful when you want multiple axes within the figure that don't follow a regular grid. So, you could do:
fig = plt.figure()
ax = fig.add_axes([.1, .1, .2, .8])
which will add a tall axes object on the left side of the figure.
Next, how do you get multiple axes to plot on?
The subplots function takes two positional arguments specifying the number of rows and columns in the grid (these default to (1, 1). So if you want two axes side by side, you would do
fig, axes = plt.subplots(1, 2)
Now axes is going to be a (1, 2) object array that is filled with Axes objects. It's often more convenient, for a small grid, to use Python's tuple unpacking and get direct references to the objects:
fig, (ax1, ax2) = plt.subplots(1, 2)
Now, what do you do with these objects, and what's the relationship between them and the MATLAB-style procedure interface?
Most functions in the pyplot namespace also exist as methods on either Figure or Axes objects. Matplotlib (and MATLAB) has a concept of the "current" figure and axes. When you call a function like plt.plot, it draws on the current axis (usually the most recently created one). When you call a function like plt.savefig, it saves the current figure.
For simple task, this is a bit more direct and usually easier than using the object-oriented interface. However, when you start making more complex plots, e.g. a grid of axes where each grid has multiple layers (maybe a scatterplot and a regression line), being able to structure the code around what you are doing rather than where you are doing has substantial advantages. Generally, plotting code that is written in an object-oriented fashion will scale much better than code written in a procedural fashion.

Re-initialize the plot in pylab

I am new to using PyLab. I want to plot some points. But I don't want to show the previous points i.e. as a new point comes the previous plotted point will vanish and the new point will be plotted. I have searched a lot but I could not find how to re-initialize the plot in between. The problem I am facing is I can set the current figure by using
plt.figure(f1.number) but after plotting the point in that figure it gets permanently changed.
plt.hold(False) before you start plotting will do what you want.
hold determines of old artists are held-on to when new ones are plotted. The default is for hold to be on.
ex
# two lines
plt.figure()
plt.hold(True)
plt.plot(range(5))
plt.plot(range(5)[::-1])
#one line
plt.figure()
plt.hold(False)
plt.plot(range(5))
plt.plot(range(5)[::-1])
Changing it via plt.hold changes it for all (new) axes. You can change the hold state for an individual axes by
ax = gca()
ax.hold(True)
With pylab, pylab.clf() should clear the figure, after which you can redraw the plot.
Alternatively, you can update your data with set_xdata and set_ydata that are methods on the axes object that gets returned when you create a new plot (either with pylab.plot or pylab.subplot).
The latter is probably preferred, but requires a litte more work. One example I can quickly find is another SO question.

Categories

Resources