Ejemplo n.º 1
0
    def draw_figures(self, ds, history, optimiser):

        fontsize = self.font_size
        fontsize_title = self.font_size_title

        nxmax = self.nx
        nymax = self.ny

        problem = history.problem

        for target in problem.targets:
            target.set_dataset(ds)

        target_index = {}
        i = 0
        for target in problem.targets:
            target_index[target] = i, i+target.nmisfits
            i += target.nmisfits

        xbest = history.get_best_model()
        misfits = history.misfits[history.get_sorted_misfits_idx(chain=0), ...]

        ws = problem.get_target_weights()

        gcms = problem.combine_misfits(
            misfits[:1, :, :],
            extra_correlated_weights=optimiser.get_correlated_weights(problem),
            get_contributions=True)[0, :]

        w_max = num.nanmax(ws)
        gcm_max = num.nanmax(gcms)

        source = problem.get_source(xbest)

        target_to_result = {}
        all_syn_trs = []
        all_syn_specs = []
        results = problem.evaluate(xbest)

        dtraces = []
        for target, result in zip(problem.targets, results):
            if not isinstance(result, WaveformMisfitResult):
                dtraces.extend([None] * target.nmisfits)
                continue

            itarget, itarget_end = target_index[target]
            assert itarget_end == itarget + 1

            w = target.get_combined_weight()

            if target.misfit_config.domain == 'cc_max_norm':
                tref = (
                    result.filtered_obs.tmin + result.filtered_obs.tmax) * 0.5
                for tr_filt, tr_proc, tshift in (
                        (result.filtered_obs,
                         result.processed_obs,
                         0.),
                        (result.filtered_syn,
                         result.processed_syn,
                         result.tshift)):

                    norm = num.sum(num.abs(tr_proc.ydata)) / tr_proc.data_len()
                    tr_filt.ydata /= norm
                    tr_proc.ydata /= norm

                    tr_filt.shift(tshift)
                    tr_proc.shift(tshift)

                ctr = result.cc
                ctr.shift(tref)

                dtrace = ctr

            else:
                for tr in (
                        result.filtered_obs,
                        result.filtered_syn,
                        result.processed_obs,
                        result.processed_syn):

                    tr.ydata *= w

                for spec in (
                        result.spectrum_obs,
                        result.spectrum_syn):

                    if spec is not None:
                        spec.ydata *= w

                if result.tshift is not None and result.tshift != 0.0:
                    # result.filtered_syn.shift(result.tshift)
                    result.processed_syn.shift(result.tshift)

                dtrace = make_norm_trace(
                    result.processed_syn, result.processed_obs,
                    problem.norm_exponent)

            target_to_result[target] = result

            dtrace.meta = dict(
                normalisation_family=target.normalisation_family,
                path=target.path)
            dtraces.append(dtrace)

            result.processed_syn.meta = dict(
                normalisation_family=target.normalisation_family,
                path=target.path)

            all_syn_trs.append(result.processed_syn)

            if result.spectrum_syn:
                result.spectrum_syn.meta = dict(
                    normalisation_family=target.normalisation_family,
                    path=target.path)

                all_syn_specs.append(result.spectrum_syn)

        if not all_syn_trs:
            logger.warn('No traces to show!')
            return

        def skey(tr):
            return tr.meta['normalisation_family'], tr.meta['path']

        trace_minmaxs = trace.minmax(all_syn_trs, skey)

        amp_spec_maxs = amp_spec_max(all_syn_specs, skey)

        dminmaxs = trace.minmax([x for x in dtraces if x is not None], skey)

        for tr in dtraces:
            if tr:
                dmin, dmax = dminmaxs[skey(tr)]
                tr.ydata /= max(abs(dmin), abs(dmax))

        cg_to_targets = meta.gather(
            problem.waveform_targets,
            lambda t: (t.path, t.codes[3]),
            filter=lambda t: t in target_to_result)

        cgs = sorted(cg_to_targets.keys())

        for cg in cgs:
            targets = cg_to_targets[cg]

            frame_to_target, nx, ny, nxx, nyy = layout(
                source, targets, nxmax, nymax)

            figures = {}
            for iy in range(ny):
                for ix in range(nx):
                    if (iy, ix) not in frame_to_target:
                        continue

                    ixx = ix // nxmax
                    iyy = iy // nymax
                    if (iyy, ixx) not in figures:
                        title = '_'.join(x for x in cg if x)
                        item = PlotItem(
                            name='fig_%s_%i_%i' % (title, ixx, iyy))
                        item.attributes['targets'] = []
                        figures[iyy, ixx] = (
                            item, plt.figure(figsize=self.size_inch))

                        figures[iyy, ixx][1].subplots_adjust(
                            left=0.03,
                            right=1.0 - 0.03,
                            bottom=0.03,
                            top=1.0 - 0.06,
                            wspace=0.2,
                            hspace=0.2)

                    item, fig = figures[iyy, ixx]

                    target = frame_to_target[iy, ix]

                    item.attributes['targets'].append(target.string_id())

                    amin, amax = trace_minmaxs[
                        target.normalisation_family, target.path]
                    absmax = max(abs(amin), abs(amax))

                    ny_this = nymax  # min(ny, nymax)
                    nx_this = nxmax  # min(nx, nxmax)
                    i_this = (iy % ny_this) * nx_this + (ix % nx_this) + 1

                    axes2 = fig.add_subplot(ny_this, nx_this, i_this)

                    space = 0.5
                    space_factor = 1.0 + space
                    axes2.set_axis_off()
                    axes2.set_ylim(-1.05 * space_factor, 1.05)

                    axes = axes2.twinx()
                    axes.set_axis_off()

                    if target.misfit_config.domain == 'cc_max_norm':
                        axes.set_ylim(-10. * space_factor, 10.)
                    else:
                        axes.set_ylim(
                            -absmax * 1.33 * space_factor, absmax * 1.33)

                    itarget, itarget_end = target_index[target]
                    assert itarget_end == itarget + 1

                    result = target_to_result[target]

                    dtrace = dtraces[itarget]

                    tap_color_annot = (0.35, 0.35, 0.25)
                    tap_color_edge = (0.85, 0.85, 0.80)
                    tap_color_fill = (0.95, 0.95, 0.90)

                    plot_taper(
                        axes2, result.processed_obs.get_xdata(), result.taper,
                        fc=tap_color_fill, ec=tap_color_edge)

                    obs_color = mpl_color('aluminium5')
                    obs_color_light = light(obs_color, 0.5)

                    syn_color = mpl_color('scarletred2')
                    syn_color_light = light(syn_color, 0.5)

                    misfit_color = mpl_color('scarletred2')
                    weight_color = mpl_color('chocolate2')

                    cc_color = mpl_color('aluminium5')

                    if target.misfit_config.domain == 'cc_max_norm':
                        tref = (result.filtered_obs.tmin +
                                result.filtered_obs.tmax) * 0.5

                        plot_dtrace(
                            axes2, dtrace, space, -1., 1.,
                            fc=light(cc_color, 0.5),
                            ec=cc_color)

                        plot_dtrace_vline(
                            axes2, tref, space, color=tap_color_annot)

                    elif target.misfit_config.domain == 'frequency_domain':

                        asmax = amp_spec_maxs[
                            target.normalisation_family, target.path]
                        fmin, fmax = \
                            target.misfit_config.get_full_frequency_range()

                        plot_spectrum(
                            axes2,
                            result.spectrum_syn,
                            result.spectrum_obs,
                            fmin, fmax,
                            space, 0., asmax,
                            syn_color=syn_color,
                            obs_color=obs_color,
                            syn_lw=1.0,
                            obs_lw=0.75,
                            color_vline=tap_color_annot,
                            fontsize=fontsize)

                    else:
                        plot_dtrace(
                            axes2, dtrace, space, 0., 1.,
                            fc=light(misfit_color, 0.3),
                            ec=misfit_color)

                    plot_trace(
                        axes, result.filtered_syn,
                        color=syn_color_light, lw=1.0)

                    plot_trace(
                        axes, result.filtered_obs,
                        color=obs_color_light, lw=0.75)

                    plot_trace(
                        axes, result.processed_syn,
                        color=syn_color, lw=1.0)

                    plot_trace(
                        axes, result.processed_obs,
                        color=obs_color, lw=0.75)

                    # xdata = result.filtered_obs.get_xdata()

                    tmarks = [
                        result.processed_obs.tmin,
                        result.processed_obs.tmax]

                    for tmark in tmarks:
                        axes2.plot(
                            [tmark, tmark], [-0.9, 0.1], color=tap_color_annot)

                    dur = tmarks[1] - tmarks[0]
                    for tmark, text, ha in [
                            (tmarks[0],
                             '$\\,$ ' + meta.str_duration(
                                 tmarks[0] - source.time),
                             'left'),
                            (tmarks[1],
                             '$\\Delta$ ' + meta.str_duration(dur),
                             'right')]:

                        axes2.annotate(
                            text,
                            xy=(tmark, -0.9),
                            xycoords='data',
                            xytext=(
                                fontsize * 0.4 * [-1, 1][ha == 'left'],
                                fontsize * 0.2),
                            textcoords='offset points',
                            ha=ha,
                            va='bottom',
                            color=tap_color_annot,
                            fontsize=fontsize)

                    axes2.set_xlim(tmarks[0] - dur*0.1, tmarks[1] + dur*0.1)

                    rel_w = ws[itarget] / w_max
                    rel_c = gcms[itarget] / gcm_max

                    sw = 0.25
                    sh = 0.1
                    ph = 0.01

                    for (ih, rw, facecolor, edgecolor) in [
                            (0, rel_w, light(weight_color, 0.5),
                             weight_color),
                            (1, rel_c, light(misfit_color, 0.5),
                             misfit_color)]:

                        bar = patches.Rectangle(
                            (1.0 - rw * sw, 1.0 - (ih + 1) * sh + ph),
                            rw * sw,
                            sh - 2 * ph,
                            facecolor=facecolor, edgecolor=edgecolor,
                            zorder=10,
                            transform=axes.transAxes, clip_on=False)

                        axes.add_patch(bar)

                    scale_string = None

                    if target.misfit_config.domain == 'cc_max_norm':
                        scale_string = 'Syn/obs scales differ!'

                    infos = []
                    if scale_string:
                        infos.append(scale_string)

                    if self.nx == 1 and self.ny == 1:
                        infos.append(target.string_id())
                    else:
                        infos.append('.'.join(x for x in target.codes if x))

                    dist = source.distance_to(target)
                    azi = source.azibazi_to(target)[0]
                    infos.append(meta.str_dist(dist))
                    infos.append('%.0f\u00B0' % azi)
                    infos.append('%.3g' % ws[itarget])
                    infos.append('%.3g' % gcms[itarget])
                    axes2.annotate(
                        '\n'.join(infos),
                        xy=(0., 1.),
                        xycoords='axes fraction',
                        xytext=(2., 2.),
                        textcoords='offset points',
                        ha='left',
                        va='top',
                        fontsize=fontsize,
                        fontstyle='normal')

                    if (self.nx == 1 and self.ny == 1):
                        yield item, fig
                        del figures[iyy, ixx]

            if not (self.nx == 1 and self.ny == 1):
                for (iyy, ixx), (_, fig) in figures.items():
                    title = '.'.join(x for x in cg if x)
                    if len(figures) > 1:
                        title += ' (%i/%i, %i/%i)' % (
                            iyy + 1, nyy, ixx + 1, nxx)

                    fig.suptitle(title, fontsize=fontsize_title)

            for item, fig in figures.values():
                yield item, fig
