OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
plot_map.py
Go to the documentation of this file.
1 import matplotlib.pyplot as plt
2 import numpy as np
3 
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
10 
11 
12 
13 
14 
15 
16 def draw_map(*lonlats, scale=0.2, world=False, us=True, eu=False, labels=[], ax=None, gray=False, res='i', **scatter_kws):
17  PLOT_WIDTH = 8
18  PLOT_HEIGHT = 6
19 
20  WORLD_MAP = {'cyl': [-90, 85, -180, 180]}
21  US_MAP = {
22  'cyl' : [24, 49, -126, -65],
23  'lcc' : [23, 48, -121, -64],
24  }
25  EU_MAP = {
26  'cyl' : [34, 65, -12, 40],
27  'lcc' : [30.5, 64, -10, 40],
28  }
29 
30  def mark_inset(ax, ax2, m, m2, MAP, loc1=(1, 2), loc2=(3, 4), **kwargs):
31  """
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
35 
36  Additionally: set connector locations separately for both axes:
37  loc1 & loc2: tuple defining start and end-locations of connector 1 & 2
38  """
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)
42  ax.add_patch(pp)
43  p1 = BboxConnector(ax2.bbox, rect, loc1=loc1[0], loc2=loc1[1], **kwargs)
44  ax2.add_patch(p1)
45  p1.set_clip_on(False)
46  p2 = BboxConnector(ax2.bbox, rect, loc1=loc2[0], loc2=loc2[1], **kwargs)
47  ax2.add_patch(p2)
48  p2.set_clip_on(False)
49  return pp, p1, p2
50 
51 
52  if world:
53  MAP = WORLD_MAP
54  kwargs = {'projection': 'cyl', 'resolution': res}
55  elif us:
56  MAP = US_MAP
57  kwargs = {'projection': 'lcc', 'lat_0':30, 'lon_0':-98, 'resolution': res}#, 'epsg':4269}
58  elif eu:
59  MAP = EU_MAP
60  kwargs = {'projection': 'lcc', 'lat_0':48, 'lon_0':27, 'resolution': res}
61  else:
62  raise Exception('Must plot world, US, or EU')
63 
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()
68 
69  if not world:
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)
72  if not gray:
73  m.drawrivers(linewidth=0.2, color='blue', zorder=9)
74  m.drawcountries(color='k', linewidth=0.5)
75  else:
76  m.drawcountries(color='w')
77  # m.bluemarble()
78  if not gray:
79  if us or eu: m.shadedrelief(scale=0.3 if world else 1)
80  else:
81  # m.arcgisimage(service='ESRI_Imagery_World_2D', xpixels = 2000, verbose= True)
82  m.arcgisimage(service='World_Imagery', xpixels = 2000, verbose= True)
83  else:
84  pass
85  # lats = m.drawparallels(np.linspace(MAP[0], MAP[1], 13))
86  # lons = m.drawmeridians(np.linspace(MAP[2], MAP[3], 13))
87 
88  # lat_lines = chain(*(tup[1][0] for tup in lats.items()))
89  # lon_lines = chain(*(tup[1][0] for tup in lons.items()))
90  # all_lines = chain(lat_lines, lon_lines)
91 
92  # for line in all_lines:
93  # line.set(linestyle='-', alpha=0.0, color='w')
94 
95  if labels:
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',]
98  mod_cr = False
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]
105  mod_cr = True
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)
108 
109  else:
110  for lonlat in lonlats:
111  if len(lonlat):
112  lonlat = np.atleast_2d(lonlat)
113  s = ax.scatter(*m(lonlat[:,0], lonlat[:,1]), zorder=12, **scatter_kws)
114  # plt.colorbar(s, ax=ax)
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)
118 
119  for axis in ['top','bottom','left','right']:
120  ax.spines[axis].set_linewidth(1.5)
121  ax.spines[axis].set_zorder(50)
122  # plt.axis('off')
123 
124  if world:
125  size = 0.35
126  if us:
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})
129 
130  scatter_kws.update({'s': 6})
131  m2 = draw_map(*lonlats, labels=labels, ax=ax_ins, **scatter_kws)
132 
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)
135 
136 
137  if eu:
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})
139 
140  scatter_kws.update({'s': 6})
141  m2 = draw_map(*lonlats, us=False, eu=True, labels=labels, ax=ax_ins, **scatter_kws)
142 
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)
145 
146  return m
147 
148 
149 if __name__ == '__main__':
150  draw_map([-76, 37])
151  plt.show()
def draw_map(*lonlats, scale=0.2, world=False, us=True, eu=False, labels=[], ax=None, gray=False, res='i', **scatter_kws)
Definition: plot_map.py:16