Chapter 15 Exercises: Advanced Charts and Dashboards

Work through these exercises in order. Each tier builds on the previous. All exercises use Python 3.10+, seaborn, plotly express, and pandas. Where data is not provided, generate plausible business data using numpy with a fixed random seed.


Tier 1 — Foundational (Do These First)

Exercise 15-1: Your First seaborn Barplot

Create a DataFrame with the following sales data and draw a grouped bar chart using sns.barplot:

Product Q1 Sales Q2 Sales Q3 Sales
Laptops 142000 158000 171000
Monitors 67000 73000 81000
Keyboards 23000 28000 31000
Headsets 41000 45000 52000

The chart should have: - A descriptive title - Dollar-formatted y-axis labels - A legend labeling the quarters - The "whitegrid" seaborn theme applied before drawing

Save the chart as product_sales_barplot.png.


Exercise 15-2: seaborn Theme Comparison

Draw the same chart from Exercise 15-1 four times in a 2×2 matplotlib grid, each with a different seaborn style: "whitegrid", "darkgrid", "white", and "ticks". Add a title to each subplot identifying the style name.

Use plt.subplots(2, 2, figsize=(14, 10)) and pass each ax to sns.barplot().

Save the result as theme_comparison.png. Write two sentences in a comment at the top of your file explaining which theme you would choose for a board-level presentation and why.


Exercise 15-3: Your First plotly Bar Chart

Reproduce the bar chart from Exercise 15-1 using plotly.express. Requirements: - Use px.bar with barmode="group" - Set the y-axis tick format to "$,.0f" using fig.update_layout - Save the result as product_sales_interactive.html - Add a hover tooltip that shows the quarter and revenue value clearly labeled

Open the HTML file in a browser and hover over several bars to verify the tooltips work.


Exercise 15-4: seaborn Line Plot

Using numpy with seed=42, generate 24 months of simulated revenue data (2022 and 2023) for a single company. The values should start around $800,000 per month in January 2022 and trend upward to around $1,100,000 by December 2023, with realistic monthly noise.

Draw a sns.lineplot with: - Two lines: one for 2022, one for 2023 - marker="o" to show data points - Month names on the x-axis (Jan through Dec) - The "muted" seaborn color palette

Save as revenue_trend.png.


Exercise 15-5: plotly Line Chart with Hover Mode

Convert the line chart from Exercise 15-4 into a plotly interactive chart using px.line. Set hovermode="x unified" so hovering over any month shows both years' values simultaneously.

Add the following to the layout: - The title "Revenue Trend: 2022 vs 2023" - Y-axis formatted as "$,.0f" - X-axis tick labels formatted as abbreviated month names

Save as revenue_trend_interactive.html.


Tier 2 — Developing Skills

Exercise 15-6: seaborn Heatmap

Generate a 6 × 12 matrix of data representing revenue by sales representative and month. Use the following rep names: Alice K., Bob L., Carol M., Dan N., Eve P., Frank Q. Use numpy with seed=55 to generate values between $45,000 and $180,000 per cell.

Draw a sns.heatmap with: - The "Blues" colormap - Cell annotations formatted as `"$XK"` (e.g., "$132K") - A title "Monthly Revenue by Sales Rep — 2023" - Rotated x-axis tick labels at 45 degrees to avoid crowding - A color bar labeled "Revenue ($)"

Save as rep_revenue_heatmap.png.


Exercise 15-7: Diverging Heatmap for Performance vs Target

Using the same 6 × 12 rep/month structure from Exercise 15-6, create a second heatmap that shows percentage above or below target for each cell (assume each rep has a flat monthly target of $110,000).

Use the "RdYlGn" diverging colormap (red = below target, green = above target), with center=0 so that zero deviation is yellow. Annotate cells with the percentage (e.g., "+12%" or "-8%").

This exercise practices the important distinction between sequential and diverging color maps.


Exercise 15-8: seaborn Boxplot with Annotations

