How to manage subplots in Pandas? - python

My DataFrame is:
df = pd.DataFrame({'A': range(0,-10,-1), 'B': range(10,20), 'C': range(10,30,2)})
and plot:
df[['A','B','C']].plot(subplots=True, sharex=True)
I get one column with 3 subplots, each even height.
How to plot it this way that I have only two subplots where 'A' is in upper one and 'B' and 'C' are in lower and lower graph's height is different than height of graph 'A' (x axis is shared)?

Use subplots with gridspec_kw parmater to setup your grid then use the ax paramter in pandas plot to use those axes defined in your subplots statement:
f, ax = plt.subplots(2,2, gridspec_kw={'height_ratios':[1,2]})
df[['A','B','C']].plot(subplots=True, sharex=True, ax=[ax[0,0],ax[0,1],ax[1,0]])
ax[1,1].set_visible(False)
Output:

For clarity I post my modified code here:
f, ax = plt.subplots(2,1, sharex=True, gridspec_kw={'height_ratios':[1,3]})
f.subplots_adjust(hspace=0)
df[['A','B','C']].plot(subplots=True, ax=[ax[0],ax[1],ax[1]])
That will do it. Thanks.

I was able to do it with .subplot2grid(). Which only creates 3 plots as needed.
ax1 = plt.subplot2grid((3, 2), (0, 0), colspan=1)
ax2 = plt.subplot2grid((3, 2), (0, 1), colspan=1)
ax3 = plt.subplot2grid((3, 2), (1, 0), rowspan=2, sharex=ax1)
plt.setp(ax1.get_xticklabels(), visible=False)
ax1.plot(df['A'])
ax2.plot(df['B'], color='darkorange')
ax3.plot(df['C'], color='green')
Output:

Related

Python Subplot2Grid - controlling axis labels

I am using the Subplot2Grid functionality within Matplotlib to combine two figures with different orientations, 4 bar plots (full width) and then 3 scatter plots splitting the full width into 3 columns, plus an extra space for a legend. The different sections have axes that need to align so I have used sharex = ax1 and sharey = ax1 within Subplot2Grid to implement this successfully.
However, I now cannot seem to control the axis labels the same as I would just using regular subplots function, having the x-axis tick labels showing only on the final bar plot and the y-axis tick labels showing only on the left-most scatter plot.
Plotting using Subplot2Grid, extra axis labels showing
I have tried the ax.set_xticklabels('') to try and switch them off, but the sharex/sharey seems to override them? I have also put the ax.set_xticklabels('') at the end of the code (after they are defined in ax4) and it switches them all off, not just the axis the one that is called (ax1, ax2 or ax3)
Relevant parts of the code are below:
# figure setup
fig = plt.figure()
fig.set_figheight(15)
fig.set_figwidth(9)
ax1 = plt.subplot2grid(shape=(6, 3), loc=(0, 0), colspan=3)
ax2 = plt.subplot2grid(shape=(6, 3), loc=(1, 0), colspan=3,sharex=ax1)
ax3 = plt.subplot2grid(shape=(6, 3), loc=(2, 0), colspan=3,sharex=ax1)
ax4 = plt.subplot2grid(shape=(6, 3), loc=(3, 0), colspan=3,sharex=ax1)
ax5 = plt.subplot2grid(shape=(6, 3), loc=(5, 0))
ax6 = plt.subplot2grid(shape=(6, 3), loc=(5, 1),sharex=ax5,sharey=ax5)
ax7 = plt.subplot2grid(shape=(6, 3), loc=(5, 2),sharex=ax5,sharey=ax5)
# plotting bars here
# first bar plot
ax1.set_title('Inundation area')
ax1.set_xticklabels('')
ylbl0 = 'Inundation area \n' + r'$(km^2)$'
ax1.set_ylabel(ylbl0)
# repeat for ax2 & ax3
# last bar plot
ax4.set_title(r'$\Delta$ Shear Stress')
ax4.set_xticks(np.arange(len(df_bars)))
ax4.set_xticklabels(df_bars['Reach Number'])
ax4.invert_xaxis()
ax4.axhline(y=0,c='k',lw = 0.5)
ax4.set_xlabel('Reach number')
ax4.set_ylabel('% change \n (2019-2020)')
Same occurs when using sharey for the 3 scatter plots and ax.set_yticklabels('')
ax1.tick_params(labelbottom=False)
does what you want.
This example works for me:
fig = plt.figure()
fig.set_figheight(15)
fig.set_figwidth(9)
ax1 = plt.subplot2grid(shape=(2, 1), loc=(0, 0), colspan=3)
ax1.plot(np.random.rand(10))
ax2 = plt.subplot2grid(shape=(2, 1), loc=(1, 0), colspan=3,sharex=ax1)
ax2.plot(np.random.rand(10))
ax1.tick_params(labelbottom=False)
plt.show()

