From 25fe631dade831050f9a6e6215a9ccf7712cc926 Mon Sep 17 00:00:00 2001
From: davidh-ssec <david.hoese@ssec.wisc.edu>
Date: Fri, 14 Jul 2017 08:54:03 -0500
Subject: [PATCH] Add units to meteorogram plots

---
 .../tower_quicklooks/create_quicklook.py      | 312 +-----------------
 1 file changed, 18 insertions(+), 294 deletions(-)

diff --git a/aosstower/tower_quicklooks/create_quicklook.py b/aosstower/tower_quicklooks/create_quicklook.py
index dd0459c..4215631 100644
--- a/aosstower/tower_quicklooks/create_quicklook.py
+++ b/aosstower/tower_quicklooks/create_quicklook.py
@@ -28,6 +28,10 @@ def remove_yticklines(ax):
         t.set_visible(False)
 
 
+def get_subtitle_location(num_subplots):
+    return 1 - 0.055 * num_subplots
+
+
 class PlotMaker(object):
     """Object for making plots and storing/validating plot metadata"""
     def __init__(self, name, dependencies, title=None, units=None):
@@ -86,8 +90,13 @@ class PlotMaker(object):
         if y_label and not is_subplot:
             ax.set_ylabel(y_label)
 
+        if is_subplot:
+            # put units on the top left of the plot axes
+            ax.text(.008, .9, self.units,
+                    horizontalalignment='left', va='top',
+                    transform=ax.transAxes, size=8)
+
     def _call_plot(self, frame, ax):
-        print(self.name, frame.columns)
         lines = ax.plot(frame.index, frame, 'k')
         return lines
 
@@ -190,6 +199,9 @@ class PlotMaker(object):
             ax.spines['top'].set_visible(False)
             ax.spines['bottom'].set_visible(False)
 
+            for t in ax.texts:
+                t.set_visible(False)
+
     def convert_to_thumbnail(self, fig, fig_size=TN_SIZE):
         fig = self._convert_fig_to_thumbnail(fig, fig_size)
         self._convert_ax_to_thumbnail(fig)
