Creating a 2x2 subplot from one dataset as different graphs - python

I have a large census dataset I am working with and am taking different data from it and representing it as a singular .png in the end. I have created the graphs individually, but when I try to add them to the subplots they get distorted or axis get messed up.
Current code:
fig = plt.figure()
ax1 = fig.add_subplot(2, 2, 1)
ax2 = fig.add_subplot(2, 2, 2)
ax3 = fig.add_subplot(2, 2, 3)
ax4 = fig.add_subplot(2, 2, 4)
ax1.pie(df.data.valuecounts(normalize=True),labels=None,startangle-240)
ax1.legend(['a','b','c','d','e'])
ax1.axis('equal')
data2=df[['A']].dropna().values
kde=df.A.plot.kde()
binss = np.logspace(0.01,7.0)
ax2=plt.hist(hincp, normed=True, bins=binss)
ax2=plt.xscale('log')
ax3 = df.replace(np.nan,0)
ax3 = (df.groupby(['G'])['R'].sum()/1000)
ax3.plot.bar(width=0.9, color='red',title='Gs').set_ylabel('Rs')
ax3.set_ylabel('Rs')
ax3.set_xlabel('# G')
t = df[['p','o','s','y']]
ax4=plt.scatter(t.o,t.p,s=t.s,c=t.y, marker = 'o', alpha = 0.2)
plt.ylim(0, 10000)
plt.xlim(0,1200000)
cbar=plt.colorbar()
plt.title("this vs that", loc = 'center')
plt.xlabel('this')
plt.ylabel('that')
All four types of graphs should be displayed and not overlap.

You create Axes for each subplot but then you don't use them.
ax1.pie(...) looks correct but later you don't use ax2,ax3,ax4.
If you are going to to use the DataFrame plotting methods, just call plt.subplot before each new plot. Like this.
df = pd.DataFrame(np.random.random((6,3)))
plt.subplot(3,1,1)
df.loc[:,0].plot()
plt.subplot(3,1,2)
df.loc[:,1].plot()
plt.subplot(3,1,3)
df.loc[:,2].plot()
plt.show()
plt.close()
Or use the Axes that you create.
df = pd.DataFrame(np.random.random((6,3)))
fig = plt.figure()
ax1 = fig.add_subplot(3,1,1)
ax2 = fig.add_subplot(3,1,2)
ax3 = fig.add_subplot(3,1,3)
ax1.plot(df.loc[:,0])
ax2.plot(df.loc[:,1])
ax3.plot(df.loc[:,2])
plt.show()
plt.close()

Related

Create symmetric figures when using matplotlib labels

I am using plt.subplots with both ax.set_ylabel and fig.supylabel. However, this creates figures that are off-centered.
Is it possible to automatically increase the right margin such that the red line is at the center of the figure?
In the case I am doing this manually, how can I precisely measure by how much I should increase the right margin?
How about this:
fig = plt.figure()
ax1 = fig.add_subplot(1,2,1)
ax2 = fig.add_subplot(1,2,2)
x = np.arange(50)
ax1.plot(x,np.sin(x))
ax2.plot(x,np.sin(x))
ax1.set_ylim(-1,1)
ax2.set_ylim(-1,1)
ax2.set_yticklabels('')
ax1.set_title('damped')
ax2.set_title('undamped')
ax1.set_ylabel('amplitude')
fig.suptitle('Different types of oscillations')
Output:
---edit---
Try this:
import matplotlib.gridspec as grd
fig = plt.subplots()
gs = grd.GridSpec(1, 2, wspace=0.5)
ax1 = plt.subplot(gs[0])
ax2 = plt.subplot(gs[1])
x = np.arange(50)
ax1.plot(x,np.sin(x))
ax2.plot(x,np.sin(x))
ax1.set_title('damped')
ax2.set_title('undamped')
ax1.set_ylabel('amplitude')
The keypoint is gs = grd.GridSpec(1, 2, wspace=0.5). Adjust wspace as you like. The plot below is for wspace=0.5

