Add plot to a given figure in matplotlib - python

I have created a figure in one part of the code as follows:
n = arange(51)
fig3 = plt.figure()
plt.semilogy(n,a1mag,'ro')
Now, i want to add another plot to this figure at a later part of the code. Is there some way to access fig3 while plotting?

It would be recommendable to either stay completely in the pyplot state-machine or comlpetely in the object oriented API; mixing the two causes just headaches.
pyplot
plt.figure(3)
plt.semilogy(x,y,'ro')
# .. do other stuff
# reactivate figure 3
plt.figure(3)
plt.plot(x,z)
object-oriented API
fig3, ax3 = plt.subplots()
ax3.semilogy(x,y)
# .. do other stuff
# plot to ax3
ax3.plot(x,z)

Related

How to combine two matplotlib figures as subfigures without replotting them

What i want
I want to combine two matplotlib figures in one new subplot.
The two figures are returned from visualization functions of libraries i don't want to or can't change myself(rebuild from source etc.). Also it should be not a hack-around but rather be a nice generic matplotlib solution.
The pseudo code looks like the following.
Pseudo code
import matplotlib.pyplot as plt
from library1 import magic_visualization_1
from library2 import magic_visualization_2
# Data of type some_crazy_data_type_of_the_library e.g. no simple x,y coords
data = ...
fig1 = magic_visualization_1(data) # type is: <class 'matplotlib.figure.Figure'>
fig2 = magic_visualization_2(data) # type is: <class 'matplotlib.figure.Figure'>
fig, axs = plt.subplots(2, 1, figsize=(10, 5))
# Somehow add fig1
# Somehow add fig2
plt.show()
# or like
fig = plt.figure(figsize=(10, 5))
gridspec = fig.add_gridspec(2, 1, left=0.05, right=0.95, wspace=0.1, hspace=0.15)
# Somehow add fig1
# Somehow add fig2
plt.show()
Example images
The two example figures:
fig1,
fig2
Photoshoped result
I should look like this(i made this by hand with gimp/photoshop)
fig1 on top of fig2
What i tried
The best idea i found was deepcopying every figure into the new subfigures but that feels to much like a hack-around.
Also i tried this solution with copying the two figures content.
Result:
vertical concatenation of the two figures

Activate a figure in matplotlib

It seems easy but I could not find any solution for opening multiple figures and save them by their name. I look for something like this:
fig1, ax1 = pl.subplots(1)
fig2, ax2 = pl.subplots(1)
...
pl.savefig('f1.png', fig1)
pl.savefig('f2.png', fig2)
usually pl.savefig acts on the last active figure. So how one can activate a figure and save it, then repeat the process for the rest of the figures?
You can save an image using the figure object itself:
fig1.savefig(...)
Alternatively, you can change the current figure by calling plt.figure(1) to select the first figure that was create and then use plt.savefig(). Or, you can use plt.figure(fig1.number) to switch focus to fig1
import matplotlib.pyplot as plt
fig1, ax1 = plt.subplots(1)
fig2, ax2 = plt.subplots(1)
# Can choose one of the below to change the current figure
plt.figure(1)
# plt.figure(fig1.number)
plt.savefig(...) # will save fig1

Overlapping legend when create plot with matplotlib and mpld3 in python

