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
5 changes: 5 additions & 0 deletions .cursor/worktrees.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"setup-worktree": [
"make init"
]
}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# ============================================================================

docs/_static/charts/*.html
docs/_static/js/plotly.min.js
docs/api/autogen
docs/api/public

Expand Down
6 changes: 4 additions & 2 deletions MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,25 @@ include docs/Makefile
include docs/make.bat
include docs/robots.txt
include docs/_static/favicon.ico
exclude docs/_static/js/plotly.min.js
recursive-include docs *.md *.py *.rst
recursive-include docs/_static/charts *.webp
recursive-include docs/_static/css *.css
recursive-include docs/_static/img *.png *.webp *.svg *.gif *.jpg
recursive-include docs/_static/img *.png *.webp *.svg *.gif *.jpeg
recursive-include docs/_static/js *.js
recursive-include docs/_templates *.html
prune docs/_build
prune docs/api/autogen
prune docs/api/public

# Misc
recursive-include .cursor *.json
recursive-include .github *.yml *.yaml
recursive-include cicd_utils README.md *.py *.sh
recursive-include misc *.py *.ipynb *.txt *.png
recursive-include requirements *.txt
recursive-include tests *.py
recursive-include tests/e2e/artifacts *.jpeg *.json
recursive-include tests/e2e/artifacts *.json

# Globally excluded patterns
recursive-exclude * *.py[cod] *.egg-info __pycache__ .ipynb_checkpoints/*
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ clean-docs: ## remove documentation build artifacts
@echo "==> Removing documentation build artifacts..."
@rm -fr docs/_build/ docs/api/autogen/ docs/api/public/
@find . -wholename 'docs/_static/charts/*.html' -exec rm -fr {} +
@rm -f docs/_static/js/plotly.min.js


.PHONY: clean-build
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,13 @@ The full official documentation can be found at: https://ridgeplot.readthedocs.i

### Basic example

For those in a hurry, here's a very basic example on how to quickly get started with [ridgeplot()](https://ridgeplot.readthedocs.io/en/stable/api/public/ridgeplot.ridgeplot.html) function.
For those in a hurry, here's a very basic example on how to quickly get started with the [ridgeplot()](https://ridgeplot.readthedocs.io/en/stable/api/public/ridgeplot.ridgeplot.html) function.

```python
import numpy as np
from ridgeplot import ridgeplot

my_samples = [np.random.normal(n / 1.2, size=600) for n in range(7, 0, -1)]
my_samples = [np.random.normal(n, size=900) for n in range(6, 0, -2)]
fig = ridgeplot(samples=my_samples)
fig.show()
```
Expand Down
11 changes: 9 additions & 2 deletions cicd_utils/ridgeplot_examples/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,13 @@ class Example:

def __post_init__(self) -> None:
self.fig = self.figure_factory() # pyright: ignore[reportUninitializedInstanceVariable]

# Both `width` and `height` should be set in all example plots
if self.fig.layout.width != 800:
raise ValueError("All figures must have width 800")
if not isinstance(self.fig.layout.height, int):
raise ValueError("All figures must have an explicit height declared") # noqa: TRY004

round_fig_data(self.fig, sig_figs=8)

def to_json(self) -> str:
Expand All @@ -86,8 +93,6 @@ def write_json(self, path: Path) -> None:
def write_html(self, path: Path, minify_html: bool) -> None:
fig = deepcopy(self.fig)

if fig.layout.height is None:
raise ValueError("The Figure's layout.height value must be explicitly set.")
# Overriding the width to None results in a '100%' CSS width.
# This is achieved by setting the `default_width` parameter
# in `fig.to_html()` to "100%" (see below).
Expand Down Expand Up @@ -140,6 +145,8 @@ def write_webp(self, path: Path) -> None:
engine="kaleido",
)

# This method isn't used anywhere anymore but
# will be kept here for potential future use
def write_jpeg(self, path: Path) -> None:
fig = deepcopy(self.fig)
fig = tighten_margins(fig, px=40)
Expand Down
4 changes: 2 additions & 2 deletions cicd_utils/ridgeplot_examples/_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ def main() -> go.Figure:
from ridgeplot import ridgeplot

rng = np.random.default_rng(42)
my_samples = [rng.normal(n / 1.2, size=600) for n in range(6, 0, -1)]
my_samples = [rng.normal(n, size=900) for n in range(6, 0, -2)]
fig = ridgeplot(samples=my_samples)
fig.update_layout(height=350, width=800)
fig.update_layout(height=400, width=800)

return fig

Expand Down
6 changes: 3 additions & 3 deletions cicd_utils/ridgeplot_examples/_basic_hist.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ def main() -> go.Figure:
from ridgeplot import ridgeplot

rng = np.random.default_rng(42)
my_samples = [rng.normal(n / 1.2, size=600) for n in range(6, 0, -1)]
fig = ridgeplot(samples=my_samples, nbins=20)
fig.update_layout(height=350, width=800)
my_samples = [rng.normal(n, size=900) for n in range(6, 0, -2)]
fig = ridgeplot(samples=my_samples, nbins=18)
fig.update_layout(height=400, width=800)

return fig

Expand Down
2 changes: 1 addition & 1 deletion docs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,5 @@ livehtml:
--watch=../src/ridgeplot \
--re-ignore 'api/public/.*' \
--re-ignore '_static/charts/.*' \
--re-ignore '_static/js/plotly.min.js' \
--re-ignore '_static/js/plotly.*' \
"$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
Binary file modified docs/_static/charts/basic.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/_static/charts/basic_hist.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
44 changes: 42 additions & 2 deletions docs/_templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,46 @@
the `extrahead` Sphinx block, which is placed at the bottom of the head
section at the top of the page.
#}
<script src="https://cdn.plot.ly/plotly-3.0.0.min.js" charset="utf-8"></script>
<script>
(function () {
const CDN_URL = "https://cdn.plot.ly/plotly-3.3.0.min.js";
const LOCAL_URL = "{{ pathto('_static/js/plotly.min.js', 1) }}";

function loadScript(src) {
return new Promise((resolve, reject) => {
const el = document.createElement('script');
el.src = src;
el.onload = resolve;
el.onerror = reject;
document.head.appendChild(el);
});
}

const plotlyReady = loadScript(CDN_URL)
.then(() => console.info("Plotly loaded from CDN"))
.catch(() => {
return loadScript(LOCAL_URL).then(() => {
console.info("Plotly loaded from local fallback");
});
});

const domReady = new Promise(resolve => {
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', resolve);
} else {
resolve();
}
});

Promise.all([plotlyReady, domReady]).then(() => {
document.querySelectorAll('.plotly-graph-wrapper script').forEach(s => {
const fresh = document.createElement('script');
fresh.textContent = s.textContent;
document.body.appendChild(fresh);
});
}).catch(() => {
console.error("Failed to load Plotly from CDN and local fallback");
});
})();
</script>
{%- endblock extrahead %}
git
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -424,5 +424,5 @@ def wrapper(*args: Any, **kwargs: Any) -> None:


def setup(app: Sphinx) -> None:
# app.connect("builder-inited", dispatch(write_plotlyjs_bundle), priority=501)
app.connect("builder-inited", dispatch(write_plotlyjs_bundle), priority=501)
app.connect("builder-inited", dispatch(compile_all_plotly_charts), priority=502)
4 changes: 2 additions & 2 deletions docs/getting_started/getting_started.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ This basic example shows how you can quickly get started with a simple call to t
import numpy as np
from ridgeplot import ridgeplot

my_samples = [np.random.normal(n / 1.2, size=600) for n in range(6, 0, -1)]
my_samples = [np.random.normal(n, size=900) for n in range(6, 0, -2)]
fig = ridgeplot(samples=my_samples)
fig.show()
```
Expand Down Expand Up @@ -97,7 +97,7 @@ The resulting ridgeline plot generated by the code above:
:::
:::{tab-item} Target/reference image
The target reference from the [_from Data to Viz_ post](https://www.data-to-viz.com/graph/ridgeline.html):
![reference ridgeline plot of the probly dataset from data to viz](/_static/img/probly_original.jpg)
![reference ridgeline plot of the probly dataset from data to viz](/_static/img/probly_original.jpeg)
:::
::::

Expand Down
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ For those in a hurry, here's a very basic example on how to quickly get started
import numpy as np
from ridgeplot import ridgeplot

my_samples = [np.random.normal(n / 1.2, size=600) for n in range(6, 0, -1)]
my_samples = [np.random.normal(n, size=900) for n in range(6, 0, -2)]
fig = ridgeplot(samples=my_samples)
fig.show()
```
Expand Down
16 changes: 15 additions & 1 deletion docs/reference/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,22 @@ This document outlines the list of changes to ridgeplot between each release. Fo
Unreleased changes
------------------

## CI/CD
### Bug fixes

- Fix the way histogram bin centers are computed ({gh-pr}`364`)

### Documentation

- Update the basic examples throughout the docs ({gh-pr}`364`)
- Bundle a local copy of `plotly.min.js` as a CDN fallback ({gh-pr}`364`)

### Developer Experience

- Add a basic version of Cursor's `worktrees.json` config ({gh-pr}`364`)

### CI/CD

- Remove the JPEGs used for visual inspection in regression tests ({gh-pr}`364`)
- Upgrade ruff's target Python version to 3.10 ({gh-pr}`363`)
- Bump sigstore/gh-action-sigstore-python from 3.1.0 to 3.2.0 ({gh-pr}`359`)
- Bump actions/download-artifact from 5 to 6 ({gh-pr}`354`)
Expand Down
28 changes: 12 additions & 16 deletions src/ridgeplot/__init__.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,22 @@
"""ridgeplot: beautiful ridgeline plots in Python

The ridgeplot python library aims at providing a simple API for plotting
beautiful ridgeline plots within the extensive Plotly interactive graphing
environment.
ridgeplot is a Python package that provides a simple interface for plotting
beautiful and interactive ridgeline plots within the extensive Plotly ecosystem.

Take a look at the getting started guide, which provides a quick introduction
to the ridgeplot library: https://ridgeplot.readthedocs.io/en/stable/getting_started/getting_started.html

Simple example:
The full official documentation can be found at: https://ridgeplot.readthedocs.io/en/stable/

from numpy.random import normal
from ridgeplot import ridgeplot
For those in a hurry, here's a very basic example on how to quickly get started
with the `ridgeplot()` function.

# Put your real samples here...
synthetic_samples = [normal(n / 1.2, size=600) for n in reversed(range(9))]
import numpy as np
from ridgeplot import ridgeplot

# The `ridgeplot()` helper comes packed with sensible defaults
fig = ridgeplot(samples=synthetic_samples)

# and the returned Plotly figure is still fully customizable
fig.update_layout(height=500, width=800)

# show us the work!!
fig.show()
my_samples = [np.random.normal(n, size=900) for n in range(6, 0, -2)]
fig = ridgeplot(samples=my_samples)
fig.show()

"""

Expand Down
5 changes: 3 additions & 2 deletions src/ridgeplot/_hist.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@ def bin_trace_samples(
raise ValueError("The weights array should have the same length as the samples array.")
if not np.isfinite(weights).all():
raise ValueError("The weights array should not contain any infs or NaNs.")
hist, bins = np.histogram(trace_samples, bins=nbins, weights=weights)
return [(float(x), float(y)) for x, y in zip(bins, hist, strict=True)]
hist_counts, hist_edges = np.histogram(trace_samples, bins=nbins, weights=weights)
bin_centers = 0.5 * (hist_edges[:-1] + hist_edges[1:])
return [(float(x), float(y)) for x, y in zip(bin_centers, hist_counts, strict=True)]


def bin_samples(
Expand Down
Binary file removed tests/e2e/artifacts/basic.jpeg
Binary file not shown.
2 changes: 1 addition & 1 deletion tests/e2e/artifacts/basic.json

Large diffs are not rendered by default.

Binary file removed tests/e2e/artifacts/basic_hist.jpeg
Binary file not shown.
Loading