devnotes.

Bivariate and Multivariate Plots in Python

Bivariate and Multivariate Plots in Python

When we plot two or more variables together, patterns between them appear.

# Keep a string copy so the original numeric column is not destroyed
df["quality_cat"] = df["quality"].astype(str)
order = sorted(df["quality_cat"].unique())

# Violin plot
plt.figure(figsize=(9, 6))
sns.violinplot(x="quality_cat", y="alcohol", data=df, order=order, palette="pastel")
plt.title("Violin Plot: Quality vs Alcohol")
plt.show()

# Box plot
plt.figure(figsize=(9, 6))
sns.boxplot(x="quality_cat", y="alcohol", data=df, order=order)
plt.title("Box Plot: Quality vs Alcohol")
plt.show()

# Pair plot on a few columns (all columns would be very slow)
sns.pairplot(df[["alcohol", "sulphates", "density", "quality"]], hue="quality", palette="viridis")
plt.show()

Note that we created quality_cat (a text copy) instead of overwriting quality. Converting the original column to string would break later steps such as df.corr().

1. Violin plot - distribution per group

A violin plot draws a mirrored density curve for each group, with a small box plot inside.

How to read it:

  • Wider section = more data points at that value (higher density).
  • Symmetric shape = balanced distribution; a lopsided one = skew.
  • Bulge / peak = most common value; two bulges = two sub-groups.
  • Long thin tails = large variability / possible outliers.
  • Inner line = the median.

Example insight: the alcohol violin for quality 8 sits higher than for quality 5, suggesting better wines tend to have more alcohol.

2. Box plot - five-number summary per group

A box plot shows: minimum (lower whisker), Q1, median, Q3, maximum (upper whisker), and dots for outliers.

  • The box is the IQR (Q3 - Q1): a taller box means more variability.
  • The line inside is the median.
  • Whiskers reach to the furthest value within 1.5 x IQR.
  • Dots beyond the whiskers are outliers.
  • Compare several boxes side by side to see how groups differ.

Use a box plot when you have many groups and want a compact, robust comparison; use a violin when the shape matters (for example, two humps).

3. Pair plot - all pairs at once

sns.pairplot builds a grid:

  • Diagonal: histogram or KDE of each variable (distribution and skew).
  • Off-diagonal: scatter plot of every pair (relationships).
  • Upper and lower triangles are mirror images (the same pair with axes swapped).
  • Adding hue="quality" colours points by group, turning it into a multivariate view.

What to look for: straight-line patterns (linear relationships), clusters, curves, and isolated points. With more than about 8 columns the grid gets unreadable and slow - pick a subset first.

Bonus: scatter plot with extra dimensions

sns.scatterplot(
    data=df, x="alcohol", y="density",
    hue="quality",        # colour  = 3rd variable
    size="sulphates",     # size    = 4th variable
    alpha=0.7,
)
plt.show()

Mini exercise

  1. Draw a box plot of volatile acidity per quality_cat. Does it go up or down with quality?
  2. Which of the two features, alcohol or volatile acidity, separates quality levels better?
Bivariate and Multivariate Plots in Python | Exploratory Data Analysis | DevNotes