HOWTO · Seaborn

How to Create a Violin Plot Using Seaborn

This tutorial demonstrates how to create a violin plot using the Seaborn module in Python

On this page

A Seaborn violin plot shows the estimated distribution of a numeric variable. Its width represents density: wider regions indicate higher estimated density near those values. The inner marks summarize the data; they are not a display of every observation. The shape can suggest multiple peaks, but it should be read alongside the sample size and the underlying data.

Understand What a Violin Plot Shows

A violin plot combines a density shape with optional summary marks. The density is estimated from the observations, so it is a smoothed view rather than a histogram or a collection of raw points. Inner marks can show a box, quartiles, a stick for each observation, or no summary, depending on the inner setting.

The plot is useful for comparing the shape and spread of numeric distributions. It does not by itself establish why the data have that shape, and a small sample can make the estimated density look more certain or detailed than the observations support.

Plot a Single Variable

Pass a numeric sequence to violinplot() to plot one variable. This self-contained example uses a Python list directly, so it needs no array conversion. Install Seaborn and Matplotlib in your Python environment before running it. The code creates an Axes with the distribution; it does not print text output.

import matplotlib.pyplot as plt
import seaborn as sns

values = [4, 5, 5, 6, 6, 7, 8, 8, 9, 10]
ax = sns.violinplot(y=values, inner="quartile", color="skyblue")
ax.set_ylabel("Value")
ax.set_title("Distribution of values")
plt.show()

The vertical axis represents the values. A wider part of the violin indicates a higher estimated concentration near that value. When the sample is small, inspect the observations as well as the smoothed shape.

Compare Distributions Across Categories

For a categorical comparison, provide the numeric column through y and the category column through x. The example uses a pandas DataFrame and maps Price to y and Product to x, so the x-axis forms one category for each product. The call has no hue argument and does not add a day grouping.

import pandas as pd
import seaborn as sns

prices = pd.DataFrame(
    {
        "Price": [9, 10, 15, 16, 13, 14, 15, 18, 11, 12, 14, 15, 16, 17, 18, 19],
        "Product": ["A"] * 4 + ["B"] * 4 + ["A"] * 4 + ["B"] * 4,
    }
)
ax = sns.violinplot(data=prices, x="Product", y="Price")
ax.set_title("Price distribution by product")

Each violin summarizes the prices assigned to that product. To add a second grouping dimension, assign its column to hue; each hue level is then distinguished within the categories on the x-axis. Do not describe a grouping such as day unless the plotted data and arguments actually include it.

Customize a Violin Plot

The density estimate can be misleading when there are few observations. Overlay stripplot() to make the individual values visible and compare them with the smoothed shape. The points help you inspect the sample; they do not make a small sample more reliable.

import matplotlib.pyplot as plt
import seaborn as sns

values = [4, 5, 5, 6, 6, 7, 8, 8, 9, 10]
ax = sns.violinplot(y=values, inner=None, color="skyblue")
sns.stripplot(y=values, color="red", ax=ax)
ax.set_ylabel("Value")
plt.show()

Use order to choose the display order of categories, for example order=["B", "A"]. Use inner to control the summary marks: common choices include "box", "quartile", "stick", and None. A box-plot overlay can add a familiar summary, but it still represents the same sample and does not replace inspecting the observations.

Use the Returned Plot Object

violinplot() returns a Matplotlib Axes, which you can use to set labels, limits, and a title or to add other marks. For example, the single-variable example stores the result in ax and calls ax.set_ylabel() and ax.set_title().

For a figure-level categorical plot, use catplot(kind="violin", ...); it returns a FacetGrid. This interface is useful when you want to create separate panels with options such as row or col. Choose violinplot() for an axes-level plot and catplot() when you need the figure-level grid.