Forked from renanxcortes/conditional_communicating_widgets.ipynb
Last active
May 4, 2019 20:47
-
-
Save sjsrey/87f4167e81e7a93d9dbd93cd0bbf2790 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"cells": [ | |
{ | |
"cell_type": "code", | |
"execution_count": 1, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/html": [ | |
"<div>\n", | |
"<style scoped>\n", | |
" .dataframe tbody tr th:only-of-type {\n", | |
" vertical-align: middle;\n", | |
" }\n", | |
"\n", | |
" .dataframe tbody tr th {\n", | |
" vertical-align: top;\n", | |
" }\n", | |
"\n", | |
" .dataframe thead th {\n", | |
" text-align: right;\n", | |
" }\n", | |
"</style>\n", | |
"<table border=\"1\" class=\"dataframe\">\n", | |
" <thead>\n", | |
" <tr style=\"text-align: right;\">\n", | |
" <th></th>\n", | |
" <th>FIPS</th>\n", | |
" <th>MSA</th>\n", | |
" <th>TOT_POP</th>\n", | |
" <th>POP_16</th>\n", | |
" <th>POP_65</th>\n", | |
" <th>WHITE_</th>\n", | |
" <th>BLACK_</th>\n", | |
" <th>ASIAN_</th>\n", | |
" <th>HISP_</th>\n", | |
" <th>MULTI_RA</th>\n", | |
" <th>...</th>\n", | |
" <th>OCC_MAN</th>\n", | |
" <th>OCC_OFF1</th>\n", | |
" <th>OCC_INFO</th>\n", | |
" <th>HH_INC</th>\n", | |
" <th>POV_POP</th>\n", | |
" <th>POV_TOT</th>\n", | |
" <th>HSG_VAL</th>\n", | |
" <th>FIPSNO</th>\n", | |
" <th>POLYID</th>\n", | |
" <th>geometry</th>\n", | |
" </tr>\n", | |
" </thead>\n", | |
" <tbody>\n", | |
" <tr>\n", | |
" <th>0</th>\n", | |
" <td>06061022001</td>\n", | |
" <td>Sacramento</td>\n", | |
" <td>5501</td>\n", | |
" <td>1077</td>\n", | |
" <td>518</td>\n", | |
" <td>4961</td>\n", | |
" <td>29</td>\n", | |
" <td>82</td>\n", | |
" <td>336</td>\n", | |
" <td>31</td>\n", | |
" <td>...</td>\n", | |
" <td>117</td>\n", | |
" <td>663</td>\n", | |
" <td>42</td>\n", | |
" <td>52941</td>\n", | |
" <td>5461</td>\n", | |
" <td>470</td>\n", | |
" <td>225900</td>\n", | |
" <td>6061022001</td>\n", | |
" <td>1</td>\n", | |
" <td>POLYGON ((-120.217504 39.162085, -120.220064 3...</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>1</th>\n", | |
" <td>06061020106</td>\n", | |
" <td>Sacramento</td>\n", | |
" <td>2072</td>\n", | |
" <td>396</td>\n", | |
" <td>109</td>\n", | |
" <td>1603</td>\n", | |
" <td>0</td>\n", | |
" <td>28</td>\n", | |
" <td>391</td>\n", | |
" <td>41</td>\n", | |
" <td>...</td>\n", | |
" <td>38</td>\n", | |
" <td>229</td>\n", | |
" <td>19</td>\n", | |
" <td>51958</td>\n", | |
" <td>2052</td>\n", | |
" <td>160</td>\n", | |
" <td>249300</td>\n", | |
" <td>6061020106</td>\n", | |
" <td>2</td>\n", | |
" <td>POLYGON ((-120.064072 39.236687, -120.064115 3...</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>2</th>\n", | |
" <td>06061020107</td>\n", | |
" <td>Sacramento</td>\n", | |
" <td>3633</td>\n", | |
" <td>911</td>\n", | |
" <td>126</td>\n", | |
" <td>1624</td>\n", | |
" <td>9</td>\n", | |
" <td>0</td>\n", | |
" <td>1918</td>\n", | |
" <td>41</td>\n", | |
" <td>...</td>\n", | |
" <td>86</td>\n", | |
" <td>197</td>\n", | |
" <td>0</td>\n", | |
" <td>32992</td>\n", | |
" <td>3604</td>\n", | |
" <td>668</td>\n", | |
" <td>175900</td>\n", | |
" <td>6061020107</td>\n", | |
" <td>3</td>\n", | |
" <td>POLYGON ((-120.00526 39.279982, -120.005266 39...</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>3</th>\n", | |
" <td>06061020105</td>\n", | |
" <td>Sacramento</td>\n", | |
" <td>1683</td>\n", | |
" <td>281</td>\n", | |
" <td>154</td>\n", | |
" <td>1564</td>\n", | |
" <td>0</td>\n", | |
" <td>55</td>\n", | |
" <td>60</td>\n", | |
" <td>4</td>\n", | |
" <td>...</td>\n", | |
" <td>5</td>\n", | |
" <td>256</td>\n", | |
" <td>6</td>\n", | |
" <td>54556</td>\n", | |
" <td>1683</td>\n", | |
" <td>116</td>\n", | |
" <td>302300</td>\n", | |
" <td>6061020105</td>\n", | |
" <td>4</td>\n", | |
" <td>POLYGON ((-120.095366 39.197183, -120.095761 3...</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>4</th>\n", | |
" <td>06061020200</td>\n", | |
" <td>Sacramento</td>\n", | |
" <td>5794</td>\n", | |
" <td>1278</td>\n", | |
" <td>830</td>\n", | |
" <td>5185</td>\n", | |
" <td>17</td>\n", | |
" <td>13</td>\n", | |
" <td>251</td>\n", | |
" <td>229</td>\n", | |
" <td>...</td>\n", | |
" <td>155</td>\n", | |
" <td>506</td>\n", | |
" <td>59</td>\n", | |
" <td>50815</td>\n", | |
" <td>5771</td>\n", | |
" <td>342</td>\n", | |
" <td>167300</td>\n", | |
" <td>6061020200</td>\n", | |
" <td>5</td>\n", | |
" <td>POLYGON ((-121.038014 38.931727, -121.037162 3...</td>\n", | |
" </tr>\n", | |
" </tbody>\n", | |
"</table>\n", | |
"<p>5 rows × 32 columns</p>\n", | |
"</div>" | |
], | |
"text/plain": [ | |
" FIPS MSA TOT_POP POP_16 POP_65 WHITE_ BLACK_ ASIAN_ \\\n", | |
"0 06061022001 Sacramento 5501 1077 518 4961 29 82 \n", | |
"1 06061020106 Sacramento 2072 396 109 1603 0 28 \n", | |
"2 06061020107 Sacramento 3633 911 126 1624 9 0 \n", | |
"3 06061020105 Sacramento 1683 281 154 1564 0 55 \n", | |
"4 06061020200 Sacramento 5794 1278 830 5185 17 13 \n", | |
"\n", | |
" HISP_ MULTI_RA ... OCC_MAN OCC_OFF1 OCC_INFO HH_INC POV_POP \\\n", | |
"0 336 31 ... 117 663 42 52941 5461 \n", | |
"1 391 41 ... 38 229 19 51958 2052 \n", | |
"2 1918 41 ... 86 197 0 32992 3604 \n", | |
"3 60 4 ... 5 256 6 54556 1683 \n", | |
"4 251 229 ... 155 506 59 50815 5771 \n", | |
"\n", | |
" POV_TOT HSG_VAL FIPSNO POLYID \\\n", | |
"0 470 225900 6061022001 1 \n", | |
"1 160 249300 6061020106 2 \n", | |
"2 668 175900 6061020107 3 \n", | |
"3 116 302300 6061020105 4 \n", | |
"4 342 167300 6061020200 5 \n", | |
"\n", | |
" geometry \n", | |
"0 POLYGON ((-120.217504 39.162085, -120.220064 3... \n", | |
"1 POLYGON ((-120.064072 39.236687, -120.064115 3... \n", | |
"2 POLYGON ((-120.00526 39.279982, -120.005266 39... \n", | |
"3 POLYGON ((-120.095366 39.197183, -120.095761 3... \n", | |
"4 POLYGON ((-121.038014 38.931727, -121.037162 3... \n", | |
"\n", | |
"[5 rows x 32 columns]" | |
] | |
}, | |
"execution_count": 1, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"import splot\n", | |
"import libpysal as lps\n", | |
"import pandas as pd\n", | |
"import geopandas as gpd\n", | |
"#from splot.mapping import vba_choropleth\n", | |
"import mapclassify as classify\n", | |
"\n", | |
"filepath = lps.examples.get_path(\"sacramentot2.shp\")\n", | |
"data = gpd.read_file(filepath)\n", | |
"data.head()" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 2, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"_classifiers = {\n", | |
" 'box_plot': classify.Box_Plot,\n", | |
" 'equal_interval': classify.Equal_Interval,\n", | |
" 'fisher_jenks': classify.Fisher_Jenks,\n", | |
" 'headtail_breaks': classify.HeadTail_Breaks,\n", | |
" 'jenks_caspall': classify.Jenks_Caspall,\n", | |
" 'jenks_caspall_forced': classify.Jenks_Caspall_Forced,\n", | |
" 'max_p_classifier': classify.Max_P_Classifier,\n", | |
" 'maximum_breaks': classify.Maximum_Breaks,\n", | |
" 'natural_breaks': classify.Natural_Breaks,\n", | |
" 'quantiles': classify.Quantiles,\n", | |
" 'percentiles': classify.Percentiles,\n", | |
" 'std_mean': classify.Std_Mean,\n", | |
" 'user_defined': classify.User_Defined,\n", | |
" }" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 3, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"import matplotlib.pyplot as plt\n", | |
"from matplotlib import colors\n", | |
"from matplotlib import patches\n", | |
"import collections\n", | |
"import matplotlib.cm as cm\n", | |
"import mapclassify as classify\n", | |
"import numpy as np\n", | |
"#from ._viz_utils import _classifiers, format_legend\n", | |
"\n", | |
"\"\"\"\n", | |
"Creating Maps with splot\n", | |
"* Value-by-Alpha maps\n", | |
"* Mapclassify wrapper\n", | |
"* Color utilities\n", | |
"TODO:\n", | |
"* add Choropleth functionality with one input variable\n", | |
"* merge all alpha keywords in one keyword dictionary\n", | |
"for vba_choropleth\n", | |
"\"\"\"\n", | |
"\n", | |
"__author__ = (\"Stefanie Lumnitz <[email protected]>\")\n", | |
"\n", | |
"\n", | |
"def value_by_alpha_cmap(x, y, cmap='GnBu', revert_alpha=False, divergent=False):\n", | |
" \"\"\"\n", | |
" Calculates Value by Alpha rgba values\n", | |
" \n", | |
" Parameters\n", | |
" ----------\n", | |
" x : array\n", | |
" Variable determined by color\n", | |
" y : array\n", | |
" Variable determining alpha value\n", | |
" cmap : str or list of str\n", | |
" Matplotlib Colormap or list of colors used\n", | |
" to create vba_layer\n", | |
" revert_alpha : bool, optional\n", | |
" If True, high y values will have a\n", | |
" low alpha and low values will be transparent.\n", | |
" Default =False.\n", | |
" divergent : bool, optional\n", | |
" Creates a divergent alpha array with high values\n", | |
" at the extremes and low, transparent values\n", | |
" in the middle of the input values.\n", | |
" \n", | |
" Returns\n", | |
" -------\n", | |
" rgba : ndarray (n,4)\n", | |
" RGBA colormap, where the alpha channel represents one\n", | |
" attribute (x) and the rgb color the other attribute (y)\n", | |
" cmap : str or list of str\n", | |
" Original Matplotlib Colormap or list of colors used\n", | |
" to create vba_layer\n", | |
" \n", | |
" Examples\n", | |
" --------\n", | |
" \n", | |
" Imports\n", | |
" \n", | |
" >>> from libpysal import examples\n", | |
" >>> import geopandas as gpd\n", | |
" >>> import matplotlib.pyplot as plt\n", | |
" >>> import matplotlib\n", | |
" >>> import numpy as np\n", | |
" >>> from splot.mapping import value_by_alpha_cmap\n", | |
" \n", | |
" Load Example Data\n", | |
" \n", | |
" >>> link_to_data = examples.get_path('columbus.shp')\n", | |
" >>> gdf = gpd.read_file(link_to_data)\n", | |
" >>> x = gdf['HOVAL'].values\n", | |
" >>> y = gdf['CRIME'].values\n", | |
" \n", | |
" Create rgba values\n", | |
" \n", | |
" >>> rgba, _ = value_by_alpha_cmap(x, y)\n", | |
" \n", | |
" Create divergent rgba and change Colormap\n", | |
" \n", | |
" >>> div_rgba, _ = value_by_alpha_cmap(x, y, cmap='seismic', divergent=True)\n", | |
" \n", | |
" Create rgba values with reverted alpha values\n", | |
" \n", | |
" >>> rev_rgba, _ = value_by_alpha_cmap(x, y, cmap='RdBu', revert_alpha=True)\n", | |
" \n", | |
" \"\"\"\n", | |
" # option for cmap or colorlist input\n", | |
" if isinstance(cmap, str):\n", | |
" cmap = cm.get_cmap(cmap)\n", | |
" elif isinstance(cmap, collections.Sequence):\n", | |
" cmap = colors.LinearSegmentedColormap.from_list('newmap', cmap)\n", | |
"\n", | |
" rgba = cmap((x - x.min()) / (x.max() - x.min()))\n", | |
" if revert_alpha:\n", | |
" rgba[:, 3] = 1 -((y - y.min()) / (y.max() - y.min()))\n", | |
" else:\n", | |
" rgba[:, 3] = (y - y.min()) / (y.max() - y.min())\n", | |
" if divergent is not False:\n", | |
" a_under_0p5 = rgba[:, 3] < 0.5\n", | |
" rgba[a_under_0p5, 3] = 1 - rgba[a_under_0p5, 3]\n", | |
" rgba[:, 3] = (rgba[:, 3] - 0.5) * 2\n", | |
" return rgba, cmap\n", | |
"\n", | |
"\n", | |
"def vba_choropleth(x_var, y_var, gdf, cmap='GnBu', \n", | |
" divergent=False, revert_alpha=False,\n", | |
" alpha_mapclassify=None,\n", | |
" rgb_mapclassify=None,\n", | |
" ax=None, legend=False):\n", | |
" \"\"\"\n", | |
" Value by Alpha Choropleth \n", | |
" \n", | |
" Parameters\n", | |
" ----------\n", | |
" x_var : string or array\n", | |
" The name of variable in gdf determined by color or an array \n", | |
" of values determined by color.\n", | |
" y_var : string or array\n", | |
" The name of variable in gdf determining alpha value or an array \n", | |
" of values determined by color.\n", | |
" gdf : geopandas dataframe instance\n", | |
" The Dataframe containing information to plot.\n", | |
" cmap : str or list of str\n", | |
" Matplotlib Colormap or list of colors used\n", | |
" to create vba_layer\n", | |
" divergent : bool, optional\n", | |
" Creates a divergent alpha array with high values at\n", | |
" the extremes and low, transparent values in the\n", | |
" middle of the input values.\n", | |
" revert_alpha : bool, optional\n", | |
" If True, high y values will have a\n", | |
" low alpha and low values will be transparent.\n", | |
" Default = False.\n", | |
" alpha_mapclassify : dict\n", | |
" Keywords used for binning input values and\n", | |
" classifying alpha values with `mapclassify`.\n", | |
" Note: valid keywords are eg. dict(classifier='quantiles', k=5,\n", | |
" hinge=1.5). For other options check `splot.mapping.mapclassify_bin`.\n", | |
" rgb_mapclassify : dict\n", | |
" Keywords used for binning input values and\n", | |
" classifying rgb values with `mapclassify`.\n", | |
" Note: valid keywords are eg.g dict(classifier='quantiles', k=5,\n", | |
" hinge=1.5).For other options check `splot.mapping.mapclassify_bin`.\n", | |
" ax : matplotlib Axes instance, optional\n", | |
" Axes in which to plot the figure in multiple Axes layout.\n", | |
" Default = None\n", | |
" legend : bool, optional\n", | |
" Adds a legend.\n", | |
" Note: currently only available if data is classified,\n", | |
" hence if `alpha_mapclassify` and `rgb_mapclassify` are used.\n", | |
" \n", | |
" Returns\n", | |
" -------\n", | |
" fig : matplotlip Figure instance\n", | |
" Figure of Value by Alpha choropleth\n", | |
" ax : matplotlib Axes instance\n", | |
" Axes in which the figure is plotted\n", | |
" \n", | |
" Examples\n", | |
" --------\n", | |
" \n", | |
" Imports\n", | |
" \n", | |
" >>> from libpysal import examples\n", | |
" >>> import geopandas as gpd\n", | |
" >>> import matplotlib.pyplot as plt\n", | |
" >>> import matplotlib\n", | |
" >>> import numpy as np\n", | |
" >>> from splot.mapping import vba_choropleth\n", | |
" \n", | |
" Load Example Data\n", | |
" \n", | |
" >>> link_to_data = examples.get_path('columbus.shp')\n", | |
" >>> gdf = gpd.read_file(link_to_data)\n", | |
" \n", | |
" Plot a Value-by-Alpha map\n", | |
" \n", | |
" >>> fig, _ = vba_choropleth('HOVAL', 'CRIME', gdf)\n", | |
" >>> plt.show()\n", | |
" \n", | |
" Plot a Value-by-Alpha map with reverted alpha values\n", | |
" \n", | |
" >>> fig, _ = vba_choropleth('HOVAL', 'CRIME', gdf, cmap='RdBu',\n", | |
" ... revert_alpha=True)\n", | |
" >>> plt.show()\n", | |
" \n", | |
" Plot a Value-by-Alpha map with classified alpha and rgb values\n", | |
" \n", | |
" >>> fig, axs = plt.subplots(2,2, figsize=(20,10))\n", | |
" >>> vba_choropleth('HOVAL', 'CRIME', gdf, cmap='viridis', ax = axs[0,0],\n", | |
" ... rgb_mapclassify=dict(classifier='quantiles', k=3), \n", | |
" ... alpha_mapclassify=dict(classifier='quantiles', k=3))\n", | |
" >>> vba_choropleth('HOVAL', 'CRIME', gdf, cmap='viridis', ax = axs[0,1],\n", | |
" ... rgb_mapclassify=dict(classifier='natural_breaks'), \n", | |
" ... alpha_mapclassify=dict(classifier='natural_breaks'))\n", | |
" >>> vba_choropleth('HOVAL', 'CRIME', gdf, cmap='viridis', ax = axs[1,0],\n", | |
" ... rgb_mapclassify=dict(classifier='std_mean'), \n", | |
" ... alpha_mapclassify=dict(classifier='std_mean'))\n", | |
" >>> vba_choropleth('HOVAL', 'CRIME', gdf, cmap='viridis', ax = axs[1,1],\n", | |
" ... rgb_mapclassify=dict(classifier='fisher_jenks', k=3), \n", | |
" ... alpha_mapclassify=dict(classifier='fisher_jenks', k=3))\n", | |
" >>> plt.show()\n", | |
" \n", | |
" Pass in a list of colors instead of a cmap\n", | |
" \n", | |
" >>> color_list = ['#a1dab4','#41b6c4','#225ea8']\n", | |
" >>> vba_choropleth('HOVAL', 'CRIME', gdf, cmap=color_list,\n", | |
" ... rgb_mapclassify=dict(classifier='quantiles', k=3), \n", | |
" ... alpha_mapclassify=dict(classifier='quantiles'))\n", | |
" >>> plt.show()\n", | |
" \n", | |
" Add a legend and use divergent alpha values\n", | |
" \n", | |
" >>> fig = plt.figure(figsize=(15,10))\n", | |
" >>> ax = fig.add_subplot(111)\n", | |
" >>> vba_choropleth('HOVAL', 'CRIME', gdf, divergent=True,\n", | |
" ... alpha_mapclassify=dict(classifier='quantiles', k=5),\n", | |
" ... rgb_mapclassify=dict(classifier='quantiles', k=5),\n", | |
" ... legend=True, ax=ax)\n", | |
" >>> plt.show()\n", | |
" \"\"\"\n", | |
" \n", | |
" if isinstance(x_var, str): \n", | |
" x = np.array(gdf[x_var]) \n", | |
" else: \n", | |
" x = x_var\n", | |
" \n", | |
" if isinstance(y_var, str): \n", | |
" y = np.array(gdf[y_var]) \n", | |
" else: \n", | |
" y = y_var\n", | |
"\n", | |
" if ax is None:\n", | |
" fig = plt.figure()\n", | |
" ax = fig.add_subplot(111)\n", | |
" else:\n", | |
" fig = ax.get_figure()\n", | |
" \n", | |
" if rgb_mapclassify is not None:\n", | |
" rgb_mapclassify.setdefault('k', 5)\n", | |
" rgb_mapclassify.setdefault('hinge', 1.5)\n", | |
" rgb_mapclassify.setdefault('multiples', [-2,-1,1,2])\n", | |
" rgb_mapclassify.setdefault('mindiff', 0)\n", | |
" rgb_mapclassify.setdefault('initial', 100)\n", | |
" rgb_mapclassify.setdefault('bins', [20, max(x)])\n", | |
" classifier = rgb_mapclassify['classifier']\n", | |
" k = rgb_mapclassify['k']\n", | |
" hinge = rgb_mapclassify['hinge']\n", | |
" multiples = rgb_mapclassify['multiples']\n", | |
" mindiff = rgb_mapclassify['mindiff']\n", | |
" initial = rgb_mapclassify['initial']\n", | |
" bins = rgb_mapclassify['bins']\n", | |
" rgb_bins = mapclassify_bin(x, classifier, k=k, hinge=hinge,\n", | |
" multiples=multiples,\n", | |
" mindiff=mindiff,\n", | |
" initial=initial, bins=bins)\n", | |
" x = rgb_bins.yb\n", | |
"\n", | |
" if alpha_mapclassify is not None:\n", | |
" alpha_mapclassify.setdefault('k', 5)\n", | |
" alpha_mapclassify.setdefault('hinge', 1.5)\n", | |
" alpha_mapclassify.setdefault('multiples', [-2,-1,1,2])\n", | |
" alpha_mapclassify.setdefault('mindiff', 0)\n", | |
" alpha_mapclassify.setdefault('initial', 100)\n", | |
" alpha_mapclassify.setdefault('bins', [20, max(y)])\n", | |
" classifier = alpha_mapclassify['classifier']\n", | |
" k = alpha_mapclassify['k']\n", | |
" hinge = alpha_mapclassify['hinge']\n", | |
" multiples = alpha_mapclassify['multiples']\n", | |
" mindiff = alpha_mapclassify['mindiff']\n", | |
" initial = alpha_mapclassify['initial']\n", | |
" bins = alpha_mapclassify['bins']\n", | |
" #TODO: use the pct keyword here\n", | |
" alpha_bins = mapclassify_bin(y, classifier,\n", | |
" k=k, hinge=hinge,\n", | |
" multiples=multiples,\n", | |
" mindiff=mindiff,\n", | |
" initial=initial, bins=bins)\n", | |
" y = alpha_bins.yb\n", | |
"\n", | |
" rgba, vba_cmap = value_by_alpha_cmap(x=x, y=y, cmap=cmap,\n", | |
" divergent=divergent,\n", | |
" revert_alpha=revert_alpha)\n", | |
" gdf.plot(color=rgba, ax=ax)\n", | |
" ax.set_axis_off()\n", | |
" ax.set_aspect('equal')\n", | |
" \n", | |
" if legend:\n", | |
" left, bottom, width, height = [0, 0.5, 0.2, 0.2]\n", | |
" ax2 = fig.add_axes([left, bottom, width, height])\n", | |
" vba_legend(rgb_bins, alpha_bins, vba_cmap, ax=ax2)\n", | |
" return fig, ax\n", | |
"\n", | |
"\n", | |
"def vba_legend(rgb_bins, alpha_bins, cmap, ax=None):\n", | |
" \"\"\"\n", | |
" Creates Value by Alpha heatmap used as choropleth legend.\n", | |
" \n", | |
" Parameters\n", | |
" ----------\n", | |
" rgb_bins : pysal.mapclassify instance\n", | |
" Object of classified values used for rgb.\n", | |
" Can be created with `mapclassify_bin()`\n", | |
" or `pysal.mapclassify`.\n", | |
" alpha_bins : pysal.mapclassify instance\n", | |
" Object of classified values used for alpha.\n", | |
" Can be created with `mapclassify_bin()`\n", | |
" or `pysal.mapclassify`.\n", | |
" ax : matplotlib Axes instance, optional\n", | |
" Axes in which to plot the figure in multiple Axes layout.\n", | |
" Default = None\n", | |
" \n", | |
" Returns\n", | |
" -------\n", | |
" fig : matplotlip Figure instance\n", | |
" Figure of Value by Alpha heatmap\n", | |
" ax : matplotlib Axes instance\n", | |
" Axes in which the figure is plotted\n", | |
" \n", | |
" Examples\n", | |
" --------\n", | |
" Imports\n", | |
" \n", | |
" >>> from libpysal import examples\n", | |
" >>> import geopandas as gpd\n", | |
" >>> import matplotlib.pyplot as plt\n", | |
" >>> import matplotlib\n", | |
" >>> import numpy as np\n", | |
" >>> from splot.mapping import vba_legend, mapclassify_bin\n", | |
" \n", | |
" Load Example Data\n", | |
" \n", | |
" >>> link_to_data = examples.get_path('columbus.shp')\n", | |
" >>> gdf = gpd.read_file(link_to_data)\n", | |
" >>> x = gdf['HOVAL'].values\n", | |
" >>> y = gdf['CRIME'].values\n", | |
" \n", | |
" Classify your data\n", | |
" \n", | |
" >>> rgb_bins = mapclassify_bin(x, 'quantiles')\n", | |
" >>> alpha_bins = mapclassify_bin(y, 'quantiles')\n", | |
" \n", | |
" Plot your legend\n", | |
" \n", | |
" >>> fig, _ = vba_legend(rgb_bins, alpha_bins, cmap='RdBu')\n", | |
" >>> plt.show()\n", | |
" \n", | |
" \"\"\"\n", | |
" # VALUES\n", | |
" rgba, legend_cmap = value_by_alpha_cmap(rgb_bins.yb, alpha_bins.yb, cmap=cmap)\n", | |
" # separate rgb and alpha values\n", | |
" alpha = rgba[:, 3]\n", | |
" # extract unique values for alpha and rgb\n", | |
" alpha_vals = np.unique(alpha)\n", | |
" rgb_vals = legend_cmap((rgb_bins.bins - rgb_bins.bins.min()) / (\n", | |
" rgb_bins.bins.max() - rgb_bins.bins.min()))[:, 0:3]\n", | |
" \n", | |
" # PLOTTING\n", | |
" if ax is None:\n", | |
" fig = plt.figure()\n", | |
" ax = fig.add_subplot(111)\n", | |
" else:\n", | |
" fig = ax.get_figure()\n", | |
"\n", | |
" for irow, alpha_val in enumerate(alpha_vals):\n", | |
" for icol, rgb_val in enumerate(rgb_vals):\n", | |
" rect = patches.Rectangle((irow, icol), 1, 1, linewidth=3,\n", | |
" edgecolor='none',\n", | |
" facecolor=rgb_val,\n", | |
" alpha=alpha_val)\n", | |
" ax.add_patch(rect)\n", | |
"\n", | |
" values_alpha, x_in_thousand = format_legend(alpha_bins.bins)\n", | |
" values_rgb, y_in_thousand = format_legend(rgb_bins.bins)\n", | |
" ax.plot([], [])\n", | |
" ax.set_xlim([0, irow+1])\n", | |
" ax.set_ylim([0, icol+1])\n", | |
" ax.set_xticks(np.arange(irow+1) + 0.5)\n", | |
" ax.set_yticks(np.arange(icol+1) + 0.5)\n", | |
" ax.set_xticklabels(['< %1.1f' % val for val in values_alpha],\n", | |
" rotation=30, horizontalalignment='right')\n", | |
" ax.set_yticklabels(['$<$%1.1f' % val for val in values_rgb])\n", | |
" if x_in_thousand:\n", | |
" ax.set_xlabel('alpha variable ($10^3$)')\n", | |
" if y_in_thousand:\n", | |
" ax.set_ylabel('rgb variable ($10^3$)')\n", | |
" else:\n", | |
" ax.set_xlabel('alpha variable')\n", | |
" ax.set_ylabel('rgb variable')\n", | |
" ax.spines['left'].set_visible(False)\n", | |
" ax.spines['right'].set_visible(False)\n", | |
" ax.spines['bottom'].set_visible(False)\n", | |
" ax.spines['top'].set_visible(False)\n", | |
" return fig, ax\n", | |
"\n", | |
"\n", | |
"def mapclassify_bin(y, classifier, k=5, pct=[1,10,50,90,99,100],\n", | |
" hinge=1.5, multiples=[-2,-1,1,2], mindiff=0,\n", | |
" initial=100, bins=None):\n", | |
" \"\"\"\n", | |
" Classify your data with `pysal.mapclassify`\n", | |
" Note: Input parameters are dependent on classifier used.\n", | |
" \n", | |
" Parameters\n", | |
" ----------\n", | |
" y : array\n", | |
" (n,1), values to classify\n", | |
" classifier : str\n", | |
" pysal.mapclassify classification scheme\n", | |
" k : int, optional\n", | |
" The number of classes. Default=5.\n", | |
" pct : array, optional\n", | |
" Percentiles used for classification with `percentiles`.\n", | |
" Default=[1,10,50,90,99,100]\n", | |
" hinge : float, optional\n", | |
" Multiplier for IQR when `Box_Plot` classifier used.\n", | |
" Default=1.5.\n", | |
" multiples : array, optional\n", | |
" The multiples of the standard deviation to add/subtract from\n", | |
" the sample mean to define the bins using `std_mean`.\n", | |
" Default=[-2,-1,1,2].\n", | |
" mindiff : float, optional\n", | |
" The minimum difference between class breaks\n", | |
" if using `maximum_breaks` classifier. Deafult =0.\n", | |
" initial : int\n", | |
" Number of initial solutions to generate or number of runs\n", | |
" when using `natural_breaks` or `max_p_classifier`.\n", | |
" Default =100.\n", | |
" Note: setting initial to 0 will result in the quickest\n", | |
" calculation of bins.\n", | |
" bins : array, optional\n", | |
" (k,1), upper bounds of classes (have to be monotically \n", | |
" increasing) if using `user_defined` classifier.\n", | |
" Default =None, Example =[20, max(y)].\n", | |
" Returns\n", | |
" -------\n", | |
" bins : pysal.mapclassify instance\n", | |
" Object containing bin ids for each observation (.yb),\n", | |
" upper bounds of each class (.bins), number of classes (.k)\n", | |
" and number of onservations falling in each class (.counts)\n", | |
" \n", | |
" Note: Supported classifiers include: quantiles, box_plot, euqal_interval,\n", | |
" fisher_jenks, headtail_breaks, jenks_caspall, jenks_caspall_forced,\n", | |
" max_p_classifier, maximum_breaks, natural_breaks, percentiles, std_mean,\n", | |
" user_defined\n", | |
" \n", | |
" Examples\n", | |
" --------\n", | |
" Imports\n", | |
" \n", | |
" >>> from libpysal import examples\n", | |
" >>> import geopandas as gpd\n", | |
" >>> from splot.mapping import mapclassify_bin\n", | |
" \n", | |
" Load Example Data\n", | |
" \n", | |
" >>> link_to_data = examples.get_path('columbus.shp')\n", | |
" >>> gdf = gpd.read_file(link_to_data)\n", | |
" >>> x = gdf['HOVAL'].values\n", | |
" \n", | |
" Classify values by quantiles\n", | |
" \n", | |
" >>> quantiles = mapclassify_bin(x, 'quantiles')\n", | |
" \n", | |
" Classify values by box_plot and set hinge to 2\n", | |
" \n", | |
" >>> box_plot = mapclassify_bin(x, 'box_plot', hinge=2)\n", | |
" \n", | |
" \"\"\"\n", | |
" classifier = classifier.lower()\n", | |
" if classifier not in _classifiers:\n", | |
" raise ValueError(\"Invalid scheme. Scheme must be in the\"\n", | |
" \" set: %r\" % _classifiers.keys())\n", | |
" elif classifier == 'box_plot':\n", | |
" bins = _classifiers[classifier](y, hinge)\n", | |
" elif classifier == 'headtail_breaks':\n", | |
" bins = _classifiers[classifier](y)\n", | |
" elif classifier == 'percentiles':\n", | |
" bins = _classifiers[classifier](y, pct)\n", | |
" elif classifier == 'std_mean':\n", | |
" bins = _classifiers[classifier](y, multiples)\n", | |
" elif classifier == 'maximum_breaks':\n", | |
" bins = _classifiers[classifier](y, k, mindiff)\n", | |
" elif classifier in ['natural_breaks', 'max_p_classifier']:\n", | |
" bins = _classifiers[classifier](y, k, initial)\n", | |
" elif classifier == 'user_defined':\n", | |
" bins = _classifiers[classifier](y, bins)\n", | |
" else:\n", | |
" bins = _classifiers[classifier](y, k)\n", | |
" return bins" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"Communicating the conditional widgets with the Output class of ipywidgets.\n", | |
"\n", | |
"Inspired by a snippet from https://github.com/jupyter-widgets/ipywidgets/issues/1960." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 4, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"application/vnd.jupyter.widget-view+json": { | |
"model_id": "", | |
"version_major": 2, | |
"version_minor": 0 | |
}, | |
"text/plain": [ | |
"VBox(children=(RadioButtons(options=('sequential', 'diverging', 'qualitative'), value='sequential'), Output())…" | |
] | |
}, | |
"metadata": {}, | |
"output_type": "display_data" | |
} | |
], | |
"source": [ | |
"from ipywidgets import interact, Dropdown, RadioButtons, IntSlider, VBox, HBox, FloatSlider, Button\n", | |
"\n", | |
"def update_map(method, k):\n", | |
" fig, _ = vba_choropleth('TOT_POP',\n", | |
" 'POP_16',\n", | |
" #np.array([0.7]*len(data)),\n", | |
" data, \n", | |
" rgb_mapclassify = dict(classifier=method, k=k))\n", | |
" plt.show()\n", | |
"\n", | |
"data_type = RadioButtons(options=['sequential', 'diverging', 'qualitative'])\n", | |
"\n", | |
"bindings = {'sequential': range(3,9+1),\n", | |
" 'diverging': range(3,11+1),\n", | |
" 'qualitative': range(3,12+1)}\n", | |
"\n", | |
"class_val = Dropdown(options=bindings[data_type.value]) \n", | |
"\n", | |
"def type_change(change):\n", | |
" class_val.options = bindings[change['new']]\n", | |
"\n", | |
"data_type.observe(type_change, names=['value'])\n", | |
"\n", | |
"\n", | |
"from ipywidgets import Output, Tab\n", | |
"out = Output()\n", | |
"t = Tab()\n", | |
"t.children = [out]\n", | |
"#t\n", | |
"\n", | |
"# In this case, the interact function must be defined after the conditions stated above... therefore, the k now depends on the radio button \n", | |
"\n", | |
"with out:\n", | |
" interact(update_map, method=list(_classifiers.keys()), k = class_val)\n", | |
"\n", | |
"display(VBox([data_type, out]))\n", | |
"\n" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"## Adding color maps" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 58, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"application/vnd.jupyter.widget-view+json": { | |
"model_id": "a11d10f9e4e54ba29e43046fc702f6ca", | |
"version_major": 2, | |
"version_minor": 0 | |
}, | |
"text/plain": [ | |
"VBox(children=(RadioButtons(options=('Sequential', 'Diverging', 'Qualitative'), value='Sequential'), HBox(chil…" | |
] | |
}, | |
"metadata": {}, | |
"output_type": "display_data" | |
}, | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"cmap_changed BrBG Diverging\n", | |
"cmap_changed Spectral Diverging\n", | |
"cmap_changed Accent Qualitative\n", | |
"cmap_changed Blues Sequential\n", | |
"cmap_changed BrBG Diverging\n" | |
] | |
} | |
], | |
"source": [ | |
"from mapclassify import color\n", | |
"import mapclassify\n", | |
"from ipywidgets import interact, Dropdown, RadioButtons, IntSlider, VBox, HBox, FloatSlider, Button, Label\n", | |
"\n", | |
"def k_values(ctype, cmap):\n", | |
" k = list(mapclassify.color.colorbrewer.COLOR_MAPS[ctype][cmap].keys())\n", | |
" return list(map(int, k))\n", | |
" \n", | |
"def update_map(method, k):\n", | |
" fig, _ = vba_choropleth('TOT_POP',\n", | |
" 'POP_16',\n", | |
" #np.array([0.7]*len(data)),\n", | |
" data, \n", | |
" rgb_mapclassify = dict(classifier=method, k=k))\n", | |
" plt.show()\n", | |
"\n", | |
"data_type = RadioButtons(options=['Sequential', 'Diverging', 'Qualitative'])\n", | |
"\n", | |
"bindings = {'Sequential': range(3,9+1),\n", | |
" 'Diverging': range(3,11+1),\n", | |
" 'Qualitative': range(3,12+1)}\n", | |
"\n", | |
"cmap_bindings = {'Sequential': list(color.sequential.keys()),\n", | |
" 'Diverging': list(color.diverging.keys()),\n", | |
" 'Qualitative': list(color.qualitative.keys())}\n", | |
"\n", | |
"class_val = Dropdown(options=bindings[data_type.value]) \n", | |
"cmap_val = Dropdown(options=cmap_bindings[data_type.value])\n", | |
"\n", | |
"def type_change(change):\n", | |
" class_val.options = bindings[change['new']]\n", | |
" cmap_val.options = cmap_bindings[change['new']]\n", | |
"\n", | |
"def cmap_change(change):\n", | |
" cmap=change['new']\n", | |
" ctype = data_type.value\n", | |
" k = k_values(ctype, cmap)\n", | |
" class_val.options = k\n", | |
" \n", | |
" #class_val.options = bindings[change['new']]\n", | |
" #f = 'yup'\n", | |
" print('cmap_changed', change['new'], ctype)\n", | |
"\n", | |
"data_type.observe(type_change, names=['value'])\n", | |
"cmap_val.observe(cmap_change, names=['value'])\n", | |
"\n", | |
"\n", | |
"from ipywidgets import Output, Tab\n", | |
"out = Output()\n", | |
"t = Tab()\n", | |
"t.children = [out]\n", | |
"#t\n", | |
"\n", | |
"# In this case, the interact function must be defined after the conditions stated above... therefore, the k now depends on the radio button \n", | |
"\n", | |
"with out:\n", | |
" interact(update_map, method=list(_classifiers.keys()), k = class_val)\n", | |
"\n", | |
"display(VBox([data_type,HBox([Label('cmap'),cmap_val]), out]))\n", | |
"\n" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"## Next steps\n", | |
"\n", | |
"- replace map with univariate choropleth\n", | |
"- filter methods so fixed k classifers are not included (boxplot)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": {}, | |
"outputs": [], | |
"source": [] | |
} | |
], | |
"metadata": { | |
"kernelspec": { | |
"display_name": "Python 3", | |
"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.7.3" | |
} | |
}, | |
"nbformat": 4, | |
"nbformat_minor": 2 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment