Repository: fitbenchmarking/fitbenchmarking

Issue:
Colours in Dash plots in compare table disagree if either plot has already been modified
Once the Dash app is running, if one plays with the Dash plot in either accuracy or runtime table (i.e., removing and adding minimizers), and then switches to the compare table, the colors in two plots (accuracy and runtime) will no longer agree.  Specifically, the minimizers that were previously removed will be shown in different colours in the two plots.


Discussion:
github-actions[bot]: ## Unit & system test results
    4 files  ±0    4 suites  ±0   11m 28s :stopwatch: -36s
  570 tests +1  560 :white_check_mark: +1  10 :zzz: ±0  0 :x: ±0 
1 068 runs  +2  992 :white_check_mark: +2  76 :zzz: ±0  0 :x: ±0 

Results for commit a69392f7. ± Comparison against base commit 05bd1e70.

[test-results]:data:application/gzip;base64,H4sIAHSD/WYC/03Myw6DIBCF4VcxrLtAwRnoyzQUISH10nBZNX33jlbU5f/N5HyYD6NL7N7IW8NSCfmIoUSTwzJTglIEdMrrsUde65GKtSvBhV7hTdSe4k0YSU5wMS5xl1jmtL2D2quOat0d8t9EqHCZ3Pq6aJdpCpmCGdBCdx5djwIkAgKXzgvetuKJaDoO2irXD+z7AzhULmoIAQAA

coveralls: 
[![Coverage Status](https://coveralls.io/builds/70322698/badge)](https://coveralls.io/builds/70322698)

coverage: 91.237% (+0.02%) from 91.222%
when pulling **3fdb284c0a818b37b57b2b6add25d347e36b9feb on 1256-dash_colours**
into **546e9783dafe0ab502cceff43e4464c6ef5de843 on master**.

AndrewLister-STFC: Not sure why this fails but the windows tests on #1271 pass. As far as I can tell, the deps and versions are all the same...
RabiyaF: Rerunning it will hopefully fix it. It happened on my PR as well. But I think it happens very rarely but I don't think is an issue with fitbenchmarking.

Patch:
diff --git a/fitbenchmarking/core/results_output.py b/fitbenchmarking/core/results_output.py
index 73d4b72c..b9d0cd73 100644
--- a/fitbenchmarking/core/results_output.py
+++ b/fitbenchmarking/core/results_output.py
@@ -588,8 +588,12 @@ def check_max_solvers(opts, solvers, max_solvers):
     return opts
 
 
-def display_page(pathname, profile_instances_all_groups,
-                 layout, max_solvers):
+def display_page(
+    pathname: str,
+    profile_instances_all_groups: "dict[str, dict[str, DashPerfProfile]]",
+    layout: "list",
+    max_solvers: int
+):
     """
     Update the layout of the dash app.
 
@@ -621,7 +625,18 @@ def display_page(pathname, profile_instances_all_groups,
     new_layout = layout
 
     try:
+        first_metric = True
+        current_styles = {}
+        avail_styles = []
         for metric in metric_str.split('+'):
+            if first_metric:
+                current_styles = group_profiles[metric].current_styles
+                avail_styles = group_profiles[metric].avail_styles
+                first_metric = False
+            else:
+                group_profiles[metric].current_styles = current_styles
+                group_profiles[metric].avail_styles = avail_styles
+
             new_layout = new_layout + [group_profiles[metric].layout()]
     except KeyError:
         return ("404 Page Error! The path was not recognized. \n"


Test patch:
diff --git a/fitbenchmarking/core/tests/test_results_output.py b/fitbenchmarking/core/tests/test_results_output.py
index e9223b45..3c61e58b 100644
--- a/fitbenchmarking/core/tests/test_results_output.py
+++ b/fitbenchmarking/core/tests/test_results_output.py
@@ -22,11 +22,8 @@ from fitbenchmarking.core.results_output import (_extract_tags,
                                                  create_directories,
                                                  create_plots,
                                                  create_problem_level_index,
-                                                 display_page,
-                                                 preprocess_data,
-                                                 save_results,
-                                                 update_warning)
-
+                                                 display_page, preprocess_data,
+                                                 save_results, update_warning)
 from fitbenchmarking.results_processing.performance_profiler import \
     DashPerfProfile
 from fitbenchmarking.utils.checkpoint import Checkpoint
@@ -675,6 +672,33 @@ class DisplayPageTests(unittest.TestCase):
                         'visual NIST_low_difficulty-Runtime']
         self.assertEqual(output_ids, expected_ids)
 
+    def test_styles_consistent_when_two_plts(self):
+        """
+        Test that the styles of lines on the graphs are consistent when
+        pathname refers to two plots.
+        """
+        pathname = "127.0.0.1:5009/NIST_low_difficulty/pp/acc+runtime"
+        pps = self.profile_instances_all_groups["NIST_low_difficulty"]
+        pp = pps["acc"]
+        pp.current_styles["solver1"] = pp.avail_styles.pop()
+
+        _ = display_page(
+            pathname,
+            self.profile_instances_all_groups,
+            self.layout,
+            self.max_solvers
+        )
+
+        self.assertDictEqual(
+            pps["acc"].current_styles,
+            pps["runtime"].current_styles
+        )
+
+        self.assertListEqual(
+            pps["acc"].avail_styles,
+            pps["runtime"].avail_styles
+        )
+
 
 if __name__ == "__main__":
     unittest.main()