Skip to content

Commit 505dd55

Browse files
authored
Merge pull request #9 from UV-CDAT/viewer
Viewer
2 parents 41b650a + 80300ac commit 505dd55

File tree

9 files changed

+126
-60
lines changed

9 files changed

+126
-60
lines changed

cdp/cdp_driver.py

Lines changed: 0 additions & 34 deletions
This file was deleted.

cdp/cdp_metric.py

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import abc
2+
import sys
23
import cdp.cdp_tool
34
import cdp._cache
45

@@ -28,35 +29,35 @@ class CDPMetric(cdp.cdp_tool.CDPTool):
2829

2930
__metaclass__ = abc.ABCMeta
3031

31-
def __init__(self, metric_path=None):
32-
# metric_path: printed when this metric is used.
33-
# Let's users know when a metric is called in the code.
32+
def __init__(self, metric_name=None):
33+
# metric_info: information displayed when the metric is used.
3434
# _values: dictionary of the computed values. This allows for compound metrics.
35-
self._metric_path = metric_path
36-
# get the 'filename' from /path/to/filename.py
37-
name_with_py = self._metric_path.split('/')[-1]
38-
name = name_with_py.split('.')[0]
39-
self._values = {name: self}
35+
self.metric_info = None
36+
if metric_name is None:
37+
metric_name = sys.modules[self.__class__.__module__].__file__ # gets the path of the file
38+
metric_name = metric_name.split('/')[-1].split('.')[0] # get the 'filename' from /path/to/filename.py
39+
self._values = {metric_name: self}
4040

4141
def __call__(self, *args, **kwargs):
4242
self._show_metric_information()
4343
if self._is_compound():
44-
# Remove the 'CompoundMetric' key from the _values because it's just a key with a blank value
45-
self._values.pop('CompoundMetric')
44+
# Remove the 'cdp_metric' key from the _values because
45+
# it's just a key with a blank value created when there's a compound metric
46+
self._values.pop('cdp_metric')
4647
# loop through and calculate all of the metrics
4748
for key, value in self._values.items():
4849
# replaces the function with the actual value
4950
self._values[key] = value(*args, **kwargs)
5051
return self._values
5152
else:
5253
#return cdp._cache.cache(self.compute, *args, **kwargs)
53-
return self.compute(*args, **kwargs)
54+
return self.compute(*args, **kwargs)
5455

5556
def __add__(self, other):
5657
class CompoundMetric(CDPMetric):
5758
def compute(self):
5859
pass
59-
compound_metric = CompoundMetric('CompoundMetric')
60+
compound_metric = CompoundMetric()
6061
self._add_values_dict_into_first(compound_metric, self)
6162
self._add_values_dict_into_first(compound_metric, other)
6263
return compound_metric
@@ -67,7 +68,7 @@ def compute(self):
6768
pass
6869
if not self._is_compound():
6970
raise TypeError('First operand must be a CompoundMetric')
70-
compound_metric = CompoundMetric('CompoundMetric')
71+
compound_metric = CompoundMetric()
7172
self._add_values_dict_into_first(compound_metric, self)
7273
self._subtract_values_dict_into_first(compound_metric, other)
7374
return compound_metric
@@ -93,7 +94,13 @@ def _subtract_values_dict_into_first(self, compound_metric, other_metric):
9394
def _show_metric_information(self):
9495
""" Displays information about this metric so that a user
9596
can easily identify what metrics are being used. """
96-
print 'Using metric: ' + self._metric_path
97+
if self.metric_info:
98+
print self.metric_info
99+
100+
def set_metric_info(self, info):
101+
''' Sets a message to be displayed everytime
102+
a metric is called. Useful for debugging. '''
103+
self.metric_info = info
97104

98105
@abc.abstractmethod
99106
def compute(self):

