# http://pyrocko.org - GPLv3 # # The Pyrocko Developers, 21st Century # ---|P------/S----------~Lg----------
Unicode, Dict)
return (c[0]*f, c[1]*f, c[2]*f)
ll_lat, ll_lon = od.ne_to_latlon(lat, lon, -0.5*h, -0.5*w) ur_lat, ur_lon = od.ne_to_latlon(lat, lon, 0.5*h, 0.5*w) return ll_lon, ll_lat, ur_lon, ur_lat
x = num.linspace(-0.5*w, 0.5*w, n) y = num.linspace(-0.5*h, 0.5*h, n) slats, slons = od.ne_to_latlon(lat, lon, y[0], x) nlats, nlons = od.ne_to_latlon(lat, lon, y[-1], x) south = slats.min() north = nlats.max()
wlats, wlons = od.ne_to_latlon(lat, lon, y, x[0]) elats, elons = od.ne_to_latlon(lat, lon, y, x[-1]) elons = num.where(elons < wlons, elons + 360., elons)
if elons.max() - elons.min() > 180 or wlons.max() - wlons.min() > 180.: west = -180. east = 180. else: west = wlons.min() east = elons.max()
return topo.positive_region((west, east, south, north))
Object.__init__(self, init_props=False) self.xmin = float(xmin) self.ymin = float(ymin) self.dx = float(dx) self.dy = float(dy) self.data = data self._set_maxes()
self.ny, self.nx = self.data.shape self.xmax = self.xmin + (self.nx-1) * self.dx self.ymax = self.ymin + (self.ny-1) * self.dy
return self.xmin + num.arange(self.nx) * self.dx
return self.ymin + num.arange(self.ny) * self.dy
ix = int(round((x - self.xmin) / self.dx)) iy = int(round((y - self.ymin) / self.dy)) if 0 <= ix < self.nx and 0 <= iy < self.ny: return self.data[iy, ix] else: raise OutOfBounds()
name = newstr(name) lat = float(lat) lon = float(lon) if asciiname is None: asciiname = name.encode('ascii', errors='replace')
if population is None: population = 0 else: population = int(population)
Object.__init__(self, name=name, lat=lat, lon=lon, population=population, asciiname=asciiname)
default=40., help='minimum resolution of topography [dpi]') default=200., help='maximum resolution of topography [dpi]') optional=True, help='replace topo color while keeping topographic shading')
Object.__init__(self, **kwargs) self._gmt = None self._scaler = None self._widget = None self._corners = None self._wesn = None self._minarea = None self._coastline_resolution = None self._rivers = None self._dems = None self._have_topo_land = None self._have_topo_ocean = None self._jxyr = None self._prep_topo_have = None self._labels = [] self._area_labels = [] self._gmtversion = gmtversion
width=None, height=None, psconvert=False):
''' Save the image.
Save the image to ``outpath``. The format is determined by the filename extension. Formats are handled as follows: ``'.eps'`` and ``'.ps'`` produce EPS and PS, respectively, directly with GMT. If the file name ends with ``'.pdf'``, GMT output is fed through ``gmtpy-epstopdf`` to create a PDF file. For any other filename extension, output is first converted to PDF with ``gmtpy-epstopdf``, then with ``pdftocairo`` to PNG with a resolution oversampled by the factor ``oversample`` and finally the PNG is downsampled and converted to the target format with ``convert``. The resolution of rasterized target image can be controlled either by ``resolution`` in DPI or by specifying ``width`` or ``height`` or ``size``, where the latter fits the image into a square with given side length. To save transparency use ``psconvert=True``. '''
gmt = self.gmt self.draw_labels() self.draw_axes() if self.show_topo and self.show_topo_scale: self._draw_topo_scale()
gmt.save(outpath, resolution=resolution, oversample=oversample, size=size, width=width, height=height, psconvert=psconvert)
def scaler(self): if self._scaler is None: self._setup_geometry()
return self._scaler
def wesn(self): if self._wesn is None: self._setup_geometry()
return self._wesn
def widget(self): if self._widget is None: self._setup()
return self._widget
def layout(self): if self._layout is None: self._setup()
return self._layout
def jxyr(self): if self._jxyr is None: self._setup()
return self._jxyr
def pxyr(self): if self._pxyr is None: self._setup()
return self._pxyr
def gmt(self): if self._gmt is None: self._setup()
if self._have_topo_ocean is None: self._draw_background()
return self._gmt
if not self._widget: self._setup_geometry()
self._setup_lod() self._setup_gmt()
wpage, hpage = self.width, self.height ml, mr, mt, mb = self._expand_margins() wpage -= ml + mr hpage -= mt + mb
wreg = self.radius * 2.0 hreg = self.radius * 2.0 if wpage >= hpage: wreg *= wpage/hpage else: hreg *= hpage/wpage
self._wreg = wreg self._hreg = hreg
self._corners = corners(self.lon, self.lat, wreg, hreg) west, east, south, north = extent(self.lon, self.lat, wreg, hreg, 10)
x, y, z = ((west, east), (south, north), (-6000., 4500.))
xax = gmtpy.Ax(mode='min-max', approx_ticks=4.) yax = gmtpy.Ax(mode='min-max', approx_ticks=4.) zax = gmtpy.Ax(mode='min-max', inc=1000., label='Height', scaled_unit='km', scaled_unit_factor=0.001)
scaler = gmtpy.ScaleGuru(data_tuples=[(x, y, z)], axes=(xax, yax, zax))
par = scaler.get_params()
west = par['xmin'] east = par['xmax'] south = par['ymin'] north = par['ymax']
self._wesn = west, east, south, north self._scaler = scaler
w, e, s, n = self._wesn if self.radius > 1500.*km: coastline_resolution = 'i' rivers = False else: coastline_resolution = 'f' rivers = True
self._minarea = (self.skip_feature_factor * self.radius/km)**2
self._coastline_resolution = coastline_resolution self._rivers = rivers
self._prep_topo_have = {} self._dems = {}
cm2inch = gmtpy.cm/gmtpy.inch
dmin = 2.0 * self.radius * m2d / (self.topo_resolution_max * (self.height * cm2inch)) dmax = 2.0 * self.radius * m2d / (self.topo_resolution_min * (self.height * cm2inch))
for k in ['ocean', 'land']: self._dems[k] = topo.select_dem_names(k, dmin, dmax, self._wesn) if self._dems[k]: logger.debug('using topography dataset %s for %s' % (','.join(self._dems[k]), k))
if len(self.margins) == 0 or len(self.margins) > 4: ml = mr = mt = mb = 2.0 elif len(self.margins) == 1: ml = mr = mt = mb = self.margins[0] elif len(self.margins) == 2: ml = mr = self.margins[0] mt = mb = self.margins[1] elif len(self.margins) == 4: ml, mr, mt, mb = self.margins
return ml, mr, mt, mb
w, h = self.width, self.height scaler = self._scaler
if gmtpy.is_gmt5(self._gmtversion): gmtconf = dict( MAP_TICK_PEN_PRIMARY='1.25p', MAP_TICK_PEN_SECONDARY='1.25p', MAP_TICK_LENGTH_PRIMARY='0.2c', MAP_TICK_LENGTH_SECONDARY='0.6c', FONT_ANNOT_PRIMARY='12p,1,black', FONT_LABEL='12p,1,black', PS_CHAR_ENCODING='ISOLatin1+', MAP_FRAME_TYPE='fancy', FORMAT_GEO_MAP='D', PS_MEDIA='Custom_%ix%i' % ( w*gmtpy.cm, h*gmtpy.cm), PS_PAGE_ORIENTATION='portrait', MAP_GRID_PEN_PRIMARY='thinnest,0/50/0', MAP_ANNOT_OBLIQUE='6') else: gmtconf = dict( TICK_PEN='1.25p', TICK_LENGTH='0.2c', ANNOT_FONT_PRIMARY='1', ANNOT_FONT_SIZE_PRIMARY='12p', LABEL_FONT='1', LABEL_FONT_SIZE='12p', CHAR_ENCODING='ISOLatin1+', BASEMAP_TYPE='fancy', PLOT_DEGREE_FORMAT='D', PAPER_MEDIA='Custom_%ix%i' % ( w*gmtpy.cm, h*gmtpy.cm), GRID_PEN_PRIMARY='thinnest/0/50/0', DOTS_PR_INCH='1200', OBLIQUE_ANNOTATION='6')
gmtconf.update( (k.upper(), v) for (k, v) in self.gmt_config.items())
gmt = gmtpy.GMT(config=gmtconf, version=self._gmtversion)
layout = gmt.default_layout()
layout.set_fixed_margins(*[x*cm for x in self._expand_margins()])
widget = layout.get_widget() widget['P'] = widget['J'] widget['J'] = ('-JA%g/%g' % (self.lon, self.lat)) + '/%(width)gp' scaler['R'] = '-R%g/%g/%g/%gr' % self._corners
# aspect = gmtpy.aspect_for_projection( # gmt.installation['version'], *(widget.J() + scaler.R()))
aspect = self._map_aspect(jr=widget.J() + scaler.R()) widget.set_aspect(aspect)
self._gmt = gmt self._layout = layout self._widget = widget self._jxyr = self._widget.JXY() + self._scaler.R() self._pxyr = self._widget.PXY() + [ '-R%g/%g/%g/%g' % (0, widget.width(), 0, widget.height())] self._have_drawn_axes = False self._have_drawn_labels = False
self._have_topo_land = False self._have_topo_ocean = False if self.show_topo: self._have_topo = self._draw_topo()
self._draw_basefeatures()
t = None demname = None for dem in self._dems[k]: t = topo.get(dem, self._wesn) demname = dem if t is not None: break
if not t: raise NoTopo()
return t, demname
gmt = self._gmt t, demname = self._get_topo_tile(k)
if demname not in self._prep_topo_have:
grdfile = gmt.tempfilename()
is_flat = num.all(t.data[0] == t.data)
gmtpy.savegrd( t.x(), t.y(), t.data, filename=grdfile, naming='lonlat')
if self.illuminate and not is_flat: if k == 'ocean': factor = self.illuminate_factor_ocean else: factor = self.illuminate_factor_land
ilumfn = gmt.tempfilename() gmt.grdgradient( grdfile, N='e%g' % factor, A=-45, G=ilumfn, out_discard=True)
ilumargs = ['-I%s' % ilumfn] else: ilumargs = []
if self.replace_topo_color_only: t2 = self.replace_topo_color_only grdfile2 = gmt.tempfilename()
gmtpy.savegrd( t2.x(), t2.y(), t2.data, filename=grdfile2, naming='lonlat')
if gmt.is_gmt5(): gmt.grdsample( grdfile2, G=grdfile, n='l', I='%g/%g' % (t.dx, t.dy), # noqa R=grdfile, out_discard=True) else: gmt.grdsample( grdfile2, G=grdfile, Q='l', I='%g/%g' % (t.dx, t.dy), # noqa R=grdfile, out_discard=True)
gmt.grdmath( grdfile, '0.0', 'AND', '=', grdfile2, out_discard=True)
grdfile = grdfile2
self._prep_topo_have[demname] = grdfile, ilumargs
return self._prep_topo_have[demname]
widget = self._widget scaler = self._scaler gmt = self._gmt cres = self._coastline_resolution minarea = self._minarea
JXY = widget.JXY() R = scaler.R()
try: grdfile, ilumargs = self._prep_topo('ocean') gmt.pscoast(D=cres, S='c', A=minarea, *(JXY+R)) gmt.grdimage(grdfile, C=topo.cpt(self.topo_cpt_wet), *(ilumargs+JXY+R)) gmt.pscoast(Q=True, *(JXY+R)) self._have_topo_ocean = True except NoTopo: self._have_topo_ocean = False
try: grdfile, ilumargs = self._prep_topo('land') gmt.pscoast(D=cres, G='c', A=minarea, *(JXY+R)) gmt.grdimage(grdfile, C=topo.cpt(self.topo_cpt_dry), *(ilumargs+JXY+R)) gmt.pscoast(Q=True, *(JXY+R)) self._have_topo_land = True except NoTopo: self._have_topo_land = False
dry = read_cpt(topo.cpt(self.topo_cpt_dry)) wet = read_cpt(topo.cpt(self.topo_cpt_wet)) combi = cpt_merge_wet_dry(wet, dry) for level in combi.levels: level.vmin /= km level.vmax /= km
topo_cpt = self.gmt.tempfilename() + '.cpt' write_cpt(combi, topo_cpt)
(w, h), (xo, yo) = self.widget.get_size() self.gmt.psscale( D='%gp/%gp/%gp/%gph' % (xo + 0.5*w, yo - 2.0*gmtpy.cm, w, 0.5*gmtpy.cm), C=topo_cpt, B='1:%s:' % label)
gmt = self._gmt cres = self._coastline_resolution rivers = self._rivers minarea = self._minarea
color_wet = self.color_wet color_dry = self.color_dry
if self.show_rivers and rivers: rivers = ['-Ir/0.25p,%s' % gmtpy.color(self.color_wet)] else: rivers = []
fill = {} if not self._have_topo_land: fill['G'] = color_dry
if not self._have_topo_ocean: fill['S'] = color_wet
if self.show_boundaries: fill['N'] = '1/1p,%s,%s' % ( gmtpy.color(self.color_boundaries), 'solid')
gmt.pscoast( D=cres, W='thinnest,%s' % gmtpy.color(darken(gmtpy.color_tup(color_dry))), A=minarea, *(rivers+self._jxyr), **fill)
if self.show_plates: self.draw_plates()
gmt = self._gmt scaler = self._scaler widget = self._widget
if self.axes_layout is None: if self.lat > 0.0: axes_layout = 'WSen' else: axes_layout = 'WseN' else: axes_layout = self.axes_layout
scale_km = gmtpy.nice_value(self.radius/5.) / 1000.
if self.show_center_mark: gmt.psxy( in_rows=[[self.lon, self.lat]], S='c20p', W='2p,black', *self._jxyr)
if self.show_grid: btmpl = ('%(xinc)gg%(xinc)g:%(xlabel)s:/' '%(yinc)gg%(yinc)g:%(ylabel)s:') else: btmpl = '%(xinc)g:%(xlabel)s:/%(yinc)g:%(ylabel)s:'
if self.show_scale: scale = 'x%gp/%gp/%g/%g/%gk' % ( 6./7*widget.width(), widget.height()/7., self.lon, self.lat, scale_km) else: scale = False
gmt.psbasemap( B=(btmpl % scaler.get_params())+axes_layout, L=scale, *self._jxyr)
if self.comment: font_size = self.gmt.label_font_size()
_, east, south, _ = self._wesn if gmt.is_gmt5(): row = [ 1, 0, '%gp,%s,%s' % (font_size, 0, 'black'), 'BR', self.comment]
farg = ['-F+f+j'] else: row = [1, 0, font_size, 0, 0, 'BR', self.comment] farg = []
gmt.pstext( in_rows=[row], N=True, R=(0, 1, 0, 1), D='%gp/%gp' % (-font_size*0.2, font_size*0.3), *(widget.PXY() + farg))
if not self._have_drawn_axes: self._draw_axes() self._have_drawn_axes = True
gmt = self._gmt cres = self._coastline_resolution minarea = self._minarea
checkfile = gmt.tempfilename()
gmt.pscoast( M=True, D=cres, W='thinnest,black', A=minarea, out_filename=checkfile, *self._jxyr)
points = [] with open(checkfile, 'r') as f: for line in f: ls = line.strip() if ls.startswith('#') or ls.startswith('>') or ls == '': continue plon, plat = [float(x) for x in ls.split()] points.append((plat, plon))
points = num.array(points, dtype=num.float) return num.any(points_in_region(points, self._wesn))
self.gmt return self._have_coastlines()
onepoint = False if isinstance(lats, float) and isinstance(lons, float): lats = [lats] lons = [lons] onepoint = True
if jr is not None: j, r = jr gmt = gmtpy.GMT(version=self._gmtversion) else: j, _, _, r = self.jxyr gmt = self.gmt
f = BytesIO() gmt.mapproject(j, r, in_columns=(lons, lats), out_stream=f, D='p') f.seek(0) data = num.loadtxt(f, ndmin=2) xs, ys = data.T if onepoint: xs = xs[0] ys = ys[0] return xs, ys
ll_lon, ll_lat, ur_lon, ur_lat = self._corners
xs_corner, ys_corner = self.project( (ll_lat, ur_lat), (ll_lon, ur_lon), jr=jr)
w = xs_corner[1] - xs_corner[0] h = ys_corner[1] - ys_corner[0]
return w, h
w, h = self._map_box(jr=jr) return h/w
points_taken = [] regions_taken = []
def no_points_in_rect(xs, ys, xmin, ymin, xmax, ymax): xx = not num.any(la(la(xmin < xs, xs < xmax), la(ymin < ys, ys < ymax))) return xx
def roverlaps(a, b): return (a[0] < b[2] and b[0] < a[2] and a[1] < b[3] and b[1] < a[3])
w, h = self._map_box()
label_font_size = self.gmt.label_font_size()
if self._labels:
n = len(self._labels)
lons, lats, texts, sx, sy, colors, fonts, font_sizes, \ angles, styles = list(zip(*self._labels))
font_sizes = [ (font_size or label_font_size) for font_size in font_sizes]
sx = num.array(sx, dtype=num.float) sy = num.array(sy, dtype=num.float)
xs, ys = self.project(lats, lons)
points_taken.append((xs, ys))
dxs = num.zeros(n) dys = num.zeros(n)
for i in range(n): dx, dy = gmtpy.text_box( texts[i], font=fonts[i], font_size=font_sizes[i], **styles[i])
dxs[i] = dx dys[i] = dy
la = num.logical_and anchors_ok = ( la(xs + sx + dxs < w, ys + sy + dys < h), la(xs - sx - dxs > 0., ys - sy - dys > 0.), la(xs + sx + dxs < w, ys - sy - dys > 0.), la(xs - sx - dxs > 0., ys + sy + dys < h), )
arects = [ (xs, ys, xs + sx + dxs, ys + sy + dys), (xs - sx - dxs, ys - sy - dys, xs, ys), (xs, ys - sy - dys, xs + sx + dxs, ys), (xs - sx - dxs, ys, xs, ys + sy + dys)]
for i in range(n): for ianch in range(4): anchors_ok[ianch][i] &= no_points_in_rect( xs, ys, *[xxx[i] for xxx in arects[ianch]])
anchor_choices = [] anchor_take = [] for i in range(n): choices = [ianch for ianch in range(4) if anchors_ok[ianch][i]] anchor_choices.append(choices) if choices: anchor_take.append(choices[0]) else: anchor_take.append(None)
def cost(anchor_take): noverlaps = 0 for i in range(n): for j in range(n): if i != j: i_take = anchor_take[i] j_take = anchor_take[j] if i_take is None or j_take is None: continue r_i = [xxx[i] for xxx in arects[i_take]] r_j = [xxx[j] for xxx in arects[j_take]] if roverlaps(r_i, r_j): noverlaps += 1
return noverlaps
cur_cost = cost(anchor_take) imax = 30 while cur_cost != 0 and imax > 0: for i in range(n): for t in anchor_choices[i]: anchor_take_new = list(anchor_take) anchor_take_new[i] = t new_cost = cost(anchor_take_new) if new_cost < cur_cost: anchor_take = anchor_take_new cur_cost = new_cost
imax -= 1
while cur_cost != 0: for i in range(n): anchor_take_new = list(anchor_take) anchor_take_new[i] = None new_cost = cost(anchor_take_new) if new_cost < cur_cost: anchor_take = anchor_take_new cur_cost = new_cost break
anchor_strs = ['BL', 'TR', 'TL', 'BR']
for i in range(n): ianchor = anchor_take[i] color = colors[i] if color is None: color = 'black'
if ianchor is not None: regions_taken.append([xxx[i] for xxx in arects[ianchor]])
anchor = anchor_strs[ianchor]
yoff = [-sy[i], sy[i]][anchor[0] == 'B'] xoff = [-sx[i], sx[i]][anchor[1] == 'L'] if self.gmt.is_gmt5(): row = ( lons[i], lats[i], '%i,%s,%s' % (font_sizes[i], fonts[i], color), anchor, texts[i])
farg = ['-F+f+j+a%g' % angles[i]] else: row = ( lons[i], lats[i], font_sizes[i], angles[i], fonts[i], anchor, texts[i]) farg = ['-G%s' % color]
self.gmt.pstext( in_rows=[row], D='%gp/%gp' % (xoff, yoff), *(self.jxyr + farg), **styles[i])
if self._area_labels:
for lons, lats, text, color, font, font_size, style in \ self._area_labels:
if font_size is None: font_size = label_font_size
if color is None: color = 'black'
if self.gmt.is_gmt5(): farg = ['-F+f+j'] else: farg = ['-G%s' % color]
xs, ys = self.project(lats, lons) dx, dy = gmtpy.text_box( text, font=font, font_size=font_size, **style)
rects = [xs-0.5*dx, ys-0.5*dy, xs+0.5*dx, ys+0.5*dy]
locs_ok = num.ones(xs.size, dtype=num.bool)
for iloc in range(xs.size): rcandi = [xxx[iloc] for xxx in rects]
locs_ok[iloc] = True locs_ok[iloc] &= ( 0 < rcandi[0] and rcandi[2] < w and 0 < rcandi[1] and rcandi[3] < h)
overlap = False for r in regions_taken: if roverlaps(r, rcandi): overlap = True break
locs_ok[iloc] &= not overlap
for xs_taken, ys_taken in points_taken: locs_ok[iloc] &= no_points_in_rect( xs_taken, ys_taken, *rcandi)
if not locs_ok[iloc]: break
rows = [] for iloc, (lon, lat) in enumerate(zip(lons, lats)): if not locs_ok[iloc]: continue
if self.gmt.is_gmt5(): row = ( lon, lat, '%i,%s,%s' % (font_size, font, color), 'MC', text)
else: row = ( lon, lat, font_size, 0, font, 'MC', text)
rows.append(row)
regions_taken.append([xxx[iloc] for xxx in rects]) break
self.gmt.pstext( in_rows=rows, *(self.jxyr + farg), **style)
self.gmt if not self._have_drawn_labels: self._draw_labels() self._have_drawn_labels = True
self, lat, lon, text, offset_x=5., offset_y=5., color=None, font='1', font_size=None, angle=0, style={}):
if 'G' in style: style = style.copy() color = style.pop('G')
self._labels.append( (lon, lat, text, offset_x, offset_y, color, font, font_size, angle, style))
self, lat, lon, text, color=None, font='3', font_size=None, style={}):
self._area_labels.append( (lon, lat, text, color, font, font_size, style))
from pyrocko.dataset import geonames cities = geonames.get_cities_region(region=self.wesn, minpop=0) cities.extend(self.custom_cities) cities.sort(key=lambda x: x.population) return cities
exact=None, include=[], exclude=[], nmax_soft=10, psxy_style=dict(S='s5p', G='black')):
cities = self.cities_in_region()
if exact is not None: cities = [c for c in cities if c.name in exact] minpop = None else: cities = [c for c in cities if c.name not in exclude] minpop = 10**3 for minpop_new in [1e3, 3e3, 1e4, 3e4, 1e5, 3e5, 1e6, 3e6, 1e7]: cities_new = [ c for c in cities if c.population > minpop_new or c.name in include]
if len(cities_new) == 0 or ( len(cities_new) < 3 and len(cities) < nmax_soft*2): break
cities = cities_new minpop = minpop_new if len(cities) <= nmax_soft: break
if cities: lats = [c.lat for c in cities] lons = [c.lon for c in cities]
self.gmt.psxy( in_columns=(lons, lats), *self.jxyr, **psxy_style)
for c in cities: try: text = c.name.encode('iso-8859-1').decode('iso-8859-1') except UnicodeEncodeError: text = c.asciiname
self.add_label(c.lat, c.lon, text)
self._cities_minpop = minpop
default_psxy_style = { 'S': 't8p', 'G': 'black' } default_psxy_style.update(psxy_style)
lats, lons = zip(*[s.effective_latlon for s in stations])
self.gmt.psxy( in_columns=(lons, lats), *self.jxyr, **default_psxy_style)
for station in stations: self.add_label( station.effective_lat, station.effective_lon, '.'.join(x for x in (station.network, station.station) if x))
tile = FloatTile( scene.frame.llLon, scene.frame.llLat, scene.frame.dLon, scene.frame.dLat, scene.displacement)
return tile
labels=True, vertical=False, fontsize=10):
stations = campaign.stations
if offset_scale is None: offset_scale = num.zeros(campaign.nstations) for ista, sta in enumerate(stations): for comp in sta.components.values(): offset_scale[ista] += comp.shift offset_scale = num.sqrt(offset_scale**2).max()
size = math.sqrt(self.height**2 + self.width**2) scale = (size/10.) / offset_scale logger.debug('GNSS: Using offset scale %f, map scale %f', offset_scale, scale)
lats, lons = zip(*[s.effective_latlon for s in stations])
if vertical: rows = [[lons[ista], lats[ista], 0., s.up.shift, (s.east.sigma + s.north.sigma) if s.east.sigma else 0., s.up.sigma, 0., s.code if labels else None] for ista, s in enumerate(stations) if s.up is not None]
else: rows = [[lons[ista], lats[ista], s.east.shift, s.north.shift, s.east.sigma, s.north.sigma, s.correlation_ne, s.code if labels else None] for ista, s in enumerate(stations) if s.east is not None or s.north is not None]
default_psxy_style = { 'h': 0, 'W': '2p,black', 'A': '+p2p,black+e+a40', 'G': 'black', 'L': True, 'S': 'e%dc/0.95/%d' % (scale, fontsize), }
if not labels: for row in rows: row.pop(-1)
if psxy_style is not None: default_psxy_style.update(psxy_style)
self.gmt.psvelo( in_rows=rows, *self.jxyr, **default_psxy_style)
from pyrocko.dataset import tectonics
neast = 20 nnorth = max(1, int(round(num.round(self._hreg/self._wreg * neast)))) norths = num.linspace(-self._hreg*0.5, self._hreg*0.5, nnorth) easts = num.linspace(-self._wreg*0.5, self._wreg*0.5, neast) norths2 = num.repeat(norths, neast) easts2 = num.tile(easts, nnorth) lats, lons = od.ne_to_latlon( self.lat, self.lon, norths2, easts2)
bird = tectonics.PeterBird2003() plates = bird.get_plates()
color_plates = gmtpy.color('aluminium5') color_velocities = gmtpy.color('skyblue1') color_velocities_lab = gmtpy.color(darken(gmtpy.color_tup('skyblue1')))
points = num.vstack((lats, lons)).T used = [] for plate in plates: mask = plate.contains_points(points) if num.any(mask): used.append((plate, mask))
if len(used) > 1:
candi_fixed = {}
label_data = [] for plate, mask in used:
mean_north = num.mean(norths2[mask]) mean_east = num.mean(easts2[mask]) iorder = num.argsort(num.sqrt( (norths2[mask] - mean_north)**2 + (easts2[mask] - mean_east)**2))
lat_candis = lats[mask][iorder] lon_candis = lons[mask][iorder]
candi_fixed[plate.name] = lat_candis.size
label_data.append(( lat_candis, lon_candis, plate, color_plates))
boundaries = bird.get_boundaries()
size = 2
psxy_kwargs = []
for boundary in boundaries: if num.any(points_in_region(boundary.points, self._wesn)): for typ, part in boundary.split_types( [['SUB'], ['OSR', 'OTF', 'OCB', 'CTF', 'CCB', 'CRB']]):
lats, lons = part.T
kwargs = {} if typ[0] == 'SUB': if boundary.kind == '\\': kwargs['S'] = 'f%g/%gp+t+r' % ( 0.45*size, 3.*size) elif boundary.kind == '/': kwargs['S'] = 'f%g/%gp+t+l' % ( 0.45*size, 3.*size)
kwargs['G'] = color_plates
kwargs['in_columns'] = (lons, lats) kwargs['W'] = '%gp,%s' % (size, color_plates),
psxy_kwargs.append(kwargs)
if boundary.kind == '\\': if boundary.name2 in candi_fixed: candi_fixed[boundary.name2] += neast*nnorth
elif boundary.kind == '/': if boundary.name1 in candi_fixed: candi_fixed[boundary.name1] += neast*nnorth
candi_fixed = [name for name in sorted( list(candi_fixed.keys()), key=lambda name: -candi_fixed[name])]
candi_fixed.append(None)
gsrm = tectonics.GSRM1()
for name in candi_fixed: if name not in gsrm.plate_names() \ and name not in gsrm.plate_alt_names():
continue
lats, lons, vnorth, veast, vnorth_err, veast_err, corr = \ gsrm.get_velocities(name, region=self._wesn)
fixed_plate_name = name
self.gmt.psvelo( in_columns=( lons, lats, veast, vnorth, veast_err, vnorth_err, corr), W='0.25p,%s' % color_velocities, A='9p+e+g%s' % color_velocities, S='e0.2p/0.95/10', *self.jxyr)
for _ in range(len(lons) // 50 + 1): ii = random.randint(0, len(lons)-1) v = math.sqrt(vnorth[ii]**2 + veast[ii]**2) self.add_label( lats[ii], lons[ii], '%.0f' % v, font_size=0.7*self.gmt.label_font_size(), style=dict( G=color_velocities_lab))
break
for (lat_candis, lon_candis, plate, color) in label_data: full_name = bird.full_name(plate.name) if plate.name == fixed_plate_name: full_name = '@_' + full_name + '@_'
self.add_area_label( lat_candis, lon_candis, full_name, color=color, font='3')
for kwargs in psxy_kwargs: self.gmt.psxy(*self.jxyr, **kwargs)
mi = float(mi) ma = float(ma) return random.random() * (ma-mi) + mi
west, east, south, north = topo.positive_region(region) if east > 180: return [(west, 180., south, north), (-180., east-360., south, north)] else: return [region]
vmin_old, vmax_old = self.levels[0].vmin, self.levels[-1].vmax for level in self.levels: level.vmin = (level.vmin - vmin_old) / (vmax_old - vmin_old) * \ (vmax - vmin) + vmin level.vmax = (level.vmax - vmin_old) / (vmax_old - vmin_old) * \ (vmax - vmin) + vmin
colors = [] vals = [] for level in self.levels: vals.append(level.vmin) vals.append(level.vmax) colors.append(level.color_min) colors.append(level.color_max)
r, g, b = num.array(colors, dtype=num.float).T vals = num.array(vals, dtype=num.float)
vmin, vmax = self.levels[0].vmin, self.levels[-1].vmax x = num.linspace(vmin, vmax, nlevels+1) rd = num.interp(x, vals, r) gd = num.interp(x, vals, g) bd = num.interp(x, vals, b)
levels = [] for ilevel in range(nlevels): color = ( float(0.5*(rd[ilevel]+rd[ilevel+1])), float(0.5*(gd[ilevel]+gd[ilevel+1])), float(0.5*(bd[ilevel]+bd[ilevel+1])))
levels.append(CPTLevel( vmin=x[ilevel], vmax=x[ilevel+1], color_min=color, color_max=color))
cpt = CPT( color_below=self.color_below, color_above=self.color_above, color_nan=self.color_nan, levels=levels)
return cpt
with open(filename) as f: color_below = None color_above = None color_nan = None levels = [] try: for line in f: line = line.strip() toks = line.split()
if line.startswith('#'): continue
elif line.startswith('B'): color_below = tuple(map(float, toks[1:4]))
elif line.startswith('F'): color_above = tuple(map(float, toks[1:4]))
elif line.startswith('N'): color_nan = tuple(map(float, toks[1:4]))
else: values = list(map(float, line.split())) vmin = values[0] color_min = tuple(values[1:4]) vmax = values[4] color_max = tuple(values[5:8]) levels.append(CPTLevel( vmin=vmin, vmax=vmax, color_min=color_min, color_max=color_max))
except Exception: raise CPTParseError()
return CPT( color_below=color_below, color_above=color_above, color_nan=color_nan, levels=levels)
return tuple(max(0, min(255, int(round(x)))) for x in color)
with open(filename, 'w') as f: for level in cpt.levels: f.write( '%e %i %i %i %e %i %i %i\n' % ((level.vmin, ) + color_to_int(level.color_min) + (level.vmax, ) + color_to_int(level.color_max)))
if cpt.color_below: f.write('B %i %i %i\n' % color_to_int(cpt.color_below))
if cpt.color_above: f.write('F %i %i %i\n' % color_to_int(cpt.color_above))
if cpt.color_nan: f.write('N %i %i %i\n' % color_to_int(cpt.color_nan))
levels = [] for level in wet.levels: if level.vmin < 0.: if level.vmax > 0.: level.vmax = 0.
levels.append(level)
for level in dry.levels: if level.vmax > 0.: if level.vmin < 0.: level.vmin = 0.
levels.append(level)
combi = CPT( color_below=wet.color_below, color_above=dry.color_above, color_nan=dry.color_nan, levels=levels)
return combi
if __name__ == '__main__': from pyrocko import util util.setup_logging('pyrocko.automap', 'info')
import sys if len(sys.argv) == 2:
n = int(sys.argv[1])
for i in range(n): m = Map( lat=rand(-60., 60.), lon=rand(-180., 180.), radius=math.exp(rand(math.log(500*km), math.log(3000*km))), width=30., height=30., show_grid=True, show_topo=True, color_dry=(238, 236, 230), topo_cpt_wet='light_sea_uniform', topo_cpt_dry='light_land_uniform', illuminate=True, illuminate_factor_ocean=0.15, show_rivers=False, show_plates=True)
m.draw_cities() print(m) m.save('map_%02i.pdf' % i) |