Using matplotlib’s zoomed_inset_axes with geopandas

I could not figure out how to plot a map in the zoomed inset

[2]:
import pandas as pd
import geopandas as gpd
import numpy as np
from shapely.geometry import Point, MultiPoint, Polygon, MultiPolygon
import os
import sys
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1.inset_locator import zoomed_inset_axes
from mpl_toolkits.axes_grid1.inset_locator import mark_inset
from zipfile import ZipFile as zzip
import requests

sys.path.append(os.path.realpath('..'))
[12]:
url = r"https://www2.census.gov/geo/tiger/GENZ2016/shp/cb_2016_us_state_5m.zip"
filename = r"cb_2016_us_state_5m.zip"
r = requests.get(url)
# open method to open a file on your system and write the contents
with open("../input_data/"+filename, "wb") as file:
    file.write(r.content)
[13]:
fp = "../input_data/"
foldername = "us_states"
with zzip(fp+filename, 'r') as file:
        #printing all the contents of the zip file
        #file.printdir()
        path = fp+foldername
        os.mkdir(path)
        # extracting all the files
        print('Extracting all the files now...')
        file.extractall(fp+foldername)
        print('Done!')
Extracting all the files now...
Done!
[3]:
fp = "../input_data/us_states/"
states = gpd.read_file(fp+"cb_2016_us_state_5m.shp")
[4]:
states.columns
[4]:
Index(['STATEFP', 'STATENS', 'AFFGEOID', 'GEOID', 'STUSPS', 'NAME', 'LSAD',
       'ALAND', 'AWATER', 'geometry'],
      dtype='object')
