diff --git a/docs/api_examples/line_plot.ipynb b/docs/api_examples/line_plot.ipynb new file mode 100644 index 0000000..4272dd8 --- /dev/null +++ b/docs/api_examples/line_plot.ipynb @@ -0,0 +1,4490 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "640ba1d5", + "metadata": {}, + "source": [ + "# Line Plot\n", + "\n", + "![VueCore logo][vuecore_logo]\n", + "\n", + "[![Open In Colab][colab_badge]][colab_link]\n", + "\n", + "[VueCore][vuecore_repo] is a Python package for creating interactive and static visualizations of multi-omics data.\n", + "It is part of a broader ecosystem of tools—including [ACore][acore_repo] for data processing and [VueGen][vuegen_repo] for automated reporting—that together enable end-to-end workflows for omics analysis.\n", + "\n", + "This notebook demonstrates how to generate line plots using plotting functions from VueCore. We showcase basic and\n", + "advanced plot configurations, highlighting key customization options such as grouping, color mapping, text annotations, and export to multiple file formats.\n", + "\n", + "## Notebook structure\n", + "\n", + "First, we will set up the work environment by installing the necessary packages and importing the required libraries. Next, we will create basic and advanced line plots.\n", + "\n", + "0. [Work environment setup](#0-work-environment-setup)\n", + "1. [Basic line plot](#1-basic-line-plot)\n", + "2. [Advanced line plot](#2-advanced-line-plot)\n", + "\n", + "## Credits and Contributors\n", + "- This notebook was created by Sebastián Ayala-Ruano under the supervision of Henry Webel and Alberto Santos, head of the [Multiomics Network Analytics Group (MoNA)][Mona] at the [Novo Nordisk Foundation Center for Biosustainability (DTU Biosustain)][Biosustain].\n", + "- You can find more details about the project in this [GitHub repository][vuecore_repo].\n", + "\n", + "[colab_badge]: https://colab.research.google.com/assets/colab-badge.svg\n", + "[colab_link]: https://colab.research.google.com/github/Multiomics-Analytics-Group/vuecore/blob/main/docs/api_examples/line_plot.ipynb\n", + "[vuecore_logo]: https://raw.githubusercontent.com/Multiomics-Analytics-Group/vuecore/main/docs/images/logo/vuecore_logo.svg\n", + "[Mona]: https://multiomics-analytics-group.github.io/\n", + "[Biosustain]: https://www.biosustain.dtu.dk/\n", + "[vuecore_repo]: https://github.com/Multiomics-Analytics-Group/vuecore\n", + "[vuegen_repo]: https://github.com/Multiomics-Analytics-Group/vuegen\n", + "[acore_repo]: https://github.com/Multiomics-Analytics-Group/acore" + ] + }, + { + "cell_type": "markdown", + "id": "3b504dfb", + "metadata": {}, + "source": [ + "## 0. Work environment setup" + ] + }, + { + "cell_type": "markdown", + "id": "f0c056a7", + "metadata": {}, + "source": [ + "### 0.1. Installing libraries and creating global variables for platform and working directory\n", + "\n", + "To run this notebook locally, you should create a virtual environment with the required libraries. If you are running this notebook on Google Colab, everything should be set." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "36246ed6", + "metadata": { + "tags": [ + "hide-output" + ] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Processing /Users/asaru/Documents/DTU/MoNA/VueCore/vuecore\n", + " Installing build dependencies ... \u001b[?25ldone\n", + "\u001b[?25h Getting requirements to build wheel ... \u001b[?25ldone\n", + "\u001b[?25h Preparing metadata (pyproject.toml) ... \u001b[?25ldone\n", + "\u001b[?25hRequirement already satisfied: numpy in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from vuecore==0.0.6.dev19+g58e96db.d20250624) (2.2.6)\n", + "Requirement already satisfied: pandas in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from vuecore==0.0.6.dev19+g58e96db.d20250624) (2.3.0)\n", + "Requirement already satisfied: scipy in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from vuecore==0.0.6.dev19+g58e96db.d20250624) (1.16.0)\n", + "Requirement already satisfied: plotly in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from vuecore==0.0.6.dev19+g58e96db.d20250624) (6.1.2)\n", + "Requirement already satisfied: beautifulsoup4 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from vuecore==0.0.6.dev19+g58e96db.d20250624) (4.13.4)\n", + "Requirement already satisfied: requests in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from vuecore==0.0.6.dev19+g58e96db.d20250624) (2.32.4)\n", + "Requirement already satisfied: dash in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from vuecore==0.0.6.dev19+g58e96db.d20250624) (3.0.4)\n", + "Requirement already satisfied: networkx in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from vuecore==0.0.6.dev19+g58e96db.d20250624) (3.5)\n", + "Requirement already satisfied: matplotlib in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from vuecore==0.0.6.dev19+g58e96db.d20250624) (3.10.3)\n", + "Requirement already satisfied: kaleido in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from vuecore==0.0.6.dev19+g58e96db.d20250624) (1.0.0)\n", + "Requirement already satisfied: pyvis in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from vuecore==0.0.6.dev19+g58e96db.d20250624) (0.3.1)\n", + "Requirement already satisfied: wordcloud in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from vuecore==0.0.6.dev19+g58e96db.d20250624) (1.9.4)\n", + "Requirement already satisfied: cyjupyter in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from vuecore==0.0.6.dev19+g58e96db.d20250624) (0.2.0)\n", + "Requirement already satisfied: nltk in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from vuecore==0.0.6.dev19+g58e96db.d20250624) (3.9.1)\n", + "Requirement already satisfied: webweb in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from vuecore==0.0.6.dev19+g58e96db.d20250624) (0.0.37)\n", + "Requirement already satisfied: acore in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from vuecore==0.0.6.dev19+g58e96db.d20250624) (0.1.3)\n", + "Requirement already satisfied: dash-cytoscape in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from vuecore==0.0.6.dev19+g58e96db.d20250624) (1.0.2)\n", + "Requirement already satisfied: pydantic in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from vuecore==0.0.6.dev19+g58e96db.d20250624) (2.11.7)\n", + "Collecting nbformat>=4.2.0 (from vuecore==0.0.6.dev19+g58e96db.d20250624)\n", + " Using cached nbformat-5.10.4-py3-none-any.whl.metadata (3.6 kB)\n", + "Collecting fastjsonschema>=2.15 (from nbformat>=4.2.0->vuecore==0.0.6.dev19+g58e96db.d20250624)\n", + " Using cached fastjsonschema-2.21.1-py3-none-any.whl.metadata (2.2 kB)\n", + "Collecting jsonschema>=2.6 (from nbformat>=4.2.0->vuecore==0.0.6.dev19+g58e96db.d20250624)\n", + " Using cached jsonschema-4.24.0-py3-none-any.whl.metadata (7.8 kB)\n", + "Requirement already satisfied: jupyter-core!=5.0.*,>=4.12 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from nbformat>=4.2.0->vuecore==0.0.6.dev19+g58e96db.d20250624) (5.8.1)\n", + "Requirement already satisfied: traitlets>=5.1 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from nbformat>=4.2.0->vuecore==0.0.6.dev19+g58e96db.d20250624) (5.14.3)\n", + "Collecting attrs>=22.2.0 (from jsonschema>=2.6->nbformat>=4.2.0->vuecore==0.0.6.dev19+g58e96db.d20250624)\n", + " Using cached attrs-25.3.0-py3-none-any.whl.metadata (10 kB)\n", + "Collecting jsonschema-specifications>=2023.03.6 (from jsonschema>=2.6->nbformat>=4.2.0->vuecore==0.0.6.dev19+g58e96db.d20250624)\n", + " Using cached jsonschema_specifications-2025.4.1-py3-none-any.whl.metadata (2.9 kB)\n", + "Collecting referencing>=0.28.4 (from jsonschema>=2.6->nbformat>=4.2.0->vuecore==0.0.6.dev19+g58e96db.d20250624)\n", + " Using cached referencing-0.36.2-py3-none-any.whl.metadata (2.8 kB)\n", + "Collecting rpds-py>=0.7.1 (from jsonschema>=2.6->nbformat>=4.2.0->vuecore==0.0.6.dev19+g58e96db.d20250624)\n", + " Using cached rpds_py-0.25.1-cp312-cp312-macosx_11_0_arm64.whl.metadata (4.1 kB)\n", + "Requirement already satisfied: platformdirs>=2.5 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from jupyter-core!=5.0.*,>=4.12->nbformat>=4.2.0->vuecore==0.0.6.dev19+g58e96db.d20250624) (4.3.8)\n", + "Requirement already satisfied: typing-extensions>=4.4.0 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from referencing>=0.28.4->jsonschema>=2.6->nbformat>=4.2.0->vuecore==0.0.6.dev19+g58e96db.d20250624) (4.14.0)\n", + "Requirement already satisfied: dsp-pandas in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from acore->vuecore==0.0.6.dev19+g58e96db.d20250624) (0.0.5)\n", + "Requirement already satisfied: scikit-learn>=1.2 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from acore->vuecore==0.0.6.dev19+g58e96db.d20250624) (1.7.0)\n", + "Requirement already satisfied: biopython in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from acore->vuecore==0.0.6.dev19+g58e96db.d20250624) (1.85)\n", + "Requirement already satisfied: combat in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from acore->vuecore==0.0.6.dev19+g58e96db.d20250624) (0.3.3)\n", + "Requirement already satisfied: gseapy!=1.1.5 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from acore->vuecore==0.0.6.dev19+g58e96db.d20250624) (1.1.9)\n", + "Requirement already satisfied: kmapper in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from acore->vuecore==0.0.6.dev19+g58e96db.d20250624) (2.1.0)\n", + "Requirement already satisfied: lifelines in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from acore->vuecore==0.0.6.dev19+g58e96db.d20250624) (0.30.0)\n", + "Requirement already satisfied: pingouin in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from acore->vuecore==0.0.6.dev19+g58e96db.d20250624) (0.5.5)\n", + "Requirement already satisfied: python-louvain in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from acore->vuecore==0.0.6.dev19+g58e96db.d20250624) (0.16)\n", + "Requirement already satisfied: PyWGCNA!=2.2.0 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from acore->vuecore==0.0.6.dev19+g58e96db.d20250624) (2.2.1)\n", + "Requirement already satisfied: snfpy in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from acore->vuecore==0.0.6.dev19+g58e96db.d20250624) (0.2.2)\n", + "Requirement already satisfied: umap-learn in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from acore->vuecore==0.0.6.dev19+g58e96db.d20250624) (0.5.7)\n", + "Requirement already satisfied: statsmodels in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from acore->vuecore==0.0.6.dev19+g58e96db.d20250624) (0.14.4)\n", + "Requirement already satisfied: inmoose in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from acore->vuecore==0.0.6.dev19+g58e96db.d20250624) (0.7.7)\n", + "Requirement already satisfied: rarfile in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from acore->vuecore==0.0.6.dev19+g58e96db.d20250624) (4.2)\n", + "Requirement already satisfied: contourpy>=1.0.1 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from matplotlib->vuecore==0.0.6.dev19+g58e96db.d20250624) (1.3.2)\n", + "Requirement already satisfied: cycler>=0.10 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from matplotlib->vuecore==0.0.6.dev19+g58e96db.d20250624) (0.12.1)\n", + "Requirement already satisfied: fonttools>=4.22.0 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from matplotlib->vuecore==0.0.6.dev19+g58e96db.d20250624) (4.58.4)\n", + "Requirement already satisfied: kiwisolver>=1.3.1 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from matplotlib->vuecore==0.0.6.dev19+g58e96db.d20250624) (1.4.8)\n", + "Requirement already satisfied: packaging>=20.0 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from matplotlib->vuecore==0.0.6.dev19+g58e96db.d20250624) (25.0)\n", + "Requirement already satisfied: pillow>=8 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from matplotlib->vuecore==0.0.6.dev19+g58e96db.d20250624) (11.2.1)\n", + "Requirement already satisfied: pyparsing>=2.3.1 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from matplotlib->vuecore==0.0.6.dev19+g58e96db.d20250624) (3.2.3)\n", + "Requirement already satisfied: python-dateutil>=2.7 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from matplotlib->vuecore==0.0.6.dev19+g58e96db.d20250624) (2.9.0.post0)\n", + "Requirement already satisfied: six>=1.5 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from python-dateutil>=2.7->matplotlib->vuecore==0.0.6.dev19+g58e96db.d20250624) (1.17.0)\n", + "Requirement already satisfied: seaborn>=0.11.2 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from PyWGCNA!=2.2.0->acore->vuecore==0.0.6.dev19+g58e96db.d20250624) (0.13.2)\n", + "Requirement already satisfied: biomart>=0.9.2 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from PyWGCNA!=2.2.0->acore->vuecore==0.0.6.dev19+g58e96db.d20250624) (0.9.2)\n", + "Requirement already satisfied: setuptools>=67.4.0 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from PyWGCNA!=2.2.0->acore->vuecore==0.0.6.dev19+g58e96db.d20250624) (80.9.0)\n", + "Requirement already satisfied: reactome2py>=3.0.0 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from PyWGCNA!=2.2.0->acore->vuecore==0.0.6.dev19+g58e96db.d20250624) (3.0.0)\n", + "Requirement already satisfied: anndata>=0.10.8 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from PyWGCNA!=2.2.0->acore->vuecore==0.0.6.dev19+g58e96db.d20250624) (0.11.4)\n", + "Requirement already satisfied: rsrc>=0.1.3 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from PyWGCNA!=2.2.0->acore->vuecore==0.0.6.dev19+g58e96db.d20250624) (0.1.3)\n", + "Requirement already satisfied: psutil>=5.9.0 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from PyWGCNA!=2.2.0->acore->vuecore==0.0.6.dev19+g58e96db.d20250624) (7.0.0)\n", + "Requirement already satisfied: jinja2>=2.9.6 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from pyvis->vuecore==0.0.6.dev19+g58e96db.d20250624) (3.1.6)\n", + "Requirement already satisfied: ipython>=5.3.0 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from pyvis->vuecore==0.0.6.dev19+g58e96db.d20250624) (9.3.0)\n", + "Requirement already satisfied: jsonpickle>=1.4.1 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from pyvis->vuecore==0.0.6.dev19+g58e96db.d20250624) (4.1.1)\n", + "Requirement already satisfied: array-api-compat!=1.5,>1.4 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from anndata>=0.10.8->PyWGCNA!=2.2.0->acore->vuecore==0.0.6.dev19+g58e96db.d20250624) (1.12.0)\n", + "Requirement already satisfied: h5py>=3.7 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from anndata>=0.10.8->PyWGCNA!=2.2.0->acore->vuecore==0.0.6.dev19+g58e96db.d20250624) (3.14.0)\n", + "Requirement already satisfied: natsort in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from anndata>=0.10.8->PyWGCNA!=2.2.0->acore->vuecore==0.0.6.dev19+g58e96db.d20250624) (8.4.0)\n", + "Requirement already satisfied: decorator in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from ipython>=5.3.0->pyvis->vuecore==0.0.6.dev19+g58e96db.d20250624) (5.2.1)\n", + "Requirement already satisfied: ipython-pygments-lexers in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from ipython>=5.3.0->pyvis->vuecore==0.0.6.dev19+g58e96db.d20250624) (1.1.1)\n", + "Requirement already satisfied: jedi>=0.16 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from ipython>=5.3.0->pyvis->vuecore==0.0.6.dev19+g58e96db.d20250624) (0.19.2)\n", + "Requirement already satisfied: matplotlib-inline in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from ipython>=5.3.0->pyvis->vuecore==0.0.6.dev19+g58e96db.d20250624) (0.1.7)\n", + "Requirement already satisfied: pexpect>4.3 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from ipython>=5.3.0->pyvis->vuecore==0.0.6.dev19+g58e96db.d20250624) (4.9.0)\n", + "Requirement already satisfied: prompt_toolkit<3.1.0,>=3.0.41 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from ipython>=5.3.0->pyvis->vuecore==0.0.6.dev19+g58e96db.d20250624) (3.0.51)\n", + "Requirement already satisfied: pygments>=2.4.0 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from ipython>=5.3.0->pyvis->vuecore==0.0.6.dev19+g58e96db.d20250624) (2.19.2)\n", + "Requirement already satisfied: stack_data in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from ipython>=5.3.0->pyvis->vuecore==0.0.6.dev19+g58e96db.d20250624) (0.6.3)\n", + "Requirement already satisfied: wcwidth in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from prompt_toolkit<3.1.0,>=3.0.41->ipython>=5.3.0->pyvis->vuecore==0.0.6.dev19+g58e96db.d20250624) (0.2.13)\n", + "Requirement already satisfied: parso<0.9.0,>=0.8.4 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from jedi>=0.16->ipython>=5.3.0->pyvis->vuecore==0.0.6.dev19+g58e96db.d20250624) (0.8.4)\n", + "Requirement already satisfied: MarkupSafe>=2.0 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from jinja2>=2.9.6->pyvis->vuecore==0.0.6.dev19+g58e96db.d20250624) (3.0.2)\n", + "Requirement already satisfied: pytz>=2020.1 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from pandas->vuecore==0.0.6.dev19+g58e96db.d20250624) (2025.2)\n", + "Requirement already satisfied: tzdata>=2022.7 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from pandas->vuecore==0.0.6.dev19+g58e96db.d20250624) (2025.2)\n", + "Requirement already satisfied: ptyprocess>=0.5 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from pexpect>4.3->ipython>=5.3.0->pyvis->vuecore==0.0.6.dev19+g58e96db.d20250624) (0.7.0)\n", + "Requirement already satisfied: json5>=0.8.4 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from reactome2py>=3.0.0->PyWGCNA!=2.2.0->acore->vuecore==0.0.6.dev19+g58e96db.d20250624) (0.12.0)\n", + "Requirement already satisfied: charset_normalizer<4,>=2 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from requests->vuecore==0.0.6.dev19+g58e96db.d20250624) (3.4.2)\n", + "Requirement already satisfied: idna<4,>=2.5 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from requests->vuecore==0.0.6.dev19+g58e96db.d20250624) (3.10)\n", + "Requirement already satisfied: urllib3<3,>=1.21.1 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from requests->vuecore==0.0.6.dev19+g58e96db.d20250624) (2.5.0)\n", + "Requirement already satisfied: certifi>=2017.4.17 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from requests->vuecore==0.0.6.dev19+g58e96db.d20250624) (2025.6.15)\n", + "Requirement already satisfied: memoir>=0.0.3 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from rsrc>=0.1.3->PyWGCNA!=2.2.0->acore->vuecore==0.0.6.dev19+g58e96db.d20250624) (0.0.3)\n", + "Requirement already satisfied: reprit>=0.3.0 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from rsrc>=0.1.3->PyWGCNA!=2.2.0->acore->vuecore==0.0.6.dev19+g58e96db.d20250624) (0.9.0)\n", + "Requirement already satisfied: joblib>=1.2.0 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from scikit-learn>=1.2->acore->vuecore==0.0.6.dev19+g58e96db.d20250624) (1.5.1)\n", + "Requirement already satisfied: threadpoolctl>=3.1.0 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from scikit-learn>=1.2->acore->vuecore==0.0.6.dev19+g58e96db.d20250624) (3.6.0)\n", + "Requirement already satisfied: patsy>=0.5.6 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from statsmodels->acore->vuecore==0.0.6.dev19+g58e96db.d20250624) (1.0.1)\n", + "Requirement already satisfied: soupsieve>1.2 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from beautifulsoup4->vuecore==0.0.6.dev19+g58e96db.d20250624) (2.7)\n", + "Requirement already satisfied: mpmath>=1.1.0 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from combat->acore->vuecore==0.0.6.dev19+g58e96db.d20250624) (1.3.0)\n", + "Requirement already satisfied: ipywidgets>=7.0.0 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from cyjupyter->vuecore==0.0.6.dev19+g58e96db.d20250624) (8.1.7)\n", + "Requirement already satisfied: comm>=0.1.3 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from ipywidgets>=7.0.0->cyjupyter->vuecore==0.0.6.dev19+g58e96db.d20250624) (0.2.2)\n", + "Requirement already satisfied: widgetsnbextension~=4.0.14 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from ipywidgets>=7.0.0->cyjupyter->vuecore==0.0.6.dev19+g58e96db.d20250624) (4.0.14)\n", + "Requirement already satisfied: jupyterlab_widgets~=3.0.15 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from ipywidgets>=7.0.0->cyjupyter->vuecore==0.0.6.dev19+g58e96db.d20250624) (3.0.15)\n", + "Requirement already satisfied: Flask<3.1,>=1.0.4 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from dash->vuecore==0.0.6.dev19+g58e96db.d20250624) (3.0.3)\n", + "Requirement already satisfied: Werkzeug<3.1 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from dash->vuecore==0.0.6.dev19+g58e96db.d20250624) (3.0.6)\n", + "Requirement already satisfied: importlib-metadata in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from dash->vuecore==0.0.6.dev19+g58e96db.d20250624) (8.7.0)\n", + "Requirement already satisfied: retrying in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from dash->vuecore==0.0.6.dev19+g58e96db.d20250624) (1.3.5)\n", + "Requirement already satisfied: nest-asyncio in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from dash->vuecore==0.0.6.dev19+g58e96db.d20250624) (1.6.0)\n", + "Requirement already satisfied: itsdangerous>=2.1.2 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from Flask<3.1,>=1.0.4->dash->vuecore==0.0.6.dev19+g58e96db.d20250624) (2.2.0)\n", + "Requirement already satisfied: click>=8.1.3 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from Flask<3.1,>=1.0.4->dash->vuecore==0.0.6.dev19+g58e96db.d20250624) (8.2.1)\n", + "Requirement already satisfied: blinker>=1.6.2 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from Flask<3.1,>=1.0.4->dash->vuecore==0.0.6.dev19+g58e96db.d20250624) (1.9.0)\n", + "Requirement already satisfied: narwhals>=1.15.1 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from plotly->vuecore==0.0.6.dev19+g58e96db.d20250624) (1.44.0)\n", + "Requirement already satisfied: openpyxl in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from dsp-pandas->acore->vuecore==0.0.6.dev19+g58e96db.d20250624) (3.1.5)\n", + "Requirement already satisfied: zipp>=3.20 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from importlib-metadata->dash->vuecore==0.0.6.dev19+g58e96db.d20250624) (3.23.0)\n", + "Requirement already satisfied: fastcluster in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from inmoose->acore->vuecore==0.0.6.dev19+g58e96db.d20250624) (1.3.0)\n", + "Requirement already satisfied: choreographer>=1.0.5 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from kaleido->vuecore==0.0.6.dev19+g58e96db.d20250624) (1.0.9)\n", + "Requirement already satisfied: logistro>=1.0.8 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from kaleido->vuecore==0.0.6.dev19+g58e96db.d20250624) (1.1.0)\n", + "Requirement already satisfied: orjson>=3.10.15 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from kaleido->vuecore==0.0.6.dev19+g58e96db.d20250624) (3.10.18)\n", + "Requirement already satisfied: simplejson>=3.19.3 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from choreographer>=1.0.5->kaleido->vuecore==0.0.6.dev19+g58e96db.d20250624) (3.20.1)\n", + "Requirement already satisfied: autograd>=1.5 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from lifelines->acore->vuecore==0.0.6.dev19+g58e96db.d20250624) (1.8.0)\n", + "Requirement already satisfied: autograd-gamma>=0.3 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from lifelines->acore->vuecore==0.0.6.dev19+g58e96db.d20250624) (0.5.0)\n", + "Requirement already satisfied: formulaic>=0.2.2 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from lifelines->acore->vuecore==0.0.6.dev19+g58e96db.d20250624) (1.1.1)\n", + "Requirement already satisfied: interface-meta>=1.2.0 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from formulaic>=0.2.2->lifelines->acore->vuecore==0.0.6.dev19+g58e96db.d20250624) (1.3.0)\n", + "Requirement already satisfied: wrapt>=1.0 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from formulaic>=0.2.2->lifelines->acore->vuecore==0.0.6.dev19+g58e96db.d20250624) (1.17.2)\n", + "Requirement already satisfied: regex>=2021.8.3 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from nltk->vuecore==0.0.6.dev19+g58e96db.d20250624) (2024.11.6)\n", + "Requirement already satisfied: tqdm in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from nltk->vuecore==0.0.6.dev19+g58e96db.d20250624) (4.67.1)\n", + "Requirement already satisfied: et-xmlfile in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from openpyxl->dsp-pandas->acore->vuecore==0.0.6.dev19+g58e96db.d20250624) (2.0.0)\n", + "Requirement already satisfied: pandas-flavor in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from pingouin->acore->vuecore==0.0.6.dev19+g58e96db.d20250624) (0.7.0)\n", + "Requirement already satisfied: tabulate in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from pingouin->acore->vuecore==0.0.6.dev19+g58e96db.d20250624) (0.9.0)\n", + "Requirement already satisfied: xarray in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from pandas-flavor->pingouin->acore->vuecore==0.0.6.dev19+g58e96db.d20250624) (2025.6.1)\n", + "Requirement already satisfied: annotated-types>=0.6.0 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from pydantic->vuecore==0.0.6.dev19+g58e96db.d20250624) (0.7.0)\n", + "Requirement already satisfied: pydantic-core==2.33.2 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from pydantic->vuecore==0.0.6.dev19+g58e96db.d20250624) (2.33.2)\n", + "Requirement already satisfied: typing-inspection>=0.4.0 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from pydantic->vuecore==0.0.6.dev19+g58e96db.d20250624) (0.4.1)\n", + "Requirement already satisfied: executing>=1.2.0 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from stack_data->ipython>=5.3.0->pyvis->vuecore==0.0.6.dev19+g58e96db.d20250624) (2.2.0)\n", + "Requirement already satisfied: asttokens>=2.1.0 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from stack_data->ipython>=5.3.0->pyvis->vuecore==0.0.6.dev19+g58e96db.d20250624) (3.0.0)\n", + "Requirement already satisfied: pure_eval in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from stack_data->ipython>=5.3.0->pyvis->vuecore==0.0.6.dev19+g58e96db.d20250624) (0.2.3)\n", + "Requirement already satisfied: numba>=0.51.2 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from umap-learn->acore->vuecore==0.0.6.dev19+g58e96db.d20250624) (0.61.2)\n", + "Requirement already satisfied: pynndescent>=0.5 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from umap-learn->acore->vuecore==0.0.6.dev19+g58e96db.d20250624) (0.5.13)\n", + "Requirement already satisfied: llvmlite<0.45,>=0.44.0dev0 in /Users/asaru/miniconda3/envs/vuecore-dev/lib/python3.12/site-packages (from numba>=0.51.2->umap-learn->acore->vuecore==0.0.6.dev19+g58e96db.d20250624) (0.44.0)\n", + "Using cached nbformat-5.10.4-py3-none-any.whl (78 kB)\n", + "Using cached fastjsonschema-2.21.1-py3-none-any.whl (23 kB)\n", + "Using cached jsonschema-4.24.0-py3-none-any.whl (88 kB)\n", + "Using cached attrs-25.3.0-py3-none-any.whl (63 kB)\n", + "Using cached jsonschema_specifications-2025.4.1-py3-none-any.whl (18 kB)\n", + "Using cached referencing-0.36.2-py3-none-any.whl (26 kB)\n", + "Using cached rpds_py-0.25.1-cp312-cp312-macosx_11_0_arm64.whl (350 kB)\n", + "Building wheels for collected packages: vuecore\n", + " Building wheel for vuecore (pyproject.toml) ... \u001b[?25ldone\n", + "\u001b[?25h Created wheel for vuecore: filename=vuecore-0.0.6.dev19+g58e96db.d20250624-py3-none-any.whl size=55625 sha256=dbbfec57f735203a8482a18fcaf73e20e081423669249c13003a42369f4aff2c\n", + " Stored in directory: /private/var/folders/64/3nt358294s9cjcj1qbtv1g_h0000gp/T/pip-ephem-wheel-cache-8mu7llb7/wheels/b7/c2/2a/80a17c0f7fe0587d17a3dc604f395e41401dc2c1e23b377f0e\n", + "Successfully built vuecore\n", + "Installing collected packages: fastjsonschema, rpds-py, attrs, referencing, jsonschema-specifications, jsonschema, nbformat, vuecore\n", + "\u001b[2K Attempting uninstall: vuecore━━━━━━━\u001b[0m\u001b[90m╺\u001b[0m\u001b[90m━━━━━━━━━\u001b[0m \u001b[32m6/8\u001b[0m [nbformat]a]]\n", + "\u001b[2K Found existing installation: vuecore 0.0.6.dev19+g58e96db.d20250624m6/8\u001b[0m [nbformat]\n", + "\u001b[2K Uninstalling vuecore-0.0.6.dev19+g58e96db.d20250624:━━━━━━\u001b[0m \u001b[32m6/8\u001b[0m [nbformat]\n", + "\u001b[2K Successfully uninstalled vuecore-0.0.6.dev19+g58e96db.d2025062432m6/8\u001b[0m [nbformat]\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m8/8\u001b[0m [vuecore]m7/8\u001b[0m [vuecore]\n", + "\u001b[1A\u001b[2KSuccessfully installed attrs-25.3.0 fastjsonschema-2.21.1 jsonschema-4.24.0 jsonschema-specifications-2025.4.1 nbformat-5.10.4 referencing-0.36.2 rpds-py-0.25.1 vuecore-0.0.6.dev19+g58e96db.d20250624\n", + "Note: you may need to restart the kernel to use updated packages.\n" + ] + } + ], + "source": [ + "# VueCore library\n", + "%pip install vuecore" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "963a9529", + "metadata": { + "tags": [ + "hide-cell" + ] + }, + "outputs": [], + "source": [ + "import os\n", + "\n", + "IN_COLAB = \"COLAB_GPU\" in os.environ" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "ee2ffd40", + "metadata": { + "tags": [ + "hide-cell" + ] + }, + "outputs": [], + "source": [ + "# Create a directory for outputs\n", + "output_dir = \"./outputs\"\n", + "os.makedirs(output_dir, exist_ok=True)" + ] + }, + { + "cell_type": "markdown", + "id": "31638f9a", + "metadata": {}, + "source": [ + "### 0.2. Importing libraries" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "06dbf6a2", + "metadata": {}, + "outputs": [], + "source": [ + "# Imports\n", + "import pandas as pd\n", + "import plotly.io as pio\n", + "\n", + "from vuecore.plots.basic.line import create_line_plot\n", + "\n", + "# Set the Plotly renderer based on the environment\n", + "pio.renderers.default = \"notebook\"" + ] + }, + { + "cell_type": "markdown", + "id": "5cc60050", + "metadata": {}, + "source": [ + "### 0.3. Create sample data\n", + "We create a synthetic dataset showing measurements over five days for two experiments (A, B), each tested under Control and Treatment conditions, with associated measurement errors." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "ac2db647", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
dayexperimentconditionvaluevalue_error
01AControl111.0
12AControl131.2
23AControl150.9
34AControl171.1
45AControl181.0
\n", + "
" + ], + "text/plain": [ + " day experiment condition value value_error\n", + "0 1 A Control 11 1.0\n", + "1 2 A Control 13 1.2\n", + "2 3 A Control 15 0.9\n", + "3 4 A Control 17 1.1\n", + "4 5 A Control 18 1.0" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sample_df = pd.DataFrame({\n", + " \"day\": list(range(1, 6)) * 4, # 5 days\n", + " \"experiment\": [\"A\"] * 10 + [\"B\"] * 10, # 2 experiments\n", + " \"condition\": ([\"Control\"] * 5 + [\"Treatment\"] * 5) * 2, # 2 conditions\n", + " \"value\": [\n", + " 11, 13, 15, 17, 18, # A - Control\n", + " 10, 12, 14, 15, 16, # A - Treatment\n", + " 19, 20, 21, 22, 23, # B - Control\n", + " 20, 22, 21, 23, 22, # B - Treatment\n", + " ],\n", + " \"value_error\": [1, 1.2, 0.9, 1.1, 1.0, 1.3, 1.0, 1.2, 1.4, 1.1,\n", + " 2.0, 1.8, 2.1, 1.5, 2.3, 1.7, 2.0, 1.8, 2.1, 2.2],\n", + "})\n", + "\n", + "sample_df.head()" + ] + }, + { + "cell_type": "markdown", + "id": "ade445fe", + "metadata": {}, + "source": [ + "## 1. Basic Line Plot\n", + "A basic line plot can be created by simply providing the `x`, `y`, and `color` columns from the DataFrame." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "d0d34455", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[VueCore] Plot saved to ./outputs/line_plot_basic.png\n" + ] + }, + { + "data": { + "text/html": [ + " \n", + " \n", + " " + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Define output path\n", + "file_path_basic_png = os.path.join(output_dir, \"line_plot_basic.png\")\n", + "\n", + "# Generate basic plot\n", + "fig = create_line_plot(\n", + " data=sample_df,\n", + " x=\"day\",\n", + " y=\"value\",\n", + " color=\"experiment\",\n", + " line_dash=\"condition\",\n", + " file_path=file_path_basic_png,\n", + ")\n", + "\n", + "fig.show()" + ] + }, + { + "cell_type": "markdown", + "id": "f5e16637", + "metadata": {}, + "source": [ + "## 2. Advanced Line Plot\n", + "Here is an example of an advanced line plot with more descriptive parameters, including error bars, line styles, markers, and custom colors." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "f9307e85", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[VueCore] Plot saved to ./outputs/line_plot_advanced.html\n" + ] + }, + { + "data": { + "text/html": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Define output path\n", + "file_path_adv_html = os.path.join(output_dir, \"line_plot_advanced.html\")\n", + "\n", + "# Generate advanced plot\n", + "fig_advanced = create_line_plot(\n", + " data=sample_df,\n", + " x=\"day\",\n", + " y=\"value\",\n", + " color=\"experiment\", \n", + " line_dash=\"condition\", \n", + " error_y=\"value_error\", \n", + " title=\"Experiment & Condition Trends\",\n", + " subtitle = \"Measurements over 5 days for two experiments (A, B) under Control and Treatment conditions.\",\n", + " labels={\"day\": \"Day\", \"value\": \"Response\", \"condition\": \"Condition\", \"experiment\": \"Experiment\"},\n", + " color_discrete_map={\"A\": \"#508AA8\", \"B\": \"#A8505E\"},\n", + " line_dash_map={\"Control\": \"solid\", \"Treatment\": \"dot\"},\n", + " markers=True,\n", + " line_shape=\"spline\",\n", + " file_path=file_path_adv_html,\n", + ")\n", + "\n", + "fig_advanced.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "vuecore-dev", + "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.12.11" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/api_examples/line_plot.py b/docs/api_examples/line_plot.py new file mode 100644 index 0000000..58c73ea --- /dev/null +++ b/docs/api_examples/line_plot.py @@ -0,0 +1,194 @@ +# --- +# jupyter: +# jupytext: +# text_representation: +# extension: .py +# format_name: percent +# format_version: '1.3' +# jupytext_version: 1.17.2 +# kernelspec: +# display_name: vuecore-dev +# language: python +# name: python3 +# --- + +# %% [markdown] +# # Line Plot +# +# ![VueCore logo][vuecore_logo] +# +# [![Open In Colab][colab_badge]][colab_link] +# +# [VueCore][vuecore_repo] is a Python package for creating interactive and static visualizations of multi-omics data. +# It is part of a broader ecosystem of tools—including [ACore][acore_repo] for data processing and [VueGen][vuegen_repo] for automated reporting—that together enable end-to-end workflows for omics analysis. +# +# This notebook demonstrates how to generate line plots using plotting functions from VueCore. We showcase basic and +# advanced plot configurations, highlighting key customization options such as grouping, color mapping, text annotations, and export to multiple file formats. +# +# ## Notebook structure +# +# First, we will set up the work environment by installing the necessary packages and importing the required libraries. Next, we will create basic and advanced line plots. +# +# 0. [Work environment setup](#0-work-environment-setup) +# 1. [Basic line plot](#1-basic-line-plot) +# 2. [Advanced line plot](#2-advanced-line-plot) +# +# ## Credits and Contributors +# - This notebook was created by Sebastián Ayala-Ruano under the supervision of Henry Webel and Alberto Santos, head of the [Multiomics Network Analytics Group (MoNA)][Mona] at the [Novo Nordisk Foundation Center for Biosustainability (DTU Biosustain)][Biosustain]. +# - You can find more details about the project in this [GitHub repository][vuecore_repo]. +# +# [colab_badge]: https://colab.research.google.com/assets/colab-badge.svg +# [colab_link]: https://colab.research.google.com/github/Multiomics-Analytics-Group/vuecore/blob/main/docs/api_examples/line_plot.ipynb +# [vuecore_logo]: https://raw.githubusercontent.com/Multiomics-Analytics-Group/vuecore/main/docs/images/logo/vuecore_logo.svg +# [Mona]: https://multiomics-analytics-group.github.io/ +# [Biosustain]: https://www.biosustain.dtu.dk/ +# [vuecore_repo]: https://github.com/Multiomics-Analytics-Group/vuecore +# [vuegen_repo]: https://github.com/Multiomics-Analytics-Group/vuegen +# [acore_repo]: https://github.com/Multiomics-Analytics-Group/acore + +# %% [markdown] +# ## 0. Work environment setup + +# %% [markdown] +# ### 0.1. Installing libraries and creating global variables for platform and working directory +# +# To run this notebook locally, you should create a virtual environment with the required libraries. If you are running this notebook on Google Colab, everything should be set. + +# %% tags=["hide-output"] +# VueCore library +# %pip install vuecore + +# %% tags=["hide-cell"] +import os + +IN_COLAB = "COLAB_GPU" in os.environ + +# %% tags=["hide-cell"] +# Create a directory for outputs +output_dir = "./outputs" +os.makedirs(output_dir, exist_ok=True) + +# %% [markdown] +# ### 0.2. Importing libraries + +# %% +# Imports +import pandas as pd +import plotly.io as pio + +from vuecore.plots.basic.line import create_line_plot + +# Set the Plotly renderer based on the environment +pio.renderers.default = "notebook" + +# %% [markdown] +# ### 0.3. Create sample data +# We create a synthetic dataset showing measurements over five days for two experiments (A, B), each tested under Control and Treatment conditions, with associated measurement errors. + +# %% +sample_df = pd.DataFrame( + { + "day": list(range(1, 6)) * 4, # 5 days + "experiment": ["A"] * 10 + ["B"] * 10, # 2 experiments + "condition": (["Control"] * 5 + ["Treatment"] * 5) * 2, # 2 conditions + "value": [ + 11, + 13, + 15, + 17, + 18, # A - Control + 10, + 12, + 14, + 15, + 16, # A - Treatment + 19, + 20, + 21, + 22, + 23, # B - Control + 20, + 22, + 21, + 23, + 22, # B - Treatment + ], + "value_error": [ + 1, + 1.2, + 0.9, + 1.1, + 1.0, + 1.3, + 1.0, + 1.2, + 1.4, + 1.1, + 2.0, + 1.8, + 2.1, + 1.5, + 2.3, + 1.7, + 2.0, + 1.8, + 2.1, + 2.2, + ], + } +) + +sample_df.head() + +# %% [markdown] +# ## 1. Basic Line Plot +# A basic line plot can be created by simply providing the `x`, `y`, and `color` columns from the DataFrame. + +# %% +# Define output path +file_path_basic_png = os.path.join(output_dir, "line_plot_basic.png") + +# Generate basic plot +fig = create_line_plot( + data=sample_df, + x="day", + y="value", + color="experiment", + line_dash="condition", + file_path=file_path_basic_png, +) + +fig.show() + +# %% [markdown] +# ## 2. Advanced Line Plot +# Here is an example of an advanced line plot with more descriptive parameters, including error bars, line styles, markers, and custom colors. + +# %% +# Define output path +file_path_adv_html = os.path.join(output_dir, "line_plot_advanced.html") + +# Generate advanced plot +fig_advanced = create_line_plot( + data=sample_df, + x="day", + y="value", + color="experiment", + line_dash="condition", + error_y="value_error", + title="Experiment & Condition Trends", + subtitle="Measurements over 5 days for two experiments (A, B) under Control and Treatment conditions.", + labels={ + "day": "Day", + "value": "Response", + "condition": "Condition", + "experiment": "Experiment", + }, + color_discrete_map={"A": "#508AA8", "B": "#A8505E"}, + line_dash_map={"Control": "solid", "Treatment": "dot"}, + markers=True, + line_shape="spline", + file_path=file_path_adv_html, +) + +fig_advanced.show() diff --git a/docs/index.md b/docs/index.md index 6b7fa9b..43f1efd 100644 --- a/docs/index.md +++ b/docs/index.md @@ -12,6 +12,7 @@ :caption: API Usage Examples api_examples/scatter_plot +api_examples/line_plot ``` ```{toctree} diff --git a/src/vuecore/engines/plotly/__init__.py b/src/vuecore/engines/plotly/__init__.py index da8e945..11d844c 100644 --- a/src/vuecore/engines/plotly/__init__.py +++ b/src/vuecore/engines/plotly/__init__.py @@ -2,10 +2,13 @@ from vuecore import PlotType, EngineType from .scatter import build as build_scatter +from .line import build as build_line from .saver import save # Register the functions with the central dispatcher register_builder( plot_type=PlotType.SCATTER, engine=EngineType.PLOTLY, func=build_scatter ) +register_builder(plot_type=PlotType.LINE, engine=EngineType.PLOTLY, func=build_line) + register_saver(engine=EngineType.PLOTLY, func=save) diff --git a/src/vuecore/engines/plotly/line.py b/src/vuecore/engines/plotly/line.py new file mode 100644 index 0000000..029d263 --- /dev/null +++ b/src/vuecore/engines/plotly/line.py @@ -0,0 +1,67 @@ +# vuecore/engines/plotly/line.py + +import pandas as pd +import plotly.express as px +import plotly.graph_objects as go + +from vuecore.schemas.basic.line import LineConfig +from .theming import apply_line_theme + + +def build(data: pd.DataFrame, config: LineConfig) -> go.Figure: + """ + Creates a Plotly line plot figure from a DataFrame and a Pydantic configuration. + + This function acts as a bridge between the abstract plot definition and the + Plotly Express implementation. It translates the validated `LineConfig` + into the arguments for `plotly.express.line` and also forwards any + additional, unvalidated keyword arguments form plotly. The resulting figure + is then customized with layout and theme settings using `plotly.graph_objects`. + (https://plotly.com/python-api-reference/generated/plotly.express.line.html). + + Parameters + ---------- + data : pd.DataFrame + The DataFrame containing the plot data. + config : LineConfig + The validated Pydantic model with all plot configurations. + + Returns + ------- + go.Figure + A `plotly.graph_objects.Figure` object representing the line plot. + """ + # Get all parameters from the config model, including extras + all_config_params = config.model_dump() + + # Define parameters handled by the theme script + theming_params = [ + "markers", + "log_x", + "log_y", + "range_x", + "range_y", + "line_shape", + "title", + "x_title", + "y_title", + "subtitle", + "template", + "width", + "height", + ] + + # Create the dictionary of arguments for px.line + plot_args = { + k: v + for k, v in all_config_params.items() + if k not in theming_params and v is not None + } + + # Create the base figure using only the arguments for px.line + fig = px.line(data, **plot_args) + + # Apply theme and additional styling + fig = apply_line_theme(fig, config) + + return fig diff --git a/src/vuecore/engines/plotly/theming.py b/src/vuecore/engines/plotly/theming.py index 86a0f8c..b389836 100644 --- a/src/vuecore/engines/plotly/theming.py +++ b/src/vuecore/engines/plotly/theming.py @@ -1,6 +1,7 @@ import plotly.graph_objects as go from vuecore.schemas.basic.scatter import ScatterConfig +from vuecore.schemas.basic.line import LineConfig def apply_scatter_theme(fig: go.Figure, config: ScatterConfig) -> go.Figure: @@ -42,3 +43,55 @@ def apply_scatter_theme(fig: go.Figure, config: ScatterConfig) -> go.Figure: hovermode="closest", ) return fig + + +def apply_line_theme(fig: go.Figure, config: LineConfig) -> go.Figure: + """ + Applies a consistent layout and theme to a Plotly line plot. + + This function handles all styling and layout adjustments, such as titles, + dimensions, templates, and trace properties, separating these concerns + from the initial data mapping. + + Parameters + ---------- + fig : go.Figure + The Plotly figure object to be styled. + config : LineConfig + The configuration object containing all styling and layout info. + + Returns + ------- + go.Figure + The styled Plotly figure object. + """ + # Apply trace-specific updates + fig.update_traces( + mode="lines+markers" if config.markers else "lines", + line_shape=config.line_shape, + ) + + # Use the labels dictionary to set axis titles, falling back to defaults + x_title = config.x_title or ( + config.labels.get(config.x) if config.labels else None or config.x.title() + ) + y_title = config.y_title or ( + config.labels.get(config.y) if config.labels else None or config.y.title() + ) + + # Apply layout updates + fig.update_layout( + title_text=config.title, + title_subtitle_text=config.subtitle, + xaxis_title=x_title, + yaxis_title=y_title, + height=config.height, + width=config.width, + template=config.template, + xaxis_type="log" if config.log_x else "linear", + yaxis_type="log" if config.log_y else "linear", + xaxis_range=config.range_x, + yaxis_range=config.range_y, + hovermode="x unified", + ) + return fig diff --git a/src/vuecore/plots/basic/line.py b/src/vuecore/plots/basic/line.py new file mode 100644 index 0000000..d049eb2 --- /dev/null +++ b/src/vuecore/plots/basic/line.py @@ -0,0 +1,72 @@ +from typing import Any + +import pandas as pd + +from vuecore import EngineType +from vuecore.engines import get_builder, get_saver +from vuecore.schemas.basic.line import LineConfig + + +def create_line_plot( + data: pd.DataFrame, + engine: EngineType = EngineType.PLOTLY, + file_path: str = None, + **kwargs, +) -> Any: + """ + Creates, styles, and optionally saves a line plot using the specified engine. + + Parameters + ---------- + data : pd.DataFrame + The DataFrame containing the data to be plotted. + engine : EngineType, optional + The plotting engine to use for rendering the plot. Defaults to `EngineType.PLOTLY`. + file_path : str, optional + If provided, the path where the final plot will be saved. The file format + is automatically inferred from the file extension (e.g., '.html', '.png'). + By default None. + **kwargs + Keyword arguments for plot configuration. These are validated against + the `LineConfig` model. See `vuecore.schemas.basic.line.LineConfig` + for all available options. + + Returns + ------- + Any + The final plot object returned by the selected engine. + For Plotly, this will be a `plotly.graph_objects.Figure`. + For Matplotlib, a `matplotlib.figure.Figure`, etc. + + Raises + ------ + pydantic.ValidationError + If the provided keyword arguments do not conform to the `LineConfig` schema, + e.g., a required parameter is missing or a value has an incorrect type. + ValueError + Raised by the plotting engine if a column specified in the + configuration is not found in the provided DataFrame. + + Examples + -------- + For detailed examples and usage, please refer to the documentation: + + * **Jupyter Notebook:** `docs/api_examples/line_plot.ipynb` - + https://vuecore.readthedocs.io/en/latest/api_examples/scatter_plot.html + * **Python Script:** `docs/api_examples/line_plot.py` + """ + # 1. Validate configuration using Pydantic + config = LineConfig(**kwargs) + + # 2. Get the correct builder function from the registry + builder_func = get_builder(plot_type="line", engine=engine) + + # 3. Build the figure object (the API doesn't know or care what type it is) + figure = builder_func(data, config) + + # 4. Save the plot using the correct saver + if file_path: + saver_func = get_saver(engine=engine) + saver_func(figure, file_path) + + return figure diff --git a/src/vuecore/schemas/basic/line.py b/src/vuecore/schemas/basic/line.py new file mode 100644 index 0000000..02940f6 --- /dev/null +++ b/src/vuecore/schemas/basic/line.py @@ -0,0 +1,150 @@ +from typing import Dict, List, Optional +from pydantic import BaseModel, Field, ConfigDict + + +class LineConfig(BaseModel): + """ + Pydantic model for validating and managing line plot configurations. + + This model serves as a curated API for the most relevant parameters + for line plots, closely aligned with the `plotly.express.line` API + (https://plotly.com/python-api-reference/generated/plotly.express.line.html). + + This model includes the most relevant parameters for data mapping, styling, + and layout. It ensures that user-provided configurations are type-safe and + adhere to the expected structure. The plotting function handles parameters + defined here, and also accepts additional Plotly keyword arguments, + forwarding them to the appropriate `plotly.express.line` or + `plotly.graph_objects.Figure` call. + + Attributes + ---------- + -----Data Mapping----- + x : str + Column for the x-axis values. + y : str + Column for the y-axis values. + line_group : Optional[str] + Column to group data into separate lines. + color : Optional[str] + Column to assign color to lines. Replaces 'group'. + line_dash : Optional[str] + Column to assign dash styles to lines. + symbol : Optional[str] + Column to assign symbols to markers. + hover_name : Optional[str] + Column to appear in bold in the hover tooltip. + hover_data : Optional[List[str]] + Additional columns to display in the hover tooltip. + text : Optional[str] + Column for adding text labels to markers. + facet_row : Optional[str] + Column to create vertical subplots (facets). + facet_col : Optional[str] + Column to create horizontal subplots (facets). + error_x : Optional[str] + Column for sizing x-axis error bars. + error_y : Optional[str] + Column for sizing y-axis error bars. + labels : Optional[Dict[str, str]] + Dictionary to override column names for titles, legends, etc. + color_discrete_map : Optional[Dict[str, str]] + Specific color mappings for values in the `color` column. + line_dash_map : Optional[Dict[str, str]] + Specific dash style mappings for values in the `line_dash` column. + symbol_map : Optional[Dict[str, str]] + Specific symbol mappings for values in the `symbol` column. + -----Styling and Layout----- + markers : bool + If True, markers are drawn on the lines. + log_x : bool + If True, the x-axis is log-scaled. + log_y : bool + If True, the y-axis is log-scaled. + range_x : Optional[List[float]] + Range for the x-axis, e.g., [0, 100]. + range_y : Optional[List[float]] + Range for the y-axis, e.g., [0, 100]. + line_shape : Optional[str] + Determines the line shape ('linear', 'spline', 'hv', etc.). + title : str + The main title of the plot. + x_title : Optional[str] + Custom title for the x-axis. + y_title : Optional[str] + Custom title for the y-axis. + subtitle : str + The subtitle of the plot. + template : str + Plotly template for styling (e.g., 'plotly_white'). + width : int + Width of the plot in pixels. + height : int + Height of the plot in pixels. + """ + + # General Configuration + # Allow extra parameters to pass through to Plotly + model_config = ConfigDict(extra="allow") + + # Data Mapping + x: str = Field(..., description="Column for x-axis values.") + y: str = Field(..., description="Column for y-axis values.") + line_group: Optional[str] = Field( + None, description="Column to group data into separate lines." + ) + color: Optional[str] = Field(None, description="Column to assign color to lines.") + line_dash: Optional[str] = Field( + None, description="Column to assign dash styles to lines." + ) + symbol: Optional[str] = Field( + None, description="Column to assign symbols to markers." + ) + hover_name: Optional[str] = Field( + None, description="Column for bold text in hover tooltip." + ) + hover_data: List[str] = Field( + [], description="Additional columns for the hover tooltip." + ) + text: Optional[str] = Field(None, description="Column for text labels on markers.") + facet_row: Optional[str] = Field( + None, description="Column to create vertical subplots." + ) + facet_col: Optional[str] = Field( + None, description="Column to create horizontal subplots." + ) + error_x: Optional[str] = Field(None, description="Column for x-axis error bars.") + error_y: Optional[str] = Field(None, description="Column for y-axis error bars.") + labels: Optional[Dict[str, str]] = Field( + None, description="Override column names in the plot." + ) + color_discrete_map: Optional[Dict[str, str]] = Field( + None, description="Map values to specific colors." + ) + line_dash_map: Optional[Dict[str, str]] = Field( + None, description="Map values to specific dash styles." + ) + symbol_map: Optional[Dict[str, str]] = Field( + None, description="Map values to specific symbols." + ) + + # Styling and Layout + markers: bool = Field(False, description="If True, displays markers on the lines.") + log_x: bool = Field(False, description="If True, use a logarithmic x-axis.") + log_y: bool = Field(False, description="If True, use a logarithmic y-axis.") + range_x: Optional[List[float]] = Field( + None, description="Range for the x-axis, e.g., [0, 100]." + ) + range_y: Optional[List[float]] = Field( + None, description="Range for the y-axis, e.g., [0, 100]." + ) + line_shape: Optional[str] = Field( + "linear", description="Line shape (e.g., 'linear', 'spline')." + ) + title: str = Field("Line Plot", description="The main title of the plot.") + x_title: Optional[str] = Field(None, description="Custom title for the x-axis.") + y_title: Optional[str] = Field(None, description="Custom title for the y-axis.") + subtitle: Optional[str] = Field(None, description="The subtitle for the plot.") + template: str = Field("plotly_white", description="Plotly template for styling.") + width: int = Field(800, description="Width of the plot in pixels.") + height: int = Field(600, description="Height of the plot in pixels.") diff --git a/src/vuecore/schemas/distribution/__init__.py b/src/vuecore/schemas/distribution/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests/test_lineplot.py b/tests/test_lineplot.py new file mode 100644 index 0000000..cd1de4c --- /dev/null +++ b/tests/test_lineplot.py @@ -0,0 +1,105 @@ +import pandas as pd +import pytest +from vuecore.plots.basic.line import create_line_plot + + +@pytest.fixture +def sample_line_df(): + """Fixture for generating sample data for a line plot.""" + data = pd.DataFrame( + { + "day": list(range(1, 6)) * 4, # 5 days + "experiment": ["A"] * 10 + ["B"] * 10, # 2 experiments + "condition": (["Control"] * 5 + ["Treatment"] * 5) * 2, # 2 conditions + "value": [ + 11, + 13, + 15, + 17, + 18, # A - Control + 10, + 12, + 14, + 15, + 16, # A - Treatment + 19, + 20, + 21, + 22, + 23, # B - Control + 20, + 22, + 21, + 23, + 22, # B - Treatment + ], + "value_error": [ + 1, + 1.2, + 0.9, + 1.1, + 1.0, + 1.3, + 1.0, + 1.2, + 1.4, + 1.1, + 2.0, + 1.8, + 2.1, + 1.5, + 2.3, + 1.7, + 2.0, + 1.8, + 2.1, + 2.2, + ], + } + ) + return pd.DataFrame(data) + + +@pytest.mark.parametrize("ext", ["png", "svg", "html", "json"]) +def test_basic_line_plot(sample_line_df, tmp_path, ext): + """Test basic line plot creation with direct color mapping.""" + output_path = tmp_path / f"line_test.{ext}" + + fig = create_line_plot( + data=sample_line_df, + x="day", + y="value", + color="experiment", + line_dash="condition", + file_path=str(output_path), + ) + + assert fig is not None + assert output_path.exists() + assert output_path.stat().st_size > 0 + + +@pytest.mark.parametrize("ext", ["png", "svg", "html", "json"]) +def test_advanced_line_plot_refactored(sample_line_df, tmp_path, ext): + """Test advanced line plot with new, more descriptive parameters.""" + output_path = tmp_path / f"line_test_advanced.{ext}" + + fig = create_line_plot( + data=sample_line_df, + x="day", + y="value", + color="experiment", + line_dash="condition", + error_y="value_error", + title="Experiment & Condition Trends", + labels={"day": "Day", "value": "Response", "condition": "Condition"}, + color_discrete_map={"A": "#508AA8", "B": "#A8505E"}, + line_dash_map={"Control": "solid", "Treatment": "dot"}, + markers=True, + line_shape="spline", + file_path=str(output_path), + ) + + assert fig is not None + assert output_path.exists() + assert output_path.stat().st_size > 0 diff --git a/tests/test_scatter.py b/tests/test_scatter.py index e7a0114..f34763b 100644 --- a/tests/test_scatter.py +++ b/tests/test_scatter.py @@ -1,6 +1,6 @@ import pandas as pd import pytest -from vuecore.plots.distribution.scatter import create_scatter_plot +from vuecore.plots.basic.scatter import create_scatter_plot @pytest.fixture