cdp/cdp_viewer.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import os
2+
import stat
3+
from output_viewer.build import build_viewer
4+
from output_viewer.utils import rechmod
5+
from output_viewer.index import OutputIndex, OutputPage, OutputFile, OutputRow, OutputGroup
6+
7+
8+
class OutputViewer(object):
9+
def __init__(self, path='.', index_name='Results'):
10+
self.path = os.path.abspath(path)
11+
self.index = OutputIndex(index_name)
12+
self.group = None
13+
self.page = None
14+
15+
def add_group(self, name):
16+
self.group = OutputGroup(name)
17+
self.page.addGroup(self.group)
18+
19+
def add_page(self, name, cols):
20+
self.page = OutputPage(name, cols)
21+
self.index.addPage(self.page)
22+
23+
def add_row(self, *args, **kwargs):
24+
''' Adds a description and all of the files in self.path to an
25+
OutputRow, which is then added to the current page'''
26+
cols = []
27+
for arg in args[1:]:
28+
cols.append(arg)
29+
file_path = os.path.abspath(kwargs['file_name'])
30+
cols.append(OutputFile(file_path))
31+
32+
if self.group is None:
33+
self.group = OutputGroup('Variables for this data set')
34+
self.page.addGroup(self.group)
35+
if self.page is not None:
36+
row = OutputRow(args[0], cols)
37+
self.page.addRow(row, len(self.page.groups)-1)
38+
else:
39+
raise RuntimeError('You need to add a page with add_page() before calling add_row()')
40+
41+
def generate_viewer(self):
42+
self.index.toJSON(os.path.join(self.path, "index.json"))
43+
44+
default_mask = stat.S_IMODE(os.stat(self.path).st_mode)
45+
rechmod(self.path, default_mask)
46+
47+
if os.access(self.path, os.W_OK):
48+
default_mask = stat.S_IMODE(os.stat(self.path).st_mode) # mode of files to be included
49+
build_viewer(os.path.join(self.path, "index.json"), diag_name="My Diagnostics", default_mask=default_mask)
50+
51+
if os.path.exists(os.path.join(self.path, "index.html")):
52+
should_open = raw_input("Viewer HTML generated at %s/index.html. Would you like to open in a browser? y/[n]: " % self.path)
53+
if should_open and should_open.lower()[0] == "y":
54+
import webbrowser
55+
webbrowser.open("file://" + os.path.join(self.path, "index.html"))
56+
else:
57+
raise RuntimeError("Failed to generate the viewer.")

cdp/test/test_cdp_metric.py

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,10 @@
55
class TestCDPMetric(unittest.TestCase):
66

77
class Add(cdp.cdp_metric.CDPMetric):
8-
def __init__(self):
9-
metric_path = 'add'
10-
super(TestCDPMetric.Add, self).__init__(metric_path)
11-
128
def compute(self, a1, a2):
139
return a1 + a2
1410

1511
class Sub(cdp.cdp_metric.CDPMetric):
16-
def __init__(self):
17-
metric_path = 'sub'
18-
super(TestCDPMetric.Sub, self).__init__(metric_path)
19-
2012
def compute(self, s1, s2):
2113
return s1 - s2
2214

@@ -36,8 +28,8 @@ def test_compute(self):
3628

3729
def test_add(self):
3830
try:
39-
sub = TestCDPMetric.Sub()
40-
add = TestCDPMetric.Add()
31+
sub = TestCDPMetric.Sub('sub')
32+
add = TestCDPMetric.Add('add')
4133
new_metric = sub + add
4234
result = new_metric(2, 1)
4335
self.assertDictEqual(result, {'add':3, 'sub':1})
@@ -46,15 +38,16 @@ def test_add(self):
4638

4739
def test_sub(self):
4840
try:
49-
sub = TestCDPMetric.Sub()
50-
add = TestCDPMetric.Add()
41+
sub = TestCDPMetric.Sub('sub')
42+
add = TestCDPMetric.Add('add')
5143
compound_metric = sub + add
5244
new_metric = compound_metric - sub
5345
result = new_metric(2, 1)
5446
self.assertDictEqual(result, {'add':3})
5547
except Exception as err:
5648
self.fail('Failure during metric subtraction: %s' % err)
5749

50+
5851
def test_is_compound(self):
5952
sub = TestCDPMetric.Sub()
6053
add = TestCDPMetric.Add()

conda/meta.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,5 @@ requirements:
1414
build:
1515
- python
1616
- setuptools
17+
run:
18+
- output_viewer

example/basic_driver.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import vcs
2+
from my_metrics import add
3+
from cdp.cdp_viewer import OutputViewer
4+
5+
result = add(1, 1)
6+
7+
# Using vcs to visualize the result. This is just to show the viewer.
8+
vcs_canvas = vcs.init(bg=True, geometry=(256, 256))
9+
text = vcs_canvas.createtextcombined()
10+
text.x = 0.5
11+
text.y = 0.5
12+
text.string = str(result)
13+
text.height = 96
14+
text.halign = 'center'
15+
vcs_canvas.plot(text)
16+
vcs_canvas.png('output.png')
17+
18+
viewer = OutputViewer(index_name='My Cool Results')
19+
# 'My Results' is the title of the page in the index. 'Generated File' is the column for each group.
20+
viewer.add_page("My Results", ['Generated File'])
21+
viewer.add_group('Results of addition')
22+
viewer.add_row('Result of 1 + 1', file_name='output.png')
23+
viewer.add_row('Another Result', file_name='output.png')
24+
viewer.add_group('Results of sub')
25+
viewer.add_row('sub2', file_name='output.png')
26+
viewer.generate_viewer()

example/my_metrics/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import add
2+
import sub
3+
4+
add = add.Add()
5+
sub = sub.Sub()

example/my_metrics/add.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import cdp.cdp_metric
2+
3+
class Add(cdp.cdp_metric.CDPMetric):
4+
def compute(self, a, b):
5+
return a + b

example/my_metrics/sub.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import cdp.cdp_metric
2+
3+
class Sub(cdp.cdp_metric.CDPMetric):
4+
def compute(self, a, b):
5+
return a - b

0 commit comments

Comments
 (0)