1 import matplotlib.pyplot
as plt
4 from matplotlib.transforms
import Bbox
5 from mpl_toolkits.axes_grid1.inset_locator
import TransformedBbox, BboxPatch, BboxConnector
6 from mpl_toolkits.axes_grid1.inset_locator
import zoomed_inset_axes, inset_axes
7 from mpl_toolkits.basemap
import Basemap
8 from itertools
import chain
9 from pathlib
import Path
16 def draw_map(*lonlats, scale=0.2, world=False, us=True, eu=False, labels=[], ax=None, gray=False, res='i', **scatter_kws):
20 WORLD_MAP = {
'cyl': [-90, 85, -180, 180]}
22 'cyl' : [24, 49, -126, -65],
23 'lcc' : [23, 48, -121, -64],
26 'cyl' : [34, 65, -12, 40],
27 'lcc' : [30.5, 64, -10, 40],
30 def mark_inset(ax, ax2, m, m2, MAP, loc1=(1, 2), loc2=(3, 4), **kwargs):
32 https://stackoverflow.com/questions/41610834/basemap-projection-geos-controlling-mark-inset-location
33 Patched mark_inset to work with Basemap.
34 Reason: Basemap converts Geographic (lon/lat) to Map Projection (x/y) coordinates
36 Additionally: set connector locations separately for both axes:
37 loc1 & loc2: tuple defining start and end-locations of connector 1 & 2
39 axzoom_geoLims = (MAP[
'cyl'][2:], MAP[
'cyl'][:2])
40 rect = TransformedBbox(Bbox(np.array(m(*axzoom_geoLims)).T), ax.transData)
41 pp = BboxPatch(rect, fill=
False, **kwargs)
43 p1 = BboxConnector(ax2.bbox, rect, loc1=loc1[0], loc2=loc1[1], **kwargs)
46 p2 = BboxConnector(ax2.bbox, rect, loc1=loc2[0], loc2=loc2[1], **kwargs)
54 kwargs = {
'projection':
'cyl',
'resolution': res}
57 kwargs = {
'projection':
'lcc',
'lat_0':30,
'lon_0':-98,
'resolution': res}
60 kwargs = {
'projection':
'lcc',
'lat_0':48,
'lon_0':27,
'resolution': res}
62 raise Exception(
'Must plot world, US, or EU')
64 kwargs.update(dict(zip([
'llcrnrlat',
'urcrnrlat',
'llcrnrlon',
'urcrnrlon'], MAP[
'lcc' if 'lcc' in MAP
else 'cyl'])))
65 if ax
is None: f = plt.figure(figsize=(PLOT_WIDTH, PLOT_HEIGHT), edgecolor=
'w')
66 m = Basemap(ax=ax, **kwargs)
67 ax = m.ax
if m.ax
is not None else plt.gca()
70 m.readshapefile(Path(__file__).parent.joinpath(
'map_files',
'st99_d00').as_posix(), name=
'states', drawbounds=
True, color=
'k', linewidth=0.5, zorder=11)
71 m.fillcontinents(color=(0,0,0,0), lake_color=
'#9abee0', zorder=9)
73 m.drawrivers(linewidth=0.2, color=
'blue', zorder=9)
74 m.drawcountries(color=
'k', linewidth=0.5)
76 m.drawcountries(color=
'w')
79 if us
or eu: m.shadedrelief(scale=0.3
if world
else 1)
82 m.arcgisimage(service=
'World_Imagery', xpixels = 2000, verbose=
True)
96 colors = [
'aqua',
'orangered',
'xkcd:tangerine',
'xkcd:fresh green',
'xkcd:clay',
'magenta',
'xkcd:sky blue',
'xkcd:greyish blue',
'xkcd:goldenrod', ]
97 markers = [
'o',
'^',
's',
'*',
'v',
'X',
'.',
'x',]
99 assert(len(labels) == len(lonlats)), [len(labels), len(lonlats)]
100 for i, (label, lonlat)
in enumerate(zip(labels, lonlats)):
101 lonlat = np.atleast_2d(lonlat)
102 if 'color' not in scatter_kws
or mod_cr:
103 scatter_kws[
'color'] = colors[i]
104 scatter_kws[
'marker'] = markers[i]
106 ax.scatter(*m(lonlat[:,0], lonlat[:,1]), label=label, zorder=12, **scatter_kws)
107 ax.legend(loc=
'lower left', prop={
'weight':
'bold',
'size':8}).set_zorder(20)
110 for lonlat
in lonlats:
112 lonlat = np.atleast_2d(lonlat)
113 s = ax.scatter(*m(lonlat[:,0], lonlat[:,1]), zorder=12, **scatter_kws)
115 hide_kwargs = {
'axis':
'both',
'which':
'both'}
116 hide_kwargs.update(dict([(k,
False)
for k
in [
'bottom',
'top',
'left',
'right',
'labelleft',
'labelbottom']]))
117 ax.tick_params(**hide_kwargs)
119 for axis
in [
'top',
'bottom',
'left',
'right']:
120 ax.spines[axis].set_linewidth(1.5)
121 ax.spines[axis].set_zorder(50)
127 loc = (0.25, -0.1)
if eu
else (0.35, -0.01)
128 ax_ins = inset_axes(ax, width=PLOT_WIDTH*size, height=PLOT_HEIGHT*size, loc=
'center', bbox_to_anchor=loc, bbox_transform=ax.transAxes, axes_kwargs={
'zorder': 5})
130 scatter_kws.update({
's': 6})
131 m2 =
draw_map(*lonlats, labels=labels, ax=ax_ins, **scatter_kws)
133 mark_inset(ax, ax_ins, m, m2, US_MAP, loc1=(1,1), loc2=(2,2), edgecolor=
'grey', zorder=3)
134 mark_inset(ax, ax_ins, m, m2, US_MAP, loc1=[3,3], loc2=[4,4], edgecolor=
'grey', zorder=0)
138 ax_ins = inset_axes(ax, width=PLOT_WIDTH*size, height=PLOT_HEIGHT*size, loc=
'center', bbox_to_anchor=(0.75, -0.05), bbox_transform=ax.transAxes, axes_kwargs={
'zorder': 5})
140 scatter_kws.update({
's': 6})
141 m2 =
draw_map(*lonlats, us=
False, eu=
True, labels=labels, ax=ax_ins, **scatter_kws)
143 mark_inset(ax, ax_ins, m, m2, EU_MAP, loc1=(1,1), loc2=(2,2), edgecolor=
'grey', zorder=3)
144 mark_inset(ax, ax_ins, m, m2, EU_MAP, loc1=[3,3], loc2=[4,4], edgecolor=
'grey', zorder=0)
149 if __name__ ==
'__main__':