1

I have a dataset that looks like

    x       y
    0.07    0.400000
    0.07    0.171429
    0.08    0.214286
    0.08    0.214286
    0.08    0.214286
    0.09    0.142857
    0.09    0.571429
    0.09    0.071429
    0.09    0.271429
    0.10    0.342857

I want to plot a violin plot for a given range of x, for example from 0.07 to 0.08 and then from 0.09 to 0.1

I'm using

ax = sns.violinplot(x="x", y="y", data=df)

Which, obviously gives me a violin plot per value of x. Using the data above I would get, 4 plots.

John Rotenstein
  • 241,921
  • 22
  • 380
  • 470
ziulfer
  • 1,339
  • 5
  • 18
  • 30
  • Does this answer your question? [Process pandas dataframe into violinplot](https://stackoverflow.com/questions/43345599/process-pandas-dataframe-into-violinplot) – Ch3steR Jul 28 '20 at 18:40

1 Answers1

3

You could try pandas' cut to put the data into bins. These bins can be added to a new column:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

df = pd.DataFrame({'x': np.random.randint(6, 13, 50) * 0.01,
                   'y': np.random.uniform(0, 1, 50)})
ranges = np.arange(0.055, 0.14, 0.02)
ax = sns.violinplot(x=pd.cut(df.x, ranges), y='y', data=df)
ax.set_xticklabels([f'{r + 0.005:.2f}-{r + 0.015:.2f}' for r in ranges[:-1]])
plt.show()

example plot

PS: An adaption to address the additional questions in the comments:

df = pd.DataFrame({'x': np.random.randint(6, 13, 50) * 0.01,
                   'y': np.random.uniform(0, 1, 50)})
ranges = np.append(0.055, np.arange(0.065, 0.14, 0.02))
df['category'] = pd.cut(df.x, ranges)
counts = df.groupby(['category'])['x'].count()

ax = sns.violinplot(x='category', y='y', data=df, palette='Greens')
labels = ['0.06'] + [f'{r + 0.005:.2f}-{r + 0.015:.2f}' for r in ranges[1:-1]]
ax.set_xticklabels([f'{label}\n({count / sum(counts) * 100:.1f} %)' for label, count in zip(labels, counts)])
plt.tight_layout()
plt.show()

resulting plot

To add the percentages on the violins:

counts = df.groupby(['category'])['x'].count()
means = df.groupby(['category'])['y'].mean()
for i, (mean, count) in enumerate(zip(means, counts)):
    ax.text(i, mean, f'{count/sum(counts)*100} %', ha='center', va='center', color='r')
JohanC
  • 71,591
  • 8
  • 33
  • 66
  • That's great! Thanks. Is there a way to specify the first only bin with a smaller range? Also, how to add the percentage of the total values present in each violin? – ziulfer Jul 28 '20 at 20:02
  • Thank you very much for the editing. I was looking for an option in which I could add the percentage on the violinplot, something like this: https://python-graph-gallery.com/58-show-number-of-observation-on-violinplot/ here however they added the number of observation, I tried to use that for the percentage but got wrong numbers (too low values) – ziulfer Jul 28 '20 at 21:28