Siksha Sarovar

Siksha Sarovar (sikshasarovar.com) is a free educational web application that helps students in India learn programming and prepare for academic and competitive exams. The platform offers structured coding courses (C, C++, Python, Java, HTML, CSS, PHP, Power BI, AI, Machine Learning, Data Science), complete university curriculum notes for BCA/MCA students with previous year question papers, Class 10 and Class 12 CBSE/HBSE school notes, and dedicated preparation material for SSC, UPSC, Banking, Railway and other government exams. Browsing the site is completely free and requires no account. Users may optionally sign in with Google solely to save their learning progress, quiz scores and personal preferences across devices.

Privacy Policy | Terms of Service | Contact Siksha Sarovar | About Siksha Sarovar

v4.0.9 · PWA
Siksha Sarovar logo
Siksha Sarovar
Your Learning Universe

Siksha Sarovar is a free e-learning platform for coding courses, BCA university notes and competitive exam preparation. Optional Google sign-in saves your learning progress across devices.

Initializing knowledge base…
Compiling modules 0%

Unit 2 — Scatter Plots

Lesson 22 of 46 in the free Introduction to Data Analytics notes on Siksha Sarovar, written by Rohit Jangra.

Scatter Plots

A scatter plot displays the relationship between two numeric variables by plotting one point per observation at coordinates (x, y). It is the fundamental tool of bivariate analysis and the visual companion to the correlation coefficient.

What a Scatter Plot Reveals

PropertyWhat to look for
DirectionUpward slope = positive; downward = negative
FormLinear, curved (quadratic/exponential), or no pattern
StrengthTightly packed around a line = strong; widely scattered = weak
OutliersIsolated points far from the main cloud
ClustersDistinct groups of points → possible subgroups
HeteroscedasticityA fan/cone shape — variance changes across x (a regression assumption violation)
The most important case is E. A perfect U-shaped (parabolic) relationship has a Pearson correlation of approximately zero, because r measures only linear association. The scatter plot shows the relationship immediately; the correlation coefficient hides it completely. This is precisely why you plot before you compute.

Which Variable Goes Where

AxisVariable
X-axis (horizontal)Independent / explanatory / predictor variable
Y-axis (vertical)Dependent / response / outcome variable

Example: hours studied (x) vs marks scored (y) — study hours plausibly influence marks, not the reverse.

Python

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

np.random.seed(42)
hours = np.random.uniform(1, 12, 80)
marks = (5.5 * hours + 30 + np.random.normal(0, 6, 80)).clip(0, 100)

df = pd.DataFrame({"hours": hours, "marks": marks})

fig, ax = plt.subplots(figsize=(8, 5.5))
ax.scatter(df["hours"], df["marks"], color="#168B99", alpha=0.7,
           s=60, edgecolor="white")

# Add the least-squares trend line
m, c = np.polyfit(df["hours"], df["marks"], 1)
x_line = np.linspace(df["hours"].min(), df["hours"].max(), 100)
ax.plot(x_line, m * x_line + c, color="#ef4444", linewidth=2,
        label=f"y = {m:.2f}x + {c:.2f}")

r = df["hours"].corr(df["marks"])
ax.set_title(f"Study Hours vs Marks (r = {r:.3f})", fontsize=13, fontweight="bold")
ax.set_xlabel("Hours Studied per Week")
ax.set_ylabel("Marks Scored")
ax.legend()
ax.spines[["top", "right"]].set_visible(False)
plt.tight_layout()
plt.show()
# The four canonical patterns, side by side
np.random.seed(1)
n = 120
x = np.random.uniform(0, 10, n)

patterns = {
    "Strong Positive":  4 * x + np.random.normal(0, 2, n),
    "Weak Positive":    2 * x + np.random.normal(0, 12, n),
    "No Relationship":  np.random.normal(20, 8, n),
    "Non-linear (U)":   (x - 5) ** 2 + np.random.normal(0, 2, n),
}

fig, axes = plt.subplots(1, 4, figsize=(18, 4))
for ax, (name, y) in zip(axes, patterns.items()):
    ax.scatter(x, y, alpha=0.6, color="#168B99", s=35)
    ax.set_title(f"{name}\nr = {np.corrcoef(x, y)[0, 1]:.3f}")
    ax.set_xlabel("x")