Adding charts to a matplotlib subgrid

I have the following Matplotlib figure, with 2 charts:
That i created with the following code:
fig = plt.figure(facecolor='#131722',dpi=155, figsize=(8, 4))
ax1 = plt.subplot2grid((1,2), (0,0), facecolor='#131722')
ax2 = plt.subplot2grid((1,2), (0,1), facecolor='#131722')
Now i would like to add two charts, so ax3 and ax4, each needs to be below the two charts, they should have the same width of the two charts but half the height of the two bigger charts. How can i do that? I tried various solutions from here here but i'm struggling to get the expected output
You can achieve this using the gridspec_kw argument of plt.subplots. This allows you to specify the dimensions of the grid (in this case 2x2) and the ratio of the heights:
f, ax = plt.subplots(2, 2 , gridspec_kw={"height_ratios": [2, 1]})
for cAx in ax.flatten():
cAx.set_facecolor('#131722')
f.savefig("test.png", facecolor='#131722')
Alternatively, you can also create a 3x2 grid and specify that the first two subplots need to span two rows:
fig = plt.figure(facecolor='#131722',dpi=155, figsize=(8, 6))
ax1 = plt.subplot2grid((3,2), (0,0), facecolor='#131722', rowspan=2)
ax2 = plt.subplot2grid((3,2), (0,1), facecolor='#131722', rowspan=2)
ax3 = plt.subplot2grid((3,2), (2,0), facecolor='#131722')
ax4 = plt.subplot2grid((3,2), (2,1), facecolor='#131722')

Can you create non-uniform iterable plots in matplotlib

I'm trying to create a figure with a number of non-uniform subplots. I would like to be able to create the plots using an iterable index so that I do not have to create each plot individually.
I can create a series of uniform subplots using fig, ax = plt.subplots(5) where I can plot to the various axes using ax[i].
fig, ax = plt.subplots(5)
Going forward I can plot to each plot using ax[i] using ax[0].plt etc.
However I would like to be able to create a series of plots that looks like:
gridsize = (10,3)
fig = plt.figure(figsize=(5,3))
ax0 = plt.subplot2grid(gridsize, (0, 0), colspan=3, rowspan=1)
for i in range(1,5):
ax1 = plt.subplot2grid(gridsize, (i, 0), colspan=2, rowspan=1)
ax2 = plt.subplot2grid(gridsize, (i, 2), colspan=2, rowspan=1)
where I can call each plot using ax[i] as above.
Does anyone have any ideas? Thanks.
You may append the axes to a list from which to index the respective item or over which to iterate.
import numpy as np
import matplotlib.pyplot as plt
gridsize = (10,3)
fig = plt.figure(figsize=(5,3))
ax0 = plt.subplot2grid(gridsize, (0, 0), colspan=3, rowspan=1)
ax = [ax0]
for i in range(1,5):
ax.append(plt.subplot2grid(gridsize, (i, 0), colspan=2, rowspan=1))
ax.append(plt.subplot2grid(gridsize, (i, 2), colspan=2, rowspan=1))
## Now plot to those axes:
for i in range(2*4+1):
ax[i].plot(np.arange(14),np.random.randn(14))
for axi in ax:
axi.plot(np.arange(14),np.random.randn(14))
plt.show()

Python - Stacking two histograms with a scatter plot

