How to Create Multiple Violin Plots in Matplotlib

When I first started visualizing complex datasets, I often relied on box plots to see the distribution of my data.

However, I quickly realized that box plots can hide important details, like whether a distribution has multiple peaks.

That is when I discovered violin plots in Matplotlib, which combine a box plot with a kernel density estimation.

In this tutorial, I will show you how to create and customize multiple violin plots to compare different datasets side-by-side.

Multiple Violin Plots

In my experience, comparing several groups at once is the most common task in data analysis.

For instance, you might want to compare the distribution of housing prices across different states like California, Texas, and Florida.

Using multiple violin plots allows you to see the median, the range, and the full “shape” of the data for every category simultaneously.

Method 1: Use the Basic plt.violinplot() with List Data

The easy way I have found to create multiple plots is by passing a list of arrays directly into the violinplot function.

This is perfect when you have distinct groups of data that you want to compare without much fuss.

In this example, let’s look at a hypothetical dataset of annual salaries for Software Engineers in three major US tech hubs: San Francisco, Austin, and New York City.

import matplotlib.pyplot as plt
import numpy as np

# Setting a seed for reproducible results
np.random.seed(42)

# Generating synthetic salary data for three US cities (in thousands)
sf_salaries = np.random.normal(150, 20, 200)
austin_salaries = np.random.normal(120, 15, 200)
nyc_salaries = np.random.normal(140, 25, 200)

# Combine into a list for plotting
data_to_plot = [sf_salaries, austin_salaries, nyc_salaries]

# Create the figure and axis
fig, ax = plt.subplots(figsize=(10, 6))

# Create multiple violin plots
# showmeans adds a marker for the average, showmedians adds a line for the middle value
vp = ax.violinplot(data_to_plot, showmeans=False, showmedians=True)

# Customizing the chart labels
ax.set_title('Salary Distribution by Tech Hub (USA)', fontsize=14)
ax.set_ylabel('Annual Salary (USD in Thousands)', fontsize=12)
ax.set_xticks([1, 2, 3])
ax.set_xticklabels(['San Francisco', 'Austin', 'New York City'])

# Adding a grid for better readability
ax.yaxis.grid(True, linestyle='--', alpha=0.7)

# Display the plot
plt.show()

I executed the above example code and added the screenshot below.

Create Multiple Violin Plots in Matplotlib

When I run this, Matplotlib automatically aligns the three violins along the x-axis.

I always set showmedians=True because it provides a clear reference point for the center of the distribution.

Method 2: Customize the Appearance of Each Violin

Sometimes, a plain blue plot isn’t enough to make a presentation pop. I like to customize the colors of my violins to make them more visually distinct, especially when presenting to stakeholders.

The violinplot function returns a dictionary containing the different parts of the plot, which you can iterate through to apply styles.

import matplotlib.pyplot as plt
import numpy as np

# Generating data: Commute times in minutes for Los Angeles vs. Chicago
la_commute = np.random.lognormal(3.5, 0.4, 300) 
chicago_commute = np.random.lognormal(3.3, 0.3, 300)

data = [la_commute, chicago_commute]

fig, ax = plt.subplots(figsize=(10, 6))
parts = ax.violinplot(data, showmeans=False, showmedians=True, showextrema=True)

# Changing the body color of the violins
colors = ['#3498db', '#e74c3c'] # Blue for LA, Red for Chicago
for i, pc in enumerate(parts['bodies']):
    pc.set_facecolor(colors[i])
    pc.set_edgecolor('black')
    pc.set_alpha(0.7)

# Customizing the center lines (cbars) and median lines (cmedians)
parts['cmedians'].set_edgecolor('black')
parts['cmins'].set_edgecolor('gray')
parts['cmaxes'].set_edgecolor('gray')

ax.set_title('Daily Commute Time Distribution: LA vs. Chicago', fontsize=14)
ax.set_xticks([1, 2])
ax.set_xticklabels(['Los Angeles', 'Chicago'])
ax.set_ylabel('Time in Minutes')

