> ## Documentation Index
> Fetch the complete documentation index at: https://fastapi2day.codewithsiva.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Data Visualization Guide: Uni, Bi & Multivariate Analysis

> A practical guide to univariate, bivariate, and multivariate analysis using Matplotlib and Seaborn on a student performance dataset.

Choosing the right chart for your data is one of the most important skills in data science. The wrong visualization can hide patterns or mislead your audience; the right one can reveal insights that tables of numbers never could. This guide walks through the three tiers of analysis — **univariate** (one variable), **bivariate** (two variables), and **multivariate** (three or more variables) — using a student performance dataset as a concrete, running example. By the end, you'll have a repeatable playbook for exploring any new dataset you encounter.

## Setup and Loading Data

```python theme={null}
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

# Set a consistent global style for all charts
sns.set_theme(style="whitegrid", palette="muted")

# Load the student performance dataset
df = pd.read_csv('student_dataset.csv')

# Quick sanity check
print(df.shape)
df.head()
```

The dataset contains one row per student with columns including `study_hours`, `exam_score`, `attendance`, `sleep_hours`, and `placement_status`.

## 1. Univariate Analysis

Univariate analysis examines **one variable at a time** — its distribution, frequency, and spread — without considering its relationship to any other variable.

### Numerical Columns: Histograms with KDE

For continuous variables like `study_hours` or `exam_score`, a histogram with a KDE (density) curve reveals the shape of the distribution:

```python theme={null}
plt.figure(figsize=(7, 4))
sns.histplot(data=df, x="study_hours", kde=True, color="teal")
plt.title("Univariate Analysis: Distribution of Weekly Study Hours")
plt.xlabel("Study Hours per Week")
plt.ylabel("Number of Students")
plt.show()
```

Look for:

* **Symmetry** — is the distribution bell-shaped or skewed?
* **Outliers** — are there isolated bars far from the main cluster?
* **Spread** — is the distribution narrow (consistent students) or wide (highly variable)?

### Categorical Columns: Count Plots

For discrete labels like `placement_status`, a count plot shows the frequency of each category:

```python theme={null}
plt.figure(figsize=(5, 4))
sns.countplot(data=df, x="placement_status", palette="pastel")
plt.title("Univariate Analysis: Student Placement Counts")
plt.xlabel("Placement Status")
plt.ylabel("Student Count")
plt.show()
```

<Tip>
  Always start every data exploration session with univariate analysis. Understanding individual distributions first prevents you from misinterpreting bivariate relationships later.
</Tip>

## 2. Bivariate Analysis

Bivariate analysis studies **how two variables relate** to each other — identifying correlations, group differences, and conditional patterns.

### Numerical vs. Numerical: Scatter Plots

To see whether more study hours are associated with higher exam scores:

```python theme={null}
plt.figure(figsize=(7, 4))
sns.scatterplot(data=df, x="study_hours", y="exam_score", alpha=0.6, color="purple")
plt.title("Bivariate Analysis: Study Hours vs. Exam Scores")
plt.xlabel("Weekly Study Hours")
plt.ylabel("Exam Score (out of 100)")
plt.show()
```

Patterns to notice:

* **Positive correlation** — points rise from left to right
* **Negative correlation** — points fall from left to right
* **No clear pattern** — variables are likely unrelated
* **Clusters** — distinct groups that may indicate hidden categories

### Numerical vs. Categorical: Box and Violin Plots

To compare exam score distributions between placed and unplaced students:

```python theme={null}
fig, axes = plt.subplots(1, 2, figsize=(12, 5))

# Box plot — shows quartiles and outliers
sns.boxplot(data=df, x="placement_status", y="exam_score", ax=axes[0], palette="Set2")
axes[0].set_title("Exam Scores by Placement (Box Plot)")
axes[0].set_xlabel("Placement Status")
axes[0].set_ylabel("Exam Score")

# Violin plot — shows the full density shape
sns.violinplot(data=df, x="placement_status", y="exam_score", ax=axes[1], palette="Set2")
axes[1].set_title("Exam Scores by Placement (Violin Plot)")
axes[1].set_xlabel("Placement Status")
axes[1].set_ylabel("Exam Score")

plt.tight_layout()
plt.show()
```

