How to add axes for subplot in matplotlib - python

I need to fit a function to a large number of datasets stored in several files and compare the fits. I open a file, read the columns and plot each fit as a subplot after fitting. Eventually I have a figure with lot of subplots showing all the fits. However, I need to see the fit and also the residual for each subplot like in the figure.
So far, I have the following. I thought I could add axes to subplot but it does not work. The function that I have works. But I do not know how to add axes to subplot to plot the residual with the fit as a subplot to the subplot.
def plotall(args):
x=args[0]
ydata=args[1]
chisq=args[2]
fit=args[3]
g1=args[4]
a=args[5]
ptitle=args[6]
axi = fig1.add_subplot(a1,b1,a+1)
axi.plot(x, ydata,'ko',markersize=2,label='Data')
axi.plot(x,fit,'m-',label='Fit')
axi.text(0.75,0.8,'T=%4.1f(K)'%ptitle, fontsize=7,transform = axi.transAxes)
axi.text(0.05,0.45,r'$\chi^2$=%3.1f'%chisq,fontsize=7,transform = axi.transAxes)
ytlist=np.linspace(min(ydata),max(ydata),4)
axi.set_yticks(ytlist)
axi.set_xlim([xlow,xhi])
xtlist=np.linspace(xlow,xhi,6)
axi.set_xticks(xtlist)
for label in (axi.get_xticklabels() + axi.get_yticklabels()):
label.set_fontname('Arial')
label.set_fontsize(5)
axi.legend(('Data','Fit'), 'upper left', shadow=False, fancybox=False,numpoints=1,
frameon = 0,labelspacing=0.01,handlelength=0.5,handletextpad=0.5,fontsize=6)

Related

Plotting two pandas series together one appears flat

