Skip to content

feat: support facet plot in py-maidr using maidr-ts #148

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 24 commits into from
Apr 29, 2025
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
748d99d
feat: support multilayer plot using maidr-ts
dakshpokar Mar 12, 2025
9f0d6ac
fix: support js engine without panel and layer based maidr data
dakshpokar Mar 12, 2025
36f51fc
fix: rename 'panels' to 'subplots' for consistency with maidr-ts
dakshpokar Mar 12, 2025
9770c1e
fix: address co-pilot comments and add jupyter notebook example for m…
dakshpokar Mar 12, 2025
d3d734e
fix: update MAIDR_TS_CDN_URL to use the production CDN instead of the…
dakshpokar Mar 12, 2025
e003c21
feat: support multipanel plots in pymaidr using maidr-ts
dakshpokar Mar 14, 2025
8cf6a56
fix: correct title typo in bar plot example and update MAIDR_TS_CDN_U…
dakshpokar Mar 14, 2025
47801cb
fix: co-pilot suggestions
dakshpokar Mar 14, 2025
9c059b0
feat: support facet plot
dakshpokar Mar 15, 2025
133e814
feat: add examples for facet plots with bar and line charts
dakshpokar Mar 15, 2025
3a730df
fix: shared xlabel extraction
dakshpokar Mar 15, 2025
b74fa88
feat: add examples for facet plots with bar and line charts
dakshpokar Mar 15, 2025
a588936
feat: add examples for facet plots with bar and line charts using mat…
dakshpokar Mar 15, 2025
eb0374a
fix: update seaborn example
dakshpokar Mar 15, 2025
06551a3
Merge branch 'main' into feat/facet-plot
dakshpokar Apr 10, 2025
ec23e98
Merge branch 'main' into feat/facet-plot
dakshpokar Apr 17, 2025
034e00e
Merge branch 'main' into feat/facet-plot
dakshpokar Apr 17, 2025
ae3264b
Merge branch 'main' into feat/facet-plot
dakshpokar Apr 17, 2025
59cf3cc
Merge remote-tracking branch 'origin/main' into feat/facet-plot
dakshpokar Apr 21, 2025
ab566a4
fix: support seaborn FacetGrid
dakshpokar Apr 21, 2025
64bf96a
fix: correct level check logic in BarPlot data extraction
dakshpokar Apr 22, 2025
36ab63c
Merge remote-tracking branch 'origin/main' into feat/facet-plot
dakshpokar Apr 28, 2025
676a272
docs: add facet plot example to quarto documentation
dakshpokar Apr 29, 2025
252fb0d
feat: add facet plot example to documentation
dakshpokar Apr 29, 2025
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
64 changes: 64 additions & 0 deletions example/facet-subplots/matplotlib/example_mpl_facet_bar_plot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#!/usr/bin/env python3
"""
Example of creating a facet plot with matplotlib.

This script demonstrates how to create a figure with multiple panels
containing bar plots that share the same axes, creating a facet plot.
Each panel represents data for a different category or condition.
"""


import matplotlib.pyplot as plt
import numpy as np

import maidr

maidr.set_engine("ts")

categories = ["A", "B", "C", "D", "E"]

np.random.seed(42)
data_group1 = np.random.rand(5) * 10
data_group2 = np.random.rand(5) * 100
data_group3 = np.random.rand(5) * 36
data_group4 = np.random.rand(5) * 42

data_sets = [data_group1, data_group2, data_group3, data_group4]
condition_names = ["Group 1", "Group 2", "Group 3", "Group 4"]

fig, axs = plt.subplots(2, 2, figsize=(12, 10), sharey=True, sharex=True)
axs = axs.flatten()

all_data = np.concatenate(data_sets)
y_min, y_max = np.min(all_data) * 0.9, np.max(all_data) * 1.1

# Create a bar plot in each subplot
for i, (data, condition) in enumerate(zip(data_sets, condition_names)):
axs[i].bar(categories, data, color=f"C{i}", alpha=0.7)
axs[i].set_title(f"{condition}")
axs[i].set_ylim(y_min, y_max) # Set consistent y-axis limits

# Add value labels on top of each bar
for j, value in enumerate(data):
axs[i].text(
j,
value + (y_max - y_min) * 0.02,
f"{value:.1f}",
ha="center",
va="bottom",
fontsize=9,
)

# Add common labels
fig.text(0.5, 0.04, "Categories", ha="center", va="center", fontsize=14)
fig.text(
0.06, 0.5, "Values", ha="center", va="center", rotation="vertical", fontsize=14
)

# Add a common title
fig.suptitle("Facet Plot: Bar Charts by Condition", fontsize=16)

# Adjust layout
plt.tight_layout(rect=(0.08, 0.08, 0.98, 0.95))

maidr.show(fig)
121 changes: 121 additions & 0 deletions example/facet-subplots/matplotlib/example_mpl_facet_combined_plot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Example of creating a facet plot with matplotlib that has shared axes.
One column contains line plots and another contains bar plots.
"""

from typing import List, Tuple

import matplotlib.pyplot as plt
import numpy as np

import maidr

maidr.set_engine("ts")


def generate_simple_data(
num_rows: int = 3, num_points: int = 5
) -> Tuple[np.ndarray, List[np.ndarray], List[np.ndarray]]:
"""
Generate simple data for line and bar plots.

