diff --git a/aosstower/tower_quicklooks/create_quicklook.py b/aosstower/tower_quicklooks/create_quicklook.py index e8da206127711847555ec727006368c150e68712..8c4100e2464ef24a416e62b476a6c3f60904858e 100644 --- a/aosstower/tower_quicklooks/create_quicklook.py +++ b/aosstower/tower_quicklooks/create_quicklook.py @@ -1,11 +1,12 @@ import os import sys -from datetime import datetime as dt, timedelta as delta +from datetime import datetime, timedelta import logging import pandas as pd from netCDF4 import MFDataset, MFTime import numpy as np import matplotlib.pyplot as plt +import matplotlib.dates as md import math LOG = logging.getLogger(__name__) @@ -27,7 +28,7 @@ class PlotMaker(object): self.deps = dependencies self._full_figure = None if title is None: - title = "{title_prefix}{title_name}{units} {start_time:%Y-%m-%d}" + title = "{title_prefix}{title_name}{units}\n{date_string}" self._title = title self.units = units @@ -37,24 +38,32 @@ class PlotMaker(object): if var_name not in frame: yield var_name - def get_title(self, frame, is_subplot): + def get_date_string(self, start_time, end_time): + delta = (end_time - start_time).total_seconds() + if delta < timedelta(hours=24).total_seconds(): + return start_time.strftime("%Y-%m-%d") + else: + return "{:%Y-%m-%d %H:%M} to {:%Y-%m-%d %H:%M}".format(start_time, end_time) + + def get_title(self, frame, is_subplot, start_time, end_time): if self._title: title_prefix = "AO&SS Building Tower " if not is_subplot else '' title_name = TITLES.get(self.name, self.name.replace('_', ' ').title()) unit_str = '({})'.format(self.units) if self.units and is_subplot else '' + date_string = self.get_date_string(start_time, end_time) title = self._title.format(title_prefix=title_prefix, title_name=title_name, units=unit_str, - start_time=frame.index[0].to_pydatetime()) + date_string=date_string) else: title = '' return title def get_yticks(self, ymin, ymax, num_plots): + if ymin == ymax: + return [ymin, ymin + 0.05, ymin + 0.1] delta = math.ceil((ymax - ymin) / num_plots) new_ticks = np.arange(ymin, (ymin + delta * num_plots), delta) - if not new_ticks: - return [ymin, ymin + 0.05, ymin + 0.1] return new_ticks def get_ylabel(self, is_subplot=False): @@ -65,7 +74,8 @@ class PlotMaker(object): return "{} ({})".format(y_label, self.units) return y_label - def create_plot(self, frame, fig, is_subplot=None, shared_x=None, title=None): + def create_plot(self, frame, fig, start_time=None, end_time=None, + is_subplot=None, shared_x=None, title=None): """ :param frame: @@ -74,8 +84,12 @@ class PlotMaker(object): :param shared_x: :return: """ + if start_time is None: + start_time = frame.index[0].to_pydatetime() + if end_time is None: + end_time = frame.index[-1].to_pydatetime() if title is None: - title = self.get_title(frame, is_subplot) + title = self.get_title(frame, is_subplot, start_time, end_time) if is_subplot: ax = fig.add_subplot(*is_subplot, sharex=shared_x) @@ -114,11 +128,17 @@ class MeteorogramPlotMaker(PlotMaker): self.plot_deps = plot_deps super(MeteorogramPlotMaker, self).__init__(name, dependencies, title=title) - def create_plot(self, frame, fig, is_subplot=False, shared_x=None): + def create_plot(self, frame, fig, start_time=None, end_time=None, + is_subplot=False, shared_x=None, title=None): if is_subplot or shared_x: raise ValueError("Meteorogram Plot can not be a subplot or share X-axis") - title = self.get_title(frame, False) + if start_time is None: + start_time = frame.index[0].to_pydatetime() + if end_time is None: + end_time = frame.index[-1].to_pydatetime() + if title is None: + title = self.get_title(frame, False, start_time, end_time) fig.suptitle(title, fontsize=13) num_plots = len(self.plot_deps) @@ -137,6 +157,7 @@ class MeteorogramPlotMaker(PlotMaker): ax.get_xaxis().get_major_ticks()[-1].set_visible(False) ax.get_xaxis().get_major_ticks()[0].set_visible(False) ax.set_xlabel('Time (UTC)') + fig.subplots_adjust(hspace=0, bottom=0.125) return ax @@ -177,12 +198,12 @@ def get_data(input_files, columns): # convert base_time epoch format into date_time object base_time = files.variables['base_time'][:] - base_time_obj = dt(1970, 1, 1) + delta(seconds=int(base_time)) + base_time_obj = datetime(1970, 1, 1) + timedelta(seconds=int(base_time)) # convert per-file offsets to offsets based on the first file's base_time offsets = MFTime(files.variables['time_offset'])[:] # for each offset, convert that into a datetime object - data_dict['stamps'] = [base_time_obj + delta(seconds=int(s)) for s in offsets] + data_dict['stamps'] = [base_time_obj + timedelta(seconds=int(s)) for s in offsets] return pd.DataFrame(data_dict).set_index(['stamps']) @@ -197,7 +218,7 @@ def get_dates_in_range(cur_dt, end): curr = cur_dt while curr <= end: yield curr - curr += delta(days=1) + curr += timedelta(days=1) # The purpose of this method is to get the min and max of # an array of stamps and determines all the 12:00:00 days @@ -220,7 +241,7 @@ def find_half_days(dewpoint_stamps, dates): cur_dt = date_min.replace(hour=12, minute=0, second=0) if cur_dt < date_min: - cur_dt += delta(days=1) + cur_dt += timedelta(days=1) datesInRange = list(get_dates_in_range(cur_dt, date_max)) @@ -467,6 +488,11 @@ def create_full_plot(plot_names, frame, output, start_time=None, end_time=None): # numberPlots = len(list(frame.columns.values)) / 2 # plotNumber = numberPlots * 100 + 10 + if start_time is None: + start_time = frame.index[0].to_pydatetime() + if end_time is None: + end_time = frame.index[-1].to_pydatetime() + for name in plot_names: plot_maker = PLOT_TYPES.get(name, PlotMaker(name, (name,))) var_names = [] @@ -485,9 +511,8 @@ def create_full_plot(plot_names, frame, output, start_time=None, end_time=None): plot_frame = plot_frame[~plot_frame.isnull().any(axis=1)] fig = plt.figure() - ax = plot_maker.create_plot(plot_frame, fig) + ax = plot_maker.create_plot(plot_frame, fig, start_time=start_time, end_time=end_time) ax.set_xlim(start_time, end_time) - import matplotlib.dates as md xloc = md.AutoDateLocator(minticks=5, maxticks=8, interval_multiples=True) xfmt = md.AutoDateFormatter(xloc) def _fmt(interval, x, pos=None): @@ -495,7 +520,7 @@ def create_full_plot(plot_names, frame, output, start_time=None, end_time=None): delta_seconds = (x_num - plot_frame.index[0].replace(hour=0, minute=0, second=0, microsecond=0)).total_seconds() num_hours = delta_seconds / 3600. if interval == md.HOURLY: - return "{:02.0f}".format(num_hours) + return "{:.0f}".format(num_hours) elif interval == md.MINUTELY: num_minutes = delta_seconds / 60. num_minutes -= int(num_hours) * 60. @@ -508,7 +533,7 @@ def create_full_plot(plot_names, frame, output, start_time=None, end_time=None): ax.xaxis.set_major_locator(xloc) ax.xaxis.set_major_formatter(xfmt) - out_fn = output.format(plot_name=name, start_time=plot_frame.index[0].to_pydatetime()) + out_fn = output.format(plot_name=name, start_time=start_time, end_time=end_time) LOG.info("Saving plot '{}' to filename '{}'".format(name, out_fn)) fig.savefig(out_fn) @@ -556,9 +581,9 @@ def create_full_plot(plot_names, frame, output, start_time=None, end_time=None): def _dt_convert(datetime_str): try: - return dt.strptime(datetime_str, '%Y-%m-%dT%H:%M:%S') + return datetime.strptime(datetime_str, '%Y-%m-%dT%H:%M:%S') except ValueError: - return dt.strptime(datetime_str, '%Y-%m-%d') + return datetime.strptime(datetime_str, '%Y-%m-%d') def main():