I'm a beginner in the world of python programming and I'm having a really hard time figuring out how to tackle my problem.
The problem is when I created a plot using loop in python with matplotlib and mpld3, the plot is as I expected it to be but the legend of the plot is really wrong because the legends were overlapping with each other. The legend of the plot will be displayed for the latest data only because other data's legend is overlapped on it.
Below is the picture of my plot:
This is the code to create the plot and legend in loop:
plt.rcParams.update({'font.size': 13})
fig, ax = plt.subplots()
for i in range(3,5):
rd1 = pd.read_sql_query("SELECT press, rs FROM basic_chart WHERE
cs = "+str(i), app.config['SQLALCHEMY_DATABASE_URI'])
print(rd1)
pt = ax.plot(rd1['press'],rd1['rs'],'-o')
plugins.connect(fig, plugins.InteractiveLegendPlugin([pt],[str(i)]))
html = mpld3.fig_to_html(fig)
I think that the main problem is on the interactive legend code but I did not manage to figure out the right way to correct it. I really hope experts can help me in this problem.
plt.rcParams.update({'font.size': 13})
fig, ax = plt.subplots()
for i in range(3,5):
rd1 = pd.read_sql_query("SELECT press, rs FROM basic_chart WHERE
cs = "+str(i), app.config['SQLALCHEMY_DATABASE_URI'])
print(rd1)
pt = ax.plot(rd1['press'],rd1['rs'],'-o')
axhandles, axlabels = ax.get_legend_handles_labels()
plugins.connect(fig, plugins.InteractiveLegendPlugin(axhandles, axlabels))
html = mpld3.fig_to_html(fig)
By having the plugins.connect in the loop, you are creating two separate legends.
After plotting, get the handles and labels from the plot and use that in the call to the InteractiveLegendPlugin.

x axis label disappearing in matplotlib and basic plotting in python

I am new to matplotlib, and I am finding it very confusing. I have spent quite a lot of time on the matplotlib tutorial website, but I still cannot really understand how to build a figure from scratch. To me, this means doing everything manually... not using the plt.plot() function, but always setting figure, axis handles.
Can anyone explain how to set up a figure from the ground up?
Right now, I have this code to generate a double y-axis plot. But my xlabels are disappearing and I dont' know why
fig, ax1 = plt.subplots()
ax1.plot(yearsTotal,timeseries_data1,'r-')
ax1.set_ylabel('Windspeed [m/s]')
ax1.tick_params('y',colors='r')
ax2 = ax1.twinx()
ax2.plot(yearsTotal,timeseries_data2,'b-')
ax2.set_xticks(np.arange(min(yearsTotal),max(yearsTotal)+1))
ax2.set_xticklabels(ax1.xaxis.get_majorticklabels(), rotation=90)
ax2.set_ylabel('Open water duration [days]')
ax2.tick_params('y',colors='b')
plt.title('My title')
fig.tight_layout()
plt.savefig('plots/my_figure.png',bbox_inches='tight')
plt.show()
Because you are using a twinx, it makes sense to operate only on the original axes (ax1).
Further, the ticklabels are not defined at the point where you call ax1.xaxis.get_majorticklabels().
If you want to set the ticks and ticklabels manually, you can use your own data to do so (although I wouldn't know why you'd prefer this over using the automatic labeling) by specifying a list or array
ticks = np.arange(min(yearsTotal),max(yearsTotal)+1)
ax1.set_xticks(ticks)
ax1.set_xticklabels(ticks)
Since the ticklabels are the same as the tickpositions here, you may also just do
ax1.set_xticks(np.arange(min(yearsTotal),max(yearsTotal)+1))
plt.setp(ax1.get_xticklabels(), rotation=70)
Complete example:
import matplotlib.pyplot as plt
import numpy as np; np.random.seed(1)
yearsTotal = np.arange(1977, 1999)
timeseries_data1 = np.cumsum(np.random.normal(size=len(yearsTotal)))+5
timeseries_data2 = np.cumsum(np.random.normal(size=len(yearsTotal)))+20
fig, ax1 = plt.subplots()
ax1.plot(yearsTotal,timeseries_data1,'r-')
ax1.set_ylabel('Windspeed [m/s]')
ax1.tick_params('y',colors='r')
ax1.set_xticks(np.arange(min(yearsTotal),max(yearsTotal)+1))
plt.setp(ax1.get_xticklabels(), rotation=70)
ax2 = ax1.twinx()
ax2.plot(yearsTotal,timeseries_data2,'b-')
ax2.set_ylabel('Open water duration [days]')
ax2.tick_params('y',colors='b')
plt.title('My title')
fig.tight_layout()
plt.show()
Based on your code, it is not disappear, it is set (overwrite) by these two functions:
ax2.set_xticks(np.arange(min(yearsTotal),max(yearsTotal)+1))
ax2.set_xticklabels(ax1.xaxis.get_majorticklabels(), rotation=90)
set_xticks() on the axes will set the locations and set_xticklabels() will set the xtick labels with list of strings labels.

Matplotlib Animation for custom artist classes

Goal
Hi,
I am trying to animate a complex figure with several subplots and have started testing with the artist animation and the function animation methods.
For now, my goal is to have the subplot on the left show a moving colored line (not the problem) and the subplot on the right show an updated representation of a brain scan (the problem). Static, this looks something like this.
# Imports
import nilearn as nil
from nilearn import plotting as nlp
from matplotlib import pyplot as plt
window = np.arange(0,200-50)
fig = plt.figure(figsize=(7,4))
ax = fig.add_subplot(121)
ax.set_xlim([0, 200])
a = ax.axvspan(window[0], window[0]+50, color='blue', alpha=0.5)
ay = fig.add_subplot(122)
b = nlp.plot_stat_map(nil.image.index_img(s_img, 0), axes=ay, colorbar=False, display_mode='x', cut_coords=(0,))
Problem
As you can see, I am using nilearn for plotting the brain image. For some reason, the nilearn object from plot_stat_map does not have an attribute set_visible unlike the matplotlib object from axvspan.
So when I attempt a simple animation like so:
fig = plt.figure(figsize=(7,4))
ax = fig.add_subplot(121)
ax.set_xlim([0, 200])
ay = fig.add_subplot(122)
iml = list()
for i in np.arange(50):
a = ax.axvspan(window[i], window[i]+50, color='blue', alpha=0.5)
b = nlp.plot_stat_map(nil.image.index_img(s_img, i), axes=ay)
iml.append((a,b))
ani = animation.ArtistAniTruemation(fig, iml, interval=50, blit=False,
repeat_delay=1000)
it crashes with the following error:
/home/surchs/Enthought/Canopy_64bit/User/lib/python2.7/site-packages/matplotlib/animation.pyc in _init_draw(self)
974 for f in self.new_frame_seq():
975 for artist in f:
--> 976 artist.set_visible(False)
977 # Assemble a list of unique axes that need flushing
978 if artist.axes not in axes:
AttributeError: 'OrthoSlicer' object has no attribute 'set_visible'
Makes sense, nilearn does maybe not conform to matplotlibs expectations. So I try the function animation method like so:
def show_things(i, window, ax, ay):
ax.axvspan(window[i], window[i]+50, color='blue', alpha=0.5)
nlp.plot_stat_map(nil.image.index_img(s_img, i), axes=ay, colorbar=False, display_mode='x', cut_coords=(0,))
fig = plt.figure(figsize=(7,4))
ax = fig.add_subplot(121)
ax.set_xlim([0, 200])
ay = fig.add_subplot(122)
ani = animation.FuncAnimation(fig, show_things, interval=10, blit=False, fargs=(window, ax, ay))
Although I am not sure if I am using things correctly, this gives me an animated brain plot on the right. However, the plot on the left is now not updated but just drawn over. So instead of a sliding bar, I get an expanding color surface. Something like this:
Question
How do I
get the plot on the left to update (as opposed to overwrite) on each iteration when using the function animation method? I already tried the ax.cla() function in matplotlib but since this also clears all axis attributes (like xlim) this is not a solution for me. Are there altneratives?
get the plot on the right to work with the artist animation method even though the custom plotting class is obviously missing a crucial attribute.
Also, I am not sure if I am doing the whole implementation part right, so any advice on that front is also very appreciated.
I suspect you may need to clear the axvspan axis between plots with ax.cla() to get the correct left plot (N.B. probably should clear the right plot too). To get round the problem of missing attributes, I'd suggest extracting the data from the returned handle from nlp.plot_stat_map and plotting with matplotlib pcolormesh (or imshow). Another possibility is creating a child class and adding this method yourself. It may also be worth submitting a bug/feature request to nilearn if this should be present.
By the way, if you're only after a quick and easy plot, you can do a poor man's version of animation using interactive plots, as a minimal example,
import matplotlib.pyplot as plt
import numpy as np
import time
#Interactive plot
plt.ion()
#Setup figures
fig = plt.figure(figsize=(7,4))
ax = fig.add_subplot(121)
ay = fig.add_subplot(122)
plt.show()
x = np.linspace(0,2*np.pi)
for i in range(10000):
print(i)
#Clear axes
ax.cla(); ay.cla()
#Update data
yx = np.sin(x+i*0.1)
yy = np.sin(2.*(x+i*0.1))
#Replot
ax.plot(x,yx)
ay.plot(x,yy)
#Pause to allow redraw
plt.draw()
plt.pause(0.01)

Categories

Resources