From 5b8b15ea02a959e367831e031112588967f7fda0 Mon Sep 17 00:00:00 2001 From: Peter Willendrup Date: Thu, 9 Jul 2026 22:04:07 +0200 Subject: [PATCH 1/9] Expand template for possible DIFF view link --- tools/Python/mctest/main.template | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/Python/mctest/main.template b/tools/Python/mctest/main.template index 85e554c46..e31fdd170 100644 --- a/tools/Python/mctest/main.template +++ b/tools/Python/mctest/main.template @@ -50,11 +50,17 @@ a:visited { color: lightgrey; background-color: transparent; text-decoration: no C:{{ c.1 }}/R:{{ c.2 }}
I={{ c.3 }} ({{ c.4 }})

{{ c.6 }}
PLOTS: [Interactive HTML] [PDF overview] + {%- if c.8 %} +
DIFF: [vs ref] + {%- endif %} {%- elif c.0 == 2 %} C:{{ c.1 }}/R:{{ c.2 }}
I={{ c.3 }} ({{ c.4 }})

{{ c.6 }}
PLOTS: [Interactive HTML] [PDF overview] + {%- if c.8 %} +
DIFF: [vs ref] + {%- endif %} {%- elif c.0 == 3 %} C:{{ c.1 }} From 6556cfa33a6b6d7bd27696676a1ebe06a6972fc5 Mon Sep 17 00:00:00 2001 From: Peter Willendrup Date: Thu, 9 Jul 2026 22:10:54 +0200 Subject: [PATCH 2/9] Let mcviewtest generate "diff" links for comparison to the "reference" column --- tools/Python/mctest/mcviewtest.py | 71 ++++++++++++++++++++++++++++--- 1 file changed, 66 insertions(+), 5 deletions(-) mode change 100755 => 100644 tools/Python/mctest/mcviewtest.py diff --git a/tools/Python/mctest/mcviewtest.py b/tools/Python/mctest/mcviewtest.py old mode 100755 new mode 100644 index c219325ec..e65793e4d --- a/tools/Python/mctest/mcviewtest.py +++ b/tools/Python/mctest/mcviewtest.py @@ -31,7 +31,7 @@ def get_oldest_dir(directory_name): files.sort(key=lambda x:x[0]) return files[0][1] -def run_normal_mode(testdir, reflabel): +def run_normal_mode(testdir, reflabel, nodiff=False, diffmax=300): ''' load test data and print to html label ''' def get_col_header(label, meta): @@ -53,7 +53,55 @@ def get_header_lst(meta): lst.append(meta["date"]) return lst - def get_cell_tuple(cellobj, refval=None): + def get_data_url(cellobj): + ''' Reconstructs the relative "label/instrname/testnb/" data directory + for a cellobj, the same way get_cell_tuple() does for its own + cell - used here to also locate the *reference* column's data + directory when generating a diff link. ''' + label = cellobj["localfile"].split("/") + if len(label) == 1: + label = cellobj["localfile"].split("\\") + label = label[len(label) - 3] + return label + "/" + cellobj["instrname"] + "/" + str(cellobj["testnb"]) + "/" + + def generate_diff_link(refcellobj, url, label): + ''' Generates (or reuses a cached) mcplotdiff-html comparison between + this cell's own test-output directory and the reference column's + corresponding directory, returning a relative URL to the diff + overview's index.html, or None if a diff isn't available/possible + (missing/incomplete data on either side, disabled via --nodiff, + or the plotter itself failing). ''' + if nodiff: + return None + if refcellobj is None or refcellobj.get("testval") is None: + # no valid reference data to diff against + return None + + ref_url = get_data_url(refcellobj) + test_abs = join(testdir, url) + ref_abs = join(testdir, ref_url) + if not (os.path.isfile(join(test_abs, "mccode.sim")) and os.path.isfile(join(ref_abs, "mccode.sim"))): + # NeXus-only output (mccode.h5) or otherwise nothing mcplotdiff-html can compare + return None + + outdir_rel = join(url, "diff_vs_%s" % reflabel) + outdir_abs = join(testdir, outdir_rel) + index_abs = join(outdir_abs, "index.html") + + if not os.path.isfile(index_abs): + diffplotter = mccode_config.configuration["MCPLOT"].split('-')[0] + "diff-html" + cmd = '%s "%s" "%s" --nobrowse -A "%s" -B "%s" --output "%s"' % ( + diffplotter, test_abs, ref_abs, label, reflabel, outdir_abs) + try: + utils.run_subtool_noread(cmd, cwd=testdir, timeout=diffmax) + except Exception as e: + print("generate_diff_link: %s" % str(e)) + + if os.path.isfile(index_abs): + return (outdir_rel + "/index.html").replace(os.sep, '/').replace("//", "/") + return None + + def get_cell_tuple(cellobj, refval=None, refcellobj=None): ''' set up and format cell data ''' state = None compiletime = None @@ -141,7 +189,9 @@ def get_cell_tuple(cellobj, refval=None): else: refp = "%2.f" % refp + "%" - return (state, compiletime, runtime, testval, refp, url, display, displayurl) + diffurl = generate_diff_link(refcellobj, url, label) + + return (state, compiletime, runtime, testval, refp, url, display, displayurl, diffurl) def get_empty_cell_tuple(tag=None): ''' return a "state_four" black cell, optionally with a tag, this could be "no ref" or "no test" etc. ''' @@ -188,7 +238,13 @@ def iterate_obj_to_populate_rows(iterobj, otherobjs, rows, ncols, use_iterobj_re targetval = o.get("targetval", None) if use_iterobj_refvalue: targetval = iterobj[key]["targetval"] - row.append(get_cell_tuple(o, targetval)) + # diff cells always compare against the true reference + # column (refobj), regardless of which object is + # currently driving iteration (iterobj may be a + # fallback "lead" column rather than refobj itself, in + # the untested multi-column case below) + refcellobj = refobj.get(key, None) + row.append(get_cell_tuple(o, targetval, refcellobj=refcellobj)) # delete "used" cell keys if del_used_from_overobjs: @@ -304,7 +360,10 @@ def main(args): print("No testdir defined, will use current dir") print("--> Using testdir=%s\n" % os.getcwd()) testdir=os.getcwd() - run_normal_mode(testdir, reflabel) + diffmax = 300 + if args.diffmax: + diffmax = int(args.diffmax[0]) + run_normal_mode(testdir, reflabel, nodiff=args.nodiff, diffmax=diffmax) if not args.nobrowse: subprocess.Popen('%s %s' % (mccode_config.configuration['BROWSER'], os.path.join(testdir,os.path.basename(testdir) +'_output.html')), shell=True) @@ -318,6 +377,8 @@ def main(args): parser.add_argument('--testroot', nargs="?", help='test root folder for test result management') parser.add_argument('--verbose', action='store_true', help='output excessive information for debug purposes') parser.add_argument('--nobrowse', action='store_true', help='Do not spawn browser on exit') + parser.add_argument('--nodiff', action='store_true', help='Do not generate mcplotdiff-html comparison cells against the reference column') + parser.add_argument('--diffmax', nargs=1, help='Maximum time (s) allowed per mcplotdiff-html comparison (default 300s)') args = parser.parse_args() main(args) From d8256757737696a2eadfbca83acc663f57c2c11e Mon Sep 17 00:00:00 2001 From: Peter Willendrup Date: Fri, 10 Jul 2026 09:16:56 +0200 Subject: [PATCH 3/9] Add a
in the cell to separate DIFF from the rest --- tools/Python/mctest/main.template | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/Python/mctest/main.template b/tools/Python/mctest/main.template index e31fdd170..9fb7cb22c 100644 --- a/tools/Python/mctest/main.template +++ b/tools/Python/mctest/main.template @@ -51,7 +51,7 @@ a:visited { color: lightgrey; background-color: transparent; text-decoration: no
{{ c.6 }}
PLOTS: [Interactive HTML] [PDF overview] {%- if c.8 %} -
DIFF: [vs ref] +

DIFF: [vs ref] {%- endif %} {%- elif c.0 == 2 %} From 061fad4dc7234bb35b6577a5f1b8910ba03e9bba Mon Sep 17 00:00:00 2001 From: Peter Willendrup Date: Fri, 10 Jul 2026 09:33:42 +0200 Subject: [PATCH 4/9] Attempt to make the diff-pages more readable --- tools/Python/mcplot/html/mcplotdiff.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tools/Python/mcplot/html/mcplotdiff.py b/tools/Python/mcplot/html/mcplotdiff.py index 724097e78..ec56f4b5a 100644 --- a/tools/Python/mcplot/html/mcplotdiff.py +++ b/tools/Python/mcplot/html/mcplotdiff.py @@ -318,7 +318,8 @@ def write_index(outdir, entries, label_a, label_b): outfile.write(" #sizecontrol input[type=range] { vertical-align: middle; margin: 0 8px; }\n") outfile.write("\n") outfile.write("\n") - outfile.write(f"

Difference plots: {label_a} − {label_b}

\n") + outfile.write("

Difference plots:

\n") + outfile.write(f"
  1. {label_a} vs.
  2. {label_b}
" outfile.write(f"

diff.monitor = ({label_a}).monitor − ({label_b}).monitor

\n") outfile.write("
\n") outfile.write(" \n") @@ -349,13 +350,13 @@ def write_index(outdir, entries, label_a, label_b): if a_lin or a_log or b_lin or b_log: outfile.write("|\n") if a_lin: - outfile.write(f"[ {label_a} ]\n") + outfile.write(f"[ A ]\n") if a_log: - outfile.write(f"[ {label_a} (log) ]\n") + outfile.write(f"[ A (log) ]\n") if b_lin: - outfile.write(f"[ {label_b} ]\n") + outfile.write(f"[ B ]\n") if b_log: - outfile.write(f"[ {label_b} (log) ]\n") + outfile.write(f"[ B (log) ]\n") outfile.write("
\n") outfile.write("\n") From ee085eb4c9dfa180c4a945c53308e18946ce8ff0 Mon Sep 17 00:00:00 2001 From: Peter Willendrup Date: Fri, 10 Jul 2026 09:41:07 +0200 Subject: [PATCH 5/9] Close by ) statement --- tools/Python/mcplot/html/mcplotdiff.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/Python/mcplot/html/mcplotdiff.py b/tools/Python/mcplot/html/mcplotdiff.py index ec56f4b5a..b821d10c8 100644 --- a/tools/Python/mcplot/html/mcplotdiff.py +++ b/tools/Python/mcplot/html/mcplotdiff.py @@ -319,7 +319,7 @@ def write_index(outdir, entries, label_a, label_b): outfile.write("\n") outfile.write("\n") outfile.write("

Difference plots:

\n") - outfile.write(f"
  1. {label_a} vs.
  2. {label_b}
" + outfile.write(f"
  1. {label_a} vs.
  2. {label_b}
") outfile.write(f"

diff.monitor = ({label_a}).monitor − ({label_b}).monitor

\n") outfile.write("
\n") outfile.write(" \n") From 81431880fcd5bdc30585f3cfda22377e0687d816 Mon Sep 17 00:00:00 2001 From: Peter Willendrup Date: Fri, 10 Jul 2026 09:44:58 +0200 Subject: [PATCH 6/9] Try separating links with
--- tools/Python/mcplot/html/mcplotdiff.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/Python/mcplot/html/mcplotdiff.py b/tools/Python/mcplot/html/mcplotdiff.py index b821d10c8..85a623a6a 100644 --- a/tools/Python/mcplot/html/mcplotdiff.py +++ b/tools/Python/mcplot/html/mcplotdiff.py @@ -348,13 +348,13 @@ def write_index(outdir, entries, label_a, label_b): b_lin = _relhref(entry.get('b_lin'), outdir) b_log = _relhref(entry.get('b_log'), outdir) if a_lin or a_log or b_lin or b_log: - outfile.write("|\n") + outfile.write("\n") if a_lin: - outfile.write(f"[ A ]\n") + outfile.write(f"
[ A ]\n") if a_log: outfile.write(f"[ A (log) ]\n") if b_lin: - outfile.write(f"[ B ]\n") + outfile.write(f"
[ B ]\n") if b_log: outfile.write(f"[ B (log) ]\n") From d95a4b660a8ded722ce59cf2d4dda019dc746429 Mon Sep 17 00:00:00 2001 From: Peter Willendrup Date: Fri, 10 Jul 2026 09:46:09 +0200 Subject: [PATCH 7/9]
->
--- tools/Python/mcplot/html/mcplotdiff.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/Python/mcplot/html/mcplotdiff.py b/tools/Python/mcplot/html/mcplotdiff.py index 85a623a6a..025f3899d 100644 --- a/tools/Python/mcplot/html/mcplotdiff.py +++ b/tools/Python/mcplot/html/mcplotdiff.py @@ -350,11 +350,11 @@ def write_index(outdir, entries, label_a, label_b): if a_lin or a_log or b_lin or b_log: outfile.write("\n") if a_lin: - outfile.write(f"
[ A ]\n") + outfile.write(f"
[ A ]\n") if a_log: outfile.write(f"[ A (log) ]\n") if b_lin: - outfile.write(f"
[ B ]\n") + outfile.write(f"
[ B ]\n") if b_log: outfile.write(f"[ B (log) ]\n") From 5ac3e2c959c0fe464f3ab5cfdeee2f44799e1ed2 Mon Sep 17 00:00:00 2001 From: Peter Willendrup Date: Fri, 10 Jul 2026 09:59:33 +0200 Subject: [PATCH 8/9] Acceptable but not great: Links below diff mons --- tools/Python/mcplot/html/mcplotdiff.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/tools/Python/mcplot/html/mcplotdiff.py b/tools/Python/mcplot/html/mcplotdiff.py index 025f3899d..c6e43222c 100644 --- a/tools/Python/mcplot/html/mcplotdiff.py +++ b/tools/Python/mcplot/html/mcplotdiff.py @@ -336,11 +336,12 @@ def write_index(outdir, entries, label_a, label_b): outfile.write(f"\n") outfile.write("
\n") outfile.write("\n") outfile.write("\n") outfile.write("\n") From 53557760061c8f74550f34fc3e5819a803fdc64e Mon Sep 17 00:00:00 2001 From: Peter Willendrup Date: Fri, 10 Jul 2026 11:17:19 +0200 Subject: [PATCH 9/9] Make clear that no datafile is available in 'diff mode' --- tools/Python/mcplot/html/mcplot.py | 3 ++- tools/Python/mcplot/html/mcplotdiff.py | 1 + tools/Python/mcplot/html/template_1d.html | 2 +- tools/Python/mcplot/html/template_2d.html | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/tools/Python/mcplot/html/mcplot.py b/tools/Python/mcplot/html/mcplot.py index a66694762..29fd40a3f 100644 --- a/tools/Python/mcplot/html/mcplot.py +++ b/tools/Python/mcplot/html/mcplot.py @@ -40,7 +40,8 @@ def get_html(template_name, params, simfile): text = open(os.path.join(os.path.dirname(__file__),template_name)).read() text = text.replace("@PARAMS@", params) text = text.replace("@DATAFILE@", simfile) - + text = text.replace("@DATALINK@", "Click for ascii data") + logscalestr = "true" if logscale==True else "false" text = text.replace("@LOGSCALE@", logscalestr) text = text.replace("@LIBPATH@", libpath) diff --git a/tools/Python/mcplot/html/mcplotdiff.py b/tools/Python/mcplot/html/mcplotdiff.py index c6e43222c..1dd6b379c 100644 --- a/tools/Python/mcplot/html/mcplotdiff.py +++ b/tools/Python/mcplot/html/mcplotdiff.py @@ -88,6 +88,7 @@ def get_html(template_name, params, simfile): text = open(os.path.join(os.path.dirname(__file__), template_name)).read() text = text.replace("@PARAMS@", params) text = text.replace("@DATAFILE@", simfile) + text = text.replace("@DATALINK@", "Diff mode (no physical datafile)") # Nothing to link to in diff-mode logscalestr = "true" if logscale == True else "false" text = text.replace("@LOGSCALE@", logscalestr) diff --git a/tools/Python/mcplot/html/template_1d.html b/tools/Python/mcplot/html/template_1d.html index e4356acbf..ece1e1cb6 100644 --- a/tools/Python/mcplot/html/template_1d.html +++ b/tools/Python/mcplot/html/template_1d.html @@ -13,6 +13,6 @@ plt.rgstrMouseRClickPlot( () => { console.log("right click"); } );

-Click for ascii data +@DATALINK@ diff --git a/tools/Python/mcplot/html/template_2d.html b/tools/Python/mcplot/html/template_2d.html index 217fcaf6f..fdd0a7fbf 100644 --- a/tools/Python/mcplot/html/template_2d.html +++ b/tools/Python/mcplot/html/template_2d.html @@ -13,6 +13,6 @@ plt.rgstrMouseRClickPlot( () => { console.log("right click"); } );

-Click for ascii data +@DATALINK@