### Categorical vs. Categorical: Grouped Count Plots

To explore whether sleep quality affects placement outcomes:

```python theme={null}
# Create a categorical sleep column from a continuous one
df['sleep_category'] = np.where(df['sleep_hours'] >= 7, 'Healthy', 'Sleep Deprived')

plt.figure(figsize=(7, 4))
sns.countplot(data=df, x="sleep_category", hue="placement_status", palette="coolwarm")
plt.title("Bivariate Analysis: Sleep Quality vs. Placement Status")
plt.xlabel("Sleep Category")
plt.ylabel("Number of Students")
plt.legend(title="Placement")
plt.show()
```

<Note>
  When converting a continuous variable like `sleep_hours` into a category (Healthy / Sleep Deprived), you are making a deliberate simplification. Be careful not to draw overly strong conclusions from the arbitrary threshold you choose.
</Note>

## 3. Multivariate Analysis

Multivariate analysis examines **three or more variables simultaneously** to uncover complex patterns, interactions, and correlations across an entire dataset.

### Scatter Plots with Hue and Size

Map a third variable to color (`hue`) and a fourth to marker size (`size`) to show four dimensions in one chart:

```python theme={null}
plt.figure(figsize=(9, 5))
sns.scatterplot(
    data=df.sample(n=1000, random_state=42),  # sample for readability
    x="study_hours",
    y="exam_score",
    hue="placement_status",  # third dimension — color
    size="attendance",        # fourth dimension — size
    sizes=(20, 200),
    alpha=0.7,
    palette="RdYlGn"
)
plt.title("Multivariate: Study Hours vs. Scores (colored by Placement, sized by Attendance)")
plt.xlabel("Weekly Study Hours")
plt.ylabel("Exam Score")
plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left')
plt.tight_layout()
plt.show()
```

### Correlation Heatmaps

To evaluate all pairwise linear relationships across the entire dataset at once:

```python theme={null}
# Select only numeric columns
numeric_df = df.select_dtypes(include=["number"])

# Calculate the Pearson correlation matrix
corr_matrix = numeric_df.corr()

plt.figure(figsize=(8, 6))
sns.heatmap(
    corr_matrix,
    annot=True,
    cmap="coolwarm",
    fmt=".2f",
    vmin=-1,
    vmax=1,
    linewidths=0.5
)
plt.title("Multivariate Analysis: Correlation Heatmap of Student Metrics")
plt.show()
```

Reading a heatmap:

* **Values near +1** (dark red) — strong positive linear correlation
* **Values near -1** (dark blue) — strong negative linear correlation
* **Values near 0** (white/light) — little to no linear relationship

## Choosing the Right Chart — Decision Guide

| Analysis Type | Variables                   | Best Chart              |
| ------------- | --------------------------- | ----------------------- |
| Univariate    | 1 numerical                 | Histogram + KDE         |
| Univariate    | 1 categorical               | Count plot              |
| Bivariate     | 2 numerical                 | Scatter plot            |
| Bivariate     | 1 numerical + 1 categorical | Box plot / Violin plot  |
| Bivariate     | 2 categorical               | Grouped count plot      |
| Multivariate  | 4 numerical or mixed        | Scatter with hue + size |
| Multivariate  | All numerical pairs         | Correlation heatmap     |
| Multivariate  | Full dataset overview       | Pair plot               |

<Warning>
  Correlation does not imply causation. A strong correlation between two variables does not mean that one causes the other. Always combine statistical analysis with domain knowledge before drawing causal conclusions.
</Warning>
