import numpy as num
|
|
import logging
|
|
import math
|
|
|
|
from pyrocko import plot
|
|
from pyrocko.guts import Tuple, Float
|
|
|
|
from matplotlib import pyplot as plt
|
|
from matplotlib import lines
|
|
from matplotlib.ticker import FuncFormatter
|
|
|
|
from grond.plot.config import PlotConfig
|
|
|
|
guts_prefix = 'grond'
|
|
km = 1e3
|
|
d2r = math.pi / 180.
|
|
|
|
logger = logging.getLogger('targets.plot')
|
|
|
|
|
|
class StationDistributionPlot(PlotConfig):
|
|
''' Plot showing all waveform fits for the ensemble of solutions'''
|
|
|
|
name = 'seismic_stations_base'
|
|
size_cm = Tuple.T(
|
|
2, Float.T(),
|
|
default=(16., 13.),
|
|
help='width and length of the figure in cm')
|
|
font_size = Float.T(
|
|
default=10,
|
|
help='font size of all text, except station labels')
|
|
font_size_labels = Float.T(
|
|
default=6,
|
|
help='font size of station labels')
|
|
|
|
def plot_station_distribution(
|
|
self, azimuths, distances, weights, labels=None,
|
|
scatter_kwargs=dict(), annotate_kwargs=dict(), maxsize=10**2):
|
|
|
|
invalid_color = plot.mpl_color('aluminium3')
|
|
|
|
scatter_default = {
|
|
'alpha': .5,
|
|
'zorder': 10,
|
|
'c': plot.mpl_color('skyblue2'),
|
|
}
|
|
|
|
annotate_default = {
|
|
'alpha': .8,
|
|
'color': 'k',
|
|
'fontsize': self.font_size_labels,
|
|
'ha': 'right',
|
|
'va': 'top',
|
|
'xytext': (-5, -5),
|
|
'textcoords': 'offset points'
|
|
}
|
|
|
|
scatter_default.update(scatter_kwargs)
|
|
annotate_default.update(annotate_kwargs)
|
|
|
|
fig = plt.figure(figsize=self.size_inch)
|
|
|
|
plot.mpl_margins(
|
|
fig, nw=1, nh=1, left=3., right=10., top=3., bottom=3.,
|
|
units=self.font_size)
|
|
|
|
ax = fig.add_subplot(111, projection='polar')
|
|
|
|
valid = num.isfinite(weights)
|
|
valid[valid] = num.logical_and(valid[valid], weights[valid] > 0.0)
|
|
|
|
weights = weights.copy()
|
|
if num.sum(valid) == 0:
|
|
weights[:] = 1.0
|
|
weights_ref = 1.0
|
|
else:
|
|
weights[~valid] = weights[valid].min()
|
|
weights_ref = plot.nice_value(weights[valid].max())
|
|
|
|
if weights_ref == 0.:
|
|
weights_ref = 1.0
|
|
|
|
colors = [scatter_default['c'] if s else invalid_color
|
|
for s in valid]
|
|
|
|
scatter_default.pop('c')
|
|
|
|
weights_scaled = (weights / weights_ref) * maxsize
|
|
|
|
stations = ax.scatter(
|
|
azimuths*d2r, distances, s=weights_scaled, c=colors,
|
|
**scatter_default)
|
|
|
|
if len(labels) < 30: # TODO: remove after impl. of collision detection
|
|
if labels is not None:
|
|
for ilbl, label in enumerate(labels):
|
|
ax.annotate(
|
|
label, (azimuths[ilbl]*d2r, distances[ilbl]),
|
|
**annotate_default)
|
|
|
|
ax.set_theta_zero_location('N')
|
|
ax.set_theta_direction(-1)
|
|
ax.tick_params('y', labelsize=self.font_size, labelcolor='gray')
|
|
ax.grid(alpha=.3)
|
|
ax.set_ylim(0, distances.max()*1.1)
|
|
ax.yaxis.set_major_locator(plt.MaxNLocator(4))
|
|
ax.yaxis.set_major_formatter(
|
|
FuncFormatter(lambda x, pos: '%d km' % (x/km)))
|
|
|
|
# Legend
|
|
entries = 4
|
|
valid_marker = num.argmax(valid)
|
|
ecl = stations.get_edgecolor()
|
|
fc = tuple(stations.get_facecolor()[valid_marker])
|
|
ec = tuple(ecl[min(valid_marker, len(ecl)-1)])
|
|
|
|
def get_min_precision(values):
|
|
sig_prec = num.floor(
|
|
num.isfinite(num.log10(values[values > 0])))
|
|
|
|
if sig_prec.size == 0:
|
|
return 1
|
|
|
|
return int(abs(sig_prec.min())) + 1
|
|
|
|
legend_artists = [
|
|
lines.Line2D(
|
|
[0], [0], ls='none',
|
|
marker='o', ms=num.sqrt(rad), mfc=fc, mec=ec)
|
|
for rad in num.linspace(maxsize, .1*maxsize, entries)
|
|
]
|
|
|
|
sig_prec = get_min_precision(weights)
|
|
legend_annot = [
|
|
'{value:.{prec}f}'.format(value=val, prec=sig_prec)
|
|
for val in num.linspace(weights_ref, .1*weights_ref, entries)
|
|
]
|
|
|
|
if not num.all(valid):
|
|
legend_artists.append(
|
|
lines.Line2D(
|
|
[0], [0], ls='none',
|
|
marker='o', ms=num.sqrt(maxsize),
|
|
mfc=invalid_color, mec=invalid_color))
|
|
legend_annot.append('Excluded')
|
|
|
|
legend = fig.legend(
|
|
legend_artists, legend_annot,
|
|
fontsize=self.font_size, loc=4,
|
|
markerscale=1, numpoints=1,
|
|
frameon=False)
|
|
|
|
return fig, ax, legend
|