plt.tight_layout()
plt.show()
# Note the U-shaped panel: r is near ZERO despite an obvious perfect relationship
# Adding more dimensions: colour (hue), size, and shape
tips = sns.load_dataset("tips")

fig, axes = plt.subplots(1, 3, figsize=(17, 4.5))

sns.scatterplot(data=tips, x="total_bill", y="tip", ax=axes[0], color="#168B99")
axes[0].set_title("Basic — 2 variables")

sns.scatterplot(data=tips, x="total_bill", y="tip", hue="time",
                style="smoker", ax=axes[1])
axes[1].set_title("4 variables via hue + style")

# BUBBLE CHART — size encodes a third numeric variable
sns.scatterplot(data=tips, x="total_bill", y="tip", size="size",
                sizes=(20, 300), hue="day", alpha=0.6, ax=axes[2])
axes[2].set_title("Bubble chart — size = party size")

plt.tight_layout()
plt.show()
# Regression plot with a 95% confidence band
plt.figure(figsize=(8, 5))
sns.regplot(data=tips, x="total_bill", y="tip",
            scatter_kws={"alpha": 0.5, "s": 45}, line_kws={"color": "#ef4444"})
plt.title("Tip vs Total Bill with Regression Line and 95% CI")
plt.show()

# Faceted: one scatter per category
sns.lmplot(data=tips, x="total_bill", y="tip", col="time", hue="smoker", height=4)
plt.show()

Handling Overplotting

With thousands of points, markers overlap and the plot becomes a solid blob. Fixes:

big = pd.DataFrame({
    "x": np.random.normal(0, 1, 20000),
    "y": np.random.normal(0, 1, 20000),
})

fig, axes = plt.subplots(1, 4, figsize=(19, 4))

axes[0].scatter(big["x"], big["y"], s=8)
axes[0].set_title("Overplotted — unreadable")

axes[1].scatter(big["x"], big["y"], s=8, alpha=0.03)
axes[1].set_title("Transparency (alpha)")

axes[2].hexbin(big["x"], big["y"], gridsize=40, cmap="viridis")
axes[2].set_title("Hexbin — binned density")

sample = big.sample(1500)
axes[3].scatter(sample["x"], sample["y"], s=12, alpha=0.5)
axes[3].set_title("Random subsample")

plt.tight_layout()
plt.show()
TechniqueHow it helps
Transparency (alpha)Dense regions appear darker
Smaller markersLess overlap
Hexbin / 2-D histogramAggregates points into coloured bins
Contour / density plotShows density as level curves
SamplingPlot a random subset
JitterSmall random offsets for discrete/rounded values

Scatter Plot Matrix (Pair Plot)

For k numeric variables, plot every pairwise scatter in a k×k grid, with distributions on the diagonal.

iris = sns.load_dataset("iris")
sns.pairplot(iris, hue="species", diag_kind="kde", height=2.2)
plt.suptitle("Scatter Plot Matrix — Iris Dataset", y=1.02)
plt.show()
# Instantly visible: petal_length and petal_width separate the three species cleanly.
# This single chart is why petal measurements dominate any Iris classifier (Unit 3).

Scatter Plots and Residual Analysis

A specialised scatter plot — residuals vs fitted values — is the standard diagnostic for regression (Unit 3):

from sklearn.linear_model import LinearRegression

X = tips[["total_bill"]]
y = tips["tip"]
model = LinearRegression().fit(X, y)
residuals = y - model.predict(X)

plt.figure(figsize=(8, 4.5))
plt.scatter(model.predict(X), residuals, alpha=0.6, color="#168B99")
plt.axhline(0, color="#ef4444", linestyle="--", linewidth=2)
plt.xlabel("Fitted values")
plt.ylabel("Residuals")
plt.title("Residual Plot — look for a random, patternless cloud")
plt.show()

How to read it:

Residual patternDiagnosis
Random cloud around zeroModel assumptions satisfied ✓
Curved patternRelationship is non-linear — add a polynomial term
Funnel/cone shapeHeteroscedasticity — try a log transform or weighted regression
Points far from zeroOutliers with high influence

Chart Selection Recap

Number of numeric variablesChart
1Histogram, box plot, density plot
2Scatter plot
3Bubble chart (size), 3-D scatter, scatter with hue
4+Pair plot, correlation heatmap, PCA projection

Scatter plots show apparent relationships. The final lesson of this unit provides the formal machinery for deciding whether an apparent pattern is real: hypothesis testing.