Ejemplo n.º 2
0
    def draw_figures(self, ds, history, optimiser):

        color_parameter = self.color_parameter
        misfit_cutoff = self.misfit_cutoff
        fontsize = self.font_size
        fontsize_title = self.font_size_title

        nxmax = self.nx
        nymax = self.ny

        problem = history.problem

        for target in problem.targets:
            target.set_dataset(ds)

        target_index = {}
        i = 0
        for target in problem.targets:
            target_index[target] = i, i+target.nmisfits
            i += target.nmisfits

        gms = history.get_sorted_primary_misfits()[::-1]
        models = history.get_sorted_primary_models()[::-1]

        if misfit_cutoff is not None:
            ibest = gms < misfit_cutoff
            gms = gms[ibest]
            models = models[ibest]

        gms = gms[::10]
        models = models[::10]

        nmodels = models.shape[0]
        if color_parameter == 'dist':
            mx = num.mean(models, axis=0)
            cov = num.cov(models.T)
            mdists = core.mahalanobis_distance(models, mx, cov)
            icolor = meta.ordersort(mdists)

        elif color_parameter == 'misfit':
            iorder = num.arange(nmodels)
            icolor = iorder

        elif color_parameter in problem.parameter_names:
            ind = problem.name_to_index(color_parameter)
            icolor = problem.extract(models, ind)

        target_to_results = defaultdict(list)
        all_syn_trs = []

        dtraces = []
        for imodel in range(nmodels):
            model = models[imodel, :]

            source = problem.get_source(model)
            results = problem.evaluate(model)

            dtraces.append([])

            for target, result in zip(problem.targets, results):
                w = target.get_combined_weight()

                if isinstance(result, gf.SeismosizerError) or \
                        not isinstance(target, WaveformMisfitTarget) or \
                        not num.all(num.isfinite(w)):

                    dtraces[-1].extend([None] * target.nmisfits)
                    continue

                itarget, itarget_end = target_index[target]
                assert itarget_end == itarget + 1

                if target.misfit_config.domain == 'cc_max_norm':
                    tref = (
                        result.filtered_obs.tmin + result.filtered_obs.tmax) \
                        * 0.5

                    for tr_filt, tr_proc, tshift in (
                            (result.filtered_obs,
                             result.processed_obs,
                             0.),
                            (result.filtered_syn,
                             result.processed_syn,
                             result.tshift)):

                        norm = num.sum(num.abs(tr_proc.ydata)) \
                            / tr_proc.data_len()
                        tr_filt.ydata /= norm
                        tr_proc.ydata /= norm

                        tr_filt.shift(tshift)
                        tr_proc.shift(tshift)

                    ctr = result.cc
                    ctr.shift(tref)

                    dtrace = ctr

                else:
                    for tr in (
                            result.filtered_obs,
                            result.filtered_syn,
                            result.processed_obs,
                            result.processed_syn):

                        tr.ydata *= w

                    if result.tshift is not None and result.tshift != 0.0:
                        # result.filtered_syn.shift(result.tshift)
                        result.processed_syn.shift(result.tshift)

                    dtrace = make_norm_trace(
                        result.processed_syn, result.processed_obs,
                        problem.norm_exponent)

                target_to_results[target].append(result)

                dtrace.meta = dict(
                    normalisation_family=target.normalisation_family,
                    path=target.path)

                dtraces[-1].append(dtrace)

                result.processed_syn.meta = dict(
                    normalisation_family=target.normalisation_family,
                    path=target.path)

                all_syn_trs.append(result.processed_syn)

        if not all_syn_trs:
            logger.warn('No traces to show!')
            return

        def skey(tr):
            return tr.meta['normalisation_family'], tr.meta['path']

        trace_minmaxs = trace.minmax(all_syn_trs, skey)

        dtraces_all = []
        for dtraces_group in dtraces:
            dtraces_all.extend(dtraces_group)

        dminmaxs = trace.minmax([
            dtrace_ for dtrace_ in dtraces_all if dtrace_ is not None], skey)

        for tr in dtraces_all:
            if tr:
                dmin, dmax = dminmaxs[skey(tr)]
                tr.ydata /= max(abs(dmin), abs(dmax))

        cg_to_targets = meta.gather(
            problem.waveform_targets,
            lambda t: (t.path, t.codes[3]),
            filter=lambda t: t in target_to_results)

        cgs = sorted(cg_to_targets.keys())

        from matplotlib import colors
        cmap = cm.ScalarMappable(
            norm=colors.Normalize(vmin=num.min(icolor), vmax=num.max(icolor)),
            cmap=plt.get_cmap('coolwarm'))

        imodel_to_color = []
        for imodel in range(nmodels):
            imodel_to_color.append(cmap.to_rgba(icolor[imodel]))

        for cg in cgs:
            targets = cg_to_targets[cg]

            frame_to_target, nx, ny, nxx, nyy = layout(
                source, targets, nxmax, nymax)

            figures = {}
            for iy in range(ny):
                for ix in range(nx):
                    if (iy, ix) not in frame_to_target:
                        continue

                    ixx = ix // nxmax
                    iyy = iy // nymax
                    if (iyy, ixx) not in figures:
                        title = '_'.join(x for x in cg if x)
                        item = PlotItem(
                            name='fig_%s_%i_%i' % (title, ixx, iyy))
                        item.attributes['targets'] = []
                        figures[iyy, ixx] = (
                            item, plt.figure(figsize=self.size_inch))

                        figures[iyy, ixx][1].subplots_adjust(
                            left=0.03,
                            right=1.0 - 0.03,
                            bottom=0.03,
                            top=1.0 - 0.06,
                            wspace=0.2,
                            hspace=0.2)

                    item, fig = figures[iyy, ixx]

                    target = frame_to_target[iy, ix]

                    item.attributes['targets'].append(target.string_id())

                    amin, amax = trace_minmaxs[
                        target.normalisation_family, target.path]
                    absmax = max(abs(amin), abs(amax))

                    ny_this = nymax  # min(ny, nymax)
                    nx_this = nxmax  # min(nx, nxmax)
                    i_this = (iy % ny_this) * nx_this + (ix % nx_this) + 1

                    axes2 = fig.add_subplot(ny_this, nx_this, i_this)

                    space = 0.5
                    space_factor = 1.0 + space
                    axes2.set_axis_off()
                    axes2.set_ylim(-1.05 * space_factor, 1.05)

                    axes = axes2.twinx()
                    axes.set_axis_off()

                    if target.misfit_config.domain == 'cc_max_norm':
                        axes.set_ylim(-10. * space_factor, 10.)
                    else:
                        axes.set_ylim(-absmax*1.33 * space_factor, absmax*1.33)

                    itarget, itarget_end = target_index[target]
                    assert itarget_end == itarget + 1

                    for imodel, result in enumerate(target_to_results[target]):

                        syn_color = imodel_to_color[imodel]

                        dtrace = dtraces[imodel][itarget]

                        tap_color_annot = (0.35, 0.35, 0.25)
                        tap_color_edge = (0.85, 0.85, 0.80)
                        tap_color_fill = (0.95, 0.95, 0.90)

                        plot_taper(
                            axes2,
                            result.processed_obs.get_xdata(),
                            result.taper,
                            fc=tap_color_fill, ec=tap_color_edge, alpha=0.2)

                        obs_color = mpl_color('aluminium5')
                        obs_color_light = light(obs_color, 0.5)

                        plot_dtrace(
                            axes2, dtrace, space, 0., 1.,
                            fc='none',
                            ec=syn_color)

                        # plot_trace(
                        #     axes, result.filtered_syn,
                        #     color=syn_color_light, lw=1.0)

                        if imodel == 0:
                            plot_trace(
                                axes, result.filtered_obs,
                                color=obs_color_light, lw=0.75)

                        plot_trace(
                            axes, result.processed_syn,
                            color=syn_color, lw=1.0, alpha=0.3)

                        plot_trace(
                            axes, result.processed_obs,
                            color=obs_color, lw=0.75, alpha=0.3)

                        if imodel != 0:
                            continue
                        xdata = result.filtered_obs.get_xdata()
                        axes.set_xlim(xdata[0], xdata[-1])

                        tmarks = [
                            result.processed_obs.tmin,
                            result.processed_obs.tmax]

                        for tmark in tmarks:
                            axes2.plot(
                                [tmark, tmark], [-0.9, 0.1],
                                color=tap_color_annot)

                        dur = tmarks[1] - tmarks[0]
                        for tmark, text, ha in [
                                (tmarks[0],
                                 '$\\,$ ' + meta.str_duration(
                                    tmarks[0] - source.time),
                                 'left'),
                                (tmarks[1],
                                 '$\\Delta$ ' + meta.str_duration(
                                    dur),
                                 'right')]:

                            axes2.annotate(
                                text,
                                xy=(tmark, -0.9),
                                xycoords='data',
                                xytext=(
                                    fontsize*0.4 * [-1, 1][ha == 'left'],
                                    fontsize*0.2),
                                textcoords='offset points',
                                ha=ha,
                                va='bottom',
                                color=tap_color_annot,
                                fontsize=fontsize)

                        axes2.set_xlim(
                            tmarks[0] - dur*0.1, tmarks[1] + dur*0.1)

                    scale_string = None

                    if target.misfit_config.domain == 'cc_max_norm':
                        scale_string = 'Syn/obs scales differ!'

                    infos = []
                    if scale_string:
                        infos.append(scale_string)

                    if self.nx == 1 and self.ny == 1:
                        infos.append(target.string_id())
                    else:
                        infos.append('.'.join(x for x in target.codes if x))
                    dist = source.distance_to(target)
                    azi = source.azibazi_to(target)[0]
                    infos.append(meta.str_dist(dist))
                    infos.append(u'%.0f\u00B0' % azi)
                    axes2.annotate(
                        '\n'.join(infos),
                        xy=(0., 1.),
                        xycoords='axes fraction',
                        xytext=(2., 2.),
                        textcoords='offset points',
                        ha='left',
                        va='top',
                        fontsize=fontsize,
                        fontstyle='normal')

                    if (self.nx == 1 and self.ny == 1):
                        yield item, fig
                        del figures[iyy, ixx]

            if not (self.nx == 1 and self.ny == 1):
                for (iyy, ixx), (_, fig) in figures.items():
                    title = '.'.join(x for x in cg if x)
                    if len(figures) > 1:
                        title += ' (%i/%i, %i/%i)' % (iyy+1, nyy, ixx+1, nxx)

                    fig.suptitle(title, fontsize=fontsize_title)

            for item, fig in figures.values():
                yield item, fig
