source: SHX/trunk/SeismicHandler/patches/ObsPy.py @ 400

Revision 400, 7.1 KB checked in by marcus, 13 years ago (diff)

...

  • Property svn:eol-style set to native
Line 
1# -*- coding: utf-8 -*-
2#
3# Copyright (C) 2008-2011 Marcus Walther (walther@szgrf.bgr.de)
4#
5# This file is part of Seismic Handler eXtended (SHX)
6# Full details can be found at project website http://www.seismic-handler.org/
7#
8# SHX is free software; you can redistribute it and/or modify
9# it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE as published by
10# the Free Software Foundation; either version 3 of the License, or
11# (at your option) any later version.
12#
13# SHX is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16# GNU Lesser General Public License for more details.
17#
18# You should have received a copy of the GNU Lesser General Public License
19# along with SHX (see license.txt); if not, write to the Free Software
20# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
21
22"""
23This modules defines extensions to obspy. They are patched into the
24original obspy modules at a very basic level in SeismicHandler/__init__.py
25
26This module is named ObsPy.py to prevent import loops.
27"""
28
29import numpy as np
30import math
31import time
32from obspy.core import Stream, Trace
33#from obspy.core import UTCDateTime
34
35__all__ = [
36    "patched",
37]
38
39def _streamAutoMerge(self, *args, **kwargs):
40    """
41    Call obspy's Stream merge method to fill up gaps using the latest pre-gap
42    sample value. This destroys the spectra of the data but it's common.
43    """
44    if self.traces:
45        self.merge(method=1, fill_value='latest')
46
47def streamAutoMergeInit(self, *args, **kwargs):
48    self.__shx_init__(*args, **kwargs)
49    _streamAutoMerge(self)
50
51def streamAutoMergeAppend(self, *args, **kwargs):
52    self.__shx_append(*args, **kwargs)
53    _streamAutoMerge(self, *args, **kwargs)
54
55def streamAutoMergeExtend(self, *args, **kwargs):
56    self.__shx_extend(*args, **kwargs)
57    _streamAutoMerge(self, *args, **kwargs)
58
59def streamAutoMergeInsert(self, *args, **kwargs):
60    self.__shx_insert(*args, **kwargs)
61    _streamAutoMerge(self, *args, **kwargs)
62
63def streamAutoMergeAdd(self, *args, **kwargs):
64    self.__shx_add__(*args, **kwargs)
65    _streamAutoMerge(self, *args, **kwargs)
66
67def tracePrepareDataForImage(self, width, height=None, timescale=None, zoom=1, norm="window"):
68    """
69    Preparing trace data for fast plotting. Using numpy's minmax feature - this
70    will not just downsample the data!
71
72    width : total width of plotting window in pixels
73    height : hight of plotting window in pixels
74    zoom : global zoom factor (y extension)
75    timescale : extension of current timescale (tuple of min and max)
76    norm : norm method: "window", "total" or value (effects y extension)
77    """
78    if not timescale:
79        # use trace's total dimensions
80        windowstart, windowend = (self.stats.starttime, self.stats.endtime)
81    else:
82        windowstart, windowend = timescale
83
84    # XXX
85    if not height:
86        height = 1000
87
88    # get slice for time window
89    pt = self.slice(windowstart, windowend)
90
91    duration_total = windowend - windowstart
92    duration_trace = pt.stats.endtime - pt.stats.starttime
93
94    # width of the total screen that is covered by trace data (pixels)
95    pixel_width = duration_trace * width / duration_total
96
97    # remember values for caching
98    CacheTraceID = \
99              (windowstart, windowend, "%.5f" % pixel_width, height, zoom, norm)
100    try:
101        cachedX = CacheTraceID[:3] == self.shxCacheTraceID[:3]
102        cachedY = cachedX and CacheTraceID[3:] == self.shxCacheTraceID[3:]
103    except:
104        cachedX = False
105        cachedY = False
106
107    if not cachedX:
108        # save new ID
109        self.shxCacheTraceID = CacheTraceID
110
111        # data points per pixel
112        npts = pt.stats.npts
113        dpp = int(npts / pixel_width)
114
115        # get copy of data
116        self.shxPlotData = pt.data.copy()
117    else:
118        print time.time(), "using cachedX data for", CacheTraceID[:3]
119
120    # use minmax approach if more than 4 data points per pixel
121    # self.shx_plotdata will be changed
122    if not cachedX and dpp >= 4:
123        # do integer division since array shape values cannot be floats
124        dimx = npts // dpp
125        covered = dpp * dimx
126
127        # get data for reshape operation
128        data = self.shxPlotData[:covered]
129
130        # extra treatment for remaining values
131        remaining = self.shxPlotData[covered:]
132
133        # reshape data and get min/max values
134        data.shape = dimx, dpp
135        _min = data.min(axis=1)
136        _max = data.max(axis=1)
137        # combine data
138        joined = np.append([_min], [_max], axis=0).T.flatten()
139        # handle remaining
140        if len(remaining):
141            joined = np.append(joined, [remaining.min(), remaining.max()])
142
143        print time.time(), "pixel_width", pixel_width, "minmax", "npts", npts, "dpp", dpp, "dimx", dimx, \
144              "covered", covered, "len_rest", len(remaining), "data_len", \
145              len(data), "joined", len(joined), "width", width
146
147        # At this stage the x-transformed data can be cached! If pixel_width
148        # doesn't change, the data can be reused to save time.
149        self.shxPlotData = joined
150
151    print time.time(), width, height, norm, type(self.shxPlotData)
152
153    if cachedY:
154        print time.time(), "using cachedY data for", CacheTraceID[3:]
155        return
156
157    # get basis for normation
158    if hasattr(norm, "lower"):
159        norm = norm.lower()
160        if norm == "window":
161            norm = abs(pt.max())
162        elif norm == "total":
163            norm = self.max()
164        else:
165            raise ValueError("Invalid input for normation!")
166
167    # Calculate y extension, leads to raw "image" data.
168    # Use a copy to save time if only y changes occur (e.g. zooming).
169    # Apply normation, calibration and total height factor
170    y = self.shxPlotData.copy()
171    y *= self.stats.calib / norm * height / 2 * zoom
172
173#    print self.shxPlotData.min(), self.shxPlotData.max(), y.min(), y.max()
174
175    # factor for x stretching (trade-off between pixel_width and array shape)
176    stretch = pixel_width / len(y)
177    width = int(math.ceil(pixel_width))
178
179    # calculate line data
180    # do not rely on framework axis' management -> shift/flip y-axis
181    offset = height // 2
182    lines = []
183    oldx, oldy = 0, -y[0] + offset
184
185    for i in xrange(1, len(y)):
186        newx = i * stretch
187        newy = -y[i] + offset
188        lines.append([oldx, oldy, newx, newy])
189        oldx, oldy = newx, newy
190
191    self.shxImageData = lines
192
193def __traceX(parameters):
194    """
195    Only the x axis is adopted here. Zoom, norm etc. regarding the y extension
196    is done ...
197    """
198    pass
199
200# monkey patching obspy stream class: traces are merge automatically if stream
201# get's altered.
202Stream.__shx_init__, Stream.__init__ = Stream.__init__, streamAutoMergeInit
203Stream.__shx_append, Stream.append = Stream.append, streamAutoMergeAppend
204Stream.__shx_extend, Stream.extend = Stream.extend, streamAutoMergeExtend
205Stream.__shx_insert, Stream.insert = Stream.insert, streamAutoMergeInsert
206Stream.__shx_add__, Stream.__add__ = Stream.__add__, streamAutoMergeAdd
207
208# add method for faster plotting
209Trace.shxPrepareImageData = tracePrepareDataForImage
210
211# just an indicator
212patched = True
Note: See TracBrowser for help on using the repository browser.