{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\n\n# Store and retrieve Skore reports in MLflow\n\nThe primilarly goal of `skore` is to create data science artifacts in the form of\nstructured reports. Those reports can easily be used programmatically via the Python\nAPI. A subsequent aim is to store those reports that you create during your experiment\ncycle in a way that it is easy to retrieve them later on.\n\nSkore provides two natives ways to store reports: locally or on Skore Hub. Skore Hub\nprovides additional interactivity features for you to explore, compare and share\nvisual insights.\n\nIn addition, Skore also provides an MLflow integration to store the content of\nreports directly as MLflow artifacts. This example shows how to persist reports in\nMLflow using :class:`~skore.Project` in ``mode=\"mlflow\"``: log reports as MLflow runs\nand inspect them.\n\nTo run this example against your own MLflow tracking server, use:\n\n```bash\nTRACKING_URI=<tracking_uri> PROJECT=<project> python plot_skore_mlflow_project.py\n```\nTo try it locally, start an MLflow server with ``uvx mlflow server`` and set\n``TRACKING_URI=http://127.0.0.1:5000``. For more setup details, see the\n[MLflow quickstart](https://mlflow.org/docs/latest/ml/getting-started/running-notebooks/).\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Create a Skore report\n\nFirst, we start by creating a Skore report by evaluating a logistic regression model\non the iris dataset using some cross-validation.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "from sklearn.datasets import load_iris\nfrom sklearn.linear_model import LogisticRegression\nfrom sklearn.pipeline import make_pipeline\nfrom sklearn.preprocessing import StandardScaler\nfrom skore import evaluate\n\nX, y = load_iris(return_X_y=True, as_frame=True)\n\nestimator = make_pipeline(StandardScaler(), LogisticRegression())\nreport = evaluate(estimator, X, y, splitter=5)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Store the Skore reports as MLflow artifacts\n\nNow, we will store the different items of the Skore report as MLflow artifacts.\nFor this matter, you need to create a :class:`~skore.Project` in ``mode=\"mlflow\"``\nand pass the information regarding the MLflow tracking server.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "import io\n\n\n# MLflow/Alembic emits verbose DB initialization logs; silence them so the\n# example page focuses on skore usage rather than backend startup details.\nwith redirect_stdout(io.StringIO()), redirect_stderr(io.StringIO()):\n    # This creates an MLflow experiment with name `PROJECT`:\n    project = Project(\n        PROJECT,\n        mode=\"mlflow\",\n        tracking_uri=TRACKING_URI,\n    )"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Once the project created, the same API used to store a report locally or on Skore Hub\napplies.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "project.put(\"logistic-regression\", report)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Once that you stored the report, the artifacts will be available on the MLflow\ntracking server at the following URL:\n``http://<TRACKING_URI>/#/<PROJECT>/1/runs/<RUN_ID>/artifacts``\n\nTo find the run ID attributed by MLflow, you can check the section below.\n\n## Retrieve the Skore report from MLflow tracking server\n\nLike for the other modes (local and Skore Hub), you can access what is stored in the\nproject via the :meth:`~skore.Project.summarize` method.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "import pandas as pd\n\nsummary = project.summarize()\npandas_summary = pd.DataFrame(summary).reset_index()\npandas_summary[[\"id\", \"key\", \"report_type\", \"learner\", \"ml_task\", \"dataset\"]]"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Then, you can retrieve a Skore report using the `\"id\"` column:\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "(run_id,) = pandas_summary[\"id\"]\nloaded_report = project.get(run_id)\nloaded_report.metrics.summarize().frame()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "You can directly use MLflow to access information stored in the MLflow tracking\nserver.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "import mlflow\n\nmlflow_run = mlflow.get_run(run_id)\nmlflow_run.data.metrics"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Conclusion\n\nSkore offers native integrations locally and with Skore Hub. However, if you are\nalready using MLflow, you can use the ``mode=\"mlflow\"`` option to store reports as\nMLflow artifacts directly inside the tracking server.\n\nHowever, you will not benefit from the interactive user interface provided by Skore\nHub.\n\n"
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.14.4"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}