Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save sjsrey/87f4167e81e7a93d9dbd93cd0bbf2790 to your computer and use it in GitHub Desktop.
Save sjsrey/87f4167e81e7a93d9dbd93cd0bbf2790 to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"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