Univariate Plots in Python
Plots for one variable at a time are the first visual step of EDA. We use the wine dataset.
# 1) Bar plot: how many wines per quality score
quality_counts = df["quality"].value_counts().sort_index()
plt.figure(figsize=(8, 5))
plt.bar(quality_counts.index, quality_counts.values, color="deeppink")
plt.title("Count Plot of Quality")
plt.xlabel("Quality")
plt.ylabel("Count")
plt.show()
# 2) Histogram + KDE for every numeric column, with skewness in the title
num_cols = df.select_dtypes(include=["int64", "float64"]).columns
plt.figure(figsize=(14, len(num_cols) * 3))
for i, col in enumerate(num_cols, 1):
plt.subplot(len(num_cols), 2, i)
sns.histplot(df[col], kde=True)
plt.title(f"{col} | Skewness: {round(df[col].skew(), 2)}")
plt.tight_layout()
plt.show()
# 3) Swarm plot to spot outliers
plt.figure(figsize=(8, 8))
sns.swarmplot(y="alcohol", data=df, color="skyblue")
plt.title("Swarm Plot of Alcohol")
plt.show()
1. Bar plot - count of each quality score
A bar plot compares categories or discrete values. In WineQT most wines score 5 or 6; very few score 3 or 8. This tells us the target is imbalanced, which matters later for classification (accuracy can be misleading; use F1 or class weights).
Tip: for many long category names use a horizontal bar chart (plt.barh).
2. Histogram with KDE - shape of the distribution
- The histogram groups values into bins; bar height = how many values fall in the bin.
- The KDE (Kernel Density Estimate) line is a smooth curve of the same distribution.
- Try different
binsvalues; too few hides detail and too many shows noise.
Reading skewness
| Skewness | Shape | Meaning |
|---|---|---|
| about 0 | symmetric | mean is close to median |
| greater than 0 | right (positive) skew | long tail to the right, some very high values |
| less than 0 | left (negative) skew | long tail to the left, some very low values |
Rule of thumb: absolute skewness above about 1 is strong. Columns like chlorides and residual sugar in the wine data are strongly right-skewed and usually benefit from a log transform.
3. Swarm plot - every point, and outliers
A swarm plot draws each observation as a point, spreading them sideways so they do not overlap. Dense areas show where most values sit; isolated points far from the crowd are potential outliers.
Swarm plots are great for up to a few hundred points. For large data (thousands of rows) use a box plot, strip plot with alpha, or a violin plot, because the swarm becomes slow and crowded.
Other useful univariate plots
sns.boxplot(x=df["alcohol"]) # median, IQR, outliers
sns.violinplot(y=df["alcohol"]) # shape + box in one
sns.kdeplot(df["alcohol"], fill=True) # smooth density
sns.ecdfplot(df["alcohol"]) # cumulative distribution
df["quality"].value_counts().plot.pie(autopct="%1.1f%%") # few categories only
Checklist when you see a univariate plot
- Is it symmetric or skewed?
- Is there one peak (unimodal) or more (multimodal - hint of hidden groups)?
- Are there gaps or spikes (data-entry patterns, rounding)?
- Are there extreme values? Are they errors or real?
- What transformation, if any, would help?