def main(argv=None): parser = ArgumentParser(prog='obspy-print', description=__doc__.strip()) parser.add_argument('-V', '--version', action='version', version='%(prog)s ' + __version__) parser.add_argument('-f', '--format', choices=ENTRY_POINTS['waveform'], help='Waveform format (slightly faster if specified).') parser.add_argument('-n', '--no-merge', action='store_false', dest='merge', help='Switch off cleanup merge.') parser.add_argument('--no-sorting', action='store_false', dest='sort', help='Switch off sorting of traces.') parser.add_argument('-g', '--print-gaps', action='store_true', help='Switch on printing of gap information.') parser.add_argument('files', nargs='+', help='Files to process.') # Deprecated arguments action = _get_deprecated_argument_action( '--nomerge', '--no-merge', real_action='store_false') parser.add_argument('--nomerge', nargs=0, action=action, dest='merge', help=SUPPRESS) args = parser.parse_args(argv) st = Stream() for f in args.files: st += read(f, format=args.format) if args.merge: st.merge(-1) if args.sort: st.sort() print(st.__str__(extended=True)) if args.print_gaps: print() st.printGaps()
def main(argv=None): parser = ArgumentParser(prog='obspy-dataless2xseed', description=__doc__.strip()) parser.add_argument('-V', '--version', action='version', version='%(prog)s ' + __version__) parser.add_argument('-s', '--split-stations', action='store_true', help='split multiple stations within one dataless ' 'file into multiple XML-SEED files, labeled with ' 'the start time of the volume.') parser.add_argument('-d', '--debug', action='store_true', help='show debugging information') parser.add_argument('-q', '--quiet', action='store_false', dest='verbose', help='non verbose mode') parser.add_argument('-o', '--output', default=None, help='output filename or directory') parser.add_argument('-x', '--xml-version', dest='version', default=1.1, help='XML-SEED version, 1.0 or 1.1', type=float) parser.add_argument('files', nargs='+', help='files to process') # Deprecated arguments action = _get_deprecated_argument_action('-v', '--xml-version') parser.add_argument('-v', dest='version', default=1.1, type=float, action=action, help=SUPPRESS) args = parser.parse_args(argv) dataless2xseed(args.files, args)
def main(argv=None): parser = ArgumentParser(prog='obspy-print', description=__doc__.strip()) parser.add_argument('-V', '--version', action='version', version='%(prog)s ' + __version__) parser.add_argument('-f', '--format', choices=ENTRY_POINTS['waveform'], help='Waveform format (slightly faster if specified).') parser.add_argument('-n', '--no-merge', action='store_false', dest='merge', help='Switch off cleanup merge.') parser.add_argument('--no-sorting', action='store_false', dest='sort', help='Switch off sorting of traces.') parser.add_argument('-g', '--print-gaps', action='store_true', help='Switch on printing of gap information.') parser.add_argument('files', nargs='+', help='Files to process.') # Deprecated arguments action = _get_deprecated_argument_action('--nomerge', '--no-merge', real_action='store_false') parser.add_argument('--nomerge', nargs=0, action=action, dest='merge', help=SUPPRESS) args = parser.parse_args(argv) st = Stream() for f in args.files: st += read(f, format=args.format) if args.merge: st.merge(-1) if args.sort: st.sort() print(st.__str__(extended=True)) if args.print_gaps: print() st.printGaps()
def main(argv=None): parser = ArgumentParser(prog='obspy-indexer', description='\n'.join(__doc__.split('\n')[:3])) parser.add_argument('-V', '--version', action='version', version="%(prog)s " + __version__) parser.add_argument('-v', '--verbose', action='store_true', help='Verbose output.') parser.add_argument( '-d', '--data', default='data=*.*', help="""Path, search patterns and feature plug-ins of waveform files. The indexer will crawl recursively through all sub-directories within each given path. Multiple paths have to be separated with a comma, e.g. '/first/path=*.*,/second/path,/third/path=*.gse'. File patterns are given as space-separated list of wildcards after a equal sign, e.g. '/path=*.gse2 *.mseed,/second/path=*.*'. Feature plug-ins may be added using the hash (#) character, e.g. '/path=*.mseed#feature1#feature2,/second/path#feature2'. Be aware that features must be provided behind file patterns (if any)! There is no default feature enabled. Default path option is 'data=*.*'.""") parser.add_argument('-u', '--db-uri', default='sqlite:///indexer.sqlite', help="Database connection URI, such as " "postgresql://*****:*****@localhost/mydatabase. " "Default is a SQLite database './indexer.sqlite'.") parser.add_argument('-n', type=int, dest='number_of_cpus', help="Number of CPUs used for the indexer.", default=multiprocessing.cpu_count()) parser.add_argument( '-i', '--poll-interval', type=float, default=0.1, help="Poll interval for file crawler in seconds (default is 0.1).") parser.add_argument( '-r', '--recent', type=int, default=0, help="Index only recent files modified within the given " "number of hours. This option is deactivated by default.") parser.add_argument( '-l', '--log', default='', help="Log file name. If no log file is given, stdout will be used.") parser.add_argument( '-m', '--mapping-file', default=None, help="Correct network, station, location and channel codes using a" + " custom mapping file.") parser.add_argument('-a', '--all-files', action='store_false', dest='skip_dots', help="The indexer will automatically skip paths or " "files starting with a dot. This option forces " "parsing of all paths and files.") parser.add_argument( '-1', '--run-once', action='store_true', help="The indexer will parse through all given directories only " "once and quit afterwards.") parser.add_argument('--check-duplicates', action='store_true', help="Checks for duplicate entries within database. " "This feature will slow down the indexer progress.") parser.add_argument( '--cleanup', action='store_true', help="Clean database from non-existing files or paths " + "if activated, but will skip all paths marked as " + "archived in the database.") parser.add_argument( '-f', '--force-reindex', action='store_true', help="Reindex existing index entry for every crawled file.") parser.add_argument( '--drop-database', action='store_true', help="Deletes and recreates the complete database at start up.") parser.add_argument('-H', '--host', default='localhost', help="Server host name. Default is 'localhost'.") parser.add_argument( '-p', '--port', type=int, default=0, help="Port number. If not given a free port will be picked.") # Deprecated arguments action = _get_deprecated_argument_action('--check_duplicates', '--check-duplicates', real_action='store_true') parser.add_argument('--check_duplicates', nargs=0, action=action, help=SUPPRESS) action = _get_deprecated_argument_action('--drop_database', '--drop-database', real_action='store_true') parser.add_argument('--drop_database', nargs=0, action=action, help=SUPPRESS) action = _get_deprecated_argument_action('--mapping_file', '--mapping-file') parser.add_argument('--mapping_file', action=action, help=SUPPRESS) action = _get_deprecated_argument_action('--run_once', '--run-once', real_action='store_true') parser.add_argument('--run_once', nargs=0, action=action, help=SUPPRESS) args = parser.parse_args(argv) # set level of verbosity if args.verbose: level = logging.DEBUG else: level = logging.INFO if args.log == "": logging.basicConfig(stream=sys.stdout, level=level, format="%(asctime)s [%(levelname)s] %(message)s") else: logging.basicConfig(filename=options.log, level=level, format="%(asctime)s [%(levelname)s] %(message)s") _runIndexer(args)
def main(argv=None): parser = ArgumentParser(prog='obspy-scan', description=__doc__.strip(), formatter_class=RawDescriptionHelpFormatter) parser.add_argument('-V', '--version', action='version', version='%(prog)s ' + __version__) parser.add_argument('-f', '--format', choices=ENTRY_POINTS['waveform'], help='Optional, the file format.\n' + ' '.join(__doc__.split('\n')[-4:])) parser.add_argument('-v', '--verbose', action='store_true', help='Optional. Verbose output.') parser.add_argument('-q', '--quiet', action='store_true', help='Optional. Be quiet. Overwritten by --verbose ' 'flag.') parser.add_argument('-n', '--non-recursive', action='store_false', dest='recursive', help='Optional. Do not descend into directories.') parser.add_argument('-i', '--ignore-links', action='store_true', help='Optional. Do not follow symbolic links.') parser.add_argument('--start-time', default=None, type=UTCDateTime, help='Optional, a UTCDateTime compatible string. ' + 'Only visualize data after this time and set ' + 'time-axis axis accordingly.') parser.add_argument('--end-time', default=None, type=UTCDateTime, help='Optional, a UTCDateTime compatible string. ' + 'Only visualize data before this time and set ' + 'time-axis axis accordingly.') parser.add_argument('--id', action='append', help='Optional, a SEED channel identifier ' "(e.g. 'GR.FUR..HHZ'). You may provide this " + 'option multiple times. Only these ' + 'channels will be plotted.') parser.add_argument('-t', '--event-time', default=None, type=UTCDateTime, action='append', help='Optional, a UTCDateTime compatible string ' + "(e.g. '2010-01-01T12:00:00'). You may provide " + 'this option multiple times. These times get ' + 'marked by vertical lines in the plot. ' + 'Useful e.g. to mark event origin times.') parser.add_argument('-w', '--write', default=None, help='Optional, npz file for writing data ' 'after scanning waveform files') parser.add_argument('-l', '--load', default=None, help='Optional, npz file for loading data ' 'before scanning waveform files') parser.add_argument('--no-x', action='store_true', help='Optional, Do not plot crosses.') parser.add_argument('--no-gaps', action='store_true', help='Optional, Do not plot gaps.') parser.add_argument('-o', '--output', default=None, help='Save plot to image file (e.g. out.pdf, ' + 'out.png) instead of opening a window.') parser.add_argument('--print-gaps', action='store_true', help='Optional, prints a list of gaps at the end.') parser.add_argument('paths', nargs='*', help='Files or directories to scan.') # Deprecated arguments action = _get_deprecated_argument_action('--endtime', '--end-time') parser.add_argument('--endtime', type=UTCDateTime, action=action, help=SUPPRESS) action = _get_deprecated_argument_action('--event-times', '--event-time') parser.add_argument('--event-times', action=action, help=SUPPRESS) action = _get_deprecated_argument_action('--ids', '--id') parser.add_argument('--ids', action=action, help=SUPPRESS) action = _get_deprecated_argument_action('--nox', '--no-x', real_action='store_true') parser.add_argument('--nox', dest='no_x', nargs=0, action=action, help=SUPPRESS) action = _get_deprecated_argument_action('--nogaps', '--no-gaps', real_action='store_true') parser.add_argument('--nogaps', dest='no_gaps', nargs=0, action=action, help=SUPPRESS) action = _get_deprecated_argument_action('--starttime', '--start-time') parser.add_argument('--starttime', type=UTCDateTime, action=action, help=SUPPRESS) args = parser.parse_args(argv) if args.output is not None: MatplotlibBackend.switch_backend("AGG", sloppy=False) # Print help and exit if no arguments are given if len(args.paths) == 0 and args.load is None: parser.error('No paths specified.') # Use recursively parsing function? if args.recursive: parse_func = recursive_parse else: parse_func = parse_file_to_dict from matplotlib.dates import date2num, num2date from matplotlib.ticker import FuncFormatter from matplotlib.patches import Rectangle from matplotlib.collections import PatchCollection import matplotlib.pyplot as plt fig = plt.figure() ax = fig.add_subplot(111) # Plot vertical lines if option 'event_times' was specified if args.event_time: times = [date2num(t.datetime) for t in args.event_time] for time in times: ax.axvline(time, color='k') # Deprecated version (don't plot twice) if args.event_times and not args.event_time: times = args.event_times.split(',') times = [date2num(UTCDateTime(t).datetime) for t in times] for time in times: ax.axvline(time, color='k') if args.start_time: args.start_time = date2num(args.start_time.datetime) elif args.starttime: # Deprecated version args.start_time = date2num(args.starttime.datetime) if args.end_time: args.end_time = date2num(args.end_time.datetime) elif args.endtime: # Deprecated version args.end_time = date2num(args.endtime.datetime) # Generate dictionary containing nested lists of start and end times per # station data = {} samp_int = {} counter = 1 if args.load: load_npz(args.load, data, samp_int) for path in args.paths: counter = parse_func(data, samp_int, path, counter, args.format, verbose=args.verbose, quiet=args.quiet, ignore_links=args.ignore_links) if not data: if args.verbose or not args.quiet: print("No waveform data found.") return if args.write: write_npz(args.write, data, samp_int) # Loop through this dictionary ids = list(data.keys()) # Handle deprecated argument if args.ids and not args.id: args.id = args.ids.split(',') # restrict plotting of results to given ids if args.id: ids = [x for x in ids if x in args.id] ids = sorted(ids)[::-1] labels = [""] * len(ids) if args.verbose or not args.quiet: print('\n') for _i, _id in enumerate(ids): labels[_i] = ids[_i] # sort data list and sampling rate list startend = np.array(data[_id]) _samp_int = np.array(samp_int[_id]) indices = np.lexsort((startend[:, 1], startend[:, 0])) startend = startend[indices] _samp_int = _samp_int[indices] if len(startend) == 0: continue # restrict plotting of results to given start/end time if args.start_time: indices = startend[:, 1] > args.start_time startend = startend[indices] _samp_int = _samp_int[indices] if len(startend) == 0: continue if args.end_time: indices = startend[:, 0] < args.end_time startend = startend[indices] _samp_int = _samp_int[indices] if len(startend) == 0: continue timerange = startend[:, 1].max() - startend[:, 0].min() if timerange == 0.0: warnings.warn('Zero sample long data for _id=%s, skipping' % _id) continue startend_compressed = compressStartend(startend, 1000) offset = np.ones(len(startend)) * _i # generate list of y values if not args.no_x: ax.plot(startend[:, 0], offset, 'x', linewidth=2) ax.hlines(offset[:len(startend_compressed)], startend_compressed[:, 0], startend_compressed[:, 1], 'b', linewidth=2, zorder=3) # find the gaps diffs = startend[1:, 0] - startend[:-1, 1] # currend.start - last.end gapsum = diffs[diffs > 0].sum() perc = (timerange - gapsum) / timerange labels[_i] = labels[_i] + "\n%.1f%%" % (perc * 100) gap_indices = diffs > 1.8 * _samp_int[:-1] gap_indices = np.concatenate((gap_indices, [False])) if any(gap_indices): # don't handle last end time as start of gap gaps_start = startend[gap_indices, 1] gaps_end = startend[np.roll(gap_indices, 1), 0] if not args.no_gaps and any(gap_indices): rects = [ Rectangle((start_, offset[0] - 0.4), end_ - start_, 0.8) for start_, end_ in zip(gaps_start, gaps_end) ] ax.add_collection(PatchCollection(rects, color="r")) if args.print_gaps: for start_, end_ in zip(gaps_start, gaps_end): start_, end_ = num2date((start_, end_)) start_ = UTCDateTime(start_.isoformat()) end_ = UTCDateTime(end_.isoformat()) if args.verbose or not args.quiet: print("%s %s %s %.3f" % (_id, start_, end_, end_ - start_)) # Pretty format the plot ax.set_ylim(0 - 0.5, _i + 0.5) ax.set_yticks(np.arange(_i + 1)) ax.set_yticklabels(labels, family="monospace", ha="right") fig.autofmt_xdate() # rotate date ax.xaxis_date() # set custom formatters to always show date in first tick formatter = ObsPyAutoDateFormatter(ax.xaxis.get_major_locator()) formatter.scaled[1 / 24.] = \ FuncFormatter(decimal_seconds_format_date_first_tick) formatter.scaled.pop(1 / (24. * 60.)) ax.xaxis.set_major_formatter(formatter) plt.subplots_adjust(left=0.2) # set x-axis limits according to given start/end time if args.start_time and args.end_time: ax.set_xlim(left=args.start_time, right=args.end_time) elif args.start_time: ax.set_xlim(left=args.start_time, auto=None) elif args.end_time: ax.set_xlim(right=args.end_time, auto=None) else: left, right = ax.xaxis.get_data_interval() x_axis_range = right - left ax.set_xlim(left - 0.05 * x_axis_range, right + 0.05 * x_axis_range) if args.output is None: plt.show() else: fig.set_dpi(72) height = len(ids) * 0.5 height = max(4, height) fig.set_figheight(height) plt.tight_layout() if not args.start_time or not args.end_time: days = ax.get_xlim() days = days[1] - days[0] else: days = args.end_time - args.start_time width = max(6, days / 30.) width = min(width, height * 4) fig.set_figwidth(width) plt.subplots_adjust(top=1, bottom=0, left=0, right=1) plt.tight_layout() fig.savefig(args.output) if args.verbose and not args.quiet: sys.stdout.write('\n')
def main(argv=None): parser = ArgumentParser(prog='obspy-indexer', description='\n'.join(__doc__.split('\n')[:3])) parser.add_argument('-V', '--version', action='version', version="%(prog)s " + __version__) parser.add_argument( '-v', '--verbose', action='store_true', help='Verbose output.') parser.add_argument( '-d', '--data', default='data=*.*', help="""Path, search patterns and feature plug-ins of waveform files. The indexer will crawl recursively through all sub-directories within each given path. Multiple paths have to be separated with a comma, e.g. '/first/path=*.*,/second/path,/third/path=*.gse'. File patterns are given as space-separated list of wildcards after a equal sign, e.g. '/path=*.gse2 *.mseed,/second/path=*.*'. Feature plug-ins may be added using the hash (#) character, e.g. '/path=*.mseed#feature1#feature2,/second/path#feature2'. Be aware that features must be provided behind file patterns (if any)! There is no default feature enabled. Default path option is 'data=*.*'.""") parser.add_argument( '-u', '--db-uri', default='sqlite:///indexer.sqlite', help="Database connection URI, such as " "postgresql://*****:*****@localhost/mydatabase. " "Default is a SQLite database './indexer.sqlite'.") parser.add_argument( '-n', type=int, dest='number_of_cpus', help="Number of CPUs used for the indexer.", default=multiprocessing.cpu_count()) parser.add_argument( '-i', '--poll-interval', type=float, default=0.1, help="Poll interval for file crawler in seconds (default is 0.1).") parser.add_argument( '-r', '--recent', type=int, default=0, help="Index only recent files modified within the given " "number of hours. This option is deactivated by default.") parser.add_argument( '-l', '--log', default='', help="Log file name. If no log file is given, stdout will be used.") parser.add_argument( '-m', '--mapping-file', default=None, help="Correct network, station, location and channel codes using a" + " custom mapping file.") parser.add_argument( '-a', '--all-files', action='store_false', dest='skip_dots', help="The indexer will automatically skip paths or " "files starting with a dot. This option forces " "parsing of all paths and files.") parser.add_argument( '-1', '--run-once', action='store_true', help="The indexer will parse through all given directories only " "once and quit afterwards.") parser.add_argument( '--check-duplicates', action='store_true', help="Checks for duplicate entries within database. " "This feature will slow down the indexer progress.") parser.add_argument( '--cleanup', action='store_true', help="Clean database from non-existing files or paths " + "if activated, but will skip all paths marked as " + "archived in the database.") parser.add_argument( '-f', '--force-reindex', action='store_true', help="Reindex existing index entry for every crawled file.") parser.add_argument( '--drop-database', action='store_true', help="Deletes and recreates the complete database at start up.") parser.add_argument( '-H', '--host', default='localhost', help="Server host name. Default is 'localhost'.") parser.add_argument( '-p', '--port', type=int, default=0, help="Port number. If not given a free port will be picked.") # Deprecated arguments action = _get_deprecated_argument_action( '--check_duplicates', '--check-duplicates', real_action='store_true') parser.add_argument('--check_duplicates', nargs=0, action=action, help=SUPPRESS) action = _get_deprecated_argument_action( '--drop_database', '--drop-database', real_action='store_true') parser.add_argument('--drop_database', nargs=0, action=action, help=SUPPRESS) action = _get_deprecated_argument_action('--mapping_file', '--mapping-file') parser.add_argument('--mapping_file', action=action, help=SUPPRESS) action = _get_deprecated_argument_action( '--run_once', '--run-once', real_action='store_true') parser.add_argument('--run_once', nargs=0, action=action, help=SUPPRESS) args = parser.parse_args(argv) # set level of verbosity if args.verbose: level = logging.DEBUG else: level = logging.INFO if args.log == "": logging.basicConfig(stream=sys.stdout, level=level, format="%(asctime)s [%(levelname)s] %(message)s") else: logging.basicConfig(filename=options.log, level=level, format="%(asctime)s [%(levelname)s] %(message)s") _runIndexer(args)
def main(argv=None): parser = ArgumentParser(prog='obspy-scan', description=__doc__.strip(), formatter_class=RawDescriptionHelpFormatter) parser.add_argument('-V', '--version', action='version', version='%(prog)s ' + __version__) parser.add_argument('-f', '--format', choices=ENTRY_POINTS['waveform'], help='Optional, the file format.\n' + ' '.join(__doc__.split('\n')[-4:])) parser.add_argument('-v', '--verbose', action='store_true', help='Optional. Verbose output.') parser.add_argument('-q', '--quiet', action='store_true', help='Optional. Be quiet. Overwritten by --verbose ' 'flag.') parser.add_argument('-n', '--non-recursive', action='store_false', dest='recursive', help='Optional. Do not descend into directories.') parser.add_argument('-i', '--ignore-links', action='store_true', help='Optional. Do not follow symbolic links.') parser.add_argument('--start-time', default=None, type=UTCDateTime, help='Optional, a UTCDateTime compatible string. ' + 'Only visualize data after this time and set ' + 'time-axis axis accordingly.') parser.add_argument('--end-time', default=None, type=UTCDateTime, help='Optional, a UTCDateTime compatible string. ' + 'Only visualize data before this time and set ' + 'time-axis axis accordingly.') parser.add_argument('--id', action='append', help='Optional, a SEED channel identifier ' "(e.g. 'GR.FUR..HHZ'). You may provide this " + 'option multiple times. Only these ' + 'channels will be plotted.') parser.add_argument('-t', '--event-time', default=None, type=UTCDateTime, action='append', help='Optional, a UTCDateTime compatible string ' + "(e.g. '2010-01-01T12:00:00'). You may provide " + 'this option multiple times. These times get ' + 'marked by vertical lines in the plot. ' + 'Useful e.g. to mark event origin times.') parser.add_argument('-w', '--write', default=None, help='Optional, npz file for writing data ' 'after scanning waveform files') parser.add_argument('-l', '--load', default=None, help='Optional, npz file for loading data ' 'before scanning waveform files') parser.add_argument('--no-x', action='store_true', help='Optional, Do not plot crosses.') parser.add_argument('--no-gaps', action='store_true', help='Optional, Do not plot gaps.') parser.add_argument('-o', '--output', default=None, help='Save plot to image file (e.g. out.pdf, ' + 'out.png) instead of opening a window.') parser.add_argument('--print-gaps', action='store_true', help='Optional, prints a list of gaps at the end.') parser.add_argument('paths', nargs='*', help='Files or directories to scan.') # Deprecated arguments action = _get_deprecated_argument_action('--endtime', '--end-time') parser.add_argument('--endtime', type=UTCDateTime, action=action, help=SUPPRESS) action = _get_deprecated_argument_action('--event-times', '--event-time') parser.add_argument('--event-times', action=action, help=SUPPRESS) action = _get_deprecated_argument_action('--ids', '--id') parser.add_argument('--ids', action=action, help=SUPPRESS) action = _get_deprecated_argument_action( '--nox', '--no-x', real_action='store_true') parser.add_argument('--nox', dest='no_x', nargs=0, action=action, help=SUPPRESS) action = _get_deprecated_argument_action( '--nogaps', '--no-gaps', real_action='store_true') parser.add_argument('--nogaps', dest='no_gaps', nargs=0, action=action, help=SUPPRESS) action = _get_deprecated_argument_action('--starttime', '--start-time') parser.add_argument('--starttime', type=UTCDateTime, action=action, help=SUPPRESS) args = parser.parse_args(argv) # Print help and exit if no arguments are given if len(args.paths) == 0 and args.load is None: parser.error('No paths specified.') # Use recursively parsing function? if args.recursive: parse_func = recursive_parse else: parse_func = parse_file_to_dict if args.output is not None: import matplotlib matplotlib.use("agg") from matplotlib.dates import date2num, num2date from matplotlib.ticker import FuncFormatter from matplotlib.patches import Rectangle from matplotlib.collections import PatchCollection import matplotlib.pyplot as plt fig = plt.figure() ax = fig.add_subplot(111) # Plot vertical lines if option 'event_times' was specified if args.event_time: times = [date2num(t.datetime) for t in args.event_time] for time in times: ax.axvline(time, color='k') # Deprecated version (don't plot twice) if args.event_times and not args.event_time: times = args.event_times.split(',') times = [date2num(UTCDateTime(t).datetime) for t in times] for time in times: ax.axvline(time, color='k') if args.start_time: args.start_time = date2num(args.start_time.datetime) elif args.starttime: # Deprecated version args.start_time = date2num(args.starttime.datetime) if args.end_time: args.end_time = date2num(args.end_time.datetime) elif args.endtime: # Deprecated version args.end_time = date2num(args.endtime.datetime) # Generate dictionary containing nested lists of start and end times per # station data = {} samp_int = {} counter = 1 if args.load: load_npz(args.load, data, samp_int) for path in args.paths: counter = parse_func(data, samp_int, path, counter, args.format, verbose=args.verbose, quiet=args.quiet, ignore_links=args.ignore_links) if not data: if args.verbose or not args.quiet: print("No waveform data found.") return if args.write: write_npz(args.write, data, samp_int) # Loop through this dictionary ids = list(data.keys()) # Handle deprecated argument if args.ids and not args.id: args.id = args.ids.split(',') # restrict plotting of results to given ids if args.id: ids = [x for x in ids if x in args.id] ids = sorted(ids)[::-1] labels = [""] * len(ids) if args.verbose or not args.quiet: print('\n') for _i, _id in enumerate(ids): labels[_i] = ids[_i] data[_id].sort() startend = np.array(data[_id]) if len(startend) == 0: continue # restrict plotting of results to given start/end time if args.start_time: startend = startend[startend[:, 1] > args.start_time] if len(startend) == 0: continue if args.start_time: startend = startend[startend[:, 0] < args.end_time] if len(startend) == 0: continue timerange = startend[:, 1].max() - startend[:, 0].min() if timerange == 0.0: warnings.warn('Zero sample long data for _id=%s, skipping' % _id) continue startend_compressed = compressStartend(startend, 1000) offset = np.ones(len(startend)) * _i # generate list of y values if not args.no_x: ax.plot(startend[:, 0], offset, 'x', linewidth=2) ax.hlines(offset[:len(startend_compressed)], startend_compressed[:, 0], startend_compressed[:, 1], 'b', linewidth=2, zorder=3) # find the gaps diffs = startend[1:, 0] - startend[:-1, 1] # currend.start - last.end gapsum = diffs[diffs > 0].sum() perc = (timerange - gapsum) / timerange labels[_i] = labels[_i] + "\n%.1f%%" % (perc * 100) gap_indices = diffs > 1.8 * np.array(samp_int[_id][:-1]) gap_indices = np.concatenate((gap_indices, [False])) if any(gap_indices): # don't handle last end time as start of gap gaps_start = startend[gap_indices, 1] gaps_end = startend[np.roll(gap_indices, 1), 0] if not args.no_gaps and any(gap_indices): rects = [Rectangle((start_, offset[0] - 0.4), end_ - start_, 0.8) for start_, end_ in zip(gaps_start, gaps_end)] ax.add_collection(PatchCollection(rects, color="r")) if args.print_gaps: for start_, end_ in zip(gaps_start, gaps_end): start_, end_ = num2date((start_, end_)) start_ = UTCDateTime(start_.isoformat()) end_ = UTCDateTime(end_.isoformat()) if args.verbose or not args.quiet: print("%s %s %s %.3f" % (_id, start_, end_, end_ - start_)) # Pretty format the plot ax.set_ylim(0 - 0.5, _i + 0.5) ax.set_yticks(np.arange(_i + 1)) ax.set_yticklabels(labels, family="monospace", ha="right") fig.autofmt_xdate() # rotate date ax.xaxis_date() # set custom formatters to always show date in first tick formatter = ObsPyAutoDateFormatter(ax.xaxis.get_major_locator()) formatter.scaled[1 / 24.] = \ FuncFormatter(decimal_seconds_format_date_first_tick) formatter.scaled.pop(1/(24.*60.)) ax.xaxis.set_major_formatter(formatter) plt.subplots_adjust(left=0.2) # set x-axis limits according to given start/end time if args.start_time and args.end_time: ax.set_xlim(left=args.start_time, right=args.end_time) elif args.start_time: ax.set_xlim(left=args.start_time, auto=None) elif args.end_time: ax.set_xlim(right=args.end_time, auto=None) else: left, right = ax.xaxis.get_data_interval() x_axis_range = right - left ax.set_xlim(left - 0.05 * x_axis_range, right + 0.05 * x_axis_range) if args.output is None: plt.show() else: fig.set_dpi(72) height = len(ids) * 0.5 height = max(4, height) fig.set_figheight(height) plt.tight_layout() if not args.start_time or not args.end_time: days = ax.get_xlim() days = days[1] - days[0] else: days = args.end_time - args.start_time width = max(6, days / 30.) width = min(width, height * 4) fig.set_figwidth(width) plt.subplots_adjust(top=1, bottom=0, left=0, right=1) plt.tight_layout() fig.savefig(args.output) if args.verbose and not args.quiet: sys.stdout.write('\n')