Having an example code for a scatter plot along with their histograms
x = np.random.rand(5000,1)
y = np.random.rand(5000,1)
fig = plt.figure(figsize=(7,7))
ax = fig.add_subplot(111)
ax.scatter(x, y, facecolors='none')
ax.set_xlim(0,1)
ax.set_ylim(0,1)
fig1 = plt.figure(figsize=(7,7))
ax1 = fig1.add_subplot(111)
ax1.hist(x, bins=25, fill = None, facecolor='none',
edgecolor='black', linewidth = 1)
fig2 = plt.figure(figsize=(7,7))
ax2 = fig2.add_subplot(111)
ax2.hist(y, bins=25 , fill = None, facecolor='none',
edgecolor='black', linewidth = 1)
What I'm wanting to do is to create this graph with the histograms attached to their respected axis almost like this example
I'm familiar with stacking and merging the x-axis
f, (ax1, ax2, ax3) = plt.subplots(3)
ax1.scatter(x, y)
ax2.hist(x, bins=25, fill = None, facecolor='none',
edgecolor='black', linewidth = 1)
ax3.hist(y, bins=25 , fill = None, facecolor='none',
edgecolor='black', linewidth = 1)
f.subplots_adjust(hspace=0)
plt.setp([a.get_xticklabels() for a in f.axes[:-1]], visible=False)
But I have no idea how to attach the histograms to the y axis and x axis like in the picture I posted above, and on top of that, how to vary the size of the graphs (ie make the scatter plot larger and the histograms smaller in comparison)
Seaborn is the way to go for quick statistical plots. But if you want to avoid another dependency you can use subplot2grid to place the subplots and the keywords sharex and sharey to make sure the axes are synchronized.
import numpy as np
import matplotlib.pyplot as plt
x = np.random.randn(100)
y = np.random.randn(100)
scatter_axes = plt.subplot2grid((3, 3), (1, 0), rowspan=2, colspan=2)
x_hist_axes = plt.subplot2grid((3, 3), (0, 0), colspan=2,
sharex=scatter_axes)
y_hist_axes = plt.subplot2grid((3, 3), (1, 2), rowspan=2,
sharey=scatter_axes)
scatter_axes.plot(x, y, '.')
x_hist_axes.hist(x)
y_hist_axes.hist(y, orientation='horizontal')
You should always look at the matplotlib gallery before asking how to plot something, chances are that it will save you a few keystrokes -- I mean you won't have to ask. There are actually two plots like this in the gallery. Unfortunately the code is old and does not take advantage of subplot2grid, the first one uses rectangles and the second one uses axes_grid, which is a somewhat weird beast. That's why I posted this answer.
I think it's hard to do this solely with matplotlib but you can use seaborn which has jointplot function.
import numpy as np
import pandas as pd
import seaborn as sns
sns.set(color_codes=True)
x = np.random.rand(1000,1)
y = np.random.rand(1000,1)
data = np.column_stack((x,y))
df = pd.DataFrame(data, columns=["x", "y"])
sns.jointplot(x="x", y="y", data=df);

Display two bar charts one by one in MATPLOTLIB

I am plotting bar charts using pivot tables. I have two independent pivot tables and need to produce two bar charts side-by-side and save it as a PNG image. Using this code, the chart is generated but it won't display as expected.
What I tried:
# Plotting Activity Begins
fig = plt.figure()
ax1 = fig.add_subplot(1, 2, 1)
ax2 = fig.add_subplot(2, 2, 1)
vig = task_frame.plot(kind="bar", figsize=(8, 6), stacked=True, width=0.3, rot=20)
print "ax1",ax1
print "vig",vig
vicky = issue_frame.plot(kind="bar", figsize=(8, 6), stacked=True, width=0.3, rot=90)
print "ax2",ax2
print "vicky",vicky
plt.ylim((0, 10))
plt.rcParams.update({'font.size': 10})
plt.savefig("/tmp/" + str(current_date) + ".png")
My print statement values:
ax1 Axes(0.125,0.1;0.352273x0.8)
vig Axes(0.125,0.1;0.775x0.8)
ax2 Axes(0.125,0.536364;0.352273x0.363636)
vicky Axes(0.125,0.1;0.775x0.8)
How can I display the charts as side-by-side pictures in a single image? Where should I assign the ax1 and ax2 value?
When you plot try to add axes instance to plot function, like here:
...
fig = plt.figure()
ax1 = fig.add_subplot(1, 2, 1)
ax2 = fig.add_subplot(2, 2, 1)
task_frame.plot(..., ax=ax1)
issue_frame.plot(..., ax=ax2)
...

Categories

Resources