Ejemplo n.º 3
0
    def draw_figures(self, problem, dataset, history):

        target_index = {}
        i = 0
        for target in problem.targets:
            target_index[target] = i, i+target.nmisfits
            i += target.nmisfits

        ws = problem.get_target_weights()

        if history:
            misfits = history.misfits[history.get_sorted_misfits_idx(), ...]
            gcms = problem.combine_misfits(
                misfits[:1, :, :], get_contributions=True)[0, :]

        event = problem.base_source

        cg_to_targets = meta.gather(
            problem.waveform_targets,
            lambda t: (t.path, t.codes[3]))

        cgs = sorted(cg_to_targets.keys())

        for cg in cgs:
            cg_str = '.'.join(cg)

            targets = cg_to_targets[cg]
            if len(targets) == 0:
                continue

            assert all(target_index[target][0] == target_index[target][1] - 1
                       for target in targets)

            itargets = num.array(
                [target_index[target][0] for target in targets])

            labels = ['.'.join(x for x in t.codes[:3] if x) for t in targets]

            azimuths = num.array([event.azibazi_to(t)[0] for t in targets])
            distances = num.array([t.distance_to(event) for t in targets])

            item = PlotItem(
                name='seismic_stations_weights_%s' % cg_str,
                title=u'Station weights (%s)' % cg_str,
                description=u'\n\nMarkers are scaled according to the '
                            u'weighting factor of the corresponding target\'s '
                            u'contribution in the misfit function.')
            fig, ax, legend = self.plot_station_distribution(
                azimuths, distances, ws[itargets], labels)
            legend.set_title(
                'Weight',
                prop=dict(size=self.font_size))

            yield (item, fig)

            if history:
                item = PlotItem(
                    name='seismic_stations_contributions_%s' % cg_str,
                    title=u'Station misfit contributions (%s)' % cg_str,
                    description=u'\n\nMarkers are scaled according to their '
                                u'misfit contribution for the globally best '
                                u'source model.')
                fig, ax, legend = self.plot_station_distribution(
                    azimuths, distances, gcms[itargets], labels)
                legend.set_title(
                    'Contribution',
                    prop=dict(size=self.font_size))

                yield (item, fig)
Ejemplo n.º 4
0
    def draw_figures(self, problem, dataset, history):

        target_index = {}
        i = 0
        for target in problem.targets:
            target_index[target] = i, i + target.nmisfits
            i += target.nmisfits

        misfits = history.misfits[history.get_sorted_misfits_idx(), ...]
        gcms = problem.combine_misfits(misfits[:1, :, :],
                                       get_contributions=True)[0, :]
        models = history.get_sorted_primary_models()[::-1]

        origin = problem.base_source

        targets = [
            t for t in problem.targets if isinstance(t, PhasePickTarget)
        ]

        ntargets = len(targets)
        nmodels = history.nmodels
        tts = num.zeros((nmodels, ntargets, 2))

        sdata = []
        for imodel in range(nmodels):
            model = models[imodel, :]
            source = problem.get_source(model)
            sdata.append(
                (origin.distance_to(source), origin.azibazi_to(source)[0]))

            results = problem.evaluate(model, targets=targets)
            for itarget, result in enumerate(results):
                result = results[itarget]
                tts[imodel, itarget, :] = result.tobs, result.tsyn

        ok = num.all(num.isfinite(tts), axis=2)
        ok = num.all(ok, axis=0)

        targets_ok = [
            target for (itarget, target) in enumerate(targets) if ok[itarget]
        ]
        tts = tts[:, ok, :]
        residuals = tts[:, :, 0] - tts[:, :, 1]
        mean_residuals = num.mean(residuals, axis=0)

        rlo, rhi = num.percentile(mean_residuals, [10., 90.])
        residual_amax = max(abs(rlo), abs(rhi))

        target_to_residual = dict(
            (target, residual)
            for (target, residual) in zip(targets_ok, mean_residuals))

        cg_to_targets = meta.gather(targets, lambda t: (t.path, ))

        cgs = sorted(cg_to_targets.keys())

        for cg in cgs:
            cg_str = '.'.join(cg)

            targets = cg_to_targets[cg]
            if len(targets) == 0:
                continue

            assert all(target_index[target][0] == target_index[target][1] - 1
                       for target in targets)

            itargets = num.array(
                [target_index[target][0] for target in targets])

            labels = ['.'.join(x for x in t.codes[:3] if x) for t in targets]

            azimuths = num.array([origin.azibazi_to(t)[0] for t in targets])
            distances = num.array([t.distance_to(origin) for t in targets])
            residuals = num.array(
                [target_to_residual.get(t, num.nan) for t in targets])

            item = PlotItem(
                name='picks_contributions_%s' % cg_str,
                title=u'Pick residuals and contributions (%s)' % cg_str,
                description=u'\n\nMarkers are scaled according to their '
                u'misfit contribution for the globally best '
                u'source model.')

            fig, axes, legend = self.plot_station_distribution(
                azimuths,
                distances,
                gcms[itargets],
                labels,
                colors=residuals,
                cnorm=(-residual_amax, residual_amax),
                cmap='RdYlBu',
                clabel='$T_{obs} - T_{syn}$ [s]',
                scatter_kwargs=dict(alpha=1.0),
                legend_title='Contribution')

            sources = [problem.get_source(x) for x in models[::10]]

            azimuths = num.array([origin.azibazi_to(s)[0] for s in sources])
            distances = num.array([s.distance_to(origin) for s in sources])

            axes.plot(azimuths * d2r,
                      distances,
                      'o',
                      ms=2.0,
                      color='black',
                      alpha=0.3)

            yield (item, fig)
Ejemplo n.º 5
0
    def draw_figures(self, ds, history):

        fontsize = self.font_size
        fontsize_title = self.font_size_title

        problem = history.problem

        for target in problem.targets:
            target.set_dataset(ds)

        target_index = dict(
            (target, i) for (i, target) in enumerate(problem.targets))

        gms = problem.combine_misfits(history.misfits)
        isort = num.argsort(gms)
        gms = gms[isort]
        models = history.models[isort, :]
        misfits = history.misfits[isort, :]

        xbest = models[0, :]

        ws = problem.get_target_weights()

        gcms = problem.combine_misfits(misfits[:1, :, :],
                                       get_contributions=True)[0, :]

        w_max = num.nanmax(ws)
        gcm_max = num.nanmax(gcms)

        source = problem.get_source(xbest)

        target_to_result = {}
        all_syn_trs = []
        all_syn_specs = []
        results = problem.evaluate(xbest)

        dtraces = []
        for target, result in zip(problem.targets, results):
            if not isinstance(result, WaveformMisfitResult):
                dtraces.append(None)
                continue

            itarget = target_index[target]
            w = target.get_combined_weight()

            if target.misfit_config.domain == 'cc_max_norm':
                tref = (result.filtered_obs.tmin +
                        result.filtered_obs.tmax) * 0.5
                for tr_filt, tr_proc, tshift in ((result.filtered_obs,
                                                  result.processed_obs, 0.),
                                                 (result.filtered_syn,
                                                  result.processed_syn,
                                                  result.tshift)):

                    norm = num.sum(num.abs(tr_proc.ydata)) / tr_proc.data_len()
                    tr_filt.ydata /= norm
                    tr_proc.ydata /= norm

                    tr_filt.shift(tshift)
                    tr_proc.shift(tshift)

                ctr = result.cc
                ctr.shift(tref)

                dtrace = ctr

            else:
                for tr in (result.filtered_obs, result.filtered_syn,
                           result.processed_obs, result.processed_syn):

                    tr.ydata *= w

                for spec in (result.spectrum_obs, result.spectrum_syn):

                    if spec is not None:
                        spec.ydata *= w

                if result.tshift is not None and result.tshift != 0.0:
                    # result.filtered_syn.shift(result.tshift)
                    result.processed_syn.shift(result.tshift)

                dtrace = make_norm_trace(result.processed_syn,
                                         result.processed_obs,
                                         problem.norm_exponent)

            target_to_result[target] = result

            dtrace.meta = dict(
                normalisation_family=target.normalisation_family,
                path=target.path)
            dtraces.append(dtrace)

            result.processed_syn.meta = dict(
                normalisation_family=target.normalisation_family,
                path=target.path)

            all_syn_trs.append(result.processed_syn)

            if result.spectrum_syn:
                result.spectrum_syn.meta = dict(
                    normalisation_family=target.normalisation_family,
                    path=target.path)

                all_syn_specs.append(result.spectrum_syn)

        if not all_syn_trs:
            logger.warn('no traces to show')
            return []

        def skey(tr):
            return tr.meta['normalisation_family'], tr.meta['path']

        trace_minmaxs = trace.minmax(all_syn_trs, skey)

        amp_spec_maxs = amp_spec_max(all_syn_specs, skey)

        dminmaxs = trace.minmax([x for x in dtraces if x is not None], skey)

        for tr in dtraces:
            if tr:
                dmin, dmax = dminmaxs[skey(tr)]
                tr.ydata /= max(abs(dmin), abs(dmax))

        cg_to_targets = meta.gather(problem.waveform_targets,
                                    lambda t: (t.path, t.codes[3]),
                                    filter=lambda t: t in target_to_result)

        cgs = sorted(cg_to_targets.keys())

        figs = []
        for cg in cgs:
            targets = cg_to_targets[cg]
            nframes = len(targets)

            nx = int(math.ceil(math.sqrt(nframes)))
            ny = (nframes - 1) // nx + 1

            nxmax = 4
            nymax = 4

            nxx = (nx - 1) // nxmax + 1
            nyy = (ny - 1) // nymax + 1

            # nz = nxx * nyy

            xs = num.arange(nx) // ((max(2, nx) - 1.0) / 2.)
            ys = num.arange(ny) // ((max(2, ny) - 1.0) / 2.)

            xs -= num.mean(xs)
            ys -= num.mean(ys)

            fxs = num.tile(xs, ny)
            fys = num.repeat(ys, nx)

            data = []

            for target in targets:
                azi = source.azibazi_to(target)[0]
                dist = source.distance_to(target)
                x = dist * num.sin(num.deg2rad(azi))
                y = dist * num.cos(num.deg2rad(azi))
                data.append((x, y, dist))

            gxs, gys, dists = num.array(data, dtype=num.float).T

            iorder = num.argsort(dists)

            gxs = gxs[iorder]
            gys = gys[iorder]
            targets_sorted = [targets[ii] for ii in iorder]

            gxs -= num.mean(gxs)
            gys -= num.mean(gys)

            gmax = max(num.max(num.abs(gys)), num.max(num.abs(gxs)))
            if gmax == 0.:
                gmax = 1.

            gxs /= gmax
            gys /= gmax

            dists = num.sqrt((fxs[num.newaxis, :] - gxs[:, num.newaxis])**2 +
                             (fys[num.newaxis, :] - gys[:, num.newaxis])**2)

            distmax = num.max(dists)

            availmask = num.ones(dists.shape[1], dtype=num.bool)
            frame_to_target = {}
            for itarget, target in enumerate(targets_sorted):
                iframe = num.argmin(
                    num.where(availmask, dists[itarget], distmax + 1.))
                availmask[iframe] = False
                iy, ix = num.unravel_index(iframe, (ny, nx))
                frame_to_target[iy, ix] = target

            figures = {}
            for iy in range(ny):
                for ix in range(nx):
                    if (iy, ix) not in frame_to_target:
                        continue

                    ixx = ix // nxmax
                    iyy = iy // nymax
                    if (iyy, ixx) not in figures:
                        title = '_'.join(x for x in cg if x)
                        item = PlotItem(name='fig_%s_%i_%i' %
                                        (title, ixx, iyy))
                        item.attributes['targets'] = []
                        figures[iyy,
                                ixx] = (item,
                                        plt.figure(figsize=self.size_inch))

                        figures[iyy, ixx][1].subplots_adjust(left=0.03,
                                                             right=1.0 - 0.03,
                                                             bottom=0.03,
                                                             top=1.0 - 0.06,
                                                             wspace=0.2,
                                                             hspace=0.2)

                        figs.append(figures[iyy, ixx])

                    item, fig = figures[iyy, ixx]

                    target = frame_to_target[iy, ix]

                    item.attributes['targets'].append(target.string_id())

                    amin, amax = trace_minmaxs[target.normalisation_family,
                                               target.path]
                    absmax = max(abs(amin), abs(amax))

                    ny_this = nymax  # min(ny, nymax)
                    nx_this = nxmax  # min(nx, nxmax)
                    i_this = (iy % ny_this) * nx_this + (ix % nx_this) + 1

                    axes2 = fig.add_subplot(ny_this, nx_this, i_this)

                    space = 0.5
                    space_factor = 1.0 + space
                    axes2.set_axis_off()
                    axes2.set_ylim(-1.05 * space_factor, 1.05)

                    axes = axes2.twinx()
                    axes.set_axis_off()

                    if target.misfit_config.domain == 'cc_max_norm':
                        axes.set_ylim(-10. * space_factor, 10.)
                    else:
                        axes.set_ylim(-absmax * 1.33 * space_factor,
                                      absmax * 1.33)

                    itarget = target_index[target]
                    result = target_to_result[target]

                    dtrace = dtraces[itarget]

                    tap_color_annot = (0.35, 0.35, 0.25)
                    tap_color_edge = (0.85, 0.85, 0.80)
                    tap_color_fill = (0.95, 0.95, 0.90)

                    plot_taper(axes2,
                               result.processed_obs.get_xdata(),
                               result.taper,
                               fc=tap_color_fill,
                               ec=tap_color_edge)

                    obs_color = mpl_color('aluminium5')
                    obs_color_light = light(obs_color, 0.5)

                    syn_color = mpl_color('scarletred2')
                    syn_color_light = light(syn_color, 0.5)

                    misfit_color = mpl_color('scarletred2')
                    weight_color = mpl_color('chocolate2')

                    cc_color = mpl_color('aluminium5')

                    if target.misfit_config.domain == 'cc_max_norm':
                        tref = (result.filtered_obs.tmin +
                                result.filtered_obs.tmax) * 0.5

                        plot_dtrace(axes2,
                                    dtrace,
                                    space,
                                    -1.,
                                    1.,
                                    fc=light(cc_color, 0.5),
                                    ec=cc_color)

                        plot_dtrace_vline(axes2,
                                          tref,
                                          space,
                                          color=tap_color_annot)

                    elif target.misfit_config.domain == 'frequency_domain':

                        asmax = amp_spec_maxs[target.normalisation_family,
                                              target.path]
                        fmin, fmax = \
                            target.misfit_config.get_full_frequency_range()

                        plot_spectrum(axes2,
                                      result.spectrum_syn,
                                      result.spectrum_obs,
                                      fmin,
                                      fmax,
                                      space,
                                      0.,
                                      asmax,
                                      syn_color=syn_color,
                                      obs_color=obs_color,
                                      syn_lw=1.0,
                                      obs_lw=0.75,
                                      color_vline=tap_color_annot,
                                      fontsize=fontsize)

                    else:
                        plot_dtrace(axes2,
                                    dtrace,
                                    space,
                                    0.,
                                    1.,
                                    fc=light(misfit_color, 0.3),
                                    ec=misfit_color)

                    plot_trace(axes,
                               result.filtered_syn,
                               color=syn_color_light,
                               lw=1.0)

                    plot_trace(axes,
                               result.filtered_obs,
                               color=obs_color_light,
                               lw=0.75)

                    plot_trace(axes,
                               result.processed_syn,
                               color=syn_color,
                               lw=1.0)

                    plot_trace(axes,
                               result.processed_obs,
                               color=obs_color,
                               lw=0.75)

                    xdata = result.filtered_obs.get_xdata()
                    axes.set_xlim(xdata[0], xdata[-1])

                    tmarks = [
                        result.processed_obs.tmin, result.processed_obs.tmax
                    ]

                    for tmark in tmarks:
                        axes2.plot([tmark, tmark], [-0.9, 0.1],
                                   color=tap_color_annot)

                    for tmark, text, ha in [
                        (tmarks[0],
                         '$\\,$ ' + meta.str_duration(tmarks[0] - source.time),
                         'right'),
                        (tmarks[1], '$\\Delta$ ' +
                         meta.str_duration(tmarks[1] - tmarks[0]), 'left')
                    ]:

                        axes2.annotate(
                            text,
                            xy=(tmark, -0.9),
                            xycoords='data',
                            xytext=(fontsize * 0.4 * [-1, 1][ha == 'left'],
                                    fontsize * 0.2),
                            textcoords='offset points',
                            ha=ha,
                            va='bottom',
                            color=tap_color_annot,
                            fontsize=fontsize)

                    rel_w = ws[itarget] / w_max
                    rel_c = gcms[itarget] / gcm_max

                    sw = 0.25
                    sh = 0.1
                    ph = 0.01

                    for (ih, rw, facecolor, edgecolor) in [
                        (0, rel_w, light(weight_color, 0.5), weight_color),
                        (1, rel_c, light(misfit_color, 0.5), misfit_color)
                    ]:

                        bar = patches.Rectangle(
                            (1.0 - rw * sw, 1.0 - (ih + 1) * sh + ph),
                            rw * sw,
                            sh - 2 * ph,
                            facecolor=facecolor,
                            edgecolor=edgecolor,
                            zorder=10,
                            transform=axes.transAxes,
                            clip_on=False)

                        axes.add_patch(bar)

                    scale_string = None

                    if target.misfit_config.domain == 'cc_max_norm':
                        scale_string = 'Syn/obs scales differ!'

                    infos = []
                    if scale_string:
                        infos.append(scale_string)

                    infos.append('.'.join(x for x in target.codes if x))
                    dist = source.distance_to(target)
                    azi = source.azibazi_to(target)[0]
                    infos.append(meta.str_dist(dist))
                    infos.append('%.0f\u00B0' % azi)
                    infos.append('%.3g' % ws[itarget])
                    infos.append('%.3g' % gcms[itarget])
                    axes2.annotate('\n'.join(infos),
                                   xy=(0., 1.),
                                   xycoords='axes fraction',
                                   xytext=(2., 2.),
                                   textcoords='offset points',
                                   ha='left',
                                   va='top',
                                   fontsize=fontsize,
                                   fontstyle='normal')

            for (iyy, ixx), (_, fig) in figures.items():
                title = '.'.join(x for x in cg if x)
                if len(figures) > 1:
                    title += ' (%i/%i, %i/%i)' % (iyy + 1, nyy, ixx + 1, nxx)

                fig.suptitle(title, fontsize=fontsize_title)

        return figs
Ejemplo n.º 6
0
    def draw_figures(self, ds, history):

        color_parameter = self.color_parameter
        misfit_cutoff = self.misfit_cutoff
        fontsize = self.font_size
        fontsize_title = self.font_size_title

        problem = history.problem

        for target in problem.targets:
            target.set_dataset(ds)

        target_index = dict(
            (target, i) for (i, target) in enumerate(problem.targets))

        gms = problem.combine_misfits(history.misfits)
        isort = num.argsort(gms)[::-1]
        gms = gms[isort]
        models = history.models[isort, :]

        if misfit_cutoff is not None:
            ibest = gms < misfit_cutoff
            gms = gms[ibest]
            models = models[ibest]

        gms = gms[::10]
        models = models[::10]

        nmodels = models.shape[0]
        if color_parameter == 'dist':
            mx = num.mean(models, axis=0)
            cov = num.cov(models.T)
            mdists = core.mahalanobis_distance(models, mx, cov)
            icolor = meta.ordersort(mdists)

        elif color_parameter == 'misfit':
            iorder = num.arange(nmodels)
            icolor = iorder

        elif color_parameter in problem.parameter_names:
            ind = problem.name_to_index(color_parameter)
            icolor = problem.extract(models, ind)

        target_to_results = defaultdict(list)
        all_syn_trs = []

        dtraces = []
        for imodel in range(nmodels):
            model = models[imodel, :]

            source = problem.get_source(model)
            results = problem.evaluate(model)

            dtraces.append([])

            for target, result in zip(problem.targets, results):
                if isinstance(result, gf.SeismosizerError):
                    dtraces[-1].append(None)
                    continue

                if not isinstance(target, WaveformMisfitTarget):
                    dtraces[-1].append(None)
                    continue

                itarget = target_index[target]
                w = target.get_combined_weight()

                if target.misfit_config.domain == 'cc_max_norm':
                    tref = (
                        result.filtered_obs.tmin + result.filtered_obs.tmax) \
                        * 0.5

                    for tr_filt, tr_proc, tshift in ((result.filtered_obs,
                                                      result.processed_obs,
                                                      0.),
                                                     (result.filtered_syn,
                                                      result.processed_syn,
                                                      result.tshift)):

                        norm = num.sum(num.abs(tr_proc.ydata)) \
                            / tr_proc.data_len()
                        tr_filt.ydata /= norm
                        tr_proc.ydata /= norm

                        tr_filt.shift(tshift)
                        tr_proc.shift(tshift)

                    ctr = result.cc
                    ctr.shift(tref)

                    dtrace = ctr

                else:
                    for tr in (result.filtered_obs, result.filtered_syn,
                               result.processed_obs, result.processed_syn):

                        tr.ydata *= w

                    if result.tshift is not None and result.tshift != 0.0:
                        # result.filtered_syn.shift(result.tshift)
                        result.processed_syn.shift(result.tshift)

                    dtrace = make_norm_trace(result.processed_syn,
                                             result.processed_obs,
                                             problem.norm_exponent)

                target_to_results[target].append(result)

                dtrace.meta = dict(
                    normalisation_family=target.normalisation_family,
                    path=target.path)

                dtraces[-1].append(dtrace)

                result.processed_syn.meta = dict(
                    normalisation_family=target.normalisation_family,
                    path=target.path)

                all_syn_trs.append(result.processed_syn)

        if not all_syn_trs:
            logger.warn('no traces to show')
            return []

        def skey(tr):
            return tr.meta['normalisation_family'], tr.meta['path']

        trace_minmaxs = trace.minmax(all_syn_trs, skey)

        dtraces_all = []
        for dtraces_group in dtraces:
            dtraces_all.extend(dtraces_group)

        dminmaxs = trace.minmax(
            [dtrace_ for dtrace_ in dtraces_all if dtrace_ is not None], skey)

        for tr in dtraces_all:
            if tr:
                dmin, dmax = dminmaxs[skey(tr)]
                tr.ydata /= max(abs(dmin), abs(dmax))

        cg_to_targets = meta.gather(problem.waveform_targets,
                                    lambda t: (t.path, t.codes[3]),
                                    filter=lambda t: t in target_to_results)

        cgs = sorted(cg_to_targets.keys())

        from matplotlib import colors
        cmap = cm.ScalarMappable(norm=colors.Normalize(vmin=num.min(icolor),
                                                       vmax=num.max(icolor)),
                                 cmap=plt.get_cmap('coolwarm'))

        imodel_to_color = []
        for imodel in range(nmodels):
            imodel_to_color.append(cmap.to_rgba(icolor[imodel]))

        figs = []
        for cg in cgs:
            targets = cg_to_targets[cg]
            nframes = len(targets)

            nx = int(math.ceil(math.sqrt(nframes)))
            ny = (nframes - 1) // nx + 1

            nxmax = 4
            nymax = 4

            nxx = (nx - 1) // nxmax + 1
            nyy = (ny - 1) // nymax + 1

            # nz = nxx * nyy

            xs = num.arange(nx) / ((max(2, nx) - 1.0) / 2.)
            ys = num.arange(ny) / ((max(2, ny) - 1.0) / 2.)

            xs -= num.mean(xs)
            ys -= num.mean(ys)

            fxs = num.tile(xs, ny)
            fys = num.repeat(ys, nx)

            data = []

            for target in targets:
                azi = source.azibazi_to(target)[0]
                dist = source.distance_to(target)
                x = dist * num.sin(num.deg2rad(azi))
                y = dist * num.cos(num.deg2rad(azi))
                data.append((x, y, dist))

            gxs, gys, dists = num.array(data, dtype=num.float).T

            iorder = num.argsort(dists)

            gxs = gxs[iorder]
            gys = gys[iorder]
            targets_sorted = [targets[ii] for ii in iorder]

            gxs -= num.mean(gxs)
            gys -= num.mean(gys)

            gmax = max(num.max(num.abs(gys)), num.max(num.abs(gxs)))
            if gmax == 0.:
                gmax = 1.

            gxs /= gmax
            gys /= gmax

            dists = num.sqrt((fxs[num.newaxis, :] - gxs[:, num.newaxis])**2 +
                             (fys[num.newaxis, :] - gys[:, num.newaxis])**2)

            distmax = num.max(dists)

            availmask = num.ones(dists.shape[1], dtype=num.bool)
            frame_to_target = {}
            for itarget, target in enumerate(targets_sorted):
                iframe = num.argmin(
                    num.where(availmask, dists[itarget], distmax + 1.))
                availmask[iframe] = False
                iy, ix = num.unravel_index(iframe, (ny, nx))
                frame_to_target[iy, ix] = target

            figures = {}
            for iy in range(ny):
                for ix in range(nx):
                    if (iy, ix) not in frame_to_target:
                        continue

                    ixx = ix // nxmax
                    iyy = iy // nymax
                    if (iyy, ixx) not in figures:
                        title = '_'.join(x for x in cg if x)
                        item = PlotItem(name='fig_%s_%i_%i' %
                                        (title, ixx, iyy))
                        item.attributes['targets'] = []
                        figures[iyy,
                                ixx] = (item,
                                        plt.figure(figsize=self.size_inch))

                        figures[iyy, ixx][1].subplots_adjust(left=0.03,
                                                             right=1.0 - 0.03,
                                                             bottom=0.03,
                                                             top=1.0 - 0.06,
                                                             wspace=0.2,
                                                             hspace=0.2)

                        figs.append(figures[iyy, ixx])

                    item, fig = figures[iyy, ixx]

                    target = frame_to_target[iy, ix]

                    item.attributes['targets'].append(target.string_id())

                    amin, amax = trace_minmaxs[target.normalisation_family,
                                               target.path]
                    absmax = max(abs(amin), abs(amax))

                    ny_this = nymax  # min(ny, nymax)
                    nx_this = nxmax  # min(nx, nxmax)
                    i_this = (iy % ny_this) * nx_this + (ix % nx_this) + 1

                    axes2 = fig.add_subplot(ny_this, nx_this, i_this)

                    space = 0.5
                    space_factor = 1.0 + space
                    axes2.set_axis_off()
                    axes2.set_ylim(-1.05 * space_factor, 1.05)

                    axes = axes2.twinx()
                    axes.set_axis_off()

                    if target.misfit_config.domain == 'cc_max_norm':
                        axes.set_ylim(-10. * space_factor, 10.)
                    else:
                        axes.set_ylim(-absmax * 1.33 * space_factor,
                                      absmax * 1.33)

                    itarget = target_index[target]
                    for imodel, result in enumerate(target_to_results[target]):

                        syn_color = imodel_to_color[imodel]

                        dtrace = dtraces[imodel][itarget]

                        tap_color_annot = (0.35, 0.35, 0.25)
                        tap_color_edge = (0.85, 0.85, 0.80)
                        tap_color_fill = (0.95, 0.95, 0.90)

                        plot_taper(axes2,
                                   result.processed_obs.get_xdata(),
                                   result.taper,
                                   fc=tap_color_fill,
                                   ec=tap_color_edge,
                                   alpha=0.2)

                        obs_color = mpl_color('aluminium5')
                        obs_color_light = light(obs_color, 0.5)

                        plot_dtrace(axes2,
                                    dtrace,
                                    space,
                                    0.,
                                    1.,
                                    fc='none',
                                    ec=syn_color)

                        # plot_trace(
                        #     axes, result.filtered_syn,
                        #     color=syn_color_light, lw=1.0)

                        if imodel == 0:
                            plot_trace(axes,
                                       result.filtered_obs,
                                       color=obs_color_light,
                                       lw=0.75)

                        plot_trace(axes,
                                   result.processed_syn,
                                   color=syn_color,
                                   lw=1.0,
                                   alpha=0.3)

                        plot_trace(axes,
                                   result.processed_obs,
                                   color=obs_color,
                                   lw=0.75,
                                   alpha=0.3)

                        if imodel != 0:
                            continue
                        xdata = result.filtered_obs.get_xdata()
                        axes.set_xlim(xdata[0], xdata[-1])

                        tmarks = [
                            result.processed_obs.tmin,
                            result.processed_obs.tmax
                        ]

                        for tmark in tmarks:
                            axes2.plot([tmark, tmark], [-0.9, 0.1],
                                       color=tap_color_annot)

                        for tmark, text, ha in [
                            (tmarks[0], '$\\,$ ' +
                             meta.str_duration(tmarks[0] - source.time),
                             'right'),
                            (tmarks[1], '$\\Delta$ ' +
                             meta.str_duration(tmarks[1] - tmarks[0]), 'left')
                        ]:

                            axes2.annotate(
                                text,
                                xy=(tmark, -0.9),
                                xycoords='data',
                                xytext=(fontsize * 0.4 * [-1, 1][ha == 'left'],
                                        fontsize * 0.2),
                                textcoords='offset points',
                                ha=ha,
                                va='bottom',
                                color=tap_color_annot,
                                fontsize=fontsize)

                    scale_string = None

                    if target.misfit_config.domain == 'cc_max_norm':
                        scale_string = 'Syn/obs scales differ!'

                    infos = []
                    if scale_string:
                        infos.append(scale_string)

                    infos.append('.'.join(x for x in target.codes if x))
                    dist = source.distance_to(target)
                    azi = source.azibazi_to(target)[0]
                    infos.append(meta.str_dist(dist))
                    infos.append(u'%.0f\u00B0' % azi)
                    axes2.annotate('\n'.join(infos),
                                   xy=(0., 1.),
                                   xycoords='axes fraction',
                                   xytext=(2., 2.),
                                   textcoords='offset points',
                                   ha='left',
                                   va='top',
                                   fontsize=fontsize,
                                   fontstyle='normal')

            for (iyy, ixx), (_, fig) in figures.items():
                title = '.'.join(x for x in cg if x)
                if len(figures) > 1:
                    title += ' (%i/%i, %i/%i)' % (iyy + 1, nyy, ixx + 1, nxx)

                fig.suptitle(title, fontsize=fontsize_title)

        return figs