{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "b30269d6-9c9d-4a1f-a5e2-95c94a4877d6",
   "metadata": {},
   "source": [
    "# Introduction to Altair\n",
    "\n",
    "## Before we start: Jupyter Notebooks\n",
    "\n",
    "- Made up of \"cells\" which can be Python, markdown, or with extensions, any language.\n",
    "- Cells execute individually, and can execute out of order.  Always re-order cells to be logical and make use of comments and/or markdown cells to make your notebook a narrative.\n",
    "- Tip: Before submitting a notebook, restart the kernel and run all cells in order. (See Kernel menu for options.) Ensure that you didn't inadvertently break things.\n",
    "- Not particularly Git friendly as the contents of the notebook are stored in JSON.  (Still keep them in Git! even if suboptimal better than losing work!)\n",
    "- An alternative is `marimo` notebooks, which fix a few of the above issues.  Still new & there are some rough edges still so I'll be sticking with Jupyter.\n",
    "\n",
    "`uv run jupyter lab` or `uv run jupyter notebook` will start the local notebook server (Lab is a newer UI, Notebook is the traditional one).  You may opt to use VS Code, but I personallyh find their interface for notebooks more confusing than helpful.\n",
    "\n",
    "### Style Addendum (for all assignments in this course)\n",
    "\n",
    "- Notebook style imports allowed/preferred.\n",
    "- Limited use of global variables permitted with useful names and comments.\n",
    "- Notebooks must execute sequentially!"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "MJUe",
   "metadata": {},
   "source": [
    "## Altair expects \"tidy\" data\n",
    "\n",
    "Altair expects our data to be [tidy](http://vita.had.co.nz/papers/tidy-data.html).\n",
    "\n",
    "- Each variable is a column.\n",
    "- Each observation is a row.\n",
    "- Each type of observational unit is a table.\n",
    "\n",
    "You may use `pandas` or `polars` DataFrames. \n",
    "Class examples will focus on pre-cleaned data, and I will use polars in examples, though rarely will what I show differ significantly in pandas."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "Hbol",
   "metadata": {},
   "outputs": [],
   "source": [
    "# best to follow convention, \"notebook\" style imports are allowed/preferred\n",
    "import marimo as mo\n",
    "import altair as alt\n",
    "import polars as pl\n",
    "from pathlib import Path"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "vblA",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div><style>\n",
       ".dataframe > thead > tr,\n",
       ".dataframe > tbody > tr {\n",
       "  text-align: right;\n",
       "  white-space: pre-wrap;\n",
       "}\n",
       "</style>\n",
       "<small>shape: (12, 3)</small><table border=\"1\" class=\"dataframe\"><thead><tr><th>state</th><th>session_start_year</th><th>num_bills</th></tr><tr><td>str</td><td>i64</td><td>i64</td></tr></thead><tbody><tr><td>&quot;IL&quot;</td><td>2017</td><td>13616</td></tr><tr><td>&quot;IL&quot;</td><td>2019</td><td>12760</td></tr><tr><td>&quot;IL&quot;</td><td>2021</td><td>12847</td></tr><tr><td>&quot;IL&quot;</td><td>2023</td><td>11951</td></tr><tr><td>&quot;MI&quot;</td><td>2017</td><td>4818</td></tr><tr><td>&hellip;</td><td>&hellip;</td><td>&hellip;</td></tr><tr><td>&quot;MI&quot;</td><td>2023</td><td>3424</td></tr><tr><td>&quot;WI&quot;</td><td>2017</td><td>1820</td></tr><tr><td>&quot;WI&quot;</td><td>2019</td><td>2264</td></tr><tr><td>&quot;WI&quot;</td><td>2021</td><td>2618</td></tr><tr><td>&quot;WI&quot;</td><td>2023</td><td>2656</td></tr></tbody></table></div>"
      ],
      "text/plain": [
       "shape: (12, 3)\n",
       "┌───────┬────────────────────┬───────────┐\n",
       "│ state ┆ session_start_year ┆ num_bills │\n",
       "│ ---   ┆ ---                ┆ ---       │\n",
       "│ str   ┆ i64                ┆ i64       │\n",
       "╞═══════╪════════════════════╪═══════════╡\n",
       "│ IL    ┆ 2017               ┆ 13616     │\n",
       "│ IL    ┆ 2019               ┆ 12760     │\n",
       "│ IL    ┆ 2021               ┆ 12847     │\n",
       "│ IL    ┆ 2023               ┆ 11951     │\n",
       "│ MI    ┆ 2017               ┆ 4818      │\n",
       "│ …     ┆ …                  ┆ …         │\n",
       "│ MI    ┆ 2023               ┆ 3424      │\n",
       "│ WI    ┆ 2017               ┆ 1820      │\n",
       "│ WI    ┆ 2019               ┆ 2264      │\n",
       "│ WI    ┆ 2021               ┆ 2618      │\n",
       "│ WI    ┆ 2023               ┆ 2656      │\n",
       "└───────┴────────────────────┴───────────┘"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Also OK, limited use of global variables.\n",
    "#\n",
    "# Avoid `df` though because that is a common parameter name and not helpful in a global context.\n",
    "# Also to avoid: `df2`, `df_pure`, `df_final_final_final_final_v4_v9`.\n",
    "\n",
    "# first let's load and look at a dataframe with three columns\n",
    "#  there is an observation for each state legislature, showing how many bills they introduced in a given year\n",
    "bills = pl.read_csv(\"midwest_bills.csv\")\n",
    "\n",
    "# Having a dataframe or chart variable as the last line in a notebook cell will automatically display it.\n",
    "#  Use sparingly, and typically only for final chart in your own work, but in tutorials I will show intermediate steps.\n",
    "bills"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "bkHC",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Let's make our own charts of this data, first we bind the data to a new chart object\n",
    "chart = alt.Chart(df)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "lEQa",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "<style>\n",
       "  #altair-viz-ce76917b42b6429cac34c70b23e012b3.vega-embed {\n",
       "    width: 100%;\n",
       "    display: flex;\n",
       "  }\n",
       "\n",
       "  #altair-viz-ce76917b42b6429cac34c70b23e012b3.vega-embed details,\n",
       "  #altair-viz-ce76917b42b6429cac34c70b23e012b3.vega-embed details summary {\n",
       "    position: relative;\n",
       "  }\n",
       "</style>\n",
       "<div id=\"altair-viz-ce76917b42b6429cac34c70b23e012b3\"></div>\n",
       "<script type=\"text/javascript\">\n",
       "  var VEGA_DEBUG = (typeof VEGA_DEBUG == \"undefined\") ? {} : VEGA_DEBUG;\n",
       "  (function(spec, embedOpt){\n",
       "    let outputDiv = document.currentScript.previousElementSibling;\n",
       "    if (outputDiv.id !== \"altair-viz-ce76917b42b6429cac34c70b23e012b3\") {\n",
       "      outputDiv = document.getElementById(\"altair-viz-ce76917b42b6429cac34c70b23e012b3\");\n",
       "    }\n",
       "    const paths = {\n",
       "      \"vega\": \"https://cdn.jsdelivr.net/npm/vega@5?noext\",\n",
       "      \"vega-lib\": \"https://cdn.jsdelivr.net/npm/vega-lib?noext\",\n",
       "      \"vega-lite\": \"https://cdn.jsdelivr.net/npm/vega-lite@5.20.1?noext\",\n",
       "      \"vega-embed\": \"https://cdn.jsdelivr.net/npm/vega-embed@6?noext\",\n",
       "    };\n",
       "\n",
       "    function maybeLoadScript(lib, version) {\n",
       "      var key = `${lib.replace(\"-\", \"\")}_version`;\n",
       "      return (VEGA_DEBUG[key] == version) ?\n",
       "        Promise.resolve(paths[lib]) :\n",
       "        new Promise(function(resolve, reject) {\n",
       "          var s = document.createElement('script');\n",
       "          document.getElementsByTagName(\"head\")[0].appendChild(s);\n",
       "          s.async = true;\n",
       "          s.onload = () => {\n",
       "            VEGA_DEBUG[key] = version;\n",
       "            return resolve(paths[lib]);\n",
       "          };\n",
       "          s.onerror = () => reject(`Error loading script: ${paths[lib]}`);\n",
       "          s.src = paths[lib];\n",
       "        });\n",
       "    }\n",
       "\n",
       "    function showError(err) {\n",
       "      outputDiv.innerHTML = `<div class=\"error\" style=\"color:red;\">${err}</div>`;\n",
       "      throw err;\n",
       "    }\n",
       "\n",
       "    function displayChart(vegaEmbed) {\n",
       "      vegaEmbed(outputDiv, spec, embedOpt)\n",
       "        .catch(err => showError(`Javascript Error: ${err.message}<br>This usually means there's a typo in your chart specification. See the javascript console for the full traceback.`));\n",
       "    }\n",
       "\n",
       "    if(typeof define === \"function\" && define.amd) {\n",
       "      requirejs.config({paths});\n",
       "      require([\"vega-embed\"], displayChart, err => showError(`Error loading script: ${err.message}`));\n",
       "    } else {\n",
       "      maybeLoadScript(\"vega\", \"5\")\n",
       "        .then(() => maybeLoadScript(\"vega-lite\", \"5.20.1\"))\n",
       "        .then(() => maybeLoadScript(\"vega-embed\", \"6\"))\n",
       "        .catch(showError)\n",
       "        .then(() => displayChart(vegaEmbed));\n",
       "    }\n",
       "  })({\"config\": {\"view\": {\"continuousWidth\": 300, \"continuousHeight\": 300}}, \"data\": {\"name\": \"data-7819b1facf2e5fc9998dcf4cad0b99f8\"}, \"mark\": {\"type\": \"point\"}, \"$schema\": \"https://vega.github.io/schema/vega-lite/v5.20.1.json\", \"datasets\": {\"data-7819b1facf2e5fc9998dcf4cad0b99f8\": [{\"state\": \"IL\", \"session_start_year\": 2017, \"num_bills\": 13616}, {\"state\": \"IL\", \"session_start_year\": 2019, \"num_bills\": 12760}, {\"state\": \"IL\", \"session_start_year\": 2021, \"num_bills\": 12847}, {\"state\": \"IL\", \"session_start_year\": 2023, \"num_bills\": 11951}, {\"state\": \"MI\", \"session_start_year\": 2017, \"num_bills\": 4818}, {\"state\": \"MI\", \"session_start_year\": 2019, \"num_bills\": 4450}, {\"state\": \"MI\", \"session_start_year\": 2021, \"num_bills\": 4520}, {\"state\": \"MI\", \"session_start_year\": 2023, \"num_bills\": 3424}, {\"state\": \"WI\", \"session_start_year\": 2017, \"num_bills\": 1820}, {\"state\": \"WI\", \"session_start_year\": 2019, \"num_bills\": 2264}, {\"state\": \"WI\", \"session_start_year\": 2021, \"num_bills\": 2618}, {\"state\": \"WI\", \"session_start_year\": 2023, \"num_bills\": 2656}]}}, {\"mode\": \"vega-lite\"});\n",
       "</script>"
      ],
      "text/plain": [
       "alt.Chart(...)"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# we add a geometry, we'll start with a point (at this point *something* can be displayed, but it won't be useful)\n",
    "chart.mark_point()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "PKri",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "<style>\n",
       "  #altair-viz-14388f53e0d5400b802ade3cdfacd6b8.vega-embed {\n",
       "    width: 100%;\n",
       "    display: flex;\n",
       "  }\n",
       "\n",
       "  #altair-viz-14388f53e0d5400b802ade3cdfacd6b8.vega-embed details,\n",
       "  #altair-viz-14388f53e0d5400b802ade3cdfacd6b8.vega-embed details summary {\n",
       "    position: relative;\n",
       "  }\n",
       "</style>\n",
       "<div id=\"altair-viz-14388f53e0d5400b802ade3cdfacd6b8\"></div>\n",
       "<script type=\"text/javascript\">\n",
       "  var VEGA_DEBUG = (typeof VEGA_DEBUG == \"undefined\") ? {} : VEGA_DEBUG;\n",
       "  (function(spec, embedOpt){\n",
       "    let outputDiv = document.currentScript.previousElementSibling;\n",
       "    if (outputDiv.id !== \"altair-viz-14388f53e0d5400b802ade3cdfacd6b8\") {\n",
       "      outputDiv = document.getElementById(\"altair-viz-14388f53e0d5400b802ade3cdfacd6b8\");\n",
       "    }\n",
       "    const paths = {\n",
       "      \"vega\": \"https://cdn.jsdelivr.net/npm/vega@5?noext\",\n",
       "      \"vega-lib\": \"https://cdn.jsdelivr.net/npm/vega-lib?noext\",\n",
       "      \"vega-lite\": \"https://cdn.jsdelivr.net/npm/vega-lite@5.20.1?noext\",\n",
       "      \"vega-embed\": \"https://cdn.jsdelivr.net/npm/vega-embed@6?noext\",\n",
       "    };\n",
       "\n",
       "    function maybeLoadScript(lib, version) {\n",
       "      var key = `${lib.replace(\"-\", \"\")}_version`;\n",
       "      return (VEGA_DEBUG[key] == version) ?\n",
       "        Promise.resolve(paths[lib]) :\n",
       "        new Promise(function(resolve, reject) {\n",
       "          var s = document.createElement('script');\n",
       "          document.getElementsByTagName(\"head\")[0].appendChild(s);\n",
       "          s.async = true;\n",
       "          s.onload = () => {\n",
       "            VEGA_DEBUG[key] = version;\n",
       "            return resolve(paths[lib]);\n",
       "          };\n",
       "          s.onerror = () => reject(`Error loading script: ${paths[lib]}`);\n",
       "          s.src = paths[lib];\n",
       "        });\n",
       "    }\n",
       "\n",
       "    function showError(err) {\n",
       "      outputDiv.innerHTML = `<div class=\"error\" style=\"color:red;\">${err}</div>`;\n",
       "      throw err;\n",
       "    }\n",
       "\n",
       "    function displayChart(vegaEmbed) {\n",
       "      vegaEmbed(outputDiv, spec, embedOpt)\n",
       "        .catch(err => showError(`Javascript Error: ${err.message}<br>This usually means there's a typo in your chart specification. See the javascript console for the full traceback.`));\n",
       "    }\n",
       "\n",
       "    if(typeof define === \"function\" && define.amd) {\n",
       "      requirejs.config({paths});\n",
       "      require([\"vega-embed\"], displayChart, err => showError(`Error loading script: ${err.message}`));\n",
       "    } else {\n",
       "      maybeLoadScript(\"vega\", \"5\")\n",
       "        .then(() => maybeLoadScript(\"vega-lite\", \"5.20.1\"))\n",
       "        .then(() => maybeLoadScript(\"vega-embed\", \"6\"))\n",
       "        .catch(showError)\n",
       "        .then(() => displayChart(vegaEmbed));\n",
       "    }\n",
       "  })({\"config\": {\"view\": {\"continuousWidth\": 300, \"continuousHeight\": 300}}, \"data\": {\"name\": \"data-7819b1facf2e5fc9998dcf4cad0b99f8\"}, \"mark\": {\"type\": \"point\"}, \"encoding\": {\"x\": {\"field\": \"num_bills\", \"type\": \"quantitative\"}, \"y\": {\"field\": \"state\", \"type\": \"nominal\"}}, \"$schema\": \"https://vega.github.io/schema/vega-lite/v5.20.1.json\", \"datasets\": {\"data-7819b1facf2e5fc9998dcf4cad0b99f8\": [{\"state\": \"IL\", \"session_start_year\": 2017, \"num_bills\": 13616}, {\"state\": \"IL\", \"session_start_year\": 2019, \"num_bills\": 12760}, {\"state\": \"IL\", \"session_start_year\": 2021, \"num_bills\": 12847}, {\"state\": \"IL\", \"session_start_year\": 2023, \"num_bills\": 11951}, {\"state\": \"MI\", \"session_start_year\": 2017, \"num_bills\": 4818}, {\"state\": \"MI\", \"session_start_year\": 2019, \"num_bills\": 4450}, {\"state\": \"MI\", \"session_start_year\": 2021, \"num_bills\": 4520}, {\"state\": \"MI\", \"session_start_year\": 2023, \"num_bills\": 3424}, {\"state\": \"WI\", \"session_start_year\": 2017, \"num_bills\": 1820}, {\"state\": \"WI\", \"session_start_year\": 2019, \"num_bills\": 2264}, {\"state\": \"WI\", \"session_start_year\": 2021, \"num_bills\": 2618}, {\"state\": \"WI\", \"session_start_year\": 2023, \"num_bills\": 2656}]}}, {\"mode\": \"vega-lite\"});\n",
       "</script>"
      ],
      "text/plain": [
       "alt.Chart(...)"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Example 1\n",
    "# We use encodings to map our data to particular dimensions.\n",
    "# Altair will make then make appropriate choices based upon the type of data.\n",
    "\n",
    "chart.mark_point().encode(\n",
    "    y=\"state\",\n",
    "    x=\"num_bills\"\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "SFPL",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "<style>\n",
       "  #altair-viz-c0984a148f9845b7be3b4dc92f7faa3c.vega-embed {\n",
       "    width: 100%;\n",
       "    display: flex;\n",
       "  }\n",
       "\n",
       "  #altair-viz-c0984a148f9845b7be3b4dc92f7faa3c.vega-embed details,\n",
       "  #altair-viz-c0984a148f9845b7be3b4dc92f7faa3c.vega-embed details summary {\n",
       "    position: relative;\n",
       "  }\n",
       "</style>\n",
       "<div id=\"altair-viz-c0984a148f9845b7be3b4dc92f7faa3c\"></div>\n",
       "<script type=\"text/javascript\">\n",
       "  var VEGA_DEBUG = (typeof VEGA_DEBUG == \"undefined\") ? {} : VEGA_DEBUG;\n",
       "  (function(spec, embedOpt){\n",
       "    let outputDiv = document.currentScript.previousElementSibling;\n",
       "    if (outputDiv.id !== \"altair-viz-c0984a148f9845b7be3b4dc92f7faa3c\") {\n",
       "      outputDiv = document.getElementById(\"altair-viz-c0984a148f9845b7be3b4dc92f7faa3c\");\n",
       "    }\n",
       "    const paths = {\n",
       "      \"vega\": \"https://cdn.jsdelivr.net/npm/vega@5?noext\",\n",
       "      \"vega-lib\": \"https://cdn.jsdelivr.net/npm/vega-lib?noext\",\n",
       "      \"vega-lite\": \"https://cdn.jsdelivr.net/npm/vega-lite@5.20.1?noext\",\n",
       "      \"vega-embed\": \"https://cdn.jsdelivr.net/npm/vega-embed@6?noext\",\n",
       "    };\n",
       "\n",
       "    function maybeLoadScript(lib, version) {\n",
       "      var key = `${lib.replace(\"-\", \"\")}_version`;\n",
       "      return (VEGA_DEBUG[key] == version) ?\n",
       "        Promise.resolve(paths[lib]) :\n",
       "        new Promise(function(resolve, reject) {\n",
       "          var s = document.createElement('script');\n",
       "          document.getElementsByTagName(\"head\")[0].appendChild(s);\n",
       "          s.async = true;\n",
       "          s.onload = () => {\n",
       "            VEGA_DEBUG[key] = version;\n",
       "            return resolve(paths[lib]);\n",
       "          };\n",
       "          s.onerror = () => reject(`Error loading script: ${paths[lib]}`);\n",
       "          s.src = paths[lib];\n",
       "        });\n",
       "    }\n",
       "\n",
       "    function showError(err) {\n",
       "      outputDiv.innerHTML = `<div class=\"error\" style=\"color:red;\">${err}</div>`;\n",
       "      throw err;\n",
       "    }\n",
       "\n",
       "    function displayChart(vegaEmbed) {\n",
       "      vegaEmbed(outputDiv, spec, embedOpt)\n",
       "        .catch(err => showError(`Javascript Error: ${err.message}<br>This usually means there's a typo in your chart specification. See the javascript console for the full traceback.`));\n",
       "    }\n",
       "\n",
       "    if(typeof define === \"function\" && define.amd) {\n",
       "      requirejs.config({paths});\n",
       "      require([\"vega-embed\"], displayChart, err => showError(`Error loading script: ${err.message}`));\n",
       "    } else {\n",
       "      maybeLoadScript(\"vega\", \"5\")\n",
       "        .then(() => maybeLoadScript(\"vega-lite\", \"5.20.1\"))\n",
       "        .then(() => maybeLoadScript(\"vega-embed\", \"6\"))\n",
       "        .catch(showError)\n",
       "        .then(() => displayChart(vegaEmbed));\n",
       "    }\n",
       "  })({\"config\": {\"view\": {\"continuousWidth\": 300, \"continuousHeight\": 300}}, \"data\": {\"name\": \"data-7819b1facf2e5fc9998dcf4cad0b99f8\"}, \"mark\": {\"type\": \"point\"}, \"encoding\": {\"color\": {\"field\": \"session_start_year\", \"type\": \"quantitative\"}, \"x\": {\"field\": \"num_bills\", \"type\": \"quantitative\"}, \"y\": {\"field\": \"state\", \"type\": \"nominal\"}}, \"$schema\": \"https://vega.github.io/schema/vega-lite/v5.20.1.json\", \"datasets\": {\"data-7819b1facf2e5fc9998dcf4cad0b99f8\": [{\"state\": \"IL\", \"session_start_year\": 2017, \"num_bills\": 13616}, {\"state\": \"IL\", \"session_start_year\": 2019, \"num_bills\": 12760}, {\"state\": \"IL\", \"session_start_year\": 2021, \"num_bills\": 12847}, {\"state\": \"IL\", \"session_start_year\": 2023, \"num_bills\": 11951}, {\"state\": \"MI\", \"session_start_year\": 2017, \"num_bills\": 4818}, {\"state\": \"MI\", \"session_start_year\": 2019, \"num_bills\": 4450}, {\"state\": \"MI\", \"session_start_year\": 2021, \"num_bills\": 4520}, {\"state\": \"MI\", \"session_start_year\": 2023, \"num_bills\": 3424}, {\"state\": \"WI\", \"session_start_year\": 2017, \"num_bills\": 1820}, {\"state\": \"WI\", \"session_start_year\": 2019, \"num_bills\": 2264}, {\"state\": \"WI\", \"session_start_year\": 2021, \"num_bills\": 2618}, {\"state\": \"WI\", \"session_start_year\": 2023, \"num_bills\": 2656}]}}, {\"mode\": \"vega-lite\"});\n",
       "</script>"
      ],
      "text/plain": [
       "alt.Chart(...)"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Example 2 - what happens when we try to add color?\n",
    "chart.mark_point().encode(\n",
    "    alt.Y(\"state\"),\n",
    "    alt.X(\"num_bills\"),\n",
    "    alt.Color(\"session_start_year\"),\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "id": "BYtC",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "<style>\n",
       "  #altair-viz-aea0a88137694b9a82ca539c11313c96.vega-embed {\n",
       "    width: 100%;\n",
       "    display: flex;\n",
       "  }\n",
       "\n",
       "  #altair-viz-aea0a88137694b9a82ca539c11313c96.vega-embed details,\n",
       "  #altair-viz-aea0a88137694b9a82ca539c11313c96.vega-embed details summary {\n",
       "    position: relative;\n",
       "  }\n",
       "</style>\n",
       "<div id=\"altair-viz-aea0a88137694b9a82ca539c11313c96\"></div>\n",
       "<script type=\"text/javascript\">\n",
       "  var VEGA_DEBUG = (typeof VEGA_DEBUG == \"undefined\") ? {} : VEGA_DEBUG;\n",
       "  (function(spec, embedOpt){\n",
       "    let outputDiv = document.currentScript.previousElementSibling;\n",
       "    if (outputDiv.id !== \"altair-viz-aea0a88137694b9a82ca539c11313c96\") {\n",
       "      outputDiv = document.getElementById(\"altair-viz-aea0a88137694b9a82ca539c11313c96\");\n",
       "    }\n",
       "    const paths = {\n",
       "      \"vega\": \"https://cdn.jsdelivr.net/npm/vega@5?noext\",\n",
       "      \"vega-lib\": \"https://cdn.jsdelivr.net/npm/vega-lib?noext\",\n",
       "      \"vega-lite\": \"https://cdn.jsdelivr.net/npm/vega-lite@5.20.1?noext\",\n",
       "      \"vega-embed\": \"https://cdn.jsdelivr.net/npm/vega-embed@6?noext\",\n",
       "    };\n",
       "\n",
       "    function maybeLoadScript(lib, version) {\n",
       "      var key = `${lib.replace(\"-\", \"\")}_version`;\n",
       "      return (VEGA_DEBUG[key] == version) ?\n",
       "        Promise.resolve(paths[lib]) :\n",
       "        new Promise(function(resolve, reject) {\n",
       "          var s = document.createElement('script');\n",
       "          document.getElementsByTagName(\"head\")[0].appendChild(s);\n",
       "          s.async = true;\n",
       "          s.onload = () => {\n",
       "            VEGA_DEBUG[key] = version;\n",
       "            return resolve(paths[lib]);\n",
       "          };\n",
       "          s.onerror = () => reject(`Error loading script: ${paths[lib]}`);\n",
       "          s.src = paths[lib];\n",
       "        });\n",
       "    }\n",
       "\n",
       "    function showError(err) {\n",
       "      outputDiv.innerHTML = `<div class=\"error\" style=\"color:red;\">${err}</div>`;\n",
       "      throw err;\n",
       "    }\n",
       "\n",
       "    function displayChart(vegaEmbed) {\n",
       "      vegaEmbed(outputDiv, spec, embedOpt)\n",
       "        .catch(err => showError(`Javascript Error: ${err.message}<br>This usually means there's a typo in your chart specification. See the javascript console for the full traceback.`));\n",
       "    }\n",
       "\n",
       "    if(typeof define === \"function\" && define.amd) {\n",
       "      requirejs.config({paths});\n",
       "      require([\"vega-embed\"], displayChart, err => showError(`Error loading script: ${err.message}`));\n",
       "    } else {\n",
       "      maybeLoadScript(\"vega\", \"5\")\n",
       "        .then(() => maybeLoadScript(\"vega-lite\", \"5.20.1\"))\n",
       "        .then(() => maybeLoadScript(\"vega-embed\", \"6\"))\n",
       "        .catch(showError)\n",
       "        .then(() => displayChart(vegaEmbed));\n",
       "    }\n",
       "  })({\"config\": {\"view\": {\"continuousWidth\": 300, \"continuousHeight\": 300}}, \"data\": {\"name\": \"data-7819b1facf2e5fc9998dcf4cad0b99f8\"}, \"mark\": {\"type\": \"point\"}, \"encoding\": {\"color\": {\"field\": \"session_start_year\", \"type\": \"nominal\"}, \"x\": {\"field\": \"num_bills\", \"type\": \"quantitative\"}, \"y\": {\"field\": \"state\", \"type\": \"nominal\"}}, \"$schema\": \"https://vega.github.io/schema/vega-lite/v5.20.1.json\", \"datasets\": {\"data-7819b1facf2e5fc9998dcf4cad0b99f8\": [{\"state\": \"IL\", \"session_start_year\": 2017, \"num_bills\": 13616}, {\"state\": \"IL\", \"session_start_year\": 2019, \"num_bills\": 12760}, {\"state\": \"IL\", \"session_start_year\": 2021, \"num_bills\": 12847}, {\"state\": \"IL\", \"session_start_year\": 2023, \"num_bills\": 11951}, {\"state\": \"MI\", \"session_start_year\": 2017, \"num_bills\": 4818}, {\"state\": \"MI\", \"session_start_year\": 2019, \"num_bills\": 4450}, {\"state\": \"MI\", \"session_start_year\": 2021, \"num_bills\": 4520}, {\"state\": \"MI\", \"session_start_year\": 2023, \"num_bills\": 3424}, {\"state\": \"WI\", \"session_start_year\": 2017, \"num_bills\": 1820}, {\"state\": \"WI\", \"session_start_year\": 2019, \"num_bills\": 2264}, {\"state\": \"WI\", \"session_start_year\": 2021, \"num_bills\": 2618}, {\"state\": \"WI\", \"session_start_year\": 2023, \"num_bills\": 2656}]}}, {\"mode\": \"vega-lite\"});\n",
       "</script>"
      ],
      "text/plain": [
       "alt.Chart(...)"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Example 3\n",
    "# The prior example treated year as an Ordinal because it was numeric,\n",
    "# instead we would treat it as Nominal for this data.\n",
    "# We can use :Q, :O, :N, :T to mark the type that should be used.\n",
    "\n",
    "by_year = chart.mark_point().encode(\n",
    "    alt.Y(\"state:N\"),\n",
    "    alt.X(\"num_bills:Q\"),\n",
    "    alt.Color(\"session_start_year:N\"),\n",
    ")\n",
    "\n",
    "# we're saving this one for later, so repeat the variable name to see it\n",
    "by_year"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "id": "RGSE",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "<style>\n",
       "  #altair-viz-95590e473fb24ba09fde2dc67ddfb3e8.vega-embed {\n",
       "    width: 100%;\n",
       "    display: flex;\n",
       "  }\n",
       "\n",
       "  #altair-viz-95590e473fb24ba09fde2dc67ddfb3e8.vega-embed details,\n",
       "  #altair-viz-95590e473fb24ba09fde2dc67ddfb3e8.vega-embed details summary {\n",
       "    position: relative;\n",
       "  }\n",
       "</style>\n",
       "<div id=\"altair-viz-95590e473fb24ba09fde2dc67ddfb3e8\"></div>\n",
       "<script type=\"text/javascript\">\n",
       "  var VEGA_DEBUG = (typeof VEGA_DEBUG == \"undefined\") ? {} : VEGA_DEBUG;\n",
       "  (function(spec, embedOpt){\n",
       "    let outputDiv = document.currentScript.previousElementSibling;\n",
       "    if (outputDiv.id !== \"altair-viz-95590e473fb24ba09fde2dc67ddfb3e8\") {\n",
       "      outputDiv = document.getElementById(\"altair-viz-95590e473fb24ba09fde2dc67ddfb3e8\");\n",
       "    }\n",
       "    const paths = {\n",
       "      \"vega\": \"https://cdn.jsdelivr.net/npm/vega@5?noext\",\n",
       "      \"vega-lib\": \"https://cdn.jsdelivr.net/npm/vega-lib?noext\",\n",
       "      \"vega-lite\": \"https://cdn.jsdelivr.net/npm/vega-lite@5.20.1?noext\",\n",
       "      \"vega-embed\": \"https://cdn.jsdelivr.net/npm/vega-embed@6?noext\",\n",
       "    };\n",
       "\n",
       "    function maybeLoadScript(lib, version) {\n",
       "      var key = `${lib.replace(\"-\", \"\")}_version`;\n",
       "      return (VEGA_DEBUG[key] == version) ?\n",
       "        Promise.resolve(paths[lib]) :\n",
       "        new Promise(function(resolve, reject) {\n",
       "          var s = document.createElement('script');\n",
       "          document.getElementsByTagName(\"head\")[0].appendChild(s);\n",
       "          s.async = true;\n",
       "          s.onload = () => {\n",
       "            VEGA_DEBUG[key] = version;\n",
       "            return resolve(paths[lib]);\n",
       "          };\n",
       "          s.onerror = () => reject(`Error loading script: ${paths[lib]}`);\n",
       "          s.src = paths[lib];\n",
       "        });\n",
       "    }\n",
       "\n",
       "    function showError(err) {\n",
       "      outputDiv.innerHTML = `<div class=\"error\" style=\"color:red;\">${err}</div>`;\n",
       "      throw err;\n",
       "    }\n",
       "\n",
       "    function displayChart(vegaEmbed) {\n",
       "      vegaEmbed(outputDiv, spec, embedOpt)\n",
       "        .catch(err => showError(`Javascript Error: ${err.message}<br>This usually means there's a typo in your chart specification. See the javascript console for the full traceback.`));\n",
       "    }\n",
       "\n",
       "    if(typeof define === \"function\" && define.amd) {\n",
       "      requirejs.config({paths});\n",
       "      require([\"vega-embed\"], displayChart, err => showError(`Error loading script: ${err.message}`));\n",
       "    } else {\n",
       "      maybeLoadScript(\"vega\", \"5\")\n",
       "        .then(() => maybeLoadScript(\"vega-lite\", \"5.20.1\"))\n",
       "        .then(() => maybeLoadScript(\"vega-embed\", \"6\"))\n",
       "        .catch(showError)\n",
       "        .then(() => displayChart(vegaEmbed));\n",
       "    }\n",
       "  })({\"config\": {\"view\": {\"continuousWidth\": 300, \"continuousHeight\": 300}}, \"data\": {\"name\": \"data-7819b1facf2e5fc9998dcf4cad0b99f8\"}, \"mark\": {\"type\": \"point\", \"shape\": \"wedge\"}, \"encoding\": {\"x\": {\"aggregate\": \"average\", \"field\": \"num_bills\", \"type\": \"quantitative\"}, \"y\": {\"field\": \"state\", \"type\": \"nominal\"}}, \"$schema\": \"https://vega.github.io/schema/vega-lite/v5.20.1.json\", \"datasets\": {\"data-7819b1facf2e5fc9998dcf4cad0b99f8\": [{\"state\": \"IL\", \"session_start_year\": 2017, \"num_bills\": 13616}, {\"state\": \"IL\", \"session_start_year\": 2019, \"num_bills\": 12760}, {\"state\": \"IL\", \"session_start_year\": 2021, \"num_bills\": 12847}, {\"state\": \"IL\", \"session_start_year\": 2023, \"num_bills\": 11951}, {\"state\": \"MI\", \"session_start_year\": 2017, \"num_bills\": 4818}, {\"state\": \"MI\", \"session_start_year\": 2019, \"num_bills\": 4450}, {\"state\": \"MI\", \"session_start_year\": 2021, \"num_bills\": 4520}, {\"state\": \"MI\", \"session_start_year\": 2023, \"num_bills\": 3424}, {\"state\": \"WI\", \"session_start_year\": 2017, \"num_bills\": 1820}, {\"state\": \"WI\", \"session_start_year\": 2019, \"num_bills\": 2264}, {\"state\": \"WI\", \"session_start_year\": 2021, \"num_bills\": 2618}, {\"state\": \"WI\", \"session_start_year\": 2023, \"num_bills\": 2656}]}}, {\"mode\": \"vega-lite\"});\n",
       "</script>"
      ],
      "text/plain": [
       "alt.Chart(...)"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Example 4\n",
    "# Here we make a different chart from the same base data \n",
    "# by re-using our `chart` variable.\n",
    "#\n",
    "# We choose a different shape (parameters that don't need to vary can be passed into the mark_* functions)\n",
    "# We also use an aggregate function average(num_bills)\n",
    "\n",
    "avgs = chart.mark_point(shape=\"wedge\").encode(\n",
    "    alt.Y(\"state:N\"),\n",
    "    alt.X(\"average(num_bills)\"),\n",
    ")\n",
    "avgs"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "id": "Kclp",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "<style>\n",
       "  #altair-viz-84be3b793e6b4ba5970b06e34046c01c.vega-embed {\n",
       "    width: 100%;\n",
       "    display: flex;\n",
       "  }\n",
       "\n",
       "  #altair-viz-84be3b793e6b4ba5970b06e34046c01c.vega-embed details,\n",
       "  #altair-viz-84be3b793e6b4ba5970b06e34046c01c.vega-embed details summary {\n",
       "    position: relative;\n",
       "  }\n",
       "</style>\n",
       "<div id=\"altair-viz-84be3b793e6b4ba5970b06e34046c01c\"></div>\n",
       "<script type=\"text/javascript\">\n",
       "  var VEGA_DEBUG = (typeof VEGA_DEBUG == \"undefined\") ? {} : VEGA_DEBUG;\n",
       "  (function(spec, embedOpt){\n",
       "    let outputDiv = document.currentScript.previousElementSibling;\n",
       "    if (outputDiv.id !== \"altair-viz-84be3b793e6b4ba5970b06e34046c01c\") {\n",
       "      outputDiv = document.getElementById(\"altair-viz-84be3b793e6b4ba5970b06e34046c01c\");\n",
       "    }\n",
       "    const paths = {\n",
       "      \"vega\": \"https://cdn.jsdelivr.net/npm/vega@5?noext\",\n",
       "      \"vega-lib\": \"https://cdn.jsdelivr.net/npm/vega-lib?noext\",\n",
       "      \"vega-lite\": \"https://cdn.jsdelivr.net/npm/vega-lite@5.20.1?noext\",\n",
       "      \"vega-embed\": \"https://cdn.jsdelivr.net/npm/vega-embed@6?noext\",\n",
       "    };\n",
       "\n",
       "    function maybeLoadScript(lib, version) {\n",
       "      var key = `${lib.replace(\"-\", \"\")}_version`;\n",
       "      return (VEGA_DEBUG[key] == version) ?\n",
       "        Promise.resolve(paths[lib]) :\n",
       "        new Promise(function(resolve, reject) {\n",
       "          var s = document.createElement('script');\n",
       "          document.getElementsByTagName(\"head\")[0].appendChild(s);\n",
       "          s.async = true;\n",
       "          s.onload = () => {\n",
       "            VEGA_DEBUG[key] = version;\n",
       "            return resolve(paths[lib]);\n",
       "          };\n",
       "          s.onerror = () => reject(`Error loading script: ${paths[lib]}`);\n",
       "          s.src = paths[lib];\n",
       "        });\n",
       "    }\n",
       "\n",
       "    function showError(err) {\n",
       "      outputDiv.innerHTML = `<div class=\"error\" style=\"color:red;\">${err}</div>`;\n",
       "      throw err;\n",
       "    }\n",
       "\n",
       "    function displayChart(vegaEmbed) {\n",
       "      vegaEmbed(outputDiv, spec, embedOpt)\n",
       "        .catch(err => showError(`Javascript Error: ${err.message}<br>This usually means there's a typo in your chart specification. See the javascript console for the full traceback.`));\n",
       "    }\n",
       "\n",
       "    if(typeof define === \"function\" && define.amd) {\n",
       "      requirejs.config({paths});\n",
       "      require([\"vega-embed\"], displayChart, err => showError(`Error loading script: ${err.message}`));\n",
       "    } else {\n",
       "      maybeLoadScript(\"vega\", \"5\")\n",
       "        .then(() => maybeLoadScript(\"vega-lite\", \"5.20.1\"))\n",
       "        .then(() => maybeLoadScript(\"vega-embed\", \"6\"))\n",
       "        .catch(showError)\n",
       "        .then(() => displayChart(vegaEmbed));\n",
       "    }\n",
       "  })({\"config\": {\"view\": {\"continuousWidth\": 300, \"continuousHeight\": 300}}, \"layer\": [{\"mark\": {\"type\": \"point\"}, \"encoding\": {\"color\": {\"field\": \"session_start_year\", \"type\": \"nominal\"}, \"x\": {\"field\": \"num_bills\", \"type\": \"quantitative\"}, \"y\": {\"field\": \"state\", \"type\": \"nominal\"}}}, {\"mark\": {\"type\": \"point\", \"shape\": \"wedge\"}, \"encoding\": {\"x\": {\"aggregate\": \"average\", \"field\": \"num_bills\", \"type\": \"quantitative\"}, \"y\": {\"field\": \"state\", \"type\": \"nominal\"}}}], \"data\": {\"name\": \"data-7819b1facf2e5fc9998dcf4cad0b99f8\"}, \"$schema\": \"https://vega.github.io/schema/vega-lite/v5.20.1.json\", \"datasets\": {\"data-7819b1facf2e5fc9998dcf4cad0b99f8\": [{\"state\": \"IL\", \"session_start_year\": 2017, \"num_bills\": 13616}, {\"state\": \"IL\", \"session_start_year\": 2019, \"num_bills\": 12760}, {\"state\": \"IL\", \"session_start_year\": 2021, \"num_bills\": 12847}, {\"state\": \"IL\", \"session_start_year\": 2023, \"num_bills\": 11951}, {\"state\": \"MI\", \"session_start_year\": 2017, \"num_bills\": 4818}, {\"state\": \"MI\", \"session_start_year\": 2019, \"num_bills\": 4450}, {\"state\": \"MI\", \"session_start_year\": 2021, \"num_bills\": 4520}, {\"state\": \"MI\", \"session_start_year\": 2023, \"num_bills\": 3424}, {\"state\": \"WI\", \"session_start_year\": 2017, \"num_bills\": 1820}, {\"state\": \"WI\", \"session_start_year\": 2019, \"num_bills\": 2264}, {\"state\": \"WI\", \"session_start_year\": 2021, \"num_bills\": 2618}, {\"state\": \"WI\", \"session_start_year\": 2023, \"num_bills\": 2656}]}}, {\"mode\": \"vega-lite\"});\n",
       "</script>"
      ],
      "text/plain": [
       "alt.LayerChart(...)"
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Example 5\n",
    "# We can combine compatible charts by using `+` to layer them.\n",
    "# There are other operators you'll encounter that allow placing charts side by side.\n",
    "by_year + avgs"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "id": "Hstk",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "<style>\n",
       "  #altair-viz-73b896755fac48a784ac7b5d2ae8c928.vega-embed {\n",
       "    width: 100%;\n",
       "    display: flex;\n",
       "  }\n",
       "\n",
       "  #altair-viz-73b896755fac48a784ac7b5d2ae8c928.vega-embed details,\n",
       "  #altair-viz-73b896755fac48a784ac7b5d2ae8c928.vega-embed details summary {\n",
       "    position: relative;\n",
       "  }\n",
       "</style>\n",
       "<div id=\"altair-viz-73b896755fac48a784ac7b5d2ae8c928\"></div>\n",
       "<script type=\"text/javascript\">\n",
       "  var VEGA_DEBUG = (typeof VEGA_DEBUG == \"undefined\") ? {} : VEGA_DEBUG;\n",
       "  (function(spec, embedOpt){\n",
       "    let outputDiv = document.currentScript.previousElementSibling;\n",
       "    if (outputDiv.id !== \"altair-viz-73b896755fac48a784ac7b5d2ae8c928\") {\n",
       "      outputDiv = document.getElementById(\"altair-viz-73b896755fac48a784ac7b5d2ae8c928\");\n",
       "    }\n",
       "    const paths = {\n",
       "      \"vega\": \"https://cdn.jsdelivr.net/npm/vega@5?noext\",\n",
       "      \"vega-lib\": \"https://cdn.jsdelivr.net/npm/vega-lib?noext\",\n",
       "      \"vega-lite\": \"https://cdn.jsdelivr.net/npm/vega-lite@5.20.1?noext\",\n",
       "      \"vega-embed\": \"https://cdn.jsdelivr.net/npm/vega-embed@6?noext\",\n",
       "    };\n",
       "\n",
       "    function maybeLoadScript(lib, version) {\n",
       "      var key = `${lib.replace(\"-\", \"\")}_version`;\n",
       "      return (VEGA_DEBUG[key] == version) ?\n",
       "        Promise.resolve(paths[lib]) :\n",
       "        new Promise(function(resolve, reject) {\n",
       "          var s = document.createElement('script');\n",
       "          document.getElementsByTagName(\"head\")[0].appendChild(s);\n",
       "          s.async = true;\n",
       "          s.onload = () => {\n",
       "            VEGA_DEBUG[key] = version;\n",
       "            return resolve(paths[lib]);\n",
       "          };\n",
       "          s.onerror = () => reject(`Error loading script: ${paths[lib]}`);\n",
       "          s.src = paths[lib];\n",
       "        });\n",
       "    }\n",
       "\n",
       "    function showError(err) {\n",
       "      outputDiv.innerHTML = `<div class=\"error\" style=\"color:red;\">${err}</div>`;\n",
       "      throw err;\n",
       "    }\n",
       "\n",
       "    function displayChart(vegaEmbed) {\n",
       "      vegaEmbed(outputDiv, spec, embedOpt)\n",
       "        .catch(err => showError(`Javascript Error: ${err.message}<br>This usually means there's a typo in your chart specification. See the javascript console for the full traceback.`));\n",
       "    }\n",
       "\n",
       "    if(typeof define === \"function\" && define.amd) {\n",
       "      requirejs.config({paths});\n",
       "      require([\"vega-embed\"], displayChart, err => showError(`Error loading script: ${err.message}`));\n",
       "    } else {\n",
       "      maybeLoadScript(\"vega\", \"5\")\n",
       "        .then(() => maybeLoadScript(\"vega-lite\", \"5.20.1\"))\n",
       "        .then(() => maybeLoadScript(\"vega-embed\", \"6\"))\n",
       "        .catch(showError)\n",
       "        .then(() => displayChart(vegaEmbed));\n",
       "    }\n",
       "  })({\"config\": {\"view\": {\"continuousWidth\": 300, \"continuousHeight\": 300}}, \"layer\": [{\"mark\": {\"type\": \"bar\", \"color\": \"#ccc\"}, \"encoding\": {\"x\": {\"aggregate\": \"average\", \"field\": \"num_bills\", \"type\": \"quantitative\"}, \"y\": {\"field\": \"state\", \"type\": \"nominal\"}}}, {\"mark\": {\"type\": \"point\"}, \"encoding\": {\"color\": {\"field\": \"session_start_year\", \"type\": \"nominal\"}, \"x\": {\"field\": \"num_bills\", \"type\": \"quantitative\"}, \"y\": {\"field\": \"state\", \"type\": \"nominal\"}}}], \"data\": {\"name\": \"data-7819b1facf2e5fc9998dcf4cad0b99f8\"}, \"$schema\": \"https://vega.github.io/schema/vega-lite/v5.20.1.json\", \"datasets\": {\"data-7819b1facf2e5fc9998dcf4cad0b99f8\": [{\"state\": \"IL\", \"session_start_year\": 2017, \"num_bills\": 13616}, {\"state\": \"IL\", \"session_start_year\": 2019, \"num_bills\": 12760}, {\"state\": \"IL\", \"session_start_year\": 2021, \"num_bills\": 12847}, {\"state\": \"IL\", \"session_start_year\": 2023, \"num_bills\": 11951}, {\"state\": \"MI\", \"session_start_year\": 2017, \"num_bills\": 4818}, {\"state\": \"MI\", \"session_start_year\": 2019, \"num_bills\": 4450}, {\"state\": \"MI\", \"session_start_year\": 2021, \"num_bills\": 4520}, {\"state\": \"MI\", \"session_start_year\": 2023, \"num_bills\": 3424}, {\"state\": \"WI\", \"session_start_year\": 2017, \"num_bills\": 1820}, {\"state\": \"WI\", \"session_start_year\": 2019, \"num_bills\": 2264}, {\"state\": \"WI\", \"session_start_year\": 2021, \"num_bills\": 2618}, {\"state\": \"WI\", \"session_start_year\": 2023, \"num_bills\": 2656}]}}, {\"mode\": \"vega-lite\"});\n",
       "</script>"
      ],
      "text/plain": [
       "alt.LayerChart(...)"
      ]
     },
     "execution_count": 41,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Example 6\n",
    "# perhaps we don't want to use mark_point anymore, maybe a bar?\n",
    "bar_avgs = chart.mark_bar(color=\"#ccc\").encode(\n",
    "    alt.Y(\"state\"),\n",
    "    alt.X(\"average(num_bills)\"),\n",
    ")\n",
    "bar_avgs + by_year"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "id": "nWHF",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "<style>\n",
       "  #altair-viz-0c92a68553c042fba9cde6540507b9cb.vega-embed {\n",
       "    width: 100%;\n",
       "    display: flex;\n",
       "  }\n",
       "\n",
       "  #altair-viz-0c92a68553c042fba9cde6540507b9cb.vega-embed details,\n",
       "  #altair-viz-0c92a68553c042fba9cde6540507b9cb.vega-embed details summary {\n",
       "    position: relative;\n",
       "  }\n",
       "</style>\n",
       "<div id=\"altair-viz-0c92a68553c042fba9cde6540507b9cb\"></div>\n",
       "<script type=\"text/javascript\">\n",
       "  var VEGA_DEBUG = (typeof VEGA_DEBUG == \"undefined\") ? {} : VEGA_DEBUG;\n",
       "  (function(spec, embedOpt){\n",
       "    let outputDiv = document.currentScript.previousElementSibling;\n",
       "    if (outputDiv.id !== \"altair-viz-0c92a68553c042fba9cde6540507b9cb\") {\n",
       "      outputDiv = document.getElementById(\"altair-viz-0c92a68553c042fba9cde6540507b9cb\");\n",
       "    }\n",
       "    const paths = {\n",
       "      \"vega\": \"https://cdn.jsdelivr.net/npm/vega@5?noext\",\n",
       "      \"vega-lib\": \"https://cdn.jsdelivr.net/npm/vega-lib?noext\",\n",
       "      \"vega-lite\": \"https://cdn.jsdelivr.net/npm/vega-lite@5.20.1?noext\",\n",
       "      \"vega-embed\": \"https://cdn.jsdelivr.net/npm/vega-embed@6?noext\",\n",
       "    };\n",
       "\n",
       "    function maybeLoadScript(lib, version) {\n",
       "      var key = `${lib.replace(\"-\", \"\")}_version`;\n",
       "      return (VEGA_DEBUG[key] == version) ?\n",
       "        Promise.resolve(paths[lib]) :\n",
       "        new Promise(function(resolve, reject) {\n",
       "          var s = document.createElement('script');\n",
       "          document.getElementsByTagName(\"head\")[0].appendChild(s);\n",
       "          s.async = true;\n",
       "          s.onload = () => {\n",
       "            VEGA_DEBUG[key] = version;\n",
       "            return resolve(paths[lib]);\n",
       "          };\n",
       "          s.onerror = () => reject(`Error loading script: ${paths[lib]}`);\n",
       "          s.src = paths[lib];\n",
       "        });\n",
       "    }\n",
       "\n",
       "    function showError(err) {\n",
       "      outputDiv.innerHTML = `<div class=\"error\" style=\"color:red;\">${err}</div>`;\n",
       "      throw err;\n",
       "    }\n",
       "\n",
       "    function displayChart(vegaEmbed) {\n",
       "      vegaEmbed(outputDiv, spec, embedOpt)\n",
       "        .catch(err => showError(`Javascript Error: ${err.message}<br>This usually means there's a typo in your chart specification. See the javascript console for the full traceback.`));\n",
       "    }\n",
       "\n",
       "    if(typeof define === \"function\" && define.amd) {\n",
       "      requirejs.config({paths});\n",
       "      require([\"vega-embed\"], displayChart, err => showError(`Error loading script: ${err.message}`));\n",
       "    } else {\n",
       "      maybeLoadScript(\"vega\", \"5\")\n",
       "        .then(() => maybeLoadScript(\"vega-lite\", \"5.20.1\"))\n",
       "        .then(() => maybeLoadScript(\"vega-embed\", \"6\"))\n",
       "        .catch(showError)\n",
       "        .then(() => displayChart(vegaEmbed));\n",
       "    }\n",
       "  })({\"config\": {\"view\": {\"continuousWidth\": 300, \"continuousHeight\": 300}}, \"layer\": [{\"mark\": {\"type\": \"point\", \"shape\": \"diamond\"}, \"encoding\": {\"color\": {\"field\": \"session_start_year\", \"title\": \"Session Year\", \"type\": \"nominal\"}, \"x\": {\"field\": \"num_bills\", \"type\": \"quantitative\"}, \"y\": {\"field\": \"state\", \"type\": \"nominal\"}}}, {\"mark\": {\"type\": \"bar\", \"color\": \"#70905050\"}, \"encoding\": {\"x\": {\"aggregate\": \"average\", \"field\": \"num_bills\", \"title\": \"Number of Bills Introduced\", \"type\": \"quantitative\"}, \"y\": {\"field\": \"state\", \"type\": \"nominal\"}}}], \"background\": \"#f5f5dc\", \"data\": {\"name\": \"data-7819b1facf2e5fc9998dcf4cad0b99f8\"}, \"title\": \"Midwest Bills by State\", \"$schema\": \"https://vega.github.io/schema/vega-lite/v5.20.1.json\", \"datasets\": {\"data-7819b1facf2e5fc9998dcf4cad0b99f8\": [{\"state\": \"IL\", \"session_start_year\": 2017, \"num_bills\": 13616}, {\"state\": \"IL\", \"session_start_year\": 2019, \"num_bills\": 12760}, {\"state\": \"IL\", \"session_start_year\": 2021, \"num_bills\": 12847}, {\"state\": \"IL\", \"session_start_year\": 2023, \"num_bills\": 11951}, {\"state\": \"MI\", \"session_start_year\": 2017, \"num_bills\": 4818}, {\"state\": \"MI\", \"session_start_year\": 2019, \"num_bills\": 4450}, {\"state\": \"MI\", \"session_start_year\": 2021, \"num_bills\": 4520}, {\"state\": \"MI\", \"session_start_year\": 2023, \"num_bills\": 3424}, {\"state\": \"WI\", \"session_start_year\": 2017, \"num_bills\": 1820}, {\"state\": \"WI\", \"session_start_year\": 2019, \"num_bills\": 2264}, {\"state\": \"WI\", \"session_start_year\": 2021, \"num_bills\": 2618}, {\"state\": \"WI\", \"session_start_year\": 2023, \"num_bills\": 2656}]}}, {\"mode\": \"vega-lite\"});\n",
       "</script>"
      ],
      "text/plain": [
       "alt.LayerChart(...)"
      ]
     },
     "execution_count": 42,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Example 7\n",
    "# We can customize titles and other details by using `.title` and `.properties`\n",
    "# the latter sets chart-wide properties.\n",
    "\n",
    "final = chart.mark_point(shape=\"diamond\").encode(\n",
    "    alt.Y(\"state:N\"),\n",
    "    alt.X(\"num_bills:Q\"),\n",
    "    alt.Color(\"session_start_year:N\").title(\"Session Year\"),\n",
    ") + chart.mark_bar(color=\"#70905050\").encode(\n",
    "    alt.Y(\"state\"),\n",
    "    alt.X(\"average(num_bills)\").title(\"Number of Bills Introduced\"),\n",
    ")\n",
    "final.properties(\n",
    "    title='Midwest Bills by State',\n",
    "    background='#f5f5dc'\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "93b3a8bc-be56-452d-a443-7b4711e339cb",
   "metadata": {},
   "source": [
    "## Exercise\n",
    "\n",
    "Let's say we instead want to see if there are trends by year.\n",
    "Try and create a new chart that:\n",
    "- has year on X axis, and bills on Y\n",
    "- is print & colorblind friendly (using multiple channels for encoding state)\n",
    "- uses a custom color scale, not the default (to avoid confusion with the colors used in our earlier chart)\n",
    "\n",
    "Try completing this below, before continuing on to look at my version."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "id": "3506dd11-76ba-40b0-8e1f-2210dcd3defd",
   "metadata": {},
   "outputs": [],
   "source": [
    "# YOUR SOLUTION HERE"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ZHCJ",
   "metadata": {},
   "source": [
    "### Altair User Guide / Next Steps\n",
    "\n",
    "See <https://capp30239.netlify.app/readings/> for details.\n",
    "\n",
    "You'll want to work your way through the recommended material at your own pace, which will help you learn the material much better than me reading library documentation to you would. :)\n",
    "\n",
    "**You aren't on your own**, we're here to help -- start with documentation and ask questions on Ed, in class, and in office hours.\n",
    "\n",
    "Once you've read the guide and worked through the assignment you will have the core ideas of Altair.\n",
    "\n",
    "The next steps towards mastery are using it a lot and asking questions to deepen understanding, *not leaning on GenAI too much*.\n",
    "\n",
    "You're reading a fairly small subset of the library's documentation. \n",
    "The remaining sections are useful as reference, and as you use Altair you will find your way to them as you ask yourself questions like \"how do I work with geospatial data\" or \"how can I combine these axes\"?\n",
    "\n",
    "It's likely the most common thing you will use the documentation for is \"what arguments can I pass to this?\"\n",
    "\n",
    "For that, use the [API Reference](https://altair-viz.github.io/user_guide/api.html) and find the class you're working with.\n",
    "\n",
    "Example:\n",
    "\n",
    "- Let's say we want to adjust the color scheme, start with <https://altair-viz.github.io/user_guide/generated/channels/altair.Color.html>\n",
    "- Note that it can take a scale, and click to <https://altair-viz.github.io/user_guide/generated/core/altair.Scale.html#altair.Scale>\n",
    "- We find ourselves on Vega documentation, here <https://vega.github.io/vega-lite/docs/scale.html#scheme> before long. Vega documentation can be very helpful for understanding the options that are available, since Altair is an interface to those."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "id": "iLit",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "<style>\n",
       "  #altair-viz-8d10ab61b28f4f6cbb22061c07d924ea.vega-embed {\n",
       "    width: 100%;\n",
       "    display: flex;\n",
       "  }\n",
       "\n",
       "  #altair-viz-8d10ab61b28f4f6cbb22061c07d924ea.vega-embed details,\n",
       "  #altair-viz-8d10ab61b28f4f6cbb22061c07d924ea.vega-embed details summary {\n",
       "    position: relative;\n",
       "  }\n",
       "</style>\n",
       "<div id=\"altair-viz-8d10ab61b28f4f6cbb22061c07d924ea\"></div>\n",
       "<script type=\"text/javascript\">\n",
       "  var VEGA_DEBUG = (typeof VEGA_DEBUG == \"undefined\") ? {} : VEGA_DEBUG;\n",
       "  (function(spec, embedOpt){\n",
       "    let outputDiv = document.currentScript.previousElementSibling;\n",
       "    if (outputDiv.id !== \"altair-viz-8d10ab61b28f4f6cbb22061c07d924ea\") {\n",
       "      outputDiv = document.getElementById(\"altair-viz-8d10ab61b28f4f6cbb22061c07d924ea\");\n",
       "    }\n",
       "    const paths = {\n",
       "      \"vega\": \"https://cdn.jsdelivr.net/npm/vega@5?noext\",\n",
       "      \"vega-lib\": \"https://cdn.jsdelivr.net/npm/vega-lib?noext\",\n",
       "      \"vega-lite\": \"https://cdn.jsdelivr.net/npm/vega-lite@5.20.1?noext\",\n",
       "      \"vega-embed\": \"https://cdn.jsdelivr.net/npm/vega-embed@6?noext\",\n",
       "    };\n",
       "\n",
       "    function maybeLoadScript(lib, version) {\n",
       "      var key = `${lib.replace(\"-\", \"\")}_version`;\n",
       "      return (VEGA_DEBUG[key] == version) ?\n",
       "        Promise.resolve(paths[lib]) :\n",
       "        new Promise(function(resolve, reject) {\n",
       "          var s = document.createElement('script');\n",
       "          document.getElementsByTagName(\"head\")[0].appendChild(s);\n",
       "          s.async = true;\n",
       "          s.onload = () => {\n",
       "            VEGA_DEBUG[key] = version;\n",
       "            return resolve(paths[lib]);\n",
       "          };\n",
       "          s.onerror = () => reject(`Error loading script: ${paths[lib]}`);\n",
       "          s.src = paths[lib];\n",
       "        });\n",
       "    }\n",
       "\n",
       "    function showError(err) {\n",
       "      outputDiv.innerHTML = `<div class=\"error\" style=\"color:red;\">${err}</div>`;\n",
       "      throw err;\n",
       "    }\n",
       "\n",
       "    function displayChart(vegaEmbed) {\n",
       "      vegaEmbed(outputDiv, spec, embedOpt)\n",
       "        .catch(err => showError(`Javascript Error: ${err.message}<br>This usually means there's a typo in your chart specification. See the javascript console for the full traceback.`));\n",
       "    }\n",
       "\n",
       "    if(typeof define === \"function\" && define.amd) {\n",
       "      requirejs.config({paths});\n",
       "      require([\"vega-embed\"], displayChart, err => showError(`Error loading script: ${err.message}`));\n",
       "    } else {\n",
       "      maybeLoadScript(\"vega\", \"5\")\n",
       "        .then(() => maybeLoadScript(\"vega-lite\", \"5.20.1\"))\n",
       "        .then(() => maybeLoadScript(\"vega-embed\", \"6\"))\n",
       "        .catch(showError)\n",
       "        .then(() => displayChart(vegaEmbed));\n",
       "    }\n",
       "  })({\"config\": {\"view\": {\"continuousWidth\": 300, \"continuousHeight\": 300}}, \"layer\": [{\"mark\": {\"type\": \"line\"}, \"encoding\": {\"color\": {\"field\": \"state\", \"scale\": {\"scheme\": \"set2\"}, \"type\": \"nominal\"}, \"x\": {\"field\": \"session_start_year\", \"type\": \"nominal\"}, \"y\": {\"field\": \"num_bills\", \"type\": \"quantitative\"}}}, {\"mark\": {\"type\": \"point\"}, \"encoding\": {\"color\": {\"field\": \"state\", \"scale\": {\"scheme\": \"set2\"}, \"type\": \"nominal\"}, \"shape\": {\"field\": \"state\", \"type\": \"nominal\"}, \"x\": {\"field\": \"session_start_year\", \"title\": \"Session Year\", \"type\": \"nominal\"}, \"y\": {\"field\": \"num_bills\", \"title\": \"Bills Introduced\", \"type\": \"quantitative\"}}, \"title\": \"Midwest Bills by Session\"}], \"data\": {\"name\": \"data-7819b1facf2e5fc9998dcf4cad0b99f8\"}, \"$schema\": \"https://vega.github.io/schema/vega-lite/v5.20.1.json\", \"datasets\": {\"data-7819b1facf2e5fc9998dcf4cad0b99f8\": [{\"state\": \"IL\", \"session_start_year\": 2017, \"num_bills\": 13616}, {\"state\": \"IL\", \"session_start_year\": 2019, \"num_bills\": 12760}, {\"state\": \"IL\", \"session_start_year\": 2021, \"num_bills\": 12847}, {\"state\": \"IL\", \"session_start_year\": 2023, \"num_bills\": 11951}, {\"state\": \"MI\", \"session_start_year\": 2017, \"num_bills\": 4818}, {\"state\": \"MI\", \"session_start_year\": 2019, \"num_bills\": 4450}, {\"state\": \"MI\", \"session_start_year\": 2021, \"num_bills\": 4520}, {\"state\": \"MI\", \"session_start_year\": 2023, \"num_bills\": 3424}, {\"state\": \"WI\", \"session_start_year\": 2017, \"num_bills\": 1820}, {\"state\": \"WI\", \"session_start_year\": 2019, \"num_bills\": 2264}, {\"state\": \"WI\", \"session_start_year\": 2021, \"num_bills\": 2618}, {\"state\": \"WI\", \"session_start_year\": 2023, \"num_bills\": 2656}]}}, {\"mode\": \"vega-lite\"});\n",
       "</script>"
      ],
      "text/plain": [
       "alt.LayerChart(...)"
      ]
     },
     "execution_count": 54,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "\n",
    "# one possible solution to the exercise\n",
    "\n",
    "color_scheme = alt.Scale(scheme=\"set2\")\n",
    "chart.mark_line().encode(\n",
    "    alt.Y(\"num_bills\"),\n",
    "    alt.X(\"session_start_year:N\"),\n",
    "    alt.Color(\"state\", scale=color_scheme),\n",
    ") + chart.mark_point().encode(\n",
    "    alt.Y(\"num_bills\").title(\"Bills Introduced\"),\n",
    "    alt.X(\"session_start_year:N\").title(\"Session Year\"),\n",
    "    alt.Color(\"state\", scale=color_scheme),\n",
    "    alt.Shape(\"state\"),\n",
    ").properties(\n",
    "    title='Midwest Bills by Session',\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b4a63b04-c8b0-4406-933e-973708c151f6",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e6ca4883-fea8-49ac-ad7c-23168c69a118",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.15"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
