
ninejs
ninejs adds interactive behavior to plotnine charts with a minimal API. You can attach tooltips, hover grouping, and on click events directly from aes(), then export the result as a standalone HTML plot. All of this with just 2 lines of code!
- Works out of the box with Jupyter, Quarto, Marimo, and Shiny
- Includes a built-in preview in Positron
- Supports custom CSS and JavaScript
- Copy-pastable self contained documentation for AI and agents
Quick start¶
Specify the tooltip and hover_group aesthetic mappings, and then pass your plotnine chart to interactive():
from plotnine import ggplot, aes, geom_point, theme_minimal
from plotnine.data import anscombe_quartet
from ninejs import interactive, save
gg = (
ggplot(
data=anscombe_quartet,
mapping=aes(x="x", y="y", color="dataset", tooltip="dataset", hover_group="dataset"),
)
+ geom_point(size=7, alpha=0.5)
+ theme_minimal()
)
interactive(gg) + save("plot.html")
Installation¶
Examples¶
map_plot = (
ggplot()
+ geom_map(
data=regions,
mapping=aes(fill="region", tooltip="tooltip", hover_key="region"),
)
+ theme_void()
)
bar_plot = (
ggplot(bars, aes("reorder(region, value)", "value"))
+ geom_col(aes(fill="region", tooltip="tooltip", hover_key="region"))
+ theme_void()
)
plot = map_plot | bar_plot
interactive(plot) + save("docs/iframes/linked-map-bars.html")
gg = (
ggplot(df, aes(x="date", y="value", fill="group", tooltip="group"))
+ geom_area(alpha=0.8)
+ theme_minimal()
+ labs(title="Monthly Growth by Product", x="Date", y="Value", fill="Category")
+ scale_x_date(date_labels="%b")
+ theme(
figure_size=(10, 5),
plot_title=element_text(size=16, weight="bold"),
axis_title=element_text(size=11),
axis_text=element_text(size=10),
legend_title=element_text(size=11),
legend_text=element_text(size=10),
)
)
interactive(gg) + save("docs/iframes/area-chart.html")
anscombe_quartet["open_url"] = "window.open('https://www.ysunflower.com/')"
gg = (
ggplot(
data=anscombe_quartet,
mapping=aes(
x="x",
y="y",
color="dataset",
tooltip="dataset",
on_click="open_url",
),
)
+ geom_point(size=7, alpha=0.7)
+ theme_minimal()
)
interactive(gg) + save("docs/iframes/on-click-new-window.html")
gg = (
ggplot(anscombe_quartet, aes("x", "y", tooltip="x"))
+ geom_point(color="sienna", fill="orange", size=3)
+ geom_smooth(method="lm", se=False, fullrange=True, color="steelblue", size=1)
+ facet_wrap("dataset")
+ labs(title="Anscombe’s Quartet")
+ scale_y_continuous(breaks=(4, 8, 12))
+ coord_fixed(xlim=(3, 22), ylim=(2, 14))
+ theme_tufte(base_family="Futura", base_size=16)
+ theme(
axis_line=element_line(color="#4d4d4d"),
axis_ticks_major=element_line(color="#00000000"),
axis_title=element_blank(),
panel_spacing=0.09,
)
)
interactive(gg) + save("docs/iframes/facet_wrap.html")
plot = (
gg.ggplot()
+ gg.geom_rect(
data=histogram,
mapping=gg.aes(
xmin="xmin",
xmax="xmax",
ymin="ymin",
ymax="ymax",
fill="rate_mid",
tooltip="tooltip",
hover_key="unemployment",
),
)
+ gg.geom_map(
data=df,
mapping=gg.aes(
fill="unemployment_rate",
tooltip="tooltip",
hover_key="unemployment"
),
color="#e6e6e6",
size=0.08,
)
+ gg.theme_void(base_size=9)
+ gg.theme(figure_size=(5.5, 7.5))
)
(
interactive(plot, hover_nearest=True)
+ css(
from_dict={
".hovered": {"stroke": "#111", "stroke-width": "1px"},
".tooltip": {"font-size": "1.1em", "padding": "8px 10px"},
}
)
+ save("docs/iframes/map-belgium-unemployment.html")
)
goo_css = """
svg {filter: contrast(20);}
.point {
filter: blur(5px);
animation: goo 3s ease-in-out infinite alternate;
}
.point:nth-child(2n) {animation-duration: 4s;}
.point:nth-child(3n) {animation-duration: 8s;}
@keyframes goo {
from {transform: translate(-12px, -12px) scale(1);}
to {transform: translate(12px, 12px) scale(1.3);}
}
"""
interactive(gg) + css(goo_css) + save("docs/iframes/animation-art.html")
This is just a small subset of what's possible with ninejs. Check out the gallery and the guides for more.
Tools for AI and agents¶
A single-file overview of the ninejs API, written for AI/LLMs and coding agents. This file contains everything an agent needs to know to use ninejs properly!
The file is also available at this URL: llms.txt
A ninejs skill that your agents will know when to use automatically. Once installed, your agent will automatically know when to use the skill, or you can mention it in a prompt (inside Codex / Claude Code) using the $skill-name syntax:
- Install for Claude Code:
- Install for Codex:
Next steps?¶
For more in-depth explanations and feature overviews, check out: