Getting empty plots when using subplots in matplotlib - python

I am having a problem using subplots in matplotlib. I am getting empty plots when using subplots. What is wrong with my implementation?
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
fig = plt.figure(figsize=(15,20))
ax = 1
for column in passenger_train_df.columns.values.tolist():
if column != 'Survived':
fig.add_subplot(4, 3, ax)
if column == 'Age':
age_binned=pd.cut(passenger_train_df['Age'], 10)
age_binned.sort_values(inplace=True)
table= pd.crosstab(age_binned, passenger_train_df['Survived'])
elif column == 'Fare':
fare_binned=pd.cut(passenger_train_df['Fare'], 10)
fare_binned.sort_values(inplace=True)
table= pd.crosstab(fare_binned, passenger_train_df['Survived'])
else:
table= pd.crosstab(passenger_train_df[column], passenger_train_df['Survived'])
table.div(table.sum(1).astype(float), axis=0).plot(kind='bar', stacked=True)
ax+=1

You need to return the axes that is created when you use fig.add_subplot(4, 3, ax). You then need to pass this as an argument into the plot function:
So change fig.add_subplot(4, 3, ax) to
axes = fig.add_subplot(4, 3, ax)
And then when you plot, pass in axes as an argument using ax=:
table.div(table.sum(1).astype(float), axis=0).plot(kind='bar', stacked=True, ax=axes)

Related

Matplotlib subplot not plotting

I have the following code:
import pandas.util.testing as testing
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import matplotlib as mpl
df = testing.makeTimeDataFrame(freq='MS')
with mpl.rc_context(rc={'font.family': 'serif', 'font.weight': 'bold', 'font.size': 12}):
fig = plt.figure(figsize= (12, 6))
fig.add_subplot(2, 2, (1,2))
ax2 = ax.twinx()
df['A'].plot(ax=ax, color = 'g')
df['B'].plot(ax=ax2, color ='g')
fig.add_subplot(223)
df['C'].plot(color='r')
fig.add_subplot(224)
df['D'].plot()
fig.tight_layout()
plt.show()
Which produces the following plot.
I am trying to plot df['A'] and df['B'] on the same top plot. Could you please advise what I have overlooked?
one little detail is missing. before calling twinx you need to assign ax to the first subplot. Then it'll work.
ax = fig.add_subplot(2, 2, (1,2))

Get pandas boxplot in one plot and matplotlib plot in another figure

import pandas as pd
import matplotlib.pyplot as plt
def csv_til_liste(filnavn):
occuDF = pd.read_csv(filnavn)
occuList=occuDF.values.tolist()
return occuDF, occuList
occuDF, occuList = csv_til_liste("occupancy.csv")
plt.figure(1)
occuDF.boxplot(column = 'Temperature', by = 'Occupancy')
plt.suptitle('')
x=(1, 2, 3, 4, 5)
y=(1,2,3,4,5)
plt.figure(2)
plt.plot(x,y)
plt.show()
When I run the program, the two plots are plotted in one figure, but I want them in two separate figures.
The pandas.DataFrame.boxplot takes an ax parameter, as written in the docs.
So you can use:
fig1 = plt.figure()
ax1 = fig1.add_subplot(1, 1, 1)
occuDF.boxplot(column = 'Temperature', by = 'Occupancy', ax=ax1)
plt.suptitle('')
x=(1, 2, 3, 4, 5)
y=(1,2,3,4,5)
fig2 = plt.figure(2)
ax2 = fig2.add_subplot(1, 1, 1)
ax2.plot(x,y)
plt.show()
Otherwise, you can plot in different subplots of the same figure by applying minimal changes.

Set xlim in heatmap with subplots and annotation

I would like to plot several heatmaps side by side, with annotations.
For this, I use subplots and I can plot each heatmap in its axes using the ax kwarg.
The issue is when I use xlim : it's applied to the heatmap, but not the annotation :
Here is the code :
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
values = np.random.random((7,24)) # create (7,24) shape array
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(30,10)) # create 2 columns for subplots
ax1 = sns.heatmap(values, annot=True, ax=ax1) # heatmap with annotation
ax1.set(xlim=(12,22)) # works fine with this line commented
# ax1.set_xlim(12,22)
# ax2 = sns.heatmap(values, annot=True, ax=ax2) # second heatmap
plt.show()
And it gets worse with a second heatmap, because the annotation from the second heatmap are ploted on the first heatmap.
How can I limit x axis to (12,22) while using annotation ?
matplotlib 2.2.2
seaborn 0.9.0
python 3.6.5
Why not providing the slice of interest in the first place and relabel the x-axis?
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
np.random.seed(1234)
values = np.random.random((7,24)) # create (7,24) shape array # create (7,24) shape array ) # create (7,24) shape array
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(21,7)) # create 2 columns for subplots
#full heatmap
sns.heatmap(values, annot=True, ax=ax1)
#slice of interest
start=12
stop=22
sns.heatmap(values[:, start:stop+1], annot=True, ax=ax2, xticklabels = np.arange(start, stop+1)) # second heatmap
plt.show()
Sample output
After posting this issue on seaborn github, here is the official answer :
matplotlib text objects are not automatically clipped when they are
placed outside of the axes limits; you can turn that on by passing
annot_kws=dict(clip_on=True) to heatmap, though.
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
values = np.random.random((7,24)) # create (7,24) shape array
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(30,10)) # create 2 columns for subplots
ax1 = sns.heatmap(values, annot=True, ax=ax1, annot_kws=dict(clip_on=True)) # heatmap with annotation
ax1.set(xlim=(12,22)) # works fine with this line commented
# ax1.set_xlim(12,22)
ax2 = sns.heatmap(values, annot=True, ax=ax2, annot_kws=dict(clip_on=True)) # second heatmap
ax2.set(xlim=(12,22))
plt.show()
clip_on=True will remove everithing that is outside the axe

Creating charts with Pandas

My code is inside a Jupyter Notebook.
I can create a chart using Method 1 below, and have it look exactly as I'd like it to look.
But when I try with Method 2, which uses subplot, I don't know how to make it look the same (setting the figsize, colors, legend off to the right).
How do I use subplot, and have it look the same as Method 1?
Thank you in advance for your help!
# Using Numpy and Pandas
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.style as style
df = pd.DataFrame(np.random.randint(0,100,size=(4, 4)), columns=list('ABCD'))
style.use('fivethirtyeight')
# Colorblind-friendly colors
colors = [[0,0,0], [230/255,159/255,0], [86/255,180/255,233/255], [0,158/255,115/255]]
# Method 1
chart = df.plot(figsize = (10,5), color = colors)
chart.yaxis.label.set_visible(True)
chart.set_ylabel("Bitcoin Price")
chart.set_xlabel("Time")
chart.legend(bbox_to_anchor=(1.05, 1), loc=2)
plt.show()
# Method 2
fig, ax = plt.subplots()
ax.plot(df)
ax.set_ylabel("Bitcoin Price")
ax.set_xlabel("Time")
plt.show()
You just replace char by ax, like this
ax.yaxis.label.set_visible(True)
ax.set_ylabel("Bitcoin Price") ax.set_xlabel("Time") ax.legend(bbox_to_anchor=(1.05, 1), loc=2)
I'm thinking of two ways to get a result that might be useful for you. pd.DataFrame.plot returns an Axes object you can pass all the methods you want, so both examples just replace chart for ax.
Setup
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.style as style
df = pd.DataFrame(np.random.randint(0,100,size=(4, 4)), columns=list('ABCD'))
style.use('fivethirtyeight')
# Colorblind-friendly colors
colors = [[0,0,0], [230/255,159/255,0], [86/255,180/255,233/255], [0,158/255,115/255]]
Iterating over df
colors_gen = (x for x in colors) # we will also be iterating over the colors
fig, ax = plt.subplots(figsize = (10,5))
for i in df: # iterate over columns...
ax.plot(df[i], color=next(colors_gen)) # and plot one at a time
ax.set_ylabel("Bitcoin Price")
ax.set_xlabel("Time")
ax.legend(bbox_to_anchor=(1.05, 1), loc=2)
ax.yaxis.label.set_visible(True)
plt.show()
Use pd.DataFrame.plot but pass ax as an argument
fig, ax = plt.subplots(figsize = (10,5))
df.plot(color=colors, ax=ax)
ax.set_ylabel("Bitcoin Price")
ax.set_xlabel("Time")
ax.legend(bbox_to_anchor=(1.05, 1), loc=2)
ax.yaxis.label.set_visible(True)
plt.show()

