Skip to main content

viscose

Scientific plots that are pieces of art.
Pick a palette. It brings its own colors, type, axes, and special effects.

Ridgeline plots in all four palettes, above an embedding, a clustermap, a volcano plot, and a line and bar figure

pip install viscose              # numpy and glycorender are all it needs
pip install "viscose[cluster]"   # adds scipy for clustermaps

One word changes everything

import viscose as vc

fig, ax = vc.subplots(palette = 'aura')
fig.suptitle('Differential abundance', 'Tumor vs. healthy tissue, 412 glycans')
ax.scatter(x, y, hue = direction)
ax.axhline(2)
ax.set_xlabel('log_{2} fold change')
ax.set_ylabel('-log_{10} adjusted p')
fig.save('volcano.pdf')

Same data, same code, and only palette changes. Spheres become rings, gradients become solid shapes, hairline axes become heavy rounded ones, and titles go from light and wide to bold and tight. No styling code, no rcParams, and no theme files.

The same volcano plot in Lumen, Couture, Poster, and Aura

Four palettes, four personalities

Each palette has two hues in four shades, and effects to match. Few colors, in shades of those few colors, on white: figures that look composed in a paper and striking on a slide.

A sample scene and eight shades for each palette

lumen: peacock and marigold

Gradients run through the marks, points are glossy spheres, lines glow, and everything rests on soft shadows.

An embedding, a line and bar figure, and a ridgeline plot in Lumen

couture: plum and gold

Hairline axes held away from the data, slender needle bars, large light titles, and spaced capitals.

A mass spectrum, stacked bars, and a volcano plot in Couture

poster: forest and vermilion

Heavy rounded axes, big bold type, and thick solid marks cut apart by crisp white gaps.

A volcano plot, stacked bars, and a ridgeline plot in Poster

aura: burgundy and teal

Marks float on soft shadows in their own color, above rounded heatmap cells, with no axis lines at all.

A clustermap, a line and bar figure, and an embedding in Aura

Out of the box

The same data and the same labels, with no styling on either side: matplotlib and seaborn on the left, viscose on the right.

A volcano plot from matplotlib and seaborn defaults beside the same plot from viscose in Aura

Glycans in your plots

viscose shares its renderer with glycowork's GlycoDraw, so a plot can carry real SNFG drawings as sharp as the rest of the figure, in PNG, PDF, and SVG.

from glycowork.motif.draw import annotate_figure

ax.annotate('Neu5Ac(a2-6)Gal(b1-4)GlcNAc', (x, y), offset = (12, 0), svg_label = True)
fig.save('volcano.svg')
annotate_figure('volcano.svg', filepath = 'volcano.pdf', compact = True)

A volcano plot and a biosynthetic network with SNFG glycan drawings as labels

Everything you reach for

hue, style, and size take one value per point and build the legend for you, as seaborn does.

ax.scatter(x, y, hue = stage, style = source, size = abundance,
           hue_label = 'Stage', style_label = 'Source', size_label = 'Abundance')
ax.text(0.02, 0.98, 'F = 4.2\np = 0.003', axes_fraction = True, va = 'top')

A scatter plot with color, shape, and size mapped to data, with a three-part legend

Clustermaps come with both dendrograms and a color bar. Hand over a DataFrame and it brings its own labels.

fig, heat = vc.clustermap(df, palette = 'aura', title = 'Glycan abundance by tissue', colorbar_label = 'z-score')

A clustermap of glycan abundance across tissues in Aura

Plots plot, scatter, bar, barh, stacked_bar, hist, fill_between, errorbar, stem, hlines, arrow, heatmap, ridgeline, dendrogram, axhline, axvline, and vc.clustermap
Markers o, s, D, ^, v, X, P, and *, all with the palette's effects
Annotation text, annotate, legend, and colorbar, with _{sub} and ^{super} in any text
Layout Colliding tick labels turn and thin themselves, labels move to the side with room, legends wrap, and the page grows for anything that needs it
Output fig.save writes PNG, PDF, or SVG from the same geometry, with marks, gradients, and text as real vectors in PDF and SVG
Display fig.show() works inline in Jupyter and slate, and in the system's image viewer from a terminal, with CI and coding agents kept silent
SVG hooks gid on arrow and scatter names elements for hover text and scripting
State None hidden: a figure is an object, with no current figure and nothing to close

