diff --git a/MANIFEST.in b/MANIFEST.in index b11c0b3..a57f0d4 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,5 +1,7 @@ -include example/*.csv -include example/*.tsv -include example/*.xml +include example/*/*.csv +include example/*/*.tsv +include example/*/*.xml +include example/*/*.yaml +include example/*/*.yml exclude .git_archival.txt exclude .gitattributes diff --git a/example/data_matrix.csv b/example/data_matrix.csv deleted file mode 100644 index 02a40d6..0000000 --- a/example/data_matrix.csv +++ /dev/null @@ -1,4 +0,0 @@ -Time,obsA,obsB,obsC -3, 1, 2, 3 -5, 4, 5, 6 -7, 7, 8, 9 diff --git a/example/simple_conversion_measurements.tsv b/example/simple_conversion_measurements.tsv new file mode 100644 index 0000000..308bfc5 --- /dev/null +++ b/example/simple_conversion_measurements.tsv @@ -0,0 +1,11 @@ +time obs_A obs_B +0 10.1 0.1 +2 8.0 2.1 +4 6.8 3.4 +6 5.6 4.6 +8 4.4 5.4 +10 3.8 6.4 +12 3.1 7.2 +15 2.3 7.9 +18 1.6 8.2 +20 1.3 8.5 diff --git a/pyproject.toml b/pyproject.toml index d7691b7..cf3f2a4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -56,6 +56,7 @@ include-package-data = true [tool.setuptools.package-data] "petab_gui.assets" = ["PEtab.png"] +"petab_gui.example" = ["*/*.yaml", "*/*.yml", "*/*.tsv", "*/*.csv", "*/*.xml", "*/*.sbml"] [tool.setuptools_scm] diff --git a/src/petab_gui/controllers/mother_controller.py b/src/petab_gui/controllers/mother_controller.py index fc2ea85..cbee89e 100644 --- a/src/petab_gui/controllers/mother_controller.py +++ b/src/petab_gui/controllers/mother_controller.py @@ -308,6 +308,23 @@ def setup_actions(self): actions["add"].triggered.connect( partial(self.open_file, mode="append") ) + # Load Examples + actions["load_example_boehm"] = QAction( + qta.icon("mdi6.book-open-page-variant"), + "Load Example: Boehm", + self.view, + ) + actions["load_example_boehm"].triggered.connect( + partial(self.load_example, "Boehm") + ) + actions["load_example_simple"] = QAction( + qta.icon("mdi6.book-open-page-variant"), + "Load Example: Simple Conversion", + self.view, + ) + actions["load_example_simple"].triggered.connect( + partial(self.load_example, "Simple_Conversion") + ) # Save actions["save"] = QAction( qta.icon("mdi6.content-save-all"), "&Save As...", self.view @@ -1072,6 +1089,64 @@ def new_file(self): self.view.plot_dock.plot_it() self.unsaved_changes_change(False) + def load_example(self, example_name): + """Load an internal example PEtab problem. + + Parameters + ---------- + example_name : str + Name of the example subdirectory (e.g., "Boehm", "Simple_Conversion"). + + Finds and loads the example dataset from the package directory. + No internet connection required - the example is bundled with the package. + """ + try: + # Use importlib.resources to access packaged example files + from importlib.resources import as_file, files + + example_files = files("petab_gui.example") + + # Check if the example package exists + if not example_files.is_dir(): + error_msg = ( + "Could not find the example dataset. " + "The example folder may not be properly installed." + ) + self.logger.log_message(error_msg, color="red") + QMessageBox.warning(self.view, "Example Not Found", error_msg) + return + + # Get the problem.yaml file path for the specified example + yaml_file = example_files.joinpath(example_name, "problem.yaml") + + 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." + self.logger.log_message(error_msg, color="red") + QMessageBox.warning( + self.view, "Example Invalid", error_msg + ) + return + + # Load the example + self.logger.log_message( + f"Loading '{example_name}' example dataset...", + color="blue", + ) + self.open_yaml_and_load_files(str(yaml_path)) + + except ModuleNotFoundError as e: + error_msg = ( + "Example dataset not found. It may not be installed properly. " + f"Error: {str(e)}" + ) + self.logger.log_message(error_msg, color="red") + QMessageBox.warning(self.view, "Example Not Found", error_msg) + except Exception as e: + error_msg = f"Failed to load example: {str(e)}" + self.logger.log_message(error_msg, color="red") + QMessageBox.critical(self.view, "Error Loading Example", error_msg) + def check_model(self): """Check the consistency of the model. And log the results.""" capture_handler = CaptureLogHandler() diff --git a/example/cond.tsv b/src/petab_gui/example/Boehm/cond.tsv similarity index 100% rename from example/cond.tsv rename to src/petab_gui/example/Boehm/cond.tsv diff --git a/example/meas.tsv b/src/petab_gui/example/Boehm/meas.tsv similarity index 100% rename from example/meas.tsv rename to src/petab_gui/example/Boehm/meas.tsv diff --git a/example/obs.tsv b/src/petab_gui/example/Boehm/obs.tsv similarity index 100% rename from example/obs.tsv rename to src/petab_gui/example/Boehm/obs.tsv diff --git a/example/para.tsv b/src/petab_gui/example/Boehm/para.tsv similarity index 100% rename from example/para.tsv rename to src/petab_gui/example/Boehm/para.tsv diff --git a/example/problem.yaml b/src/petab_gui/example/Boehm/problem.yaml similarity index 100% rename from example/problem.yaml rename to src/petab_gui/example/Boehm/problem.yaml diff --git a/example/sbml_model.xml b/src/petab_gui/example/Boehm/sbml_model.xml similarity index 100% rename from example/sbml_model.xml rename to src/petab_gui/example/Boehm/sbml_model.xml diff --git a/src/petab_gui/example/Simple_Conversion/conditions.tsv b/src/petab_gui/example/Simple_Conversion/conditions.tsv new file mode 100644 index 0000000..60b87e2 --- /dev/null +++ b/src/petab_gui/example/Simple_Conversion/conditions.tsv @@ -0,0 +1,2 @@ +conditionId conditionName +cond_1 diff --git a/src/petab_gui/example/Simple_Conversion/measurements.tsv b/src/petab_gui/example/Simple_Conversion/measurements.tsv new file mode 100644 index 0000000..311c613 --- /dev/null +++ b/src/petab_gui/example/Simple_Conversion/measurements.tsv @@ -0,0 +1,21 @@ +observableId simulationConditionId time measurement +obs_A cond_1 0.0 10.1 +obs_A cond_1 2.0 8.0 +obs_A cond_1 4.0 6.8 +obs_A cond_1 6.0 5.6 +obs_A cond_1 8.0 4.4 +obs_A cond_1 10.0 3.8 +obs_A cond_1 12.0 3.1 +obs_A cond_1 15.0 2.3 +obs_A cond_1 18.0 1.6 +obs_A cond_1 20.0 1.3 +obs_B cond_1 0.0 0.1 +obs_B cond_1 2.0 2.1 +obs_B cond_1 4.0 3.4 +obs_B cond_1 6.0 4.6 +obs_B cond_1 8.0 5.4 +obs_B cond_1 10.0 6.4 +obs_B cond_1 12.0 7.2 +obs_B cond_1 15.0 7.9 +obs_B cond_1 18.0 8.2 +obs_B cond_1 20.0 8.5 diff --git a/src/petab_gui/example/Simple_Conversion/model.xml b/src/petab_gui/example/Simple_Conversion/model.xml new file mode 100644 index 0000000..6742e86 --- /dev/null +++ b/src/petab_gui/example/Simple_Conversion/model.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + k_conversion + A + + + + + + + diff --git a/src/petab_gui/example/Simple_Conversion/observables.tsv b/src/petab_gui/example/Simple_Conversion/observables.tsv new file mode 100644 index 0000000..ca5f721 --- /dev/null +++ b/src/petab_gui/example/Simple_Conversion/observables.tsv @@ -0,0 +1,3 @@ +observableId observableFormula noiseFormula +obs_A A 0.5 +obs_B B 0.5 diff --git a/src/petab_gui/example/Simple_Conversion/parameters.tsv b/src/petab_gui/example/Simple_Conversion/parameters.tsv new file mode 100644 index 0000000..e41a76e --- /dev/null +++ b/src/petab_gui/example/Simple_Conversion/parameters.tsv @@ -0,0 +1,2 @@ +parameterId parameterScale lowerBound upperBound nominalValue estimate +k_conversion log10 0.001 100.0 0.1 1 diff --git a/src/petab_gui/example/Simple_Conversion/problem.yaml b/src/petab_gui/example/Simple_Conversion/problem.yaml new file mode 100644 index 0000000..4f715eb --- /dev/null +++ b/src/petab_gui/example/Simple_Conversion/problem.yaml @@ -0,0 +1,11 @@ +parameter_file: parameters.tsv +format_version: 1 +problems: +- condition_files: + - conditions.tsv + measurement_files: + - measurements.tsv + sbml_files: + - model.xml + observable_files: + - observables.tsv diff --git a/src/petab_gui/example/__init__.py b/src/petab_gui/example/__init__.py new file mode 100644 index 0000000..03f89ad --- /dev/null +++ b/src/petab_gui/example/__init__.py @@ -0,0 +1,5 @@ +"""Example PEtab dataset bundled with PEtab GUI. + +This package contains an example PEtab problem that can be loaded +without an internet connection. +""" diff --git a/src/petab_gui/views/task_bar.py b/src/petab_gui/views/task_bar.py index 408221c..e596e9d 100644 --- a/src/petab_gui/views/task_bar.py +++ b/src/petab_gui/views/task_bar.py @@ -52,6 +52,8 @@ def __init__(self, parent, actions): self.menu.addAction(actions["new"]) self.menu.addAction(actions["open"]) self.menu.addAction(actions["add"]) + self.menu.addAction(actions["load_example_boehm"]) + self.menu.addAction(actions["load_example_simple"]) self.menu.addAction(actions["save"]) self.menu.addMenu(actions["recent_files"]) self.menu.addSeparator()