Having python plot two different x-axes with different scales

Here's my code so far:
QE_ellip_fixed = [-1.04e-3,-1.04e-2,-0.1,-0.76,-2.34,-2.54]
QL_ellip_fixed = [1.77e-4,9.89e-4,-6e-2,-2.9,-4.45,-2.74]
QP_ellip_fixed = [1.26e-3,1.45e-2,0.14,0.98,2.6,2.5]
QE_ellip_varied = [-1.73e-4,-1.73e-3,-1.71e-2,-0.15,-0.86,-3.16]
QL_ellip_varied = [7.57e-5,7.53e-4,5.4e-3,-0.13,-4.15,-7.3]
QP_ellip_varied = [1.41e-3,1.77e-3,2.34e-2,0.22,1.33,3.14]
RHScalls_ellip = [764021,76388,7625,750,63,3]
RHScalls_circ = [629171,62864,6234,577,41,5]
QE_circ_fixed= [-1.26e-4,-1.26e-3,-1.24e-2,-0.11,-0.57,-2.98]
QL_circ_fixed = [-1.32e-4,5.89e-4,1.5e-3,-0.51,0.4,-9.57]
QP_circ_fixed = [1.45e-2,9.25e-3,4.62e-2,0.58,3.5,8.54]
QE_circ_varied = [-1.26e-4,-1.25e-3,-1.24e-2,-0.11,-0.56,-2.13]
QL_circ_varied = [-1.33e-4,5.88e-4,1.69e-3,-0.45,-0.64,-6.58]
QP_circ_varied = [1.45e-2,9.32e-3,5.2e-2,0.55,3.11,13.05]
alp = [1e-5,1e-4,1e-3,1e-2,1e-1,1]
fig = plt.figure()
ax1 = fig.add_subplot(111)
ax1.plot(alp,np.abs(QE_ellip_varied),label='$|Q_E|$')
ax1.plot(alp,np.abs(QL_ellip_varied),label='$|Q_L|$')
ax1.plot(alp,np.abs(QP_ellip_varied),label='$|Q_P|$')
ax2 = ax1.twiny()
ax2.set_xticks([1e-5,1e-4,1e-3,1e-2,1e-1,1])
ax2.set_xticklabels(RHScalls_ellip)
ax1.set_xscale('log')
plt.yscale('log')
ax1.grid()
ax1.set_xlabel('alpha')
ax1.set_ylabel('Score (unitless)')
ax1.legend()
plt.show()
And here's the outputted image:
I want to have the values on the top axis have ticklabels in line with the grid lines already imposed, as they actually correspond to those gridlines, but I can't seem to make the top axis not behave in this annoying logarithmic way. I've only specified for axis 1 to have a logarithmic scale, but it seems to have applied to axis 2 as well...
it's because the axes share the y-axis, but not the x-axis. The xlimits are different for each..the following worked for me:
fig = plt.figure()
ax1 = fig.add_subplot(111)
ax2 = ax1.twiny()
ax1.set_xscale('log')
ax2.set_xscale('log') #make sure both log
plt.yscale('log')
ax1.plot(alp,np.abs(QE_ellip_varied),label='$|Q_E|$')
ax1.plot(alp,np.abs(QL_ellip_varied),label='$|Q_L|$')
ax1.plot(alp,np.abs(QP_ellip_varied),label='$|Q_P|$')
ax2.set_xlim(ax1.get_xlim()) #make sure same limits
ax2.set_xticks([1e-5,1e-4,1e-3,1e-2,1e-1,1])
ax2.set_xticklabels(RHScalls_ellip)
ax1.grid()
ax1.set_xlabel('alpha')
ax1.set_ylabel('Score (unitless)')
ax1.legend()

matplotlib subplot gridspec automatic axis limits

