Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4,318 changes: 4,318 additions & 0 deletions docs/api_examples/histogram_plot.ipynb

Large diffs are not rendered by default.

162 changes: 162 additions & 0 deletions docs/api_examples/histogram_plot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
# ---
# 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]
# # Histogram 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 histogram 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 histogram plots.
#
# 0. [Work environment setup](#0-work-environment-setup)
# 1. [Basic histogram plot](#1-basic-histogram-plot)
# 2. [Advanced histogram plot](#2-advanced-histogram-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/bar_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 numpy as np
from pathlib import Path
import plotly.io as pio

from vuecore.plots.basic.histogram import create_histogram_plot

# Set the Plotly renderer based on the environment
pio.renderers.default = "notebook"

# %% [markdown]
# ### 0.3. Create sample data
# We create a synthetic dataset simulating gene expression data across two experimental conditions to demonstrate how histograms can visualize data distribution.

# %%
# Set a random seed for reproducibility of the synthetic data
np.random.seed(42)

# Define parameters for synthetic gene expression data
num_genes = 1000
conditions = ["Control", "Treated"]
gene_names = [f"Gene_{i}" for i in range(num_genes)]

# Simulate expression data with a slight shift in the "Treated" group
expression_values = np.concatenate(
[
np.random.normal(loc=10, scale=2, size=num_genes // 2),
np.random.normal(loc=12, scale=2, size=num_genes // 2),
]
)
condition_values = np.concatenate(
[["Control"] * (num_genes // 2), ["Treated"] * (num_genes // 2)]
)

# Create the DataFrame
gene_exp_df = pd.DataFrame(
{
"Gene_ID": gene_names,
"Expression": expression_values,
"Condition": condition_values,
}
)

gene_exp_df.head()

# %% [markdown]
# ## 1. Basic Histogram Plot
# A basic histogram plot can be created by simply providing the `x` and `y` columns from the DataFrame, along with style options like `title`.

# %%
# Define output file path for the PNG basic histogram
file_path_basic_hist_png = Path(output_dir) / "histogram_plot_basic.png"

# Generate the basic histogram plot
histogram_plot_basic = create_histogram_plot(
data=gene_exp_df,
x="Expression",
title="Distribution of Gene Expression Levels",
file_path=file_path_basic_hist_png,
)

histogram_plot_basic.show()

# %% [markdown]
# ## 2. Advanced Histogram Plot
# Here is an example of an advanced histogram plot with more descriptive parameters, including `color grouping`, `overlay barmode`, `probability density normalization`, `hover tooltips`, and export to `HTML`.

# %%
# Define the output file path for the advanced HTML histogram
file_path_adv_hist_html = Path(output_dir) / "histogram_plot_advanced.html"

# Generate the advanced histogram plot
histogram_plot_adv = create_histogram_plot(
data=gene_exp_df,
x="Expression",
color="Condition",
barmode="overlay",
histnorm="probability density",
title="Gene Expression Distribution by Treatment Condition",
subtitle="Histogram with probability density normalized",
labels={"Expression": "Gene Expression", "Condition": "Treatment Condition"},
hover_data=["Gene_ID"],
opacity=0.75,
file_path=file_path_adv_hist_html,
)

histogram_plot_adv.show()
1 change: 1 addition & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ api_examples/scatter_plot
api_examples/line_plot
api_examples/bar_plot
api_examples/box_violin_plot
api_examples/histogram_plot
```

```{toctree}
Expand Down
1 change: 1 addition & 0 deletions src/vuecore/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class PlotType(StrEnum):
BAR = auto()
BOX = auto()
VIOLIN = auto()
HISTOGRAM = auto()


class EngineType(StrEnum):
Expand Down
4 changes: 4 additions & 0 deletions src/vuecore/engines/plotly/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from .bar import build as build_bar
from .box import build as build_box
from .violin import build as build_violin
from .histogram import build as build_histogram
from .saver import save

# Import build_utils to ensure it's available
Expand All @@ -19,5 +20,8 @@
register_builder(plot_type=PlotType.BAR, engine=EngineType.PLOTLY, func=build_bar)
register_builder(plot_type=PlotType.BOX, engine=EngineType.PLOTLY, func=build_box)
register_builder(plot_type=PlotType.VIOLIN, engine=EngineType.PLOTLY, func=build_violin)
register_builder(
plot_type=PlotType.HISTOGRAM, engine=EngineType.PLOTLY, func=build_histogram
)

register_saver(engine=EngineType.PLOTLY, func=save)
58 changes: 58 additions & 0 deletions src/vuecore/engines/plotly/histogram.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go

from vuecore.schemas.basic.histogram import HistogramConfig
from .theming import apply_histogram_theme
from .plot_builder import build_plot

# Define parameters handled by the theme script
THEMING_PARAMS = [
"opacity",
"barmode",
"barnorm",
"histnorm",
"log_x",
"log_y",
"range_x",
"range_y",
"title",
"x_title",
"y_title",
"subtitle",
"template",
"width",
"height",
]


def build(data: pd.DataFrame, config: HistogramConfig) -> go.Figure:
"""
Creates a Plotly histogram 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 `HistogramConfig`
into the arguments for `plotly.express.histogram` and also forwards any
additional, unvalidated keyword arguments from 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.histogram.html).

Parameters
----------
data : pd.DataFrame
The DataFrame containing the plot data.
config : HistogramConfig
The validated Pydantic model with all plot configurations.

Returns
-------
go.Figure
A `plotly.graph_objects.Figure` object representing the histogram.
"""
return build_plot(
data=data,
config=config,
px_function=px.histogram,
theming_function=apply_histogram_theme,
theming_params=THEMING_PARAMS,
)
34 changes: 34 additions & 0 deletions src/vuecore/engines/plotly/theming.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from vuecore.schemas.basic.bar import BarConfig
from vuecore.schemas.basic.box import BoxConfig
from vuecore.schemas.basic.violin import ViolinConfig
from vuecore.schemas.basic.histogram import HistogramConfig


def _get_axis_title(config, axis: str) -> str:
Expand Down Expand Up @@ -246,3 +247,36 @@ def apply_violin_theme(fig: go.Figure, config: ViolinConfig) -> go.Figure:
fig = _apply_common_layout(fig, config)

return fig


def apply_histogram_theme(fig: go.Figure, config: HistogramConfig) -> go.Figure:
"""
Applies a consistent layout and theme to a Plotly histogram 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 : HistogramConfig
The configuration object containing all styling and layout info.

Returns
-------
go.Figure
The styled Plotly figure object.
"""
# Apply trace-specific updates for histogram
fig.update_traces(
opacity=config.opacity,
orientation=config.orientation,
selector=dict(type="histogram"),
)

# Apply common layout
fig = _apply_common_layout(fig, config)

return fig
4 changes: 4 additions & 0 deletions src/vuecore/plots/basic/__init__.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
# vuecore/plots/basic/__init__.py
from .bar import create_bar_plot
from .box import create_box_plot
from .histogram import create_histogram_plot
from .line import create_line_plot
from .scatter import create_scatter_plot
from .violin import create_violin_plot

__all__ = [
"create_bar_plot",
"create_box_plot",
"create_line_plot",
"create_scatter_plot",
"create_histogram_plot",
"create_violin_plot",
]
73 changes: 73 additions & 0 deletions src/vuecore/plots/basic/histogram.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
from typing import Any

import pandas as pd

from vuecore import EngineType, PlotType
from vuecore.schemas.basic.histogram import HistogramConfig
from vuecore.plots.plot_factory import create_plot
from vuecore.utils.docs_utils import document_pydant_params


@document_pydant_params(HistogramConfig)
def create_histogram_plot(
data: pd.DataFrame,
engine: EngineType = EngineType.PLOTLY,
file_path: str = None,
**kwargs,
) -> Any:
"""
Creates, styles, and optionally saves a histogram using the specified engine.

This function serves as the main entry point for users to generate histograms.
It validates the provided configuration against the `HistogramConfig` schema,
retrieves the appropriate plotting builder and saver functions based on the
selected engine, builds the plot, and optionally saves it to a file.

Parameters
----------
data : pd.DataFrame
The DataFrame containing the data to be plotted. Each row represents
an observation, and columns correspond to variables.
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', '.jpeg', '.svg'). Defaults to None, meaning
the plot will not be saved.

Returns
-------
Any
The final plot object returned by the selected engine.
For Plotly, this will typically be a `plotly.graph_objects.Figure`.
The exact type depends on the chosen engine.

Raises
------
pydantic.ValidationError
If the provided keyword arguments do not conform to the `HistogramConfig` schema.
e.g., a required parameter is missing or a value has an incorrect type.
ValueError
Raised by the plotting engine (e.g., Plotly Express) if a
column specified in the configuration (e.g., 'x', 'y', 'color') is
not found in the provided DataFrame.

Examples
--------
For detailed examples and usage, please refer to the documentation:

* **Jupyter Notebook:** `docs/api_examples/histogram_plot.ipynb` -
https://vuecore.readthedocs.io/en/latest/api_examples/histogram_plot.html
* **Python Script:** `docs/api_examples/histogram_plot.py` -
https://github.com/Multiomics-Analytics-Group/vuecore/blob/main/docs/api_examples/histogram_plot.py
"""
return create_plot(
data=data,
config=HistogramConfig,
plot_type=PlotType.HISTOGRAM,
engine=engine,
file_path=file_path,
**kwargs,
)
Loading