@@ -345,7 +357,7 @@ PLOT_TYPES = {
     'wind_dir': WindDirPlotMaker('wind_dir', ('wind_dir',), units='°'),  # special tick labels
     'rh': PlotMaker('rh', ('rh',), units='%'),
     'air_temp': PlotMaker('air_temp', ('air_temp',), units='°C'),
-    'pressure': PlotMaker('pressure', ('pressure',), units='hpa'),
+    'pressure': PlotMaker('pressure', ('pressure',), units='hPa'),
     'dewpoint': PlotMaker('dewpoint', ('air_temp',), units='°C'),
     'wind_speed': PlotMaker('wind_speed', ('wind_speed',), units='m/s'),
     'accum_precip': PrecipPlotMaker('accum_precip', ('accum_precip',), units='mm'),
@@ -377,255 +389,8 @@ def get_data(input_files, columns):
     return pd.DataFrame(data_dict).set_index(['stamps'])
 
 
-# The purpose of this method is to determines all the 12:00:00 days
-# within a start and end date
-# @param cur_dt - start time
-# @param dates - end time
-# @return dates in lists
-
-def get_dates_in_range(cur_dt, end):
-    curr = cur_dt
-    while curr <= end:
-        yield curr
-        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
-# in that array
-# @param dewpoint stamps - time stamps for valid dewpoint data. Only specified if
-# air temp and dew point need to be ploted in the same plot
-# @param dates - time stamps for data
-# @return datesInRange - all days with 12:00:00
-def find_half_days(dewpoint_stamps, dates):
-    date_max = np.amax(dates)
-    date_min = np.amin(dates)
-
-    if(dewpoint_stamps):
-        dew_max = np.amax(dewpoint_stamps)
-        dew_min = np.amin(dewpoint_stamps)
-
-        date_max = max(date_max, dew_max)
-        date_min = min(date_min, dew_min)    
-
-    cur_dt = date_min.replace(hour=12, minute=0, second=0)
-    
-    if cur_dt < date_min:
-        cur_dt += timedelta(days=1)
-
-    datesInRange = list(get_dates_in_range(cur_dt, date_max))    
-
-    return datesInRange           
-
-# The purpose of this method is to create a thumbnail plot
-# @param frame - all data I need in a data frame
-# @param ymin - lower limit of the y axis if specified. set only when --daily is given
-# @param ymax - upper limit of yaxis if specified. Set only when --daily is given
-# @param dewpoint_stamps - timestamps for valid dewpoint data. Only specified if 
-# air temp and dew point need to be plotted in the same plot
-# @param dewpoint_data - valid dewpoint data. Only specified if 
-# air temp and dew point need to be plotted in the same plot
-#@param output - output filename pattern
-def thumbnail_plot(dates, data, ymin, ymax,
-    dewpoint_stamps, dewpoint_data, output, wind_dir):
-
-    if(dewpoint_stamps):
-        plt.plot(dates, data, 'r', dewpoint_stamps, dewpoint_data, 'b')
-        plt.axis([min(dates), max(dates), ymin, ymax])
-        #plt.plot(dewpoint_stamps, dewpoint_data, 'b')
-
-    elif(wind_dir):
-        plt.plot(dates, data, 'ko', markersize=0.1)
-        plt.axis([min(dates), max(dates), 0, 360])
-
-    else:
-        plt.plot(dates, data, 'k')
-        plt.axis([min(dates), max(dates), ymin, ymax])
-
-    #scale
-    fig = plt.gcf()
-    dpi = fig.get_dpi()
-    fig.set_size_inches(80/float(dpi), 80/float(dpi))
-
-    #create axes
-    axes = plt.gca()
-    axes.axes.get_xaxis().set_ticklabels([])
-    axes.axes.get_xaxis().set_tick_params(length=7)
-    axes.axes.get_yaxis().set_ticklabels([])
-    axes.axes.get_yaxis().set_visible(False)
-    axes.spines['right'].set_visible(False)
-    axes.spines['bottom'].set_visible(False)
-
-    #got the basic shape of the plot
-    #still need to draw a line in the middle
-    datesInRange = find_half_days(dewpoint_stamps, dates)
-    
-    for date in datesInRange:
-        plt.axvline(x=date, color='k')       
-
-# The purpose of this method is to create a thumbnail
-# @param frame - all data I need in a data frame
-# @param ymin - lower limit of the y axis if specified. set only when --daily is given
-# @param ymax - upper limit of yaxis if specified. Set only when --daily is given
-# @param create_air_dew_plot - boolean specifying if air temp and dewpoint
-# @param output - output filename pattern 
-# should be in same plot
-def create_thumbnail(plot_names, frame, ymin, ymax, create_air_dew_plot, output):
-    #see if we're going to need subplots
-    #subplots needed when len is greater than 2 for one variable
-    #or greater than 4 for two variables
-
-    need_subplots = len(list(frame.columns.values)) > 2 and not create_air_dew_plot
-    need_subplots = need_subplots or len(list(frame.columns.values)) > 4 and create_air_dew_plot
-
-    if need_subplots:
-        plots_created = 1
-
-        if create_air_dew_plot:
-            numberPlots = (len(list(frame.columns.values)) - 2) / 2
-            plotNumber = numberPlots * 100 + 10
-
-        else:
-            numberPlots = len(list(frame.columns.values)) / 2
-            plotNumber = numberPlots * 100 + 10    
-
-    stamps = frame.index
-    #get dewpoint data
-    if create_air_dew_plot:
-        all_data = frame['dewpoint']
-        qc_data = frame['qc_dewpoint']
-
-        good_list = get_good_data(qc_data, stamps, all_data)
-        dewpoint_data = good_list[0]
-        dewpoint_stamps = good_list[1]
-
-    for name in plot_names:
-        if name == 'dewpoint' and create_air_dew_plot:
-            continue
-
-        if name not in list(frame.columns.values):
-            continue        
-
-        elif need_subplots:
-            plt.subplot(plotNumber + plots_created)
-            plots_created += 1
-
-
-        all_data = frame[name]
-        qc_data = frame['qc_' + name]
-
-        good_list = get_good_data(qc_data, stamps, all_data)
-        good_data = good_list[0]
-        good_stamps= good_list[1]
-
-        #if we don't need two lines in same plot, plot
-        if not (create_air_dew_plot and name == 'air_temp'):
-            if name != 'wind_dir':    
-                thumbnail_plot(good_stamps, good_data, ymin[name], ymax[name], 
-                    None, None, output, False)
-
-            if name == 'wind_dir':
-               thumbnail_plot(good_stamps, good_data, ymin[name], ymax[name], 
-                    None, None, output, True)      
-
-        else:        
-            thumbnail_plot(good_stamps, good_data, ymin[name], ymax[name], 
-                dewpoint_stamps, dewpoint_data, output, False)
-
-    plt.savefig(output.format(plot_name='test', start_time=good_stamps[0]))
-
-def full_plot_stamps(stamps):
-    # assume the timestamps are monotonic
-    first_stamp = stamps[0].replace(hour=0, minute=0, second=0)
-    return [((s - first_stamp).total_seconds()/3600) for s in stamps]
-
-# The purpose of this method is to change how the y ticks are shown
-# @param min - minimum of the y range right now
-# @param max - maximum of the y range right now
-# @return new tick labels
-
-def get_new_labels(mini, maxi):
-    delta = math.ceil((maxi - mini) / 6)
-    return np.arange(mini, (mini + delta*6), delta)
-        
-# The purpose of this method is to create a full_size plot
-# @param frame - all data I need in a data frame
-# @param ymin - lower limit of the y axis if specified. set only when --daily is given
-# @param ymax - upper limit of yaxis if specified. Set only when --daily is given
-# @param dewpoint_stamps - timestamps for valid dewpoint data. Only specified if 
-# air temp and dew point need to be plotted in the same plot
-# @param dewpoint_data - valid dewpoint data. Only specified if 
-# air temp and dew point need to be plotted in the same plot
-# @param output - output filename pattern
-# @param wind_direction - says different yaxis labels
-# @param accum_precip - different yaxis handling
-# @param see if we need subplots
-def full_plot(fig, axes, dates, data, ymin, ymax,
-    dewpoint_stamps, dewpoint_data, output, wind_dir,
-    accum_precip, need_subplots):
-
-    dates = full_plot_stamps(dates)
-
-    if(dewpoint_stamps):
-        dewpoint_stamps = full_plot_stamps(dewpoint_stamps)
-
-        plt.plot(dates, data, 'r', dewpoint_stamps, dewpoint_data, 'b')
-        plt.axis([min(dates), max(dates), ymin, ymax])
-        
-
-        #labels = [math.ceil(float(item.get_text())) for item in ticks]
-        #plt.plot(dewpoint_stamps, dewpoint_data, 'b')
-
-
-    elif(wind_dir):
-        plt.plot(dates, data, 'ko', markersize=1)
-        plt.axis([min(dates), max(dates), 0, 360])
-
-        axes = plt.gca()
-        axes.get_yaxis().set_ticks([0,90,180,270])
-
-
-    else:
-        # import ipdb; ipdb.set_trace()
-        plt.plot(dates, data, 'k')
-        # plt.axis([min(dates), max(dates), ymin, ymax])
-
-    if not need_subplots:
-        return
-
-    #if not wind_direction, reset yaxis ticks
-    if not wind_dir:
-        if not accum_precip:
-            mini, maxi = axes.get_ylim()
-            new_labels = get_new_labels(mini, maxi)
-
-        else:
-            mini, maxi = axes.get_ylim()
-            delta = ((maxi - mini)/6)
-            new_labels = np.arange(mini, (mini + delta*6), delta)
-            
-            if len(new_labels) == 0:
-                new_labels = [0, 0.05, 0.1]   
-
-        plt.yticks(new_labels)
-        axes.get_yaxis().get_major_ticks()[-1].set_visible(False)
-
-    #hid last tick because for subplots above the last one, it's peeping out...
-    # will show for the last subplot or when subplots are not needed
-    # in other words, this code should only affect plots above the last plot
-    # only when sublots are needed
-    axes.get_xaxis().get_major_ticks()[-1].set_visible(False)
-    axes.get_xaxis().get_major_ticks()[0].set_visible(False)
-
-# The purpose of this method is to get the subtitle's y coordinate
-# based upon how many subplots there are
-# @param numSubPlots - number of subplots
-# @return y-coordinate of subtitle
-def get_subtitle_location(numSubPlots):
-    return 1 - 0.055*numSubPlots
-
-
-def create_full_plot(plot_names, frame, output,
-                     start_time=None, end_time=None, thumbnail=False):
+def create_plot(plot_names, frame, output,
+                start_time=None, end_time=None, thumbnail=False):
     """
     
     Args:
@@ -672,49 +437,9 @@ def create_full_plot(plot_names, frame, output,
             stem, ext = os.path.splitext(out_fn)
             out_fn = "{}_thumbnail{}".format(stem, ext)
             plot_maker.convert_to_thumbnail(fig)
+            LOG.info("Saving thumbnail '{}' to filename '{}'".format(name, out_fn))
             fig.savefig(out_fn)
 
-        # all_data = frame[name]
-        # qc_data = frame['qc_' + name]
-        #
-        # good_list = get_good_data(qc_data, stamps, all_data)
-        # good_data = good_list[0]
-        # good_stamps = good_list[1]
-        #
-        # dateString = good_stamps[0].strftime('%m/%d/%Y')
-        #
-        # # create plots
-        # if need_subplots:
-        #     if plots_created == 1:
-        #         plt.figure().suptitle('AO&SS Building Tower Meteorogram ' + dateString, fontsize=13)
-        #         ax1 = plt.subplot(plotNumber + plots_created)
-        #         ax1.set_title(TITLES[name], x=0.5, y=get_subtitle_location(numberPlots), fontsize=8)
-        #     else:
-        #         curr_plot = plt.subplot(plotNumber + plots_created, sharex=ax1)
-        #         curr_plot.set_title(TITLES[name], x=0.5, y=get_subtitle_location(numberPlots), fontsize=8)
-        #
-        #     plots_created += 1
-        #
-        # else:
-        #     plt.figure().suptitle('AO&SS Building Tower ' + IND_TITLES[name] + ' ' + dateString, fontsize=13)
-        #     plt.ylabel(TITLES[name])
-        #
-        # #if we don't need two lines in same plot, plot
-        # if not (create_air_dew_plot and name == 'air_temp'):
-        #     full_plot(good_stamps, good_data, ymin[name], ymax[name],
-        #                 None, None, output, name == 'wind_dir',
-        #                 name == 'accum_precip', need_subplots)
-        #
-        # else:
-        #     full_plot(good_stamps, good_data, ymin[name], ymax[name],
-        #         dewpoint_stamps, dewpoint_data, output, False, False,
-        #         need_subplots)
-
-    # if need_subplots:
-    #     plt.subplots_adjust(hspace=0, bottom=0.125)
-    #
-    # plt.xlabel('Time (UTC)')
-
 
 def _dt_convert(datetime_str):
     try:
@@ -764,7 +489,6 @@ def main():
 
     plot_deps = [PLOT_TYPES[k].deps if k in PLOT_TYPES else (k,) for k in args.plot_names]
     plot_deps = list(set(d for deps in plot_deps for d in deps))
-    print(plot_deps)
     frame = get_data(args.input_files, plot_deps)
     bad_plot_names = set(args.plot_names) - (set(frame.columns) | set(PLOT_TYPES.keys()))
     if bad_plot_names:
@@ -793,7 +517,7 @@ def main():
             start_time = args.start_time
             end_time = args.end_time
 
-        create_full_plot(args.plot_names, frame, args.output, start_time, end_time, args.thumbnail)
+        create_plot(args.plot_names, frame, args.output, start_time, end_time, args.thumbnail)
 
 if __name__ == "__main__":
     sys.exit(main())
-- 
GitLab