diff --git a/pyproject.toml b/pyproject.toml index 5914c00..c2b224d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -88,7 +88,6 @@ lint.ignore = [ "D101", # Ignore missing docstring in public classes "F401", # FIXME: those are ignored for now, should be fixed eventually - "E501", # Ignore line too long "ERA001", # Found commented-out code "T201", # `print` found" "SIM105", # Use `contextlib.suppress` diff --git a/src/petab_gui/commands.py b/src/petab_gui/commands.py index 9ba472a..6fb97d9 100644 --- a/src/petab_gui/commands.py +++ b/src/petab_gui/commands.py @@ -12,8 +12,8 @@ def _convert_dtype_with_nullable_int(series, dtype): """Convert a series to the specified dtype, handling nullable integers. When converting to integer types and the series contains NaN values, - this function automatically uses pandas nullable integer types (Int64, Int32, etc.) - instead of numpy integer types which don't support NaN. + this function automatically uses pandas nullable integer types (Int64, + Int32, etc.) instead of numpy integer types which don't support NaN. Args: series: The pandas Series to convert diff --git a/src/petab_gui/controllers/file_io_controller.py b/src/petab_gui/controllers/file_io_controller.py index 49032dd..b82fd63 100644 --- a/src/petab_gui/controllers/file_io_controller.py +++ b/src/petab_gui/controllers/file_io_controller.py @@ -1,7 +1,7 @@ """File I/O Controller for PEtab GUI. -This module contains the FileIOController class, which handles all file input/output -operations for PEtab models, including: +This module contains the FileIOController class, which handles all +file input/output operations for PEtab models, including: - Opening and saving PEtab YAML files - Opening and saving COMBINE archives (OMEX) - Opening and saving individual tables @@ -35,7 +35,8 @@ class FileIOController: Attributes ---------- main : MainController - Reference to the main controller for access to models, views, and other controllers. + Reference to the main controller for access to models, views, and + other controllers. model : PEtabModel The PEtab model being managed. view : MainWindow @@ -60,8 +61,9 @@ def __init__(self, main_controller): def save_model(self): """Save the entire PEtab model. - Opens a dialog to select the save format and location, then saves the model - as either a COMBINE archive (OMEX), ZIP file, or folder structure. + Opens a dialog to select the save format and location, then saves + the model as either a COMBINE archive (OMEX), ZIP file, or folder + structure. Returns ------- @@ -129,7 +131,8 @@ def save_single_table(self): Returns ------- bool or None - True if saved successfully, False if cancelled, None if no active table. + True if saved successfully, False if cancelled, None if no + active table. """ active_controller = self.main.active_controller() if not active_controller: @@ -253,8 +256,9 @@ def _open_file(self, actionable, file_path, sep, mode): Parameters ---------- actionable : str - Type of file: "yaml", "omex", "sbml", "measurement", "observable", - "parameter", "condition", "visualization", "simulation", "data_matrix". + Type of file: "yaml", "omex", "sbml", "measurement", + "observable", "parameter", "condition", "visualization", + "simulation", "data_matrix". file_path : str Path to the file. sep : str @@ -412,7 +416,8 @@ def _load_file_list(self, controller, file_list, file_type, yaml_dir): file_mode = "overwrite" if i == 0 else "append" controller.open_table(yaml_dir / file_name, mode=file_mode) self.logger.log_message( - f"Loaded {file_type} file ({i + 1}/{len(file_list)}): {file_name}", + f"Loaded {file_type} file ({i + 1}/{len(file_list)}): " + f"{file_name}", color="blue", ) @@ -478,8 +483,8 @@ def open_yaml_and_load_files(self, yaml_path=None, mode="overwrite"): ) if not all_exist: error_msg = ( - "The following files referenced in the YAML are missing:\n - " - + "\n - ".join(missing_files) + "The following files referenced in the YAML are " + "missing:\n - " + "\n - ".join(missing_files) ) self.logger.log_message(error_msg, color="red") QMessageBox.critical(self.view, "Missing Files", error_msg) @@ -565,7 +570,10 @@ def open_yaml_and_load_files(self, yaml_path=None, mode="overwrite"): self.main.unsaved_changes_change(False) except FileNotFoundError as e: - error_msg = f"File not found: {e.filename if hasattr(e, 'filename') else str(e)}" + error_msg = ( + f"File not found: " + f"{e.filename if hasattr(e, 'filename') else str(e)}" + ) self.logger.log_message(error_msg, color="red") QMessageBox.warning(self.view, "File Not Found", error_msg) except KeyError as e: @@ -659,12 +667,14 @@ def load_example(self, example_name): Parameters ---------- example_name : str - Name of the example subdirectory (e.g., "Boehm", "Simple_Conversion"). + Name of the example subdirectory (e.g., "Boehm", + "Simple_Conversion"). Notes ----- Finds and loads the example dataset from the package directory. - No internet connection required - the example is bundled with the package. + No internet connection required - the example is bundled with the + package. """ try: # Use importlib.resources to access packaged example files @@ -687,7 +697,10 @@ def load_example(self, example_name): with as_file(yaml_file) as yaml_path: if not yaml_path.exists(): - error_msg = f"Example '{example_name}' not found or problem.yaml file is missing." + error_msg = ( + f"Example '{example_name}' not found or " + f"problem.yaml file is missing." + ) self.logger.log_message(error_msg, color="red") QMessageBox.warning( self.view, "Example Invalid", error_msg diff --git a/src/petab_gui/controllers/mother_controller.py b/src/petab_gui/controllers/mother_controller.py index 31a6da9..ce2eb69 100644 --- a/src/petab_gui/controllers/mother_controller.py +++ b/src/petab_gui/controllers/mother_controller.py @@ -728,7 +728,8 @@ def replace(self): self.view.toggle_replace() def _toggle_whats_this_mode(self, on: bool): - """Enable/disable click-to-help mode by installing/removing the global filter. + """ + Enable/disable click-to-help mode. On enter: show a short instruction bubble. """ @@ -754,7 +755,7 @@ def _toggle_whats_this_mode(self, on: bool): self._show_help_welcome() def _show_help_welcome(self): - """Centered welcome with a 'Don't show again' option persisted in QSettings.""" + """Welcome with a 'Don't show again' option persisted in QSettings.""" settings = settings_manager.settings if settings.value("help_mode/welcome_disabled", False, type=bool): return @@ -765,9 +766,12 @@ def _show_help_welcome(self): msg.setText( "Welcome to help mode
" "" ) dont = QCheckBox("Don't show again") @@ -795,7 +799,7 @@ def about(self): ) def _show_next_steps_panel(self): - """Show the next steps panel (ignores 'don't show again' preference).""" + """Show the next steps panel.""" # Sync checkbox state with current settings dont_show = settings_manager.get_value( "next_steps/dont_show_again", False, bool diff --git a/src/petab_gui/controllers/plot_coordinator.py b/src/petab_gui/controllers/plot_coordinator.py index 9bf01d5..073fdbf 100644 --- a/src/petab_gui/controllers/plot_coordinator.py +++ b/src/petab_gui/controllers/plot_coordinator.py @@ -23,7 +23,8 @@ class PlotCoordinator: Attributes ---------- main : MainController - Reference to the main controller for access to models, views, and other controllers. + Reference to the main controller for access to models, views, and + other controllers. model : PEtabModel The PEtab model being visualized. view : MainWindow @@ -188,7 +189,8 @@ def _on_plot_point_clicked(self, x, y, label, data_type): x : float X-coordinate of the clicked point (time). y : float - Y-coordinate of the clicked point (measurement or simulation value). + Y-coordinate of the clicked point (measurement or simulation + value). label : str Label of the clicked point (observable ID). data_type : str @@ -250,7 +252,8 @@ def column_index(name): and self._floats_match(row_y, y) ): # Manually update highlight BEFORE selecting row - # This ensures the circle appears even though we skip the signal handler + # This ensures the circle appears even though we skip + # the signal handler if data_type == "measurement": self.plotter.highlight_from_selection([row]) else: @@ -272,7 +275,8 @@ def column_index(name): # Provide feedback if no match found if not matched: self.logger.log_message( - f"No matching row found for plot point (obs={obs}, x={x:.4g}, y={y:.4g})", + f"No matching row found for plot point " + f"(obs={obs}, x={x:.4g}, y={y:.4g})", color="orange", ) diff --git a/src/petab_gui/controllers/simulation_controller.py b/src/petab_gui/controllers/simulation_controller.py index 24b6652..3ef9a4d 100644 --- a/src/petab_gui/controllers/simulation_controller.py +++ b/src/petab_gui/controllers/simulation_controller.py @@ -22,7 +22,8 @@ class SimulationController: Attributes ---------- main : MainController - Reference to the main controller for access to models, views, and other controllers. + Reference to the main controller for access to models, views, and + other controllers. model : PEtabModel The PEtab model being simulated. logger : LoggerController @@ -80,7 +81,7 @@ def simulate(self): value = sbml_model.get_parameter_value(param_id) nominal_values.append(value) except Exception: - # If parameter not found in SBML, use default value of 1 + # If parameter not found in SBML, use default value nominal_values.append(1.0) # Add nominalValue column to parameter_df @@ -108,7 +109,8 @@ def simulate(self): # report current basico / COPASI version self.logger.log_message( - f"Simulate with basico: {basico.__version__}, COPASI: {basico.COPASI.__version__}", + f"Simulate with basico: {basico.__version__}, " + f"COPASI: {basico.COPASI.__version__}", color="green", ) diff --git a/src/petab_gui/controllers/table_controllers.py b/src/petab_gui/controllers/table_controllers.py index b51dc32..52bf16b 100644 --- a/src/petab_gui/controllers/table_controllers.py +++ b/src/petab_gui/controllers/table_controllers.py @@ -227,8 +227,9 @@ def append_df(self, new_df: pd.DataFrame): self.model.beginResetModel() current_df = self.model.get_df() - # For tables without a named index (measurement, visualization, simulation), - # ignore the index to avoid removing appended data due to index conflicts + # For tables without a named index (measurement, visualization, + # simulation), ignore the index to avoid removing appended data due + # to index conflicts if self.model.table_type in [ "measurement", "visualization", @@ -238,7 +239,8 @@ def append_df(self, new_df: pd.DataFrame): [current_df, new_df], axis=0, ignore_index=True ) else: - # For tables with named indices, concatenate and remove duplicate indices + # For tables with named indices, concatenate and remove + # duplicate indices combined_df = pd.concat([current_df, new_df], axis=0) combined_df = combined_df[ ~combined_df.index.duplicated(keep="first") @@ -784,12 +786,14 @@ def _detect_time_column(self, df) -> str | None: return None def _rank_dose_candidates(self, df: pd.DataFrame) -> list[str]: - """Rank DataFrame columns by likelihood of containing dose/concentration data. + """Rank columns by likelihood of containing dose/concentration data. - This method implements a lightweight scoring system to identify and rank - columns that are most likely to contain dose, concentration, or drug-related - data. The ranking is based on multiple heuristics including column naming - patterns, data types, value ranges, and statistical properties. + This method implements a lightweight scoring system to identify + and rank columns that are most likely to contain dose, + concentration, or drug-related + data. The ranking is based on multiple heuristics including column + naming patterns, data types, value ranges, and statistical + properties. Parameters ---------- @@ -800,29 +804,32 @@ def _rank_dose_candidates(self, df: pd.DataFrame) -> list[str]: Returns ------- list[str] - Column names sorted by descending likelihood of containing dose data. - Columns with higher scores appear first. In case of tied scores, - columns with fewer unique values are ranked higher. + Column names sorted by descending likelihood of containing + dose data. Columns with higher scores appear first. In case of + tied scores, columns with fewer unique values are ranked higher. Notes ----- The scoring algorithm considers the following criteria: - - **Name matching** (+2.0 points): Column names containing keywords like - 'dose', 'conc', 'concentration', 'drug', 'compound', 'stim', 'input', - or patterns like 'u' (case-insensitive). + - **Name matching** (+2.0 points): Column names containing keywords + like 'dose', 'conc', 'concentration', 'drug', 'compound', 'stim', + 'input', or patterns like 'u' (case-insensitive). - - **Numeric data type** (+1.0 points): Columns with integer or float dtype. + - **Numeric data type** (+1.0 points): Columns with integer or float + dtype. - - **Reasonable cardinality** (+0.8 points): Columns with 2-30 unique - non-null values, which is typical for dose series. + - **Reasonable cardinality** (+0.8 points): Columns with 2-30 + unique non-null values, which is typical for dose series. - - **Non-negative values** (+0.3 points): All values are >= 0 when converted - to numeric (dose/concentration values are typically non-negative). + - **Non-negative values** (+0.3 points): All values are >= 0 when + converted to numeric (dose/concentration values are typically + non-negative). - - **Monotonic tendency** (+0.2 points): At least 70% of consecutive numeric - differences are non-decreasing, indicating potential dose escalation - patterns. Requires at least 5 non-null numeric values. + - **Monotonic tendency** (+0.2 points): At least 70% of + consecutive numeric differences are non-decreasing, indicating + potential dose escalation patterns. Requires at least 5 non-null + numeric values. Raises ------ diff --git a/src/petab_gui/controllers/utils.py b/src/petab_gui/controllers/utils.py index 3af5af8..f8ef706 100644 --- a/src/petab_gui/controllers/utils.py +++ b/src/petab_gui/controllers/utils.py @@ -29,9 +29,12 @@ class _WhatsThisClickHelp(QObject): While the action is checked: • Left-click shows a What's This bubble for the target under cursor. - • Clicking the SAME target again closes the bubble (stays in help mode). - • ESC closes the bubble if one is open; if none is open, exits help mode. - • Special cases: QTabBar tabs and QHeaderView sections handled explicitly. + • Clicking the SAME target again closes the bubble (stays in help + mode). + • ESC closes the bubble if one is open; if none is open, exits help + mode. + • Special cases: QTabBar tabs and QHeaderView sections handled + explicitly. """ def __init__(self, action): @@ -81,7 +84,8 @@ def eventFilter(self, _obj, ev): if isinstance(w, QScrollBar): return False - # If click landed outside app widgets (e.g., on the bubble), just close it + # If click landed outside app widgets (e.g., on the bubble), + # just close it if not w: self._has_bubble = False return True diff --git a/src/petab_gui/controllers/validation_controller.py b/src/petab_gui/controllers/validation_controller.py index 550cd13..712d4af 100644 --- a/src/petab_gui/controllers/validation_controller.py +++ b/src/petab_gui/controllers/validation_controller.py @@ -23,7 +23,8 @@ class ValidationController: Attributes ---------- main : MainController - Reference to the main controller for access to models, views, and other controllers. + Reference to the main controller for access to models, views, and + other controllers. model : PEtabModel The PEtab model being validated. logger : LoggerController diff --git a/src/petab_gui/models/tooltips.py b/src/petab_gui/models/tooltips.py index 3cb2ff6..00dac90 100644 --- a/src/petab_gui/models/tooltips.py +++ b/src/petab_gui/models/tooltips.py @@ -24,23 +24,32 @@ def register_tips( "measurement", header={ "observableId": "ID from Observables; the output being measured.", - "preequilibrationConditionId": "Condition for preequilibration; empty = none.", + "preequilibrationConditionId": ( + "Condition for preequilibration; empty = none." + ), "simulationConditionId": "Condition ID used for simulation.", "time": "Time in SBML units; number or 'inf' (steady state).", - "measurement": "Measured value; same units/scale as model output.", - "observableParameters": "Override placeholder params; ';'-separated values/names; empty if none.", - "noiseParameters": "Std dev σ as value or name; NaN if σ is modeled.", + "measurement": ("Measured value; same units/scale as model output."), + "observableParameters": ( + "Override placeholder params; ';'-separated values/names; " + "empty if none." + ), + "noiseParameters": ( + "Std dev σ as value or name; NaN if σ is modeled." + ), "datasetId": "Dataset grouping ID (for plotting).", "replicateId": "Replicate label within datasetId.", }, cell={ "observableId": "Must exist in Observables.", - "preequilibrationConditionId": "Condition ID or empty for no preeq.", + "preequilibrationConditionId": ("Condition ID or empty for no preeq."), "simulationConditionId": "Condition ID from Conditions.", "time": "e.g. 0, 5, 10 or 'inf' for steady state.", "measurement": "Numeric observed value.", - "observableParameters": "Match placeholders; provide n ';'-separated values/names.", - "noiseParameters": "Sigma value or parameter name; NaN if modeled.", + "observableParameters": ( + "Match placeholders; provide n ';'-separated values/names." + ), + "noiseParameters": ("Sigma value or parameter name; NaN if modeled."), "datasetId": "Optional dataset ID to group points.", "replicateId": "Optional replicate tag within dataset.", }, @@ -50,20 +59,47 @@ def register_tips( register_tips( "observable", header={ - "observableId": "Unique ID; letters, digits, underscores; not starting with digit. Referenced in Measurements.", - "observableName": "Optional display name; not used for identification.", - "observableFormula": "Observation function as text formula. May use SBML symbols or parameters from parameter table. Can introduce placeholder parameters observableParameter{n}_{observableId}.", - "observableTransformation": "Transformation applied in objective; one of lin, log, log10. Default: lin.", - "noiseFormula": "Noise model formula or numeric σ. May include noiseParameter{n}_{observableId}. Must be overridden in Measurement table if present.", - "noiseDistribution": "Noise distribution type: normal (σ) or laplace (scale). Default: normal.", + "observableId": ( + "Unique ID; letters, digits, underscores; not starting with " + "digit. Referenced in Measurements." + ), + "observableName": ( + "Optional display name; not used for identification." + ), + "observableFormula": ( + "Observation function as text formula. May use SBML symbols " + "or parameters from parameter table. Can introduce placeholder " + "parameters observableParameter{n}_{observableId}." + ), + "observableTransformation": ( + "Transformation applied in objective; one of lin, log, log10. " + "Default: lin." + ), + "noiseFormula": ( + "Noise model formula or numeric σ. May include " + "noiseParameter{n}_{observableId}. Must be overridden in " + "Measurement table if present." + ), + "noiseDistribution": ( + "Noise distribution type: normal (σ) or laplace (scale). " + "Default: normal." + ), }, cell={ - "observableId": "Identifier; must be valid and unique. Used in Measurement table.", + "observableId": ( + "Identifier; must be valid and unique. Used in Measurement table." + ), "observableName": "Optional label for output/plots.", - "observableFormula": "E.g. a species ID, assignment rule, or formula with parameters.", + "observableFormula": ( + "E.g. a species ID, assignment rule, or formula with parameters." + ), "observableTransformation": "Choose: lin, log, or log10.", - "noiseFormula": "Numeric σ or formula with noiseParameter{n}_{observableId}.", - "noiseDistribution": "normal (σ as std dev) or laplace (σ as scale).", + "noiseFormula": ( + "Numeric σ or formula with noiseParameter{n}_{observableId}." + ), + "noiseDistribution": ( + "normal (σ as std dev) or laplace (σ as scale)." + ), }, ) @@ -71,30 +107,52 @@ def register_tips( register_tips( "parameter", header={ - "parameterId": "Unique ID; must match SBML parameter, condition override, or observable/noise parameter.", - "parameterName": "Optional label for plotting; may differ from SBML name.", + "parameterId": ( + "Unique ID; must match SBML parameter, condition override, " + "or observable/noise parameter." + ), + "parameterName": ( + "Optional label for plotting; may differ from SBML name." + ), "parameterScale": "Scale for estimation: lin, log, or log10.", - "lowerBound": "Lower bound (linear space). Optional if estimate==0.", - "upperBound": "Upper bound (linear space). Optional if estimate==0.", - "nominalValue": "Value if not estimated (estimate==0). Linear space.", + "lowerBound": ("Lower bound (linear space). Optional if estimate==0."), + "upperBound": ("Upper bound (linear space). Optional if estimate==0."), + "nominalValue": ( + "Value if not estimated (estimate==0). Linear space." + ), "estimate": "1 = estimated, 0 = fixed.", - "initializationPriorType": "Prior for sampling initial points. Default: parameterScaleUniform.", - "initializationPriorParameters": "Parameters for initialization prior; ';'-separated; numeric.", - "objectivePriorType": "Prior type used in objective function.", - "objectivePriorParameters": "Parameters for objective prior; ';'-separated; numeric.", + "initializationPriorType": ( + "Prior for sampling initial points. Default: " + "parameterScaleUniform." + ), + "initializationPriorParameters": ( + "Parameters for initialization prior; ';'-separated; numeric." + ), + "objectivePriorType": ("Prior type used in objective function."), + "objectivePriorParameters": ( + "Parameters for objective prior; ';'-separated; numeric." + ), }, cell={ - "parameterId": "Must match SBML/condition/observable/noise parameter ID.", + "parameterId": ( + "Must match SBML/condition/observable/noise parameter ID." + ), "parameterName": "Optional descriptive name.", "parameterScale": "Choose lin, log, or log10.", "lowerBound": "Numeric lower bound (linear space).", "upperBound": "Numeric upper bound (linear space).", "nominalValue": "Numeric value if not estimated.", "estimate": "0 = fixed, 1 = estimated.", - "initializationPriorType": "E.g., uniform, normal, laplace, logNormal, parameterScaleUniform…", - "initializationPriorParameters": "Numeric parameters for init prior; e.g., mean;stddev.", - "objectivePriorType": "Prior type for optimization objective.", - "objectivePriorParameters": "Numeric parameters for objective prior.", + "initializationPriorType": ( + "E.g., uniform, normal, laplace, logNormal, parameterScaleUniform…" + ), + "initializationPriorParameters": ( + "Numeric parameters for init prior; e.g., mean;stddev." + ), + "objectivePriorType": ("Prior type for optimization objective."), + "objectivePriorParameters": ( + "Numeric parameters for objective prior." + ), }, ) @@ -102,16 +160,24 @@ def register_tips( register_tips( "condition", header={ - "conditionId": "Unique ID; letters/digits/underscores; not starting with digit. Referenced by Measurements.", - "conditionName": "Optional human-readable name for reports/plots.", - "*": "User-defined column. Needs to be SBML ID column: parameter, species, or compartment.", + "conditionId": ( + "Unique ID; letters/digits/underscores; not starting with " + "digit. Referenced by Measurements." + ), + "conditionName": ("Optional human-readable name for reports/plots."), + "*": ( + "User-defined column. Needs to be SBML ID column: parameter, " + "species, or compartment." + ), }, cell={ "conditionId": "Enter a valid, unique identifier.", "conditionName": "Optional label.", - "*": "User-defined column. Provide numeric value or SBML/parameter ID. " - "Species IDs = initial amount/concentration (NaN = keep preeq/initial). " - "Compartment IDs = initial size.", + "*": ( + "User-defined column. Provide numeric value or SBML/parameter " + "ID. Species IDs = initial amount/concentration (NaN = keep " + "preeq/initial). Compartment IDs = initial size." + ), }, ) @@ -120,13 +186,22 @@ def register_tips( header={ "plotId": "Plot ID; datasets with same ID share axes.", "plotName": "Optional plot display name.", - "plotTypeSimulation": "LinePlot | BarPlot | ScatterPlot. Default: LinePlot.", - "plotTypeData": "MeanAndSD | MeanAndSEM | replicate | provided. Default: MeanAndSD.", - "datasetId": "Dataset grouping ID from Measurements (optional).", - "xValues": "Independent variable: 'time' (default) or parameter/state ID.", + "plotTypeSimulation": ( + "LinePlot | BarPlot | ScatterPlot. Default: LinePlot." + ), + "plotTypeData": ( + "MeanAndSD | MeanAndSEM | replicate | provided. " + "Default: MeanAndSD." + ), + "datasetId": ("Dataset grouping ID from Measurements (optional)."), + "xValues": ( + "Independent variable: 'time' (default) or parameter/state ID." + ), "xOffset": "Offset added to x values (default 0).", "xLabel": "X-axis label; defaults to xValues.", - "xScale": "lin | log | log10 | order (only with LinePlot). Default: lin.", + "xScale": ( + "lin | log | log10 | order (only with LinePlot). Default: lin." + ), "yValues": "Observable ID to plot on Y.", "yOffset": "Offset added to y values (default 0).", "yLabel": "Y-axis label; defaults to yValues.", @@ -136,8 +211,10 @@ def register_tips( cell={ "plotId": "Required; same ID -> same axes.", "plotName": "Optional human-readable name.", - "plotTypeSimulation": "Choose: LinePlot, BarPlot, or ScatterPlot.", - "plotTypeData": "Choose: MeanAndSD, MeanAndSEM, replicate, or provided.", + "plotTypeSimulation": ("Choose: LinePlot, BarPlot, or ScatterPlot."), + "plotTypeData": ( + "Choose: MeanAndSD, MeanAndSEM, replicate, or provided." + ), "datasetId": "Optional dataset ID to include in this plot.", "xValues": "Use 'time' or a parameter/state ID.", "xOffset": "Numeric x offset (e.g., 0).", @@ -210,8 +287,8 @@ def cell_tip(table: str, column: str) -> str: COND_TABLE_TOOLTIP = ( "Condition table
" "• Define condition IDs and names.
" - "• User-defined SBML ID columns override parameters/species initial " - "states (NaN keeps preeq/initial)." + "• User-defined SBML ID columns override parameters/species " + "initial states (NaN keeps preeq/initial)." ) VIS_TABLE_TOOLTIP = ( @@ -239,14 +316,15 @@ def cell_tip(table: str, column: str) -> str: DATA_TABLES_TAB_TOOLTIP = ( "Data Tables
" - "• Edit PEtab tables: Measurement, Observable, Parameter, Condition," - " Visualization.
" - "• Hover headers for definitions;" - " use toolbar to add/remove rows and import/export." + "• Edit PEtab tables: Measurement, Observable, Parameter, " + "Condition, Visualization.
" + "• Hover headers for definitions; use toolbar to add/remove rows " + "and import/export." ) SBML_MODEL_TAB_TOOLTIP = ( "SBML Model
" "• Edit SBML (XML) and Antimony side-by-side.
" - "• Use Forward Changes buttons to sync; see logger for errors." + "• Use Forward Changes buttons to sync; see logger for " + "errors." ) diff --git a/src/petab_gui/resources/whats_this.py b/src/petab_gui/resources/whats_this.py index 4a5d7ee..7c03f59 100644 --- a/src/petab_gui/resources/whats_this.py +++ b/src/petab_gui/resources/whats_this.py @@ -5,19 +5,25 @@ "data_tables": ( "Data Tables
" "" ), "sbml_model": ( "SBML Model
" "" ), }, @@ -25,7 +31,8 @@ "sbml_editor": ( "SBML editor (XML)
" "