{
 "nbformat": 4,
 "nbformat_minor": 5,
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "name": "python",
   "version": "3.11"
  },
  "colab": {
   "provenance": []
  }
 },
 "cells": [
  {
   "cell_type": "markdown",
   "id": "cell-0000",
   "metadata": {},
   "source": [
    "# Matplotlib: Your First Charts\n",
    "\n",
    "Draw line, scatter, bar, and histogram charts with Matplotlib, style them with colors and markers, and compose multi-panel figures with plt.subplots.\n",
    "\n",
    "*Part of the free [Python for Data Science](https://ramadnsyh.dev/courses/python-for-data-science) course by [Muhammad Ramadiansyah](https://ramadnsyh.dev). This notebook is generated from the interactive lesson — [read it online](https://ramadnsyh.dev/courses/python-for-data-science/matplotlib).*"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-0001",
   "metadata": {},
   "source": [
    "Numbers convince analysts; **pictures** convince everyone else. Matplotlib is\n",
    "Python's foundational plotting library — nearly every other charting tool\n",
    "(including seaborn, next lesson) is built on top of it. Here you'll learn the\n",
    "four workhorse chart types, how to label and style them, and how to arrange\n",
    "several plots in one figure."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-0002",
   "metadata": {},
   "source": [
    "## The pyplot workflow\n",
    "\n",
    "The standard import is `import matplotlib.pyplot as plt`. A minimal plot is\n",
    "three lines: prepare data, call a plot function, show the figure:"
   ]
  },
  {
   "cell_type": "code",
   "id": "cell-0003",
   "metadata": {},
   "execution_count": null,
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "x = np.linspace(0, 10, 100)   # 100 smooth points\n",
    "y = np.sin(x)\n",
    "\n",
    "plt.plot(x, y)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-0004",
   "metadata": {},
   "source": [
    "Every `plt.*` call between the plot function and `plt.show()` modifies the\n",
    "*current figure* — that's how you'll add titles, labels, and more lines. There\n",
    "is also an object-oriented style (`fig, ax = plt.subplots()` then `ax.plot`),\n",
    "which shines for multi-panel figures — we'll use it in the subplots section."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-0005",
   "metadata": {},
   "source": [
    "## A fully dressed line chart\n",
    "\n",
    "A chart without labels is a puzzle. Here's the checklist version — two lines,\n",
    "a title, axis labels, a legend, and a grid:"
   ]
  },
  {
   "cell_type": "code",
   "id": "cell-0006",
   "metadata": {},
   "execution_count": null,
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "x = np.linspace(0, 10, 100)\n",
    "\n",
    "plt.figure(figsize=(8, 4))                     # width, height in inches\n",
    "plt.plot(x, np.sin(x), \"r--\", linewidth=2, label=\"sin(x)\")\n",
    "plt.plot(x, np.cos(x), \"b-.\", linewidth=2, label=\"cos(x)\")\n",
    "plt.xlim(0, 12)\n",
    "plt.ylim(-1.5, 1.5)\n",
    "plt.title(\"Trigonometric functions\")\n",
    "plt.xlabel(\"x\")\n",
    "plt.ylabel(\"y\")\n",
    "plt.legend()\n",
    "plt.grid(alpha=0.3)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-0007",
   "metadata": {},
   "source": [
    "The compact format strings pack color + marker + linestyle into a few\n",
    "characters:\n",
    "\n",
    "- `\"r--\"` — red, dashed line\n",
    "- `\"b-.\"` — blue, dash-dot line\n",
    "- `\"go\"` — green, circle markers (no line)\n",
    "- `\"k^:\"` — black, triangle markers, dotted line\n",
    "\n",
    "Prefer the explicit keywords (`color=\"tab:red\"`, `linestyle=\"--\"`,\n",
    "`marker=\"o\"`) in real code — they're easier to read six months later."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-0008",
   "metadata": {},
   "source": [
    "## Scatter plots: relationships between two variables\n",
    "\n",
    "Use a scatter plot when each point is one *observation* and you want to see\n",
    "how two quantities relate. `plt.scatter` can also encode a **third** variable\n",
    "via color and a **fourth** via size:"
   ]
  },
  {
   "cell_type": "code",
   "id": "cell-0009",
   "metadata": {},
   "execution_count": null,
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "rng = np.random.default_rng(42)\n",
    "hours = rng.uniform(0, 10, 60)                       # hours studied\n",
    "score = 40 + 5.5 * hours + rng.normal(0, 6, 60)      # exam score\n",
    "attendance = rng.uniform(0.5, 1.0, 60)               # share of classes attended\n",
    "\n",
    "plt.figure(figsize=(7, 4.5))\n",
    "sc = plt.scatter(hours, score, c=attendance, s=attendance * 80,\n",
    "                 cmap=\"viridis\", alpha=0.8)\n",
    "plt.colorbar(sc, label=\"attendance\")\n",
    "plt.xlabel(\"hours studied\")\n",
    "plt.ylabel(\"exam score\")\n",
    "plt.title(\"Study time vs. exam score\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-0010",
   "metadata": {},
   "source": [
    "The upward trend jumps out immediately — that's the point of a scatter plot."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-0011",
   "metadata": {},
   "source": [
    "## Bar charts: comparing categories\n",
    "\n",
    "Bars compare a numeric value **across categories**. Keep them honest: start\n",
    "the y-axis at zero and sort when order isn't meaningful:"
   ]
  },
  {
   "cell_type": "code",
   "id": "cell-0012",
   "metadata": {},
   "execution_count": null,
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "\n",
    "cities = [\"Jakarta\", \"Surabaya\", \"Bandung\", \"Medan\", \"Makassar\"]\n",
    "revenue = [420, 265, 310, 180, 150]\n",
    "\n",
    "plt.figure(figsize=(7, 4))\n",
    "plt.bar(cities, revenue, color=\"tab:blue\")\n",
    "plt.ylabel(\"revenue (million IDR)\")\n",
    "plt.title(\"Revenue by city\")\n",
    "plt.grid(axis=\"y\", alpha=0.3)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-0013",
   "metadata": {},
   "source": [
    "For long category names, `plt.barh` (horizontal bars) keeps labels readable."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-0014",
   "metadata": {},
   "source": [
    "## Histograms: the shape of one variable\n",
    "\n",
    "A histogram chops a numeric variable into **bins** and counts how many values\n",
    "land in each — it's the fastest way to see a distribution's shape, center, and\n",
    "outliers:"
   ]
  },
  {
   "cell_type": "code",
   "id": "cell-0015",
   "metadata": {},
   "execution_count": null,
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "rng = np.random.default_rng(0)\n",
    "uniform_data = rng.random(5000)          # flat\n",
    "normal_data = rng.normal(0, 1, 5000)     # bell curve\n",
    "\n",
    "plt.figure(figsize=(8, 4))\n",
    "plt.hist(normal_data, bins=30, alpha=0.7, label=\"normal\", color=\"tab:blue\")\n",
    "plt.hist(uniform_data * 6 - 3, bins=30, alpha=0.5, label=\"uniform (rescaled)\", color=\"tab:orange\")\n",
    "plt.xlabel(\"value\")\n",
    "plt.ylabel(\"count\")\n",
    "plt.title(\"Two very different distributions\")\n",
    "plt.legend()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-0016",
   "metadata": {},
   "source": [
    "Try changing `bins` — too few hides structure, too many turns the plot into\n",
    "noise. Between 20 and 50 is a good starting range for a few thousand points."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-0017",
   "metadata": {},
   "source": [
    "## Subplots: several charts, one figure\n",
    "\n",
    "`plt.subplots(rows, cols)` returns a figure and an **array of axes**; each axis\n",
    "is its own little plotting surface with `ax.plot`, `ax.set_title`, and friends:"
   ]
  },