{ "cells": [ { "cell_type": "code", "execution_count": null, "id": "79e92e8d-2d31-4072-a3aa-a94361277eeb", "metadata": {}, "outputs": [], "source": [ "!pip install --quiet pandas plotly requests ipywidgets" ] }, { "cell_type": "code", "execution_count": null, "id": "3df16db7-6739-454f-8970-197af3aba1a1", "metadata": {}, "outputs": [], "source": [ "import requests\n", "import pandas as pd\n", "\n", "# --- Students: Change this to your API key ---\n", "### API_KEY = \"YOUR_FREE_CENTSUS_API_KEY\"\n", "API_KEY = \"---YOUR API KEY---\"\n", "STATE_FIPS = \"37\" # North Carolina (can change to any state)\n", "\n", "# --- THE FIX (Part 1) ---\n", "# Using the correct \"Data Profile\" (DP) variable codes\n", "variables = \"NAME,DP03_0062E,DP05_0001E,DP04_0089E\"\n", "\n", "# Build the API call URL (this endpoint is still correct)\n", "url = f\"https://api.census.gov/data/2022/acs/acs5/profile?get={variables}&for=county:*&in=state:{STATE_FIPS}&key={API_KEY}\"\n", "\n", "print(\"Calling Census API...\")\n", "response = requests.get(url)\n", "\n", "if response.status_code == 200:\n", " print(\"Success! Data received.\")\n", " data = response.json()\n", " \n", " # 1. Convert messy JSON list-of-lists to a DataFrame\n", " df = pd.DataFrame(data[1:], columns=data[0])\n", " \n", " # --- THE FIX (Part 2) ---\n", " # 2. Rename columns to be human-readable\n", " df = df.rename(columns={\n", " \"DP03_0062E\": \"Income\",\n", " \"DP05_0001E\": \"Population\",\n", " \"DP04_0089E\": \"Home_Value\",\n", " \"NAME\": \"County\"\n", " })\n", " \n", " # 3. Clean the data (convert from string to number)\n", " cols_to_numeric = ['Income', 'Population', 'Home_Value']\n", " df[cols_to_numeric] = df[cols_to_numeric].apply(pd.to_numeric, errors='coerce')\n", " \n", " # 4. Create our \"Business Impact\" metric\n", " df['Value_to_Income_Ratio'] = df['Home_Value'] / df['Income']\n", " \n", " # 5. Save for our dashboard\n", " df.to_csv(\"nc_county_data.csv\", index=False)\n", " \n", " print(\"Data cleaned, processed, and saved to 'nc_county_data.csv'\")\n", " print(df.head())\n", " \n", "else:\n", " print(f\"Error: API call failed with status code {response.status_code}\")\n", " # Print the error message from the server\n", " print(response.text)" ] }, { "cell_type": "code", "execution_count": null, "id": "81d90d3b-5409-4433-ba2d-15dec857d5d2", "metadata": {}, "outputs": [], "source": [ "import pandas as pd\n", "import plotly.graph_objects as go\n", "import ipywidgets as widgets\n", "from ipywidgets import HBox, VBox\n", "from IPython.display import display\n", "\n", "# --- 1. Load the Data ---\n", "df = pd.read_csv(\"nc_county_data.csv\")\n", "df['County'] = df['County'].str.replace(\", North Carolina\", \"\")\n", "\n", "# --- 2. Create the Interactive Sliders ---\n", "income_slider = widgets.IntSlider(\n", " value=50000,\n", " min=df['Income'].min(),\n", " max=df['Income'].max(),\n", " step=1000,\n", " description='Min Income ($):',\n", " style={'description_width': 'initial'}\n", ")\n", "\n", "pop_slider = widgets.IntSlider(\n", " value=75000,\n", " min=df['Population'].min(),\n", " max=df['Population'].max(),\n", " step=5000,\n", " description='Min Population:',\n", " style={'description_width': 'initial'}\n", ")\n", "\n", "# --- 3. Create the Chart \"Containers\" ---\n", "# We use FigureWidget to make them \"updatable\"\n", "fig_bubble = go.FigureWidget(layout=go.Layout(\n", " title=\"Market Analysis (Income vs. Home Value vs. Population)\",\n", " xaxis_title=\"Median Income\",\n", " yaxis_title=\"Median Home Value\"\n", "))\n", "fig_bubble.add_scatter(x=df['Income'], y=df['Home_Value'], mode='markers')\n", "\n", "fig_bar = go.FigureWidget(layout=go.Layout(\n", " title=\"Home Value-to-Income Ratio (Lower may be 'cheaper')\"\n", "))\n", "fig_bar.add_bar(x=df['County'], y=df['Value_to_Income_Ratio'])\n", "\n", "# --- 4. The \"Brain\" (The Update Function) ---\n", "# This function will run EVERY time a slider value changes\n", "def update_charts(change):\n", " # Filter the dataframe based on the NEW slider values\n", " min_income = income_slider.value\n", " min_pop = pop_slider.value\n", " \n", " df_filtered = df[\n", " (df['Income'] >= min_income) &\n", " (df['Population'] >= min_pop)\n", " ]\n", " \n", " # Sort for the bar chart\n", " df_bar_sorted = df_filtered.sort_values(\"Value_to_Income_Ratio\")\n", " \n", " # --- Update the charts IN-PLACE (this is fast) ---\n", " # We don't re-create the charts, we just update their data\n", " with fig_bubble.batch_update():\n", " fig_bubble.data[0].x = df_filtered['Income']\n", " fig_bubble.data[0].y = df_filtered['Home_Value']\n", " # We need to add the other properties for the bubble chart\n", " fig_bubble.data[0].marker.size = df_filtered['Population'] / 10000 # Scale size\n", " fig_bubble.data[0].text = df_filtered['County'] # Set hover text\n", " fig_bubble.data[0].marker.color = df_filtered['Income'] # Color by income\n", " \n", " with fig_bar.batch_update():\n", " fig_bar.data[0].x = df_bar_sorted['County']\n", " fig_bar.data[0].y = df_bar_sorted['Value_to_Income_Ratio']\n", "\n", "# --- 5. Link the Sliders to the Function ---\n", "# This says: \"When the 'value' of a slider changes, call the 'update_charts' function\"\n", "income_slider.observe(update_charts, names='value')\n", "pop_slider.observe(update_charts, names='value')\n", "\n", "# --- 6. Display the Dashboard ---\n", "# VBox = Vertical Box (stacks things)\n", "# HBox = Horizontal Box (puts things side-by-side)\n", "controls = VBox([income_slider, pop_slider])\n", "charts = HBox([fig_bubble, fig_bar])\n", "display(VBox([controls, charts]))\n", "\n", "# --- 7. Run the initial update to sync charts ---\n", "update_charts(None) # Call it once to load the default data" ] }, { "cell_type": "code", "execution_count": null, "id": "5e1a5502-3e6f-4295-8596-8d9a23fbdf18", "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.6" } }, "nbformat": 4, "nbformat_minor": 5 }