diff --git a/doc/example/censored_data.ipynb b/doc/example/censored_data.ipynb index c5ac649db..6483aa475 100644 --- a/doc/example/censored_data.ipynb +++ b/doc/example/censored_data.ipynb @@ -59,7 +59,8 @@ "import pypesto.logging\n", "import pypesto.optimize as optimize\n", "from pypesto.petab import PetabImporter\n", - "from pypesto.visualize import plot_categories_from_pypesto_result" + "from pypesto.visualize import plot_categories_from_pypesto_result\n", + "from pypesto.examples import censored_data" ] }, { @@ -70,20 +71,6 @@ "To use censored data for parameter estimation, in pyPESTO we use the optimal scaling approach. Since the optimal scaling approach is implemented in the hierarchical manner, it requires us to specify `hierarchical=True` when importing the `petab_problem`:" ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "petab_folder = \"./example_censored/\"\n", - "yaml_file = \"example_censored.yaml\"\n", - "\n", - "petab_problem = petab.Problem.from_yaml(petab_folder + yaml_file)\n", - "\n", - "importer = PetabImporter(petab_problem, hierarchical=True)" - ] - }, { "attachments": {}, "cell_type": "markdown", @@ -107,7 +94,7 @@ "from pandas import option_context\n", "\n", "with option_context(\"display.max_colwidth\", 400):\n", - " display(petab_problem.measurement_df)" + " display(censored_data.petab_problem.measurement_df)" ] }, { @@ -162,7 +149,7 @@ "metadata": {}, "outputs": [], "source": [ - "problem = importer.create_problem()\n", + "problem = censored_data.problem\n", "\n", "engine = pypesto.engine.MultiProcessEngine(n_procs=3)\n", "\n", diff --git a/doc/example/gradient_check.ipynb b/doc/example/gradient_check.ipynb index 85de4f799..11f2ebdf0 100644 --- a/doc/example/gradient_check.ipynb +++ b/doc/example/gradient_check.ipynb @@ -38,7 +38,9 @@ "np.random.seed(2)\n", "\n", "import pandas as pd\n", - "import seaborn as sns" + "import seaborn as sns\n", + "\n", + "from pypesto.examples import boehm" ] }, { @@ -55,31 +57,14 @@ "Here, we use the startpoint sampling method to generate random parameter vectors." ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "pycharm": { - "name": "#%%\n" - } - }, - "outputs": [], - "source": [ - "%%capture\n", - "\n", - "model_name = \"Boehm_JProteomeRes2014\"\n", - "petab_problem = models.get_problem(model_name)\n", - "\n", - "importer = pypesto.petab.PetabImporter(petab_problem)\n", - "pypesto_problem = importer.create_problem(verbose=False)" - ] - }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ + "%%capture\n", + "pypesto_problem = boehm.problem\n", "startpoints = pypesto_problem.get_startpoints(n_starts=4)" ] }, @@ -318,7 +303,7 @@ ], "metadata": { "kernelspec": { - "display_name": "developer", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -332,7 +317,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.4" + "version": "3.12.3" } }, "nbformat": 4, diff --git a/doc/example/relative_data.ipynb b/doc/example/relative_data.ipynb index 677b7ff75..c87e60e3f 100644 --- a/doc/example/relative_data.ipynb +++ b/doc/example/relative_data.ipynb @@ -82,7 +82,7 @@ "outputs": [], "source": [ "# get the PEtab problem\n", - "# requires installation of\n", + "# requires installation of the benchmark collection\n", "from pypesto.testing.examples import (\n", " get_Boehm_JProteomeRes2014_hierarchical_petab,\n", " get_Boehm_JProteomeRes2014_hierarchical_petab_corrected_bounds,\n", diff --git a/doc/example/sampler_study.ipynb b/doc/example/sampler_study.ipynb index f5e0ccf95..f43b90db9 100644 --- a/doc/example/sampler_study.ipynb +++ b/doc/example/sampler_study.ipynb @@ -54,16 +54,9 @@ "import pypesto.sample as sample\n", "import pypesto.visualize as visualize\n", "\n", - "np.random.seed(0)\n", + "from pypesto.examples import conversion_reaction\n", "\n", - "# import to petab\n", - "petab_problem = petab.Problem.from_yaml(\n", - " \"conversion_reaction/conversion_reaction.yaml\"\n", - ")\n", - "# import to pypesto\n", - "importer = pypesto.petab.PetabImporter(petab_problem)\n", - "# create problem\n", - "problem = importer.create_problem(verbose=False)" + "np.random.seed(0)" ] }, { @@ -79,7 +72,7 @@ "metadata": {}, "outputs": [], "source": [ - "result = optimize.minimize(problem, n_starts=10, filename=None)" + "result = optimize.minimize(conversion_reaction.problem, n_starts=10, filename=None)" ] }, { @@ -124,7 +117,7 @@ "source": [ "%%time\n", "result = sample.sample(\n", - " problem, n_samples=1000, sampler=sampler, result=result, filename=None\n", + " conversion_reaction.problem, n_samples=1000, sampler=sampler, result=result, filename=None\n", ")" ] }, diff --git a/doc/example/store.ipynb b/doc/example/store.ipynb index 18df12962..addcacb9f 100644 --- a/doc/example/store.ipynb +++ b/doc/example/store.ipynb @@ -64,6 +64,7 @@ }, "outputs": [], "source": [ + "%%capture\n", "import logging\n", "import tempfile\n", "\n", @@ -78,51 +79,17 @@ "import pypesto.sample as sample\n", "import pypesto.visualize as visualize\n", "\n", + "from pypesto.examples import conversion_reaction\n", + "\n", "mpl.rcParams[\"figure.dpi\"] = 100\n", "mpl.rcParams[\"font.size\"] = 18\n", "# set a random seed to get reproducible results\n", "np.random.seed(3142)\n", + "problem = conversion_reaction.problem\n", "\n", "%matplotlib inline" ] }, - { - "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, - "source": [ - "## 0. Objective function and problem definition\n", - "\n", - "We will use the Boehm model from the [benchmark initiative](https://github.com/Benchmarking-Initiative/Benchmark-Models-PEtab) in this notebook as an example.\n", - "We load the model through [PEtab](https://petab.readthedocs.io/en/latest/), a data format for specifying parameter estimation problems in systems biology." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false, - "jupyter": { - "outputs_hidden": false - }, - "pycharm": { - "name": "#%%\n" - }, - "tags": [] - }, - "outputs": [], - "source": [ - "%%capture\n", - "# directory of the PEtab problem\n", - "petab_yaml = \"./conversion_reaction/conversion_reaction.yaml\"\n", - "\n", - "importer = pypesto.petab.PetabImporter.from_yaml(petab_yaml)\n", - "problem = importer.create_problem(verbose=False)" - ] - }, { "cell_type": "markdown", "metadata": { diff --git a/pypesto/examples/__init__.py b/pypesto/examples/__init__.py new file mode 100644 index 000000000..48a4412d6 --- /dev/null +++ b/pypesto/examples/__init__.py @@ -0,0 +1,9 @@ +"""Examples of the pyPESTO package.""" +from .examples import ( + boehm, + censored_data, + conversion_reaction, + ordinal_data, + semiquantitative_data, + semiquantitative_data_linear, +) diff --git a/pypesto/examples/example_class.py b/pypesto/examples/example_class.py new file mode 100644 index 000000000..b083cc797 --- /dev/null +++ b/pypesto/examples/example_class.py @@ -0,0 +1,151 @@ +"""Define a simple example class for pypesto examples.""" +import os +import tempfile +from abc import ABC, abstractmethod + +import petab.v1 as petab +import requests + +from ..objective import ObjectiveBase +from ..petab import PetabImporter +from ..problem import Problem + + +class PyPESTOExampleBase(ABC): + """Abstract example class for pypesto examples. + + Examples provide a simple wrapper around generic and in documentation + used examples. They provide a simple interface to load the objective and + problem functions. + """ + + def __init__( + self, + name: str, + description: str, + detailed_description: str | None = None, + ): + """ + Initialize the example. + + Parameters + ---------- + name: + The name of the example. + description: + A short description of the example. + detailed_description: + A detailed description of the example. + """ + self.name = name + self.description = description + self.detailed_description = detailed_description + + @property + @abstractmethod + def objective(self) -> ObjectiveBase: + """Returns the objective function of this example.""" + pass + + @property + @abstractmethod + def problem(self) -> Problem: + """Returns the problem of this example.""" + pass + + +class PyPESTOExamplePEtab(PyPESTOExampleBase): + """A PEtab example class for pypesto examples.""" + + def __init__( + self, + name: str, + description: str, + github_repo: str, + filenames: list[str], + detailed_description: str | None = None, + hierarchical: bool = False, + ): + """ + Initialize the example. + + Parameters + ---------- + name: + The name of the example. + description: + A short description of the example. + github_repo: + The github repository to download the example from. + filenames: + The filenames to download. + detailed_description: + A detailed description of the example. + hierarchical: + Whether the example is hierarchical problem. + Needs to be set for problem creation. + """ + super().__init__(name, description, detailed_description) + self.hierarchical = hierarchical + self.github_repo = github_repo + self.filenames = filenames + self.petab_yaml = next( + (filename for filename in filenames if filename.endswith(".yaml")), + None, + ) + + self._importer = None + self._petab_problem = None + self._objective = None + self._problem = None + + @property + def petab_problem(self) -> petab.Problem: + """Load the PEtab problem.""" + if self._petab_problem is not None: + return self._petab_problem + with tempfile.TemporaryDirectory() as temp_dir: + download_success = self.download_files(temp_dir) + if not download_success: + raise FileNotFoundError( + f"Could not download files from {self.github_repo}. " + f"Check your internet connection." + ) + self._petab_problem = petab.Problem.from_yaml( + os.path.join(temp_dir, self.petab_yaml) + ) + return self._petab_problem + + @property + def importer(self) -> PetabImporter: + """Load the importer.""" + if self._importer is None: + self._importer = PetabImporter( + self.petab_problem, hierarchical=self.hierarchical + ) + return self._importer + + @property + def objective(self) -> ObjectiveBase: + """Load the objective function.""" + if self._objective is None: + self._objective = self.problem.objective + return self._objective + + @property + def problem(self) -> Problem: + """Load the problem.""" + if self._problem is None: + self._problem = self.importer.create_problem() + return self._problem + + def download_files(self, dir: str): + """Download the petab files from the github repository to ``dir``.""" + for filename in self.filenames: + url = f"{self.github_repo}/{filename}" + response = requests.get(url, timeout=10) + if response.status_code != 200: + return False + with open(os.path.join(dir, filename), "wb") as file: + file.write(response.content) + return True diff --git a/pypesto/examples/examples.py b/pypesto/examples/examples.py new file mode 100644 index 000000000..bbda9130c --- /dev/null +++ b/pypesto/examples/examples.py @@ -0,0 +1,114 @@ +from .example_class import PyPESTOExamplePEtab + +boehm = PyPESTOExamplePEtab( + name="boehm_JProteomeRes2014", + description="A model of the STAT5 dimerization. Based on the publication " + "by Boehm et al. (2014) https://doi.org/10.1021/pr5006923", + github_repo="https://raw.githubusercontent.com/ICB-DCM/pyPESTO/refs/heads/" + "main/doc/example/boehm_JProteomeRes2014", + filenames=[ + "boehm_JProteomeRes2014.yaml", + "parameters_Boehm_JProteomeRes2014.tsv", + "experimentalCondition_Boehm_JProteomeRes2014.tsv", + "measurementData_Boehm_JProteomeRes2014.tsv", + "observables_Boehm_JProteomeRes2014.tsv", + "boehm_JProteomeRes2014.xml", + "visualizationSpecification_Boehm_JProteomeRes2014.tsv", + ], +) + +censored_data = PyPESTOExamplePEtab( + name="censored_data", + description="A model with censored data. Right censoring >20, left <3, " + "interval censoring [10, 16].", + github_repo="https://raw.githubusercontent.com/ICB-DCM/pyPESTO/refs/heads/" + "main/doc/example/example_censored", + filenames=[ + "example_censored.yaml", + "parameters_example_censored.tsv", + "experimentalCondition_example_censored.tsv", + "measurementData_example_censored.tsv", + "observables_example_censored.tsv", + "model_example_censored.xml", + ], + detailed_description="This model was taken from " + "https://doi.org/10.1093/bioinformatics/btab512 and " + "censoring was added to it. The PEtab problem was " + "adjusted accordingly.", + hierarchical=True, +) + +ordinal_data = PyPESTOExamplePEtab( + name="ordinal_data", + description="A model with ordinal data. The data is binned into three " + "categories.", + github_repo="https://raw.githubusercontent.com/ICB-DCM/pyPESTO/refs/heads/" + "main/doc/example/example_ordinal", + filenames=[ + "example_ordinal.yaml", + "parameters_example_ordinal.tsv", + "experimentalCondition_example_ordinal.tsv", + "measurementData_example_ordinal.tsv", + "observables_example_ordinal.tsv", + "model_example_ordinal.xml", + ], + detailed_description="This model was taken from " + "https://doi.org/10.1093/bioinformatics/btab512 and " + "The PEtab problem was slightly adjusted.", + hierarchical=True, +) + +semiquantitative_data = PyPESTOExamplePEtab( + name="semiquantitative_data", + description="A model with semiquantitative data. Nonlinear " + "transformations were applied to the data.", + github_repo="https://raw.githubusercontent.com/ICB-DCM/pyPESTO/refs/heads/" + "main/doc/example/example_semiquantitative", + filenames=[ + "example_semiquantitative.yaml", + "parameters_example_semiquantitative.tsv", + "experimentalCondition_example_semiquantitative.tsv", + "measurementData_example_semiquantitative.tsv", + "observables_example_semiquantitative.tsv", + "model_example_semiquantitative.xml", + ], + detailed_description="This model was taken from " + "https://doi.org/10.1093/bioinformatics/btab512 and " + "the PEtab problem was adjusted.", + hierarchical=True, +) + +semiquantitative_data_linear = PyPESTOExamplePEtab( + name="semiquantitative_data_linear", + description="A model with semiquantitative data. Linear " + "transformations were applied to the data.", + github_repo="https://raw.githubusercontent.com/ICB-DCM/pyPESTO/refs/heads/" + "main/doc/example/example_semiquantitative", + filenames=[ + "example_semiquantitative_linear.yaml", + "parameters_example_semiquantitative.tsv", + "experimentalCondition_example_semiquantitative.tsv", + "measurementData_example_semiquantitative_linear.tsv", + "observables_example_semiquantitative.tsv", + "model_example_semiquantitative.xml", + ], + detailed_description="This model was taken from " + "https://doi.org/10.1093/bioinformatics/btab512 and " + "the PEtab problem was adjusted.", + hierarchical=True, +) + +conversion_reaction = PyPESTOExamplePEtab( + name="conversion_reaction", + description="A simple conversion reaction model. A -> B and B -> A.", + github_repo="https://raw.githubusercontent.com/ICB-DCM/pyPESTO/refs/heads/" + "main/doc/example/conversion_reaction", + filenames=[ + "conversion_reaction.yaml", + "parameters.tsv", + "conditions.tsv", + "measurements.tsv", + "observables.tsv", + "model_conversion_reaction.xml", + ], +)