Cinematic matplotlib styles inspired by iconic films, plus a reusable-brand API
Project description
cinestyle
Cinematic data-viz theming, done with color science. Twenty-four film-inspired themes that are beautiful, correct, and accessible, defined once and applied to matplotlib, Plotly, or Altair, plus an API for defining your own brand.
Every theme plots data from its own film. Same data, cinematic finish:
Why this exists
Most "pretty matplotlib" packages pick colors by eye and only look right on the one chart in their README. cinestyle is built differently:
- Perceptually derived. Each theme's categorical palette and its sequential and diverging colormaps are computed in a perceptual color space (OKLCH, with CIEDE2000 distances) from a few sourced "hero" colors, not hand-waved. Sequential maps have monotonic lightness; diverging maps are symmetric.
- One spec, three backends. Define a theme once and apply it to matplotlib, Plotly, or Altair. The palette, the sequential/diverging colormaps, and the chrome all travel; you stop caring which plotting library wins.
- Works on every chart type. On matplotlib it only sets rcParams and registers colormaps. Lines, bars, scatter, hist, boxplots, pies, heatmaps, errorbars: all themed. You never switch themes mid-deck.
- Accessible by design.
audit()any palette (or theme) for color-vision deficiency and contrast;repair()turns it into a colorblind-safe variant. - Reproducible. Themes ship their fonts (SIL OFL), so a matplotlib chart looks the same on every machine.
- Cinematic extras (matplotlib). A neon glow for the dark themes, and
film-look LUTs you can apply to image plots and export as
.cube.
Install
pip install cinestyle
Latest unreleased build: pip install git+https://github.com/Burton-David/cinematic-matplotlib.git.
Optional extras: cinestyle[plotly], cinestyle[altair] (the other backends),
cinestyle[a11y] (color-vision checks), cinestyle[luts] (reading external
.cube LUTs). For development: pip install -e ".[dev]". Requires Python 3.10+.
Quick start
import matplotlib.pyplot as plt
import numpy as np
import cinestyle
x = np.linspace(0, 12, 200)
# 1. Scoped: styling is restored when the block exits
with cinestyle.use("blade_runner"):
fig, ax = plt.subplots()
for i in range(4):
ax.plot(x, np.sin(x + i * 0.6) + i * 0.4)
cinestyle.add_glow(ax) # the neon glow
# 2. Registered style sheet: use it like any matplotlib style
cinestyle.register()
plt.style.use("cinestyle-dune")
# 3. The Theme object itself: palette, colormaps, and more
theme = cinestyle.get_theme("ghibli")
plt.imshow(data, cmap=theme.sequential)
Other backends
The same theme drives Plotly and Altair. The palette, colormaps, and chrome carry over; glow and LUTs stay matplotlib-only.
import cinestyle
# Plotly
cinestyle.register_plotly()
fig.update_layout(template="cinestyle-blade_runner") # or use_plotly("dune")
# Altair
cinestyle.register_altair(enable="dune") # enables the theme
See docs/gallery.md for the same theme rendered across all three backends side by side.
Gallery
Each card plots something from its own film: Blade Runner's "Tears in Rain", the
Bride's kill count, the Balance of the Force. All regenerated from deterministic
data by python scripts/generate_gallery.py (add --reel to rebuild the GIF).
The themes
| Theme | Film | Font |
|---|---|---|
noir |
Film noir / chiaroscuro | Oswald |
ghibli |
Studio Ghibli | EB Garamond |
wes_anderson |
Wes Anderson | Jost |
blade_runner |
Blade Runner (neon-noir) | Share Tech Mono |
star_wars |
Star Wars | Oswald |
matrix |
The Matrix | Share Tech Mono |
dune |
Dune (Villeneuve) | Space Grotesk |
fury_road |
Mad Max: Fury Road | Anton |
kill_bill |
Kill Bill | Bebas Neue |
in_the_mood |
In the Mood for Love | EB Garamond |
sin_city |
Sin City | Anton |
akira |
Akira | Share Tech Mono |
the_fall |
The Fall (Tarsem) | EB Garamond |
tron |
Tron: Legacy | Share Tech Mono |
amelie |
Amélie | EB Garamond |
the_shining |
The Shining (Kubrick) | Bebas Neue |
drive |
Drive | Share Tech Mono |
grand_budapest |
The Grand Budapest Hotel | Jost |
nolan |
Nolan (Interstellar, Inception) | Space Grotesk |
hero |
Hero (Zhang Yimou) | Oswald |
suspiria |
Suspiria | Anton |
moonlight |
Moonlight | Jost |
blade_runner_2049 |
Blade Runner 2049 | Space Grotesk |
her |
Her | EB Garamond |
Each Theme exposes its palette, sequential and diverging colormaps,
heroes, and chrome. cinestyle.list_themes() lists them all.
Color, done right
The palette and colormaps are derived from the hero colors, preserving the film's mood (hue identity and chroma) while spacing colors perceptually:
theme = cinestyle.get_theme("dune")
theme.palette # categorical cycle, perceptually separated
theme.sequential # monotonic-lightness sequential colormap
theme.diverging # symmetric diverging colormap
Accessibility
audit() and repair() work on any palette, theme name, or Theme, not just
ours:
cinestyle.audit("blade_runner").summary() # CIEDE2000 under protan/deutan/tritan + contrast
cinestyle.audit(["#D62728", "#2CA02C"]) # check your own colors
safe = cinestyle.repair("blade_runner") # a colorblind-safe version
Checks simulate the palette under each color-vision deficiency and flag any pair that collapses (CIEDE2000), plus WCAG non-text contrast against the background. The repair keeps the film's mood where it can and borrows from known-safe palettes (Okabe-Ito, Paul Tol) where it must.
Film looks
look = cinestyle.get_look("teal_orange")
im = ax.imshow(image)
look.apply_to_image(im) # grade an image plot / heatmap
look.to_cube("teal_orange.cube") # export a 3D LUT for video tools
Looks are original parametric grades (lift/gamma/gain, saturation, split-tone). They matter most for image and heatmap plots; flat bar/line charts are carried by the palette and chrome.
Define your own brand
brand = cinestyle.define_brand(
"acme",
palette=["#0B5FFF", "#FF6B00", "#00B5AD"],
background="#FBFBFD",
foreground="#1A1A2E",
)
with brand.use():
...
brand.register() # plt.style.use("cinestyle-acme")
brand.to_matplotlibrc("acme.mplstyle")
Development
pip install -e ".[dev]"
black --check . && ruff check . && mypy cinestyle && pytest
python scripts/generate_gallery.py # regenerate the gallery
Tests run headless (Agg) and assert that styling is actually applied: rcParams change, artist colors match the palette, colormaps are monotonic/symmetric, the scoped context restores global state, palettes pass the accessibility checks.
Credits
cinestyle is an independent, inspired-by tribute and is not affiliated with or
endorsed by any rights holder; film titles are trademarks of their owners. See
NOTICE.md for palette sources (incl. the wesanderson and ghibli
palette projects) and bundled-font licenses.
License
MIT. See LICENSE.
Author
David Burton, databurton.com
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file cinestyle-0.2.0.tar.gz.
File metadata
- Download URL: cinestyle-0.2.0.tar.gz
- Upload date:
- Size: 795.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1aabf1dab51e02718b6dcb062614ee541724a0a322614ca66d34c65d1163ed7d
|
|
| MD5 |
f80a96994362ba3ea45f53685c9a5309
|
|
| BLAKE2b-256 |
edae5775ec90974b4934c231d59978234597efeca494671a039762866bfb510c
|
Provenance
The following attestation bundles were made for cinestyle-0.2.0.tar.gz:
Publisher:
release.yml on Burton-David/cinematic-matplotlib
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cinestyle-0.2.0.tar.gz -
Subject digest:
1aabf1dab51e02718b6dcb062614ee541724a0a322614ca66d34c65d1163ed7d - Sigstore transparency entry: 1698497781
- Sigstore integration time:
-
Permalink:
Burton-David/cinematic-matplotlib@6b7d0d323560152b98bed94f9109e4353c1f01b5 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/Burton-David
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@6b7d0d323560152b98bed94f9109e4353c1f01b5 -
Trigger Event:
release
-
Statement type:
File details
Details for the file cinestyle-0.2.0-py3-none-any.whl.
File metadata
- Download URL: cinestyle-0.2.0-py3-none-any.whl
- Upload date:
- Size: 802.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
97f871360e034b7029696bede7df157a496f423de1077db3c501e69f8f59c023
|
|
| MD5 |
71b676ff710c22c099b8167af24bba18
|
|
| BLAKE2b-256 |
8a756e4b635e45554e11419f8fe2aee5d252335bf2d5aff38071e118a4774c9a
|
Provenance
The following attestation bundles were made for cinestyle-0.2.0-py3-none-any.whl:
Publisher:
release.yml on Burton-David/cinematic-matplotlib
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cinestyle-0.2.0-py3-none-any.whl -
Subject digest:
97f871360e034b7029696bede7df157a496f423de1077db3c501e69f8f59c023 - Sigstore transparency entry: 1698498069
- Sigstore integration time:
-
Permalink:
Burton-David/cinematic-matplotlib@6b7d0d323560152b98bed94f9109e4353c1f01b5 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/Burton-David
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@6b7d0d323560152b98bed94f9109e4353c1f01b5 -
Trigger Event:
release
-
Statement type: