climate-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From good...@apache.org
Subject svn commit: r1507046 - in /incubator/climate/branches/RefactorInput/ocw: plotter.py tests/test_plotter.py
Date Thu, 25 Jul 2013 16:13:34 GMT
Author: goodman
Date: Thu Jul 25 16:13:34 2013
New Revision: 1507046

URL: http://svn.apache.org/r1507046
Log:
CLIMATE-215 - Added first implementation of assign_plot_data() method

Modified:
    incubator/climate/branches/RefactorInput/ocw/plotter.py
    incubator/climate/branches/RefactorInput/ocw/tests/test_plotter.py

Modified: incubator/climate/branches/RefactorInput/ocw/plotter.py
URL: http://svn.apache.org/viewvc/incubator/climate/branches/RefactorInput/ocw/plotter.py?rev=1507046&r1=1507045&r2=1507046&view=diff
==============================================================================
--- incubator/climate/branches/RefactorInput/ocw/plotter.py (original)
+++ incubator/climate/branches/RefactorInput/ocw/plotter.py Thu Jul 25 16:13:34 2013
@@ -21,6 +21,7 @@ Classes: 
 '''
 
 import os
+import logging
 from tempfile import TemporaryFile
 import matplotlib as mpl
 import matplotlib.pyplot as plt
@@ -57,7 +58,7 @@ class Plotter:
         :type evaluation: Evaluation 
         :param workdir: The working directory to save generated figures.
         	If set to None, it will be set to your current working directory.
-        :type work_dir: [optional] str or None
+        :type workdir: [optional] str or None
         :param fmt: The file type to save figures. Supported formats include
             png, eps, and pdf.
         :type fmt: [optional] str 
@@ -67,6 +68,7 @@ class Plotter:
             
         self.workdir = workdir
         self.fmt = fmt
+        self._plot_data = []
         self.assign_plot_data(evaluation)
     
     def assign_plot_data(self, evaluation):
@@ -77,41 +79,110 @@ class Plotter:
         Plotting function shapes are based on the length of the following 
         evaluation attributes (X denotes an arbitrary value):
         Contour Map: datasets, lats, lons
-        Portrait Diagram: X, subregions, datasets
-        Time Series: datasets, X, times
+        Portrait Diagram: X, subregions, datasets (not supported)
+        Time Series: subregions, datasets, times
         Taylor Diagram: datasets, 2
         
         Arguments:
         :param evaluation: A previously ran Evaluation instance
         :type evaluation: Evaluation
         '''
-        # Check if the evaluation was ran previously. Could check the results
-        # attribute but it may be better to have a flag defined somewhere that
-        # checks if run() has been called successfully in the Evaluation class.
-        # if not evaluation.processed:
-        if evaluation.results is None:
-            # Should either raise an exception (ValueError or a custom class)
-            # or run the evaluation directly
-            # self.evaluation.run() 
+        # Check if the evaluation was ran previously. 
+        try:
+            results = evaluation.results
+        except AttributeError:
             raise ValueError('evaluation must be ran before being processed')
         
-        for result in evaluation.results:
-            # Function to be selected from if-else block based on result shape
+        # Load dataset attributes
+        names = [dataset.name for dataset in evaluation.target_datasets]
+        lats = evaluation.ref_dataset.lats
+        lons = evaluation.ref_dataset.lons
+        variable = evaluation.ref_dataset.variable
+        times = evaluation.ref_dataset.times        
+        mtimes = [t for t in times if t.day == 1][:12]
+        ytimes = [t for t in times if t.month == 1 and t.day == 1]
+        
+        # For default plotting always assume two columns
+        gridshape = len(names), 2
+        
+        # Process results
+        for result, metric in zip(results, evaluation.metrics):
             
-            # Function arguments are also constructed from the attributes of
-            # evaluation
+            # Convert result to numpy array for easier processing
+            result = np.array(result)
             
