{ "cells": [ { "cell_type": "markdown", "id": "4b69cd7a-5802-4bd2-b2d3-217226f3489b", "metadata": {}, "source": [ "# Pulling and Cleaning Philadelphia Sales Data" ] }, { "cell_type": "code", "execution_count": 1, "id": "c2c28910-c08b-4fd0-bc5a-dda9c045abba", "metadata": { "tags": [] }, "outputs": [], "source": [ "import requests\n", "import pandas as pd\n", "import geopandas as gpd\n", "\n", "# Define the CARTO API endpoint URL\n", "carto_api_url = \"https://phl.carto.com/api/v2/sql\"\n", "\n", "# Define SQL query to fetch properties with last sale during 2022\n", "sql_query = \"\"\"\n", "SELECT * \n", "FROM opa_properties_public\n", "WHERE sale_date >= '2023-01-01' AND sale_date < '2024-12-31' AND cast(category_code as int) = 1 AND sale_price > 1000\n", "\"\"\"\n", "\n", "# Define the parameters for the API request\n", "params = {\n", " 'q': sql_query, # The SQL query parameter\n", " 'format': 'GeoJSON' # Return the data in GeoJSON format (or any other preferred format)\n", "}\n", "\n", "# Send the GET request to the CARTO API\n", "response = requests.get(carto_api_url, params=params)\n", "\n", "# Check if the request was successful\n", "if response.status_code == 200:\n", " # If successful, load the JSON data\n", " sales = gpd.GeoDataFrame.from_features(response.json(), crs=\"EPSG:4326\")" ] }, { "cell_type": "code", "execution_count": 2, "id": "2726a15e-f6fc-4b0f-bd1c-26cd699400ba", "metadata": { "tags": [] }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
geometrycartodb_idassessment_datebasementsbeginning_pointbook_and_pagebuilding_codebuilding_code_descriptioncategory_codecategory_code_description...utilityview_typeyear_builtyear_built_estimatezip_codezoningpinbuilding_code_newbuilding_code_description_newobjectid
0POINT (-74.98443 40.04761)9412024-06-06T16:14:28ZNoneS E STATE RD54355102536RES CONDO 2 STY FRAME1SINGLE FAMILY...NoneB1972Y19114RM2100115749740CONDO NON CONFORMING562459610
1POINT (-75.24867 39.90375)9442024-06-06T16:07:28ZF175.630' FR NES 80TH54355114R30ROW B/GAR 2 STY MASONRY1SINGLE FAMILY...NoneI1965None19153RM1100111496823ROW POST WAR562459613
2POINT (-75.17125 39.96941)9452024-06-06T16:11:14ZNone17.51' N BROWN ST54355230551RES CONDO 3 STY MAS+OTH1SINGLE FAMILY...NoneNone1920Y19130RM1100115836625ROW MODERN562459614
3POINT (-75.02445 40.03807)9462024-06-06T16:14:03ZNoneNone54355121551RES CONDO 3 STY MAS+OTH1SINGLE FAMILY...NoneI1960None19136RM2100118220640CONDO NON CONFORMING562459615
4POINT (-75.02445 40.03807)9472024-06-06T16:13:27ZNoneSUB OF 1 2 354355121551RES CONDO 3 STY MAS+OTH1SINGLE FAMILY...NoneI1960None19136RM2100118220540CONDO NON CONFORMING562459616
..................................................................
23201POINT (-75.15812 39.94422)34332023-05-21T02:12:25ZD28' S WAVERLY ST54347210O30ROW 2 STY MASONRY1SINGLE FAMILY...NoneI1857Y19147RM1100161093521ROW OLD STYLE562460660
23202POINT (-74.97006 40.08167)34342024-06-06T16:13:25ZH475'11\" SW WHITING RD54347168R31ROW B/GAR 2 STY MAS+OTHER1SINGLE FAMILY...NoneI1973Y19154RSA4100131720523ROW POST WAR562460661
23203POINT (-75.12476 40.04060)34362024-06-06T16:11:43ZA132 FT W 2ND ST54345347R30ROW B/GAR 2 STY MASONRY1SINGLE FAMILY...NoneI1925Y19120RSA5100138695224ROW PORCH FRONT562460875
23204POINT (-75.15085 39.94606)34372024-06-06T16:12:23ZNoneSEC LOCUST WALK54345293590RES CONDO 5+ STY MASONRY1SINGLE FAMILY...NoneI1980Y19106RMX3100159990808None562460876
23205POINT (-75.02291 40.12832)34382024-06-06T16:07:39ZENE COR BYBERRY + BLAKELEE54345314K11S/D W/B GAR 1 STY MAS+OTH1SINGLE FAMILY...NoneI1988None19116RSA3100111347128TWIN RANCH562460877
\n", "

23206 rows × 80 columns

\n", "
" ], "text/plain": [ " geometry cartodb_id assessment_date basements \\\n", "0 POINT (-74.98443 40.04761) 941 2024-06-06T16:14:28Z None \n", "1 POINT (-75.24867 39.90375) 944 2024-06-06T16:07:28Z F \n", "2 POINT (-75.17125 39.96941) 945 2024-06-06T16:11:14Z None \n", "3 POINT (-75.02445 40.03807) 946 2024-06-06T16:14:03Z None \n", "4 POINT (-75.02445 40.03807) 947 2024-06-06T16:13:27Z None \n", "... ... ... ... ... \n", "23201 POINT (-75.15812 39.94422) 3433 2023-05-21T02:12:25Z D \n", "23202 POINT (-74.97006 40.08167) 3434 2024-06-06T16:13:25Z H \n", "23203 POINT (-75.12476 40.04060) 3436 2024-06-06T16:11:43Z A \n", "23204 POINT (-75.15085 39.94606) 3437 2024-06-06T16:12:23Z None \n", "23205 POINT (-75.02291 40.12832) 3438 2024-06-06T16:07:39Z E \n", "\n", " beginning_point book_and_page building_code \\\n", "0 S E STATE RD 54355102 536 \n", "1 175.630' FR NES 80TH 54355114 R30 \n", "2 17.51' N BROWN ST 54355230 551 \n", "3 None 54355121 551 \n", "4 SUB OF 1 2 3 54355121 551 \n", "... ... ... ... \n", "23201 28' S WAVERLY ST 54347210 O30 \n", "23202 475'11\" SW WHITING RD 54347168 R31 \n", "23203 132 FT W 2ND ST 54345347 R30 \n", "23204 SEC LOCUST WALK 54345293 590 \n", "23205 NE COR BYBERRY + BLAKELEE 54345314 K11 \n", "\n", " building_code_description category_code category_code_description ... \\\n", "0 RES CONDO 2 STY FRAME 1 SINGLE FAMILY ... \n", "1 ROW B/GAR 2 STY MASONRY 1 SINGLE FAMILY ... \n", "2 RES CONDO 3 STY MAS+OTH 1 SINGLE FAMILY ... \n", "3 RES CONDO 3 STY MAS+OTH 1 SINGLE FAMILY ... \n", "4 RES CONDO 3 STY MAS+OTH 1 SINGLE FAMILY ... \n", "... ... ... ... ... \n", "23201 ROW 2 STY MASONRY 1 SINGLE FAMILY ... \n", "23202 ROW B/GAR 2 STY MAS+OTHER 1 SINGLE FAMILY ... \n", "23203 ROW B/GAR 2 STY MASONRY 1 SINGLE FAMILY ... \n", "23204 RES CONDO 5+ STY MASONRY 1 SINGLE FAMILY ... \n", "23205 S/D W/B GAR 1 STY MAS+OTH 1 SINGLE FAMILY ... \n", "\n", " utility view_type year_built year_built_estimate zip_code zoning \\\n", "0 None B 1972 Y 19114 RM2 \n", "1 None I 1965 None 19153 RM1 \n", "2 None None 1920 Y 19130 RM1 \n", "3 None I 1960 None 19136 RM2 \n", "4 None I 1960 None 19136 RM2 \n", "... ... ... ... ... ... ... \n", "23201 None I 1857 Y 19147 RM1 \n", "23202 None I 1973 Y 19154 RSA4 \n", "23203 None I 1925 Y 19120 RSA5 \n", "23204 None I 1980 Y 19106 RMX3 \n", "23205 None I 1988 None 19116 RSA3 \n", "\n", " pin building_code_new building_code_description_new objectid \n", "0 1001157497 40 CONDO NON CONFORMING 562459610 \n", "1 1001114968 23 ROW POST WAR 562459613 \n", "2 1001158366 25 ROW MODERN 562459614 \n", "3 1001182206 40 CONDO NON CONFORMING 562459615 \n", "4 1001182205 40 CONDO NON CONFORMING 562459616 \n", "... ... ... ... ... \n", "23201 1001610935 21 ROW OLD STYLE 562460660 \n", "23202 1001317205 23 ROW POST WAR 562460661 \n", "23203 1001386952 24 ROW PORCH FRONT 562460875 \n", "23204 1001599908 08 None 562460876 \n", "23205 1001113471 28 TWIN RANCH 562460877 \n", "\n", "[23206 rows x 80 columns]" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sales" ] }, { "cell_type": "code", "execution_count": 3, "id": "474714ba-9ffd-440e-90b7-1e3904ddd43a", "metadata": { "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " geometry cartodb_id assessment_date basements \\\n", "0 POINT (-74.98443 40.04761) 941 2024-06-06T16:14:28Z None \n", "1 POINT (-75.24867 39.90375) 944 2024-06-06T16:07:28Z F \n", "2 POINT (-75.17125 39.96941) 945 2024-06-06T16:11:14Z None \n", "3 POINT (-75.02445 40.03807) 946 2024-06-06T16:14:03Z None \n", "4 POINT (-75.02445 40.03807) 947 2024-06-06T16:13:27Z None \n", "... ... ... ... ... \n", "23201 POINT (-75.15812 39.94422) 3433 2023-05-21T02:12:25Z D \n", "23202 POINT (-74.97006 40.08167) 3434 2024-06-06T16:13:25Z H \n", "23203 POINT (-75.12476 40.04060) 3436 2024-06-06T16:11:43Z A \n", "23204 POINT (-75.15085 39.94606) 3437 2024-06-06T16:12:23Z None \n", "23205 POINT (-75.02291 40.12832) 3438 2024-06-06T16:07:39Z E \n", "\n", " beginning_point book_and_page building_code \\\n", "0 S E STATE RD 54355102 536 \n", "1 175.630' FR NES 80TH 54355114 R30 \n", "2 17.51' N BROWN ST 54355230 551 \n", "3 None 54355121 551 \n", "4 SUB OF 1 2 3 54355121 551 \n", "... ... ... ... \n", "23201 28' S WAVERLY ST 54347210 O30 \n", "23202 475'11\" SW WHITING RD 54347168 R31 \n", "23203 132 FT W 2ND ST 54345347 R30 \n", "23204 SEC LOCUST WALK 54345293 590 \n", "23205 NE COR BYBERRY + BLAKELEE 54345314 K11 \n", "\n", " building_code_description category_code category_code_description ... \\\n", "0 RES CONDO 2 STY FRAME 1 SINGLE FAMILY ... \n", "1 ROW B/GAR 2 STY MASONRY 1 SINGLE FAMILY ... \n", "2 RES CONDO 3 STY MAS+OTH 1 SINGLE FAMILY ... \n", "3 RES CONDO 3 STY MAS+OTH 1 SINGLE FAMILY ... \n", "4 RES CONDO 3 STY MAS+OTH 1 SINGLE FAMILY ... \n", "... ... ... ... ... \n", "23201 ROW 2 STY MASONRY 1 SINGLE FAMILY ... \n", "23202 ROW B/GAR 2 STY MAS+OTHER 1 SINGLE FAMILY ... \n", "23203 ROW B/GAR 2 STY MASONRY 1 SINGLE FAMILY ... \n", "23204 RES CONDO 5+ STY MASONRY 1 SINGLE FAMILY ... \n", "23205 S/D W/B GAR 1 STY MAS+OTH 1 SINGLE FAMILY ... \n", "\n", " year_built_estimate zip_code zoning pin building_code_new \\\n", "0 Y 19114 RM2 1001157497 40 \n", "1 None 19153 RM1 1001114968 23 \n", "2 Y 19130 RM1 1001158366 25 \n", "3 None 19136 RM2 1001182206 40 \n", "4 None 19136 RM2 1001182205 40 \n", "... ... ... ... ... ... \n", "23201 Y 19147 RM1 1001610935 21 \n", "23202 Y 19154 RSA4 1001317205 23 \n", "23203 Y 19120 RSA5 1001386952 24 \n", "23204 Y 19106 RMX3 1001599908 08 \n", "23205 None 19116 RSA3 1001113471 28 \n", "\n", " building_code_description_new objectid year month year_month \n", "0 CONDO NON CONFORMING 562459610 2024 10 2024-10 \n", "1 ROW POST WAR 562459613 2024 10 2024-10 \n", "2 ROW MODERN 562459614 2024 10 2024-10 \n", "3 CONDO NON CONFORMING 562459615 2024 10 2024-10 \n", "4 CONDO NON CONFORMING 562459616 2024 10 2024-10 \n", "... ... ... ... ... ... \n", "23201 ROW OLD STYLE 562460660 2024 9 2024-09 \n", "23202 ROW POST WAR 562460661 2024 9 2024-09 \n", "23203 ROW PORCH FRONT 562460875 2024 8 2024-08 \n", "23204 None 562460876 2024 8 2024-08 \n", "23205 TWIN RANCH 562460877 2024 9 2024-09 \n", "\n", "[22982 rows x 83 columns]\n" ] } ], "source": [ "import pandas as pd\n", "\n", "# Convert sale_date to datetime\n", "sales['sale_date'] = pd.to_datetime(sales['sale_date'])\n", "\n", "# Extract year and month separately into new columns\n", "sales['year'] = sales['sale_date'].dt.year\n", "sales['month'] = sales['sale_date'].dt.month\n", "\n", "# Create a new column combining month and year\n", "sales['year_month'] = sales['sale_date'].dt.strftime('%Y-%m')\n", "\n", "# Filter out sales in November 2024\n", "sales_filtered = sales.loc[~((sales['year'] == 2024) & (sales['month'] == 11))]\n", "\n", "# Filter rows where number_of_bedrooms is less than 6\n", "sales_filtered = sales_filtered[sales_filtered['number_of_bedrooms'] < 6]\n", "\n", "# Display the filtered dataframe\n", "print(sales_filtered)" ] }, { "cell_type": "markdown", "id": "8f93bd37-2ffd-48a7-adee-a51a8f45f01d", "metadata": {}, "source": [ "# Average Home Sale Price for Philadelphia 2023 - 2024" ] }, { "cell_type": "code", "execution_count": 4, "id": "b1235980-3fa2-4810-8053-97e20b20623f", "metadata": { "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " year_month sale_price_avg sales_count\n", "0 2023-01 279954 927\n", "1 2023-02 272271 924\n", "2 2023-03 286418 1211\n", "3 2023-04 304288 1151\n", "4 2023-05 308751 1282\n", "5 2023-06 318395 1314\n", "6 2023-07 305109 1113\n", "7 2023-08 298002 1156\n", "8 2023-09 291677 1020\n", "9 2023-10 273622 1025\n", "10 2023-11 586262 1053\n", "11 2023-12 269771 901\n", "12 2024-01 353808 819\n", "13 2024-02 308012 854\n", "14 2024-03 283893 1032\n", "15 2024-04 399986 1230\n", "16 2024-05 387278 1357\n", "17 2024-06 303560 1148\n", "18 2024-07 308003 1263\n", "19 2024-08 290855 1080\n", "20 2024-09 281130 827\n", "21 2024-10 278158 295\n" ] } ], "source": [ "# Group by year and month, then calculate average sale price and count the number of sales\n", "monthly_sales_summary = sales_filtered.groupby(['year_month']).agg(\n", " sale_price_avg=('sale_price', 'mean'), # Replace 'sale_price' with your actual sale price column name\n", " sales_count=('sale_date', 'size') # Counting the number of sales by counting sale_date entries\n", ").reset_index()\n", "\n", "# Convert sale_price_avg to int (after rounding)\n", "monthly_sales_summary['sale_price_avg'] = monthly_sales_summary['sale_price_avg'].round(0).astype(int)\n", "\n", "# Print the final result\n", "print(monthly_sales_summary)" ] }, { "cell_type": "code", "execution_count": 5, "id": "5bc09676-65a5-4b7b-8f0b-5125131a2ac8", "metadata": { "tags": [] }, "outputs": [ { "data": { "text/html": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/javascript": [ "(function(root) {\n", " function now() {\n", " return new Date();\n", " }\n", "\n", " const force = true;\n", " const py_version = '3.5.2'.replace('rc', '-rc.').replace('.dev', '-dev.');\n", " const reloading = false;\n", " const Bokeh = root.Bokeh;\n", "\n", " // Set a timeout for this load but only if we are not already initializing\n", " if (typeof (root._bokeh_timeout) === \"undefined\" || (force || !root._bokeh_is_initializing)) {\n", " root._bokeh_timeout = Date.now() + 5000;\n", " root._bokeh_failed_load = false;\n", " }\n", "\n", " function run_callbacks() {\n", " try {\n", " root._bokeh_onload_callbacks.forEach(function(callback) {\n", " if (callback != null)\n", " callback();\n", " });\n", " } finally {\n", " delete root._bokeh_onload_callbacks;\n", " }\n", " console.debug(\"Bokeh: all callbacks have finished\");\n", " }\n", "\n", " function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n", " if (css_urls == null) css_urls = [];\n", " if (js_urls == null) js_urls = [];\n", " if (js_modules == null) js_modules = [];\n", " if (js_exports == null) js_exports = {};\n", "\n", " root._bokeh_onload_callbacks.push(callback);\n", "\n", " if (root._bokeh_is_loading > 0) {\n", " // Don't load bokeh if it is still initializing\n", " console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n", " return null;\n", " } else if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n", " // There is nothing to load\n", " run_callbacks();\n", " return null;\n", " }\n", "\n", " function on_load() {\n", " root._bokeh_is_loading--;\n", " if (root._bokeh_is_loading === 0) {\n", " console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n", " run_callbacks()\n", " }\n", " }\n", " window._bokeh_on_load = on_load\n", "\n", " function on_error(e) {\n", " const src_el = e.srcElement\n", " console.error(\"failed to load \" + (src_el.href || src_el.src));\n", " }\n", "\n", " const skip = [];\n", " if (window.requirejs) {\n", " window.requirejs.config({'packages': {}, 'paths': {}, 'shim': {}});\n", " root._bokeh_is_loading = css_urls.length + 0;\n", " } else {\n", " root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n", " }\n", "\n", " const existing_stylesheets = []\n", " const links = document.getElementsByTagName('link')\n", " for (let i = 0; i < links.length; i++) {\n", " const link = links[i]\n", " if (link.href != null) {\n", " existing_stylesheets.push(link.href)\n", " }\n", " }\n", " for (let i = 0; i < css_urls.length; i++) {\n", " const url = css_urls[i];\n", " const escaped = encodeURI(url)\n", " if (existing_stylesheets.indexOf(escaped) !== -1) {\n", " on_load()\n", " continue;\n", " }\n", " const element = document.createElement(\"link\");\n", " element.onload = on_load;\n", " element.onerror = on_error;\n", " element.rel = \"stylesheet\";\n", " element.type = \"text/css\";\n", " element.href = url;\n", " console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n", " document.body.appendChild(element);\n", " } var existing_scripts = []\n", " const scripts = document.getElementsByTagName('script')\n", " for (let i = 0; i < scripts.length; i++) {\n", " var script = scripts[i]\n", " if (script.src != null) {\n", " existing_scripts.push(script.src)\n", " }\n", " }\n", " for (let i = 0; i < js_urls.length; i++) {\n", " const url = js_urls[i];\n", " const escaped = encodeURI(url)\n", " if (skip.indexOf(escaped) !== -1 || existing_scripts.indexOf(escaped) !== -1) {\n", " if (!window.requirejs) {\n", " on_load();\n", " }\n", " continue;\n", " }\n", " const element = document.createElement('script');\n", " element.onload = on_load;\n", " element.onerror = on_error;\n", " element.async = false;\n", " element.src = url;\n", " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", " document.head.appendChild(element);\n", " }\n", " for (let i = 0; i < js_modules.length; i++) {\n", " const url = js_modules[i];\n", " const escaped = encodeURI(url)\n", " if (skip.indexOf(escaped) !== -1 || existing_scripts.indexOf(escaped) !== -1) {\n", " if (!window.requirejs) {\n", " on_load();\n", " }\n", " continue;\n", " }\n", " var element = document.createElement('script');\n", " element.onload = on_load;\n", " element.onerror = on_error;\n", " element.async = false;\n", " element.src = url;\n", " element.type = \"module\";\n", " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", " document.head.appendChild(element);\n", " }\n", " for (const name in js_exports) {\n", " const url = js_exports[name];\n", " const escaped = encodeURI(url)\n", " if (skip.indexOf(escaped) >= 0 || root[name] != null) {\n", " if (!window.requirejs) {\n", " on_load();\n", " }\n", " continue;\n", " }\n", " var element = document.createElement('script');\n", " element.onerror = on_error;\n", " element.async = false;\n", " element.type = \"module\";\n", " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", " element.textContent = `\n", " import ${name} from \"${url}\"\n", " window.${name} = ${name}\n", " window._bokeh_on_load()\n", " `\n", " document.head.appendChild(element);\n", " }\n", " if (!js_urls.length && !js_modules.length) {\n", " on_load()\n", " }\n", " };\n", "\n", " function inject_raw_css(css) {\n", " const element = document.createElement(\"style\");\n", " element.appendChild(document.createTextNode(css));\n", " document.body.appendChild(element);\n", " }\n", "\n", " const js_urls = [\"https://cdn.holoviz.org/panel/1.5.4/dist/bundled/reactiveesm/es-module-shims@^1.10.0/dist/es-module-shims.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-3.5.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.5.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.5.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.5.2.min.js\", \"https://cdn.holoviz.org/panel/1.5.4/dist/panel.min.js\"];\n", " const js_modules = [];\n", " const js_exports = {};\n", " const css_urls = [];\n", " const inline_js = [ function(Bokeh) {\n", " Bokeh.set_log_level(\"info\");\n", " },\n", "function(Bokeh) {} // ensure no trailing comma for IE\n", " ];\n", "\n", " function run_inline_js() {\n", " if ((root.Bokeh !== undefined) || (force === true)) {\n", " for (let i = 0; i < inline_js.length; i++) {\n", " try {\n", " inline_js[i].call(root, root.Bokeh);\n", " } catch(e) {\n", " if (!reloading) {\n", " throw e;\n", " }\n", " }\n", " }\n", " // Cache old bokeh versions\n", " if (Bokeh != undefined && !reloading) {\n", " var NewBokeh = root.Bokeh;\n", " if (Bokeh.versions === undefined) {\n", " Bokeh.versions = new Map();\n", " }\n", " if (NewBokeh.version !== Bokeh.version) {\n", " Bokeh.versions.set(NewBokeh.version, NewBokeh)\n", " }\n", " root.Bokeh = Bokeh;\n", " }\n", " } else if (Date.now() < root._bokeh_timeout) {\n", " setTimeout(run_inline_js, 100);\n", " } else if (!root._bokeh_failed_load) {\n", " console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n", " root._bokeh_failed_load = true;\n", " }\n", " root._bokeh_is_initializing = false\n", " }\n", "\n", " function load_or_wait() {\n", " // Implement a backoff loop that tries to ensure we do not load multiple\n", " // versions of Bokeh and its dependencies at the same time.\n", " // In recent versions we use the root._bokeh_is_initializing flag\n", " // to determine whether there is an ongoing attempt to initialize\n", " // bokeh, however for backward compatibility we also try to ensure\n", " // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n", " // before older versions are fully initialized.\n", " if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n", " // If the timeout and bokeh was not successfully loaded we reset\n", " // everything and try loading again\n", " root._bokeh_timeout = Date.now() + 5000;\n", " root._bokeh_is_initializing = false;\n", " root._bokeh_onload_callbacks = undefined;\n", " root._bokeh_is_loading = 0\n", " console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n", " load_or_wait();\n", " } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n", " setTimeout(load_or_wait, 100);\n", " } else {\n", " root._bokeh_is_initializing = true\n", " root._bokeh_onload_callbacks = []\n", " const bokeh_loaded = root.Bokeh != null && (root.Bokeh.version === py_version || (root.Bokeh.versions !== undefined && root.Bokeh.versions.has(py_version)));\n", " if (!reloading && !bokeh_loaded) {\n", " if (root.Bokeh) {\n", " root.Bokeh = undefined;\n", " }\n", " console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n", " }\n", " load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n", " console.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n", " run_inline_js();\n", " });\n", " }\n", " }\n", " // Give older versions of the autoload script a head-start to ensure\n", " // they initialize before we start loading newer version.\n", " setTimeout(load_or_wait, 100)\n", "}(window));" ], "application/vnd.holoviews_load.v0+json": "(function(root) {\n function now() {\n return new Date();\n }\n\n const force = true;\n const py_version = '3.5.2'.replace('rc', '-rc.').replace('.dev', '-dev.');\n const reloading = false;\n const Bokeh = root.Bokeh;\n\n // Set a timeout for this load but only if we are not already initializing\n if (typeof (root._bokeh_timeout) === \"undefined\" || (force || !root._bokeh_is_initializing)) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks;\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n if (js_exports == null) js_exports = {};\n\n root._bokeh_onload_callbacks.push(callback);\n\n if (root._bokeh_is_loading > 0) {\n // Don't load bokeh if it is still initializing\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n } else if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n // There is nothing to load\n run_callbacks();\n return null;\n }\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n window._bokeh_on_load = on_load\n\n function on_error(e) {\n const src_el = e.srcElement\n console.error(\"failed to load \" + (src_el.href || src_el.src));\n }\n\n const skip = [];\n if (window.requirejs) {\n window.requirejs.config({'packages': {}, 'paths': {}, 'shim': {}});\n root._bokeh_is_loading = css_urls.length + 0;\n } else {\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n }\n\n const existing_stylesheets = []\n const links = document.getElementsByTagName('link')\n for (let i = 0; i < links.length; i++) {\n const link = links[i]\n if (link.href != null) {\n existing_stylesheets.push(link.href)\n }\n }\n for (let i = 0; i < css_urls.length; i++) {\n const url = css_urls[i];\n const escaped = encodeURI(url)\n if (existing_stylesheets.indexOf(escaped) !== -1) {\n on_load()\n continue;\n }\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n } var existing_scripts = []\n const scripts = document.getElementsByTagName('script')\n for (let i = 0; i < scripts.length; i++) {\n var script = scripts[i]\n if (script.src != null) {\n existing_scripts.push(script.src)\n }\n }\n for (let i = 0; i < js_urls.length; i++) {\n const url = js_urls[i];\n const escaped = encodeURI(url)\n if (skip.indexOf(escaped) !== -1 || existing_scripts.indexOf(escaped) !== -1) {\n if (!window.requirejs) {\n on_load();\n }\n continue;\n }\n const element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (let i = 0; i < js_modules.length; i++) {\n const url = js_modules[i];\n const escaped = encodeURI(url)\n if (skip.indexOf(escaped) !== -1 || existing_scripts.indexOf(escaped) !== -1) {\n if (!window.requirejs) {\n on_load();\n }\n continue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (const name in js_exports) {\n const url = js_exports[name];\n const escaped = encodeURI(url)\n if (skip.indexOf(escaped) >= 0 || root[name] != null) {\n if (!window.requirejs) {\n on_load();\n }\n continue;\n }\n var element = document.createElement('script');\n element.onerror = on_error;\n element.async = false;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n element.textContent = `\n import ${name} from \"${url}\"\n window.${name} = ${name}\n window._bokeh_on_load()\n `\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n const js_urls = [\"https://cdn.holoviz.org/panel/1.5.4/dist/bundled/reactiveesm/es-module-shims@^1.10.0/dist/es-module-shims.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-3.5.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.5.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.5.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.5.2.min.js\", \"https://cdn.holoviz.org/panel/1.5.4/dist/panel.min.js\"];\n const js_modules = [];\n const js_exports = {};\n const css_urls = [];\n const inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (let i = 0; i < inline_js.length; i++) {\n try {\n inline_js[i].call(root, root.Bokeh);\n } catch(e) {\n if (!reloading) {\n throw e;\n }\n }\n }\n // Cache old bokeh versions\n if (Bokeh != undefined && !reloading) {\n var NewBokeh = root.Bokeh;\n if (Bokeh.versions === undefined) {\n Bokeh.versions = new Map();\n }\n if (NewBokeh.version !== Bokeh.version) {\n Bokeh.versions.set(NewBokeh.version, NewBokeh)\n }\n root.Bokeh = Bokeh;\n }\n } else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n root._bokeh_is_initializing = false\n }\n\n function load_or_wait() {\n // Implement a backoff loop that tries to ensure we do not load multiple\n // versions of Bokeh and its dependencies at the same time.\n // In recent versions we use the root._bokeh_is_initializing flag\n // to determine whether there is an ongoing attempt to initialize\n // bokeh, however for backward compatibility we also try to ensure\n // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n // before older versions are fully initialized.\n if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n // If the timeout and bokeh was not successfully loaded we reset\n // everything and try loading again\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_is_initializing = false;\n root._bokeh_onload_callbacks = undefined;\n root._bokeh_is_loading = 0\n console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n load_or_wait();\n } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n setTimeout(load_or_wait, 100);\n } else {\n root._bokeh_is_initializing = true\n root._bokeh_onload_callbacks = []\n const bokeh_loaded = root.Bokeh != null && (root.Bokeh.version === py_version || (root.Bokeh.versions !== undefined && root.Bokeh.versions.has(py_version)));\n if (!reloading && !bokeh_loaded) {\n if (root.Bokeh) {\n root.Bokeh = undefined;\n }\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n }\n load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n console.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n run_inline_js();\n });\n }\n }\n // Give older versions of the autoload script a head-start to ensure\n // they initialize before we start loading newer version.\n setTimeout(load_or_wait, 100)\n}(window));" }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/javascript": [ "\n", "if ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n", " window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n", "}\n", "\n", "\n", " function JupyterCommManager() {\n", " }\n", "\n", " JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n", " if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n", " var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n", " comm_manager.register_target(comm_id, function(comm) {\n", " comm.on_msg(msg_handler);\n", " });\n", " } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n", " window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n", " comm.onMsg = msg_handler;\n", " });\n", " } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n", " google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n", " var messages = comm.messages[Symbol.asyncIterator]();\n", " function processIteratorResult(result) {\n", " var message = result.value;\n", " console.log(message)\n", " var content = {data: message.data, comm_id};\n", " var buffers = []\n", " for (var buffer of message.buffers || []) {\n", " buffers.push(new DataView(buffer))\n", " }\n", " var metadata = message.metadata || {};\n", " var msg = {content, buffers, metadata}\n", " msg_handler(msg);\n", " return messages.next().then(processIteratorResult);\n", " }\n", " return messages.next().then(processIteratorResult);\n", " })\n", " }\n", " }\n", "\n", " JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n", " if (comm_id in window.PyViz.comms) {\n", " return window.PyViz.comms[comm_id];\n", " } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n", " var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n", " var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n", " if (msg_handler) {\n", " comm.on_msg(msg_handler);\n", " }\n", " } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n", " var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n", " comm.open();\n", " if (msg_handler) {\n", " comm.onMsg = msg_handler;\n", " }\n", " } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n", " var comm_promise = google.colab.kernel.comms.open(comm_id)\n", " comm_promise.then((comm) => {\n", " window.PyViz.comms[comm_id] = comm;\n", " if (msg_handler) {\n", " var messages = comm.messages[Symbol.asyncIterator]();\n", " function processIteratorResult(result) {\n", " var message = result.value;\n", " var content = {data: message.data};\n", " var metadata = message.metadata || {comm_id};\n", " var msg = {content, metadata}\n", " msg_handler(msg);\n", " return messages.next().then(processIteratorResult);\n", " }\n", " return messages.next().then(processIteratorResult);\n", " }\n", " }) \n", " var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n", " return comm_promise.then((comm) => {\n", " comm.send(data, metadata, buffers, disposeOnDone);\n", " });\n", " };\n", " var comm = {\n", " send: sendClosure\n", " };\n", " }\n", " window.PyViz.comms[comm_id] = comm;\n", " return comm;\n", " }\n", " window.PyViz.comm_manager = new JupyterCommManager();\n", " \n", "\n", "\n", "var JS_MIME_TYPE = 'application/javascript';\n", "var HTML_MIME_TYPE = 'text/html';\n", "var EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\n", "var CLASS_NAME = 'output';\n", "\n", "/**\n", " * Render data to the DOM node\n", " */\n", "function render(props, node) {\n", " var div = document.createElement(\"div\");\n", " var script = document.createElement(\"script\");\n", " node.appendChild(div);\n", " node.appendChild(script);\n", "}\n", "\n", "/**\n", " * Handle when a new output is added\n", " */\n", "function handle_add_output(event, handle) {\n", " var output_area = handle.output_area;\n", " var output = handle.output;\n", " if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n", " return\n", " }\n", " var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n", " var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n", " if (id !== undefined) {\n", " var nchildren = toinsert.length;\n", " var html_node = toinsert[nchildren-1].children[0];\n", " html_node.innerHTML = output.data[HTML_MIME_TYPE];\n", " var scripts = [];\n", " var nodelist = html_node.querySelectorAll(\"script\");\n", " for (var i in nodelist) {\n", " if (nodelist.hasOwnProperty(i)) {\n", " scripts.push(nodelist[i])\n", " }\n", " }\n", "\n", " scripts.forEach( function (oldScript) {\n", " var newScript = document.createElement(\"script\");\n", " var attrs = [];\n", " var nodemap = oldScript.attributes;\n", " for (var j in nodemap) {\n", " if (nodemap.hasOwnProperty(j)) {\n", " attrs.push(nodemap[j])\n", " }\n", " }\n", " attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n", " newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n", " oldScript.parentNode.replaceChild(newScript, oldScript);\n", " });\n", " if (JS_MIME_TYPE in output.data) {\n", " toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n", " }\n", " output_area._hv_plot_id = id;\n", " if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n", " window.PyViz.plot_index[id] = Bokeh.index[id];\n", " } else {\n", " window.PyViz.plot_index[id] = null;\n", " }\n", " } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n", " var bk_div = document.createElement(\"div\");\n", " bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n", " var script_attrs = bk_div.children[0].attributes;\n", " for (var i = 0; i < script_attrs.length; i++) {\n", " toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n", " }\n", " // store reference to server id on output_area\n", " output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n", " }\n", "}\n", "\n", "/**\n", " * Handle when an output is cleared or removed\n", " */\n", "function handle_clear_output(event, handle) {\n", " var id = handle.cell.output_area._hv_plot_id;\n", " var server_id = handle.cell.output_area._bokeh_server_id;\n", " if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n", " var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n", " if (server_id !== null) {\n", " comm.send({event_type: 'server_delete', 'id': server_id});\n", " return;\n", " } else if (comm !== null) {\n", " comm.send({event_type: 'delete', 'id': id});\n", " }\n", " delete PyViz.plot_index[id];\n", " if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n", " var doc = window.Bokeh.index[id].model.document\n", " doc.clear();\n", " const i = window.Bokeh.documents.indexOf(doc);\n", " if (i > -1) {\n", " window.Bokeh.documents.splice(i, 1);\n", " }\n", " }\n", "}\n", "\n", "/**\n", " * Handle kernel restart event\n", " */\n", "function handle_kernel_cleanup(event, handle) {\n", " delete PyViz.comms[\"hv-extension-comm\"];\n", " window.PyViz.plot_index = {}\n", "}\n", "\n", "/**\n", " * Handle update_display_data messages\n", " */\n", "function handle_update_output(event, handle) {\n", " handle_clear_output(event, {cell: {output_area: handle.output_area}})\n", " handle_add_output(event, handle)\n", "}\n", "\n", "function register_renderer(events, OutputArea) {\n", " function append_mime(data, metadata, element) {\n", " // create a DOM node to render to\n", " var toinsert = this.create_output_subarea(\n", " metadata,\n", " CLASS_NAME,\n", " EXEC_MIME_TYPE\n", " );\n", " this.keyboard_manager.register_events(toinsert);\n", " // Render to node\n", " var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n", " render(props, toinsert[0]);\n", " element.append(toinsert);\n", " return toinsert\n", " }\n", "\n", " events.on('output_added.OutputArea', handle_add_output);\n", " events.on('output_updated.OutputArea', handle_update_output);\n", " events.on('clear_output.CodeCell', handle_clear_output);\n", " events.on('delete.Cell', handle_clear_output);\n", " events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n", "\n", " OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n", " safe: true,\n", " index: 0\n", " });\n", "}\n", "\n", "if (window.Jupyter !== undefined) {\n", " try {\n", " var events = require('base/js/events');\n", " var OutputArea = require('notebook/js/outputarea').OutputArea;\n", " if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n", " register_renderer(events, OutputArea);\n", " }\n", " } catch(err) {\n", " }\n", "}\n" ], "application/vnd.holoviews_load.v0+json": "\nif ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n}\n\n\n function JupyterCommManager() {\n }\n\n JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n comm_manager.register_target(comm_id, function(comm) {\n comm.on_msg(msg_handler);\n });\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n comm.onMsg = msg_handler;\n });\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n console.log(message)\n var content = {data: message.data, comm_id};\n var buffers = []\n for (var buffer of message.buffers || []) {\n buffers.push(new DataView(buffer))\n }\n var metadata = message.metadata || {};\n var msg = {content, buffers, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n })\n }\n }\n\n JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n if (comm_id in window.PyViz.comms) {\n return window.PyViz.comms[comm_id];\n } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n if (msg_handler) {\n comm.on_msg(msg_handler);\n }\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n comm.open();\n if (msg_handler) {\n comm.onMsg = msg_handler;\n }\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n var comm_promise = google.colab.kernel.comms.open(comm_id)\n comm_promise.then((comm) => {\n window.PyViz.comms[comm_id] = comm;\n if (msg_handler) {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n var content = {data: message.data};\n var metadata = message.metadata || {comm_id};\n var msg = {content, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n }\n }) \n var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n return comm_promise.then((comm) => {\n comm.send(data, metadata, buffers, disposeOnDone);\n });\n };\n var comm = {\n send: sendClosure\n };\n }\n window.PyViz.comms[comm_id] = comm;\n return comm;\n }\n window.PyViz.comm_manager = new JupyterCommManager();\n \n\n\nvar JS_MIME_TYPE = 'application/javascript';\nvar HTML_MIME_TYPE = 'text/html';\nvar EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\nvar CLASS_NAME = 'output';\n\n/**\n * Render data to the DOM node\n */\nfunction render(props, node) {\n var div = document.createElement(\"div\");\n var script = document.createElement(\"script\");\n node.appendChild(div);\n node.appendChild(script);\n}\n\n/**\n * Handle when a new output is added\n */\nfunction handle_add_output(event, handle) {\n var output_area = handle.output_area;\n var output = handle.output;\n if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n return\n }\n var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n if (id !== undefined) {\n var nchildren = toinsert.length;\n var html_node = toinsert[nchildren-1].children[0];\n html_node.innerHTML = output.data[HTML_MIME_TYPE];\n var scripts = [];\n var nodelist = html_node.querySelectorAll(\"script\");\n for (var i in nodelist) {\n if (nodelist.hasOwnProperty(i)) {\n scripts.push(nodelist[i])\n }\n }\n\n scripts.forEach( function (oldScript) {\n var newScript = document.createElement(\"script\");\n var attrs = [];\n var nodemap = oldScript.attributes;\n for (var j in nodemap) {\n if (nodemap.hasOwnProperty(j)) {\n attrs.push(nodemap[j])\n }\n }\n attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n oldScript.parentNode.replaceChild(newScript, oldScript);\n });\n if (JS_MIME_TYPE in output.data) {\n toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n }\n output_area._hv_plot_id = id;\n if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n window.PyViz.plot_index[id] = Bokeh.index[id];\n } else {\n window.PyViz.plot_index[id] = null;\n }\n } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n var bk_div = document.createElement(\"div\");\n bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n var script_attrs = bk_div.children[0].attributes;\n for (var i = 0; i < script_attrs.length; i++) {\n toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n }\n // store reference to server id on output_area\n output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n }\n}\n\n/**\n * Handle when an output is cleared or removed\n */\nfunction handle_clear_output(event, handle) {\n var id = handle.cell.output_area._hv_plot_id;\n var server_id = handle.cell.output_area._bokeh_server_id;\n if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n if (server_id !== null) {\n comm.send({event_type: 'server_delete', 'id': server_id});\n return;\n } else if (comm !== null) {\n comm.send({event_type: 'delete', 'id': id});\n }\n delete PyViz.plot_index[id];\n if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n var doc = window.Bokeh.index[id].model.document\n doc.clear();\n const i = window.Bokeh.documents.indexOf(doc);\n if (i > -1) {\n window.Bokeh.documents.splice(i, 1);\n }\n }\n}\n\n/**\n * Handle kernel restart event\n */\nfunction handle_kernel_cleanup(event, handle) {\n delete PyViz.comms[\"hv-extension-comm\"];\n window.PyViz.plot_index = {}\n}\n\n/**\n * Handle update_display_data messages\n */\nfunction handle_update_output(event, handle) {\n handle_clear_output(event, {cell: {output_area: handle.output_area}})\n handle_add_output(event, handle)\n}\n\nfunction register_renderer(events, OutputArea) {\n function append_mime(data, metadata, element) {\n // create a DOM node to render to\n var toinsert = this.create_output_subarea(\n metadata,\n CLASS_NAME,\n EXEC_MIME_TYPE\n );\n this.keyboard_manager.register_events(toinsert);\n // Render to node\n var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n render(props, toinsert[0]);\n element.append(toinsert);\n return toinsert\n }\n\n events.on('output_added.OutputArea', handle_add_output);\n events.on('output_updated.OutputArea', handle_update_output);\n events.on('clear_output.CodeCell', handle_clear_output);\n events.on('delete.Cell', handle_clear_output);\n events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n\n OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n safe: true,\n index: 0\n });\n}\n\nif (window.Jupyter !== undefined) {\n try {\n var events = require('base/js/events');\n var OutputArea = require('notebook/js/outputarea').OutputArea;\n if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n register_renderer(events, OutputArea);\n }\n } catch(err) {\n }\n}\n" }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "
\n", "
\n", "" ] }, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "71b628f5-9f8f-4f0f-8be8-85768129c9e4" } }, "output_type": "display_data" }, { "data": { "text/html": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/javascript": [ "(function(root) {\n", " function now() {\n", " return new Date();\n", " }\n", "\n", " const force = false;\n", " const py_version = '3.5.2'.replace('rc', '-rc.').replace('.dev', '-dev.');\n", " const reloading = true;\n", " const Bokeh = root.Bokeh;\n", "\n", " // Set a timeout for this load but only if we are not already initializing\n", " if (typeof (root._bokeh_timeout) === \"undefined\" || (force || !root._bokeh_is_initializing)) {\n", " root._bokeh_timeout = Date.now() + 5000;\n", " root._bokeh_failed_load = false;\n", " }\n", "\n", " function run_callbacks() {\n", " try {\n", " root._bokeh_onload_callbacks.forEach(function(callback) {\n", " if (callback != null)\n", " callback();\n", " });\n", " } finally {\n", " delete root._bokeh_onload_callbacks;\n", " }\n", " console.debug(\"Bokeh: all callbacks have finished\");\n", " }\n", "\n", " function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n", " if (css_urls == null) css_urls = [];\n", " if (js_urls == null) js_urls = [];\n", " if (js_modules == null) js_modules = [];\n", " if (js_exports == null) js_exports = {};\n", "\n", " root._bokeh_onload_callbacks.push(callback);\n", "\n", " if (root._bokeh_is_loading > 0) {\n", " // Don't load bokeh if it is still initializing\n", " console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n", " return null;\n", " } else if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n", " // There is nothing to load\n", " run_callbacks();\n", " return null;\n", " }\n", "\n", " function on_load() {\n", " root._bokeh_is_loading--;\n", " if (root._bokeh_is_loading === 0) {\n", " console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n", " run_callbacks()\n", " }\n", " }\n", " window._bokeh_on_load = on_load\n", "\n", " function on_error(e) {\n", " const src_el = e.srcElement\n", " console.error(\"failed to load \" + (src_el.href || src_el.src));\n", " }\n", "\n", " const skip = [];\n", " if (window.requirejs) {\n", " window.requirejs.config({'packages': {}, 'paths': {}, 'shim': {}});\n", " root._bokeh_is_loading = css_urls.length + 0;\n", " } else {\n", " root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n", " }\n", "\n", " const existing_stylesheets = []\n", " const links = document.getElementsByTagName('link')\n", " for (let i = 0; i < links.length; i++) {\n", " const link = links[i]\n", " if (link.href != null) {\n", " existing_stylesheets.push(link.href)\n", " }\n", " }\n", " for (let i = 0; i < css_urls.length; i++) {\n", " const url = css_urls[i];\n", " const escaped = encodeURI(url)\n", " if (existing_stylesheets.indexOf(escaped) !== -1) {\n", " on_load()\n", " continue;\n", " }\n", " const element = document.createElement(\"link\");\n", " element.onload = on_load;\n", " element.onerror = on_error;\n", " element.rel = \"stylesheet\";\n", " element.type = \"text/css\";\n", " element.href = url;\n", " console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n", " document.body.appendChild(element);\n", " } var existing_scripts = []\n", " const scripts = document.getElementsByTagName('script')\n", " for (let i = 0; i < scripts.length; i++) {\n", " var script = scripts[i]\n", " if (script.src != null) {\n", " existing_scripts.push(script.src)\n", " }\n", " }\n", " for (let i = 0; i < js_urls.length; i++) {\n", " const url = js_urls[i];\n", " const escaped = encodeURI(url)\n", " if (skip.indexOf(escaped) !== -1 || existing_scripts.indexOf(escaped) !== -1) {\n", " if (!window.requirejs) {\n", " on_load();\n", " }\n", " continue;\n", " }\n", " const element = document.createElement('script');\n", " element.onload = on_load;\n", " element.onerror = on_error;\n", " element.async = false;\n", " element.src = url;\n", " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", " document.head.appendChild(element);\n", " }\n", " for (let i = 0; i < js_modules.length; i++) {\n", " const url = js_modules[i];\n", " const escaped = encodeURI(url)\n", " if (skip.indexOf(escaped) !== -1 || existing_scripts.indexOf(escaped) !== -1) {\n", " if (!window.requirejs) {\n", " on_load();\n", " }\n", " continue;\n", " }\n", " var element = document.createElement('script');\n", " element.onload = on_load;\n", " element.onerror = on_error;\n", " element.async = false;\n", " element.src = url;\n", " element.type = \"module\";\n", " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", " document.head.appendChild(element);\n", " }\n", " for (const name in js_exports) {\n", " const url = js_exports[name];\n", " const escaped = encodeURI(url)\n", " if (skip.indexOf(escaped) >= 0 || root[name] != null) {\n", " if (!window.requirejs) {\n", " on_load();\n", " }\n", " continue;\n", " }\n", " var element = document.createElement('script');\n", " element.onerror = on_error;\n", " element.async = false;\n", " element.type = \"module\";\n", " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", " element.textContent = `\n", " import ${name} from \"${url}\"\n", " window.${name} = ${name}\n", " window._bokeh_on_load()\n", " `\n", " document.head.appendChild(element);\n", " }\n", " if (!js_urls.length && !js_modules.length) {\n", " on_load()\n", " }\n", " };\n", "\n", " function inject_raw_css(css) {\n", " const element = document.createElement(\"style\");\n", " element.appendChild(document.createTextNode(css));\n", " document.body.appendChild(element);\n", " }\n", "\n", " const js_urls = [\"https://cdn.holoviz.org/panel/1.5.4/dist/bundled/reactiveesm/es-module-shims@^1.10.0/dist/es-module-shims.min.js\"];\n", " const js_modules = [];\n", " const js_exports = {};\n", " const css_urls = [];\n", " const inline_js = [ function(Bokeh) {\n", " Bokeh.set_log_level(\"info\");\n", " },\n", "function(Bokeh) {} // ensure no trailing comma for IE\n", " ];\n", "\n", " function run_inline_js() {\n", " if ((root.Bokeh !== undefined) || (force === true)) {\n", " for (let i = 0; i < inline_js.length; i++) {\n", " try {\n", " inline_js[i].call(root, root.Bokeh);\n", " } catch(e) {\n", " if (!reloading) {\n", " throw e;\n", " }\n", " }\n", " }\n", " // Cache old bokeh versions\n", " if (Bokeh != undefined && !reloading) {\n", " var NewBokeh = root.Bokeh;\n", " if (Bokeh.versions === undefined) {\n", " Bokeh.versions = new Map();\n", " }\n", " if (NewBokeh.version !== Bokeh.version) {\n", " Bokeh.versions.set(NewBokeh.version, NewBokeh)\n", " }\n", " root.Bokeh = Bokeh;\n", " }\n", " } else if (Date.now() < root._bokeh_timeout) {\n", " setTimeout(run_inline_js, 100);\n", " } else if (!root._bokeh_failed_load) {\n", " console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n", " root._bokeh_failed_load = true;\n", " }\n", " root._bokeh_is_initializing = false\n", " }\n", "\n", " function load_or_wait() {\n", " // Implement a backoff loop that tries to ensure we do not load multiple\n", " // versions of Bokeh and its dependencies at the same time.\n", " // In recent versions we use the root._bokeh_is_initializing flag\n", " // to determine whether there is an ongoing attempt to initialize\n", " // bokeh, however for backward compatibility we also try to ensure\n", " // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n", " // before older versions are fully initialized.\n", " if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n", " // If the timeout and bokeh was not successfully loaded we reset\n", " // everything and try loading again\n", " root._bokeh_timeout = Date.now() + 5000;\n", " root._bokeh_is_initializing = false;\n", " root._bokeh_onload_callbacks = undefined;\n", " root._bokeh_is_loading = 0\n", " console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n", " load_or_wait();\n", " } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n", " setTimeout(load_or_wait, 100);\n", " } else {\n", " root._bokeh_is_initializing = true\n", " root._bokeh_onload_callbacks = []\n", " const bokeh_loaded = root.Bokeh != null && (root.Bokeh.version === py_version || (root.Bokeh.versions !== undefined && root.Bokeh.versions.has(py_version)));\n", " if (!reloading && !bokeh_loaded) {\n", " if (root.Bokeh) {\n", " root.Bokeh = undefined;\n", " }\n", " console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n", " }\n", " load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n", " console.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n", " run_inline_js();\n", " });\n", " }\n", " }\n", " // Give older versions of the autoload script a head-start to ensure\n", " // they initialize before we start loading newer version.\n", " setTimeout(load_or_wait, 100)\n", "}(window));" ], "application/vnd.holoviews_load.v0+json": "(function(root) {\n function now() {\n return new Date();\n }\n\n const force = false;\n const py_version = '3.5.2'.replace('rc', '-rc.').replace('.dev', '-dev.');\n const reloading = true;\n const Bokeh = root.Bokeh;\n\n // Set a timeout for this load but only if we are not already initializing\n if (typeof (root._bokeh_timeout) === \"undefined\" || (force || !root._bokeh_is_initializing)) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks;\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n if (js_exports == null) js_exports = {};\n\n root._bokeh_onload_callbacks.push(callback);\n\n if (root._bokeh_is_loading > 0) {\n // Don't load bokeh if it is still initializing\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n } else if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n // There is nothing to load\n run_callbacks();\n return null;\n }\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n window._bokeh_on_load = on_load\n\n function on_error(e) {\n const src_el = e.srcElement\n console.error(\"failed to load \" + (src_el.href || src_el.src));\n }\n\n const skip = [];\n if (window.requirejs) {\n window.requirejs.config({'packages': {}, 'paths': {}, 'shim': {}});\n root._bokeh_is_loading = css_urls.length + 0;\n } else {\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n }\n\n const existing_stylesheets = []\n const links = document.getElementsByTagName('link')\n for (let i = 0; i < links.length; i++) {\n const link = links[i]\n if (link.href != null) {\n existing_stylesheets.push(link.href)\n }\n }\n for (let i = 0; i < css_urls.length; i++) {\n const url = css_urls[i];\n const escaped = encodeURI(url)\n if (existing_stylesheets.indexOf(escaped) !== -1) {\n on_load()\n continue;\n }\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n } var existing_scripts = []\n const scripts = document.getElementsByTagName('script')\n for (let i = 0; i < scripts.length; i++) {\n var script = scripts[i]\n if (script.src != null) {\n existing_scripts.push(script.src)\n }\n }\n for (let i = 0; i < js_urls.length; i++) {\n const url = js_urls[i];\n const escaped = encodeURI(url)\n if (skip.indexOf(escaped) !== -1 || existing_scripts.indexOf(escaped) !== -1) {\n if (!window.requirejs) {\n on_load();\n }\n continue;\n }\n const element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (let i = 0; i < js_modules.length; i++) {\n const url = js_modules[i];\n const escaped = encodeURI(url)\n if (skip.indexOf(escaped) !== -1 || existing_scripts.indexOf(escaped) !== -1) {\n if (!window.requirejs) {\n on_load();\n }\n continue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (const name in js_exports) {\n const url = js_exports[name];\n const escaped = encodeURI(url)\n if (skip.indexOf(escaped) >= 0 || root[name] != null) {\n if (!window.requirejs) {\n on_load();\n }\n continue;\n }\n var element = document.createElement('script');\n element.onerror = on_error;\n element.async = false;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n element.textContent = `\n import ${name} from \"${url}\"\n window.${name} = ${name}\n window._bokeh_on_load()\n `\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n const js_urls = [\"https://cdn.holoviz.org/panel/1.5.4/dist/bundled/reactiveesm/es-module-shims@^1.10.0/dist/es-module-shims.min.js\"];\n const js_modules = [];\n const js_exports = {};\n const css_urls = [];\n const inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (let i = 0; i < inline_js.length; i++) {\n try {\n inline_js[i].call(root, root.Bokeh);\n } catch(e) {\n if (!reloading) {\n throw e;\n }\n }\n }\n // Cache old bokeh versions\n if (Bokeh != undefined && !reloading) {\n var NewBokeh = root.Bokeh;\n if (Bokeh.versions === undefined) {\n Bokeh.versions = new Map();\n }\n if (NewBokeh.version !== Bokeh.version) {\n Bokeh.versions.set(NewBokeh.version, NewBokeh)\n }\n root.Bokeh = Bokeh;\n }\n } else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n root._bokeh_is_initializing = false\n }\n\n function load_or_wait() {\n // Implement a backoff loop that tries to ensure we do not load multiple\n // versions of Bokeh and its dependencies at the same time.\n // In recent versions we use the root._bokeh_is_initializing flag\n // to determine whether there is an ongoing attempt to initialize\n // bokeh, however for backward compatibility we also try to ensure\n // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n // before older versions are fully initialized.\n if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n // If the timeout and bokeh was not successfully loaded we reset\n // everything and try loading again\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_is_initializing = false;\n root._bokeh_onload_callbacks = undefined;\n root._bokeh_is_loading = 0\n console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n load_or_wait();\n } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n setTimeout(load_or_wait, 100);\n } else {\n root._bokeh_is_initializing = true\n root._bokeh_onload_callbacks = []\n const bokeh_loaded = root.Bokeh != null && (root.Bokeh.version === py_version || (root.Bokeh.versions !== undefined && root.Bokeh.versions.has(py_version)));\n if (!reloading && !bokeh_loaded) {\n if (root.Bokeh) {\n root.Bokeh = undefined;\n }\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n }\n load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n console.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n run_inline_js();\n });\n }\n }\n // Give older versions of the autoload script a head-start to ensure\n // they initialize before we start loading newer version.\n setTimeout(load_or_wait, 100)\n}(window));" }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/javascript": [ "\n", "if ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n", " window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n", "}\n", "\n", "\n", " function JupyterCommManager() {\n", " }\n", "\n", " JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n", " if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n", " var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n", " comm_manager.register_target(comm_id, function(comm) {\n", " comm.on_msg(msg_handler);\n", " });\n", " } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n", " window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n", " comm.onMsg = msg_handler;\n", " });\n", " } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n", " google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n", " var messages = comm.messages[Symbol.asyncIterator]();\n", " function processIteratorResult(result) {\n", " var message = result.value;\n", " console.log(message)\n", " var content = {data: message.data, comm_id};\n", " var buffers = []\n", " for (var buffer of message.buffers || []) {\n", " buffers.push(new DataView(buffer))\n", " }\n", " var metadata = message.metadata || {};\n", " var msg = {content, buffers, metadata}\n", " msg_handler(msg);\n", " return messages.next().then(processIteratorResult);\n", " }\n", " return messages.next().then(processIteratorResult);\n", " })\n", " }\n", " }\n", "\n", " JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n", " if (comm_id in window.PyViz.comms) {\n", " return window.PyViz.comms[comm_id];\n", " } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n", " var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n", " var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n", " if (msg_handler) {\n", " comm.on_msg(msg_handler);\n", " }\n", " } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n", " var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n", " comm.open();\n", " if (msg_handler) {\n", " comm.onMsg = msg_handler;\n", " }\n", " } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n", " var comm_promise = google.colab.kernel.comms.open(comm_id)\n", " comm_promise.then((comm) => {\n", " window.PyViz.comms[comm_id] = comm;\n", " if (msg_handler) {\n", " var messages = comm.messages[Symbol.asyncIterator]();\n", " function processIteratorResult(result) {\n", " var message = result.value;\n", " var content = {data: message.data};\n", " var metadata = message.metadata || {comm_id};\n", " var msg = {content, metadata}\n", " msg_handler(msg);\n", " return messages.next().then(processIteratorResult);\n", " }\n", " return messages.next().then(processIteratorResult);\n", " }\n", " }) \n", " var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n", " return comm_promise.then((comm) => {\n", " comm.send(data, metadata, buffers, disposeOnDone);\n", " });\n", " };\n", " var comm = {\n", " send: sendClosure\n", " };\n", " }\n", " window.PyViz.comms[comm_id] = comm;\n", " return comm;\n", " }\n", " window.PyViz.comm_manager = new JupyterCommManager();\n", " \n", "\n", "\n", "var JS_MIME_TYPE = 'application/javascript';\n", "var HTML_MIME_TYPE = 'text/html';\n", "var EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\n", "var CLASS_NAME = 'output';\n", "\n", "/**\n", " * Render data to the DOM node\n", " */\n", "function render(props, node) {\n", " var div = document.createElement(\"div\");\n", " var script = document.createElement(\"script\");\n", " node.appendChild(div);\n", " node.appendChild(script);\n", "}\n", "\n", "/**\n", " * Handle when a new output is added\n", " */\n", "function handle_add_output(event, handle) {\n", " var output_area = handle.output_area;\n", " var output = handle.output;\n", " if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n", " return\n", " }\n", " var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n", " var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n", " if (id !== undefined) {\n", " var nchildren = toinsert.length;\n", " var html_node = toinsert[nchildren-1].children[0];\n", " html_node.innerHTML = output.data[HTML_MIME_TYPE];\n", " var scripts = [];\n", " var nodelist = html_node.querySelectorAll(\"script\");\n", " for (var i in nodelist) {\n", " if (nodelist.hasOwnProperty(i)) {\n", " scripts.push(nodelist[i])\n", " }\n", " }\n", "\n", " scripts.forEach( function (oldScript) {\n", " var newScript = document.createElement(\"script\");\n", " var attrs = [];\n", " var nodemap = oldScript.attributes;\n", " for (var j in nodemap) {\n", " if (nodemap.hasOwnProperty(j)) {\n", " attrs.push(nodemap[j])\n", " }\n", " }\n", " attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n", " newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n", " oldScript.parentNode.replaceChild(newScript, oldScript);\n", " });\n", " if (JS_MIME_TYPE in output.data) {\n", " toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n", " }\n", " output_area._hv_plot_id = id;\n", " if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n", " window.PyViz.plot_index[id] = Bokeh.index[id];\n", " } else {\n", " window.PyViz.plot_index[id] = null;\n", " }\n", " } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n", " var bk_div = document.createElement(\"div\");\n", " bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n", " var script_attrs = bk_div.children[0].attributes;\n", " for (var i = 0; i < script_attrs.length; i++) {\n", " toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n", " }\n", " // store reference to server id on output_area\n", " output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n", " }\n", "}\n", "\n", "/**\n", " * Handle when an output is cleared or removed\n", " */\n", "function handle_clear_output(event, handle) {\n", " var id = handle.cell.output_area._hv_plot_id;\n", " var server_id = handle.cell.output_area._bokeh_server_id;\n", " if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n", " var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n", " if (server_id !== null) {\n", " comm.send({event_type: 'server_delete', 'id': server_id});\n", " return;\n", " } else if (comm !== null) {\n", " comm.send({event_type: 'delete', 'id': id});\n", " }\n", " delete PyViz.plot_index[id];\n", " if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n", " var doc = window.Bokeh.index[id].model.document\n", " doc.clear();\n", " const i = window.Bokeh.documents.indexOf(doc);\n", " if (i > -1) {\n", " window.Bokeh.documents.splice(i, 1);\n", " }\n", " }\n", "}\n", "\n", "/**\n", " * Handle kernel restart event\n", " */\n", "function handle_kernel_cleanup(event, handle) {\n", " delete PyViz.comms[\"hv-extension-comm\"];\n", " window.PyViz.plot_index = {}\n", "}\n", "\n", "/**\n", " * Handle update_display_data messages\n", " */\n", "function handle_update_output(event, handle) {\n", " handle_clear_output(event, {cell: {output_area: handle.output_area}})\n", " handle_add_output(event, handle)\n", "}\n", "\n", "function register_renderer(events, OutputArea) {\n", " function append_mime(data, metadata, element) {\n", " // create a DOM node to render to\n", " var toinsert = this.create_output_subarea(\n", " metadata,\n", " CLASS_NAME,\n", " EXEC_MIME_TYPE\n", " );\n", " this.keyboard_manager.register_events(toinsert);\n", " // Render to node\n", " var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n", " render(props, toinsert[0]);\n", " element.append(toinsert);\n", " return toinsert\n", " }\n", "\n", " events.on('output_added.OutputArea', handle_add_output);\n", " events.on('output_updated.OutputArea', handle_update_output);\n", " events.on('clear_output.CodeCell', handle_clear_output);\n", " events.on('delete.Cell', handle_clear_output);\n", " events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n", "\n", " OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n", " safe: true,\n", " index: 0\n", " });\n", "}\n", "\n", "if (window.Jupyter !== undefined) {\n", " try {\n", " var events = require('base/js/events');\n", " var OutputArea = require('notebook/js/outputarea').OutputArea;\n", " if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n", " register_renderer(events, OutputArea);\n", " }\n", " } catch(err) {\n", " }\n", "}\n" ], "application/vnd.holoviews_load.v0+json": "\nif ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n}\n\n\n function JupyterCommManager() {\n }\n\n JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n comm_manager.register_target(comm_id, function(comm) {\n comm.on_msg(msg_handler);\n });\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n comm.onMsg = msg_handler;\n });\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n console.log(message)\n var content = {data: message.data, comm_id};\n var buffers = []\n for (var buffer of message.buffers || []) {\n buffers.push(new DataView(buffer))\n }\n var metadata = message.metadata || {};\n var msg = {content, buffers, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n })\n }\n }\n\n JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n if (comm_id in window.PyViz.comms) {\n return window.PyViz.comms[comm_id];\n } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n if (msg_handler) {\n comm.on_msg(msg_handler);\n }\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n comm.open();\n if (msg_handler) {\n comm.onMsg = msg_handler;\n }\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n var comm_promise = google.colab.kernel.comms.open(comm_id)\n comm_promise.then((comm) => {\n window.PyViz.comms[comm_id] = comm;\n if (msg_handler) {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n var content = {data: message.data};\n var metadata = message.metadata || {comm_id};\n var msg = {content, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n }\n }) \n var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n return comm_promise.then((comm) => {\n comm.send(data, metadata, buffers, disposeOnDone);\n });\n };\n var comm = {\n send: sendClosure\n };\n }\n window.PyViz.comms[comm_id] = comm;\n return comm;\n }\n window.PyViz.comm_manager = new JupyterCommManager();\n \n\n\nvar JS_MIME_TYPE = 'application/javascript';\nvar HTML_MIME_TYPE = 'text/html';\nvar EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\nvar CLASS_NAME = 'output';\n\n/**\n * Render data to the DOM node\n */\nfunction render(props, node) {\n var div = document.createElement(\"div\");\n var script = document.createElement(\"script\");\n node.appendChild(div);\n node.appendChild(script);\n}\n\n/**\n * Handle when a new output is added\n */\nfunction handle_add_output(event, handle) {\n var output_area = handle.output_area;\n var output = handle.output;\n if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n return\n }\n var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n if (id !== undefined) {\n var nchildren = toinsert.length;\n var html_node = toinsert[nchildren-1].children[0];\n html_node.innerHTML = output.data[HTML_MIME_TYPE];\n var scripts = [];\n var nodelist = html_node.querySelectorAll(\"script\");\n for (var i in nodelist) {\n if (nodelist.hasOwnProperty(i)) {\n scripts.push(nodelist[i])\n }\n }\n\n scripts.forEach( function (oldScript) {\n var newScript = document.createElement(\"script\");\n var attrs = [];\n var nodemap = oldScript.attributes;\n for (var j in nodemap) {\n if (nodemap.hasOwnProperty(j)) {\n attrs.push(nodemap[j])\n }\n }\n attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n oldScript.parentNode.replaceChild(newScript, oldScript);\n });\n if (JS_MIME_TYPE in output.data) {\n toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n }\n output_area._hv_plot_id = id;\n if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n window.PyViz.plot_index[id] = Bokeh.index[id];\n } else {\n window.PyViz.plot_index[id] = null;\n }\n } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n var bk_div = document.createElement(\"div\");\n bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n var script_attrs = bk_div.children[0].attributes;\n for (var i = 0; i < script_attrs.length; i++) {\n toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n }\n // store reference to server id on output_area\n output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n }\n}\n\n/**\n * Handle when an output is cleared or removed\n */\nfunction handle_clear_output(event, handle) {\n var id = handle.cell.output_area._hv_plot_id;\n var server_id = handle.cell.output_area._bokeh_server_id;\n if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n if (server_id !== null) {\n comm.send({event_type: 'server_delete', 'id': server_id});\n return;\n } else if (comm !== null) {\n comm.send({event_type: 'delete', 'id': id});\n }\n delete PyViz.plot_index[id];\n if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n var doc = window.Bokeh.index[id].model.document\n doc.clear();\n const i = window.Bokeh.documents.indexOf(doc);\n if (i > -1) {\n window.Bokeh.documents.splice(i, 1);\n }\n }\n}\n\n/**\n * Handle kernel restart event\n */\nfunction handle_kernel_cleanup(event, handle) {\n delete PyViz.comms[\"hv-extension-comm\"];\n window.PyViz.plot_index = {}\n}\n\n/**\n * Handle update_display_data messages\n */\nfunction handle_update_output(event, handle) {\n handle_clear_output(event, {cell: {output_area: handle.output_area}})\n handle_add_output(event, handle)\n}\n\nfunction register_renderer(events, OutputArea) {\n function append_mime(data, metadata, element) {\n // create a DOM node to render to\n var toinsert = this.create_output_subarea(\n metadata,\n CLASS_NAME,\n EXEC_MIME_TYPE\n );\n this.keyboard_manager.register_events(toinsert);\n // Render to node\n var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n render(props, toinsert[0]);\n element.append(toinsert);\n return toinsert\n }\n\n events.on('output_added.OutputArea', handle_add_output);\n events.on('output_updated.OutputArea', handle_update_output);\n events.on('clear_output.CodeCell', handle_clear_output);\n events.on('delete.Cell', handle_clear_output);\n events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n\n OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n safe: true,\n index: 0\n });\n}\n\nif (window.Jupyter !== undefined) {\n try {\n var events = require('base/js/events');\n var OutputArea = require('notebook/js/outputarea').OutputArea;\n if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n register_renderer(events, OutputArea);\n }\n } catch(err) {\n }\n}\n" }, "metadata": {}, "output_type": "display_data" }, { "data": {}, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "
\n", "
\n", "" ], "text/plain": [ ":Curve [year_month] (sale_price_avg)" ] }, "execution_count": 5, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "39749264-766e-4050-beb0-d11e41e4aaf6" } }, "output_type": "execute_result" } ], "source": [ "import holoviews as hv\n", "import hvplot.pandas\n", "\n", "# Load Bokeh extension for Holoviews\n", "hv.extension(\"bokeh\")\n", "\n", "# Create an interactive plot using hvplot\n", "interactive_plot = monthly_sales_summary.hvplot.line(\n", " x='year_month', \n", " y='sale_price_avg', \n", " title='Average Sale Price in Philadelphia 2023 - 2024', \n", " xlabel='Month', \n", " ylabel='Average Home Sale Price'\n", ")\n", "\n", "# Format the sale_price axis to avoid scientific notation (if needed)\n", "interactive_plot = interactive_plot.opts(\n", " width=1200, \n", " height=800, \n", " tools=['hover'], \n", " line_width=2, \n", " yformatter='%.0f' # This prevents scientific notation by formatting the y-axis labels\n", ")\n", "\n", "# Display the plot\n", "interactive_plot\n" ] }, { "cell_type": "markdown", "id": "8a2a373f-86cc-4023-b9f4-763f3b0b3f24", "metadata": {}, "source": [ "# Calculating Average Sale Price by Zip Code" ] }, { "cell_type": "code", "execution_count": 12, "id": "4f1039ac-0401-4cd8-b36f-fcd24b9e1d8e", "metadata": { "tags": [] }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
zip_codeavg_sale_price
019102520983.0
119103867617.0
219104321289.0
319106620418.0
419107448678.0
\n", "
" ], "text/plain": [ " zip_code avg_sale_price\n", "0 19102 520983.0\n", "1 19103 867617.0\n", "2 19104 321289.0\n", "3 19106 620418.0\n", "4 19107 448678.0" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Step 1: Calculate the average sale price by zip code\n", "avg_sale_price_by_zip = sales_filtered.groupby('zip_code')['sale_price'].mean()\n", "\n", "# Round the average sale price to 0 decimal places\n", "avg_sale_price_by_zip = avg_sale_price_by_zip.round(0)\n", "\n", "# Step 2: Remove zip codes with no sales (filtering NaN values)\n", "avg_sale_price_by_zip = avg_sale_price_by_zip.dropna()\n", "\n", "# Convert to a DataFrame\n", "avg_sale_price_by_zip = avg_sale_price_by_zip.reset_index()\n", "\n", "# Rename 'sale_price' column to 'avg_sale_price'\n", "avg_sale_price_by_zip = avg_sale_price_by_zip.rename(columns={'sale_price': 'avg_sale_price'})\n", "\n", "# Display the result\n", "avg_sale_price_by_zip.head()" ] }, { "cell_type": "code", "execution_count": 13, "id": "50acee4c-1798-4ff5-a7e1-d5b5873e46e6", "metadata": { "tags": [] }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
zip_codeavg_sale_priceCODEgeometry
019102520983.019102POLYGON ((-75.16196 39.95958, -75.16206 39.959...
119103867617.019103POLYGON ((-75.17802 39.96212, -75.17524 39.960...
219104321289.019104POLYGON ((-75.20436 39.97443, -75.20372 39.974...
319106620418.019106POLYGON ((-75.15032 39.95811, -75.15013 39.958...
419107448678.019107POLYGON ((-75.15324 39.95849, -75.15205 39.958...
\n", "
" ], "text/plain": [ " zip_code avg_sale_price CODE \\\n", "0 19102 520983.0 19102 \n", "1 19103 867617.0 19103 \n", "2 19104 321289.0 19104 \n", "3 19106 620418.0 19106 \n", "4 19107 448678.0 19107 \n", "\n", " geometry \n", "0 POLYGON ((-75.16196 39.95958, -75.16206 39.959... \n", "1 POLYGON ((-75.17802 39.96212, -75.17524 39.960... \n", "2 POLYGON ((-75.20436 39.97443, -75.20372 39.974... \n", "3 POLYGON ((-75.15032 39.95811, -75.15013 39.958... \n", "4 POLYGON ((-75.15324 39.95849, -75.15205 39.958... " ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "#Load zip code shape data\n", "zips = gpd.read_file('https://opendata.arcgis.com/datasets/b54ec5210cee41c3a884c9086f7af1be_0.geojson')\n", "\n", "# Perform a merge on 'zip_code'\n", "avg_sale_price_by_zip_gdf = avg_sale_price_by_zip.merge(zips[['CODE', 'geometry']], left_on='zip_code', right_on='CODE', how='left')\n", "\n", "# Check if the object is already a GeoDataFrame\n", "if not isinstance(avg_sale_price_by_zip_gdf, gpd.GeoDataFrame):\n", " # If it's not a GeoDataFrame, convert it\n", " avg_sale_price_by_zip_gdf = gpd.GeoDataFrame(\n", " avg_sale_price_by_zip_gdf, \n", " geometry='geometry' # Specify the existing geometry column\n", " )\n", "\n", "# Display the merged result\n", "avg_sale_price_by_zip_gdf.head()" ] }, { "cell_type": "code", "execution_count": 14, "id": "b5faf360-b8d0-4e16-a3a1-6489b24fb3ab", "metadata": { "tags": [] }, "outputs": [ { "data": {}, "metadata": {}, "output_type": "display_data" }, { "data": {}, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "
\n", "
\n", "" ], "text/plain": [ "Column\n", " [0] Select(options=['Entire Map', ...], value='Entire Map')\n", " [1] ParamFunction(function, _pane=HoloViews, defer_load=False)" ] }, "execution_count": 14, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "e85a4a82-8704-4d44-b96c-aae385ac6597" } }, "output_type": "execute_result" } ], "source": [ "import geopandas as gpd\n", "import hvplot.pandas # For using hvplot with GeoDataFrame\n", "import panel as pn\n", "import bokeh\n", "from bokeh.models import NumeralTickFormatter # Import the NumeralTickFormatter\n", "\n", "# Create the base choropleth plot\n", "choropleth_map1 = avg_sale_price_by_zip_gdf.hvplot(\n", " geo='geometry', # The geometry column\n", " hover_cols=['zip_code', 'avg_sale_price'], # Show zip code, avg sale price on hover\n", " color='avg_sale_price', # Color the areas by average sale price\n", " colorbar=True, # Show colorbar for average sale price\n", " width=800, height=600, title='Average Home Sale Price in 2023 - 2024 by Zip Code',\n", " tools=['pan', 'wheel_zoom', 'box_zoom', 'reset'], # Enable pan, zoom, and reset tools for interactivity\n", " frame_width=800, frame_height=600 # Set size of the map\n", ")\n", "\n", "# Modify colorbar formatter to avoid scientific notation\n", "choropleth_map1.opts(\n", " colorbar_opts={'formatter': NumeralTickFormatter(format=\"0.00\")} # Adjust this as needed\n", ")\n", "\n", "# Get the bounds of the entire dataset (default extent)\n", "default_bounds1 = avg_sale_price_by_zip_gdf.total_bounds # [minx, miny, maxx, maxy]\n", "\n", "# Create a dropdown widget to select the zip code or \"Entire Map\"\n", "zip_code_options1 = ['Entire Map'] + avg_sale_price_by_zip_gdf['zip_code'].unique().tolist()\n", "zip_code_widget1 = pn.widgets.Select(name='Select Zip Code', options=zip_code_options1)\n", "\n", "# Function to update the map based on the selected zip code\n", "def update_map1(zip_code1):\n", " # If the selected zip code is not \"Entire Map\", zoom to the selected zip code but don't filter other zip codes\n", " if zip_code1 != 'Entire Map':\n", " # Find the bounds of the selected zip code\n", " selected_zip_bounds = avg_sale_price_by_zip_gdf[avg_sale_price_by_zip_gdf['zip_code'] == zip_code1].total_bounds\n", " else:\n", " selected_zip_bounds = default_bounds1 # Use the entire bounds for the entire map\n", " \n", " # Create the choropleth plot for the entire dataset (show all zip codes)\n", " filtered_map1 = avg_sale_price_by_zip_gdf.hvplot(\n", " geo='geometry', # The geometry column\n", " hover_cols=['zip_code', 'avg_sale_price'], # Show zip code, avg sale price on hover\n", " color='avg_sale_price', # Color the areas by average sale price\n", " colorbar=True, # Show colorbar for average sale price\n", " width=800, height=600, title='Average Home Sale Price in 2023 - 2024 by Zip Code',\n", " tools=['pan', 'wheel_zoom', 'box_zoom', 'reset'], # Enable pan, zoom, and reset tools for interactivity\n", " frame_width=800, frame_height=600 # Set size of the map\n", " )\n", "\n", " # Modify colorbar formatter to avoid scientific notation\n", " filtered_map1.opts(\n", " colorbar_opts={'formatter': NumeralTickFormatter(format=\"0.00\")} # Adjust this as needed\n", " )\n", " \n", " # Adjust the map bounds based on the selected zip code (or entire map)\n", " filtered_map1.opts(\n", " xlim=(selected_zip_bounds[0], selected_zip_bounds[2]), # Set the x limits based on the selected zip code bounds\n", " ylim=(selected_zip_bounds[1], selected_zip_bounds[3]) # Set the y limits based on the selected zip code bounds\n", " )\n", " \n", " return filtered_map1\n", "\n", "# Link the widget to the map\n", "interactive_map1 = pn.bind(update_map1, zip_code1=zip_code_widget1)\n", "\n", "# Display the widgets and the map together\n", "pn.Column(zip_code_widget1, interactive_map1)\n" ] }, { "cell_type": "markdown", "id": "70c92509-c6be-4aaf-b9ed-bd05b01863cd", "metadata": {}, "source": [ "# Calculating Average Sale Price by Number of Bedrooms and Bathrooms by Zip Code" ] }, { "cell_type": "code", "execution_count": 15, "id": "bfd613fd-d923-4895-b56f-a05bb2decc8c", "metadata": { "tags": [] }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
zip_codenumber_of_bathroomsnumber_of_bedroomsavg_sale_price
0191021.01.0309259.0
1191022.01.0280000.0
2191022.02.0644583.0
3191022.03.01160000.0
4191023.03.01895000.0
\n", "
" ], "text/plain": [ " zip_code number_of_bathrooms number_of_bedrooms avg_sale_price\n", "0 19102 1.0 1.0 309259.0\n", "1 19102 2.0 1.0 280000.0\n", "2 19102 2.0 2.0 644583.0\n", "3 19102 2.0 3.0 1160000.0\n", "4 19102 3.0 3.0 1895000.0" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Step 1: Filter the dataset to include only rows with at least 1 bedroom and 1 bathroom\n", "sales_filtered = sales_filtered[(sales_filtered['number_of_bedrooms'] >= 1) & (sales_filtered['number_of_bathrooms'] >= 1)]\n", "\n", "# Step 2: Calculate the average sale price by zip code, number of bathrooms, and number of bedrooms\n", "avg_sale_price_by_zip_bath_bed = sales_filtered.groupby(['zip_code', 'number_of_bathrooms', 'number_of_bedrooms'])['sale_price'].mean()\n", "\n", "# Round the average sale price to 0 decimal places\n", "avg_sale_price_by_zip_bath_bed = avg_sale_price_by_zip_bath_bed.round(0)\n", "\n", "# Step 3: Remove entries with no sales (filtering NaN values)\n", "avg_sale_price_by_zip_bath_bed = avg_sale_price_by_zip_bath_bed.dropna()\n", "\n", "# Convert to a DataFrame\n", "avg_sale_price_by_zip_bath_bed = avg_sale_price_by_zip_bath_bed.reset_index()\n", "\n", "# Rename 'sale_price' column to 'avg_sale_price'\n", "avg_sale_price_by_zip_bath_bed = avg_sale_price_by_zip_bath_bed.rename(columns={'sale_price': 'avg_sale_price'})\n", "\n", "# Display the result\n", "avg_sale_price_by_zip_bath_bed.head()\n" ] }, { "cell_type": "code", "execution_count": 16, "id": "c9c0e3f1-ad47-4ac7-972e-443efad7bcae", "metadata": { "tags": [] }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
zip_codenumber_of_bathroomsnumber_of_bedroomsavg_sale_priceCODEgeometry
0191021130925919102POLYGON ((-75.16196 39.95958, -75.16206 39.959...
1191022128000019102POLYGON ((-75.16196 39.95958, -75.16206 39.959...
2191022264458319102POLYGON ((-75.16196 39.95958, -75.16206 39.959...
31910223116000019102POLYGON ((-75.16196 39.95958, -75.16206 39.959...
41910233189500019102POLYGON ((-75.16196 39.95958, -75.16206 39.959...
\n", "
" ], "text/plain": [ " zip_code number_of_bathrooms number_of_bedrooms avg_sale_price CODE \\\n", "0 19102 1 1 309259 19102 \n", "1 19102 2 1 280000 19102 \n", "2 19102 2 2 644583 19102 \n", "3 19102 2 3 1160000 19102 \n", "4 19102 3 3 1895000 19102 \n", "\n", " geometry \n", "0 POLYGON ((-75.16196 39.95958, -75.16206 39.959... \n", "1 POLYGON ((-75.16196 39.95958, -75.16206 39.959... \n", "2 POLYGON ((-75.16196 39.95958, -75.16206 39.959... \n", "3 POLYGON ((-75.16196 39.95958, -75.16206 39.959... \n", "4 POLYGON ((-75.16196 39.95958, -75.16206 39.959... " ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "#Load zip code shape data\n", "zips = gpd.read_file('https://opendata.arcgis.com/datasets/b54ec5210cee41c3a884c9086f7af1be_0.geojson')\n", "\n", "# Perform a merge on 'zip_code'\n", "avg_sale_price_by_zip_bath_bed_gdf = avg_sale_price_by_zip_bath_bed.merge(zips[['CODE', 'geometry']], left_on='zip_code', right_on='CODE', how='left')\n", "\n", "# Cast columns to int\n", "avg_sale_price_by_zip_bath_bed_gdf['avg_sale_price'] = avg_sale_price_by_zip_bath_bed_gdf['avg_sale_price'].astype(int)\n", "avg_sale_price_by_zip_bath_bed_gdf['number_of_bedrooms'] = avg_sale_price_by_zip_bath_bed_gdf['number_of_bedrooms'].astype(int)\n", "avg_sale_price_by_zip_bath_bed_gdf['number_of_bathrooms'] = avg_sale_price_by_zip_bath_bed_gdf['number_of_bathrooms'].astype(int)\n", "\n", "# Check if the object is already a GeoDataFrame\n", "if not isinstance(avg_sale_price_by_zip_bath_bed_gdf, gpd.GeoDataFrame):\n", " # If it's not a GeoDataFrame, convert it\n", " avg_sale_price_by_zip_bath_bed_gdf = gpd.GeoDataFrame(\n", " avg_sale_price_by_zip_bath_bed_gdf, \n", " geometry='geometry' # Specify the existing geometry column\n", " )\n", "\n", "# Display the merged result\n", "avg_sale_price_by_zip_bath_bed_gdf.head()" ] }, { "cell_type": "code", "execution_count": 17, "id": "8200e2bb-a61b-4687-8cd0-d5f43ad3a096", "metadata": { "tags": [] }, "outputs": [ { "data": {}, "metadata": {}, "output_type": "display_data" }, { "data": {}, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "
\n", "
\n", "" ], "text/plain": [ "Column\n", " [0] Select(options=['Entire Map', ...], value='Entire Map')\n", " [1] Select(name='Number of Bedrooms', options=[1, 2, 3, 4, 5], value=1)\n", " [2] Select(name='Number of Bathrooms', options=[1, 2, 3, 4, 5, 6, 12], value=1)\n", " [3] ParamFunction(function, _pane=HoloViews, defer_load=False)" ] }, "execution_count": 17, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "26e88c74-acb5-4a00-9bcb-94c2e0457df6" } }, "output_type": "execute_result" } ], "source": [ "import geopandas as gpd\n", "import hvplot.pandas # For using hvplot with GeoDataFrame\n", "import panel as pn\n", "import bokeh\n", "from bokeh.models import NumeralTickFormatter # Import the NumeralTickFormatter\n", "\n", "# Get the bounds of the entire dataset (default extent)\n", "default_bounds = avg_sale_price_by_zip_bath_bed_gdf.total_bounds # [minx, miny, maxx, maxy]\n", "\n", "# Create a dropdown widget to select the zip code or \"Entire Map\"\n", "zip_code_options = ['Entire Map'] + avg_sale_price_by_zip_bath_bed_gdf['zip_code'].unique().tolist()\n", "zip_code_widget = pn.widgets.Select(name='Select Zip Code', options=zip_code_options)\n", "\n", "# Create dropdown widgets for number of bedrooms and bathrooms\n", "bedroom_options = sorted(avg_sale_price_by_zip_bath_bed_gdf['number_of_bedrooms'].unique().tolist())\n", "bedrooms_widget = pn.widgets.Select(\n", " name='Number of Bedrooms',\n", " options=bedroom_options,\n", " value=bedroom_options[0] # Default to the first value\n", ")\n", "\n", "bathroom_options = sorted(avg_sale_price_by_zip_bath_bed_gdf['number_of_bathrooms'].unique().tolist())\n", "bathrooms_widget = pn.widgets.Select(\n", " name='Number of Bathrooms',\n", " options=bathroom_options,\n", " value=bathroom_options[0] # Default to the first value\n", ")\n", "\n", "# Function to update the map based on the selected zip code, number of bedrooms, and bathrooms\n", "def update_map(zip_code, bedrooms, bathrooms):\n", " # Filter data by the selected number of bedrooms and bathrooms\n", " filtered_data = avg_sale_price_by_zip_bath_bed_gdf[\n", " (avg_sale_price_by_zip_bath_bed_gdf['number_of_bedrooms'] == bedrooms) & \n", " (avg_sale_price_by_zip_bath_bed_gdf['number_of_bathrooms'] == bathrooms)\n", " ]\n", " \n", " # If the selected zip code is not \"Entire Map\", zoom to the selected zip code but don't filter other zip codes\n", " if zip_code != 'Entire Map':\n", " # Find the bounds of the selected zip code\n", " selected_zip_bounds = avg_sale_price_by_zip_bath_bed_gdf[avg_sale_price_by_zip_bath_bed_gdf['zip_code'] == zip_code].total_bounds\n", " else:\n", " selected_zip_bounds = default_bounds # Use the entire bounds for the entire map\n", " \n", " # Create the choropleth plot for the filtered data\n", " filtered_map = filtered_data.hvplot(\n", " geo='geometry', # The geometry column\n", " hover_cols=['zip_code', 'avg_sale_price', 'number_of_bedrooms', 'number_of_bathrooms'], # Show zip code, avg sale price, bedrooms, and bathrooms on hover\n", " color='avg_sale_price', # Color the areas by average sale price\n", " colorbar=True, # Show colorbar for average sale price\n", " width=800, height=600, title='Average Home Sale Price in 2023 - 2024 by Zip Code and Number of Bedrooms and Bathrooms',\n", " tools=['pan', 'wheel_zoom', 'box_zoom', 'reset'], # Enable pan, zoom, and reset tools for interactivity\n", " frame_width=800, frame_height=600 # Set size of the map\n", " )\n", "\n", " # Modify colorbar formatter to avoid scientific notation\n", " filtered_map.opts(\n", " colorbar_opts={'formatter': NumeralTickFormatter(format=\"0.00\")} # Adjust this as needed\n", " )\n", " \n", " # Adjust the map bounds based on the selected zip code (or entire map)\n", " filtered_map.opts(\n", " xlim=(selected_zip_bounds[0], selected_zip_bounds[2]), # Set the x limits based on the selected zip code bounds\n", " ylim=(selected_zip_bounds[1], selected_zip_bounds[3]) # Set the y limits based on the selected zip code bounds\n", " )\n", " \n", " return filtered_map\n", "\n", "# Link the widget to the map\n", "interactive_map = pn.bind(update_map, zip_code=zip_code_widget, bedrooms=bedrooms_widget, bathrooms=bathrooms_widget)\n", "\n", "# Display the widgets and the map together\n", "pn.Column(zip_code_widget, bedrooms_widget, bathrooms_widget, interactive_map)\n" ] }, { "cell_type": "code", "execution_count": 18, "id": "fb681841-d93a-45f1-8c8c-4f8b2d3e8b6f", "metadata": { "tags": [] }, "outputs": [ { "data": {}, "metadata": {}, "output_type": "display_data" }, { "data": {}, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "
\n", "
\n", "" ], "text/plain": [ "Column\n", " [0] HTML(str)\n", " [1] HoloViews(Curve, height=800, sizing_mode='fixed', width=1200)\n", " [2] Row\n", " [0] Select(options=['Entire Map', ...], value='Entire Map')\n", " [1] ParamFunction(function, _pane=HoloViews, defer_load=False)\n", " [3] Row\n", " [0] Column\n", " [0] Select(options=['Entire Map', ...], value='Entire Map')\n", " [1] Select(name='Number of Bedrooms', options=[1, 2, 3, 4, 5], value=1)\n", " [2] Select(name='Number of Bathrooms', options=[1, 2, 3, 4, 5, 6, 12], value=1)\n", " [1] ParamFunction(function, _pane=HoloViews, defer_load=False)" ] }, "execution_count": 18, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "0138e464-44f3-4d4c-9e6d-cbcbd90d3e84" } }, "output_type": "execute_result" } ], "source": [ "# Arrange components using Column and Row layout\n", "layout = pn.Column(\n", " pn.pane.HTML(\"

Philadelphia Home Sale Trends Dashboard

\"), # Add the title with custom styling\n", " interactive_plot, # Display the interactive plot first\n", " pn.Row(zip_code_widget1, interactive_map1), # Display the zip code widget1 and interactive map1 next\n", " pn.Row( # Create a row that contains the column of widgets and the interactive map\n", " pn.Column(zip_code_widget, bedrooms_widget, bathrooms_widget), # Place the widgets in a column\n", " interactive_map # Place the interactive map to the right of the widgets\n", " )\n", ")\n", "\n", "# Display the layout\n", "layout.servable()\n" ] }, { "cell_type": "code", "execution_count": null, "id": "7b506b9b-d21d-4602-a893-f656dcd90c4d", "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.12" } }, "nbformat": 4, "nbformat_minor": 5 }