I am practicing with Python Pandas plotting functions and I am trying to plot the content of two series extracted from the same dataframe into one plot.
When I plot the two series individually the result is correct. However, when I plot them together, the one that I plot as second appears flat in the picture.
Here is my code:
# dailyFlow and smooth are created in the same way from the same dataframe
dailyFlow = pd.Series(dataFrame...
smooth = pd.Series(dataFrame...
# lower the noise in the signal with standard deviation = 6
smooth = smooth.resample('D').sum().rolling(31, center=True, win_type='gaussian').sum(std=6)
dailyFlow.plot(style ='-b')
plt.legend(loc = 'upper right')
plt.show()
smooth.plot(style ='-r')
plt.legend(loc = 'upper right')
plt.show()
plt.figure(figsize=(12,5))
smooth.plot(style ='-r')
dailyFlow.plot(style ='-b')
plt.legend(loc = 'upper right')
plt.show()
Here is the output of my function:
I already tried using the parameter secondary_y=True in the second plot, but then I lose the information on the second line in the legend and the scaling between the two plots is wrong.
Many sources on the Internet seem to suggest that plotting the two series like I am doing should be correct, but then why is the third plot incorrect?
Thank you very much for your help.
For the data you have, the 3rd plot is correct. Look at the scale of the y axis on your two plots: one goes up to 70,000 and the other to 60,000,000.
I suspect what you actually want is a .rolling(...).mean() which should have a range comparable to your original data.
If you would like to make both plots bigger, you cold try something like this
fig, ax1 = plt.subplots()
ax1.set_ylim([0, 75000])
# plot first graph
ax2 = ax1.twinx() # second axes that shares the same x-axis
ax2.set_ylim([0, 60000000])
#plot the second graph

Overlaying matplotlib plot from multiple function calls while also plotting them separately

I have a function which plots and displays the distribution using the distplot from seaborn. it looks like this
def getPlot(data):
x=sns.distplot(data, hist=False)
plt.show()
return x
every time I call the function I get a plot of the distribution.
I want some help in modifying the function so that at the end of calling the function multiple times I should get an extra plot which is the combination of all the previous plots.
So if my function calls were
getPlot(data1)
getPlot(data2)
getPlot(data3)
I should get the individual plots for the data as I call the function and also at the very end I want the plots for the 3 data to be superimposed on each other.
Just moving plt.show() outside the function will not suffice because I want individual plots of the separate data as well as one figure that contains all the data.
Since you have to keep both a separate plot and a joint one of your data you have to plot each dataset twice. Once in a separate axes and once in a common one.
What I would do is create a figure and an axes into which everything will be plotted together. Then pass that axes object into the function, and make the function plot into the axes as well as into a new figure:
def plot_twice(data, ax_all):
# first plot into the common axes
sns.distplot(data, hist=False, ax=ax_all)
# and create a new figure and axes for a standalone plot
fig,ax = plt.subplots()
x = sns.distplot(data, hist=False, ax=ax)
return x
# create axes for the common plot
fig,ax_all = plt.subplots()
# now plot the things
getPlot(data1, ax_all)
getPlot(data2, ax_all)
getPlot(data3, ax_all)
# only call blocking plt.show() at the end
plt.show()
It doesn't seem feasible to copy plots from one axes to the other with matplotlib (see e.g. this or this), so unless the plotting takes an excessive amount of time or memory I'd just plot the data twice for simplicity.

How to plot grid, scatter points, and trend of one graph as separate files

I am attempting to save a plot in "layers". First I want to save just the grid. Then I want to save just my scatter points. And finally I want to save just my trend line, but I can't figure out how to "turn off" my scatter points to do this. My reasoning for doing this is so that I can import each component of the graph as a layer in photoshop.
Here's my code:
FIRST PLOT GRID ONLY
fig=plt.figure()
ax1=fig.add_subplot(111)
#ax1.plot(x,p(x), linewidth=3.0, color="#daa004")
plt.ylim(top=72)
plt.ylim(bottom=60)
plt.xlim(right=2025)
plt.xlim(left=1895)
plt.grid(axis='x', alpha=0.4)
plt.grid(axis='y', alpha=0.4)
plt.savefig('MeanAnnualFallTMAX_Grid.png', transparent=True)
PLOT SCATTER ONLY
ax1.plot(x,y,'o',markersize=3,color="#daa004",label="Annual Mean Fall Maximum Temperature")
plt.axis('off')
plt.savefig('MeanAnnualFallTMAX_Scatter.png', transparent=True)
PLOT TREND ONLY (The problem)
ax1.plot(x,p(x), linewidth=3.0, color="#daa004")
plt.axis('off')
plt.savefig('MeanAnnualFallTMAX_Trend.png', transparent=True)
But this prints the scatter and the trend. Is there a way to "clear" or "turn-off" the scatter points I previously plotted?
if you save a reference to your line you may either
Turn the points invisible
line, = ax1.plot(x,y,'o')
# ...
line.set_visible(False)
Remove the points from the axes
line, = ax1.plot(x,y,'o')
# ...
line.remove()
I think for this workflow I'd at least try to save the figure as svg and open this in Inkscape. Ungrouping the results there gives access to every partof the figure.
However, it'll soon be divided into too small pieces like points or lines, but have a look - perhaps it helps.

Seaborn -xtick labels in KDE plot

Ive created a simple histogram/KDE plot with seaborn and Im trying to add custom labels to the x-axis as follows:
plt.title("Cond Density")
plt.xlabel("Cond")
plt.ylabel("Density")
plt.xticks = (['Bob','Alex','Steve','Gwen','Darren'])
sns.distplot(rawData['Conditions'], bins=20)
sns.kdeplot(rawData['Conditions'], shade=True)
plt.show()
There are only 5 int elements in rawData['Conditions'], but the x-axis justs reflects the values in rawData['Conditions'], which are just [0,1,2,3,4].
What am I missing?
Histograms need sequential ticks. I'm unsure as to what you're exactly trying to plot, but if you want to graph the density relative to each of these names, a bar graph would be best.

autofmt_xdate deletes x-axis labels of all subplots

I use autofmt_xdate to plot long x-axis labels in a readable way. The problem is, when I want to combine different subplots, the x-axis labeling of the other subplots disappears, which I do not appreciate for the leftmost subplot in the figure below (two rows high). Is there a way to prevent autofmt_xdate from quenching the other x-axis labels? Or is there another way to rotate the labels? As you can see I experimented with xticks and "rotate" as well, but the results were not satisfying because the labels were rotated around their center, which resulted in messy labeling.
Script that produces plot below:
from matplotlib import pyplot as plt
from numpy import arange
import numpy
from matplotlib import rc
rc("figure",figsize=(15,10))
#rc('figure.subplot',bottom=0.1,hspace=0.1)
rc("legend",fontsize=16)
fig = plt.figure()
Test_Data = numpy.random.normal(size=20)
fig = plt.figure()
Dimension = (2,3)
plt.subplot2grid(Dimension, (0,0),rowspan=2)
plt.plot(Test_Data)
plt.subplot2grid(Dimension, (0,1),colspan=2)
for i,j in zip(Test_Data,arange(len(Test_Data))):
plt.bar(i,j)
plt.legend(arange(len(Test_Data)))
plt.subplot2grid(Dimension, (1,1),colspan=2)
xticks = [r"%s (%i)" % (a,b) for a,b in zip(Test_Data,Test_Data)]
plt.xticks(arange(len(Test_Data)),xticks)
fig.autofmt_xdate()
plt.ylabel(r'$Some Latex Formula/Divided by some Latex Formula$',fontsize=14)
plt.plot(Test_Data)
#plt.setp(plt.xticks()[1],rotation=30)
plt.tight_layout()
#plt.show()
This is actually a feature of the autofmt_xdate method. From the documentation of the autofmt_xdate method:
Date ticklabels often overlap, so it is useful to rotate them and right align them. Also, a common use case is a number of subplots with shared xaxes where the x-axis is date data. The ticklabels are often long, and it helps to rotate them on the bottom subplot and turn them off on other subplots, as well as turn off xlabels.
If you want to rotate the xticklabels of the bottom right subplot only, use
plt.setp(plt.xticks()[1], rotation=30, ha='right') # ha is the same as horizontalalignment
This rotates the ticklabels 30 degrees and right aligns them (same result as when using autofmt_xdate) for the bottom right subplot, leaving the two other subplots unchanged.

Categories