Share axes in matplotlib for only part of the subplots

I am having a big plot where I initiated with:
import numpy as np
import matplotlib.pyplot as plt
fig, axs = plt.subplots(5, 4)
And I want to do share-x-axis between column 1 and 2; and do the same between column 3 and 4. However, column 1 and 2 does not share the same axis with column 3 and 4.
I was wondering that would there be anyway to do this, and not sharex=True and sharey=True across all figures?
PS: This tutorial does not help too much, because it is only about sharing x/y within each row/column; they cannot do axis sharing between different rows/columns (unless share them across all axes).
I'm not exactly sure what you want to achieve from your question. However, you can specify per subplot which axis it should share with which subplot when adding a subplot to your figure.
This can be done via:
import matplotlib.pylab as plt
fig = plt.figure()
ax1 = fig.add_subplot(5, 4, 1)
ax2 = fig.add_subplot(5, 4, 2, sharex = ax1)
ax3 = fig.add_subplot(5, 4, 3, sharex = ax1, sharey = ax1)
A slightly limited but much simpler option is available for subplots. The limitation is there for a complete row or column of subplots.
For example, if one wants to have common y axis for all the subplots but common x axis only for individual columns in a 3x2 subplot, one could specify it as:
import matplotlib.pyplot as plt
fig, ax = plt.subplots(3, 2, sharey=True, sharex='col')
One can manually manage axes sharing using a Grouper object, which can be accessed via ax._shared_x_axes and ax._shared_y_axes. For example,
import matplotlib.pyplot as plt
def set_share_axes(axs, target=None, sharex=False, sharey=False):
if target is None:
target = axs.flat[0]
# Manage share using grouper objects
for ax in axs.flat:
if sharex:
target._shared_x_axes.join(target, ax)
if sharey:
target._shared_y_axes.join(target, ax)
# Turn off x tick labels and offset text for all but the bottom row
if sharex and axs.ndim > 1:
for ax in axs[:-1,:].flat:
ax.xaxis.set_tick_params(which='both', labelbottom=False, labeltop=False)
ax.xaxis.offsetText.set_visible(False)
# Turn off y tick labels and offset text for all but the left most column
if sharey and axs.ndim > 1:
for ax in axs[:,1:].flat:
ax.yaxis.set_tick_params(which='both', labelleft=False, labelright=False)
ax.yaxis.offsetText.set_visible(False)
fig, axs = plt.subplots(5, 4)
set_share_axes(axs[:,:2], sharex=True)
set_share_axes(axs[:,2:], sharex=True)
To adjust the spacing between subplots in a grouped manner, please refer to this question.
I used Axes.sharex /sharey in a similar setting
https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.sharex.html#matplotlib.axes.Axes.sharex
import matplotlib.pyplot as plt
fig, axd = plt.subplot_mosaic([list(range(3))] +[['A']*3, ['B']*3])
axd[0].plot([0,0.2])
axd['A'].plot([1,2,3])
axd['B'].plot([1,2,3,4,5])
axd['B'].sharex(axd['A'])
for i in [1,2]:
axd[i].sharey(axd[0])
plt.show()

Categories

Resources