Parameters
----------
num_rows : int, optional
Number of rows (facets) to generate data for, by default 3
num_points : int, optional
Number of data points per plot, by default 5

Returns
-------
Tuple[np.ndarray, List[np.ndarray], List[np.ndarray]]
A tuple containing:
- x values common for all plots
- list of y values for line plots
- list of y values for bar plots

Examples
--------
>>> x, line_data, bar_data = generate_simple_data(2, 5)
>>> len(line_data)
2
"""
# Generate x values common to both plot types
x = np.arange(num_points)

# Generate line plot data with different linear trends
line_data = []
for i in range(num_rows):
# Create a simple linear trend with different slopes
y = np.random.rand(5) * 10
line_data.append(y)

# Generate bar plot data with different patterns
bar_data = []
for i in range(num_rows):
# Create simple bar heights
y = np.abs(np.sin(x + i) * 5) + i
bar_data.append(y)

return x, line_data, bar_data


def create_facet_plot(
x: np.ndarray, line_data: List[np.ndarray], bar_data: List[np.ndarray]
) -> Tuple[plt.Figure, np.ndarray]: # type: ignore
"""
Create a facet plot with one column of line plots and one column of bar plots.

Parameters
----------
x : np.ndarray
The x-values for all plots
line_data : List[np.ndarray]
List of y-values for the line plots, one array per row
bar_data : List[np.ndarray]
List of y-values for the bar plots, one array per row

Returns
-------
Tuple[plt.Figure, np.ndarray]
The figure and axes objects
"""
num_rows = len(line_data)

# Create a figure with a 2-column grid of subplots
fig, axs = plt.subplots(num_rows, 2, figsize=(10, 3 * num_rows), sharey="row")

# Loop through each row to create the facet plots
for row in range(num_rows):
# Left column: line plot
axs[row, 0].plot(x, line_data[row], "o-", linewidth=2, color=f"C{row}")
axs[row, 0].set_title(f"Line Plot {row+1}")

# Right column: bar plot
axs[row, 1].bar(x, bar_data[row], color=f"C{row}", alpha=0.7)
axs[row, 1].set_title(f"Bar Plot {row+1}")

# Add a y-axis label only on the left column
axs[row, 0].set_ylabel(f"Values (Row {row+1})")

# Add x-labels to the bottom row only
for col in range(2):
axs[-1, col].set_xlabel("X Values")

# Add a global title
fig.suptitle("Facet Plot Example with Shared Y-Axes", fontsize=16, y=0.98)

# Adjust spacing between subplots
plt.tight_layout()

return fig, axs


x, line_data, bar_data = generate_simple_data(num_rows=3)

# Create and display the facet plot
fig, axs = create_facet_plot(x, line_data, bar_data)

maidr.show(fig)
97 changes: 97 additions & 0 deletions example/facet-subplots/seaborn/example_sns_facet_bar_plot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
from typing import Any, Dict, List

import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns

import maidr

maidr.set_engine("ts")


def create_sample_data() -> pd.DataFrame:
"""
Create a simple sample DataFrame for facet bar plotting.

Returns
-------
pd.DataFrame
A DataFrame with product categories, regions, and sales data.

Examples
--------
>>> df = create_sample_data()
>>> df.head()
category region sales
0 Product1 North 25
1 Product1 South 18
2 Product1 East 30
3 Product1 West 22
4 Product2 North 15
"""
# Define data for our example
data: Dict[str, List[Any]] = {
"category": [
"Product1",
"Product1",
"Product1",
"Product1",
"Product2",
"Product2",
"Product2",
"Product2",
"Product3",
"Product3",
"Product3",
"Product3",
],
"region": ["North", "South", "East", "West"] * 3,
"sales": [25, 18, 30, 22, 15, 29, 10, 24, 32, 17, 22, 35],
}

return pd.DataFrame(data)


def create_facet_bar_plot(data: pd.DataFrame) -> None:
"""
Create a facet grid of bar plots with shared axis.

Parameters
----------
data : pd.DataFrame
The DataFrame containing the data to plot.

Examples
--------
>>> df = create_sample_data()
>>> create_facet_bar_plot(df)
"""
# Set the aesthetic style of the plots
sns.set_theme(style="whitegrid")

# Initialize the FacetGrid object with category as rows
# This will create a separate subplot for each product category
g = sns.FacetGrid(data, row="category", height=3, aspect=1.5, sharey=True)

# Map a barplot using region as x and sales as y
# This creates a bar plot for each category showing sales by region
g.map_dataframe(sns.barplot, x="region", y="sales", palette="viridis")

# Add titles and labels
g.set_axis_labels("Region", "Sales")
g.set_titles(row_template="{row_name}")

# Adjust the layout and add a title
plt.tight_layout()
plt.subplots_adjust(top=0.9)
g.figure.suptitle("Sales by Region for Different Products", fontsize=16)

# Show the plot
maidr.show(g.figure)


# Create sample data
df = create_sample_data()

# Create and display the facet bar plot
create_facet_bar_plot(df)
Loading