X-Git-Url: https://gerrit.fd.io/r/gitweb?p=csit.git;a=blobdiff_plain;f=resources%2Ftools%2Fpresentation%2Fgenerator_plots.py;h=48af3432452f97374e8a2146d02e656ef26112f8;hp=7cdcb62e1f7e82d2e4597a8bd871bc0cbf419811;hb=23185b233e4dd7984a404aa54d5dd0da2502074b;hpb=3532ea7e201971b463e6d72ae799a7871c5b3c9f diff --git a/resources/tools/presentation/generator_plots.py b/resources/tools/presentation/generator_plots.py index 7cdcb62e1f..48af343245 100644 --- a/resources/tools/presentation/generator_plots.py +++ b/resources/tools/presentation/generator_plots.py @@ -35,6 +35,8 @@ COLORS = ["SkyBlue", "Olive", "Purple", "Coral", "Indigo", "Pink", "LightGreen", "LightSeaGreen", "LightSkyBlue", "Maroon", "MediumSeaGreen", "SeaGreen", "LightSlateGrey"] +REGEX_NIC = re.compile(r'\d*ge\dp\d\D*\d*-') + def generate_plots(spec, data): """Generate all plots specified in the specification file. @@ -145,21 +147,14 @@ def plot_performance_box(plot, input_data): df.head() y_max = list() for i, col in enumerate(df.columns): + tst_name = re.sub(REGEX_NIC, "", + col.lower().replace('-ndrpdr', ''). + replace('2n1l-', '')) name = "{nr}. ({samples:02d} run{plural}) {name}".\ format(nr=(i + 1), samples=nr_of_samples[i], plural='s' if nr_of_samples[i] > 1 else '', - name=col.lower().replace('-ndrpdr', '')) - if len(name) > 50: - name_lst = name.split('-') - name = "" - split_name = True - for segment in name_lst: - if (len(name) + len(segment) + 1) > 50 and split_name: - name += "
" - split_name = False - name += segment + '-' - name = name[:-1] + name=tst_name) logging.debug(name) traces.append(plgo.Box(x=[str(i + 1) + '.'] * len(df[col]), @@ -178,7 +173,7 @@ def plot_performance_box(plot, input_data): # Create plot layout = deepcopy(plot["layout"]) if layout.get("title", None): - layout["title"] = "Packet Throughput: {0}". \ + layout["title"] = "Throughput: {0}". \ format(layout["title"]) if y_max: layout["yaxis"]["range"] = [0, max(y_max)] @@ -383,13 +378,14 @@ def plot_soak_boxes(plot, input_data): for test_name, test_data in y_sorted.items(): idx += 1 name = "{nr}. {name}".\ - format(nr=idx, name=test_name.lower().replace('-soak', '')) - if len(name) > 50: + format(nr=idx, name=test_name.lower().replace('-soak', ''). + replace('2n1l-', '')) + if len(name) > 55: name_lst = name.split('-') name = "" split_name = True for segment in name_lst: - if (len(name) + len(segment) + 1) > 50 and split_name: + if (len(name) + len(segment) + 1) > 55 and split_name: name += "
" split_name = False name += segment + '-' @@ -405,10 +401,8 @@ def plot_soak_boxes(plot, input_data): if y_base: y_base /= 1000000 - hovertext = ("{name}
" - "Upper bound: {upper:.2f}Mpps
" - "Lower bound: {lower:.2f}Mpps".format(name=name, - upper=y_val, + hovertext = ("Upper bound: {upper:.2f}
" + "Lower bound: {lower:.2f}".format(upper=y_val, lower=y_base)) traces.append(plgo.Bar(x=[str(idx) + '.', ], # +0.05 to see the value in case lower == upper @@ -421,7 +415,7 @@ def plot_soak_boxes(plot, input_data): # Create plot layout = deepcopy(plot["layout"]) if layout.get("title", None): - layout["title"] = "Soak Tests: {0}". \ + layout["title"] = "Throughput: {0}". \ format(layout["title"]) if y_max: layout["yaxis"]["range"] = [0, y_max + 1] @@ -541,17 +535,8 @@ def plot_latency_error_bars(plot, input_data): y_maxs = list() nr_of_samples = list() for key, val in y_sorted.items(): - name = "-".join(key.split("-")[1:-1]) - if len(name) > 50: - name_lst = name.split('-') - name = "" - split_name = True - for segment in name_lst: - if (len(name) + len(segment) + 1) > 50 and split_name: - name += "
" - split_name = False - name += segment + '-' - name = name[:-1] + name = re.sub(REGEX_NIC, "", key.replace('-ndrpdr', ''). + replace('2n1l-', '')) x_vals.append(name) # dir 1 y_vals.append(mean(val[1]) if val[1] else None) y_mins.append(mean(val[0]) if val[0] else None) @@ -641,7 +626,7 @@ def plot_latency_error_bars(plot, input_data): format(plot["output-file"], plot["output-file-type"])) layout = deepcopy(plot["layout"]) if layout.get("title", None): - layout["title"] = "Packet Latency: {0}".\ + layout["title"] = "Latency: {0}".\ format(layout["title"]) layout["annotations"] = annotations plpl = plgo.Figure(data=traces, layout=layout) @@ -730,18 +715,8 @@ def plot_throughput_speedup_analysis(plot, input_data): for test_name, test_vals in y_vals.items(): try: if test_vals["1"][1]: - name = "-".join(test_name.split('-')[1:-1]) - if len(name) > 50: - name_lst = name.split('-') - name = "" - split_name = True - for segment in name_lst: - if (len(name) + len(segment) + 1) > 50 and split_name: - name += "
" - split_name = False - name += segment + '-' - name = name[:-1] - + name = re.sub(REGEX_NIC, "", test_name.replace('-ndrpdr', ''). + replace('2n1l-', '')) vals[name] = dict() y_val_1 = test_vals["1"][0] / 1000000.0 y_val_2 = test_vals["2"][0] / 1000000.0 if test_vals["2"][0] \ @@ -761,12 +736,14 @@ def plot_throughput_speedup_analysis(plot, input_data): test_vals["4"][1]] try: - val_max = max(max(vals[name]["val"], vals[name]["ideal"])) + # val_max = max(max(vals[name]["val"], vals[name]["ideal"])) + val_max = max(vals[name]["val"]) except ValueError as err: logging.error(err) continue if val_max: - y_max.append(int((val_max / 10) + 1) * 10) + # y_max.append(int((val_max / 10) + 1) * 10) + y_max.append(val_max) if y_val_2: vals[name]["rel"][1] = round(y_val_2 / y_val_1, 2) @@ -818,7 +795,9 @@ def plot_throughput_speedup_analysis(plot, input_data): for tag in order: for test, tags in y_tags_l.items(): if tag.lower() in tags: - name = "-".join(test.split('-')[1:-1]) + name = re.sub(REGEX_NIC, "", + test.replace('-ndrpdr', ''). + replace('2n1l-', '')) try: y_sorted[name] = vals.pop(name) y_tags_l.pop(test) @@ -840,35 +819,36 @@ def plot_throughput_speedup_analysis(plot, input_data): logging.error(err) return nic_limit /= 1000000.0 - if nic_limit < threshold: - traces.append(plgo.Scatter( - x=x_vals, - y=[nic_limit, ] * len(x_vals), - name="NIC: {0:.2f}Mpps".format(nic_limit), - showlegend=False, - mode="lines", - line=dict( - dash="dot", - color=COLORS[-1], - width=1), - hoverinfo="none" - )) - annotations.append(dict( - x=1, - y=nic_limit, - xref="x", - yref="y", - xanchor="left", - yanchor="bottom", - text="NIC: {0:.2f}Mpps".format(nic_limit), - font=dict( - size=14, - color=COLORS[-1], - ), - align="left", - showarrow=False - )) - y_max.append(int((nic_limit / 10) + 1) * 10) + # if nic_limit < threshold: + traces.append(plgo.Scatter( + x=x_vals, + y=[nic_limit, ] * len(x_vals), + name="NIC: {0:.2f}Mpps".format(nic_limit), + showlegend=False, + mode="lines", + line=dict( + dash="dot", + color=COLORS[-1], + width=1), + hoverinfo="none" + )) + annotations.append(dict( + x=1, + y=nic_limit, + xref="x", + yref="y", + xanchor="left", + yanchor="bottom", + text="NIC: {0:.2f}Mpps".format(nic_limit), + font=dict( + size=14, + color=COLORS[-1], + ), + align="left", + showarrow=False + )) + # y_max.append(int((nic_limit / 10) + 1) * 10) + y_max.append(nic_limit) lnk_limit /= 1000000.0 if lnk_limit < threshold: @@ -899,10 +879,12 @@ def plot_throughput_speedup_analysis(plot, input_data): align="left", showarrow=False )) - y_max.append(int((lnk_limit / 10) + 1) * 10) + # y_max.append(int((lnk_limit / 10) + 1) * 10) + y_max.append(lnk_limit) pci_limit /= 1000000.0 - if pci_limit < threshold: + if (pci_limit < threshold and + (pci_limit < lnk_limit * 0.95 or lnk_limit > lnk_limit * 1.05)): traces.append(plgo.Scatter( x=x_vals, y=[pci_limit, ] * len(x_vals), @@ -930,7 +912,8 @@ def plot_throughput_speedup_analysis(plot, input_data): align="left", showarrow=False )) - y_max.append(int((pci_limit / 10) + 1) * 10) + # y_max.append(int((pci_limit / 10) + 1) * 10) + y_max.append(pci_limit) # Perfect and measured: cidx = 0 @@ -990,6 +973,8 @@ def plot_throughput_speedup_analysis(plot, input_data): if layout.get("title", None): layout["title"] = "Speedup Multi-core: {0}". \ format(layout["title"]) + # layout["yaxis"]["range"] = [0, int((max(y_max) / 10) + 1) * 10] + layout["yaxis"]["range"] = [0, int(max(y_max) * 1.1)] layout["annotations"].extend(annotations) plpl = plgo.Figure(data=traces, layout=layout) @@ -1097,6 +1082,9 @@ def plot_service_density_heatmap(plot, input_data): """ REGEX_CN = re.compile(r'^(\d*)R(\d*)C$') + REGEX_TEST_NAME = re.compile(r'^.*-(\d+vhost|\d+memif)-' + r'(\d+chain|\d+pipe)-' + r'(\d+vm|\d+dcr|\d+drc).*$') txt_chains = list() txt_nodes = list() @@ -1106,7 +1094,7 @@ def plot_service_density_heatmap(plot, input_data): logging.info(" Creating the data set for the {0} '{1}'.". format(plot.get("type", ""), plot.get("title", ""))) data = input_data.filter_data(plot, continue_on_error=True) - if data is None: + if data is None or data.empty: logging.error("No data.") return @@ -1121,26 +1109,41 @@ def plot_service_density_heatmap(plot, input_data): break else: continue + groups = re.search(REGEX_TEST_NAME, test["name"]) + if groups and len(groups.groups()) == 3: + hover_name = "{vhost}-{chain}-{vm}".format( + vhost=str(groups.group(1)), + chain=str(groups.group(2)), + vm=str(groups.group(3))) + else: + hover_name = "" if vals.get(c, None) is None: vals[c] = dict() if vals[c].get(n, None) is None: - vals[c][n] = dict(name=test["name"], + vals[c][n] = dict(name=hover_name, vals=list(), nr=None, mean=None, stdev=None) - if plot["include-tests"] == "MRR": - result = test["result"]["receive-rate"].avg - elif plot["include-tests"] == "PDR": - result = test["throughput"]["PDR"]["LOWER"] - elif plot["include-tests"] == "NDR": - result = test["throughput"]["NDR"]["LOWER"] - else: + try: + if plot["include-tests"] == "MRR": + result = test["result"]["receive-rate"].avg + elif plot["include-tests"] == "PDR": + result = test["throughput"]["PDR"]["LOWER"] + elif plot["include-tests"] == "NDR": + result = test["throughput"]["NDR"]["LOWER"] + else: + result = None + except TypeError: result = None if result: vals[c][n]["vals"].append(result) + if not vals: + logging.error("No data.") + return + for key_c in vals.keys(): txt_chains.append(key_c) for key_n in vals[key_c].keys(): @@ -1148,9 +1151,9 @@ def plot_service_density_heatmap(plot, input_data): if vals[key_c][key_n]["vals"]: vals[key_c][key_n]["nr"] = len(vals[key_c][key_n]["vals"]) vals[key_c][key_n]["mean"] = \ - round(mean(vals[key_c][key_n]["vals"]) / 1000000, 2) + round(mean(vals[key_c][key_n]["vals"]) / 1000000, 1) vals[key_c][key_n]["stdev"] = \ - round(stdev(vals[key_c][key_n]["vals"]) / 1000000, 2) + round(stdev(vals[key_c][key_n]["vals"]) / 1000000, 1) txt_nodes = list(set(txt_nodes)) txt_chains = sorted(txt_chains, key=lambda chain: int(chain)) @@ -1168,13 +1171,23 @@ def plot_service_density_heatmap(plot, input_data): val = None data[c - 1].append(val) + # Colorscales: + my_green = [[0.0, 'rgb(235, 249, 242)'], + [1.0, 'rgb(45, 134, 89)']] + + my_blue = [[0.0, 'rgb(236, 242, 248)'], + [1.0, 'rgb(57, 115, 172)']] + + my_grey = [[0.0, 'rgb(230, 230, 230)'], + [1.0, 'rgb(102, 102, 102)']] + hovertext = list() annotations = list() - text = ("{name}
" - "No. of Samples: {nr}
" - "Throughput: {val}
" - "Stdev: {stdev}") + text = ("Test: {name}
" + "Runs: {nr}
" + "Thput: {val}
" + "StDev: {stdev}") for c in range(len(txt_chains)): hover_line = list() @@ -1206,22 +1219,30 @@ def plot_service_density_heatmap(plot, input_data): y=chains, z=data, colorbar=dict( - title="Packet Throughput [Mpps]", + title=plot.get("z-axis", ""), titleside="right", titlefont=dict( - size=14 + size=16 ), + tickfont=dict( + size=16, + ), + tickformat=".1f", + yanchor="bottom", + y=-0.02, + len=0.925, ), showscale=True, - colorscale="Reds", + colorscale=my_green, text=hovertext, hoverinfo="text") ] for idx, item in enumerate(txt_nodes): + # X-axis, numbers: annotations.append(dict( x=idx+1, - y=0, + y=0.05, xref="x", yref="y", xanchor="center", @@ -1234,8 +1255,9 @@ def plot_service_density_heatmap(plot, input_data): showarrow=False )) for idx, item in enumerate(txt_chains): + # Y-axis, numbers: annotations.append(dict( - x=0.3, + x=0.35, y=idx+1, xref="x", yref="y", @@ -1248,30 +1270,30 @@ def plot_service_density_heatmap(plot, input_data): align="center", showarrow=False )) - # X-axis: + # X-axis, title: annotations.append(dict( x=0.55, - y=1.05, + y=-0.15, xref="paper", - yref="paper", + yref="y", xanchor="center", - yanchor="middle", - text="No. of Network Functions per Service Instance", + yanchor="bottom", + text=plot.get("x-axis", ""), font=dict( size=16, ), align="center", showarrow=False )) - # Y-axis: + # Y-axis, title: annotations.append(dict( - x=-0.04, + x=-0.1, y=0.5, - xref="paper", + xref="x", yref="paper", xanchor="center", yanchor="middle", - text="No. of Service Instances", + text=plot.get("y-axis", ""), font=dict( size=16, ), @@ -1288,79 +1310,467 @@ def plot_service_density_heatmap(plot, input_data): direction='up', buttons=list([ dict( - args=[{"colorscale": "Reds", "reversescale": False}], - label="Red", + args=[{"colorscale": [my_green, ], "reversescale": False}], + label="Green", method="update" ), dict( - args=[{"colorscale": "Blues", "reversescale": True}], + args=[{"colorscale": [my_blue, ], "reversescale": False}], label="Blue", method="update" ), dict( - args=[{"colorscale": "Greys", "reversescale": True}], + args=[{"colorscale": [my_grey, ], "reversescale": False}], label="Grey", method="update" + ) + ]) + ) + ]) + + try: + layout = deepcopy(plot["layout"]) + except KeyError as err: + logging.error("Finished with error: No layout defined") + logging.error(repr(err)) + return + + layout["annotations"] = annotations + layout['updatemenus'] = updatemenus + + try: + # Create plot + plpl = plgo.Figure(data=traces, layout=layout) + + # Export Plot + logging.info(" Writing file '{0}{1}'.". + format(plot["output-file"], plot["output-file-type"])) + ploff.plot(plpl, show_link=False, auto_open=False, + filename='{0}{1}'.format(plot["output-file"], + plot["output-file-type"])) + except PlotlyError as err: + logging.error(" Finished with error: {}". + format(str(err).replace("\n", " "))) + return + + +def plot_service_density_heatmap_compare(plot, input_data): + """Generate the plot(s) with algorithm: plot_service_density_heatmap_compare + specified in the specification file. + + :param plot: Plot to generate. + :param input_data: Data to process. + :type plot: pandas.Series + :type input_data: InputData + """ + + REGEX_CN = re.compile(r'^(\d*)R(\d*)C$') + REGEX_TEST_NAME = re.compile(r'^.*-(\d+ch|\d+pl)-' + r'(\d+vh|\d+mif)-' + r'(\d+vm|\d+dcr).*$') + REGEX_THREADS = re.compile(r'^(\d+)(VM|DCR)(\d+)T$') + + txt_chains = list() + txt_nodes = list() + vals = dict() + + # Transform the data + logging.info(" Creating the data set for the {0} '{1}'.". + format(plot.get("type", ""), plot.get("title", ""))) + data = input_data.filter_data(plot, continue_on_error=True) + if data is None or data.empty: + logging.error("No data.") + return + + for job in data: + for build in job: + for test in build: + for tag in test['tags']: + groups = re.search(REGEX_CN, tag) + if groups: + c = str(groups.group(1)) + n = str(groups.group(2)) + break + else: + continue + groups = re.search(REGEX_TEST_NAME, test["name"]) + if groups and len(groups.groups()) == 3: + hover_name = "{chain}-{vhost}-{vm}".format( + chain=str(groups.group(1)), + vhost=str(groups.group(2)), + vm=str(groups.group(3))) + else: + hover_name = "" + if vals.get(c, None) is None: + vals[c] = dict() + if vals[c].get(n, None) is None: + vals[c][n] = dict(name=hover_name, + vals_r=list(), + vals_c=list(), + nr_r=None, + nr_c=None, + mean_r=None, + mean_c=None, + stdev_r=None, + stdev_c=None) + try: + if plot["include-tests"] == "MRR": + result = test["result"]["receive-rate"].avg + elif plot["include-tests"] == "PDR": + result = test["throughput"]["PDR"]["LOWER"] + elif plot["include-tests"] == "NDR": + result = test["throughput"]["NDR"]["LOWER"] + else: + result = None + except TypeError: + result = None + + if result: + for tag in test['tags']: + groups = re.search(REGEX_THREADS, tag) + if groups and len(groups.groups()) == 3: + if str(groups.group(3)) == \ + plot["reference"]["include"]: + vals[c][n]["vals_r"].append(result) + elif str(groups.group(3)) == \ + plot["compare"]["include"]: + vals[c][n]["vals_c"].append(result) + break + if not vals: + logging.error("No data.") + return + + for key_c in vals.keys(): + txt_chains.append(key_c) + for key_n in vals[key_c].keys(): + txt_nodes.append(key_n) + if vals[key_c][key_n]["vals_r"]: + vals[key_c][key_n]["nr_r"] = len(vals[key_c][key_n]["vals_r"]) + vals[key_c][key_n]["mean_r"] = \ + round(mean(vals[key_c][key_n]["vals_r"]) / 1000000, 1) + vals[key_c][key_n]["stdev_r"] = \ + round(stdev(vals[key_c][key_n]["vals_r"]) / 1000000, 1) + if vals[key_c][key_n]["vals_c"]: + vals[key_c][key_n]["nr_c"] = len(vals[key_c][key_n]["vals_c"]) + vals[key_c][key_n]["mean_c"] = \ + round(mean(vals[key_c][key_n]["vals_c"]) / 1000000, 1) + vals[key_c][key_n]["stdev_c"] = \ + round(stdev(vals[key_c][key_n]["vals_c"]) / 1000000, 1) + + txt_nodes = list(set(txt_nodes)) + + txt_chains = sorted(txt_chains, key=lambda chain: int(chain)) + txt_nodes = sorted(txt_nodes, key=lambda node: int(node)) + + chains = [i + 1 for i in range(len(txt_chains))] + nodes = [i + 1 for i in range(len(txt_nodes))] + + data_r = [list() for _ in range(len(chains))] + data_c = [list() for _ in range(len(chains))] + diff = [list() for _ in range(len(chains))] + for c in chains: + for n in nodes: + try: + val_r = vals[txt_chains[c - 1]][txt_nodes[n - 1]]["mean_r"] + except (KeyError, IndexError): + val_r = None + data_r[c - 1].append(val_r) + try: + val_c = vals[txt_chains[c - 1]][txt_nodes[n - 1]]["mean_c"] + except (KeyError, IndexError): + val_c = None + data_c[c - 1].append(val_c) + + if val_c is not None and val_r: + diff[c - 1].append(round((val_c - val_r) * 100 / val_r, 1)) + else: + diff[c - 1].append(None) + + # Colorscales: + my_green = [[0.0, 'rgb(235, 249, 242)'], + [1.0, 'rgb(45, 134, 89)']] + + my_blue = [[0.0, 'rgb(236, 242, 248)'], + [1.0, 'rgb(57, 115, 172)']] + + my_grey = [[0.0, 'rgb(230, 230, 230)'], + [1.0, 'rgb(102, 102, 102)']] + + hovertext = list() + + annotations = list() + annotations_r = list() + annotations_c = list() + annotations_diff = list() + + text = ("Test: {name}" + "
{title_r}: {text_r}" + "
{title_c}: {text_c}{text_diff}") + text_r = "Thput: {val_r}; StDev: {stdev_r}; Runs: {nr_r}" + text_c = "Thput: {val_c}; StDev: {stdev_c}; Runs: {nr_c}" + text_diff = "
Relative Difference {title_c} vs. {title_r}: {diff}%" + + for c in range(len(txt_chains)): + hover_line = list() + for n in range(len(txt_nodes)): + point = dict( + x=n + 1, + y=c + 1, + xref="x", + yref="y", + xanchor="center", + yanchor="middle", + text="", + font=dict( + size=14, ), + align="center", + showarrow=False + ) + + point_text_r = "Not present" + point_text_c = "Not present" + point_text_diff = "" + try: + point_r = data_r[c][n] + if point_r is not None: + point_text_r = text_r.format( + val_r=point_r, + stdev_r=vals[txt_chains[c]][txt_nodes[n]]["stdev_r"], + nr_r=vals[txt_chains[c]][txt_nodes[n]]["nr_r"]) + except KeyError: + point_r = None + point["text"] = "" if point_r is None else point_r + annotations_r.append(deepcopy(point)) + + try: + point_c = data_c[c][n] + if point_c is not None: + point_text_c = text_c.format( + val_c=point_c, + stdev_c=vals[txt_chains[c]][txt_nodes[n]]["stdev_c"], + nr_c=vals[txt_chains[c]][txt_nodes[n]]["nr_c"]) + except KeyError: + point_c = None + point["text"] = "" if point_c is None else point_c + annotations_c.append(deepcopy(point)) + + try: + point_d = diff[c][n] + if point_d is not None: + point_text_diff = text_diff.format( + title_r=plot["reference"]["name"], + title_c=plot["compare"]["name"], + diff=point_d) + except KeyError: + point_d = None + point["text"] = "" if point_d is None else point_d + annotations_diff.append(deepcopy(point)) + + try: + name = vals[txt_chains[c]][txt_nodes[n]]["name"] + except KeyError: + continue + + hover_line.append(text.format( + name=name, + title_r=plot["reference"]["name"], + text_r=point_text_r, + title_c=plot["compare"]["name"], + text_c=point_text_c, + text_diff=point_text_diff + )) + + hovertext.append(hover_line) + + traces = [ + plgo.Heatmap(x=nodes, + y=chains, + z=data_r, + visible=True, + colorbar=dict( + title=plot.get("z-axis", ""), + titleside="right", + titlefont=dict( + size=16 + ), + tickfont=dict( + size=16, + ), + tickformat=".1f", + yanchor="bottom", + y=-0.02, + len=0.925, + ), + showscale=True, + colorscale=my_green, + reversescale=False, + text=hovertext, + hoverinfo="text"), + plgo.Heatmap(x=nodes, + y=chains, + z=data_c, + visible=False, + colorbar=dict( + title=plot.get("z-axis", ""), + titleside="right", + titlefont=dict( + size=16 + ), + tickfont=dict( + size=16, + ), + tickformat=".1f", + yanchor="bottom", + y=-0.02, + len=0.925, + ), + showscale=True, + colorscale=my_blue, + reversescale=False, + text=hovertext, + hoverinfo="text"), + plgo.Heatmap(x=nodes, + y=chains, + z=diff, + name="Diff", + visible=False, + colorbar=dict( + title="Relative Difference {name_c} vs. {name_r} [%]". + format(name_c=plot["compare"]["name"], + name_r=plot["reference"]["name"]), + titleside="right", + titlefont=dict( + size=16 + ), + tickfont=dict( + size=16, + ), + tickformat=".1f", + yanchor="bottom", + y=-0.02, + len=0.925, + ), + showscale=True, + colorscale=my_grey, + reversescale=False, + text=hovertext, + hoverinfo="text") + ] + + for idx, item in enumerate(txt_nodes): + # X-axis, numbers: + annotations.append(dict( + x=idx+1, + y=0.05, + xref="x", + yref="y", + xanchor="center", + yanchor="top", + text=item, + font=dict( + size=16, + ), + align="center", + showarrow=False + )) + for idx, item in enumerate(txt_chains): + # Y-axis, numbers: + annotations.append(dict( + x=0.35, + y=idx+1, + xref="x", + yref="y", + xanchor="right", + yanchor="middle", + text=item, + font=dict( + size=16, + ), + align="center", + showarrow=False + )) + # X-axis, title: + annotations.append(dict( + x=0.55, + y=-0.15, + xref="paper", + yref="y", + xanchor="center", + yanchor="bottom", + text=plot.get("x-axis", ""), + font=dict( + size=16, + ), + align="center", + showarrow=False + )) + # Y-axis, title: + annotations.append(dict( + x=-0.1, + y=0.5, + xref="x", + yref="paper", + xanchor="center", + yanchor="middle", + text=plot.get("y-axis", ""), + font=dict( + size=16, + ), + align="center", + textangle=270, + showarrow=False + )) + updatemenus = list([ + dict( + active=0, + x=1.0, + y=0.0, + xanchor='right', + yanchor='bottom', + direction='up', + buttons=list([ dict( - args=[{"colorscale": "Greens", "reversescale": True}], - label="Green", - method="update" - ), - dict( - args=[{"colorscale": "RdBu", "reversescale": False}], - label="RedBlue", - method="update" - ), - dict( - args=[{"colorscale": "Picnic", "reversescale": False}], - label="Picnic", - method="update" - ), - dict( - args=[{"colorscale": "Rainbow", "reversescale": False}], - label="Rainbow", - method="update" - ), - dict( - args=[{"colorscale": "Portland", "reversescale": False}], - label="Portland", - method="update" - ), - dict( - args=[{"colorscale": "Jet", "reversescale": False}], - label="Jet", - method="update" - ), - dict( - args=[{"colorscale": "Hot", "reversescale": True}], - label="Hot", - method="update" - ), - dict( - args=[{"colorscale": "Blackbody", "reversescale": True}], - label="Blackbody", - method="update" - ), - dict( - args=[{"colorscale": "Earth", "reversescale": True}], - label="Earth", - method="update" - ), - dict( - args=[{"colorscale": "Electric", "reversescale": True}], - label="Electric", - method="update" + label=plot["reference"]["name"], + method="update", + args=[ + { + "visible": [True, False, False] + }, + { + "colorscale": [my_green, ], + "reversescale": False, + "annotations": annotations + annotations_r, + }, + ] ), dict( - args=[{"colorscale": "Viridis", "reversescale": True}], - label="Viridis", - method="update" + label=plot["compare"]["name"], + method="update", + args=[ + { + "visible": [False, True, False] + }, + { + "colorscale": [my_blue, ], + "reversescale": False, + "annotations": annotations + annotations_c, + }, + ] ), dict( - args=[{"colorscale": "Cividis", "reversescale": True}], - label="Cividis", - method="update" + label="Diff", + method="update", + args=[ + { + "visible": [False, False, True] + }, + { + "colorscale": [my_grey, ], + "reversescale": False, + "annotations": annotations + annotations_diff, + }, + ] ), ]) ) @@ -1373,7 +1783,7 @@ def plot_service_density_heatmap(plot, input_data): logging.error(repr(err)) return - layout["annotations"] = annotations + layout["annotations"] = annotations + annotations_r layout['updatemenus'] = updatemenus try: