def call(self):
        '''Main work routine of the snuffling.'''

        by_nslc, times, tinc = self.extract()

        fframe = self.figure_frame()
        fig = fframe.gcf()

        nslcs = sorted(by_nslc.keys())

        p = None

        ncols = int(len(nslcs) / 5 + 1)
        nrows = (len(nslcs) - 1) / ncols + 1

        tmin = min(times)
        tmax = max(times)
        nt = int(round((tmax - tmin) / tinc)) + 1
        t = num.linspace(tmin, tmax, nt)

        if (tmax - tmin) < 60:
            tref = util.day_start(tmin)
            tref += math.floor((tmin - tref) / 60.) * 60.
            t -= tref
            tunit = 's'
        elif (tmax - tmin) < 3600:
            tref = util.day_start(tmin)
            tref += math.floor((tmin - tref) / 3600.) * 3600.
            t -= tref
            t /= 60.
            tunit = 'min'
        else:
            tref = util.day_start(tmin)
            t -= tref
            t /= 3600.
            tunit = 'h'

        axes = []
        for i, nslc in enumerate(nslcs):
            p = fig.add_subplot(nrows, ncols, i + 1, sharex=p, sharey=p)
            axes.append(p)
            group = by_nslc[nslc]
            f = group[0][1]

            nf = f.size
            a = num.zeros((nf, nt), dtype=num.float)
            a.fill(num.nan)
            for (t1, _, a1) in group:
                it = int(round((t1 - tmin) / tinc))
                if it < 0 or nt <= it:
                    continue

                a[:, it] = a1

            if self.color_scale == 'log':
                a = num.log(a)
                label = 'log PSD'
            elif self.color_scale == 'sqrt':
                a = num.sqrt(a)
                label = 'sqrt PSD'
            else:
                label = 'PSD'

            a = num.ma.masked_invalid(a)

            min_a = num.min(a)
            max_a = num.max(a)
            mean_a = num.mean(a)
            std_a = num.std(a)

            zmin = max(min_a, mean_a - 3.0 * std_a)
            zmax = min(max_a, mean_a + 3.0 * std_a)

            pcm = p.pcolormesh(t,
                               f,
                               a,
                               cmap=get_cmap(self.ctb_name),
                               vmin=zmin,
                               vmax=zmax)

            fmin = 2.0 / self.twin
            fmax = f[-1]

            p.set_title('.'.join(x for x in nslc if x),
                        ha='right',
                        va='top',
                        x=0.99,
                        y=0.9)

            p.grid()

            p.set_yscale('log')

            divider = make_axes_locatable(p)
            cax = divider.append_axes('right', size='2%', pad=0.2)

            cbar = fig.colorbar(pcm, cax=cax)
            cbar.set_label(label)

            if i / ncols == (len(nslcs) - 1) / ncols:
                p.set_xlabel(
                    'Time since %s [%s]' %
                    (util.time_to_str(tref, format='%Y-%m-%d %H:%M'), tunit))

            if i % ncols == 0:
                p.set_ylabel('Frequency [Hz]')

            p.set_xlim(t[0], t[-1])
            p.set_ylim(fmin, fmax)

        for i, p in enumerate(axes):

            if i / ncols != (len(nslcs) - 1) / ncols:
                for t in p.get_xticklabels():
                    t.set_visible(False)

            if i % ncols != 0:
                for t in p.get_yticklabels():
                    t.set_visible(False)
            else:
                tls = p.get_yticklabels()
                if len(tls) > 8:
                    for t in tls[1::2]:
                        t.set_visible(False)

        try:
            fig.tight_layout()
        except AttributeError:
            pass

        if self.save:
            fig.savefig(self.output_filename(dir='psd.pdf'))

        fig.canvas.draw()
Esempio n. 2
0
    def make_time_line(self, events):

        if self.cli_mode:
            import matplotlib.pyplot as plt
            self.fig = plt.figure()
        else:
            fframe = self.figure_frame()
            self.fig = fframe.gcf()

        gs = gridspec.GridSpec(
            2, 1, figure=self.fig, hspace=0.005, top=0.95)

        gs1 = gridspec.GridSpec(
            2, 2, figure=self.fig)

        ax = self.fig.add_subplot(gs[0])
        ax1 = ax.twinx()
        ax2 = self.fig.add_subplot(gs1[-1])
        ax3 = self.fig.add_subplot(gs1[-2])

        events.sort(key=lambda x: x.time)

        magnitudes = []
        i_has_magnitude = []
        for i, e in enumerate(events):
            if e.moment_tensor is not None:
                magnitude = e.moment_tensor.magnitude
            else:
                magnitude = e.magnitude

            if magnitude is not None:
                magnitudes.append(magnitude)
                i_has_magnitude.append(i)

        cum_events = num.cumsum(num.ones(len(i_has_magnitude)))
        moments = moment_tensor.magnitude_to_moment(num.array(magnitudes))
        cum_events_magnitude = num.cumsum(moments)
        times = num.array([events[i].time for i in i_has_magnitude])
        timeslabels = [datetime.datetime(1970, 1, 1) +
                       datetime.timedelta(seconds=t) for t in times]

        ax.plot(timeslabels, cum_events)
        ax.set_ylabel('Cumulative number of events')
        ax.axes.get_xaxis().set_ticklabels([])
        ax1.plot(timeslabels, cum_events_magnitude, '-b')
        ax1.set_ylabel('Cumulative moment [Nm]')
        xfmt = md.DateFormatter('%Y-%m-%d')
        ax1.xaxis.set_major_formatter(xfmt)
        ax.yaxis.label.set_color('r')
        ax1.yaxis.label.set_color('b')

        ax.grid(True)
        ax1.grid(True)

        t0 = min(times)
        if self.variation == 'daily':
            normalization = 60 * 60
            nbins = 24
            t0_day = util.day_start(t0)
            ax2.set_xlabel('hour of day')

        elif self.variation == 'annual':
            normalization = 60 * 60 * 24
            nbins = 365
            t0_day = util.year_start(t0)
            ax2.set_xlabel('day of year')

        binned = (times - t0_day) % (nbins * normalization)
        ax2.hist(binned/normalization, bins=nbins, color='grey')
        ax2.set_ylabel('Number of events')
        ax2.set_xlim((0, nbins))

        ax3.hist(magnitudes, bins=21, histtype='stepfilled')
        ax3.set_xlabel('Magnitude')
        ax3.set_ylabel('Number of events')

        if self.cli_mode:
            plt.show()
        else:
            self.fig.canvas.draw()
Esempio n. 3
0
    def call(self):
        '''Main work routine of the snuffling.'''
        self.cleanup()
        viewer = self.get_viewer()

        figs = {}
        fig_width_inch = viewer.width()
        npixel_hori = float(fig_width_inch * 50)
        xminutes = int(self.xminutes)
        xseconds = xminutes * 60

        self.nhours = 24
        nrows = int(self.nhours) * 60 / xminutes
        ynormalizations = {}
        lines_data = {}

        for traces in self.chopper_selected_traces(tinc=60 * 60,
                                                   fallback=True):
            for tr in traces:
                t0 = util.day_start(tr.tmin)
                key = (tr.nslc_id, t0)
                if key not in figs:
                    fig = self.pylab(get='figure')
                    ax = fig.add_subplot(111)
                    figs[key] = (fig, ax)
                    ynormalizations[key] = 0
                    lines_data[key] = []

                tr = tr.copy(data=True)
                ndecimate = int((xseconds / tr.deltat) / npixel_hori)
                tr.downsample(ndecimate)
                if self.prescale == 'max':
                    ynormalizations[key] = max(num.max(tr.ydata),
                                               ynormalizations[key])
                else:
                    ynormalizations[key] = max(num.std(tr.ydata),
                                               ynormalizations[key])

                if viewer.highpass:
                    tr.highpass(4, viewer.highpass)
                if viewer.lowpass and 1. / tr.deltat > 2. * viewer.lowpass:
                    tr.lowpass(4, viewer.lowpass)

                t = tr.get_xdata() - t0
                y = num.asarray(tr.get_ydata(), dtype=num.float)
                nskip = t / 3600.
                x = t % xseconds
                xdiff = num.diff(x)
                itmp = num.where(
                    num.logical_or(xdiff < 0,
                                   num.abs(xdiff - tr.deltat) > 1E-4))[0]
                indices = num.zeros(len(itmp) + 2, dtype=num.int)
                indices[1:-1] = itmp
                indices[-1] = len(y) - 1
                for i in range(len(indices) - 1):
                    istart = indices[i] + 1
                    istop = indices[i + 1]
                    lines_data[key].append(
                        (t0, x[istart:istop], y[istart:istop],
                         nskip[istart:istop]))

        ynorm = None
        if self.scale_global:
            ynorm = max(ynormalizations.values())

        for key, lines in lines_data.items():
            if not self.scale_global:
                ynorm = float(ynormalizations.get(key, 1.))

            for (t0, x, y, shifts) in lines:
                fig, ax = figs[key]
                ax.plot(x / 60.,
                        y / (ynorm / self.yscale) + shifts,
                        color='black')

                ax.set_title(util.tts(t0, format='%Y-%m-%d'))

        yticks = range(0, self.nhours + 2, 2)
        xticks = range(0, xminutes + 1, 1)
        for key, (fig, ax) in figs.items():
            ax.set_xlim(0, xminutes)
            ax.set_ylabel('Hour')
            ax.set_xlabel('Minute')
            ax.yaxis.set_ticks(yticks)
            ax.xaxis.set_ticks(xticks)
            ax.set_ylim(-0.1, 24.1)
            fig.canvas.draw()