I'm trying to create a subplot using matplotlib using gridspec.
I was wondering why matplotlib isn't putting correct x limits on the plot.
x values are a range from 0 to 40, but the plot only shows 1 datapoint, as the plottet x axis only reaches from -0.06 to 0.06.
Do I have to set the xlim manually when using subplot + gridspec?
x = range(0, len(stuff["training"]))
y = stuff["training"]
fig = plt.figure()
gs = gridspec.GridSpec(3, 1)
ax1 = fig.add_subplot(gs[0:2])
ax2 = fig.add_subplot(gs[-1], sharex=ax1)
plt.setp(ax2.get_xticklabels(), visible=False)
plt.setp([ax1, ax2], title='Test')
ax1.scatter(x, stuff["training"])
ax2.plot(x, stuff["lr"])
fig.suptitle('An overall title', size=20)
gs.tight_layout(fig, rect=[0, 0, 1, 0.97])
EDIT: I think I found the problem
This is not working:
ax1 = fig.add_subplot(gs[0:2])
ax2 = fig.add_subplot(gs[-1], sharex=ax1)
ax1.scatter(x,y)
This is working:
ax1 = fig.add_subplot(gs[0:2])
ax1.scatter(x,y)
ax2 = fig.add_subplot(gs[-1], sharex=ax1)

Pandas: plotting two histograms on the same plot

I would like to have 2 histograms to appear on the same plot (with different colors, and possibly differente alphas). I tried
import random
x = pd.DataFrame([random.gauss(3,1) for _ in range(400)])
y = pd.DataFrame([random.gauss(4,2) for _ in range(400)])
x.hist( alpha=0.5, label='x')
y.hist(alpha=0.5, label='y')
x.plot(kind='kde', style='k--')
y.plot(kind='kde', style='k--')
plt.legend(loc='upper right')
plt.show()
This produces the result in 4 different plots. How can I have them on the same one?
If I understood correctly, both hists should go into the same subplot. So it should be
fig = plt.figure()
ax = fig.add_subplot(111)
_ = ax.hist(x.values)
_ = ax.hist(y.values, color='red', alpha=.3)
You can also pass the pandas plot method an axis object, so if you want both kde's in another plot do:
fig = plt.figure()
ax = fig.add_subplot(111)
x.plot(kind='kde', ax=ax)
y.plot(kind='kde', ax=ax, color='red')
To get everything into a single plot you need two different y-scales since kde is density and histogram is frequency. For that you use the axes.twinx() command.
fig = plt.figure()
ax = fig.add_subplot(111)
_ = ax.hist(x.values)
_ = ax.hist(y.values, color='red', alpha=.3)
ax1 = ax.twinx()
x.plot(kind='kde', ax=ax1)
y.plot(kind='kde', ax=ax1, color='red')
You can use plt.figure() and the function add_subplot(): the first 2 arguments are the number of rows and cols you want in your plot, the last is the position of the subplot in the plot.
fig = plt.figure()
subplot = fig.add_subplot(1, 2, 1)
subplot.hist(x.ix[:,0], alpha=0.5)
subplot = fig.add_subplot(1, 2, 2)
subplot.hist(y.ix[:,0], alpha=0.5)

How to add a title to each subplot

