SkillNavoraData Science & AI Handbook
Python for Data Science · Lesson 21 of 29

Data Visualisation II: Seaborn Statistical Charts and Interactive Plotly

Make statistical charts quickly with Seaborn (distributions, categorical comparisons, relationships, correlation heatmaps, pair plots and facets) using the HR attrition data, and build interactive charts and simple dashboards with Plotly Express and Streamlit.

● Python class 16✦ Seaborn 0.13 · Plotly 6Intermediate⏱ 100 min
⬇ Download PDF
By the end of this lesson you can
  • Use Seaborn's figure-level and axes-level functions with hue, col and row
  • Compare distributions across groups with histplot, kdeplot, boxplot, violinplot and countplot
  • Show relationships with scatterplot, regplot, heatmaps of correlations and pairplot
  • Build interactive charts with Plotly Express and know when to use Streamlit
  • Turn charts into a clear data story

Seaborn in one idea

Seaborn works directly with long DataFrames: you name the columns for x, y, hue (colour), col/row (small multiples), and it groups, aggregates and adds legends for you.

Python
import pandas as pd, numpy as np, seaborn as sns, matplotlib.pyplot as plt
hr = pd.read_csv("hr_employees.csv")
hr["left"] = (hr["attrition"] == "Yes").astype(int)
print(hr.shape, f"attrition rate {hr.left.mean():.1%}", sns.__version__)
print(hr.groupby("overtime")["left"].mean().round(3).to_dict(), hr.groupby("department")["left"].mean().round(3).sort_values().to_dict())
Output
(1500, 16) attrition rate 25.9% 0.13.2
{'No': 0.216, 'Yes': 0.367} {'Operations': 0.219, 'Finance': 0.227, 'HR': 0.229, 'IT': 0.243, 'R&D': 0.26, 'Sales': 0.304}
Question Seaborn function
Distribution of one variable histplot, kdeplot, ecdfplot
Distribution by group boxplot, violinplot, stripplot, boxenplot
Counts of categories countplot
Average per category (with CI) barplot, pointplot
Two numeric variables scatterplot, regplot, lmplot, jointplot
Many variables pairplot, heatmap of df.corr()
Small multiples displot, catplot, relplot with col=/row=

Distributions

Income distribution for leavers vs stayers: leavers cluster at lower incomes.
Income distribution for leavers vs stayers: leavers cluster at lower incomes.

common_norm=False scales each group separately, so a small group (leavers) is not dwarfed by a big one.

Violin plots combine a box plot with the distribution shape; split by overtime.
Violin plots combine a box plot with the distribution shape; split by overtime.

Categorical comparisons

Attrition rate by overtime and job satisfaction. Bars show the mean with a 95% confidence interval.
Attrition rate by overtime and job satisfaction. Bars show the mean with a 95% confidence interval.
Python
print((hr.pivot_table(index="job_satisfaction", columns="overtime", values="left", aggfunc="mean") * 100).round(1))
Output
overtime            No   Yes
job_satisfaction            
1                 31.1  45.5
2                 24.4  40.5
3                 18.7  32.8
4                 12.0  25.8

Relationships and correlation

Correlation heatmap of numeric HR variables (Pearson r). Only the lower triangle is shown.
Correlation heatmap of numeric HR variables (Pearson r). Only the lower triangle is shown.
Python
print(corr["left"].drop("left").sort_values())
Output
job_satisfaction        -0.17
years_at_company        -0.13
monthly_income          -0.11
age                     -0.08
performance_rating      -0.03
distance_from_home_km    0.09
Name: left, dtype: float64

Correlation measures linear association between −1 and +1. It does not prove causation, and it can miss non-linear patterns: always look at the scatter too.

regplot adds a fitted line with a confidence band; lmplot repeats it per group.
regplot adds a fitted line with a confidence band; lmplot repeats it per group.

Pair plots and facets

A pair plot shows every pairwise scatter and each distribution, coloured by churn (telecom data).
A pair plot shows every pairwise scatter and each distribution, coloured by churn (telecom data).
Facets (small multiples) with catplot: churn rate by contract type, split by internet service.
Facets (small multiples) with catplot: churn rate by contract type, split by internet service.
Python
print((tc.pivot_table(index="contract", columns="internet_service", values="churned", aggfunc="mean") * 100).round(1))
Output
internet_service   DSL  Fiber  No internet
contract                                  
Month-to-month    30.8   43.5         28.5
One year          11.1   26.7          4.1
Two year           5.6    9.5          2.8