Esempio n. 4
0
    def call(self):
        '''Main work routine of the snuffling.'''

        by_nslc, times, tinc = self.extract()

        fframe = self.figure_frame()
        fig = fframe.gcf()

        nslcs = sorted(by_nslc.keys())

        p = None

        ncols = int(len(nslcs) / 5 + 1)
        nrows = (len(nslcs)-1) / ncols + 1

        tmin = min(times)
        tmax = max(times)
        nt = int(round((tmax - tmin) / tinc)) + 1
        t = num.linspace(tmin, tmax, nt)

        if (tmax - tmin) < 60:
            tref = util.day_start(tmin)
            tref += math.floor((tmin-tref) / 60.) * 60.
            t -= tref
            tunit = 's'
        elif (tmax - tmin) < 3600:
            tref = util.day_start(tmin)
            tref += math.floor((tmin-tref) / 3600.) * 3600.
            t -= tref
            t /= 60.
            tunit = 'min'
        else:
            tref = util.day_start(tmin)
            t -= tref
            t /= 3600.
            tunit = 'h'

        axes = []
        for i, nslc in enumerate(nslcs):
            p = fig.add_subplot(nrows, ncols, i+1, sharex=p, sharey=p)
            axes.append(p)
            group = by_nslc[nslc]
            f = group[0][1]

            nf = f.size
            a = num.zeros((nf, nt), dtype=num.float)
            a.fill(num.nan)
            for (t1, _, a1) in group:
                it = int(round((t1 - tmin) / tinc))
                if it < 0 or nt <= it:
                    continue

                a[:, it] = a1

            if self.color_scale == 'log':
                a = num.log(a)
                label = 'log PSD'
            elif self.color_scale == 'sqrt':
                a = num.sqrt(a)
                label = 'sqrt PSD'
            else:
                label = 'PSD'

            a = num.ma.masked_invalid(a)

            min_a = num.min(a)
            max_a = num.max(a)
            mean_a = num.mean(a)
            std_a = num.std(a)

            zmin = max(min_a, mean_a - 3.0 * std_a)
            zmax = min(max_a, mean_a + 3.0 * std_a)

            pcm = p.pcolormesh(t, f, a, cmap=get_cmap(self.ctb_name),
                               vmin=zmin, vmax=zmax)

            fmin = 2.0 / self.twin
            fmax = f[-1]

            p.set_title(
                '.'.join(x for x in nslc if x),
                ha='right',
                va='top',
                x=0.99,
                y=0.9)

            p.grid()

            p.set_yscale('log')

            divider = make_axes_locatable(p)
            cax = divider.append_axes('right', size='2%', pad=0.2)

            cbar = fig.colorbar(pcm, cax=cax)
            cbar.set_label(label)

            if i/ncols == (len(nslcs)-1)/ncols:
                p.set_xlabel('Time since %s [%s]' %
                             (util.time_to_str(tref, format='%Y-%m-%d %H:%M'),
                              tunit))

            if i % ncols == 0:
                p.set_ylabel('Frequency [Hz]')

            p.set_xlim(t[0], t[-1])
            p.set_ylim(fmin, fmax)

        for i, p in enumerate(axes):

            if i/ncols != (len(nslcs)-1)/ncols:
                for t in p.get_xticklabels():
                    t.set_visible(False)

            if i % ncols != 0:
                for t in p.get_yticklabels():
                    t.set_visible(False)
            else:
                tls = p.get_yticklabels()
                if len(tls) > 8:
                    for t in tls[1::2]:
                        t.set_visible(False)

        try:
            fig.tight_layout()
        except AttributeError:
            pass

        if self.save:
            fig.savefig(self.output_filename(dir='psd.pdf'))

        fig.canvas.draw()
Esempio n. 5
0
    def make_time_line(self, events):

        if self.cli_mode:
            import matplotlib.pyplot as plt
            self.fig = plt.figure()
        else:
            fframe = self.figure_frame()
            self.fig = fframe.gcf()

        gs = gridspec.GridSpec(2, 1)
        gs.update(hspace=0.005, top=0.95)
        gs1 = gridspec.GridSpec(2, 1)
        gs1.update(bottom=0.06, hspace=0.01)

        ax = self.fig.add_subplot(gs[0])
        ax1 = ax.twinx()
        ax2 = self.fig.add_subplot(gs1[-1])
        events.sort(key=lambda x: x.time)
        magnitudes = []
        cum_events = num.cumsum(num.ones(len(events)))

        for e in events:
            if e.moment_tensor is not None:
                magnitudes.append(e.moment_tensor.magnitude)
            else:
                magnitudes.append(e.magnitude)
            if magnitudes[-1] is None:
                magnitudes.pop()
                magnitudes.append(0.)

        magnitudes = moment_tensor.magnitude_to_moment(num.array(magnitudes))
        cum_events_magnitude = num.cumsum(magnitudes)
        times = num.array([e.time for e in events])
        timeslabels = [datetime.datetime(1970, 1, 1) +
                       datetime.timedelta(seconds=t) for t in times]

        ax.plot(timeslabels, cum_events)
        ax.set_ylabel('Cumulative number of events')
        ax.axes.get_xaxis().set_ticklabels([])
        ax1.plot(timeslabels, cum_events_magnitude, '-b')
        ax1.set_ylabel('Cumulative moment [Nm]')
        xfmt = md.DateFormatter('%Y-%m-%d')
        ax1.xaxis.set_major_formatter(xfmt)
        ax.yaxis.label.set_color('r')
        ax1.yaxis.label.set_color('b')

        ax.grid(True)
        ax1.grid(True)

        t0 = min(times)
        if self.variation == 'daily':
            normalization = 60 * 60
            nbins = 24
            t0_day = util.day_start(t0)
            ax2.set_xlabel('hour of day')

        elif self.variation == 'annual':
            normalization = 60 * 60 * 24
            nbins = 365
            t0_day = util.year_start(t0)
            ax2.set_xlabel('day of year')

        binned = (times - t0_day) % (nbins * normalization)
        ax2.hist(binned/normalization, bins=nbins, color='grey')
        ax2.set_ylabel('Number of events')
        ax2.set_xlim((0, nbins))

        if self.cli_mode:
            plt.show()
        else:
            self.fig.canvas.draw()
Esempio n. 6
0
def analyse_gps_tags(header, gps_tags, offset, nsamples):

    ipos, t, fix, nsvs = gps_tags
    deltat = 1.0 / int(header['S_RATE'])

    tquartz = offset + ipos * deltat

    toff = t - tquartz
    toff_median = num.median(toff)

    n = t.size

    dtdt = (t[1:n] - t[0:n-1]) / (tquartz[1:n] - tquartz[0:n-1])

    ok = abs(toff_median - toff) < 10.

    xok = num.abs(dtdt - 1.0) < 0.00001

    ok[0] = False
    ok[1:n] &= xok
    ok[0:n-1] &= xok
    ok[n-1] = False

    ipos = ipos[ok]
    t = t[ok]
    fix = fix[ok]
    nsvs = nsvs[ok]

    blocksize = N_GPS_TAGS_WANTED // 2

    try:
        if ipos.size < blocksize:
            raise ControlPointError(
                'could not safely determine time corrections from gps')

        j = 0
        control_points = []
        tref = num.median(t - ipos*deltat)
        while j < ipos.size - blocksize:
            ipos_block = ipos[j:j+blocksize]
            t_block = t[j:j+blocksize]
            try:
                ic, tc = make_control_point(ipos_block, t_block, tref, deltat)
                control_points.append((ic, tc))
            except ControlPointError:
                pass
            j += blocksize

        ipos_last = ipos[-blocksize:]
        t_last = t[-blocksize:]
        try:
            ic, tc = make_control_point(ipos_last, t_last, tref, deltat)
            control_points.append((ic, tc))
        except ControlPointError:
            pass

        if len(control_points) < 2:
            raise ControlPointError(
                'could not safely determine time corrections from gps')

        i0, t0 = control_points[0]
        i1, t1 = control_points[1]
        i2, t2 = control_points[-2]
        i3, t3 = control_points[-1]
        if len(control_points) == 2:
            tmin = t0 - i0 * deltat - offset * deltat
            tmax = t3 + (nsamples - i3 - 1) * deltat
        else:
            icontrol = num.array(
                [x[0] for x in control_points], dtype=num.int64)
            tcontrol = num.array(
                [x[1] for x in control_points], dtype=num.float)
            # robust against steps:
            slope = num.median(
                (tcontrol[1:] - tcontrol[:-1])
                / (icontrol[1:] - icontrol[:-1]))

            tmin = t0 + (offset - i0) * slope
            tmax = t2 + (offset + nsamples - 1 - i2) * slope

        if offset < i0:
            control_points[0:0] = [(offset, tmin)]

        if offset + nsamples - 1 > i3:
            control_points.append((offset + nsamples - 1, tmax))

        icontrol = num.array([x[0] for x in control_points], dtype=num.int64)
        tcontrol = num.array([x[1] for x in control_points], dtype=num.float)

        return tmin, tmax, icontrol, tcontrol, ok

    except ControlPointError:

        tmin = util.str_to_time(header['S_DATE'] + header['S_TIME'],
                                format='%y/%m/%d%H:%M:%S')

        idat = int(header['DAT_NO'])
        if idat == 0:
            tmin = tmin + util.gps_utc_offset(tmin)
        else:
            tmin = util.day_start(tmin + idat * 24.*3600.) \
                + util.gps_utc_offset(tmin)

        tmax = tmin + (nsamples - 1) * deltat
        icontrol, tcontrol = None, None
        return tmin, tmax, icontrol, tcontrol, None
Esempio n. 7
0
    def call(self):
        '''Main work routine of the snuffling.'''

        by_nslc = {}
        tpad = self.twin * self.overlap/100. * 0.5
        tinc = self.twin - 2 * tpad
        times = []
        for traces in self.chopper_selected_traces(
                tinc=tinc, tpad=tpad, want_incomplete=False, fallback=True):

            for tr in traces:
                nslc = tr.nslc_id
                nwant = int(math.floor((tinc + 2*tpad) / tr.deltat))

                if nwant != tr.data_len():
                    if tr.data_len() == nwant + 1:
                        tr.set_ydata(tr.get_ydata()[:-1])
                    else:
                        continue

                tr.ydata = tr.ydata.astype(num.float)
                tr.ydata -= tr.ydata.mean()

                win = self.get_taper(self.taper_name, tr.data_len())
                tr.ydata *= win

                f, a = tr.spectrum(pad_to_pow2=True)
                df = f[1] - f[0]
                a = num.abs(a)**2
                a *= tr.deltat * 2. / (df*num.sum(win**2))
                a[0] /= 2.
                a[a.size/2] /= 2.

                if nslc not in by_nslc:
                    by_nslc[nslc] = []

                tmid = 0.5*(tr.tmax + tr.tmin)
                by_nslc[nslc].append((tmid, f, a))
                times.append(tmid)

        if not by_nslc:
            self.fail('No complete data windows could be exctracted for '
                      'given selection')

        fframe = self.figure_frame()
        fig = fframe.gcf()

        nslcs = sorted(by_nslc.keys())

        p = None

        ncols = len(nslcs) / 5 + 1
        nrows = (len(nslcs)-1) / ncols + 1

        tmin = min(times)
        tmax = max(times)
        nt = int(round((tmax - tmin) / tinc)) + 1
        t = num.linspace(tmin, tmax, nt)

        if (tmax - tmin) < 60:
            tref = util.day_start(tmin)
            tref += math.floor((tmin-tref) / 60.) * 60.
            t -= tref
            tunit = 's'
        elif (tmax - tmin) < 3600:
            tref = util.day_start(tmin)
            tref += math.floor((tmin-tref) / 3600.) * 3600.
            t -= tref
            t /= 60.
            tunit = 'min'
        else:
            tref = util.day_start(tmin)
            t -= tref
            t /= 3600.
            tunit = 'h'

        axes = []
        for i, nslc in enumerate(nslcs):
            p = fig.add_subplot(nrows, ncols, i+1, sharex=p, sharey=p)
            axes.append(p)
            group = by_nslc[nslc]
            f = group[0][1]

            nf = f.size
            a = num.zeros((nf, nt), dtype=num.float)
            a.fill(num.nan)
            for (t1, _, a1) in group:
                it = int(round((t1 - tmin) / tinc))
                if it < 0 or nt <= it:
                    continue

                a[:, it] = a1

            if self.color_scale == 'log':
                a = num.log(a)
                label = 'log PSD'
            elif self.color_scale == 'sqrt':
                a = num.sqrt(a)
                label = 'sqrt PSD'
            else:
                label = 'PSD'

            a = num.ma.masked_invalid(a)

            min_a = num.min(a)
            max_a = num.max(a)
            mean_a = num.mean(a)
            std_a = num.std(a)

            zmin = max(min_a, mean_a - 3.0 * std_a)
            zmax = min(max_a, mean_a + 3.0 * std_a)

            pcm = p.pcolormesh(t, f, a, cmap=get_cmap(self.ctb_name),
                               vmin=zmin, vmax=zmax)

            fmin = 2.0 / self.twin
            fmax = f[-1]

            p.set_title(
                '.'.join(x for x in nslc if x),
                ha='right',
                va='top',
                x=0.99,
                y=0.9)

            p.grid()

            p.set_yscale('log')

            divider = make_axes_locatable(p)
            cax = divider.append_axes('right', size='2%', pad=0.2)

            cbar = fig.colorbar(pcm, cax=cax)
            cbar.set_label(label)

            if i/ncols == (len(nslcs)-1)/ncols:
                p.set_xlabel('Time since %s [%s]' %
                             (util.time_to_str(tref, format='%Y-%m-%d %H:%M'),
                              tunit))

            if i % ncols == 0:
                p.set_ylabel('Frequency [Hz]')

            p.set_xlim(t[0], t[-1])
            p.set_ylim(fmin, fmax)

        for i, p in enumerate(axes):

            if i/ncols != (len(nslcs)-1)/ncols:
                for t in p.get_xticklabels():
                    t.set_visible(False)

            if i % ncols != 0:
                for t in p.get_yticklabels():
                    t.set_visible(False)
            else:
                tls = p.get_yticklabels()
                if len(tls) > 8:
                    for t in tls[1::2]:
                        t.set_visible(False)

        try:
            fig.tight_layout()
        except AttributeError:
            pass

        if self.save:
            fig.savefig(self.output_filename(dir='psd.pdf'))

        fig.canvas.draw()
Esempio n. 8
0
# Download example data
get_example_data('data_conversion', recursive=True)

input_path = 'data_conversion/mseed'
output_path = 'data_conversion/sac/' \
        '%(dirhz)s/%(station)s_%(channel)s_%(tmin)s.sac'

fn_stations = 'data_conversion/stations.txt'

stations_list = model.load_stations(fn_stations)

stations = {}
for s in stations_list:
    stations[s.network, s.station, s.location] = s
    s.set_channels_by_name(*'BHN BHE BHZ BLN BLE BLZ'.split())

