Python Visualization · EDA Framework · The Semester Project
Three things today:
Four short exercises woven throughout — all pair discussions, no code required.
groupby?Activity
With your neighbor, identify:
What can you tell from this table?
| Week | Produce | Dairy | Frozen | Deli |
|---|---|---|---|---|
| 1 | 11,500 | 12,100 | 7,320 | 4,100 |
| 2 | 12,800 | 11,400 | 7,180 | 4,080 |
| 3 | 12,200 | 10,800 | 1,780 | 4,120 |
| 4 | 13,900 | 10,100 | 7,410 | 4,090 |
| 5 | 13,400 | 9,800 | 7,260 | 4,110 |
| 6 | 15,100 | 9,200 | 7,350 | 4,085 |
| 7 | 14,800 | 8,700 | 7,420 | 4,115 |
| 8 | 16,400 | 8,100 | 7,190 | 4,095 |
What can you tell from this plot?
Scenario 1
You just pulled the Complete Journey data and need to quickly check whether basket spend looks reasonable before writing any analysis code.
Scenario 2
You’re presenting weekly revenue trends to the VP of Marketing in a board meeting. The chart will appear in a formal slide deck.
Scenario 3
The promotions team wants a tool to interactively explore coupon redemption rates by store, product category, and week.
We should match how we visualize to the goal we have in mind.
| Purpose | Tool | Example Use Case |
|---|---|---|
| Quick EDA | Pandas .plot() |
Spot-check basket spend distribution |
| Statistical comparison | Seaborn | Compare spend across income brackets |
| Polished reporting | Matplotlib | Weekly sales trend for an executive report |
| Interactive exploration | Bokeh | Let stakeholders filter by store or category |
Tip
If you can answer your question in one line, Pandas .plot() is the right tool.
.plot() Mental ModelOne variable — call .plot() on a Series, specify kind:
Two variables — call .plot() on a DataFrame, add x= and y=:
Tip
The kind= argument is the only required choice — everything else (figsize, title, xlabel, legend) is optional polish you layer on top.
Pandas .plot() calls Matplotlib under the hood — which means you can mix them:
Tip
Knowing Matplotlib unlocks the full range of customization even when starting from a Pandas plot.
Exercise 1 — Try It 💻
Using the basket_spend DataFrame (already loaded):
Part A — One variable: Plot the distribution of basket_spend. Choose a kind that shows the shape of the data.
Part B — Two variables: basket_demo has both basket_spend and marital_status. Aggregate to get average basket spend per marital status, then plot a comparison.
4 minutes — write the code, run it, discuss what you see.
| Pandas | Seaborn |
|---|---|
.plot(kind='hist') — basic bin counts |
histplot() — bins + KDE curve in one call |
.groupby().mean().plot.bar() — manual aggregation |
barplot() / boxplot() — handles stats automatically |
| No built-in group ordering | order= parameter on every chart |
Every Seaborn function follows the same pattern:
| Argument | Role | When to use |
|---|---|---|
data= |
the DataFrame | always |
x= |
horizontal axis | always |
y= |
vertical axis | two-variable plots |
hue= |
color by group | adds a third dimension |
order= |
control category order | ordered categoricals (income, size, day) |
Common functions by goal:
sns.histplot(data=df, x='col', kde=True) # distribution shape
sns.boxplot(data=df, x='group', y='col', order=[…]) # spread across groups
sns.scatterplot(data=df, x='col_a', y='col_b', hue='group') # relationship
sns.heatmap(pivot_df, cmap='YlOrRd') # matrix of values
sns.barplot(data=df, x='group', y='col', order=[…]) # mean + confidence intervalhistplotboxplotfig, ax = plt.subplots(figsize=(10, 3.8))
sns.boxplot(
data=basket_demo,
x='income',
y='basket_spend',
order=income_order, # explicit ordering — critical for income brackets
ax=ax,
showfliers=False
)
ax.set_xticklabels(ax.get_xticklabels(), rotation=45, ha='right', fontsize=8)
ax.set_xlabel('Income bracket')
ax.set_ylabel('Basket spend ($)')
ax.set_title('Basket spend by income bracket')
plt.tight_layout()
plt.show()heatmapfig, ax = plt.subplots(figsize=(10, 3.8))
sns.heatmap(
heatmap_data.iloc[:, 6:22], # hours 6am–10pm
cmap='YlOrRd',
linewidths=0.3,
ax=ax,
cbar_kws={'label': 'Trip count'}
)
ax.set_xlabel('Hour of day')
ax.set_ylabel('')
ax.set_title('Shopping trips by day of week and hour')
plt.tight_layout()
plt.show()Use Seaborn when you want to:
histplot, boxplot, violinplotscatterplot with hue, lmplotheatmapTip
Seaborn handles the statistical aggregation and grouping for you. You still get a Matplotlib figure back — so you can use ax.set_title(), ax.set_xlabel(), etc. to polish it.
Exercise 2 — Seaborn Gallery Hunt 🔍
Browse the Seaborn example gallery for 3 minutes.
Find one plot that you think could reveal something interesting about the Complete Journey data.
Be ready to share:
hue=)3 minutes — browse, pick, discuss with your neighbor.
Tip
Use Matplotlib when the chart needs to stand on its own — in a report, a slide deck, or a published figure.
Everything in Matplotlib is an object you can reference and modify:
Start with a rough Pandas plot — fast, but no formatting:
Get handles — now you control everything:
fig, ax = plt.subplots(figsize=(10, 3.2))
ax.plot(weekly_sales['week'], weekly_sales['total_sales'], linewidth=2)
ax.set_title('Weekly total sales — Regork grocery chain', pad=10)
ax.set_xlabel('Week')
ax.yaxis.set_major_formatter(mtick.StrMethodFormatter('${x:,.0f}'))
ax.grid(True, alpha=0.3)
for spine in ['top', 'right']:
ax.spines[spine].set_visible(False)
plt.tight_layout()
plt.show()fig, ax = plt.subplots(figsize=(10, 3.5))
ax.plot(weekly_sales['week'], weekly_sales['total_sales'], linewidth=2)
ax.set_title('Weekly total sales — note holiday spike in late December', pad=10)
ax.set_xlabel('Week')
ax.yaxis.set_major_formatter(mtick.StrMethodFormatter('${x:,.0f}'))
ax.grid(True, alpha=0.3)
for spine in ['top', 'right']:
ax.spines[spine].set_visible(False)
peak_idx = weekly_sales['total_sales'].idxmax()
peak_week = weekly_sales.loc[peak_idx, 'week']
peak_val = weekly_sales.loc[peak_idx, 'total_sales']
ax.annotate(
f'Holiday spike\n${peak_val:,.0f}',
xy=(peak_week, peak_val),
xytext=(peak_week - pd.Timedelta(weeks=8), peak_val * 0.97),
arrowprops=dict(arrowstyle='->', lw=1.2),
fontsize=9
)
plt.tight_layout()
plt.show()Most Python visualization libraries are built on top of Matplotlib — so once you know the Figure/Axes API, you can refine plots from Seaborn, Pandas, and others using the exact same code.
# --- Seaborn draws the plot ---
fig, ax = plt.subplots(figsize=(10, 3.8))
sns.boxplot(
data=basket_demo, x='income', y='basket_spend',
order=income_order, ax=ax, showfliers=False,
color='steelblue'
)
# --- Matplotlib polishes it ---
ax.set_xticklabels(ax.get_xticklabels(), rotation=45, ha='right', fontsize=8)
ax.set_xlabel('Income bracket')
ax.set_ylabel('Basket spend ($)')
ax.set_title('Basket spend by income — same Seaborn call, Matplotlib finishing touches')
ax.yaxis.set_major_formatter(mtick.StrMethodFormatter('${x:,.0f}'))
for spine in ['top', 'right']:
ax.spines[spine].set_visible(False)
plt.tight_layout()
plt.show()| Problem | Fix |
|---|---|
| Unreadable axis numbers | StrMethodFormatter('${x:,.0f}') for currency |
| Cluttered or overlapping labels | rotation=45, ha='right' on tick labels |
| Overplotting | alpha=0.3 on scatter points |
| Cramped layout | plt.tight_layout() or constrained_layout=True |
| Inconsistent styles | plt.style.use() once at the top of your notebook |
A Note on Matplotlib’s Learning Curve
Matplotlib is powerful but verbose. The good news: there is a massive example gallery and AI tools are very good at helping adapt Matplotlib code. Learning to describe what you want and adapt examples is itself a valuable skill.
Exercise 3 — Matplotlib Gallery Hunt 🔍
Browse the Matplotlib example gallery for 3 minutes.
Find one plot that you think could reveal something interesting about the Complete Journey data.
Be ready to share:
3 minutes — browse, pick, discuss with your neighbor.
source = ColumnDataSource(weekly_sales)
p = figure(
title='Total Weekly Sales — hover, zoom, and pan to explore',
x_axis_type='datetime',
width=750, height=350,
tools='pan,wheel_zoom,box_zoom,reset,save'
)
p.line('week', 'total_sales', source=source,
line_width=2, color='steelblue')
hover = HoverTool(tooltips=[
('Week', '@week{%F}'),
('Sales', '@total_sales{$0,0}')
], formatters={'@week': 'datetime'})
p.add_tools(hover)
p.xaxis.axis_label = 'Week'
p.yaxis.axis_label = 'Total Sales ($)'
show(p)Tip
Run this in the companion notebook to see the interactive version — it won’t fully render in a static slide.
| Tool | Strengths | Best For |
|---|---|---|
| Pandas | Fast, one-liner, tied to DataFrames | Quick spot-checks during EDA |
| Seaborn | Statistical grouping, ordering, distributions | Comparing groups, showing spread |
| Matplotlib | Complete control, publication quality | Reports, presentations, polished figures |
| Bokeh | Interactive, web-ready, shareable HTML | Dashboards, stakeholder exploration |
Exploratory Data Analysis is not a checklist of charts to run.
It is a sequence of questions — each answer raising the next question.
Data dump (avoid)
Real EDA (aim for)
Important
The goal is not to show that you looked at the data. The goal is to find something worth saying.
flowchart LR
A["1️⃣ Question"] --> B["2️⃣ Structure"]
B --> C["3️⃣ Distributions"]
C --> D["4️⃣ Segmentation"]
D --> E["5️⃣ Story"]
style A fill:#2c3e50,color:#fff
style B fill:#2980b9,color:#fff
style C fill:#27ae60,color:#fff
style D fill:#e67e22,color:#fff
style E fill:#8e44ad,color:#fff
| Step | Question to ask |
|---|---|
| Question | What do I actually want to know? Is it specific enough to know when I’ve answered it? |
| Structure | What shape is the data? What do I need to join? Where are the missings? |
| Distributions | What does the outcome variable look like across all households? Any outliers? |
| Segmentation | Does the pattern differ across groups? Where does the interesting variation live? |
| Story | What changed? What surprised me? What should the decision-maker do next? |
The question determines everything that follows.
Caution
Too broad: “How do customers shop?”
This can’t be answered — no unit of analysis, no metric, no comparison to make.
Tip
Sharp: “Do households that redeem coupons have larger basket spend than those that don’t — and does this differ across income brackets?”
This names: the unit (basket), the metric (spend), the comparison (coupon vs. no coupon), and the segmentation (income).
A sharp question tells you exactly which tables to join, which columns to compute, and what a result would look like.
Check your data before trusting it:
Baskets: 155,848
Households with demographics: 801
Median basket spend: $19.91
Distributions tell you what. Segmentation tells you who and where.
The segmentation raised a new question: Why does it flatten? Is it basket size (fewer items) or price per item?
A good EDA concludes with something worth saying:
The “So What” Test
After every chart, ask: So what? If you can’t answer that in one sentence — why a decision-maker should care — the chart is not yet doing its job.
A data dump shows charts. A good EDA tells a story.
Thursday’s lab is the project ideation session — you’ll brainstorm and pitch.
To get the most out of it, read Chapter 15 (EDA) before lab.
It walks through a full EDA case study on the Complete Journey data and shows the framework in action from first question to final story. Coming in with that mental model will make Thursday’s brainstorming sharper.
Tip
The companion notebook for Chapter 15 is runnable in Colab — follow along and experiment with your own questions as you read.
Exercise 4 — What’s the Next Question? 🤔
A teammate reports this finding:
“Households in the top two income brackets spend 38% more per basket on average than households in the bottom two brackets.”
Name 3 follow-up questions you would investigate next and explain what each one would reveal.
Discuss with your neighbor for 3 minutes.
You are a data scientist at Regork, a national grocery chain.
Your manager has asked you to identify a potential growth opportunity — an area where the company could invest future resources to increase revenue or profits.
Your task:
Tip
Groups: 2–4 students. Sign up in Canvas → People → Project Groups.
Caution
Too vague
“We want to understand how customers shop.”
No unit of analysis. No metric. No comparison. Cannot be answered.
Caution
Better, but still broad
“Do different income groups shop differently?”
“Differently” could mean anything — frequency, basket size, category mix, price sensitivity.
Tip
Sharp
“Do households in the bottom two income brackets redeem coupons at higher rates — and does redemption translate into larger basket spend, or just a cheaper version of the same basket?”
Has a unit (basket), a metric (spend), a comparison (redemption vs. not), and a segmentation (income). You would know when you had answered it.
Clear business problem — state one specific, answerable question tied to a real decision. Not “understand customer behavior.” Something like: “Do low-income households redeem coupons at higher rates, and does redemption translate into larger basket spend or just a cheaper version of the same basket?”
Proposed value to the decision-maker — name who acts on your findings and what they would do differently. The VP of Promotions needs a recommendation, not a summary of what you computed.
Logical, methodical analysis — start with data structure and distributions, then move into group comparisons and segmentation. Each step should raise the next question. Show your reasoning, not just your outputs.
Clearly explained findings — every chart and table earns its place by making one point. Label axes properly, use readable scales, and narrate what the reader should see. Plots without interpretation are just decoration.
Polished communication — the report reads as a coherent story, not a list of code cells. The presentation looks like a business deck, not a notebook printout. Your audience is an executive, not a grader.
Clear recommendations — end with something actionable. “Based on our findings, we recommend…” is a sentence your report and presentation must contain.
YYYY_BANA7025_groupXX_project.htmlNote
One group member submits both deliverables together. Submit early — large video files can take time to upload.
Go to Canvas → Assignments → Project
The Canvas project page has everything you need before writing a single line of code:
Reading the rubric before you start is one of the highest-leverage things you can do.
75 points total — split across a written report (40 pts) and a recorded presentation (35 pts).
Report (40 pts)
| Section | Pts | What We’re Looking For |
|---|---|---|
| Introduction | 5 | Clear business problem, approach, and proposed value to the decision-maker |
| Packages | 5 | All imports upfront, warnings suppressed, unfamiliar libraries explained |
| EDA | 10 | Non-obvious insights, polished plots + tables, findings clearly narrated |
| Summary | 5 | Problem, approach, insights, recommendations, and limitations |
| Code & Craft | 15 | Clean style, systematic logic, mastery — notebook runs without errors |
Presentation (35 pts)
| Section | Pts | What We’re Looking For |
|---|---|---|
| Introduction | 5 | Business problem, approach, and proposed solution — no code |
| Findings | 10 | Key charts and tables, one point per visual, clearly explained |
| Summary | 5 | Insights, implications, clear recommendation, and limitations |
| Delivery | 15 | ≤ 3 minutes, professional, compelling narrative — executive audience |
Tip
The EDA section (10 pts) is where most projects separate. Uncovering a non-obvious pattern and explaining why it matters is worth more than five polished charts that say nothing new.
In Thursday’s lab you will:
Tips for a Strong Pitch
After lab: refine your idea into a formal proposal (the homework due this week).
Part 1 — Python Visualization
Part 2 — EDA Framework
Part 3 — The Project
Open floor for questions on:
BANA 7025