def __init__(self, flex): """Initialize box.""" super().__init__(style=Pack(direction=COLUMN, flex=flex)) self.__title_input = self.__add_column_option("Title:") self.__residuals_title_input = self.__add_column_option( "Residuals title:") self.__xlabel_input = self.__add_column_option("X label:") self.__ylabel_input = self.__add_column_option("Y label:") self.__grid_switch = toga.Switch(label="Grid") self.__legend_switch = toga.Switch(label="Legend") self.add(LineBox(children=[self.__grid_switch, self.__legend_switch])) self.__x_domain_switch = toga.Switch( label="Custom X domain", on_toggle=lambda _: self.x_domain_switch_handler()) self.__x_min_title = toga.Label("X minimum:", style=Pack(visibility=HIDDEN)) self.__x_min_input = toga.TextInput(style=Pack(visibility=HIDDEN)) self.__x_max_title = toga.Label("X maximum:", style=Pack(visibility=HIDDEN)) self.__x_max_input = toga.TextInput(style=Pack(visibility=HIDDEN)) self.add( LineBox(children=[ self.__x_domain_switch, self.__x_min_title, self.__x_min_input, self.__x_max_title, self.__x_max_input, ]))
def __init__(self, flex): """Initialize box.""" super().__init__(style=Pack(direction=COLUMN, flex=flex)) self.fitting_function_box = LineBox() self.fitting_function_box.add(toga.Label(text="Fitting function:")) self.fitting_function_selection = toga.Selection( on_select=self.load_select_fitting_function_name, ) self.fitting_function_box.add(self.fitting_function_selection) self.fitting_function_syntax = toga.TextInput( readonly=True, style=Pack(flex=1, padding_left=BIG_PADDING, padding_right=BIG_PADDING), ) self.fitting_function_box.add(self.fitting_function_syntax) self.load_module_button = toga.Button(label="Load module", on_press=self.load_module) self.fitting_function_box.add(self.load_module_button) self.add(self.fitting_function_box) self.polynomial_degree_title = toga.Label("Degree:") self.polynomial_degree_input = toga.NumberInput( min_value=1, max_value=5, default=1, on_change=lambda widget: self.set_polynomial_degree(), ) self.update_fitting_function_options()
def __init__(self, plot_method, suffix, has_legend=True): """Initialize box.""" super().__init__(style=Pack(direction=COLUMN)) self.__base_name = None self.__ycolumn = None self.__xcolumn = None self.plot_method = plot_method self.suffix = suffix self.__title_input = self.__add_column_option("Title:") self.__x_log_scale = toga.Switch( label="X log scale", style=Pack(padding_left=SMALL_PADDING)) self.__y_log_scale = toga.Switch( label="Y log scale", style=Pack(padding_left=SMALL_PADDING)) self.__xlabel_input = self.__add_column_option("X label:", self.__x_log_scale) self.__ylabel_input = self.__add_column_option("Y label:", self.__y_log_scale) self.__grid_switch = toga.Switch(label="Grid") switches = [self.__grid_switch] self.__has_legend = has_legend if has_legend: self.__legend_switch = toga.Switch(label="Legend") switches.append(self.__legend_switch) self.add(LineBox(children=switches)) self.__x_domain_switch = toga.Switch( label="Custom X domain", on_toggle=lambda _: self.x_domain_switch_handler()) self.__x_min_title = toga.Label("X minimum:", style=Pack(visibility=HIDDEN)) self.__x_min_input = toga.TextInput(style=Pack(visibility=HIDDEN), validators=[Number()]) self.__x_max_title = toga.Label("X maximum:", style=Pack(visibility=HIDDEN)) self.__x_max_input = toga.TextInput(style=Pack(visibility=HIDDEN), validators=[Number()]) self.add( LineBox(children=[ self.__x_domain_switch, self.__x_min_title, self.__x_min_input, self.__x_max_title, self.__x_max_input, ]))
def __add_column_option(self, label): text_input = toga.TextInput(style=Pack(width=LONG_INPUT_WIDTH)) line = LineBox(children=[ toga.Label(text=label, style=Pack(width=LABEL_WIDTH)), text_input, ], ) self.add(line) return text_input
def __init__(self, on_save_output): """Initialize box.""" super().__init__(style=Pack(direction=COLUMN)) self.output_directory_input = toga.TextInput(style=Pack(flex=1)) self.add( LineBox( children=[ toga.Label(text="Output directory:"), self.output_directory_input, toga.Button( label="Choose directory", on_press=self.choose_output_dir, style=Pack(padding_left=SMALL_PADDING), ), toga.Button( label="Save", on_press=on_save_output, style=Pack( padding_left=SMALL_PADDING, padding_right=SMALL_PADDING ), ), ] ) ) self.plot_data_checkbox = toga.Switch(label="Data", is_on=False) self.plot_fitting_checkbox = toga.Switch(label="Fitting", is_on=True) self.plot_residuals_checkbox = toga.Switch(label="Residuals", is_on=True) self.result_text_checkbox = toga.Switch(label="Result text", is_on=True) self.result_json_checkbox = toga.Switch(label="Result json", is_on=False) self.add( LineBox( children=[ self.plot_data_checkbox, self.plot_fitting_checkbox, self.plot_residuals_checkbox, self.result_text_checkbox, self.result_json_checkbox, ] ) )
def __init__(self, flex): """Initialize box.""" super(InputFileBox, self).__init__(style=Pack(direction=COLUMN, flex=flex)) self.__input_file_path = toga.TextInput( readonly=True, style=Pack(flex=1, padding_left=BIG_PADDING, padding_right=BIG_PADDING), ) self.__select_file = toga.Button(label="Choose file", on_press=self.select_file) self.add( LineBox(children=[ toga.Label(text="Input file:"), self.__input_file_path, self.__select_file, ])) self.__select_sheet = toga.Selection(enabled=False, on_select=self.select_sheet) self.add( LineBox(children=[toga.Label(text="Sheet:"), self.__select_sheet]))
def __init__(self, fitting_data: FittingData, app: toga.App): """Initialize window.""" super().__init__(title="Choose Records", size=RECORD_WINDOW_SIZE) main_box = toga.Box(style=Pack(direction=COLUMN)) data_box = toga.Box() self.__checkboxes = [ toga.Switch( label="", is_on=fitting_data.is_selected(i), style=Pack(height=LINE_HEIGHT), ) for i in range(1, fitting_data.length + 1) ] data_box.add( toga.Box( style=Pack( flex=1, direction=COLUMN, padding_left=SMALL_PADDING, padding_right=SMALL_PADDING, ), children=[ toga.Label(text="Chosen", style=Pack(height=LINE_HEIGHT)) ] + self.__checkboxes, # noqa: W503 )) for header, column in fitting_data.data.items(): data_box.add( toga.Box( style=Pack( flex=1, direction=COLUMN, padding_left=SMALL_PADDING, padding_right=SMALL_PADDING, ), children=[ toga.Label(text=header, style=Pack(height=LINE_HEIGHT)) ] + [ # noqa: W503 toga.Label(text=element, style=Pack(height=LINE_HEIGHT)) for element in column ], )) main_box.add(data_box) main_box.add( LineBox(children=[ toga.Button(label="Save", on_press=self.save_action(fitting_data)) ], )) scroller = toga.ScrollContainer(content=main_box) self.content = scroller self.app = app
def __init__(self, flex): """Initialize box.""" super(PlotConfigurationBox, self).__init__(style=Pack(direction=COLUMN, flex=flex)) self.__title_input = self.__add_column_option("Title:") self.__residuals_title_input = self.__add_column_option( "Residuals title:") self.__xlabel_input = self.__add_column_option("X label:") self.__ylabel_input = self.__add_column_option("Y label:") self.__grid_switch = toga.Switch( label="Grid", on_toggle=lambda _: self.reset_plot_configuration(), ) self.add(LineBox(children=[self.__grid_switch]))
def __add_column_option(self, label, on_select): selection = toga.Selection( enabled=self.selection_enabled, on_select=on_select, style=Pack(alignment=LEFT, width=SELECTION_WIDTH), ) line = LineBox( alignment=LEFT, children=[ toga.Label(text=label, style=Pack(width=LABEL_WIDTH)), selection, ], ) self.add(line) return selection
class FittingFunctionBox(toga.Box): # pylint: disable=too-many-instance-attributes """Visual box instance for choosing a fitting function.""" fitting_function_box: LineBox fitting_function_selection: toga.Selection fitting_function_syntax: toga.TextInput polynomial_degree_title: toga.Label polynomial_degree_input: toga.NumberInput load_module_button: toga.Button __fitting_function: Optional[FittingFunction] = None __on_fitting_function_load: Optional[Callable[[FittingFunction], None]] = None __polynomial_is_set: bool = False def __init__(self, flex): """Initialize box.""" super().__init__(style=Pack(direction=COLUMN, flex=flex)) self.fitting_function_box = LineBox() self.fitting_function_box.add(toga.Label(text="Fitting function:")) self.fitting_function_selection = toga.Selection( on_select=self.load_select_fitting_function_name, ) self.fitting_function_box.add(self.fitting_function_selection) self.fitting_function_syntax = toga.TextInput( readonly=True, style=Pack(flex=1, padding_left=BIG_PADDING, padding_right=BIG_PADDING), ) self.fitting_function_box.add(self.fitting_function_syntax) self.load_module_button = toga.Button(label="Load module", on_press=self.load_module) self.fitting_function_box.add(self.load_module_button) self.add(self.fitting_function_box) self.polynomial_degree_title = toga.Label("Degree:") self.polynomial_degree_input = toga.NumberInput( min_value=1, max_value=5, default=1, on_change=lambda widget: self.set_polynomial_degree(), ) self.update_fitting_function_options() @property def fitting_function(self): """Getter of the fitting function.""" return self.__fitting_function @fitting_function.setter def fitting_function(self, fitting_function): """ Setter of the fitting function. After setting the fit function, run handlers in order to notify other components of the change. """ self.__fitting_function = fitting_function if self.on_fitting_function_load is not None: self.on_fitting_function_load(self.fitting_function) @property def fitting_function_state(self): """Set fit function state.""" return self.fitting_function_selection.value @property def on_fitting_function_load(self): """on_fitting_function_load getter.""" return self.__on_fitting_function_load @on_fitting_function_load.setter def on_fitting_function_load(self, on_fitting_function_load): """on_fitting_function_load setter.""" self.__on_fitting_function_load = on_fitting_function_load def update_fitting_function_options(self): """Update the fitting functions options.""" self.fitting_function_selection.items = [NO_VALUE, POLYNOMIAL] + list( FittingFunctionsRegistry.names()) def load_select_fitting_function_name(self, widget): # pylint: disable=unused-argument """Load the selection fitting function from the FittingFunctionRegistry.""" if self.fitting_function_state == POLYNOMIAL and not self.__polynomial_is_set: self.fitting_function_box.insert(2, self.polynomial_degree_title) self.fitting_function_box.insert(3, self.polynomial_degree_input) self.set_polynomial_degree() self.__polynomial_is_set = True return if self.fitting_function_state != POLYNOMIAL and self.__polynomial_is_set: self.fitting_function_box.remove(self.polynomial_degree_title) self.fitting_function_box.remove(self.polynomial_degree_input) self.__polynomial_is_set = False if self.fitting_function_state == NO_VALUE: self.fitting_function = None self.fitting_function_syntax.value = "" return self.fitting_function = FittingFunctionsRegistry.load( self.fitting_function_state) self.fitting_function_syntax.value = self.fitting_function.syntax def load_module(self, widget): # pylint: disable=unused-argument """ Open a file dialog in order to load user module. This is done in order to add costume fitting functions. """ try: file_path = self.window.open_file_dialog( title="Choose module file", multiselect=False) except ValueError: return spec = importlib.util.spec_from_file_location("eddington.dummy", file_path) dummy_module = importlib.util.module_from_spec(spec) spec.loader.exec_module(dummy_module) self.update_fitting_function_options() def set_polynomial_degree(self): """Set fitting function to be polynomial based on given degree.""" degree = int(self.polynomial_degree_input.value) self.fitting_function = polynomial(degree) if degree == 1: self.fitting_function_syntax.value = "a[0] + a[1] * x" else: self.fitting_function_syntax.value = "a[0] + a[1] * x + " + " + ".join( [f"a[{i}] * x ^ {i}" for i in range(2, degree + 1)])
def __init__(self, fitting_data: FittingData, font_size: FontSize, app: toga.App): """Initialize window.""" super().__init__(title="Choose Records", size=RECORD_WINDOW_SIZE) self.__fitting_data = fitting_data main_box = toga.Box(style=Pack(direction=COLUMN)) data_box = toga.Box() statistics_box = toga.Box() font_size_value = FontSize.get_font_size(font_size) self.__update_on_check = True self.__statistics_labels = { (column, parameter): toga.Label( text=to_relevant_precision_string( getattr(fitting_data.statistics(column), parameter, 0)), style=Pack(height=LINE_HEIGHT, width=COLUMN_WIDTH, font_size=font_size_value), ) for column, parameter in itertools.product( fitting_data.all_columns, Statistics.parameters()) } self.__checkboxes = [ toga.Switch( label="", is_on=fitting_data.is_selected(i), on_toggle=self.select_records, style=Pack(height=LINE_HEIGHT, width=COLUMN_WIDTH, font_size=font_size_value), ) for i in range(1, fitting_data.length + 1) ] self.__all_checkbox = toga.Switch( label="", is_on=self.are_all_selected(), on_toggle=self.select_all, style=Pack(height=TITLES_LINE_HEIGHT, font_size=font_size_value), ) self.__selected_records_label = toga.Label( text="", style=Pack(font_size=font_size_value, width=COLUMN_WIDTH, height=TITLES_LINE_HEIGHT), ) data_box.add( toga.Box( style=Pack( flex=1, direction=COLUMN, padding_left=SMALL_PADDING, padding_right=SMALL_PADDING, ), children=[ toga.Box( style=Pack( height=TITLES_LINE_HEIGHT, font_size=font_size_value, ), children=[ self.__all_checkbox, self.__selected_records_label ], ), *self.__checkboxes, ], )) for header, column in fitting_data.data.items(): data_box.add( toga.Box( style=Pack( flex=1, direction=COLUMN, padding_left=SMALL_PADDING, padding_right=SMALL_PADDING, ), children=[ toga.Label( text=header, style=Pack( height=TITLES_LINE_HEIGHT, width=COLUMN_WIDTH, font_size=font_size_value, font_weight=BOLD, ), ), *[ toga.Label( text=to_relevant_precision_string(element), style=Pack( height=LINE_HEIGHT, width=COLUMN_WIDTH, font_size=font_size_value, ), ) for element in column ], ], )) main_box.add(data_box) main_box.add(toga.Divider()) statistics_box.add( toga.Box( style=Pack( flex=1, direction=COLUMN, padding_left=SMALL_PADDING, padding_right=SMALL_PADDING, ), children=[ toga.Label( text=parameter.replace("_", " ").title(), style=Pack( height=LINE_HEIGHT, width=COLUMN_WIDTH, font_size=font_size_value, font_weight=BOLD, ), ) for parameter in Statistics.parameters() ], )) for header, column in fitting_data.data.items(): statistics_box.add( toga.Box( style=Pack( flex=1, direction=COLUMN, padding_left=SMALL_PADDING, padding_right=SMALL_PADDING, ), children=[ self.__statistics_labels[(header, parameter)] for parameter in Statistics.parameters() ], )) main_box.add(statistics_box) main_box.add( LineBox(children=[ toga.Button(label="Close", on_press=lambda _: self.close()) ], )) scroller = toga.ScrollContainer(content=main_box) self.content = scroller self.app = app self.update()
def __init__(self, flex): """Initialize box.""" super(FittingFunctionBox, self).__init__( style=Pack(direction=COLUMN, flex=flex) ) fit_function_box = LineBox() fit_function_box.add(toga.Label(text="Fitting function:")) self.fitting_function_selection = toga.Selection( on_select=self.load_select_fit_function_name, ) fit_function_box.add(self.fitting_function_selection) self.fitting_function_syntax = toga.TextInput( readonly=True, style=Pack(flex=1, padding_left=BIG_PADDING, padding_right=BIG_PADDING), ) fit_function_box.add(self.fitting_function_syntax) self.load_module_button = toga.Button( label="Load module", on_press=self.load_module ) fit_function_box.add(self.load_module_button) self.add(fit_function_box) self.parameters_box = LineBox() self.parameters_box.add(toga.Label("Parameters:")) self.parameter_inputs = toga.TextInput( readonly=True, style=Pack(width=PARAMETER_WIDTH), on_change=lambda widget: self.reset_fit_function(), ) self.parameters_box.add(self.parameter_inputs) self.add(self.parameters_box) self.update_fitting_function_options()
class FittingFunctionBox(toga.Box): """Visual box instance for choosing a fitting function.""" fitting_function_selection: toga.Selection fitting_function_syntax: toga.TextInput parameters_box: LineBox parameter_inputs: toga.TextInput load_module_button: toga.Button __fit_function: FitFunction = None __handlers: List[Callable] = [] def __init__(self, flex): """Initialize box.""" super(FittingFunctionBox, self).__init__( style=Pack(direction=COLUMN, flex=flex) ) fit_function_box = LineBox() fit_function_box.add(toga.Label(text="Fitting function:")) self.fitting_function_selection = toga.Selection( on_select=self.load_select_fit_function_name, ) fit_function_box.add(self.fitting_function_selection) self.fitting_function_syntax = toga.TextInput( readonly=True, style=Pack(flex=1, padding_left=BIG_PADDING, padding_right=BIG_PADDING), ) fit_function_box.add(self.fitting_function_syntax) self.load_module_button = toga.Button( label="Load module", on_press=self.load_module ) fit_function_box.add(self.load_module_button) self.add(fit_function_box) self.parameters_box = LineBox() self.parameters_box.add(toga.Label("Parameters:")) self.parameter_inputs = toga.TextInput( readonly=True, style=Pack(width=PARAMETER_WIDTH), on_change=lambda widget: self.reset_fit_function(), ) self.parameters_box.add(self.parameter_inputs) self.add(self.parameters_box) self.update_fitting_function_options() def add_handler(self, handler): """ Add handler to run whenever the fitting function is updated. :param handler: Callable """ self.__handlers.append(handler) def update_fitting_function_options(self): """Update the fitting functions options.""" self.fitting_function_selection.items = [NO_VALUE] + list( FitFunctionsRegistry.names() ) def load_select_fit_function_name(self, widget): # pylint: disable=unused-argument """Load the selection fitting function from the FitFunctionRegistry.""" if self.fit_function_state == NO_VALUE: self.reset_fit_function() return self.fit_function = FitFunctionsRegistry.load(self.fit_function_state) self.fitting_function_syntax.value = self.fit_function.syntax def load_module(self, widget): # pylint: disable=unused-argument """ Open a file dialog in order to load user module. This is done in order to add costume fitting functions. """ try: file_path = self.window.open_file_dialog( title="Choose module file", multiselect=False ) except ValueError: return spec = importlib.util.spec_from_file_location("eddington.dummy", file_path) dummy_module = importlib.util.module_from_spec(spec) spec.loader.exec_module(dummy_module) self.update_fitting_function_options() def reset_fit_function(self): """Set fit function to be None.""" self.fit_function = None @property def fit_function(self): """Getter of the fitting function.""" return self.__fit_function @fit_function.setter def fit_function(self, fit_function): """ Setter of the fitting function. After setting the fit function, run handlers in order to notify other components of the change. """ self.__fit_function = fit_function for handler in self.__handlers: handler(self.fit_function) @property def fit_function_state(self): """Set fit function state.""" return self.fitting_function_selection.value
def startup(self): """ Construct and show the Toga application. Usually, you would add your application to a main content box. We then create a main window (with a name matching the app), and show the main window. """ main_box = toga.Box(style=Pack(direction=COLUMN)) main_box.add(HeaderBox()) self.input_file_box = InputFileBox(flex=1) self.input_file_box.add_handler(self.reset_fit_data) main_box.add(self.input_file_box) self.fitting_function_box = FittingFunctionBox(flex=1) self.fitting_function_box.add_handler( lambda fit_func: self.reset_fit_result()) main_box.add(self.fitting_function_box) self.initial_guess_box = InitialGuessBox() self.initial_guess_box.add_handler(lambda a0: self.reset_fit_result()) self.fitting_function_box.add_handler(self.set_parameters_number) main_box.add(self.initial_guess_box) self.data_columns_box = DataColumnsBox(flex=5) self.data_columns_box.add_handler( lambda fit_data: self.reset_fit_result()) self.input_file_box.on_csv_read = self.data_columns_box.read_csv self.input_file_box.on_excel_read = self.data_columns_box.read_excel self.plot_configuration_box = PlotConfigurationBox(flex=5) self.fitting_function_box.add_handler( self.plot_configuration_box.on_fit_function_load) self.data_columns_box.add_handler( self.plot_configuration_box.on_fit_data_load) main_box.add( toga.Box( style=Pack(direction=ROW, padding_top=BIG_PADDING, flex=1), children=[ self.data_columns_box, toga.Box(style=Pack(flex=2)), self.plot_configuration_box, ], )) main_box.add( LineBox(children=[ toga.Button(label="Choose Records", on_press=self.choose_records) ])) main_box.add(toga.Box(style=Pack(flex=1))) main_box.add( LineBox(children=[ toga.Button(label="Fit", on_press=self.fit, style=Pack(flex=1)) ], )) main_box.add( LineBox(children=[ toga.Button(label="Plot data", on_press=self.plot_data, style=Pack(flex=1)), toga.Button( label="Plot Initial Guess", on_press=self.plot_initial_guess, style=Pack(flex=1), ), ])) main_box.add( LineBox(children=[ toga.Button(label="Plot Fitting", on_press=self.plot, style=Pack(flex=1)), toga.Button(label="Residuals", on_press=self.residuals, style=Pack(flex=1)), ], )) self.output_directory_input = toga.TextInput(style=Pack(flex=1)) main_box.add( LineBox( padding_bottom=MAIN_BOTTOM_PADDING, children=[ toga.Label(text="Output directory:"), self.output_directory_input, toga.Button( label="Choose directory", on_press=self.choose_output_dir, style=Pack(padding_left=SMALL_PADDING), ), toga.Button( label="Save", on_press=self.save_to_output_dir, style=Pack(padding_left=SMALL_PADDING, padding_right=SMALL_PADDING), ), ], )) self.main_window = toga.MainWindow(title=self.formal_name, size=WINDOW_SIZE) self.main_window.content = main_box self.main_window.show()
def startup(self): """ Construct and show the Toga application. Usually, you would add your application to a main content box. We then create a main window (with a name matching the app), and show the main window. """ main_box = toga.Box(style=Pack(direction=COLUMN)) main_box.add(HeaderBox()) self.input_file_box = InputFileBox( on_choose_record=self.choose_records) self.input_file_box.on_input_file_change = self.reset_fitting_data self.input_file_box.on_csv_read = self.read_csv self.input_file_box.on_excel_read = self.read_excel self.input_file_box.on_select_excel_file = self.select_default_sheet main_box.add(self.input_file_box) self.fitting_function_box = FittingFunctionBox(flex=1) self.fitting_function_box.on_fitting_function_load = ( self.on_fitting_function_load) main_box.add(self.fitting_function_box) self.initial_guess_box = InitialGuessBox( on_initial_guess_change=self.reset_fitting_result) main_box.add(self.initial_guess_box) self.data_columns_box = DataColumnsBox(flex=5) self.data_columns_box.on_columns_change = self.on_data_columns_change self.plot_configuration_box = PlotConfigurationBox(flex=5) main_box.add( toga.Box( style=Pack(direction=ROW, padding_top=BIG_PADDING, flex=1), children=[ self.data_columns_box, toga.Box(style=Pack(flex=2)), self.plot_configuration_box, ], )) main_box.add( LineBox(children=[ toga.Button(label="Fit", on_press=self.fit, style=Pack(flex=1)) ], )) main_box.add( LineBox(children=[ toga.Button(label="Plot data", on_press=self.plot_data, style=Pack(flex=1)), toga.Button( label="Plot Initial Guess", on_press=self.plot_initial_guess, style=Pack(flex=1), ), ])) main_box.add( LineBox(children=[ toga.Button(label="Plot Fitting", on_press=self.plot, style=Pack(flex=1)), toga.Button(label="Residuals", on_press=self.residuals, style=Pack(flex=1)), ], )) self.output_box = OutputBox(on_save_output=self.on_save_output) main_box.add(self.output_box) main_box.add(FooterBox()) self.main_window = toga.MainWindow(title=self.formal_name, size=WINDOW_SIZE) self.main_window.content = main_box self.main_window.show() self.commands.add( # File group toga.Command( self.input_file_box.select_file, label="Upload data file", shortcut=toga.Key.MOD_1 + "f", group=toga.Group.FILE, order=1, ), toga.Command( self.fitting_function_box.load_module, label="Load module", shortcut=toga.Key.MOD_1 + "m", group=toga.Group.FILE, order=2, ), toga.Command( self.choose_records, label="Choose records", shortcut=toga.Key.MOD_1 + "c", group=toga.Group.FILE, order=3, ), toga.Command( self.output_box.choose_output_dir, label="Choose output directory", shortcut=toga.Key.MOD_1 + "o", group=toga.Group.FILE, order=4, ), toga.Command( self.on_save_output, label="Save plots and results", shortcut=toga.Key.MOD_1 + "s", group=toga.Group.FILE, order=5, ), # Plot group # Section 1 toga.Command( self.plot_configuration_box.toggle_grid_switch, label="Add/remove grid lines", shortcut=toga.Key.MOD_1 + "g", group=PLOT_GROUP, section=1, order=1, ), toga.Command( self.plot_configuration_box.toggle_legend_switch, label="Add/remove legend", shortcut=toga.Key.MOD_1 + "l", group=PLOT_GROUP, section=1, order=2, ), # Section 2 toga.Command( self.fit, label="Fit result", shortcut=toga.Key.MOD_1 + "e", group=PLOT_GROUP, section=2, order=1, ), toga.Command( self.plot_data, label="Plot data points", shortcut=toga.Key.MOD_1 + "d", section=2, group=PLOT_GROUP, order=2, ), toga.Command( self.plot_initial_guess, label="Plot initial guess fitting", shortcut=toga.Key.MOD_1 + "i", section=2, group=PLOT_GROUP, order=3, ), toga.Command( self.plot, label="Plot fitting", shortcut=toga.Key.MOD_1 + "p", section=2, group=PLOT_GROUP, order=4, ), toga.Command( self.residuals, label="Plot residuals", shortcut=toga.Key.MOD_1 + "r", section=2, group=PLOT_GROUP, order=5, ), )