p = pile.make_pile(input_path)
h = 3600.
tinc = 1 * h
tmin = util.day_start(p.tmin)
for traces in p.chopper_grouped(tmin=tmin,
                                tinc=tinc,
                                gather=lambda tr: tr.nslc_id):
    for tr in traces:
        dirhz = '%ihz' % int(round(1. / tr.deltat))
        io.save([tr],
                output_path,
                format='sac',
                additional={'dirhz': dirhz},
                stations=stations)
    def call(self):
        '''Main work routine of the snuffling.'''
        self.cleanup()
        viewer = self.get_viewer()

        figs = {}
        fig_width_inch = viewer.width()
        npixel_hori = float(fig_width_inch*50)
        xminutes = int(self.xminutes)
        xseconds = xminutes * 60

        self.nhours = 24
        nrows = int(self.nhours) * 60 / xminutes
        ynormalizations = {}
        lines_data = {}

        for traces in self.chopper_selected_traces(tinc=60*60, fallback=True):
            for tr in traces:
                t0 = util.day_start(tr.tmin)
                key = (tr.nslc_id, t0)
                if key not in figs:
                    fig = self.pylab(get='figure')
                    ax = fig.add_subplot(111)
                    figs[key] = (fig, ax)
                    ynormalizations[key] = 0
                    lines_data[key] = []

                tr = tr.copy(data=True)
                ndecimate = int((xseconds/tr.deltat) / npixel_hori)
                tr.downsample(ndecimate)
                if self.prescale == 'max':
                    ynormalizations[key] = max(num.max(tr.ydata), ynormalizations[key])
                else:
                    ynormalizations[key] = max(num.std(tr.ydata), ynormalizations[key])

                if viewer.highpass:
                    tr.highpass(4, viewer.highpass)
                if viewer.lowpass and 1./tr.deltat>2.*viewer.lowpass:
                    tr.lowpass(4, viewer.lowpass)

                t = tr.get_xdata() - t0
                y = num.asarray(tr.get_ydata(), dtype=num.float)
                nskip = t / 3600.
                x = t % xseconds
                xdiff = num.diff(x) 
                itmp = num.where(num.logical_or(xdiff < 0, num.abs(xdiff-tr.deltat) > 1E-4))[0]
                indices = num.zeros(len(itmp)+2, dtype=num.int)
                indices[1:-1] = itmp
                indices[-1] = len(y)-1
                for i in range(len(indices)-1):
                    istart = indices[i] + 1
                    istop = indices[i+1]
                    lines_data[key].append(
                        (t0, x[istart: istop], y[istart: istop],
                         nskip[istart: istop])
                    )

        ynorm = None
        if self.scale_global:
            ynorm = max(ynormalizations.values())

        for key, lines in lines_data.items():
            if not self.scale_global:
                ynorm = float(ynormalizations.get(key, 1.))

            for (t0, x, y, shifts) in lines:
                fig, ax = figs[key]
                ax.plot(
                    x/60.,
                    y/(ynorm/self.yscale) + shifts,
                    color='black')

                ax.set_title(util.tts(t0, format='%Y-%m-%d'))
        
        yticks = range(0, self.nhours+2, 2)
        xticks = range(0, xminutes+1, 1)
        for key, (fig, ax) in figs.items():
            ax.set_xlim(0, xminutes)
            ax.set_ylabel('Hour')
            ax.set_xlabel('Minute')
            ax.yaxis.set_ticks(yticks)
            ax.xaxis.set_ticks(xticks)
            ax.set_ylim(-0.1, 24.1)
            fig.canvas.draw()
# Download example data
get_example_data('data_conversion', recursive=True)

input_path = 'data_conversion/mseed'
output_path = 'data_conversion/sac/' \
        '%(dirhz)s/%(station)s_%(channel)s_%(tmin)s.sac'

fn_stations = 'data_conversion/stations.txt'

stations_list = model.load_stations(fn_stations)

stations = {}
for s in stations_list:
    stations[s.network, s.station, s.location] = s
    s.set_channels_by_name(*'BHN BHE BHZ BLN BLE BLZ'.split())

p = pile.make_pile(input_path)
h = 3600.
tinc = 1*h
tmin = util.day_start(p.tmin)
for traces in p.chopper_grouped(tmin=tmin, tinc=tinc,
                                gather=lambda tr: tr.nslc_id):
    for tr in traces:
        dirhz = '%ihz' % int(round(1./tr.deltat))
        io.save(
            [tr], output_path,
            format='sac',
            additional={'dirhz': dirhz},
            stations=stations
        )