How can I use matplotlib to create many different chart objects and then have the ability to control each chart object separately (without affecting the other chart objects)?
Ideally, I'd like to have something of the following:
# creating the chart handler object
chartHandler = ChartHandler()
# plotting some values for chart #0
chartHandler[0].plot( range(0,100) )
# plotting some values for chart #5
chartHandler[5].plot( range(500,700) )
Unless you are talking about something that I haven't dealt with in matplotlib yet, I think that what you are looking for is figure.add_subplot(). You should be able to capture the return from each figure.add_subplot() and operate on each individually from then on, kind of like this:
import matplotlib.pyplot as plt
#Create an 11x5 figure
fig = plt.figure(figsize=(11,5))
#Create subplots[0]
subplts = []
subplt = fig.add_subplot(121)
subplts.append(subplt)
#Create subplots[1:20]
for xind in range(4,8):
for yind in range(0,5):
subplt = fig.add_subplot(5,8,(yind*8+xind))
subplts.append(subplt)
plt.show()
It should be noted that there are a few problems with the above script. Mainly, the subplots overlap slightly. This can be solved using the position keyword to add_subplot and some simple math.
In any case, you can now modify each subplot by referencing its index in subplots. It should be pretty simple to add plots, modify ranges, etc.
Related
optional context feel free to skip: I'm currently using cartopy and matplotlib to read in and plot weather model data on a map. I have three different fields I'm plotting: temperature, wind, and surface pressure. I'm using contourf, barbs, and contour respectively to plot each field. I want one image for each field, and then I'd like one image that contains all three fields overlaid on a single map. Currently I'm doing this by plotting each field individually, saving each of the individual images, then replotting all three fields on a single ax and a new fig, and saving that fig. Since the data takes a while to plot, I would like to be able to plot each of the single fields, then combine the axes into one final image.
I'd like to be able to combine multiple matplotlib axes without replotting the data on the axes. I'm not sure if this is possible, but doing so would be a pretty major time and performance saver. An example of what I'm talking about:
from matplotlib import pyplot as plt
import numpy as np
x1 = np.linspace(0, 2*np.pi, 100)
x2 = x1 + 5
y = np.sin(x1)
firstFig = plt.figure()
firstAx = firstFig.gca()
firstAx.scatter(x1, y, 1, "red")
firstAx.set_xlim([0, 12])
secondFig = plt.figure()
secondAx = secondFig.gca()
secondAx.scatter(x2, y, 1, "blue")
secondAx.set_xlim([0, 12])
firstFig.savefig("1.png")
secondFig.savefig("2.png")
This generates two images, 1.png and 2.png.
Is it possible to save a third file, 3.png that would look something like the following, but without calling scatter again, because for my dataset, the actual plotting takes a long time?
If you just want to save images of your plots and you don't intend to further use the Figure objects, you can use the following after saving "2.png".
# get the scatter object from the first figure
scatter = firstAx.get_children()[0]
# remove it from this collection so you can assign it to a new axis
# the axis reassignment will raise an error if it already belongs to another axis
scatter.remove()
scatter.axes = secondAx
# now you can add it to your new axis
secondAx.add_artist(scatter)
secondFig.savefig("3.png")
This modifies both figures, as it removes a scatter from one and adds it to another. If for some reason you want to preserve them, you can copy the contents of secondFig to a new one and then add the scatter to that. However, this will still modify the first plot as you have to remove the scatter from there.
I am trying to merge an arbitrary number of line charts into a single image, and while there are many, many questions about this sort of thing, none of them seem applicable to the code I'm working with.
Unlike a large number of answers, I don't want to have the separate graphs displayed side by side, or above one another, in a single output, but rather, combined together.
For all of these graphs the value of the "y_x" column would be the same, but the "yhat_y" produced during each loop would be different.
Adding subplots = True to the plot method of a dataframe seems to change the return type to something that is no longer compatible with the code numpy.ndarray' object has no attribute 'get_figure'
#ax = plt.subplot(111) doesnt seem to do anything
for variable in range(max_num):
forecast = get_forecast(variable)
cmp1 = forecast.set_index("ds")[["yhat", "yhat_lower", "yhat_upper"]].join(
both.set_index("ds")
)
e.augmented_error[variable]= sklearn.metrics.mean_absolute_error(
cmp["y"].values, cmp1["yhat"].values
)
cmp2=cmp.merge(cmp1,on='ds')
plot = cmp2[['y_x', 'yhat_y']].plot(title =e)
fig1 = plot.get_figure()
plot.set_title("prediction")
plt.show()
fig1.savefig('output.pdf', format="pdf")
plt.close()
The most straightforward way would be to create a reusable ax handle outside the loop, then call ax.plot inside the loop:
fig, ax = plt.subplots() # create reusable `fig` and `ax` handles
for variable in range(max_num):
...
ax.plot(cmp2['y_x'], cmp2['yhat_y']) # use `ax.plot(cmp2...)` instead of `cmp2.plot()`
ax.set_title('predictions')
fig.savefig('output.pdf', format='pdf')
Most of the problems I have with Python is related to plotting stuff...
In my code I have two functions that have more than one output each one. Those functions give as return, for example, the plot_periodogram function returns best_period, period_error and also when used it gives a plot.
The other function fold_LC when used gives a plot as a result.
What I'm trying to do is to use those resulting plots as subplots in a figure. Ihave tried to save the plots in varibles and returning them, to plot them in axes in side the functions, and all the solutions that I've found on the internet but nothing worked. Here is an example: IPython/matplotlib: Return subplot from function
Is there any way to store in a variable the plots obtained in those functions and then use them as subplots?
Here you have the two functions in my code.
def plot_periodogram(curva_corregida):
gls = Gls(lc,fbeg=None, fend=None,Pbeg=min_t,Pend=max_t)
best_period = gls.best['P']
period_error = gls.best['e_P']
period = 1/gls.freq
power = gls.power
max_power = power.max()
plt.plot(period,power,'b-',linewidth=.8)
plt.scatter(best_period,max_power,c='r',s=4,label='P={0} d'.format(round(best_period,4)))
plt.legend(loc='best')
return best_period, period_error
def fold_LC(curva_corregida, best_period):
folded = curva_corregida.fold(period = best_period)
lc_flux_folded = folded.flux
lc_time_folded = folded.phase
plt.scatter(lc_time_folded,lc_flux_folded,s=0.5, color='b')
The standard approach is the opposite to what you're trying to do.
Do not return the subplot from the function but rather pass the subplot to it.
import numpy as np, matplotlib.pyplot as plt
def plot_periodogram(subplot, curva_corregida):
gls = Gls(lc,fbeg=None, fend=None,Pbeg=min_t,Pend=max_t)
best_period = gls.best['P']
period_error = gls.best['e_P']
period = 1/gls.freq
power = gls.power
max_power = power.max()
subplot.plot(period,power,'b-',linewidth=.8)
subplot.scatter(best_period,max_power,c='r',s=4,label='P={0} d'.format(round(best_period,4)))
subplot.legend(loc='best')
fig, subplots = plt.subplots(nrows=2, ncols=3)
for n, subplot in enumerate(subplots.flatten()):
plot_periodogram(subplot, curva_corregida(n))
Remember that everything that you can do using the functions in the plt namespace can be done also using the methods of the graphical objects that Matplotlib provides you.
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.
I am looping through a bunch of CSV files containing various measurements.
Each file might be from one of 4 different data sources.
In each file, I merge the data into monthly datasets, that I then plot in a 3x4 grid. After this plot has been saved, the loop moves on and does the same to the next file.
This part I got figured out, however I would like to add a visual clue to the plots, as to what data it is. As far as I understand it (and tried it)
plt.subplot(4,3,1)
plt.hist(Jan_Data,facecolor='Red')
plt.ylabel('value count')
plt.title('January')
does work, however this way, I would have to add the facecolor='Red' by hand to every 12 subplots. Looping through the plots wont work for this situation, since I want the ylabel only for the leftmost plots, and xlabels for the bottom row.
Setting facecolor at the beginning in
fig = plt.figure(figsize=(20,15),facecolor='Red')
does not work, since it only changes the background color of the 20 by 15 figure now, which subsequently gets ignored when I save it to a PNG, since it only gets set for screen output.
So is there just a simple setthecolorofallbars='Red' command for plt.hist(… or plt.savefig(… I am missing, or should I just copy n' paste it to all twelve months?
You can use mpl.rc("axes", color_cycle="red") to set the default color cycle for all your axes.
In this little toy example, I use the with mpl.rc_context block to limit the effects of mpl.rc to just the block. This way you don't spoil the default parameters for your whole session.
import matplotlib as mpl
import matplotlib.pylab as plt
import numpy as np
np.random.seed(42)
# create some toy data
n, m = 2, 2
data = []
for i in range(n*m):
data.append(np.random.rand(30))
# and do the plotting
with mpl.rc_context():
mpl.rc("axes", color_cycle="red")
fig, axes = plt.subplots(n, m, figsize=(8,8))
for ax, d in zip(axes.flat, data):
ax.hist(d)
The problem with the x- and y-labels (when you use loops) can be solved by using plt.subplots as you can access every axis seperately.
import matplotlib.pyplot as plt
import numpy.random
# creating figure with 4 plots
fig,ax = plt.subplots(2,2)
# some data
data = numpy.random.randn(4,1000)
# some titles
title = ['Jan','Feb','Mar','April']
xlabel = ['xlabel1','xlabel2']
ylabel = ['ylabel1','ylabel2']
for i in range(ax.size):
a = ax[i/2,i%2]
a.hist(data[i],facecolor='r',bins=50)
a.set_title(title[i])
# write the ylabels on all axis on the left hand side
for j in range(ax.shape[0]):
ax[j,0].set_ylabel(ylabel[j])
# write the xlabels an all axis on the bottom
for j in range(ax.shape[1]):
ax[-1,j].set_xlabel(xlabels[j])
fig.tight_layout()
All features (like titles) which are not constant can be put into arrays and placed at the appropriate axis.