Reputation: 1
I want to create a double violin plot with custom markers for each thing. So far, I have successfully been able to create the violin plot
However, when I add the scatter of the various markers on top it ruins everything about the violin plot (you can see the shading of the violin plots off to the left).
I was wondering how to overlay the two.
I've included my code below (violin plots made by commenting out all the ax.scatter lines)
def plot_psd(centralised_frequencies,centralised_psds,distributed_frequencies,distributed_psds):
fig,ax=plt.subplots(1,1,figsize=(10,5))
add_label(ax.violinplot(centralised_psds,side='high',showmeans=False,showmedians=False,showextrema=False), "Centralised Control")
ax.set_xticklabels(centralised_frequencies)
add_label(ax.violinplot(distributed_psds,side='low',showmeans=False,showmedians=False,showextrema=False), "Distributed Control")
ax.set_xticklabels(distributed_frequencies)
ax.scatter(centralised_frequencies,np.mean(centralised_psds,1),marker=markers.CARETLEFTBASE,color='r')
ax.scatter(centralised_frequencies,np.min(centralised_psds,1),marker=markers.TICKLEFT,color='r')
ax.scatter(centralised_frequencies,np.max(centralised_psds,1),marker=markers.TICKLEFT,color='r')
ax.scatter(distributed_frequencies,np.mean(distributed_psds,1),marker=markers.CARETRIGHTBASE,color='b')
ax.scatter(distributed_frequencies,np.min(distributed_psds,1),marker=markers.TICKRIGHT,color='b')
ax.scatter(distributed_frequencies,np.max(distributed_psds,1),marker=markers.TICKRIGHT,color='b')
ax.legend(*zip(*labels))
ax.set_xlabel("Frequency (Hz)")
ax.set_ylabel("PSD*Freq")
ax.set_xlabel("Frequency (Hz)")
ax.set_ylabel("PSD*Freq")
ax.set_title("Centralised Control")
ax.set_title("Distributed Control")
fig.savefig("6_Results/clean_data/psd.png")
plt.clf()
plt.close()
I've tried changing the x-ticker and axis stuff several times and it always just returns to this and nothing works.
Upvotes: 0
Views: 99
Reputation: 69116
The problem is in the way you are setting the tick labels. Notice that your x axis labels are all out of order.
When you use ax.set_xticklabels()
to change the values on the x-axis, you have decoupled the x axis ticks from their labels.
By default, ax.violinplot
will automatically choose the x positions of the violins to be integer values (1, 2, 3, etc), with a default violin width of 0.5.
You have then changed the labels of those ticks to some new values, but the underlying position on the axes does not know what those labels are.
So, when you then use your scatterplot later, it plots on the real values of the axes, and your violins get shunted over to the left.
Consider this minimal example showing 3 ways of plotting violins
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(19680801)
data = [sorted(np.random.normal(0, std, 100)) for std in range(1, 5)]
fig, (ax1, ax2, ax3) = plt.subplots(ncols=3, figsize=(15, 5))
ax1.violinplot(data)
ax1.set_title('default labels')
ax2.violinplot(data)
ax2.set_xticklabels([100, 200, 300, 400, 500])
ax2.set_title('decoupled labels')
ax3.violinplot(data, positions=[50, 60, 70, 80], widths=5)
ax3.set_title('correctly modified labels')
plt.show()
As you can see, by setting the positions
and width
of our violins properly in ax3
, we have not had to set the x axis labels ourselves, these are now set to whatever you want them to be.
So the solution for you is to define whatever position you want your violins to be in, then set them with positions
before you add your scatterplot on top. This appears to be what you call centralised_frequencies
and distributed_frequencies
. e.g.:
ax.violinplot(centralised_psds, positions=centralised_frequencies, widths=X,
side='high', showmeans=False, showmedians=False,
showextrema=False)
ax.violinplot(distributed_psds, positions=distributed_frequencies, widths=X,
side='low', showmeans=False, showmedians=False,
showextrema=False)
Since your current axes labels are a bit mixed up, it's hard to estimate what the widths should be (X
in the code above), so you will probably want to experiment to find that. I would start somewhere around widths=10
and modify from there.
Upvotes: 0