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 overwritingquality. Converting the original column to string would break later steps such asdf.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
- Draw a box plot of
volatile acidityperquality_cat. Does it go up or down with quality? - Which of the two features, alcohol or volatile acidity, separates quality levels better?