[5]:
states.plot()
[5]:
<matplotlib.axes._subplots.AxesSubplot at 0x1c26eaa3dd8>
_images/zoomed_inset_axes_7_1.png
[6]:
states.crs
[6]:
{'init': 'epsg:4269'}
[7]:
states.head()
[7]:
STATEFP STATENS AFFGEOID GEOID STUSPS NAME LSAD ALAND AWATER geometry
0 01 01779775 0400000US01 01 AL Alabama 00 131173688951 4593686489 (POLYGON ((-88.04374299999999 30.517423, -88.0...
1 02 01785533 0400000US02 02 AK Alaska 00 1477946266785 245390495931 (POLYGON ((-133.655819 55.625617, -133.624921 ...
2 04 01779777 0400000US04 04 AZ Arizona 00 294198560125 1027346486 POLYGON ((-114.799683 32.593621, -114.809393 3...
3 08 01779779 0400000US08 08 CO Colorado 00 268429343790 1175112870 POLYGON ((-109.060253 38.599328, -109.059541 3...
4 09 01779780 0400000US09 09 CT Connecticut 00 12542638347 1815476291 POLYGON ((-73.72777499999999 41.100696, -73.69...
[8]:
statesbounds = states.bounds
[9]:
statesbounds.head()
[9]:
minx miny maxx maxy
0 -88.473227 30.221132 -84.891841 35.008028
1 -179.147340 51.219862 179.778470 71.352561
2 -114.814185 31.332177 -109.045223 37.004260
3 -109.060253 36.992426 -102.041524 41.003444
4 -73.727775 40.985171 -71.786994 42.050587
[10]:
statesbounds = statesbounds.merge(states['STATEFP'],how = 'left',
                      left_on = statesbounds.index,
                      right_on = states.index)
[11]:
statesbounds = statesbounds.set_index('STATEFP')
[12]:
statesbounds.drop('key_0', axis = 1, inplace = True)
[13]:
statesbounds.head()
[13]:
minx miny maxx maxy
STATEFP
01 -88.473227 30.221132 -84.891841 35.008028
02 -179.147340 51.219862 179.778470 71.352561
04 -114.814185 31.332177 -109.045223 37.004260
08 -109.060253 36.992426 -102.041524 41.003444
09 -73.727775 40.985171 -71.786994 42.050587

Could not figure out how to get a plot to appear in the zoomed inset

[16]:
f, ax = plt.subplots(figsize=(15, 20))

# State layer
states.loc[(states['STATEFP'] != "60") &
           (states['STATEFP'] != "66") &
           (states['STATEFP'] != "69") &
           (states['STATEFP'] != "72") &
           (states['STATEFP'] != "78") &
           (states['STATEFP'] != "15") &
           (states['STATEFP'] != "02")
          ].plot(ax=ax, edgecolor='black', color = 'white')

axins = zoomed_inset_axes(ax, 2, loc=1)
axins2 = zoomed_inset_axes(ax, 2, loc=4)

minx,miny,maxx,maxy =  statesbounds.loc['33']
axins.set_xlim(minx, maxx)
axins.set_ylim(miny, maxy)

minx,miny,maxx,maxy =  statesbounds.loc['54']
axins2.set_xlim(minx, maxx)
axins2.set_ylim(miny, maxy)


mark_inset(ax, axins, loc1=2, loc2=4, fc="none", ec="0.5")
mark_inset(ax, axins2, loc1=2, loc2=3, fc="none", ec="0.5")

# Plot zoom window


plt.setp(axins.get_xticklabels(), visible=False)
plt.setp(axins.get_yticklabels(), visible=False)
plt.setp(axins2.get_xticklabels(), visible=False)
plt.setp(axins2.get_yticklabels(), visible=False)

#ax.set_axis_off()
plt.show()
_images/zoomed_inset_axes_17_0.png

Figured this out thanks to ljwolf in https://github.com/geopandas/geopandas/issues/1114

[15]:
f, ax = plt.subplots(figsize=(15, 20))

# State layer
states.loc[(states['STATEFP'] != "60") &
           (states['STATEFP'] != "66") &
           (states['STATEFP'] != "69") &
           (states['STATEFP'] != "72") &
           (states['STATEFP'] != "78") &
           (states['STATEFP'] != "15") &
           (states['STATEFP'] != "02")
          ].plot(ax=ax, edgecolor='black', color = 'white')

axins = zoomed_inset_axes(ax, 2, loc=1)
axins2 = zoomed_inset_axes(ax, 2, loc=4)

minx,miny,maxx,maxy =  statesbounds.loc['33']
axins.set_xlim(minx, maxx)
axins.set_ylim(miny, maxy)

minx,miny,maxx,maxy =  statesbounds.loc['54']
axins2.set_xlim(minx, maxx)
axins2.set_ylim(miny, maxy)


mark_inset(ax, axins, loc1=2, loc2=4, fc="none", ec="0.5")
mark_inset(ax, axins2, loc1=2, loc2=3, fc="none", ec="0.5")

# Plot zoom window
states.loc[(states['STATEFP'] != "33")].plot(ax= axins, edgecolor='black', color='white' )
states.loc[(states['STATEFP'] != "54")].plot(ax= axins2, edgecolor='black', color='white' )

plt.setp(axins.get_xticklabels(), visible=False)
plt.setp(axins.get_yticklabels(), visible=False)
plt.setp(axins2.get_xticklabels(), visible=False)
plt.setp(axins2.get_yticklabels(), visible=False)

#ax.set_axis_off()
plt.show()
_images/zoomed_inset_axes_19_0.png

Also, a better way to get the boundary box without creating a new dataframe and merging in a key id into the new dataframe to use it

[17]:
minx,miny,maxx,maxy =  states.query('STATEFP == "33"').total_bounds
print(minx,miny,maxx,maxy)
-72.55724699999999 42.69699 -70.703799 45.305476
[18]:
# requires more initial steps
statesbounds = states.bounds
statesbounds = statesbounds.merge(states['STATEFP'],how = 'left',
                      left_on = statesbounds.index,
                      right_on = states.index)
statesbounds = statesbounds.set_index('STATEFP')
statesbounds.drop('key_0', axis = 1, inplace = True)
minx,miny,maxx,maxy =  statesbounds.loc['33']
print(minx,miny,maxx,maxy)
-72.55724699999999 42.69699 -70.703799 45.305476