Light and quick

No compiled plotting stack, no backends, and no font cache. For vector output, viscose is often many times faster than matplotlib and seaborn, and its files can be far smaller. At 300 dpi, in Poster:

matplotlib and seaborn viscose
Dependencies Nine extra packages, 42.5 MB numpy and glycorender, with 0.11 MB of its own code
Clustermap, 300 x 100, PDF 1.57 s, 587 kB 0.02 s, 79 kB
Clustermap, 300 x 100, SVG 1.40 s, 5,943 kB 0.02 s, 182 kB
Clustermap, 26 x 16, PDF 0.11 s, 22 kB 0.01 s, 26 kB
Three lines with a legend, PDF 0.03 s, 12 kB under 0.01 s, 13 kB
Scatter, 100,000 points, PDF 0.96 s, 1,524 kB 0.19 s, 644 kB
Scatter, 412 points, PNG 0.18 s, 147 kB 0.20 s, 180 kB

matplotlib's compiled rasterizer is still about twice as fast on most PNGs, and the soft shadows of Lumen and Aura add about half a second. To rerun the full comparison, wins and losses alike, use benchmarks/compare_matplotlib.py.

Make it yours

vc.set_palette('aura') changes the default for every figure. A library that builds on viscose calls vc.default_palette('aura') instead, which gives way to the choice of whoever uses it. In any palette, refer to its shades as a0 to a3 and b0 to b3, dark to pale, or as ink, muted, and faint; hex and CSS color names work too. fig.pal.groups(3, 2) gives categories grouped by hue, here three shades of one and two of the other, and fig.pal.contrast(n) alternates between the hues for categories that have to stand apart, as scatter(hue = ...) does.

A palette of your own is two hues, three text colors, and whichever effects you like:

vc.register_palette(vc.Palette('midnight', ['#14213D', '#27477E', '#5C85C5', '#C4D5EE'], ['#8F5B00', '#D08C00', '#F2B83B', '#FBE5B0'],
                               '#14213D', '#5A6478', '#E6EAF1', point = 'sphere', bar = 'deep', shadow = 0.4))
fig, ax = vc.subplots(palette = 'midnight')

Century Gothic is used where it is installed, and glycorender's bundled Comfortaa elsewhere.

More

examples/gallery.py draws seven standard figures in every palette, examples/features.py draws one sheet of features per palette, and examples/readme_figures.py draws every image on this page.

Metadata

Release files for viscose 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for viscose 0.1.0
File Size Uploaded Provenance Actions
viscose-0.1.0.tar.gz 53.6 kB With provenance Details for viscose-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for viscose 0.1.0
File Interpreter ABI Platform Actions
viscose-0.1.0-py3-none-any.whl Python 3 none any Details for viscose-0.1.0-py3-none-any.whl

Total release size: 94.6 kB

Release files / viscose-0.1.0.tar.gz

Download URL viscose-0.1.0.tar.gz
Size 53.6 kB
Tags Source
SHA-256 checksum
How to use checksums
56972841fe92d5d98dd402852b86fdcba5f24effc77183373b7551507c59ea03
BLAKE2b-256 checksum
How to use checksums
3e530831ef9a3905511c8ebe5de6767b262324c7f3f23747b65a505519cbd0eb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 3, 2026.

Transparency log

Release files / viscose-0.1.0-py3-none-any.whl

Download URL viscose-0.1.0-py3-none-any.whl
Size 40.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b2961fdb133241e102898297dd081ab9bddf06b3e7c7b33792619555f4cbe976
BLAKE2b-256 checksum
How to use checksums
0c12d2d9abd9eabca91939db0a986bc073dc2e23856e4448e4619440148ef2e5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 3, 2026.

Transparency log

Security for viscose 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for viscose-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 3, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page