I have one figure which contains many subplots.
fig = plt.figure(num=None, figsize=(26, 12), dpi=80, facecolor='w', edgecolor='k')
fig.canvas.set_window_title('Window Title')
# Returns the Axes instance
ax = fig.add_subplot(311)
ax2 = fig.add_subplot(312)
ax3 = fig.add_subplot(313)
How do I add titles to the subplots?
fig.suptitle adds a title to all graphs and although ax.set_title() exists, the latter does not add any title to my subplots.
Thank you for your help.
Edit:
Corrected typo about set_title(). Thanks Rutger Kassies
ax.title.set_text('My Plot Title') seems to work too.
fig = plt.figure()
ax1 = fig.add_subplot(221)
ax2 = fig.add_subplot(222)
ax3 = fig.add_subplot(223)
ax4 = fig.add_subplot(224)
ax1.title.set_text('First Plot')
ax2.title.set_text('Second Plot')
ax3.title.set_text('Third Plot')
ax4.title.set_text('Fourth Plot')
plt.show()
ax.set_title() should set the titles for separate subplots:
import matplotlib.pyplot as plt
if __name__ == "__main__":
data = [1, 2, 3, 4, 5]
fig = plt.figure()
fig.suptitle("Title for whole figure", fontsize=16)
ax = plt.subplot("211")
ax.set_title("Title for first plot")
ax.plot(data)
ax = plt.subplot("212")
ax.set_title("Title for second plot")
ax.plot(data)
plt.show()
Can you check if this code works for you? Maybe something overwrites them later?
A shorthand answer assuming
import matplotlib.pyplot as plt:
plt.gca().set_title('title')
as in:
plt.subplot(221)
plt.gca().set_title('title')
plt.subplot(222)
etc...
Then there is no need for superfluous variables.
If you want to make it shorter, you could write :
import matplotlib.pyplot as plt
for i in range(4):
plt.subplot(2,2,i+1).set_title(f'Subplot n°{i+1}')
plt.show()
It makes it maybe less clear but you don't need more lines or variables
A solution I tend to use more and more is this one:
import matplotlib.pyplot as plt
fig, axs = plt.subplots(2, 2) # 1
for i, ax in enumerate(axs.ravel()): # 2
ax.set_title("Plot #{}".format(i)) # 3
Create your arbitrary number of axes
axs.ravel() converts your 2-dim object to a 1-dim vector in row-major style
assigns the title to the current axis-object
fig, (ax1, ax2, ax3, ax4) = plt.subplots(nrows=1, ncols=4,figsize=(11, 7))
grid = plt.GridSpec(2, 2, wspace=0.2, hspace=0.5)
ax1 = plt.subplot(grid[0, 0])
ax2 = plt.subplot(grid[0, 1:])
ax3 = plt.subplot(grid[1, :1])
ax4 = plt.subplot(grid[1, 1:])
ax1.title.set_text('First Plot')
ax2.title.set_text('Second Plot')
ax3.title.set_text('Third Plot')
ax4.title.set_text('Fourth Plot')
plt.show()
In case you have multiple images and you want to loop though them and show them 1 by 1 along with titles - this is what you can do. No need to explicitly define ax1, ax2, etc.
The catch is you can define dynamic axes(ax) as in Line 1 of code
and you can set its title inside a loop.
The rows of 2D array is length (len) of axis(ax)
Each row has 2 items i.e. It is list within a list (Point No.2)
set_title can be used to set title, once the proper axes(ax) or subplot is selected.
import matplotlib.pyplot as plt
fig, ax = plt.subplots(2, 2, figsize=(6, 8))
for i in range(len(ax)):
for j in range(len(ax[i])):
## ax[i,j].imshow(test_images_gr[0].reshape(28,28))
ax[i,j].set_title('Title-' + str(i) + str(j))
You are able to give every graph a different title and label by Iteration only.
titles = {221: 'First Plot', 222: 'Second Plot', 223: 'Third Plot', 224: 'Fourth Plot'}
fig = plt.figure()
for x in range(221,225):
ax = fig.add_subplot(x)
ax.title.set_text(titles.get(x))
plt.subplots_adjust(left=0.1,
bottom=0.1,
right=0.9,
top=0.9,
wspace=0.4,
hspace=0.4)
plt.show()
Output:
As of matplotlib 3.4.3, the Figure.add_subplot function supports kwargs with title as:
fig.add_subplot(311, title="first")
fig.add_subplot(312, title="second")
For completeness, the requested result can also be achieve without explicit reference to the figure axes as follows:
import matplotlib.pyplot as plt
plt.subplot(221)
plt.title("Title 1")
plt.subplot(222)
plt.title("Title 2")
plt.subplot(223)
plt.title("Title 3")
plt.subplot(224)
plt.title("Title 4")
Use plt.tight_layout() after the last plot if you have issues with overlapping labels.

Categories