Generate order-value data for five sales reps: 80 orders each, with different median order values and spreads. Draw a sns.boxplot and:

  1. Add the median value as a text annotation above each box
  2. Overlay a sns.stripplot with jitter=True and 20% opacity
  3. Use a custom color palette (one color per rep, not seaborn's default)
  4. Add a footnote text box explaining what the box and whiskers represent

Save as rep_order_boxplot.png.


Exercise 15-9: plotly Scatter with Trendlines

Using numpy with seed=88, generate 150 data points representing marketing campaigns with: - spend: log-normally distributed, mean ~$8,000 - leads_generated: correlated with spend but with noise, roughly spend / 85 - channel: randomly assigned — Email, Social, Search, Events (4 categories)

Draw a px.scatter with: - x = spend, y = leads_generated - Color by channel - trendline="ols" (requires statsmodels installed) - Formatted axes (spend as dollars, leads as integers) - Title: "Marketing Spend vs Leads Generated by Channel" - Custom hover showing spend, leads, and channel

Save as marketing_scatter.html.


Exercise 15-10: plotly Sunburst Chart

Build a sunburst chart representing the following hierarchical sales data:

North America
  ├── USA
  │   ├── Enterprise: $4.2M
  │   ├── Mid-Market: $2.1M
  │   └── SMB: $0.8M
  └── Canada
      ├── Enterprise: $0.9M
      └── Mid-Market: $0.5M
Europe
  ├── UK
  │   ├── Enterprise: $1.8M
  │   └── Mid-Market: $0.7M
  └── Germany
      ├── Enterprise: $1.4M
      └── Mid-Market: $0.6M

Use px.sunburst with path=[px.Constant("Global"), "continent", "country", "segment"]. Color by revenue value using "Blues" sequential scale. Save as global_revenue_sunburst.html.


Tier 3 — Applied Business

Exercise 15-11: The Complete seaborn Exploratory Dashboard

You are an analyst at a regional insurance company. Load or generate a dataset with 500 policies including columns: premium (annual premium), claims_count (0-5), policy_type ("Auto", "Home", "Life"), region ("North", "South", "East", "West"), and agent_years_experience (1-25 years).

Produce a 2×2 seaborn figure with: - Top-left: Boxplot of premium by policy type - Top-right: Heatmap of average premium by region × policy type (you'll need a pivot_table) - Bottom-left: Scatter of agent experience vs average premium per client - Bottom-right: Bar chart of claims count distribution (count of policies per claims value)

Save the entire figure as insurance_eda.png. Use consistent colors for policy type across all panels.


Exercise 15-12: plotly Dashboard — Two Metrics, One Panel

Sandra Chen has asked for a single chart showing both monthly revenue (bars) and cumulative revenue (line) for 2023. These are two different chart types on the same plot.

Use plotly.graph_objects (not plotly express) to build this: - go.Bar for monthly revenue - go.Scatter with mode="lines+markers" for cumulative sum - Dual y-axes: left for monthly revenue, right for cumulative - The cumulative line on yaxis="y2" with overlaying="y" and side="right" - hovermode="x unified"

Save as monthly_cumulative_revenue.html.


Exercise 15-13: seaborn Pairplot for Business Insight

Generate a dataset of 100 accounts with four metrics: account_age_years, lifetime_revenue, churn_risk_score (0-100), and support_tickets_ytd. Include an industry category column with values: "Retail", "Healthcare", "Manufacturing", "Finance".

Draw a sns.pairplot with: - hue="industry" for color - diag_kind="kde" on the diagonal - Semi-transparent points (alpha=0.6) - A title above the entire grid

Inspect the result and write a 3-sentence interpretation: what correlation do you observe between any two variables, and what business action might that suggest?


Exercise 15-14: plotly Chart with Dropdown Filter

Build a plotly figure that shows monthly revenue as a bar chart, but includes a dropdown menu that lets the viewer switch between four regions. When a region is selected, only that region's data is visible.

Use plotly.graph_objects. Create one go.Bar trace per region. Use updatemenus with "buttons" to build the dropdown. Set the initial visible trace to "Northeast".

Save as regional_revenue_dropdown.html. This exercise teaches the mechanics of plotly dropdowns, which are useful whenever you want filter functionality without a full web framework.


Exercise 15-15: Saving Charts for Different Destinations

Take any plotly chart you've built in this chapter's exercises and save it in three formats: 1. chart_offline.html — fully self-contained HTML (no CDN) 2. chart_cdn.html — HTML using CDN for plotly.js (smaller file) 3. chart_print.png — static PNG at 1400px wide, scale=2 (requires kaleido)

Use os.path.getsize() to print the file sizes of all three. Write a comment explaining which format you would use in each of these scenarios: - Emailing to a client with no Python access - Embedding in a company intranet page - Including in a printed quarterly report


Tier 4 — Challenge

Exercise 15-16: Animated plotly Bar Chart

Using plotly.express, create an animated bar chart showing the top 5 product categories by revenue for each quarter (Q1 through Q4). Use px.bar with animation_frame="quarter" and animation_group="category".

The chart should have: - Fixed x-axis range (so bars don't jump) - Play button that animates through quarters - Hover showing exact revenue per category per quarter

Save as animated_category_revenue.html.


Exercise 15-17: seaborn FacetGrid

Using a dataset of 8 sales reps, 4 regions, and 12 months (generate synthetically), draw a sns.FacetGrid that shows one line plot per region (4 rows) with all reps' monthly revenue on each subplot. Color lines by rep.

This requires: FacetGrid(data=..., row="region") followed by .map_dataframe(sns.lineplot, x="month", y="revenue", hue="rep_name").

Save as facet_rep_by_region.png. This exercise demonstrates how to produce small multiples — one of the most powerful techniques in data visualization.


Exercise 15-18: Full Business Dashboard

Build a complete self-contained plotly dashboard that a VP of Operations could use to monitor a distribution business. The dashboard should have at least five panels arranged in a grid:

  1. Monthly shipments: actual vs target (line chart)
  2. On-time delivery rate by warehouse (bar chart)
  3. Average days to ship by product category (horizontal bar chart)
  4. Inventory turnover by region (heatmap — use go.Heatmap)
  5. Delivery delay distribution (histogram — use go.Histogram)

Use consistent colors. Write custom hover templates for every panel. Add a descriptive subtitle to the overall dashboard. Save as operations_dashboard.html.


Tier 5 — Mastery

Exercise 15-19: Reusable Visualization Functions

Write a Python module called biz_charts.py that provides the following reusable functions:

def revenue_heatmap(pivot_df: pd.DataFrame, title: str, output_path: str) -> None:
    """Draws a seaborn heatmap with standard business formatting."""
    ...

def trend_vs_target(
    dates, actuals, targets, title: str, output_path: str
) -> go.Figure:
    """Returns a plotly figure with actual and target lines."""
    ...

def category_breakdown(
    labels, values, title: str, output_path: str
) -> go.Figure:
    """Returns a plotly donut chart."""
    ...

Each function should: - Apply consistent styling (theme, font, colors) - Accept an output_path and save the chart automatically - Include a Google-style docstring - Handle edge cases (empty data, NaN values) gracefully

Demonstrate the module by importing it and generating three charts from a sample business dataset.


Exercise 15-20: The Interactive Client Report

Maya wants to give each of her clients a personalized interactive HTML report at year-end. The report for each client should contain:

  1. A line chart of that client's monthly revenue over the year
  2. A bar chart of hours spent per project for that client
  3. A summary table (using go.Table) with: project name, billed amount, hours, effective rate, and status

Write a script that: 1. Reads client data from a CSV (generate it with at least 5 clients) 2. Loops over each client 3. Generates a separate HTML file per client (e.g., client_harrington_report.html) 4. Names each report with the client's name and the report date

This exercise brings together: data filtering, plotly subplots, go.Table, custom styling, write_html, and file naming conventions — the full production workflow.


Answer Guidance (Selected Exercises)

Exercise 15-1 (key points): - Data must be reshaped to long format for sns.barplot with hue. Use pd.DataFrame with columns ["product", "quarter", "sales"] or use .melt(). - errorbar=None prevents seaborn from drawing confidence intervals on aggregated single-observation data.

Exercise 15-7 (key points): - The deviation matrix: deviation = (revenue_matrix - 110000) / 110000 - sns.heatmap(..., center=0) ensures zero maps to the center of the diverging palette. - Format annotations with f"{v:+.0%}" to show the + sign for positive values.

Exercise 15-12 (key points): - fig.update_layout(yaxis2={"overlaying": "y", "side": "right"}) is the correct syntax for dual y-axes in graph objects. - The cumulative line is df["revenue"].cumsum().

Exercise 15-14 (key points): - Each go.Bar trace has visible=False except the first. Dropdown buttons set visible to a list of booleans matching trace count. - Use "method": "update" (not "restyle") when updating both data and layout simultaneously.