From 54d4a2b66bd536828b257b29a29bc794b5f1d243 Mon Sep 17 00:00:00 2001 From: Aleksandra Date: Wed, 8 Apr 2020 12:13:48 +0200 Subject: [PATCH] OWLinePlot: data info displayed in the status bar --- Orange/widgets/visualize/owlineplot.py | 30 +++++++++-- .../visualize/tests/test_owlineplot.py | 54 +++++++++++++++++-- 2 files changed, 76 insertions(+), 8 deletions(-) diff --git a/Orange/widgets/visualize/owlineplot.py b/Orange/widgets/visualize/owlineplot.py index 7686bfe688b..5808082ccca 100644 --- a/Orange/widgets/visualize/owlineplot.py +++ b/Orange/widgets/visualize/owlineplot.py @@ -25,6 +25,8 @@ from Orange.widgets.utils.plot import OWPlotGUI, SELECT, PANNING, ZOOMING from Orange.widgets.utils.sql import check_sql_input from Orange.widgets.utils.widgetpreview import WidgetPreview +from Orange.widgets.utils.state_summary import format_summary_details, \ + format_multiple_summaries from Orange.widgets.visualize.owdistributions import LegendItem from Orange.widgets.widget import OWWidget, Input, Output, Msg @@ -475,8 +477,6 @@ def _add_graph(self): box.layout().addWidget(self.graph) def _add_controls(self): - infobox = gui.widgetBox(self.controlArea, "Info") - self.infoLabel = gui.widgetLabel(infobox, "No data on input.") displaybox = gui.widgetBox(self.controlArea, "Display") gui.checkBox(displaybox, self, "show_profiles", "Lines", callback=self.__show_profiles_changed, @@ -505,6 +505,9 @@ def _add_controls(self): gui.rubber(self.controlArea) gui.auto_send(self.controlArea, self, "auto_commit") + self.info.set_input_summary(self.info.NoInput) + self.info.set_output_summary(self.info.NoOutput) + def __show_profiles_changed(self): self.check_display_options() self._update_visibility("profiles") @@ -555,8 +558,6 @@ def error(err): self.clear_messages() if self.data is not None: - self.infoLabel.setText("%i instances on input\n%i features" % ( - len(self.data), len(self.data.domain.attributes))) self.graph_variables = [var for var in self.data.domain.attributes if var.is_continuous] self.valid_data = ~countnans(self.data.X, axis=1).astype(bool) @@ -587,11 +588,27 @@ def set_subset_data(self, subset): def handleNewSignals(self): self.set_subset_ids() + self._set_input_summary() if self.data is not None: self._update_profiles_color() self._update_sel_profiles_color() self._update_sub_profiles() + def _set_input_summary(self): + n_data = len(self.data) if self.data else 0 + n_subset = len(self.subset_data) if self.subset_data else 0 + + summary, details, kwargs = self.info.NoInput, "", {} + if self.data or self.subset_data: + summary = f"{self.info.format_number(n_data)}, " \ + f"{self.info.format_number(n_subset)}" + kwargs = {"format": Qt.RichText} + details = format_multiple_summaries([ + ("Data", self.data), + ("Data subset", self.subset_data) + ]) + self.info.set_input_summary(summary, details, **kwargs) + def set_subset_ids(self): sub_ids = {e.id for e in self.subset_data} \ if self.subset_data is not None else {} @@ -733,6 +750,10 @@ def commit(self): selected = self.data[self.selection] \ if self.data is not None and bool(self.selection) else None annotated = create_annotated_table(self.data, self.selection) + + summary = len(selected) if selected else self.info.NoOutput + details = format_summary_details(selected) if selected else "" + self.info.set_output_summary(summary, details) self.Outputs.selected_data.send(selected) self.Outputs.annotated_data.send(annotated) @@ -754,7 +775,6 @@ def clear(self): self.__groups = [] self.graph_variables = [] self.graph.reset() - self.infoLabel.setText("No data on input.") self.group_vars.set_domain(None) self.group_view.setEnabled(False) diff --git a/Orange/widgets/visualize/tests/test_owlineplot.py b/Orange/widgets/visualize/tests/test_owlineplot.py index 155aec92c38..0ffe12fe013 100644 --- a/Orange/widgets/visualize/tests/test_owlineplot.py +++ b/Orange/widgets/visualize/tests/test_owlineplot.py @@ -19,6 +19,8 @@ from Orange.widgets.visualize.owlineplot import ( OWLinePlot, ccw, intersects, line_intersects_profiles ) +from Orange.widgets.utils.state_summary import format_summary_details, \ + format_multiple_summaries class TestOWLinePLot(WidgetTest, WidgetOutputsTestMixin): @@ -42,13 +44,13 @@ def _select_data(self): return self.widget.selection def test_input_data(self): - no_data_info = "No data on input." - self.assertEqual(self.widget.infoLabel.text(), no_data_info) + no_data = "No data on input" + self.assertEqual(self.widget.info._StateInfo__input_summary.details, no_data) self.send_signal(self.widget.Inputs.data, self.data) self.assertEqual(self.widget.group_view.model().rowCount(), 2) self.send_signal(self.widget.Inputs.data, None) self.assertEqual(self.widget.group_view.model().rowCount(), 1) - self.assertEqual(self.widget.infoLabel.text(), no_data_info) + self.assertEqual(self.widget.info._StateInfo__input_summary.details, no_data) def test_input_continuous_class(self): self.send_signal(self.widget.Inputs.data, self.housing) @@ -279,6 +281,52 @@ def test_unconditional_commit_on_new_signal(self): self.send_signal(self.widget.Inputs.data, self.titanic) commit.assert_called() + def test_summary(self): + """Check if status bar is updated when data is received""" + info = self.widget.info + data, subset = self.housing[:100], self.housing[::10] + no_input, no_output = "No data on input", "No data on output" + + self.send_signal(self.widget.Inputs.data, data) + data_list = [("Data", data), ("Data subset", None)] + summary, details = f"{len(data)}, 0", format_multiple_summaries(data_list) + self.assertEqual(info._StateInfo__input_summary.brief, summary) + self.assertEqual(info._StateInfo__input_summary.details, details) + self.assertEqual(info._StateInfo__output_summary.brief, "") + self.assertEqual(info._StateInfo__output_summary.details, no_output) + + sel_indices = list(range(5)) + self.widget.selection_changed(sel_indices) + output = self.get_output(self.widget.Outputs.selected_data) + summary, details = f"{len(output)}", format_summary_details(output) + self.assertEqual(info._StateInfo__output_summary.brief, summary) + self.assertEqual(info._StateInfo__output_summary.details, details) + + self.send_signal(self.widget.Inputs.data_subset, subset) + data_list = [("Data", data), ("Data subset", subset)] + summary = f"{len(data)}, {len(subset)}" + details = format_multiple_summaries(data_list) + self.assertEqual(info._StateInfo__input_summary.brief, summary) + self.assertEqual(info._StateInfo__input_summary.details, details) + output = self.get_output(self.widget.Outputs.selected_data) + summary, details = f"{len(output)}", format_summary_details(output) + self.assertEqual(info._StateInfo__output_summary.brief, summary) + self.assertEqual(info._StateInfo__output_summary.details, details) + + self.send_signal(self.widget.Inputs.data, None) + data_list = [("Data", None), ("Data subset", subset)] + summary, details = f"0, {len(subset)}", format_multiple_summaries(data_list) + self.assertEqual(info._StateInfo__input_summary.brief, summary) + self.assertEqual(info._StateInfo__input_summary.details, details) + self.assertEqual(info._StateInfo__output_summary.brief, "") + self.assertEqual(info._StateInfo__output_summary.details, no_output) + + self.send_signal(self.widget.Inputs.data_subset, None) + self.assertEqual(info._StateInfo__input_summary.brief, "") + self.assertEqual(info._StateInfo__input_summary.details, no_input) + self.assertEqual(info._StateInfo__output_summary.brief, "") + self.assertEqual(info._StateInfo__output_summary.details, no_output) + class TestSegmentsIntersection(unittest.TestCase): def test_ccw(self):