-            # self.plot_data.append(func, args, kwargs)
-            pass
+            # Plot title
+            ptitle = '%s_%s' %(variable, metric.__name__)
+        
+            # Contour Map 
+            if result.shape == (len(names), len(lats), len(lons)):
+                plotfunc = draw_contour_map
+                fname = os.path.join(self.workdir, '%s_contour_map' 
+                                     %(metric.__name__))
+                args = result, lats, lons, fname
+                kwargs = {'fmt': self.fmt, 
+                          'subtitles': names, 
+                          'gridshape': gridshape,
+                          'ptitle': title
+                          }
+            
+            # Taylor Diagram    
+            elif result.shape == (len(names), 2):
+                plotfunc = draw_taylor_diagram
+                fname = os.path.join(self.workdir, '%s_taylor_diagram'
+                                     %(metric.name))
+                refname = self.ref_dataset.name
+                args = result, names, refname
+                kwargs = {'fmt': self.fmt, 'ptitle': title}
+                
+            # Time Series
+            elif result.shape[2] == len(mtimes) or result.shape[2] == len(ytimes):
+                plotfunc = draw_time_series
+                fname = os.path.join(self.workdir, '%s_time_series'
+                                     %(metric.name))
+                
+                # Arguments vary slightly depending on whether the time series
+                # is monthly or annual
+                if result.shape[2] % 12 == 0:
+                    ptimes = mtimes
+                    label_month = True
+                else:
+                    ptimes = ytimes
+                    label_month = False
+                
+                # Number of datasets is always the first dimension in result
+                # so make it the second dimension to be compatible with the
+                # plotting function.
+                result = result.swapaxes(1, 0)
+                args = result, ptimes, names, fname
+                kwargs = {'fmt': self.fmt, 
+                          'gridshape': gridshape,
+                          'ptitle': title,
+                          'label_month': label_month
+                           # TODO: Subplot Titles by subregion?
+                          }
+                
+            # Automatic plotting currently not supported for given result
+            else:
+                warning = 'No plotting function found for metric %s.' \
+                          'Consider assigning one manually and rerun the' \
+                          'evaluation.' %(metric.__name__)
+                logging.warning(warning)
+                continue
+                
+            self._plot_data.append((plotfunc, args, kwargs))
         
     def make_plots(self):
         '''
         Calls the actual plotting functions, either defined in a separate module
         (eg rcmes/toolkit/plots.py or placed directly in this one. 
         '''
-        # for func, args, kwargs in self.plot_data:
-        #     func(*args, **kwargs)
-        pass
+        if not self._plot_data:
+            raise AttributeError('No compatible plotting functions found!')
+        
+        for plotfunc, args, kwargs in self._plot_data:
+            plotfunc(*args, **kwargs)
+
     
 # Plotting function library. Originally from a separate file, but placed here
 # for now so that the original rcmet code in this branch still works
@@ -202,16 +273,17 @@ def _fig_size(gridshape):
         
     return width, height
     
-def draw_taylor_diagram(data, refname, fname, fmt='png', ptitle='', 
-                      pos='upper right', frameon=False, radmax=1.5):
+def draw_taylor_diagram(data, names, refname, fname, fmt='png', ptitle='', 
+                        pos='upper right', frameon=False, radmax=1.5):
     '''
     Purpose::
         Draws a Taylor diagram
         
     Input::
-        data - an Nx3 array containing normalized standard deviations,
-               correlation coefficients, and names of evaluation datasetss
-        refname - The name of the reference datasets
+        data - an Nx2 array containing normalized standard deviations,
+               correlation coefficients, and names of evaluation datasets
+        names - list of names for each evaluated dataset
+        refname - The name of the reference dataset
         fname  - a string specifying the filename of the plot
         fmt  - an optional string specifying the filetype, default is .png
         ptitle - an optional string specifying the plot title
@@ -225,8 +297,8 @@ def draw_taylor_diagram(data, refname, f
     fig = plt.figure()
     fig.suptitle(ptitle)            
     dia = TaylorDiagram (1, fig=fig, rect=111, label=refname, radmax=radmax)
-    for i, (stddev, corrcoef, name) in enumerate(data):
-        dia.add_sample(stddev, corrcoef, marker='$%d$' % (i + 1), ms=6, label=name)
+    for i, (stddev, corrcoef) in enumerate(data):
+        dia.add_sample(stddev, corrcoef, marker='$%d$' % (i + 1), ms=6, label=names[i])
     
     legend = fig.legend(dia.samplePoints, [p.get_label() for p in dia.samplePoints], handlelength=0.,

                         prop={'size': 10}, numpoints=1, loc=pos)
@@ -235,7 +307,7 @@ def draw_taylor_diagram(data, refname, f
     fig.clf()
     
 def draw_subregions(subregions, lats, lons, fname, fmt='png', ptitle='',
-                   parallels=None, meridians=None, subregion_masks=None):
+                    parallels=None, meridians=None, subregion_masks=None):
     '''
     Purpose::
         Function to draw subregion domain(s) on a map
@@ -329,8 +401,8 @@ def draw_subregions(subregions, lats, lo
     fig.clf()
 
 def draw_time_series(datasets, times, labels, fname, fmt='png', gridshape=(1, 1), 
-                   xlabel='', ylabel='', ptitle='', subtitles=None, 
-                   label_month=False, yscale='linear'):
+                     label='', ylabel='', ptitle='', subtitles=None, 
+                     label_month=False, yscale='linear'):
     '''
     Purpose::
         Function to draw a time series plot
@@ -444,9 +516,9 @@ def draw_time_series(datasets, times, la
     fig.clf()
 
 def draw_contour_map(dataset, lats, lons, fname, fmt='png', gridshape=(1, 1),
-                   clabel='', ptitle='', subtitles=None, cmap=None, 
-                   clevs=None, nlevs=10, parallels=None, meridians=None,
-                   extend='neither'):
+                     clabel='', ptitle='', subtitles=None, cmap=None, 
+                     clevs=None, nlevs=10, parallels=None, meridians=None,
+                     extend='neither'):
     '''
     Purpose::
         Create a multiple panel contour map plot.
@@ -588,9 +660,9 @@ def draw_contour_map(dataset, lats, lons
     fig.clf()
 
 def draw_portrait_diagram(datasets, rowlabels, collabels, fname, fmt='png', 
-                        gridshape=(1, 1), xlabel='', ylabel='', clabel='', 
-                        ptitle='', subtitles=None, cmap=None, clevs=None, 
-                        nlevs=10, extend='neither'):
+                          ridshape=(1, 1), xlabel='', ylabel='', clabel='', 
+                          ptitle='', subtitles=None, cmap=None, clevs=None, 
+                          nlevs=10, extend='neither'):
     '''
     Purpose::
         Makes a portrait diagram plot.

Modified: incubator/climate/branches/RefactorInput/ocw/tests/test_plotter.py
URL: http://svn.apache.org/viewvc/incubator/climate/branches/RefactorInput/ocw/tests/test_plotter.py?rev=1507046&r1=1507045&r2=1507046&view=diff
==============================================================================
--- incubator/climate/branches/RefactorInput/ocw/tests/test_plotter.py (original)
+++ incubator/climate/branches/RefactorInput/ocw/tests/test_plotter.py Thu Jul 25 16:13:34
2013
@@ -18,6 +18,32 @@
 '''Unit tests for the plotter.py module'''
 
 import unittest
+import os
+import datetime
+import metrics
+import numpy as np
+from dataset import Dataset
+from evaluation import Evaluation
+from plotter import Plotter
 
 class TestPlotter(unittest.TestCase):
-    pass
+    def setUp(self):
+        pass
+        
+    def test_init(self):
+        pass
+
+    def test_assign_plot_data_contour_map(self):
+        pass
+    
+    def test_assign_plot_data_time_series(self):
+        pass
+    
+    def test_assign_plot_data_taylor_diagram(self):
+        pass
+        
+    def test_assign_plot_data_portrait_diagram(self):
+        pass
+
+if __name__  == '__main__':
+    unittest.main()
\ No newline at end of file



Mime
View raw message