API reference#
The page follows the tasks of the capabilities tour: plot, lay out, read the inputs, save, and
pick colors. Every entry links to the tour sections that use it, and its examples run as tests, so they match the
current version. draw, plot, legend and get_artists load matplotlib on first access, so import alluvial
alone does not import it.
- alluvial.__version__#
The package version, a string such as
"0.7.0":print(alluvial.__version__).
Plotting#
- alluvial.plot(networks, ax=None, **kwargs)#
Lay out and draw in one call:
draw(layout(networks, **layout_kwargs), ax, **draw_kwargs).- Parameters:
networks (iterable of str or PathLike, infomap.Infomap, dict or NetworkFile, or a pandas DataFrame) – Networks from left to right, as for
alluvial.layout: paths, runinfomap.Infomapobjects, Infomap JSON dicts,NetworkFileobjects, dicts mapping nodes to modules (alluvial.partition(...)), or a long-format DataFrame with one network pernetworkvalue (alluvial.from_dataframe).ax (matplotlib.axes.Axes, optional) – Target axes; by default a new figure sized by content (see
alluvial.draw): taller with more modules, wider with more networks and longer labels.**kwargs – Keyword arguments of
alluvial.layout(includingLayoutOptionsfields) andalluvial.draw.
- Returns:
get_artists(ax)returns the created artists.- Return type:
Examples
>>> import alluvial >>> ax = alluvial.plot([{"a": 1, "b": 1, "c": 2}, {"a": 1, "b": 2, "c": 2}], names=["2020", "2021"])
Layout and drawing keywords go together, here on an axes of your own:
>>> import matplotlib.pyplot as plt >>> fig, ax = plt.subplots(figsize=(3.4, 2.4), layout="constrained") >>> ax = alluvial.plot( ... [{"a": 1, "b": 1, "c": 2}, {"a": 1, "b": 2, "c": 2}], ax=ax, colors="similarity", palette="tab10" ... )
Used in: 1.2 Infomap output files · 6.1 Axes, fonts and figure sizes · 6.5 Saving figures
- alluvial.draw(geometry, ax=None, *, palette=None, default_color=None, module_labels=True, network_labels=True, fontsize=None, network_fontsize=None, max_label_lines=None, max_label_width='auto', avoid_label_overlap=True, label_pad=3.0, streamline_alpha=0.8, gradient=True, edgecolor='face', linewidth=0.3, rasterized=False, hierarchy=True, legend=False, label_colors='auto', module_kw=None, streamline_kw=None, hierarchy_kw=None, text_kw=None, label_kw=None, network_label_kw=None)#
Draw a laid-out alluvial diagram on a matplotlib Axes.
The shapes are in layout px (data coordinates, y up); every text size, gap and margin is in points. At each draw the labels and the axes limits are fitted to the axes size, so the diagram fills the axes, every text stays inside it and font sizes are exact at any figure size (also under
layout="constrained"and after resizing).- Parameters:
geometry (AlluvialGeometry) – Result of
alluvial.layout.ax (matplotlib.axes.Axes, optional) – Target axes, drawn on at its size. By default a new figure is created, sized by content: 1.0 + 0.28 in per module of the network with the most modules (between 2 and 6 in) tall, and 0.4 + 1.1 in per further network wide, plus the width of the labels (at most as much again).
palette (sequence of colors, str or Colormap, optional) – Highlight colors, or a matplotlib colormap (name). Qualitative maps are used as is, continuous maps are sampled to the needed number of colors. Defaults to
geometry.palette. Indices beyond the palette cycle it, with a warning.default_color (color, optional) – Color of unhighlighted modules; defaults to the web app’s gray.
module_labels (bool, default True) – Draw module name labels (first and last network) and network names (below each network).
network_labels (bool, default True) – Draw module name labels (first and last network) and network names (below each network).
fontsize (float or str, optional) – Module label size in points or a relative size; defaults to
"small"(rcParams["font.size"]/ 1.2).network_fontsize (float or str, optional) – Network name size; defaults to
"medium"(rcParams["font.size"]).max_label_lines (int, optional) – Cap on the names (lines) per module label. By default as many as fit (the web app rule: one line per 1.8 em of module height, an odd number).
max_label_width (float, "auto" or None, default "auto") – Longer label lines are truncated with an ellipsis to this width in points.
"auto"keeps each label column within a quarter of the axes width; None never truncates.avoid_label_overlap (bool, default True) – Where labels of neighboring modules would overlap, drop lines of the smaller module, then its whole label. False reproduces the web app, which lets them overlap.
label_pad (float, default 3) – Gap between a module and its label, in points.
streamline_alpha (float, default 0.8) – Streamline opacity.
gradient (bool, default True) – Fill streamlines whose ends differ in color with a horizontal gradient (as the web app does; a small embedded image, clipped to the streamline). If False they use the color of their left end, all vector.
edgecolor (default "face", 0.3) – Module edge style. The default hairline in the face color hides the antialiasing seams between stacked groups and at streamline ends; use
linewidth=0for exact web app rectangles.linewidth (default "face", 0.3) – Module edge style. The default hairline in the face color hides the antialiasing seams between stacked groups and at streamline ends; use
linewidth=0for exact web app rectangles.rasterized (bool, default False) – Rasterize modules and streamlines (texts stay vector) in PDF/SVG output, for very large diagrams.
hierarchy (bool or {"shadow", "outline"}, default True) – How to show the parent modules of expanded sub-modules (
NetworkGeometry.outlines, fromlayout(module_level=...)orexpand=), as the web app does:"shadow"(or True) draws a gray box behind each parent, offset right and down by 5 px per level;"outline"a thin solid dark gray rounded box around it (the web app’s is dotted). False or None draws nothing. A diagram of top modules has no outlines either way.legend (bool, default False) – Add a legend of the highlight labels (
layout(highlight=...)) above the diagram; seealluvial.legend.label_colors (bool or "auto", default "auto") – Color each module label line by its node’s highlight color, as the web app does (black when gray).
"auto"does so only for a diagram with highlight labels (layout(highlight=...)), where the color tells which names belong to a group.module_kw (dict, optional) – Extra
Rectangle/ streamline properties (e.g.{"hatch": "//", "edgecolor": "white"},{"alpha": 0.6}). A hatch is drawn in the edge color, which is the face color by default.streamline_kw (dict, optional) – Extra
Rectangle/ streamline properties (e.g.{"hatch": "//", "edgecolor": "white"},{"alpha": 0.6}). A hatch is drawn in the edge color, which is the face color by default.hierarchy_kw (dict, optional) – Extra properties of the hierarchy shadows or outlines (e.g.
{"facecolor": "0.85"},{"edgecolor": "k", "linewidth": 1.5},{"linestyle": "--"}).text_kw (dict, optional) – Extra
Textproperties for all labels (e.g.{"family": "serif"}).label_kw (dict, optional) – Extra
Textproperties for module labels or network names only (overridetext_kw).network_label_kw (dict, optional) – Extra
Textproperties for module labels or network names only (overridetext_kw).
- Returns:
The axes drawn on, with the axis turned off.
get_artists(ax)returns the created artists.- Return type:
Examples
>>> import alluvial >>> import matplotlib.pyplot as plt >>> geometry = alluvial.layout([{"a": 1, "b": 1, "c": 2}, {"a": 1, "b": 2, "c": 2}], names=["2020", "2021"]) >>> fig, ax = plt.subplots(figsize=(3.4, 2.4), layout="constrained") >>> ax = alluvial.draw(geometry, ax, fontsize=6, max_label_lines=3) >>> fig.savefig("alluvial.pdf")
Used in: 2 Layout options · 3.1 Color modes · 6.2 Label options · 6.3 Palettes, colormaps, gradients and styles
- alluvial.legend(ax, *, other=None, **kwargs)#
Add a legend of the highlight labels (
layout(highlight=...)) of the diagram drawn onax.By default the legend is a row of color swatches centered above the diagram, inside the axes. It takes more rows when it is wider than the axes, and the fit makes room for it at every draw. Passing
locorbbox_to_anchorplaces it like any matplotlib legend instead (no room is made). Calling it again replaces the legend.- Parameters:
ax (matplotlib.axes.Axes) – An axes
draworplotdrew on.other (str, optional) – Also add an entry in the default (gray) color with this label, e.g.
"other".**kwargs –
Axes.legendkeywords (e.g.title,fontsize,ncols,frameon).
- Returns:
None (with a warning) if the geometry has no highlight labels and no
other.- Return type:
matplotlib.legend.Legend or None
Examples
>>> import alluvial >>> networks = [{"a": 1, "b": 1, "c": 2}, {"a": 1, "b": 2, "c": 2}] >>> ax = alluvial.plot(networks, highlight={"group a": ["a"]}) >>> legend = alluvial.legend(ax, other="other", title="Nodes") >>> [text.get_text() for text in legend.get_texts()] ['group a', 'other']
Used in: 3.4 Highlight groups and legends
- alluvial.get_artists(ax)#
The
AlluvialArtistsof the last diagram drawn onax.Examples
>>> import alluvial >>> ax = alluvial.plot([{"a": 1, "b": 1, "c": 2}, {"a": 1, "b": 2, "c": 2}], names=["2020", "2021"]) >>> artists = alluvial.get_artists(ax) >>> for text in artists.network_labels: ... text.set_fontweight("bold") >>> for patch in artists.streamlines: ... patch.set_alpha(0.5)
- Parameters:
ax (Axes)
- Return type:
Used in: 6.4 Restyling with get_artists
- class alluvial.mpl.AlluvialArtists(geometry, modules=<factory>, streamlines=<factory>, module_labels=<factory>, network_labels=<factory>, outlines=<factory>, legend=None, _colors=None)#
The artists
drawadded to an axes, for restyling after the fact. Get it withget_artists(ax).Every artist also carries a
gid(kept as the element id in SVG output):module:<network id>:<module id>:<group>,streamline:<streamline id>,module-label:<network id>:<module id>:<line>,network-label:<network id>andoutline:<network id>:<module path>.- Parameters:
- geometry#
The geometry that was drawn.
- Type:
- modules#
One rectangle per module group, in geometry order.
- Type:
- streamlines#
One per streamline in geometry (draw) order: a
PathPatch, or a clippedAxesImagefor gradients.- Type:
- module_labels#
One text per label line. Lines that do not fit are invisible; the fitter decides at every draw.
- Type:
- network_labels#
One per network with a name.
- Type:
- outlines#
One per super-module box (
NetworkGeometry.outlines) when drawn withhierarchy: a shadowRectangleor a dottedFancyBboxPatch.- Type:
- legend#
The highlight legend, from
draw(..., legend=True)oralluvial.legend(ax).- Type:
matplotlib.legend.Legend or None
Examples
>>> import alluvial >>> ax = alluvial.plot([{"a": 1, "b": 1, "c": 2}, {"a": 1, "b": 2, "c": 2}], names=["2020", "2021"]) >>> artists = alluvial.get_artists(ax) >>> len(artists.modules), len(artists.streamlines), [text.get_text() for text in artists.network_labels] (4, 3, ['2020', '2021']) >>> artists.network_labels[0].get_gid() 'network-label:net0'
Used in: 6.4 Restyling with get_artists
Layout and geometry#
- alluvial.layout(networks, *, names=None, ids=None, identifier='id', split_layers=False, colors='module_id', color_network=None, module_level=1, expand=None, highlight=None, highlight_colors=None, scheme=None, tone=None, offset=None, restore_state=True, module_order=None, module_names=None, show_bipartite_nodes=None, **options)#
Lay out an alluvial diagram of one or more partitioned networks.
- Parameters:
networks (iterable of str or PathLike, infomap.Infomap, dict or NetworkFile, or a pandas DataFrame) – Networks from left to right. Paths are read by suffix (
.tree,.ftree,.stree,.clu,.json); aninfomap.Infomapmust already have run. A.zipof network files (the web app’s zip upload, orsave_diagram) contributes its files in archive order. A dict is Infomap JSON when its"nodes"is a list of dicts; any other dict is a partition{node: module}without Infomap (alluvial.partition): nodes are ids or names matched across networks by key, a module is an int, a path string"1:2"or a tuple of ints, and every node gets flow 1/N. A long-format DataFrame with the columnsnetwork,node,moduleand optionallyflowgives one network pernetworkvalue (alluvial.from_dataframe, which also takes other column names). When no input carries flows (only such dicts, or partitions and frames without flows),module_sizeandsort_modules_bydefault to"nodes".names (sequence of str, optional) – Network names, one per network (after splitting layers; numbers are converted with
str). Defaults to the file basename,"network {i}"for objects (a partition’snameif given), and"<name> layer <k>"-style names for split layers.ids (sequence of str, optional) – Network ids, one per network (after splitting layers): unique, without
"--". By default the file stem,"net{i}"for objects or theNetworkFileid, with colliding ids made unique asout,out_2, … An input that is split gets that suffix before splitting (out_2_layer1, …).identifier ({"id", "name"}, default "id") – How nodes are matched across networks:
stateId ?? id, or the node name. Applies to paths, dicts and Infomap objects; aNetworkFilekeeps the identifiers it was read with.split_layers (bool or sequence of bool, default False) – Split multilayer networks into one network per layer (
alluvial.read(..., split_layers=True)); a sequence gives one flag per input. Split layers match their nodes by physical id.colors ({"similarity", "module_id", "nodes", "layer", "physical_id", "hierarchy"} or None, default "module_id") – Coloring operation applied after the build, as in the web app: by module id (the same id gets the same color in every network), matching modules across networks, every node by its module in one network (
color_network), by layer id (multilayer networks), by physical node id (state or multilayer networks), or by the module hierarchy (c3’shierarchy(): sub-modules get colors close to their parent’s, and the same module path gets the same color in every network; use it withmodule_level/expand, andscheme,toneandoffsetset the top-module colors).Nonekeeps the input colors (gray unless the input carries colors). Not allowed withhighlight. The default isNonewhen the input carries colors: Infomap JSON with a top-levelcolors(as written bysave_diagram).color_network (int or str, optional) – With
colors="nodes", the network whose modules color the nodes (in every network), as the web app’s selected network: an index, a network id, or a name given withnames=when exactly one network has it. Default the first network. Only allowed withcolors="nodes".module_level (int or sequence of int, default 1) – Show sub-modules down to this level (one value, or one per network): every visible module whose sub-modules go that deep is expanded, as when clicking modules in the web app.
1shows the top modules. Withcolors="similarity"a sub-module that is not paired with a module of a neighboring network can stay gray, as in the web app.expand (iterable of (network, module_id), optional) – Modules to expand first, in order.
networkis an index or a network id,module_ida path string like"1"or"1:2"(looked up when its turn comes, so[(0, "1"), (0, "1:2")]works).highlight (mapping or callable, optional) – Highlight groups of nodes, each in its own color (the rest stays gray). Either
{label: identifiers}(matched against node identifiers, ints allowed; an identifier may belong to one label only), or a callable(NodeInfo) -> label or Noneevaluated once per node. Labels are kept in mapping order (or first-appearance order) inAlluvialGeometry.highlight_labels, fordraw(..., legend=True).highlight_colors (sequence or mapping, optional) – Colors of the highlight labels (a list aligned with the labels, or
{label: color}): color strings (any matplotlib color name,"#rrggbb"or"rgb(r, g, b)") or RGB tuples in [0, 1]. Defaults to the scheme.scheme (str or sequence of colors, optional) – The color scheme of the coloring operations: a web-app scheme name (
alluvial.SCHEMESlists them, e.g."Paired","Tableau20","C3 Sinebow"; default"C3 Oklch", as in the web app) or a list of colors. Also the defaulthighlight_colors. The C3 schemes ("C3 Oklch","C3 Turbo","C3 Rainbow","C3 Sinebow","C3 Viridis") are computed with c3 (https://mapequation.github.io/c3).tone (str, optional) – The c3 tone:
"vivid","bright","strong","deep","dark","soft","pastel"or"muted", the lightness and chroma of the C3 schemes and ofcolors="hierarchy"with a C3 or an interpolated (diverging, sequential or cyclical) scheme. Other schemes ignore it. Default"vivid", as in the web app (or the stored tone of a saved diagram).offset (float, optional) – Where c3 puts the first color, in degrees around the hue source: its hue on the OKLCH hue circle (
"C3 Oklch"), else 360 is the whole scheme. Applies wheretonedoes. Default c3’s (245 for"C3 Oklch", else 0), or the stored offset of a saved diagram when its scheme is used.restore_state (bool, default True) – Restore what a saved diagram (
save_diagramor the web app’s “Download diagram”) stores besides the networks, colors and expanded modules: the options, the color scheme with its tone and offset, the custom module orders and the module names, as the web app opens it. Explicit keywords win: a layout option,scheme,toneoroffsetgiven here replaces the stored one (anotherschemedrops the stored offset), andmodule_order/module_namesreplace the stored orders/names. Files from different saves, or not all files of one save, restore their module orders and names but not the options (warned).Falseloads the files as plain Infomap JSON (with their colors and expanded modules).module_order (mapping, optional) –
{network: [module_id, ...]}: put these visible modules of a network (index, id, or a name given withnames=as a string when exactly one network has it) at these positions, listed bottom to top. The unlisted visible modules keep their relative order above them; an...(Ellipsis) in the list stands for them, so["3", ...]puts module 3 at the bottom,[..., "3"]at the top and["2", ..., "5"]both. Applied after the coloring as one reorder of the web app’s store (one layout however many modules move; “move up/down” in the web app gives the same order), sosort_modules_bysets the start. Module ids are those shown afterexpand/module_level(e.g."1:2"); hidden modules cannot be placed.module_names (mapping or callable, optional) – Custom module names, shown instead of the node names (as the web app’s module name field): either
{(network, module_id): name}(network as formodule_order) or a callable(ModuleInfo) -> str or Nonecalled for every module (also hidden ones) after all other steps. Names are kept inModuleGeometry.name(save_diagramstores them); the labels are drawn on the first and last network only, as in the web app.show_bipartite_nodes (bool, optional) –
Falsehides the second node type of bipartite networks (node id >= the network’sbipartiteStartId), as the web app’s “Show bipartite nodes” switch. DefaultTrue(or the stored value of a saved diagram).**options – Fields of
LayoutOptions.
- Returns:
Frozen geometry in the web app’s SVG coordinates (y down).
- Return type:
- Raises:
ValueError – For an Infomap object that has not run, an unreadable or unsupported file, no networks, an invalid option value, a module to
expandthat does not exist or has no sub-modules,colorswithhighlight, an unknowncolor_networkor one withoutcolors="nodes", or amodule_order/module_namesentry with an unknown network or module, a module given twice, or (formodule_order) a hidden module.FileNotFoundError – For a path that does not exist.
TypeError – For an unknown keyword, a single network not wrapped in a list, or an argument of the wrong type.
- Warns:
UserWarning – For state networks matched by state id next to networks matched by node id (
identifier="id"), amodule_leveldeeper than a network’s module tree,highlightidentifiers that match no node, duplicate node identifiers within a network, highlight labels drawn gray or in a shared color, and a diagram where no node flow is positive.
Notes
The steps run in the web app’s store, in this order: build,
expand,module_level, the coloring (colorsorhighlight),module_order, thenmodule_names. Each is a sequence of the store’s own operations, so the geometry matches the web app bit for bit.Examples
>>> import alluvial >>> geometry = alluvial.layout([{"a": 1, "b": 1, "c": 2}, {"a": 1, "b": 2, "c": 2}], names=["2020", "2021"]) >>> [network.name for network in geometry.networks] ['2020', '2021'] >>> [len(network.modules) for network in geometry.networks], len(geometry.streamlines) ([2, 2], 3)
Used in: 1 Inputs · 2 Layout options · 3.1 Color modes · 4 Hierarchy · 7 Geometry access
- class alluvial.LayoutOptions(height=600.0, module_width=80.0, streamline_fraction=2.0, streamline_threshold=1.0, flow_threshold=0.005, margin_exponent=4.0, zero_margins=False, vertical_align='bottom', module_size='flow', sort_modules_by='flow')#
Layout options with the web app’s defaults. Validated on construction.
- Parameters:
height (float, default 600) – Diagram height in layout px. Must be > 0.
module_width (float, default 80) – Width of each network’s module column. Must be > 0.
streamline_fraction (float, default 2) – Gap between networks as a multiple of
module_width. Must be >= 0.streamline_threshold (float, default 1) – Streamlines with mean height
<=this (px, not scaled withheight) are not drawn. Must be >= 0.flow_threshold (float, default 0.005) – Fraction of each network’s flow to hide, smallest modules first. Must be in [0, 1).
margin_exponent (float, default 4) – Module margins are
2 ** (margin_exponent - 2 * difference_index).zero_margins (bool, default False) – Put no margin between modules.
vertical_align ({"bottom", "justify"}, default "bottom") –
"justify"stretches the margins so every network spans the full height."top"is rejected (the web app never implemented it).module_size ({"flow", "nodes"}, default "flow") – Module height measure.
sort_modules_by ({"flow", "nodes", "node_id", "highlight_index"}, default "flow") – Module order key (descending).
"node_id"is the mean node id.
- Raises:
TypeError – If a value has the wrong type.
ValueError – If a value is out of range or not one of the allowed choices.
Examples
Pass the fields as keywords to
layoutorplot; the geometry keeps the options it ran with:>>> import alluvial >>> geometry = alluvial.layout([{"a": 1, "b": 1, "c": 2}, {"a": 1, "b": 2, "c": 2}], height=300, module_width=40) >>> geometry.options.height, geometry.options.module_width (300.0, 40.0) >>> alluvial.LayoutOptions(vertical_align="justify").to_ts()["verticalAlign"] 'justify'
- to_ts()#
The options under the web app’s option names and values, as a saved diagram stores them.
- classmethod from_ts(options)#
Build from the web app’s option names (the inverse of
to_ts()). Unknown keys raiseValueError.- Parameters:
- Return type:
Used in: 2 Layout options
- class alluvial.AlluvialGeometry(width, height, networks, streamlines, palette=(), options=None, highlight_labels=())#
The complete diagram geometry.
- Parameters:
width (float)
height (float)
networks (tuple[NetworkGeometry, ...])
streamlines (tuple[StreamlineGeometry, ...])
options (LayoutOptions | None)
highlight_labels (tuple[HighlightLabel, ...])
- width, height
Diagram size in layout px.
- Type:
- networks#
Left to right.
- Type:
- streamlines#
In draw order (
getLinksorder per network pair, pairs left to right).- Type:
- options#
The options the layout ran with.
- Type:
LayoutOptions or None
- highlight_labels#
The labels of
layout(highlight=...)in label order (empty otherwise), for legends.- Type:
Examples
>>> import alluvial >>> geometry = alluvial.layout([{"a": 1, "b": 1, "c": 2}, {"a": 1, "b": 2, "c": 2}], names=["2020", "2021"]) >>> geometry.width, geometry.height (320.0, 600.0) >>> module = geometry.networks[0].modules[0] >>> module.id, module.label.text.splitlines() ('1', ['a', 'b'])
It converts to plain dicts and lists (e.g. for JSON) and back:
>>> alluvial.AlluvialGeometry.from_dict(geometry.to_dict()) == geometry True
- classmethod from_dict(data)#
Inverse of
to_dict().- Parameters:
- Return type:
Used in: 7 Geometry access
The geometry is a tree of frozen dataclasses: AlluvialGeometry.networks holds the NetworkGeometry of each
network, with its ModuleGeometry modules, their GroupGeometry highlight groups and Label labels, and the
OutlineGeometry boxes of the module hierarchy; AlluvialGeometry.streamlines holds the StreamlineGeometry between
adjacent networks. Each has to_dict().
- class alluvial.geometry.NetworkGeometry(id, name, index, x, y, width, height, flow, name_label, modules, outlines=())#
One network column.
modulesare the visible modules in layout order (bottom first).outlinesare the super-module boxes of expanded modules in breadth-first order (empty when every module is a top module).
- class alluvial.geometry.ModuleGeometry(id, path, network_index, flow, x, y, width, height, highlight_index, groups, label, largest_leaf_names, name_candidates=(), level=1, max_level=1, order=None, name_highlight_indices=(), name_insignificant=(), name='')#
A visible module of a network.
- Parameters:
- groups#
In the web app’s group order: significant first, then by highlight index.
- Type:
- label#
Name label; only modules of the first (anchor
"end") and last (anchor"start") network have one.- Type:
Label or None
- largest_leaf_names#
Label names in descending flow (aggregated to physical names for state networks), capped by the web app’s lines-per-module rule at layout px (
label.textjoins them).
- name_candidates#
For labeled modules only:
largest_leaf_namesfollowed by the next largest names, up toNAME_CANDIDATESin total. Renderers that size labels at their own scale (alluvial.mpl) pick lines from these, so a tall axes or a small font can show more names than a 600 px web view.
- max_level#
The deepest level the module could be expanded to;
> levelmeans it has sub-modules.- Type:
- order#
Index of the module in the network’s hierarchical draw order (breadth first, interleaved with
NetworkGeometry.outlines). In a flat diagram it is the index inmodules.- Type:
int or None
- name_highlight_indices#
Highlight index of each label name, aligned with
name_candidates(orlargest_leaf_nameswhen there are no candidates). The web app colors each label line with it (black for -1).
- name_insignificant#
Whether each label name is an insignificant node (drawn brighter); always False for aggregated names.
- class alluvial.geometry.GroupGeometry(highlight_index, insignificant, x, y, width, height, flow)#
A highlight group: a colored slice of a module.
highlight_index-1 is the default color.
- class alluvial.geometry.Label(text, x, y, anchor, center_line=0)#
A text label at
(x, y).- Parameters:
- x, y
Anchor point. For module labels
yis the module’s vertical center and linecenter_lineis vertically centered on it (SVGdominant-baseline: middle). For network namesyisnetwork.height + 20and the web app puts the first baseline one network font size below it.- Type:
- anchor#
SVG
text-anchor.- Type:
{“start”, “end”, “middle”}
- class alluvial.geometry.OutlineGeometry(path, level, max_level, x, y, width, height, order)#
A super-module box: the union of the visible modules below one parent module path.
- Parameters:
- max_level#
The deepest module level in its subtree (sets the web app’s shadow/outline offset).
- Type:
- x, y, width, height
The raw union rect of the visible descendant modules (no render offset).
- Type:
- class alluvial.geometry.StreamlineGeometry(id, left, right, x0, y0, h0, x1, y1, h1, avg_height, highlight_index, left_highlight_index, right_highlight_index, left_insignificant=False, right_insignificant=False)#
A streamline between two adjacent networks.
- Parameters:
- left, right
(network_index, module_id, highlight_index)of the group at each end.- Type:
- x0, y0, h0
Left end: x (module right edge), top y and height.
- Type:
- x1, y1, h1
Right end: x (module left edge), top y and height.
- Type:
- left_insignificant, right_insignificant
Whether the group at each end is insignificant (drawn with a brighter color).
- Type:
- path()#
Closed outline as
(code, (x, y))pairs with matplotlibPathcodes, in layout coordinates.Same points as the web app’s SVG path: bottom edge left to right, up the right end, top edge back, close. Top edges below 1e-6 snap to 0.
Used in: 7 Geometry access
Inputs#
- alluvial.partition(modules, flows=None, *, name=None)#
One network from a mapping of node ids or names to modules, without Infomap.
- Parameters:
modules (mapping) –
{node: module}. A node is an id (int) or a name (str); nodes are matched across networks by this key (whateverlayout(identifier=...)says). A module is a positive int (a top module), a tree path string"1:2"(sub-module 2 of module 1) or a tuple or list of positive ints(1, 2); module ids start at 1, as in Infomap. The mapping order is the node order.flows (mapping, optional) –
{node: flow}with one non-negative finite number per node ofmodules. The flows are normalized to sum to 1, as Infomap’s flows do. Withoutflowsevery node gets flow 1/N, N being the number of nodes.name (str, optional) – Network name (and id, unless it is empty or contains
"--").layoutnames an unnamed partition"network {i}", as other objects.
- Returns:
Nodes in mapping order. An int node keeps its value as node id; a named node gets its 1-based position as node id and the key as name. A node’s path is its module’s path plus its position in that module, as in Infomap’s
.treefiles:"2:1:3"is the third node of sub-module"2:1".- Return type:
- Raises:
ValueError – For no nodes, a module value of another kind (or below 1), a key that is neither str nor int, two keys with the same string (
1and"1"), or flows that are negative, not finite, missing for a node, given for a node not inmodules, or all zero.TypeError – If
modulesorflowsis not a mapping, ornameis not a string.
Notes
A diagram of only flow-less networks (
partitionwithoutflows, plain{node: module}dicts inlayout) sizes and sorts its modules by node count:module_sizeandsort_modules_bydefault to"nodes"there, unless given.Examples
>>> import alluvial >>> nf = alluvial.partition({"Ann": 1, "Bo": 1, "Cy": "2:1"}, name="2020") >>> [(n.name, n.path) for n in nf.nodes] [('Ann', '1:1'), ('Bo', '1:2'), ('Cy', '2:1:1')] >>> [n.flow for n in alluvial.partition({1: 1, 2: (1, 2)}).nodes] [0.5, 0.5] >>> [n.flow for n in alluvial.partition({"Ann": 1, "Bo": 2}, flows={"Ann": 3, "Bo": 1}).nodes] [0.75, 0.25]
Plain dicts work directly as networks in
layoutandplot:>>> geom = alluvial.layout([{"Ann": 1, "Bo": 1, "Cy": 2}, {"Ann": 1, "Bo": 2, "Cy": "2:1"}], names=["2020", "2021"]) >>> [network.name for network in geom.networks] ['2020', '2021']
Used in: 1.1 Dicts, partition() and DataFrames
- alluvial.from_dataframe(df, *, network='network', node='node', module='module', flow=None)#
Networks from a long-format data frame with one row per (network, node), without Infomap.
- Parameters:
df (pandas.DataFrame) – The rows. pandas is not required by alluvial; any data frame with
columnsand column access works.network (str, default "network", "node", "module") – Column names: the network of a row, its node (id or name, matched across networks) and its module (as in
partition: an int, a path string"1:2"or a tuple of ints).node (str, default "network", "node", "module") – Column names: the network of a row, its node (id or name, matched across networks) and its module (as in
partition: an int, a path string"1:2"or a tuple of ints).module (str, default "network", "node", "module") – Column names: the network of a row, its node (id or name, matched across networks) and its module (as in
partition: an int, a path string"1:2"or a tuple of ints).flow (str, optional) – The flow column. If
None(the default), a column named"flow"is used when there is one; otherwise every node gets flow 1/N. Flows are normalized to sum to 1 per network.
- Returns:
One
partitionper network, in order of first appearance, or in category order for a pandas Categorical network column. A network’s name isstr(value).- Return type:
list of NetworkFile
- Raises:
ValueError – For a missing column, a node twice in one network, an empty frame, or any value
partitionrejects.TypeError – If
dfis not a data frame.
Examples
>>> import alluvial, pandas as pd >>> df = pd.DataFrame({"year": [2020, 2020, 2021, 2021], "who": ["Ann", "Bo", "Ann", "Bo"], ... "community": [1, 2, 1, 1]}) >>> networks = alluvial.from_dataframe(df, network="year", node="who", module="community") >>> [(nf.name, [n.path for n in nf.nodes]) for nf in networks] [('2020', ['1:1', '2:1']), ('2021', ['1:1', '1:2'])]
With the default column names, pass the frame straight to
layoutorplot:>>> df = df.rename(columns={"year": "network", "who": "node", "community": "module"}) >>> [network.name for network in alluvial.layout(df).networks] ['2020', '2021']
Used in: 1.1 Dicts, partition() and DataFrames
- alluvial.read(source: str | PathLike[str] | Any, *, name: str | None = None, identifier: Literal['id', 'name'] = 'id', states: bool | None = None, network_id: str | None = None, split_layers: Literal[False] = False) NetworkFile#
- alluvial.read(source: str | PathLike[str] | Any, *, name: str | None = None, identifier: Literal['id', 'name'] = 'id', states: bool | None = None, network_id: str | None = None, split_layers: Literal[True]) list[NetworkFile]
Read one network into a
NetworkFile(or, withsplit_layers=True, one per layer).- Parameters:
source (str, PathLike, dict, infomap.Infomap or NetworkFile) – A
.tree/.ftree/.stree/.clupath (format from the suffix; Infomap’s-o statesfiles*_states.tree/.ftree/.cluincluded), an Infomap-o jsonfile (.json) or its parseddict, aninfomap.Infomapthat has run, an infomapResult(fromim.run(),infomap.run(...)orNetwork.run(); infomap >= 2.14), or aNetworkFile(returned unchanged unless split). A.zipof network files (the web app’s zip upload, orsave_diagram), a directory of network files, or a list of paths gives a list, oneNetworkFileper file, in archive (file-name, list) order, or in saved order when they are the files of one saved diagram.name (str, optional) – Network name. Defaults to the file basename, or
"network"for objects. For JSON a top-levelnamecomes before these defaults.identifier ({"id", "name"}, default "id") – Node identity across networks, as in the web app:
"id"usesstate_idif present else the node id,"name"the node name. See State networks below. Ignored withsplit_layers=True.states (bool, optional) – Infomap objects only: read state nodes.
Nonepicks them for state/memory and multilayer networks (likewrite_tree(states=True));Falsereads the physical level (write_tree(states=False)).network_id (str, optional) – Network id. Defaults to the file stem for paths, or
name(else"network") for objects. For JSON a top-level stringidcomes before these defaults.split_layers (bool, default False) – Split a multilayer state network into one network per layer, like the web app’s “split layers” (
alluvial.io.split_layers). Layers are ordered by layer id, named"Layer <k>"(or from a JSONlayerslist), get the ids"<network_id>_layer<k>"and match their nodes by physical id.
- Returns:
A list (one per layer) if
split_layersis true. Pass it on unpacked:layout([*read(path, split_layers=True)]).- Return type:
NetworkFile or list of NetworkFile
- Raises:
ValueError – For an unsupported file (Infomap input
.net,.csv, Newick, JSON that is not Infomap output, a saved diagram in the 2019 web-app format), a malformed file, a node whose flow is not a finite number, an Infomap object that has not been run, orsplit_layers=Trueon a network that is not a multilayer state network.TypeError – For other sources, or an infomap older than 2.14.
- Warns:
UserWarning – If several nodes share an identifier (the engine then matches the last one, as in the web app; checked per layer after a split), if a tree file has node names with a double quote (Infomap writes them unescaped, so the id column is misread), or if
identifier="name"is combined withsplit_layers=True.
Notes
State networks. Networks are matched node by node through
identifier, exactly as in the web app.identifier="id"matches state nodes by state id. That is right for memory networks whose state ids mean the same thing in every network (you assign them in the*Statessection or withadd_state_node). For multilayer networks Infomap assigns the state ids itself, in input order, so the same (layer, node) can get different state ids in two runs: do not match multilayer networks by"id"unless they were built from identically ordered input.identifier="name"matches by physical node name: Infomap writes the physical name (or the physical id when unnamed) for every state node. A physical node with several state nodes then gives duplicate identifiers (warned; matching uses the last one).The physical level (
states=Falseor awrite_tree(states=False)file) has one row per physical node and module; a node whose state nodes sit in several modules still appears more than once.split_layers=Trueshows how one multilayer partition changes across its layers: each layer is a network, and its nodes are matched by physical node id (the identifier mode does not apply, as in the web app). A non-split network next to the layers matches them only if its identifiers are physical ids too, e.g. a first-order.treeread withidentifier="id".
Examples
A parsed Infomap JSON (
infomap -o json), here written inline:>>> import alluvial >>> nf = alluvial.read( ... { ... "nodes": [ ... {"id": 1, "name": "a", "path": [1, 1], "flow": 0.5}, ... {"id": 2, "name": "b", "path": [2, 1], "flow": 0.5}, ... ] ... }, ... name="2020", ... ) >>> nf.name, nf.format, [node.name for node in nf.nodes] ('2020', 'json', ['a', 'b'])
A
.clufile of Infomap (node id, module, flow). The id defaults to the file stem and the name to the file name:>>> import pathlib, tempfile >>> with tempfile.TemporaryDirectory() as tmp: ... path = pathlib.Path(tmp) / "2021.clu" ... _ = path.write_text("# node_id module flow\n1 1 0.5\n2 1 0.5\n") ... nf = alluvial.read(path) >>> nf.id, nf.name, nf.format, [node.path for node in nf.nodes] ('2021', '2021.clu', 'clu', ['1', '1'])
Used in: 1.2 Infomap output files · 1.3 Infomap JSON · 1.4 Infomap results and objects · 1.7 The web app’s zip, directories and lists of files
- alluvial.split_layers(nf, *, id_format='{id}_layer{layer}')#
Split a multilayer state network into one network per layer, like the web app’s “split layers”.
Nodes are matched across the layers by physical node id (as the web app does), whatever identifiers
nfwas read with. Streamlines then connect the same physical node in adjacent layers.- Parameters:
nf (NetworkFile) – A multilayer network read at the state level (its first node has a
layer_id). Not mutated: the layers get copies of the nodes.id_format (str, default
"{id}_layer{layer}") – Network id of each layer, formatted withid(nf.id) andlayer(the layer id as a string, e.g."3"). The result must not contain"--".
- Returns:
In layer id order: non-negative integer ids ascending, then any other ids in first-seen order (only hand-made input has those). Each layer copies every field of
nf(header,modules…) and setsid,name(nf.layersentry with a strictly equalid, else"Layer <id>"),nodes(file order),layer_id,original_id = nf.id, the statistics of its nodes andis_expanded = True.- Return type:
list of NetworkFile
- Raises:
ValueError – If
nfis not multilayer.
Notes
Nodes without a
layer_idform a last"Layer undefined"network, as in the web app. A JSONlayerId: nullreads as missing (the web app would make a"Layer null"network).Examples
A multilayer state network with two layers, as Infomap JSON:
>>> import alluvial >>> nf = alluvial.read( ... { ... "nodes": [ ... {"id": 1, "stateId": 1, "layerId": 1, "name": "a", "path": [1, 1], "flow": 0.25}, ... {"id": 2, "stateId": 2, "layerId": 1, "name": "b", "path": [1, 2], "flow": 0.25}, ... {"id": 1, "stateId": 3, "layerId": 2, "name": "a", "path": [1, 1], "flow": 0.25}, ... {"id": 2, "stateId": 4, "layerId": 2, "name": "b", "path": [2, 1], "flow": 0.25}, ... ] ... }, ... network_id="net", ... ) >>> layers = alluvial.split_layers(nf) >>> [(layer.id, layer.name) for layer in layers] [('net_layer1', 'Layer 1'), ('net_layer2', 'Layer 2')] >>> [len(network.modules) for network in alluvial.layout(layers).networks] [1, 2]
Used in: 1.6 Multilayer networks and split_layers
- class alluvial.NetworkFile(id, name, format, nodes, ...)#
A parsed network file, as
alluvial.readandalluvial.partitionreturn it.Besides the attributes below, it holds the file’s Infomap header (
codelength,directed, …) and statistics (is_state_network,is_multilayer,num_top_modules, …).- Parameters:
id (str)
name (str)
format (str)
nodes (list[Node])
filename (str)
size (int)
last_modified (int)
have_modules (bool)
version (str | None)
args (str | None)
started_at (str | None)
completed_in (float | None)
codelength (float | None)
relative_codelength_savings (float | None)
flow_model (str | None)
higher_order (bool | None)
state_level (bool | None)
clu_level (int | None)
bipartite_start_id (int | None)
directed (bool | None)
modules (list[InfomapModule] | None)
is_state_network (bool | None)
is_multilayer (bool | None)
is_expanded (bool | None)
num_top_modules (int | None)
num_levels (int | None)
num_layers (int | None)
network (str | None)
num_trials (int | None)
two_level (bool | None)
layer_id (int | None)
original_id (str | None)
colors (Any)
alluvial (Any)
- id#
Network id. Must be unique within a diagram and must not contain
"--"; readers default it to the file stem.- Type:
- nodes#
Node rows in file order (the order decides module creation order and every downstream tie-break).
- Type:
list of Node
Examples
>>> import dataclasses, alluvial >>> nf = alluvial.partition({"a": 1, "b": 1, "c": 2}, name="2020") >>> nf.id, nf.name, nf.num_top_modules ('2020', '2020', 2) >>> renamed = dataclasses.replace(nf, id="first", name="First year") >>> [network.name for network in alluvial.layout([renamed, alluvial.partition({"a": 1, "b": 2, "c": 2})]).networks] ['First year', 'network 1']
Used in: 1.8 NetworkFile, names, ids and identifiers
- class alluvial.NodeInfo(network_index, network_id, identifier, id, state_id, layer_id, name, flow, path, metadata)#
A read-only view of one input node, passed to a
layout(highlight=callable).- Parameters:
- state_id, layer_id
State and layer ids of state and multilayer networks.
- Type:
int or None
- metadata#
The node’s metadata, read-only.
- Type:
Mapping or None
Examples
>>> import alluvial >>> geometry = alluvial.layout( ... [{"a": 1, "b": 1, "c": 2}, {"a": 1, "b": 2, "c": 2}], ... highlight=lambda node: "a" if node.identifier == "a" else None, ... ) >>> [label.label for label in geometry.highlight_labels] ['a']
Used in: 3.4 Highlight groups and legends
- class alluvial.ModuleInfo(network_index, network_id, network_name, id, path, level, flow, visible, node_names)#
A read-only view of one module, passed to a
layout(module_names=callable).- Parameters:
- node_names#
The names of its nodes in descending flow (nodes without a name are left out).
Examples
>>> import alluvial >>> geometry = alluvial.layout( ... [{"a": 1, "b": 1, "c": 2}, {"a": 1, "b": 2, "c": 2}], module_names=lambda module: f"M{module.id}" ... ) >>> [module.name for module in geometry.networks[0].modules] ['M1', 'M2']
Used in: 5 Module names and order
- class alluvial.HighlightLabel(label, highlight_index, color)#
One label of
layout(highlight=...): its text, its highlight index (-1: drawn in the default color) and the color string registered for it.Examples
>>> import alluvial >>> networks = [{"a": 1, "b": 1, "c": 2}, {"a": 1, "b": 2, "c": 2}] >>> geometry = alluvial.layout(networks, highlight={"group a": ["a"]}, highlight_colors=["tab:red"]) >>> geometry.highlight_labels (HighlightLabel(label='group a', highlight_index=0, color='tab:red'),)
Used in: 3.4 Highlight groups and legends
Saving#
- alluvial.save_diagram(networks, path, *, loose=False, **layout_kwargs)#
Lay out
networkslikelayoutand save the diagram as the web app saves it (“Download diagram”).The files are “alluvial network files” (formatVersion 1): one Infomap-JSON file per network (
00_<name>.json, …) with the network name, the palette (colors), each node’s color index and module level, Infomap’s own top-level data, and analluvialblock with the options, the color scheme with its c3 tone and offset, the module names and any custom module order. The web app opens them (drop the zip, or all files, on “Load networks”) with the same picture, andalluvial.read/layoutload them back exactly. Other Infomap-JSON readers ignore the block. The text equals the web app’s for the same diagram, apart fromgenerator.- Parameters:
networks (Iterable[Any]) – As for
layout(names,colors,color_network,module_level,highlight,scheme,tone,offset,module_order,module_names, layout options, …). The writer reads the engine store after these steps, as the web app saves its own store.**layout_kwargs – As for
layout(names,colors,color_network,module_level,highlight,scheme,tone,offset,module_order,module_names, layout options, …). The writer reads the engine store after these steps, as the web app saves its own store.path (str or PathLike) – Where to write. By default a zip (
.zipis appended ifpathhas another suffix). Withloose=True, a directory (created if needed) for the loose files. A.jsonpath writes the one file of a single-network diagram.loose (bool, default False) – Write loose files to a directory instead of a zip.
- Returns:
The path written (the zip, the directory or the
.jsonfile).- Return type:
- Raises:
TypeError – If
networksis anAlluvialGeometry(pass the networks andlayout’s keywords instead).ValueError – For a
.jsonpath and a diagram of more than one network.
Examples
>>> import alluvial, pathlib, tempfile >>> networks = [{"a": 1, "b": 1, "c": 2}, {"a": 1, "b": 2, "c": 2}] >>> with tempfile.TemporaryDirectory() as tmp: ... path = alluvial.save_diagram(networks, pathlib.Path(tmp) / "diagram.zip", names=["2020", "2021"]) ... [network.name for network in alluvial.read(path)] ['2020', '2021']
Used in: 8 Save and load
Colors#
- alluvial.SCHEMES: tuple[str, ...]#
the values of
scheme=.- Type:
The names of the web app’s color schemes, in the order of its scheme menu
Used in: 3.2 Color schemes · 3.3 Tones and offsets
Pass a name as scheme= to layout, plot or save_diagram, or pass a list of colors instead. The C3 schemes are
computed with c3, which shows what they and its tones look like; tone= and
offset= apply to them. The other schemes are those of the web app’s scheme menu. To draw with any matplotlib
colormap instead, pass palette= to draw or plot.
Group |
Schemes |
|---|---|
ColorBrewer |
|
Seaborn |
|
Matplotlib |
|
C3 |
|
Natural |
|
Uniform |
|
Diverging |
|
Sequential Multi |
|
Sequential Single |
|
Cyclical |
|
The c3 tones (tone=): vivid (default), bright, strong, deep, dark, soft, pastel, muted.