Interactive charts with Plotly Express

Plotly makes charts you can hover, zoom and filter in a browser or notebook. The syntax mirrors Seaborn:

Python
import plotly.express as px
fig = px.scatter(tc, x="tenure_months", y="monthly_charges", color="churn",
                 hover_data=["contract", "payment_method"], opacity=.6,
                 title="Churn by tenure and charges")
fig.show()                         # interactive in notebooks
fig.write_html("churn.html")       # share as a standalone web page

px.line(monthly_df, x="month", y="sales", color="category")
px.bar(region_df, x="region", y="sales", text_auto=".2s")
px.histogram(hr, x="monthly_income", color="attrition", barmode="overlay")
px.choropleth(...)                 # maps

A mini dashboard app with Streamlit

Python
# app.py  ->  run with:  streamlit run app.py
import streamlit as st, pandas as pd, plotly.express as px
df = pd.read_csv("telecom_churn.csv")
contract = st.sidebar.multiselect("Contract", df.contract.unique(), default=list(df.contract.unique()))
d = df[df.contract.isin(contract)]
st.title("Churn dashboard")
st.metric("Churn rate", f"{(d.churn == 'Yes').mean():.1%}")
st.plotly_chart(px.histogram(d, x="tenure_months", color="churn", barmode="overlay"))

Streamlit turns a Python script into a web app with filters, which is useful for sharing analyses and ML demos (see the GenAI track for chat apps).

From charts to a data story

The story arc: context, finding, evidence, recommendation.
The story arc: context, finding, evidence, recommendation.
  1. One message per chart, written as the title.
  2. Show the comparison that proves it (overtime vs not), not every chart you made.
  3. Quantify impact (people, ₹, %).
  4. End with a recommendation and its owner.

Summary

Key takeaways
  • Seaborn plots long DataFrames by column name with hue, col and row; it sits on Matplotlib, so you can still style the axes.
  • Distributions: histplot (with common_norm=False), kdeplot, boxplot, violinplot; categories: countplot, barplot with confidence intervals.
  • Relationships: scatterplot, regplot, pairplot, correlation heatmap (correlation ≠ causation).
  • Facets (catplot, relplot, displot) create small multiples.
  • Plotly Express gives interactive charts; Streamlit turns scripts into dashboards. Tell a story: one message per chart.
Quick quiz6 questions · tap an answer to check it

1. What does hue="attrition" do in Seaborn?

Answer: B. col= would create separate panels instead.

2. Which chart shows the mean per category with a confidence interval?

Answer: B. countplot shows counts.

3. A correlation of −0.8 means…

Answer: B. Correlation does not imply causation.

4. Which function creates small multiples of bar charts?

Answer: B. Figure-level functions accept col and row.

5. What is the main advantage of Plotly over Matplotlib?

Answer: B. Export with write_html.

6. Why use common_norm=False in a histplot with hue?

Answer: A. Otherwise the larger group dominates.
ExerciseSeaborn practice (telecom_churn.csv)

(1) Histogram of monthly_charges by churn. (2) Box plot of tenure_months by contract. (3) Churn rate by payment method, sorted. (4) Correlation heatmap of numeric columns plus churned. (5) Write three insight titles from what you see.

Show solution
Python
sns.histplot(tc, x="monthly_charges", hue="churn", common_norm=False, stat="density")
sns.boxplot(tc, x="contract", y="tenure_months")
order = tc.groupby("payment_method")["churned"].mean().sort_values(ascending=False).index
sns.barplot(tc, x="payment_method", y="churned", order=order, errorbar=None)
sns.heatmap(tc.select_dtypes("number").corr(), annot=True, fmt=".2f", cmap="RdBu_r", center=0)
# e.g. "Month-to-month customers churn far more", "Churners have short tenure", "Churn rises with support calls"
Interview cornerQuestions you may be asked

Q: How would you visualise the relationship between a categorical and a numeric variable? Box or violin plots per category (distribution), or bar/point plots of the mean with confidence intervals.

Q: How do you show correlations among many numeric variables? A correlation heatmap (masked upper triangle) followed by scatter plots for the interesting pairs; a pair plot for a handful of variables.

Q: How do you present findings to non-technical stakeholders? Lead with the recommendation, show one clear chart per point with an insight title, quantify impact, and keep methods in an appendix.

Practise more online

Free, trusted places to test yourself on this topic. Links open the original site in a new tab.