4444techniques.
4545"""
4646
47- from __future__ import absolute_import , division , print_function , unicode_literals
48- import six
49-
50- import os
5147import argparse
52-
53- from pprint import pprint
48+ import os
5449from collections import OrderedDict
55-
56- import numpy as np
57- from scipy import stats
50+ from pathlib import Path
51+ from pprint import pprint
5852
5953import livvkit
60- from livvkit .util import elements as el
54+ import numpy as np
55+ import pandas as pd
56+ import six
57+ from livvkit import elements as el
6158from livvkit .util import functions as fn
6259from livvkit .util .LIVVDict import LIVVDict
60+ from scipy import stats
6361
62+ from evv4esm import EVVException , human_color_names
6463from evv4esm .ensembles import e3sm
6564from evv4esm .ensembles .tools import monthly_to_annual_avg , prob_plot
6665from evv4esm .utils import bib2html
67- from evv4esm import human_color_names , EVVException
6866
6967
7068def variable_set (name ):
@@ -118,7 +116,7 @@ def parse_args(args=None):
118116 default = 13 , type = float ,
119117 help = 'The critical value (desired significance level) for rejecting the ' +
120118 'null hypothesis.' )
121-
119+
122120 parser .add_argument ('--img-dir' ,
123121 default = os .getcwd (),
124122 help = 'Image output location.' )
@@ -138,13 +136,26 @@ def parse_args(args=None):
138136 args .config ['ks' ][key ] = val
139137
140138 config_arg_list = []
141- [config_arg_list .extend (['--' + key , str (val )]) for key , val in args .config ['ks' ].items ()
142- if key != 'config' ]
139+ _ = [
140+ config_arg_list .extend (['--' + key , str (val )])
141+ for key , val in args .config ['ks' ].items () if key != 'config'
142+ ]
143143 args , _ = parser .parse_known_args (config_arg_list )
144144
145145 return args
146146
147147
148+ def col_fmt (dat ):
149+ """Format results for table output."""
150+ if dat is not None :
151+ try :
152+ _out = "{:.3e}, {:.3e}" .format (* dat )
153+ except TypeError :
154+ _out = dat
155+ else :
156+ _out = "-"
157+ return _out
158+
148159def run (name , config ):
149160 """
150161 Runs the analysis.
@@ -156,7 +167,7 @@ def run(name, config):
156167 Returns:
157168 The result of elements.page with the list of elements to display
158169 """
159-
170+
160171 config_arg_list = []
161172 [config_arg_list .extend (['--' + key , str (val )]) for key , val in config .items ()]
162173
@@ -167,31 +178,52 @@ def run(name, config):
167178
168179 details , img_gal = main (args )
169180
170- tbl_data = OrderedDict (sorted (details .items ()))
171- tbl_el = {'Type' : 'V-H Table' ,
172- 'Title' : 'Validation' ,
173- 'TableTitle' : 'Analyzed variables' ,
174- 'Headers' : ['h0' , 'K-S test (D, p)' , 'T test (t, p)' ],
175- 'Data' : {'' : tbl_data }
176- }
181+ table_data = pd .DataFrame (details ).T
182+ _hdrs = [
183+ "h0" ,
184+ "K-S test (D, p)" ,
185+ "T test (t, p)" ,
186+ "mean (test case, ref. case)" ,
187+ "std (test case, ref. case)" ,
188+ ]
189+ table_data = table_data [_hdrs ]
190+ for _hdr in _hdrs [1 :]:
191+ table_data [_hdr ] = table_data [_hdr ].apply (col_fmt )
192+
193+ tables = [
194+ el .Table ("Rejected" , data = table_data [table_data ["h0" ] == "reject" ]),
195+ el .Table ("Accepted" , data = table_data [table_data ["h0" ] == "accept" ]),
196+ el .Table ("Null" , data = table_data [~ table_data ["h0" ].isin (["accept" , "reject" ])])
197+ ]
198+
177199 bib_html = bib2html (os .path .join (os .path .dirname (__file__ ), 'ks.bib' ))
178- tl = [el .tab ('Figures' , element_list = [img_gal ]),
179- el .tab ('Details' , element_list = [tbl_el ]),
180- el .tab ('References' , element_list = [el .html (bib_html )])]
181-
182- rejects = [var for var , dat in tbl_data .items () if dat ['h0' ] == 'reject' ]
183- results = {'Type' : 'Table' ,
184- 'Title' : 'Results' ,
185- 'Headers' : ['Test status' , 'Variables analyzed' , 'Rejecting' , 'Critical value' , 'Ensembles' ],
186- 'Data' : {'Test status' : 'pass' if len (rejects ) < args .critical else 'fail' ,
187- 'Variables analyzed' : len (tbl_data .keys ()),
188- 'Rejecting' : len (rejects ),
189- 'Critical value' : args .critical ,
190- 'Ensembles' : 'statistically identical' if len (rejects ) < args .critical else 'statistically different' }
191- }
200+
201+ tabs = el .Tabs (
202+ {
203+ "Figures" : img_gal ,
204+ "Details" : tables ,
205+ "References" : [el .RawHTML (bib_html )]
206+ }
207+ )
208+ rejects = [var for var , dat in details .items () if dat ["h0" ] == "reject" ]
209+
210+ results = el .Table (
211+ title = "Results" ,
212+ data = OrderedDict (
213+ {
214+ 'Test status' : ['pass' if len (rejects ) < args .critical else 'fail' ],
215+ 'Variables analyzed' : [len (details .keys ())],
216+ 'Rejecting' : [len (rejects )],
217+ 'Critical value' : [int (args .critical )],
218+ 'Ensembles' : [
219+ 'statistically identical' if len (rejects ) < args .critical else 'statistically different'
220+ ]
221+ }
222+ )
223+ )
192224
193225 # FIXME: Put into a ___ function
194- page = el .page (name , __doc__ .replace ('\n \n ' , '<br><br>' ), element_list = [results ], tab_list = tl )
226+ page = el .Page (name , __doc__ .replace ('\n \n ' , '<br><br>' ), elements = [results , tabs ] )
195227 return page
196228
197229
@@ -232,17 +264,17 @@ def print_details(details):
232264
233265
234266def summarize_result (results_page ):
235- summary = {'Case' : results_page ['Title' ]}
236- for elem in results_page ['Data' ]['Elements' ]:
237- if elem ['Type' ] == 'Table' and elem ['Title' ] == 'Results' :
238- summary ['Test status' ] = elem ['Data' ]['Test status' ]
239- summary ['Variables analyzed' ] = elem ['Data' ]['Variables analyzed' ]
240- summary ['Rejecting' ] = elem ['Data' ]['Rejecting' ]
241- summary ['Critical value' ] = elem ['Data' ]['Critical value' ]
242- summary ['Ensembles' ] = elem ['Data' ]['Ensembles' ]
267+ summary = {'Case' : results_page .title }
268+
269+ for elem in results_page .elements :
270+ if isinstance (elem , el .Table ) and elem .title == "Results" :
271+ summary ['Test status' ] = elem .data ['Test status' ][0 ]
272+ summary ['Variables analyzed' ] = elem .data ['Variables analyzed' ][0 ]
273+ summary ['Rejecting' ] = elem .data ['Rejecting' ][0 ]
274+ summary ['Critical value' ] = elem .data ['Critical value' ][0 ]
275+ summary ['Ensembles' ] = elem .data ['Ensembles' ][0 ]
243276 break
244- else :
245- continue
277+
246278 return {'' : summary }
247279
248280
@@ -251,13 +283,13 @@ def populate_metadata():
251283 Generates the metadata responsible for telling the summary what
252284 is done by this module's run method
253285 """
254-
286+
255287 metadata = {'Type' : 'ValSummary' ,
256288 'Title' : 'Validation' ,
257289 'TableTitle' : 'Kolmogorov-Smirnov test' ,
258290 'Headers' : ['Test status' , 'Variables analyzed' , 'Rejecting' , 'Critical value' , 'Ensembles' ]}
259291 return metadata
260-
292+
261293
262294def main (args ):
263295 ens_files , key1 , key2 = case_files (args )
@@ -276,7 +308,7 @@ def main(args):
276308 if not common_vars :
277309 raise EVVException ('No common variables between {} and {} to analyze!' .format (args .test_case , args .ref_case ))
278310
279- img_list = []
311+ images = { "accept" : [], "reject" : [], "-" : []}
280312 details = LIVVDict ()
281313 for var in sorted (common_vars ):
282314 annuals_1 = annual_avgs .query ('case == @args.test_case & variable == @var' ).monthly_mean .values
@@ -307,24 +339,32 @@ def main(args):
307339 img_file = os .path .relpath (os .path .join (args .img_dir , var + '.png' ), os .getcwd ())
308340 prob_plot (annuals_1 , annuals_2 , 20 , img_file , test_name = args .test_case , ref_name = args .ref_case ,
309341 pf = details [var ]['h0' ])
310-
311- img_desc = 'Mean annual global average of {var} for <em>{testcase}</em> ' \
342+ _desc = monthly_avgs . query ( 'case == @args.test_case & variable == @var' ). desc . values [ 0 ]
343+ img_desc = 'Mean annual global average of {var}{desc} for <em>{testcase}</em> ' \
312344 'is {testmean:.3e} and for <em>{refcase}</em> is {refmean:.3e}. ' \
313345 'Pass (fail) is indicated by {cpass} ({cfail}) coloring of the ' \
314346 'plot markers and bars.' .format (var = var ,
347+ desc = _desc ,
315348 testcase = args .test_case ,
316349 testmean = details [var ]['mean (test case, ref. case)' ][0 ],
317350 refcase = args .ref_case ,
318351 refmean = details [var ]['mean (test case, ref. case)' ][1 ],
319352 cfail = human_color_names ['fail' ][0 ],
320353 cpass = human_color_names ['pass' ][0 ])
321354
322- img_link = os .path .join (os .path .basename (args .img_dir ), os .path .basename (img_file ))
323- img_list .append (el .image (var , img_desc , img_link ))
324-
325- img_gal = el .gallery ('Analyzed variables' , img_list )
355+ img_link = Path (* Path (args .img_dir ).parts [- 2 :], Path (img_file ).name )
356+ _img = el .Image (var , img_desc , img_link , relative_to = "" , group = details [var ]['h0' ])
357+ images [details [var ]['h0' ]].append (_img )
358+
359+ gals = []
360+ for group in ["reject" , "accept" , "-" ]:
361+ _group_name = {
362+ "reject" : "Failed variables" , "accept" : "Passed variables" , "-" : "Null variables"
363+ }
364+ if images [group ]:
365+ gals .append (el .Gallery (_group_name [group ], images [group ]))
326366
327- return details , img_gal
367+ return details , gals
328368
329369
330370if __name__ == '__main__' :
0 commit comments