Reputation: 77
I'm trying to plot a selection of box-and-whisker subplots with a visible y axis only on the left hand plots. I'm looping through pandas dataframes to do this. However, the despine function I'm using to remove axes appears to apply to all plots whenever it is used. In this case, the final subplot should have no y axis, but the axis is also removed from the left hand side plots. Is there any way to get around this?
Is it possible to insulate each subplot from the despine function applied on the others? This only seems to happen for the despine function. Current code is below but I have also tried creating specific axes both before the loop (using [fig, axes = plt.subplots(ncols=3, nrows=4)]) and within the loop (ax = plt.subplot(4,3,q+1), then trying to call ax=ax in seaborn plotting functions).
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
sns.set(rc={"figure.figsize":(10,20)}, font_scale=1) # set size of plots and font
sns.set_style("ticks", {"font.sans-serif": "Arial"}) # set style for plots
sns.set_palette("cubehelix", n_colors=len(participants)) # set colour palette for individual datapoints
plt.figure
for q in range(11):
plt.subplot(4,3,q+1)
qplot = sns.swarmplot(data=eval("s" + str(q+1)), x="variable", y="value", hue="Participant", size=3) # plot individual participant data as points
qplot.legend().set_visible(False) # hide the legend for individual participant data
qplot = sns.boxplot(data=eval("s" + str(q+1)), x="variable", y="value", palette="Greys", linewidth=2, fliersize=0, width=0.85) # plot the boxplot
qplot.set(ylim=(-3.5,3.5), xlabel="Condition", ylabel="Response") # set y axis values and label axes
plt.title("S" + str(q+1)) # add a title
if (q == 0) or (q == 3) or (q == 6):
qplot.set(xticklabels=[], xlabel=None, xticks = []) # remove ticks and labels
sns.despine(bottom = True, top=True, right=True, left=False, trim=True) # remove spines
if (q == 1) or (q == 2) or (q == 4) or (q == 5) or (q == 7):
qplot.set(xticklabels=[], xlabel=None, xticks = [], yticklabels=[], ylabel = None, yticks = []) # remove ticks and labels
sns.despine(bottom = True, top=True, right=True, left=True, trim=True) # remove spines
if (q == 9):
sns.despine(top=True, right = True,trim=True) # remove spines
if (q == 8) or (q == 10):
qplot.set(yticks = [], yticklabels=[], ylabel = None) # remove ticks and labels
sns.despine(bottom=True, top=True, left=True, right=True, trim=True) # remove spines
for axis in ["top","bottom","left","right"]:
qplot.spines[axis].set_linewidth(2) # set linewidth of axes
qplot.tick_params(axis = "x", width=0) # set linewidth of x ticks to zero
qplot.tick_params(axis = "y", width=2) # set linewidth of y ticks
Upvotes: 3
Views: 5058
Reputation: 40667
For future answer-seekers who would stumble upon this question, you could do something like the following to show/hide the spines in a grid of axes using sns.despine()
:
fig, axs = plt.subplots(4,3)
for ax in axs.flat:
if ax.is_first_col():
if ax.is_last_row():
sns.despine(bottom=False, left=False, ax=ax)
else:
sns.despine(bottom=True, left=False, ax=ax)
elif ax.is_last_row():
sns.despine(bottom=False, left=True, ax=ax)
else:
sns.despine(bottom=True, left=True, ax=ax)
@PaulH was kind enough to refactor the code above. His version is much more compact and easier to read:
fig, axs = plt.subplots(4,3)
for ax in axs.flat:
sns.despine(bottom=not ax.is_last_row(), left=not ax.is_first_col(), ax=ax)
Upvotes: 3