plt.show()

I executed the above example code and added the screenshot below.

How to Create Multiple Violin Plots in Matplotlib

I find that using set_facecolor through the bodies key is the most reliable way to handle multiple colors.

It gives you full control over the aesthetic, making the data much easier to digest at a glance.

Method 3: Handle Grouped Data with Pandas and Seaborn

While Matplotlib is powerful, I often use it alongside Pandas when I’m dealing with large CSV files.

If your data is in a “Long Format” (one column for the value and one for the category), you might find it easier to use the Seaborn wrapper for Matplotlib.

Let’s look at a US-specific example involving voter turnout percentages across different regions.

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

# Creating a sample DataFrame for US Regions
data = {
    'Region': ['Northeast']*100 + ['South']*100 + ['Midwest']*100 + ['West']*100,
    'Turnout': np.concatenate([
        np.random.normal(65, 5, 100), # Northeast
        np.random.normal(58, 8, 100), # South
        np.random.normal(62, 6, 100), # Midwest
        np.random.normal(60, 7, 100)  # West
    ])
}
df = pd.DataFrame(data)

# Using Seaborn to create the Matplotlib plot
plt.figure(figsize=(12, 7))
sns.violinplot(x='Region', y='Turnout', data=df, palette="Set2", inner="quartile")

plt.title('Voter Turnout Distribution by US Census Region', fontsize=15)
plt.xlabel('Region', fontsize=12)
plt.ylabel('Turnout Percentage (%)', fontsize=12)

plt.show()

I executed the above example code and added the screenshot below.

Create Multiple Matplotlib Violin Plots

The inner=”quartile” argument is one of my favorite features here.

It draws dashed lines inside the violin to show the 25th, 50th, and 75th percentiles, providing a wealth of information in one image.

Important Considerations for Your Plots

When you are plotting multiple violins, keep an eye on the sample size of each group.

If one city has 1,000 data points and another has only 10, the “width” of the violin can be misleading.

I usually normalize the width of the violins so they are comparable, regardless of the number of observations.

Another tip I’ve learned the hard way is to always label your axes clearly.

Without labels, a violin plot is just a series of shapes; with them, it’s a story about your data.

Advanced Customization: Horizontal Multiple Violins

Sometimes you have many categories, like all 50 US states. In that case, vertical plots become too crowded.

I prefer switching to a horizontal orientation to give the labels more room to breathe.

Simply set the vert parameter to False in the violinplot function.

import matplotlib.pyplot as plt
import numpy as np

# Fuel Efficiency (MPG) for different US Vehicle Classes
trucks = np.random.normal(18, 3, 150)
suvs = np.random.normal(22, 4, 150)
sedans = np.random.normal(30, 5, 150)
hybrids = np.random.normal(45, 6, 150)

labels = ['Trucks', 'SUVs', 'Sedans', 'Hybrids']
data = [trucks, suvs, sedans, hybrids]

fig, ax = plt.subplots(figsize=(10, 8))

# Setting vert=False makes the violins horizontal
ax.violinplot(data, vert=False, showmedians=True)

ax.set_yticks([1, 2, 3, 4])
ax.set_yticklabels(labels)
ax.set_xlabel('Miles Per Gallon (MPG)')
ax.set_title('US Vehicle Fuel Efficiency Distribution')

plt.tight_layout()
plt.show()

Horizontal plots are much easier to read when you have long category names.

I always use plt.tight_layout() at the end to ensure the labels don’t get cut off the edge of the figure.

Creating multiple violin plots in Matplotlib is a fantastic way to bring your data to life.

It takes a little more effort than a standard bar chart, but the insights you gain into the distribution and density of your data are well worth it.

You may also like to read:

51 Python Programs

51 PYTHON PROGRAMS PDF FREE

Download a FREE PDF (112 Pages) Containing 51 Useful Python Programs.

pyython developer roadmap

Aspiring to be a Python developer?

Download a FREE PDF on how to become a Python developer.

Let’s be friends

Be the first to know about sales and special discounts.