{ "cells": [ { "cell_type": "markdown", "id": "0", "metadata": {}, "source": [ "---\n", "title: \"Chapter 17: The storytelling capstone\"\n", "---" ] }, { "cell_type": "markdown", "id": "1", "metadata": {}, "source": [ "[](https://colab.research.google.com/github/sambaiga/ds-mlops-path/blob/main/tutorials/01-python-basics/17-storytelling-capstone.ipynb) [](https://raw.githubusercontent.com/sambaiga/ds-mlops-path/main/tutorials/01-python-basics/17-storytelling-capstone.ipynb)" ] }, { "cell_type": "markdown", "id": "2", "metadata": {}, "source": [ "The department head has ten minutes before her next meeting. You have three charts and twelve numbers, and a strong opinion about which courses need help. She asks one question: *\"So what do I do?\"* Your charts are correct. None of them answer that.\n", "\n", "Chapters 14 through 16 taught you how to build a chart and how to make it honest. This chapter is about the step before any of that: knowing who the chart is for and what they need to decide, diagnosing why a draft chart is not landing, and recognising the moment you stop exploring and start explaining. It closes the Data Visualization part by putting every judgment call from the last three chapters, and both libraries, to work on one real case, start to finish. Chapter 18 picks up the engineering practices, uv, ruff, git, testing, that make analysis like this reproducible.\n", "\n", "> Callout markers: [book cover page](../../index.qmd#callout-guide)." ] }, { "cell_type": "markdown", "id": "3", "metadata": {}, "source": [ "::: {.callout-note collapse=\"true\" icon=false}\n", "## Learning objectives\n", "\n", "By the end of Chapter 17 you will be able to:\n", "\n", "| # | Skill | Covered in |\n", "|---|---|---|\n", "| 1 | Name a chart's audience, decision, and medium, and let medium decide the library | Sec. 1 |\n", "| 2 | Diagnose a failing chart with the Trifecta Checkup: content, story, or visual form | Sec. 2 |\n", "| 3 | Decide explore vs explain and change how you build a chart accordingly | Sec. 3 |\n", "| 4 | Rebuild one explanatory chart in matplotlib and lets-plot for two different mediums | Sec. 4 |\n", "| 5 | Produce one explanatory chart, backed by a one-paragraph brief, from a real dataset | Capstone |\n", ":::" ] }, { "cell_type": "markdown", "id": "4", "metadata": {}, "source": [ "## 1. Audience, decision, medium\n", "\n", "Every chart decision so far assumed the audience was you: fast defaults, all the data, nothing hidden. The moment someone else needs to act on what you found, three questions come before any chart type: who is this for, what do they need to decide, and how will they see it? Skip these and even a perfectly honest, perfectly decluttered chart can still miss." ] }, { "cell_type": "code", "execution_count": null, "id": "5", "metadata": {}, "outputs": [], "source": [ "import pandas as pd\n", "\n", "df = pd.read_csv(\"data/university_analytics.csv\")\n", "\n", "# Same three-course, three-Fall-cohort slice as Chapters 14 to 16: the\n", "# department head's question is about these students specifically.\n", "courses = [\"Machine Learning\", \"Data Structures\", \"Python Programming\"]\n", "semesters = [\"Fall 2022\", \"Fall 2023\", \"Fall 2024\"]\n", "results = df[df[\"course\"].isin(courses) & df[\"semester\"].isin(semesters)].copy()\n", "results.head()" ] }, { "cell_type": "markdown", "id": "6", "metadata": {}, "source": [ "
brief = {\"audience\": ..., \"decision\": ..., \"medium\": ...}.audience: who reads this chart.decision: the one thing they do differently depending on what the chart shows.medium: how they will see it (live meeting, slide, printed report).+ layers changed. This is the payoff of Chapter 15's grammar: scale_fill_manual() and labs() work the same way regardless of which chart they are attached to, so switching libraries for a medium change costs a rewrite of the drawing code, not a rethink of the message.\n",
"brief dict from Activity 1. Decide which medium fits: a live meeting or a printed handout.attendance_pct into three groups the same way as study_bucket, and compute mean final_score per group. Is the gap as large as the study-hours gap?configure_matplotlib_style() for a printed medium, or lets-plot with modern_theme() for a live one, matching the medium from step 1.pd.qcut(results[\"attendance_pct\"], 3, labels=[\"Low\", \"Mid\", \"High\"]) mirrors the study_bucket code from Section 2.\n",
"