Reputation: 105
I am plotting boxplot in logscale using pyplot.boxplots and then I want to do swarmplot/strip plot on top of it using seaborn. However the seaborn messes us the entire scale and plots very absurdly. Any idea how I can give custom position in seaborn?
att1= np.sort(np.unique(df1.att1))
w = 0.085
width = lambda p, w: 10 ** (np.log10(p) + w / 2.) - 10 ** (np.log10(p) - w / 2.)
custom_widths = width(freqns, w)
ax.boxplot([df1[df1.att1== xi].att2 for xi in att1], positions=att1,
boxprops={'facecolor': 'none'}, medianprops={'color': 'black'}, patch_artist=True,
widths=custom_widths)
ax.set_xscale("log")
fig.set_size_inches(10.5, 8)
means = [np.median(df1[df1.Frequency == xi].CapDensity) for xi in freqs]
plt.plot(freqns, means, '--k*', lw=1.2)
This is image w/o strip plot:
sns.stripplot(x="Frequency", y="CapDensity",data=df1, edgecolor="black", linewidth=.3, jitter=0.1, zorder=0.5, ax=ax)
This is when I do strip plot on top of boxplot.
Upvotes: 1
Views: 689
Reputation: 80509
The problem is that you use att1
as positions for the boxplots, while seaborn will always put a stripplot at internal positions 0,1,2,3,...
. The easiest solution would be to also create the stripplot via matplotlib. (A swarmplot would be much more complicated to create.)
Supposing you have similar data as your previous question, such a plot could be created as:
from matplotlib import pyplot as plt
import numpy as np
import pandas as pd
df = pd.DataFrame({'x': np.random.choice([1, 3, 5, 8, 10, 30, 50, 100], 500),
'y': np.random.normal(750, 20, 500)})
xvals = np.unique(df.x)
w = 0.085
width = lambda p, w: 10 ** (np.log10(p) + w / 2.) - 10 ** (np.log10(p) - w / 2.)
custom_widths = width(xvals, w)
fig, ax = plt.subplots(figsize=(12, 4))
ax.set_xscale('log')
ax.boxplot([df[df.x == xi].y for xi in xvals],
positions=xvals, showfliers=False,
boxprops={'facecolor': 'none'}, medianprops={'color': 'black'}, patch_artist=True,
widths=custom_widths)
medians = [np.median(df[df.x == xi].y) for xi in xvals]
ax.plot(xvals, medians, '--k*', lw=2)
ax.set_xticks(xvals)
for xi, wi in zip(xvals, custom_widths):
yis = df[df.x == xi].y
ax.scatter(xi + np.random.uniform(-wi / 2, wi / 2, yis.size), yis)
plt.show()
Upvotes: 2