
  {
   "cell_type": "code",
   "id": "cell-0018",
   "metadata": {},
   "execution_count": null,
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "rng = np.random.default_rng(1)\n",
    "x = np.linspace(0, 10, 100)\n",
    "\n",
    "fig, axes = plt.subplots(2, 2, figsize=(9, 6))\n",
    "\n",
    "axes[0, 0].plot(x, np.sin(x), color=\"tab:blue\")\n",
    "axes[0, 0].set_title(\"line\")\n",
    "\n",
    "axes[0, 1].scatter(rng.random(50), rng.random(50), color=\"tab:orange\", s=20)\n",
    "axes[0, 1].set_title(\"scatter\")\n",
    "\n",
    "axes[1, 0].bar([\"A\", \"B\", \"C\"], [3, 7, 5], color=\"tab:green\")\n",
    "axes[1, 0].set_title(\"bar\")\n",
    "\n",
    "axes[1, 1].hist(rng.normal(size=800), bins=25, color=\"tab:red\")\n",
    "axes[1, 1].set_title(\"histogram\")\n",
    "\n",
    "fig.suptitle(\"Four chart types at a glance\")\n",
    "fig.tight_layout()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-0019",
   "metadata": {},
   "source": [
    "`fig.tight_layout()` fixes overlapping labels — make it a habit for any\n",
    "multi-panel figure."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-0020",
   "metadata": {},
   "source": [
    "> **Which chart when?**\n",
    "> \n",
    "> **Line** — something changing over a continuous axis (time, x).\n",
    "> **Scatter** — relationship between two numeric variables.\n",
    "> **Bar** — one number per category.\n",
    "> **Histogram** — the distribution of a single numeric variable.\n",
    "> When unsure, ask \"what question is this chart answering?\" first, then pick."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-0021",
   "metadata": {},
   "source": [
    "### 🏋️ Exercise — A two-panel sales dashboard\n",
    "\n",
    "Build a 1×2 figure: on the **left**, a line chart of 12 months of simulated\n",
    "sales (an upward trend plus random noise, with circle markers); on the\n",
    "**right**, a histogram of 500 simulated order values (normal around 50, no\n",
    "negatives). Give every panel a title and axis labels, and make the whole\n",
    "figure `figsize=(10, 4)`."
   ]
  },
  {
   "cell_type": "code",
   "id": "cell-0022",
   "metadata": {},
   "execution_count": null,
   "outputs": [],
   "source": [
    "# Your solution here"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-0023",
   "metadata": {},
   "source": [
    "<details><summary>✅ Show solution</summary>\n",
    "\n",
    "```python\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "rng = np.random.default_rng(3)\n",
    "months = [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\",\n",
    "          \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"]\n",
    "sales = 100 + 8 * np.arange(12) + rng.normal(0, 12, 12)\n",
    "order_values = rng.normal(50, 15, 500).clip(min=5)\n",
    "\n",
    "fig, axes = plt.subplots(1, 2, figsize=(10, 4))\n",
    "\n",
    "axes[0].plot(months, sales, marker=\"o\", color=\"tab:blue\")\n",
    "axes[0].set_title(\"Monthly sales\")\n",
    "axes[0].set_xlabel(\"month\")\n",
    "axes[0].set_ylabel(\"sales (units)\")\n",
    "axes[0].grid(alpha=0.3)\n",
    "axes[0].tick_params(axis=\"x\", rotation=45)\n",
    "\n",
    "axes[1].hist(order_values, bins=30, color=\"tab:orange\")\n",
    "axes[1].set_title(\"Order value distribution\")\n",
    "axes[1].set_xlabel(\"order value\")\n",
    "axes[1].set_ylabel(\"count\")\n",
    "\n",
    "fig.tight_layout()\n",
    "plt.show()\n",
    "```\n",
    "\n",
    "</details>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-0024",
   "metadata": {},
   "source": [
    "Matplotlib gives you full control; next lesson, seaborn gives you beautiful\n",
    "statistical charts with a fraction of the code."
   ]
  }
 ]
}