# http://pyrocko.org - GPLv3 # # The Pyrocko Developers, 21st Century # ---|P------/S----------~Lg----------
Unicode, Dict)
west = -180. east = 180. else:
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')
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``. '''
self._draw_topo_scale()
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): self._setup()
def pxyr(self): if self._pxyr is None: self._setup()
return self._pxyr
def gmt(self):
else: hreg *= hpage/wpage
scaled_unit='km', scaled_unit_factor=0.001)
coastline_resolution = 'i' rivers = False else:
(self.height * cm2inch)) (self.height * cm2inch))
% (','.join(self._dems[k]), k))
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
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')
(k.upper(), v) for (k, v) in self.gmt_config.items())
# aspect = gmtpy.aspect_for_projection( # gmt.installation['version'], *(widget.J() + scaler.R()))
'-R%g/%g/%g/%g' % (0, widget.width(), 0, widget.height())]
raise NoTopo()
t.x(), t.y(), t.data, filename=grdfile, naming='lonlat')
factor = self.illuminate_factor_ocean else:
grdfile, N='e%g' % factor, A=-45, G=ilumfn, out_discard=True)
else: ilumargs = []
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
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
*(ilumargs+JXY+R)) 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)
else: rivers = []
fill['N'] = '1/1p,%s,%s' % ( gmtpy.color(self.color_boundaries), 'solid')
D=cres, W='thinnest,%s' % gmtpy.color(darken(gmtpy.color_tup(color_dry))), A=minarea, *(rivers+self._jxyr), **fill)
self.draw_plates()
else: axes_layout = 'WseN' else: axes_layout = self.axes_layout
gmt.psxy( in_rows=[[self.lon, self.lat]], S='c20p', W='2p,black', *self._jxyr)
'%(yinc)gg%(yinc)g:%(ylabel)s:') else: btmpl = '%(xinc)g:%(xlabel)s:/%(yinc)g:%(ylabel)s:'
scale = 'x%gp/%gp/%g/%g/%gk' % ( 6./7*widget.width(), widget.height()/7., self.lon, self.lat, scale_km) else:
B=(btmpl % scaler.get_params())+axes_layout, L=scale, *self._jxyr)
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))
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()
lats = [lats] lons = [lons] onepoint = True
else:
xs = xs[0] ys = ys[0]
(ll_lat, ur_lat), (ll_lon, ur_lon), jr=jr)
la(ymin < ys, ys < ymax)))
a[1] < b[3] and b[1] < a[3])
angles, styles = list(zip(*self._labels))
(font_size or label_font_size) for font_size in font_sizes]
texts[i], font=fonts[i], font_size=font_sizes[i], **styles[i])
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), )
(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)]
xs, ys, *[xxx[i] for xxx in arects[ianch]])
if anchors_ok[ianch][i]] else: anchor_take.append(None)
continue noverlaps += 1
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
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
lons[i], lats[i], '%i,%s,%s' % (font_sizes[i], fonts[i], color), anchor, texts[i])
else: row = ( lons[i], lats[i], font_sizes[i], angles[i], fonts[i], anchor, texts[i]) farg = ['-G%s' % color]
in_rows=[row], D='%gp/%gp' % (xoff, yoff), *(self.jxyr + farg), **styles[i])
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, lat, lon, text, offset_x=5., offset_y=5., color=None, font='1', font_size=None, angle=0, style={}):
style = style.copy() color = style.pop('G')
(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
'S': 't8p', 'G': 'black' }
in_columns=(lons, lats), *self.jxyr, **default_psxy_style)
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):
offset_scale, scale)
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: 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]
'h': 0, 'W': '2p,black', 'A': '+p2p,black+e+a40', 'G': 'black', 'L': True, 'S': 'e%dc/0.95/%d' % (scale, fontsize), }
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) |