# datachart > Data visualization package, simple to use, highly customizable datachart is a Python data visualization package built on matplotlib. It provides simple chart functions (BarChart, LineChart, StackedAreaChart, ScatterChart, Histogram, Heatmap, ContourChart, HexbinChart, BoxPlot, ViolinPlot, SwarmPlot, RaincloudPlot, ParallelCoords, PyramidChart, RadialChart, SankeyChart), figure composition via Panel (overlaying charts on shared axes) and Grid (arranging charts in a grid), and a global configuration system with predefined themes. Install with `pip install datachart`. All charts return a matplotlib Figure. Style is controlled globally via `datachart.config.config` and themes; per-chart overrides go in each chart's `style` parameter. # Getting Started *Data visualization package, simple to use, highly customizable* ______________________________________________________________________ **Documentation:** **Source code:** ______________________________________________________________________ The datachart package is a python package for creating data visualizations, built on top of [matplotlib](https://matplotlib.org/). It is designed to be simple to use and highly customizable, i.e. it is easy to change the look and feel of the charts. **Features:** - **Charts.** Bar charts, line charts, scatter charts, histograms, heatmaps, box plots, pyramid charts, radial charts, and parallel coordinates — each created with a single function call from plain lists of dicts. - **Composition.** Combine rendered charts with `Panel` (overlay charts on a single plot, with optional dual y-axes) and `Grid` (arrange charts in a grid; grids nest). - **Themes & configuration.** Six predefined themes, each named for its visual trait, plus a global `config` for tweaking any style attribute — per-chart `style` overrides included. ## Requirements Before starting the project make sure these requirements are available: - [python](https://www.python.org/). The python programming language (v3.10 or higher). ## Install ``` pip install datachart ``` ## Upgrade ``` pip install datachart --upgrade ``` ## Example Set a theme once and every chart follows it. The example below uses the `INK` theme: ``` from datachart.charts import LineChart from datachart.config import config from datachart.constants import THEME config.set_theme(THEME.INK) figure = LineChart( [ [{"x": x, "y": y} for x, y in enumerate([40, 45, 43, 50, 56, 54, 61])], [{"x": x, "y": y} for x, y in enumerate([38, 40, 44, 43, 48, 52, 55])], ], title="Line", subtitle=["Run 1", "Run 2"], show_legend=True, ) ``` The same theme, across chart types and composed with `Grid`: More examples on how to use the `datachart` package are available on the official [How-to Guides](https://eriknovak.github.io/datachart/how-to-guides/). ## Using with LLMs The documentation is available in LLM-friendly formats: - [llms.txt](https://eriknovak.github.io/datachart/llms.txt) — index of the documentation with descriptions - [llms-full.txt](https://eriknovak.github.io/datachart/llms-full.txt) — full documentation in a single file - Every documentation page is also available as plain markdown by appending `index.md` to its URL, e.g. [how-to-guides/charts/linechart/index.md](https://eriknovak.github.io/datachart/how-to-guides/charts/linechart/index.md) You can also connect your AI assistant directly: - [Context7](https://context7.com/eriknovak/datachart) — up-to-date, version-aware docs for AI coding assistants - [GitMCP](https://gitmcp.io/eriknovak/datachart) — an MCP server serving this repository's documentation # How-to Guides The how-to guides showcase how to utilize the `datachart` package: creating charts that reflect the data and the message the user wants to send, composing multiple charts into panels and grids, and styling everything through themes and the global configuration. | Section | Description | | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ | | [charts](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/charts/index.md) | Showcases the creation and customization of charts available in the `charts` module. | | [composition & utilities](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/utility/index.md) | Composing figures with `Panel` and `Grid`, plus the statistics and saving utilities. | | [styling](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/styling/index.md) | Configuring the global style, applying and creating themes, emphasis, and colormaps. | # Charts # Charts The [datachart.charts](https://eriknovak.github.io/datachart/0.9.0/references/charts/index.md) module of the `datachart` package provides various chart types to create data visualizations. The module is designed to be highly customizable and easy to use. It offers a wide range of chart types, including line charts, bar charts, histograms, and more. The module allows users to customize the look and feel of their charts by providing attributes to control the colors, labels, and titles of the charts. The module also includes methods to create subplots, i.e., to display multiple charts in the same figure. This makes it easy to compare different data sets and highlight the details of each chart. ## Trends and Comparisons Values along an axis or across categories: how a quantity moves and how the categories compare. | Chart | Description | | ---------------------------------------------------------------------------------------------------------------- | --------------------------------------- | | [Line Chart](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/charts/linechart/index.md) | The showcase of the line chart. | | [Stacked Area Chart](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/charts/stackedareachart/index.md) | The showcase of the stacked area chart. | | [Bar Chart](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/charts/barchart/index.md) | The showcase of the bar chart. | | [Pyramid Chart](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/charts/pyramidchart/index.md) | The showcase of the pyramid chart. | | [Radial Chart](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/charts/radialchart/index.md) | The showcase of the radial chart. | ## Distributions The spread of the values within each group, from a binned summary to every observation. | Chart | Description | | --------------------------------------------------------------------------------------------------------- | ----------------------------------- | | [Histogram](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/charts/histogram/index.md) | The showcase of the histogram. | | [Box Plot](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/charts/boxplot/index.md) | The showcase of the box plot. | | [Violin Plot](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/charts/violinplot/index.md) | The showcase of the violin plot. | | [Swarm Plot](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/charts/swarmplot/index.md) | The showcase of the swarm plot. | | [Raincloud Plot](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/charts/raincloudplot/index.md) | The showcase of the raincloud plot. | ## Relationships How two or more variables relate to each other. | Chart | Description | | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------- | | [Scatter Chart](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/charts/scatterchart/index.md) | The showcase of the scatter chart. | | [Heatmap](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/charts/heatmap/index.md) | The showcase of the heatmap. | | [Contour Chart](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/charts/contourchart/index.md) | The showcase of the contour chart. | | [Hexbin Chart](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/charts/hexbinchart/index.md) | The showcase of the hexbin chart. | | [Parallel Coordinates](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/charts/parallelcoords/index.md) | The showcase of the parallel coordinates. | ## Flows How a quantity moves between categories: where it comes from and where it goes. | Chart | Description | | ----------------------------------------------------------------------------------------------------- | --------------------------------- | | [Sankey Chart](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/charts/sankeychart/index.md) | The showcase of the Sankey chart. | ## Composition Here are some utility functions, that could help you. | Utility | Description | | ---------------------------------------------------------------------------------------------- | ------------------------------------------- | | [Panel](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/utility/panel/index.md) | How to overlay multiple charts in one plot. | | [Grid Layout](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/utility/grid/index.md) | How to combine multiple charts in a grid. | # Line Chart This section showcases the line chart. It contains examples of how to create line charts using the [datachart.charts.LineChart](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.LineChart) function. Looking for a specific customization? Jump straight to the [quick reference](#customizing-the-line-chart), which maps common tasks to the parameter or style attribute that does the job. As mentioned above, the line charts are created using the `LineChart` function found in the [datachart.charts](https://eriknovak.github.io/datachart/0.9.0/references/charts/index.md) module. Let's import it: ``` from datachart.charts import LineChart ``` ## Line Chart Input Attributes The `LineChart` function accepts keyword arguments for chart configuration. The main argument is `data`, which contains the data points. For a single line chart, `data` is a list of dictionaries. For multiple line charts, `data` is a list of lists. ``` LineChart( data=[{ # A list of line data points (or list of lists for multiple charts) "x": Union[int, float], # The x-axis value "y": Union[int, float], # The y-axis value "yerr": Optional[Union[int, float]] # The y-axis error value (to plot the confidence interval) }], style={ # The style of the line (optional) "plot_line_color": Optional[str], # The color of the line (hex color code) "plot_line_style": Optional[LINE_STYLE], # The line style (solid, dashed, etc.) "plot_line_marker": Optional[LINE_MARKER], # The marker style of the line (circle, square, etc.) "plot_line_width": Optional[float], # The width of the line "plot_line_alpha": Optional[float], # The alpha of the line (how visible the line is) "plot_line_drawstyle": Optional[LINE_DRAW_STYLE], # The drawstyle of the line (step, steps-mid, etc.) "plot_line_zorder": Optional[int], # The zorder of the line "plot_area_color": Optional[str], # The color of the area under the line / confidence band "plot_area_alpha": Optional[float], # The alpha of the area "plot_area_hatch": Optional[HATCH_STYLE], # The hatch style of the area }, subtitle=Optional[str], # The subtitle of the chart (or list for multiple charts) emphasis=Optional[str], # "highlight" or "background" (or list for multiple charts) title=Optional[str], # The title of the chart xlabel=Optional[str], # The x-axis label ylabel=Optional[str], # The y-axis label figsize=Optional[Tuple[float, float]], # The figure size in inches show_grid=Optional[str], # Which grid lines to show ("both", "x", "y") aspect_ratio=Optional[str], # The aspect ratio of the axes ("auto", "equal") show_legend=Optional[bool], # Whether to show the legend show_area=Optional[bool], # Whether to fill the area under the line show_yerr=Optional[bool], # Whether to show the confidence interval (from "yerr") subplots=Optional[bool], # Whether to draw each chart in its own subplot max_cols=Optional[int], # Maximum number of subplots per row sharex=Optional[bool], # Whether subplots share the x-axis sharey=Optional[bool], # Whether subplots share the y-axis scalex=Optional[str], # The x-axis scale ("linear", "log", "symlog", "asinh") scaley=Optional[str], # The y-axis scale ("linear", "log", "symlog", "asinh") xmin=Optional[Union[int, float]], # The x-axis range xmax=Optional[Union[int, float]], ymin=Optional[Union[int, float]], # The y-axis range ymax=Optional[Union[int, float]], xticks=Optional[List[Union[int, float]]], # the x-axis ticks xticklabels=Optional[List[str]], # the x-axis tick labels (must be same length as xticks) xtickrotate=Optional[int], # the x-axis tick labels rotation yticks=Optional[List[Union[int, float]]], # the y-axis ticks yticklabels=Optional[List[str]], # the y-axis tick labels (must be same length as yticks) ytickrotate=Optional[int], # the y-axis tick labels rotation vlines=Optional[Union[dict, List[dict]]], # the vertical lines hlines=Optional[Union[dict, List[dict]]], # the horizontal lines x=Optional[str], # the key holding the x-axis value (default: "x") y=Optional[str], # the key holding the y-axis value (default: "y") yerr=Optional[str], # the key holding the y-axis error value (default: "yerr") ) ``` For more details, see the [datachart.charts.LineChart](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.LineChart) function. ## Basics The examples in this guide share one dataset: the average monthly temperature (in °C) of three European cities, based on their 1991–2020 climate normals. The data is hard-coded in a hidden cell; `temperature_ljubljana` holds the twelve monthly values of Ljubljana, and `temperature_by_city` holds one series per city — Ljubljana, Reykjavik and Lisbon — with the year-to-year standard deviation of each monthly mean as `yerr`. `MONTHS` holds the month names used as tick labels. Each data point is a dictionary with an `x` value (here the month number) and a `y` value: ``` temperature_ljubljana[:3] ``` **Basic example.** Only the `data` argument is required to draw the line chart. ``` LineChart( # add the data to the chart data=temperature_ljubljana ).show() ``` ## Customizing the Line Chart Every customization is either a keyword argument of `LineChart` or a `plot_line_*` / `plot_area_*` attribute of its `style` dictionary. The table maps common tasks to the one you need and links to the subsection that shows it. | I want to… | Use | See | | ------------------------------------- | --------------------------------------------------------------------- | ------------------------------------------------------------- | | add a title and axis labels | `title`, `xlabel`, `ylabel` | [Title, axis labels and ticks](#title-axis-labels-and-ticks) | | set custom tick positions and labels | `xticks`, `xticklabels`, `yticks`, `yticklabels` | [Title, axis labels and ticks](#title-axis-labels-and-ticks) | | rotate the tick labels | `xtickrotate`, `ytickrotate` | [Title, axis labels and ticks](#title-axis-labels-and-ticks) | | fix the axis range | `xmin`, `xmax`, `ymin`, `ymax` | [Title, axis labels and ticks](#title-axis-labels-and-ticks) | | resize the figure | `figsize` | [Figure size and grid](#figure-size-and-grid) | | show grid lines | `show_grid` | [Figure size and grid](#figure-size-and-grid) | | fix the aspect ratio of the axes | `aspect_ratio` | [Figure size and grid](#figure-size-and-grid) | | change the line color | `style={"plot_line_color": ...}` | [Line style](#line-style) | | dash or dot the line | `style={"plot_line_style": ...}` | [Line style](#line-style) | | mark the data points | `style={"plot_line_marker": ...}` | [Line style](#line-style) | | draw the line as steps | `style={"plot_line_drawstyle": ...}` | [Line style](#line-style) | | change the line width or transparency | `style={"plot_line_width": ..., "plot_line_alpha": ...}` | [Line style](#line-style) | | fill the area under the line | `show_area`, `style={"plot_area_color": ..., "plot_area_alpha": ...}` | [Area under the line](#area-under-the-line) | | highlight one series, mute the rest | `emphasis` | [Emphasis](#emphasis) | | mark a threshold or an event | `hlines`, `vlines` | [Reference lines](#reference-lines) | | compare several series in one chart | `data` as a list of lists, `subtitle`, `show_legend` | [Multiple Line Charts](#multiple-line-charts) | | draw each series in its own subplot | `subplots`, `sharex`, `sharey`, `max_cols` | [Subplots](#subplots) | | draw a confidence interval | `yerr` in `data`, `show_yerr` | [Confidence interval](#confidence-interval) | | use a logarithmic axis | `scaley`, `scalex` | [Axis scales](#axis-scales) | | plot data with other key names | `x`, `y`, `yerr` | [Custom data keys](#custom-data-keys) | | save the chart to a file | `save_figure` | [Saving the Chart as an Image](#saving-the-chart-as-an-image) | The full list of style attributes is in the [datachart.typings.LineStyleAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.LineStyleAttrs) and [datachart.typings.AreaStyleAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.AreaStyleAttrs) types; the full list of parameters is in the [datachart.charts.LineChart](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.LineChart) reference. ### Title, axis labels and ticks To add the chart title and axis labels, add the `title`, `xlabel` and `ylabel` attributes. The tick positions and their labels can be set with `xticks` and `xticklabels` (or `yticks` and `yticklabels`) — here the month numbers on the x-axis are replaced by month names. Tick labels can be rotated with `xtickrotate` (or `ytickrotate`), and the axis range can be fixed with `xmin`, `xmax`, `ymin` and `ymax`. ``` LineChart( data=temperature_ljubljana, # add the title title="Average monthly temperature in Ljubljana", # add the x and y axis labels xlabel="Month", ylabel="Temperature (°C)", # show the month names instead of the month numbers xticks=MONTH_TICKS, xticklabels=MONTHS, # rotate the x-axis tick labels xtickrotate=45, # fix the y-axis range ymin=-5, ymax=25, ).show() ``` ### Figure size and grid To change the figure size, add the `figsize` attribute. The `figsize` attribute can be a tuple (width, height), values are in inches. The `datachart` package provides a [datachart.constants.FIG_SIZE](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.FIG_SIZE) constant, which contains some of the predefined figure sizes. To add the grid, add the `show_grid` attribute. The possible options are: | Option | Description | | -------- | ----------------------------------------------- | | `"both"` | shows both the x-axis and the y-axis gridlines. | | `"x"` | shows only the x-axis grid lines. | | `"y"` | shows only the y-axis grid lines. | Again, `datachart` provides a [datachart.constants.SHOW_GRID](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.SHOW_GRID) constant, which contains the supported options. Related is the `aspect_ratio` attribute, which fixes the aspect ratio of the axes rather than of the figure: `"auto"` (the default) lets the axes fill the figure, `"equal"` keeps one data unit the same length on both axes. The supported values are in the [datachart.constants.ASPECT_RATIO](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.ASPECT_RATIO) constant; the [ROC curve example](#example-1-roc-curve-custom-data-keys-and-equal-aspect-ratio) below uses it. ``` from datachart.constants import FIG_SIZE, SHOW_GRID ``` ``` LineChart( data=temperature_ljubljana, title="Average monthly temperature in Ljubljana", xlabel="Month", ylabel="Temperature (°C)", xticks=MONTH_TICKS, xticklabels=MONTHS, # add to determine the figure size figsize=FIG_SIZE.FULL_SHORT, # add to show the grid lines show_grid=SHOW_GRID.BOTH, ).show() ``` ### Line style To change the line style, add the `style` attribute with the corresponding attributes. The supported attributes are shown in the [datachart.typings.LineStyleAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.LineStyleAttrs) type, which contains the following attributes: | Attribute | Description | | ---------------------------- | ---------------------------------------------------- | | `"plot_line_color"` | The color of the line (hex color code). | | `"plot_line_alpha"` | The alpha of the line (how visible the line is). | | `"plot_line_width"` | The width of the line. | | `"plot_line_style"` | The line style (solid, dashed, etc.). | | `"plot_line_marker"` | The marker style of the line (circle, square, etc.). | | `"plot_line_drawstyle"` | The drawstyle of the line (step, steps-mid, etc.). | | `"plot_line_zorder"` | The zorder of the line. | | `"plot_xticks_label_rotate"` | The rotation of the x-axis tick labels. | | `"plot_yticks_label_rotate"` | The rotation of the y-axis tick labels. | Again, to help with the style settings, the [datachart.constants](https://eriknovak.github.io/datachart/0.9.0/references/constants/index.md) module contains the following constants: | Constant | Description | | -------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------- | | [datachart.constants.LINE_STYLE](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.LINE_STYLE) | The line style (solid, dashed, etc.) | | [datachart.constants.LINE_MARKER](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.LINE_MARKER) | The marker style of the line (circle, square, etc.) | | [datachart.constants.LINE_DRAW_STYLE](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.LINE_DRAW_STYLE) | The drawstyle of the line (step, steps-mid, etc.) | The example below changes the color, width, dash pattern and marker of the line in one go. Any attribute you leave out keeps the value of the active theme. ``` from datachart.constants import LINE_STYLE, LINE_MARKER, LINE_DRAW_STYLE ``` ``` LineChart( data=temperature_ljubljana, # define the style of the line style={ "plot_line_color": "#e76f51", "plot_line_width": 2, "plot_line_style": LINE_STYLE.DASHED, "plot_line_marker": LINE_MARKER.CIRCLE, }, title="Average monthly temperature in Ljubljana", xlabel="Month", ylabel="Temperature (°C)", xticks=MONTH_TICKS, xticklabels=MONTHS, figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.BOTH, ).show() ``` Monthly averages are one value per month rather than a continuous curve. The `plot_line_drawstyle` attribute draws the line as steps instead — `LINE_DRAW_STYLE.STEPS_MID` centers each step on its data point. ``` LineChart( data=temperature_ljubljana, style={ # draw the line as steps centered on the data points "plot_line_drawstyle": LINE_DRAW_STYLE.STEPS_MID, "plot_line_marker": LINE_MARKER.POINT, }, title="Average monthly temperature in Ljubljana", xlabel="Month", ylabel="Temperature (°C)", xticks=MONTH_TICKS, xticklabels=MONTHS, figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.BOTH, ).show() ``` ### Area under the line To fill the area between the line and the bottom of the axes, add the `show_area` attribute. The fill takes the color of the line at a lower alpha; the `plot_area_color`, `plot_area_alpha` and `plot_area_hatch` style attributes from the [datachart.typings.AreaStyleAttrs](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/charts/linechart/%7BREF%7D/typings/#datachart.typings.AreaStyleAttrs) type override that. With the step draw style the fill follows the steps. ``` LineChart( data=temperature_ljubljana, style={ "plot_line_drawstyle": LINE_DRAW_STYLE.STEPS_MID, # make the fill a bit stronger than the theme default "plot_area_alpha": 0.35, }, title="Average monthly temperature in Ljubljana", xlabel="Month", ylabel="Temperature (°C)", xticks=MONTH_TICKS, xticklabels=MONTHS, figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.BOTH, # fill the area under the line show_area=True, ).show() ``` ### Emphasis When a chart carries several series, the story is often about one of them. The `emphasis` attribute expresses that directly: `"highlight"` thickens a line and brings it to the front, `"background"` mutes a line (the theme's muted color at a lower alpha, thinner and drawn behind the others), and `None` leaves a line unchanged. For multiple charts, `emphasis` is a list aligned with `data`, just like `subtitle` and `style`. Only emphasized-or-unset series appear in the legend — background lines drop out of it. The role strings are also available as the [datachart.constants.EMPHASIS](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.EMPHASIS) constants. The example highlights Ljubljana against the other two cities. See the [Highlighting](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/styling/highlighting/index.md) guide for how emphasis works across all chart types and themes. ``` LineChart( data=temperature_by_city, subtitle=CITIES, # highlight Ljubljana, mute the other cities emphasis=["highlight", "background", "background"], title="Average monthly temperature", xlabel="Month", ylabel="Temperature (°C)", xticks=MONTH_TICKS, xticklabels=MONTHS, figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.BOTH, show_legend=True, ).show() ``` ### Reference lines Reference lines mark a threshold or an event on the chart. **Horizontal lines.** Use the `hlines` argument with the [datachart.typings.HLinePlotAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.HLinePlotAttrs) typing, which is either a `dict` or a `List[dict]` where each dictionary contains some of the following attributes: ``` { "y": Union[int, float], # The y-axis value "xmin": Optional[Union[int, float]], # The minimum x-axis value "xmax": Optional[Union[int, float]], # The maximum x-axis value "style": { # The style of the line (optional) "plot_hline_color": Optional[str], # The color of the line (hex color code) "plot_hline_style": Optional[LineStyle], # The line style (solid, dashed, etc.) "plot_hline_width": Optional[float], # The width of the line "plot_hline_alpha": Optional[float], # The alpha of the line (how visible the line is) }, "label": Optional[str], # The label of the line (shown in the legend) } ``` **Vertical lines.** Use the `vlines` argument with the [datachart.typings.VLinePlotAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.VLinePlotAttrs) typing, which has the same shape with `x`, `ymin`, `ymax` and `plot_vline_*` style attributes. The `x` value is in data coordinates, so a line can sit anywhere along the axis — here between two months. The example marks the freezing point with a dashed horizontal line and the summer solstice (21 June) with a vertical line. The line labels appear in the legend. ``` LineChart( data=temperature_ljubljana, subtitle="Ljubljana", # add a horizontal line at the freezing point hlines={ "y": 0, "label": "freezing point", "style": { "plot_hline_color": "#1d3557", "plot_hline_style": LINE_STYLE.DASHED, "plot_hline_width": 1.5, }, }, # add a vertical line at the summer solstice vlines={ "x": 6.7, "label": "summer solstice", "style": { "plot_vline_color": "#e9a03b", "plot_vline_style": LINE_STYLE.DOTTED, "plot_vline_width": 1.5, }, }, title="Average monthly temperature in Ljubljana", xlabel="Month", ylabel="Temperature (°C)", xticks=MONTH_TICKS, xticklabels=MONTHS, figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.BOTH, show_legend=True, ).show() ``` ## Multiple Line Charts To create multiple line charts, pass a list of lists to the `data` argument. Each inner list represents the data for one line. Per-chart attributes like `subtitle`, `style` and `emphasis` can be passed as lists, where each element corresponds to a chart. Multiple charts pattern For multiple charts, `data` becomes a list of lists, and per-chart attributes like `subtitle` and `style` become lists where each element applies to the corresponding chart. The `temperature_by_city` dataset is such a list of lists, one series per city. A single `style` dictionary applies to every line; a list of dictionaries styles each line separately (`None` keeps the theme style for that line). ``` LineChart( # use a list of lists to define multiple lines data=temperature_by_city, # style can be a list (one per chart) or a single dict (applies to all) style=[ {"plot_line_marker": LINE_MARKER.CIRCLE}, {"plot_line_marker": LINE_MARKER.SQUARE}, None, # keep the theme style for the third line ], title="Average monthly temperature", xlabel="Month", ylabel="Temperature (°C)", xticks=MONTH_TICKS, xticklabels=MONTHS, figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.BOTH, ).show() ``` ### Sub-chart subtitles We can name each chart by passing a list of subtitles to the `subtitle` argument. In addition, to help with discerning which chart is which, use the `show_legend` argument to show the legend of the charts. ``` LineChart( data=temperature_by_city, # add a subtitle to each line subtitle=CITIES, title="Average monthly temperature", xlabel="Month", ylabel="Temperature (°C)", xticks=MONTH_TICKS, xticklabels=MONTHS, figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.BOTH, # show the legend show_legend=True, ).show() ``` ### Subplots To draw each chart in its own subplot, add the `subplots` attribute. The chart's `subtitle` are then added at the top of each subplot, while the `title`, `xlabel` and `ylabel` are positioned to be global for all charts. The `max_cols` attribute limits the number of subplots per row. ``` LineChart( data=temperature_by_city, subtitle=CITIES, title="Average monthly temperature", xlabel="Month", ylabel="Temperature (°C)", xticks=MONTH_TICKS, xticklabels=MONTHS, figsize=FIG_SIZE.FULL_MEDIUM, show_grid=SHOW_GRID.BOTH, # show each chart in its own subplot subplots=True, # at most two subplots per row max_cols=2, ).show() ``` ### Sharing the x-axis and/or y-axis across subplots To share the x-axis and/or y-axis across subplots, add the `sharex` and/or `sharey` attributes, which are boolean values that specify whether to share the axis across all subplots. With a shared y-axis, the cities become directly comparable — Reykjavik's flat curve no longer fills its subplot. ``` LineChart( data=temperature_by_city, subtitle=CITIES, title="Average monthly temperature", xlabel="Month", ylabel="Temperature (°C)", xticks=MONTH_TICKS, xticklabels=MONTHS, figsize=FIG_SIZE.FULL_MEDIUM, show_grid=SHOW_GRID.BOTH, subplots=True, max_cols=2, # share the x-axis across subplots sharex=True, # share the y-axis across subplots sharey=True, ).show() ``` ### Area under the lines Specifying the `show_area` attribute fills the area under each line. In a single chart the fills overlap, so the attribute is at its best with subplots. ``` LineChart( data=temperature_by_city, subtitle=CITIES, title="Average monthly temperature", xlabel="Month", ylabel="Temperature (°C)", xticks=MONTH_TICKS, xticklabels=MONTHS, figsize=FIG_SIZE.FULL_MEDIUM, show_grid=SHOW_GRID.BOTH, subplots=True, max_cols=2, sharex=True, sharey=True, # fill the area under the line in all subplots show_area=True, ).show() ``` ### Confidence interval If a line chart has a confidence interval, it can be added by adding the `yerr` attribute to the chart's `data` attribute. Afterwards, the `show_yerr` attribute can be set to `True` to draw the band between `y - yerr` and `y + yerr`. The `temperature_by_city` data points carry the year-to-year standard deviation of each monthly mean as `yerr`. The band is styled with the same `plot_area_*` attributes as the area under the line. ``` LineChart( data=temperature_by_city, subtitle=CITIES, title="Average monthly temperature", xlabel="Month", ylabel="Temperature (°C)", xticks=MONTH_TICKS, xticklabels=MONTHS, figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.BOTH, show_legend=True, # draw the confidence interval using the error values show_yerr=True, ).show() ``` ## Additional Features ### Axis scales The user can change the axis scale using the `scalex` and `scaley` attributes. The supported scale options are: | Options | Description | | ---------- | ------------------------ | | `"linear"` | The linear scale. | | `"log"` | The log scale. | | `"symlog"` | The symmetric log scale. | | `"asinh"` | The asinh scale. | Again, to help with the options settings, the [datachart.constants](https://eriknovak.github.io/datachart/0.9.0/references/constants/index.md) module contains the following constants: | Constant | Description | | ------------------------------------------------------------------------------------------------------------------------ | ----------------- | | [datachart.constants.SCALE](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.SCALE) | The axis options. | A logarithmic scale pays off when the values span several orders of magnitude. The hidden cell below defines `transistors`, the transistor count of a representative microprocessor per year from the Intel 4004 (1971) to the Apple M1 Ultra (2022) — Moore's law in sixteen data points, rounded from the manufacturers' figures. ``` from datachart.constants import SCALE ``` On a linear scale the first forty years collapse onto the x-axis; on a log scale the exponential growth becomes the straight line it is famous for. ``` for scale in [SCALE.LINEAR, SCALE.LOG]: figure = LineChart( data=transistors, style={"plot_line_marker": LINE_MARKER.CIRCLE}, title=f"Transistors per microprocessor on the '{scale}' scale", xlabel="Year", ylabel="Transistors", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.BOTH, # set the scale of the y axis scaley=scale, ) figure.show() ``` ### Custom data keys By default, the `data` items are dictionaries with the keys `x`, `y` and, optionally, `yerr`. Data that comes from elsewhere rarely uses those names, and renaming every key just to plot it is a chore. Instead, tell `LineChart` which keys to read with the `x`, `y` and `yerr` arguments. The `readings` list below stores the Ljubljana temperatures under `month` and `temperature`, with the deviation under `spread`. ``` readings = [ {"month": month, "temperature": temp, "spread": std} for month, temp, std in zip(MONTH_TICKS, TEMPERATURE["Ljubljana"], TEMPERATURE_STD["Ljubljana"]) ] readings[:3] ``` ``` figure = LineChart( data=readings, # specify which keys hold the x, y and error values x="month", y="temperature", yerr="spread", title="Average monthly temperature in Ljubljana", xlabel="Month", ylabel="Temperature (°C)", xticks=MONTH_TICKS, xticklabels=MONTHS, figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.BOTH, show_yerr=True, ) figure.show() ``` ## Saving the Chart as an Image To save the chart as an image, use the [datachart.utils.save_figure](https://eriknovak.github.io/datachart/0.9.0/references/utils#datachart.utils.save_figure) function. ``` from datachart.utils import save_figure ``` ``` save_figure(figure, "./fig_line_chart.png", dpi=300) ``` The figure should be saved in the current working directory. ## Real-World Examples The following examples put the features above to work on real or realistic data. Each one states what its data is and where it comes from; the data itself lives in a hidden cell. ### Example 1: ROC Curve (Custom Data Keys and Equal Aspect Ratio) `roc_curves` holds the receiver operating characteristic of two illustrative binary classifiers: each point is the false positive rate (`fp`) and true positive rate (`tp`) at one decision threshold, so the keys are mapped with the `x` and `y` arguments. A ROC curve is read against the diagonal, so the subplots share an equal aspect ratio (`aspect_ratio`) and the area under each curve — the AUC — is filled with a hatch pattern. ``` from datachart.constants import ASPECT_RATIO, HATCH_STYLE ``` ``` LineChart( data=roc_curves, subtitle=list(ROC_POINTS), # the points are stored as "fp" and "tp", instead of "x" and "y" x="fp", y="tp", # hatch the area under each curve (a single style applies to every chart) style={"plot_area_hatch": HATCH_STYLE.DIAGONAL}, title="ROC curve", xlabel="False positive rate", ylabel="True positive rate", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.BOTH, xmin=0, xmax=1, ymin=0, ymax=1, show_area=True, subplots=True, sharex=True, sharey=True, # keep one unit the same length on both axes aspect_ratio=ASPECT_RATIO.EQUAL, ).show() ``` ### Example 2: Training Loss (Confidence Interval on a Log Scale) `training_loss` holds the validation loss of three illustrative training methods, evaluated every five steps over 200 steps and averaged over several runs; `spread` is the standard deviation across the runs. The loss decays exponentially toward a floor, so the y-axis uses a log scale to keep the late-training differences readable, and `show_yerr` draws the run-to-run spread as a band around each mean. ``` LineChart( data=training_loss, subtitle=list(LOSS_CURVES), # the points are stored as "step", "loss" and "spread" x="step", y="loss", yerr="spread", title="Validation loss during training", xlabel="Training step", ylabel="Validation loss", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, show_legend=True, # draw the run-to-run spread as a band show_yerr=True, # depict the y-axis as a log scale scaley=SCALE.LOG, ).show() ``` ### Example 3: One Index Among Many (Emphasis) `sector_indices` holds the illustrative performance of five stock market sector indices over three years, sampled quarterly and rebased to 100 at the end of 2022. The question is how the technology sector did against the market, so `emphasis` highlights it and mutes the other four. Muted indices drop out of the legend automatically. ``` LineChart( data=sector_indices, subtitle=list(SECTOR_INDEX), # highlight Technology, mute the other sectors emphasis=["highlight", "background", "background", "background", "background"], title="Sector indices, rebased to 100", xlabel="Quarter", ylabel="Index level", # the x values are quarter offsets; label them with the quarter names xticks=list(range(len(QUARTERS))), xticklabels=QUARTERS, xtickrotate=45, figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, show_legend=True, ).show() ``` ### Example 4: Website Traffic (Reference Lines) `weekly_visitors` holds the illustrative weekly unique visitors of a website over sixteen weeks. A marketing campaign launched in week 7, and the hosting plan is sized for 60,000 weekly visitors. A vertical line marks the launch and a horizontal line the capacity, so the chart answers both "did the campaign work" and "when do we need to upgrade" at a glance. ``` LineChart( data=weekly_visitors, subtitle="unique visitors", style={"plot_line_marker": LINE_MARKER.CIRCLE}, # mark the campaign launch vlines={ "x": CAMPAIGN_WEEK, "label": "campaign launch", "style": { "plot_vline_color": "#2a9d8f", "plot_vline_style": LINE_STYLE.DASHED, "plot_vline_width": 1.5, }, }, # mark the hosting capacity hlines={ "y": CAPACITY, "label": "hosting capacity", "style": { "plot_hline_color": "#c1121f", "plot_hline_style": LINE_STYLE.DOTTED, "plot_hline_width": 1.5, }, }, title="Weekly website visitors", xlabel="Week", ylabel="Visitors (thousands)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, show_legend=True, ymin=0, ).show() ``` # Stacked Area Chart This section showcases the stacked area chart. It contains examples of how to create stacked area charts using the [datachart.charts.StackedAreaChart](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.StackedAreaChart) function. Looking for a specific customization? Jump straight to the [quick reference](#customizing-the-stacked-area-chart), which maps common tasks to the parameter or style attribute that does the job. As mentioned above, the stacked area charts are created using the `StackedAreaChart` function found in the [datachart.charts](https://eriknovak.github.io/datachart/0.9.0/references/charts/index.md) module. Let's import it: ``` from datachart.charts import StackedAreaChart ``` ## Stacked Area Chart Input Attributes The `StackedAreaChart` function accepts keyword arguments for chart configuration. The main argument is `data`, which contains the series to stack. For a single band, `data` is a list of data points; for a stack of several series, `data` is a list of such lists — every series must hold the same `x` values in the same order, as the bands sit on top of one another point by point. ``` StackedAreaChart( data=[ # The series to stack, first at the bottom (or one list of points for a single band) [ { "x": Union[int, float], # The x-axis value "y": Union[int, float], # The y-axis value }, ... ], ... ], baseline=Optional[str], # Where the first series starts: "zero" (default), "percent", "sym", "wiggle", or "weighted_wiggle" style={ # The style of the bands (optional; a list for multiple series) "plot_area_color": Optional[str], # The fill color of the band "plot_area_hatch": Optional[str], # The hatch pattern of the band "plot_area_zorder": Optional[int], # The zorder of the band "plot_stackedarea_alpha": Optional[float], # The alpha of the band (0.8 by default) "plot_stackedarea_outline": Optional[bool], # Whether to draw the top edge of the band as a line (False by default) "plot_line_color": Optional[str], # The outline color "plot_line_width": Optional[float], # The outline width "plot_line_style": Optional[str], # The outline style }, subtitle=Optional[str], # The series name, used in the legend (or list for multiple series) emphasis=Optional[str], # "highlight" or "background" (or list for multiple series) title=Optional[str], # The chart title xlabel=Optional[str], # The x-axis label ylabel=Optional[str], # The y-axis label figsize=Optional[Tuple[float, float]], # The figure size show_legend=Optional[bool], # Whether to show the legend show_grid=Optional[str], # Which grid lines to show subplots=Optional[bool], # Whether to draw each series unstacked in its own subplot max_cols=Optional[int], # The maximum number of subplot columns sharex=Optional[bool], # Whether the subplots share the x-axis sharey=Optional[bool], # Whether the subplots share the y-axis xmin=Optional[float], # The minimum x-axis value xmax=Optional[float], # The maximum x-axis value ymin=Optional[float], # The minimum y-axis value ymax=Optional[float], # The maximum y-axis value scalex=Optional[str], # The x-axis scale scaley=Optional[str], # The y-axis scale vlines=Optional[Union[dict, List[dict]]], # The vertical reference lines hlines=Optional[Union[dict, List[dict]]], # The horizontal reference lines texts=Optional[Union[dict, List[dict]]], # The text annotations x=Optional[str], # The key holding the x-axis value (default: "x") y=Optional[str], # The key holding the y-axis value (default: "y") ) ``` For more details, see the [datachart.charts.StackedAreaChart](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.StackedAreaChart) function. ## Basics The examples in this guide share one dataset: the world's electricity generation by source, in terawatt-hours per year from 2000 to 2023 — coal, gas, nuclear, hydro, wind, solar, and everything else (oil, bioenergy, geothermal). The values are rounded from the annual figures published by Ember's *Global Electricity Review* and the Energy Institute's *Statistical Review of World Energy*, and live in the hidden cell below. Generation is a textbook part-to-whole-over-time story: the total more than doubled while the mix underneath it shifted, and a stacked area chart shows both at once. The data is a list of series, one per source, in the order they stack — the first series sits at the bottom. Every series is a list of `{x, y}` points with the year as `x` and the generation as `y`, and all of them share the same years: ``` {source: points[:3] for source, points in zip(SOURCES, generation)} ``` **Basic example.** Only the `data` argument is required to draw the stacked area chart. Each source fills the band between the sources below it and its own share, so the top edge of the stack traces the world's total generation, and the y-axis starts at zero where the stack does. ``` StackedAreaChart( # add the data to the chart data=generation ).show() ``` ## Customizing the Stacked Area Chart Every customization is either a keyword argument of `StackedAreaChart` or a `plot_*` attribute of its `style` dictionary. The table maps common tasks to the one you need and links to the subsection that shows it. | I want to… | Use | See | | ------------------------------------------- | --------------------------------------------------------------- | --------------------------------------------------- | | add a title and axis labels | `title`, `xlabel`, `ylabel` | [Title and axis labels](#title-and-axis-labels) | | name the series in a legend | `subtitle`, `show_legend` | [Legend](#legend) | | resize the figure | `figsize` | [Figure size and grid](#figure-size-and-grid) | | show the grid lines | `show_grid` | [Figure size and grid](#figure-size-and-grid) | | show shares instead of totals | `baseline="percent"` | [Baseline](#baseline) | | centre the stack or draw a streamgraph | `baseline="sym"`, `"wiggle"`, `"weighted_wiggle"` | [Baseline](#baseline) | | change the band colors, alpha, or hatch | `style={"plot_area_color": ..., "plot_stackedarea_alpha": ...}` | [Band style](#band-style) | | outline the top of every band | `style={"plot_stackedarea_outline": True}` | [Band style](#band-style) | | highlight one series, mute the rest | `emphasis` | [Emphasis](#emphasis) | | mark a year or a level | `vlines`, `hlines` | [Reference lines](#reference-lines) | | annotate a point of the chart | `texts` | [Text annotations](#text-annotations) | | draw every series on its own | `subplots` | [Subplots](#subplots) | | overlay the total or arrange several stacks | `Panel`, `Grid` | [Composing stacked areas](#composing-stacked-areas) | ### Title and axis labels To add the chart title and axis labels, add the `title`, `xlabel` and `ylabel` attributes. ``` StackedAreaChart( data=generation, # add the title title="World electricity generation", # add the x and y axis labels xlabel="Year", ylabel="Generation (TWh)", ).show() ``` ### Legend To name the series, add the `subtitle` attribute with one name per series; the `show_legend` attribute then lists them. The legend follows the input order — the first series, at the bottom of the stack, comes first. ``` StackedAreaChart( data=generation, # name the series; the legend lists them bottom to top subtitle=SOURCES, show_legend=True, title="World electricity generation", xlabel="Year", ylabel="Generation (TWh)", ).show() ``` ### Figure size and grid To change the figure size, add the `figsize` attribute. The `figsize` attribute can be a tuple (width, height), values are in inches. The `datachart` package provides a [datachart.constants.FIG_SIZE](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.FIG_SIZE) constant, which contains predefined figure sizes. To change which grid lines show, add the `show_grid` attribute, which supports the values of the [datachart.constants.SHOW_GRID](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.SHOW_GRID) constant. ``` from datachart.constants import FIG_SIZE, SHOW_GRID ``` ``` StackedAreaChart( data=generation, subtitle=SOURCES, show_legend=True, title="World electricity generation", xlabel="Year", ylabel="Generation (TWh)", # add to determine the figure size figsize=FIG_SIZE.FULL_MEDIUM, # add to show the grid lines on both axes show_grid=SHOW_GRID.BOTH, ).show() ``` ### Baseline The `baseline` attribute picks where the first series starts, and so what the stack shows; the supported values are in the [datachart.constants.BASELINE](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.BASELINE) constant. The default, `ZERO`, stacks from zero so the top edge is the total. `PERCENT` normalises every year to 100, so the bands show each source's share of the mix and the total disappears — the chart to read when the question is "how has the mix changed", not "how much is generated". ``` from datachart.constants import BASELINE ``` ``` StackedAreaChart( data=generation, # every year sums to 100: the bands are shares baseline=BASELINE.PERCENT, subtitle=SOURCES, show_legend=True, title="World electricity mix", xlabel="Year", ylabel="Share (%)", figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` The remaining baselines centre the stack instead of resting it on zero. `SYM` centres it on the x-axis; `WIGGLE` and `WEIGHTED_WIGGLE` pick, at every x, the baseline that keeps the bands flattest — the streamgraph look, which reads best when the series are many and the total matters little. Only the ZERO and PERCENT baselines pin the y-axis at zero; the others keep the usual margin around the stack. ``` StackedAreaChart( data=generation, # a streamgraph: the baseline wiggles to flatten the bands baseline=BASELINE.WEIGHTED_WIGGLE, subtitle=SOURCES, show_legend=True, title="World electricity generation", xlabel="Year", ylabel="Generation (TWh)", figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` ### Band style To change the band style, add the `style` attribute with the corresponding attributes. The supported attributes are shown in the [datachart.typings.StackedAreaStyleAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.StackedAreaStyleAttrs) typing: the fill takes the `plot_area_*` color, hatch and zorder, its alpha comes from `plot_stackedarea_alpha`, and `plot_stackedarea_outline` draws the top edge of every band as a line in the `plot_line_*` style. A single dictionary applies to every series; a list, aligned with `data`, styles each on its own. The example groups the fossil sources in warm colors and the low-carbon ones in cool colors, with outlines to separate the bands. ``` FOSSIL, CLEAN = "#C8553D", "#2E86AB" StackedAreaChart( data=generation, # one style per series: fossil sources warm, the rest cool style=[ {"plot_area_color": color, "plot_stackedarea_outline": True, "plot_line_width": 0.8} for color in (FOSSIL, "#E8975A", CLEAN, "#5FA8D3", "#8ACBE6", "#B8E0F0", "#9E9E9E") ], subtitle=SOURCES, show_legend=True, title="World electricity generation", xlabel="Year", ylabel="Generation (TWh)", figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` ### Emphasis When a stack carries several series, the story is often about one of them. The `emphasis` attribute expresses that directly: `"highlight"` brings a band to the front, `"background"` mutes it (the theme's muted color at a lower alpha, dropped from the legend), and `None` leaves it unchanged. `emphasis` is a list aligned with `data`, just like `subtitle` and `style`; the role strings are also available as the [datachart.constants.EMPHASIS](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.EMPHASIS) constants. The stack itself does not change — a muted band keeps its place, so the bands above it stay where they were. The example highlights wind and solar against the rest of the mix. See the [Highlighting](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/styling/highlighting/index.md) guide for how emphasis works across all chart types and themes. ``` from datachart.constants import EMPHASIS ``` ``` StackedAreaChart( data=generation, baseline=BASELINE.PERCENT, # mute everything but wind and solar emphasis=[ EMPHASIS.HIGHLIGHT if source in ("Wind", "Solar") else EMPHASIS.BACKGROUND for source in SOURCES ], subtitle=SOURCES, show_legend=True, title="Wind and solar in the world electricity mix", xlabel="Year", ylabel="Share (%)", figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` ### Reference lines A reference line marks a position on the chart. To add vertical lines, add the `vlines` attribute with the [datachart.typings.VLinePlotAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.VLinePlotAttrs) typing; for horizontal lines, add the `hlines` attribute with the [datachart.typings.HLinePlotAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.HLinePlotAttrs) typing. The lines below mark the 2015 Paris Agreement and the 2020 pandemic dip, and the level of total generation in 2000. Both attributes take a `style` dictionary; the [datachart.constants.LINE_STYLE](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.LINE_STYLE) constant holds the line styles. A single line or list of lines applies to every series, so a stack of seven would draw each line seven times; a list aligned with `data` attaches the lines to one series — here the first — and draws them once. ``` from datachart.constants import LINE_STYLE ``` ``` StackedAreaChart( data=generation, subtitle=SOURCES, show_legend=True, # mark two years and the 2000 total, attached to the first series only vlines=[ [ {"x": 2015, "label": "Paris Agreement", "style": {"plot_vline_style": LINE_STYLE.DASHED}}, {"x": 2020, "label": "COVID-19", "style": {"plot_vline_style": LINE_STYLE.DOTTED}}, ] ] + [None] * (len(SOURCES) - 1), hlines=[{"y": sum(values[0] for values in GENERATION.values()), "label": "2000 total"}] + [None] * (len(SOURCES) - 1), title="World electricity generation", xlabel="Year", ylabel="Generation (TWh)", figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` ### Text annotations To place text on the chart, add the `texts` attribute with the [datachart.typings.TextAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.TextAttrs) typing. Each annotation sets its `text` and position, in data coordinates by default or in axes fractions with `"coords": "axes"`, and an optional `target` point to draw a connector to. The annotation below points at the year solar generation passed 1,000 TWh. ``` SOLAR_1000 = next(year for year, twh in zip(YEARS, GENERATION["Solar"]) if twh >= 1000) # the top of the solar band that year: everything stacked below it plus solar itself solar_top = sum(GENERATION[source][YEARS.index(SOLAR_1000)] for source in SOURCES[: SOURCES.index("Solar") + 1]) StackedAreaChart( data=generation, subtitle=SOURCES, show_legend=True, # point at the year solar passed 1,000 TWh texts={ "text": f"solar passes 1,000 TWh ({SOLAR_1000})", "x": 0.35, "y": 0.9, "coords": "axes", "target": (SOLAR_1000, solar_top), }, title="World electricity generation", xlabel="Year", ylabel="Generation (TWh)", figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` ## Multiple Stacked Area Charts ### Subplots A stacked area chart is already a multi-series chart; the `subplots` attribute takes the stack apart instead, drawing each series unstacked in its own subplot, from zero, so the sources can be compared at their own scale. The `subtitle` becomes the subplot title and the `title`, `xlabel` and `ylabel` are positioned to be global for all charts. The `max_cols` attribute limits the number of columns, and `sharex` and `sharey` share an axis across the subplots; a shared axis is labeled once, on the outer subplots only. ``` StackedAreaChart( data=generation, subtitle=SOURCES, # one series per subplot, unstacked subplots=True, max_cols=4, sharex=True, sharey=True, title="World electricity generation by source", xlabel="Year", ylabel="Generation (TWh)", figsize=(12, 5), ).show() ``` ### Composing stacked areas A stacked area figure composes like any other chart. [datachart.utils.Panel](https://eriknovak.github.io/datachart/0.9.0/references/utils/#datachart.utils.Panel) overlays it with other charts on shared axes — the natural pairing is a [datachart.charts.LineChart](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.LineChart) of a related total or target drawn over the stack. Other charts in the panel sit on top of the stack without joining it; the panel keeps the stack's baseline. The line below is the low-carbon total — nuclear, hydro, wind and solar together — over the full mix. ``` from datachart.charts import LineChart from datachart.utils import Panel LOW_CARBON = ["Nuclear", "Hydro", "Wind", "Solar"] low_carbon = [ {"x": year, "y": sum(GENERATION[source][i] for source in LOW_CARBON)} for i, year in enumerate(YEARS) ] stack = StackedAreaChart(data=generation, subtitle=SOURCES) total = LineChart( data=low_carbon, subtitle="Low-carbon total", style={"plot_line_color": "#1F1F1F", "plot_line_style": LINE_STYLE.DASHED}, ) Panel( [stack, total], title="World electricity generation", xlabel="Year", ylabel_left="Generation (TWh)", show_legend=True, figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` [datachart.utils.Grid](https://eriknovak.github.io/datachart/0.9.0/references/utils/#datachart.utils.Grid) arranges stacked area figures next to other figures. The generation spans the top row; the mix in percent and a bar chart of the 2023 generation share the bottom one. ``` from datachart.charts import BarChart from datachart.utils import Grid top = StackedAreaChart(data=generation, subtitle=SOURCES, title="Generation (TWh)", show_legend=True) left = StackedAreaChart( data=generation, baseline=BASELINE.PERCENT, subtitle=SOURCES, title="Mix (%)" ) right = BarChart( data=[{"label": source, "y": GENERATION[source][-1]} for source in SOURCES], title="2023 generation (TWh)", show_values=False, ) Grid([[top], [left, right]], xlabel="Year", figsize=(10, 7)).show() ``` ## Additional Features ### Custom data keys By default the chart reads the `x` and `y` keys of every point. When the data uses other names, add the `x` and `y` attributes with the key names — the hidden cell below holds the same generation as `year`/`twh` records. ``` StackedAreaChart( data=records, # read the year and twh keys instead of x and y x="year", y="twh", subtitle=SOURCES, show_legend=True, title="World electricity generation", xlabel="Year", ylabel="Generation (TWh)", figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` ### Themes A theme sets the palette, the band alpha and the furniture of every chart at once; see the [Theme Gallery](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/styling/theme-gallery.ipynb) for the whole suite under each. Apply one with [datachart.config.Config.set_theme](https://eriknovak.github.io/datachart/0.9.0/references/config/#datachart.config.Config.set_theme) from the [datachart.constants.THEME](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.THEME) constant, and reset the configuration afterwards so the following charts draw in the default again. ``` from datachart.config import config from datachart.constants import THEME config.set_theme(THEME.INK) figure = StackedAreaChart( data=generation, subtitle=SOURCES, show_legend=True, title="World electricity generation", xlabel="Year", ylabel="Generation (TWh)", figsize=FIG_SIZE.FULL_MEDIUM, ) config.reset_config() figure.show() ``` ## Saving the Chart as an Image To save the chart as an image, use the [datachart.utils.save_figure](https://eriknovak.github.io/datachart/0.9.0/references/utils#datachart.utils.save_figure) function. ``` from datachart.utils import save_figure figure = StackedAreaChart( data=generation, subtitle=SOURCES, show_legend=True, title="World electricity generation", xlabel="Year", ylabel="Generation (TWh)", ) save_figure(figure, "./fig_stacked_area_chart.png", dpi=300) ``` The figure should be saved in the current working directory. ## Real-World Examples The following examples put the features above to work on the generation data. Each one states what it shows; any derived data lives in a hidden cell. ### Example 1: Fossil Versus Low-Carbon Generation (Grouped Series, Percent Baseline, and Emphasis) The seven sources collapse into three groups in the hidden cell — fossil (coal, gas), low-carbon (nuclear, hydro, wind, solar), and other — and the percent baseline turns them into shares. With the fossil band highlighted and the rest muted, the chart makes one point: the fossil share of the world's electricity has barely moved in two decades, because generation grew as fast as the low-carbon sources did. A reference line at 50 % and an annotation on the 2023 fossil share anchor the reading. ``` StackedAreaChart( data=grouped, baseline=BASELINE.PERCENT, subtitle=list(GROUPS), emphasis=[EMPHASIS.HIGHLIGHT, EMPHASIS.BACKGROUND, EMPHASIS.BACKGROUND], show_legend=True, hlines={"y": 50, "style": {"plot_hline_style": LINE_STYLE.DASHED}}, texts={ "text": f"fossil: {FOSSIL_2023:.0f}% in 2023", "x": 0.6, "y": 0.3, "coords": "axes", "target": (2023, FOSSIL_2023), }, title="Fossil share of world electricity", xlabel="Year", ylabel="Share (%)", figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` ### Example 2: The Rise of Wind and Solar (Streamgraph, Outlines, and a Grid) Wind and solar are the two sources that grew from nothing, and a streamgraph — the weighted-wiggle baseline — shows growth by band thickness without a total to distract from it. The grid pairs the streamgraph of the two sources with their share of the world's electricity on the percent baseline, the bands outlined so the thin early years stay visible. ``` outlined = {"plot_stackedarea_outline": True, "plot_line_width": 1.0} stream = StackedAreaChart( data=renewables, baseline=BASELINE.WEIGHTED_WIGGLE, subtitle=["Wind", "Solar"], style=outlined, title="Wind and solar generation (TWh)", show_legend=True, ) share = StackedAreaChart( data=renewable_shares, subtitle=["Wind", "Solar"], style=outlined, title="Share of world electricity (%)", ) Grid([[stream, share]], xlabel="Year", figsize=(12, 4)).show() ``` # Bar Chart This section showcases the bar chart. It contains examples of how to create the bar chart using the [datachart.charts.BarChart](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.BarChart) function. Looking for a specific customization? Jump straight to the [quick reference](#customizing-the-bar-chart), which maps common tasks to the parameter or style attribute that does the job. As mentioned above, the bar charts are created using the `BarChart` function found in the [datachart.charts](https://eriknovak.github.io/datachart/0.9.0/references/charts/index.md) module. Let's import it: ``` from datachart.charts import BarChart ``` ## Bar Chart Input Attributes The `BarChart` function accepts keyword arguments for chart configuration. The main argument is `data`, which contains the data points. For a single bar chart, `data` is a list of dictionaries. For multiple bar charts, `data` is a list of lists. ``` BarChart( data=[{ # A list of bar data points (or list of lists for multiple charts) "label": str, # The x-axis value "y": Union[int, float], # The y-axis value "yerr": Optional[Union[int, float]] # The y-axis error value }], style={ # The style of the bar (optional) "plot_bar_color": Union[str, None], # The color of the bar "plot_bar_alpha": Union[float, None], # The alpha of the bar "plot_bar_width": Union[int, float, None], # The width of the bar "plot_bar_zorder": Union[int, float, None], # The z-order of the bar "plot_bar_hatch": Union[HATCH_STYLE, None], # The hatch style of the bar "plot_bar_edge_width": Union[int, float, None], # The edge line width of the edge "plot_bar_edge_color": Union[str, None], # The edge line color "plot_bar_error_color": Union[str, None], # The error line color "plot_bar_value_fontsize": Union[int, float, None], # The font size of bar value labels "plot_bar_value_color": Union[str, None], # The color of bar value labels "plot_bar_value_padding": Union[int, float, None], # The padding between bar and value label }, subtitle=Optional[str], # The subtitle of the chart (or list for multiple charts) emphasis=Optional[str], # "highlight" or "background" (or list for multiple charts) title=Optional[str], # The title of the chart xlabel=Optional[str], # The x-axis label ylabel=Optional[str], # The y-axis label figsize=Optional[Tuple[float, float]], # The figure size in inches show_grid=Optional[str], # Which grid lines to show ("both", "x", "y") aspect_ratio=Optional[str], # The aspect ratio of the axes ("auto", "equal") show_legend=Optional[bool], # Whether to show the legend orientation=Optional[str], # "vertical" (default) or "horizontal" bar_mode=Optional[str], # How multiple series share the axis ("group", "stack", "overlay") show_yerr=Optional[bool], # Whether to show the error bars show_values=Optional[bool], # Whether to show bar value labels value_format=Optional[str], # Format of the value labels (VALUE_FORMAT constant or e.g. "{:.1f}%") subplots=Optional[bool], # Whether to draw each chart in its own subplot max_cols=Optional[int], # Maximum number of subplots per row sharex=Optional[bool], # Whether subplots share the x-axis sharey=Optional[bool], # Whether subplots share the y-axis scalex=Optional[str], # The x-axis scale ("linear", "log", "symlog", "asinh") scaley=Optional[str], # The y-axis scale ("linear", "log", "symlog", "asinh") xmin=Optional[Union[int, float]], # The x-axis range xmax=Optional[Union[int, float]], ymin=Optional[Union[int, float]], # The y-axis range ymax=Optional[Union[int, float]], xticks=Optional[List[Union[int, float]]], # the x-axis ticks xticklabels=Optional[List[str]], # the x-axis tick labels (must be same length as xticks) xtickrotate=Optional[int], # the x-axis tick labels rotation yticks=Optional[List[Union[int, float]]], # the y-axis ticks yticklabels=Optional[List[str]], # the y-axis tick labels (must be same length as yticks) ytickrotate=Optional[int], # the y-axis tick labels rotation vlines=Optional[Union[dict, List[dict]]], # the vertical lines hlines=Optional[Union[dict, List[dict]]], # the horizontal lines ) ``` For more details, see the [datachart.charts.BarChart](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.BarChart) function. ## Basics The examples in this guide share one dataset: the monthly unit sales of a product in 2025, broken down by sales region. The data is hard-coded in a hidden cell; `sales_total` holds the company-wide monthly totals, `sales_by_region` holds one series per region (with the day-to-day standard deviation of daily sales as `yerr`), and `SALES_GOAL` is the monthly target. Each data point is a dictionary with a `label` (the category) and a `y` value: ``` sales_total[:3] ``` **Basic example.** Only the `data` argument is required to draw the bar chart. ``` BarChart( # add the data to the chart data=sales_total ).show() ``` ## Customizing the Bar Chart Every customization is either a keyword argument of `BarChart` or a `plot_bar_*` attribute of its `style` dictionary. The table maps common tasks to the one you need and links to the subsection that shows it. | I want to… | Use | See | | ----------------------------------- | ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- | | add a title and axis labels | `title`, `xlabel`, `ylabel` | [Title, axis labels and ticks](#title-axis-labels-and-ticks) | | rotate the tick labels | `xtickrotate`, `ytickrotate` | [Title, axis labels and ticks](#title-axis-labels-and-ticks) | | fix the axis range | `xmin`, `xmax`, `ymin`, `ymax` | [Title, axis labels and ticks](#title-axis-labels-and-ticks) | | resize the figure | `figsize` | [Figure size and grid](#figure-size-and-grid) | | show grid lines | `show_grid` | [Figure size and grid](#figure-size-and-grid) | | fix the aspect ratio of the axes | `aspect_ratio` | [Figure size and grid](#figure-size-and-grid) | | change the bar color | `style={"plot_bar_color": ...}` | [Bar style](#bar-style) | | change the bar width | `style={"plot_bar_width": ...}` | [Bar style](#bar-style) | | make the bars (semi-)transparent | `style={"plot_bar_alpha": ...}` | [Bar style](#bar-style) | | add a hatch pattern | `style={"plot_bar_hatch": ...}` | [Bar style](#bar-style) | | outline the bars | `style={"plot_bar_edge_color": ..., "plot_bar_edge_width": ...}` | [Bar style](#bar-style) | | draw horizontal bars | `orientation` | [Bar orientation](#bar-orientation) | | highlight one series, mute the rest | `emphasis` | [Emphasis](#emphasis) | | mark a goal, threshold or event | `hlines`, `vlines` | [Reference lines](#reference-lines) | | compare several series side by side | `data` as a list of lists, `subtitle`, `show_legend` | [Multiple Bar Charts](#multiple-bar-charts) | | stack or overlay the series | `bar_mode` | [Bar mode](#bar-mode) | | draw each series in its own subplot | `subplots`, `sharex`, `sharey`, `max_cols` | [Subplots](#subplots) | | add error bars | `yerr` in `data`, `show_yerr`, `style={"plot_bar_error_color": ...}` | [Error bars](#error-bars) | | print the value on each bar | `show_values` | [Bar value labels](#bar-value-labels) | | format the printed values | `value_format` (a `VALUE_FORMAT` constant or a format string) | [Bar value labels](#bar-value-labels) | | style the value labels | `style={"plot_bar_value_fontsize": ..., "plot_bar_value_color": ..., "plot_bar_value_padding": ...}` | [Bar value labels](#bar-value-labels) | | use a logarithmic axis | `scaley`, `scalex` | [Axis scales](#axis-scales) | | save the chart to a file | `save_figure` | [Saving the Chart as an Image](#saving-the-chart-as-an-image) | The full list of style attributes is in the [datachart.typings.BarStyleAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.BarStyleAttrs) type; the full list of parameters is in the [datachart.charts.BarChart](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.BarChart) reference. ### Title, axis labels and ticks To add the chart title and axis labels, add the `title`, `xlabel` and `ylabel` attributes. Tick labels can be rotated with `xtickrotate` (or `ytickrotate`), and the axis range can be fixed with `xmin`, `xmax`, `ymin` and `ymax` — here the y-axis is pinned to start at zero so the bar heights stay comparable. ``` BarChart( data=sales_total, # add the title title="Monthly unit sales (2025)", # add the x and y axis labels xlabel="Month", ylabel="Units sold", # rotate the x-axis tick labels xtickrotate=45, # fix the y-axis range ymin=0, ymax=2000, ).show() ``` ### Figure size and grid To change the figure size, add the `figsize` attribute. The `figsize` attribute can be a tuple (width, height), values are in inches. The `datachart` package provides a [datachart.constants.FIG_SIZE](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.FIG_SIZE) constant, which contains some of the predefined figure sizes. To add the grid, add the `show_grid` attribute. The possible options are: | Option | Description | | -------- | ----------------------------------------------- | | `"both"` | shows both the x-axis and the y-axis gridlines. | | `"x"` | shows only the x-axis grid lines. | | `"y"` | shows only the y-axis grid lines. | Again, `datachart` provides a [datachart.constants.SHOW_GRID](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.SHOW_GRID) constant, which contains the supported options. Related is the `aspect_ratio` attribute, which fixes the aspect ratio of the axes rather than of the figure: `"auto"` (the default) lets the axes fill the figure, `"equal"` keeps one data unit the same length on both axes. The supported values are in the [datachart.constants.ASPECT_RATIO](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.ASPECT_RATIO) constant. Bar charts rarely need it, so the examples leave it at the default. ``` from datachart.constants import FIG_SIZE, SHOW_GRID ``` ``` BarChart( data=sales_total, title="Monthly unit sales (2025)", xlabel="Month", ylabel="Units sold", # add to determine the figure size figsize=FIG_SIZE.FULL_SHORT, # add to show the grid lines show_grid=SHOW_GRID.Y, ).show() ``` ### Bar style To change the bar style, add the `style` attribute with the corresponding attributes. The supported attributes are shown in the [datachart.typings.BarStyleAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.BarStyleAttrs) type, which contains the following attributes: | Attribute | Description | | --------------------------- | ----------------------------------------------------------------------------- | | `"plot_bar_color"` | The color of the bar (hex color code). | | `"plot_bar_alpha"` | The alpha of the bar (how visible the bar is). | | `"plot_bar_width"` | The width of the bar (as a fraction of the category width, `0.8` by default). | | `"plot_bar_zorder"` | The zorder of the bar. | | `"plot_bar_hatch"` | The hatch style of the bar. | | `"plot_bar_edge_width"` | The edge line width of the edge. | | `"plot_bar_edge_color"` | The edge line color (hex color code). | | `"plot_bar_error_color"` | The error line color (hex color code). | | `"plot_bar_value_fontsize"` | The font size of bar value labels. | | `"plot_bar_value_color"` | The color of bar value labels (hex color code). | | `"plot_bar_value_padding"` | The padding between bar edge and value label. | Again, to help with the style settings, the [datachart.constants](https://eriknovak.github.io/datachart/0.9.0/references/constants/index.md) module contains the following constants: | Constant | Description | | ------------------------------------------------------------------------------------------------------------------------------------ | --------------------------- | | [datachart.constants.HATCH_STYLE](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.HATCH_STYLE) | The hatch style of the bar. | The example below changes the color, alpha, width, hatch pattern and outline of the bars in one go. Any attribute you leave out keeps the value of the active theme. ``` from datachart.constants import HATCH_STYLE ``` ``` BarChart( data=sales_total, # define the style of the bars style={ "plot_bar_color": "#2a9d8f", "plot_bar_alpha": 0.8, "plot_bar_width": 0.6, "plot_bar_hatch": HATCH_STYLE.DIAGONAL, "plot_bar_edge_width": 1.0, "plot_bar_edge_color": "#264653", }, title="Monthly unit sales (2025)", xlabel="Month", ylabel="Units sold", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, ).show() ``` ### Bar orientation To change the orientation of the bars, add the `orientation` attribute, which supports the following values: | Value | Description | | -------------- | ------------------------ | | `"horizontal"` | The bars are horizontal. | | `"vertical"` | The bars are vertical. | Again, to help with the style settings, the [datachart.constants](https://eriknovak.github.io/datachart/0.9.0/references/constants/index.md) module contains the following constants: | Constant | Description | | ------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------- | | [datachart.constants.ORIENTATION](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.ORIENTATION) | The orientation of the bars. | With horizontal bars the categories run along the y-axis, so swap the axis labels and the grid accordingly. ``` from datachart.constants import ORIENTATION ``` ``` BarChart( data=sales_total, title="Monthly unit sales (2025)", # swap the axis labels to match the orientation xlabel="Units sold", ylabel="Month", figsize=FIG_SIZE.FULL_MEDIUM, # change the grid to match the change in orientation show_grid=SHOW_GRID.X, # change the orientation of the bars orientation=ORIENTATION.HORIZONTAL, ).show() ``` ### Emphasis When a chart carries several series, the story is often about one of them. The `emphasis` attribute expresses that directly: `"highlight"` bolds a series' edges and brings it to the front, `"background"` mutes a series (the theme's muted color at a lower alpha, drawn behind the others and left out of the legend), and `None` leaves a series unchanged. For multiple charts, `emphasis` is a list aligned with `data`, just like `subtitle` and `style`. The role strings are also available as the [datachart.constants.EMPHASIS](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.EMPHASIS) constants. The example highlights the Asia-Pacific region against the other two. See the [Highlighting](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/styling/highlighting/index.md) guide for how emphasis works across all chart types and themes. ``` BarChart( data=sales_by_region, subtitle=REGIONS, # highlight one region, mute the rest emphasis=["background", "background", "highlight"], title="Monthly unit sales by region (2025)", xlabel="Month", ylabel="Units sold", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, show_legend=True, ).show() ``` ### Reference lines Reference lines mark a threshold or an event on the chart. **Horizontal lines.** Use the `hlines` argument with the [datachart.typings.HLinePlotAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.HLinePlotAttrs) typing, which is either a `dict` or a `List[dict]` where each dictionary contains some of the following attributes: ``` { "y": Union[int, float], # The y-axis value "xmin": Optional[Union[int, float]], # The minimum x-axis value (values are bar indices, e.g. 0, 1, 2, etc.) "xmax": Optional[Union[int, float]], # The maximum x-axis value (values are bar indices, e.g. 0, 1, 2, etc.) "style": { # The style of the line (optional) "plot_hline_color": Optional[str], # The color of the line (hex color code) "plot_hline_style": Optional[LineStyle], # The line style (solid, dashed, etc.) "plot_hline_width": Optional[float], # The width of the line "plot_hline_alpha": Optional[float], # The alpha of the line (how visible the line is) }, "label": Optional[str], # The label of the line (shown in the legend) } ``` **Vertical lines.** Use the `vlines` argument with the [datachart.typings.VLinePlotAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.VLinePlotAttrs) typing, which has the same shape with `x`, `ymin`, `ymax` and `plot_vline_*` style attributes. The `x` value is a bar index (`0`, `1`, `2`, …), so a line *between* two bars sits at a half-integer position. The example marks the monthly sales goal with a dashed horizontal line and the July price cut with a vertical line between June and July. The line labels appear in the legend. ``` from datachart.constants import LINE_STYLE ``` ``` BarChart( data=sales_total, # add a horizontal line at the sales goal hlines={ "y": SALES_GOAL, "label": "monthly goal", "style": { "plot_hline_color": "#c1121f", "plot_hline_style": LINE_STYLE.DASHED, "plot_hline_width": 1.5, }, }, # add a vertical line between the June and July bars vlines={ "x": 5.5, "label": "price cut", "style": { "plot_vline_color": "#555555", "plot_vline_style": LINE_STYLE.DOTTED, "plot_vline_width": 1.5, }, }, title="Monthly unit sales (2025)", xlabel="Month", ylabel="Units sold", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, show_legend=True, ).show() ``` ## Multiple Bar Charts To create multiple bar charts, pass a list of lists to the `data` argument. Each inner list represents the data for one chart. Per-chart attributes like `subtitle`, `style` and `emphasis` can be passed as lists, where each element corresponds to a chart. Multiple charts pattern For multiple charts, `data` becomes a list of lists, and per-chart attributes like `subtitle` and `style` become lists where each element applies to the corresponding chart. The `sales_by_region` dataset is such a list of lists, one series per region. Series that share a label are grouped side by side. ``` BarChart( # use a list of lists to define multiple bar charts data=sales_by_region, title="Monthly unit sales by region (2025)", xlabel="Month", ylabel="Units sold", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, ).show() ``` ### Sub-chart subtitles We can name each chart by passing a list of subtitles to the `subtitle` argument. In addition, to help with discerning which chart is which, use the `show_legend` argument to show the legend of the charts. ``` BarChart( data=sales_by_region, # add a subtitle to each chart subtitle=REGIONS, title="Monthly unit sales by region (2025)", xlabel="Month", ylabel="Units sold", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, # show the legend show_legend=True, ).show() ``` ### Bar mode The `bar_mode` attribute controls how the series share the axis: | Value | Description | | ----------- | --------------------------------------------------------------- | | `"group"` | The series are drawn side by side (default). | | `"stack"` | The series are stacked on top of each other. | | `"overlay"` | The series are drawn on top of each other at the same position. | Again, `datachart` provides a [datachart.constants.BAR_MODE](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.BAR_MODE) constant, which contains the supported options. Stacking the regions shows both the regional split and the company-wide total in one chart. ``` from datachart.constants import BAR_MODE ``` ``` BarChart( data=sales_by_region, subtitle=REGIONS, # stack the series bar_mode=BAR_MODE.STACK, title="Monthly unit sales by region (2025)", xlabel="Month", ylabel="Units sold", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, show_legend=True, ).show() ``` ### Subplots To draw each chart in its own subplot, add the `subplots` attribute. The chart's `subtitle` are then added at the top of each subplot, while the `title`, `xlabel` and `ylabel` are positioned to be global for all charts. The `max_cols` attribute limits the number of subplots per row. ``` BarChart( data=sales_by_region, subtitle=REGIONS, title="Monthly unit sales by region (2025)", xlabel="Month", ylabel="Units sold", figsize=FIG_SIZE.FULL_MEDIUM, show_grid=SHOW_GRID.Y, # show each chart in its own subplot subplots=True, # at most two subplots per row max_cols=2, ).show() ``` ### Sharing the x-axis and/or y-axis across subplots To share the x-axis and/or y-axis across subplots, add the `sharex` and/or `sharey` attributes, which are boolean values that specify whether to share the axis across all subplots. With a shared y-axis, the regions become directly comparable. ``` BarChart( data=sales_by_region, subtitle=REGIONS, title="Monthly unit sales by region (2025)", xlabel="Month", ylabel="Units sold", figsize=FIG_SIZE.FULL_MEDIUM, show_grid=SHOW_GRID.Y, subplots=True, max_cols=2, # share the x-axis across subplots sharex=True, # share the y-axis across subplots sharey=True, ).show() ``` ### Subplot orientation The `orientation` attribute can be used to change the orientation of all subplots. ``` BarChart( data=sales_by_region, subtitle=REGIONS, title="Monthly unit sales by region (2025)", xlabel="Units sold", ylabel="Month", figsize=FIG_SIZE.FULL_TALL, subplots=True, max_cols=2, sharex=True, sharey=True, # change the grid to match the change in orientation show_grid=SHOW_GRID.X, # change the orientation of the bars orientation=ORIENTATION.HORIZONTAL, ).show() ``` ## Additional Features ### Error bars To add error bars, first define the `yerr` value of each data point in `data`, then add the `show_yerr` attribute. The `sales_by_region` data points carry the standard deviation of daily sales as `yerr`. The color of the error lines is set with the `plot_bar_error_color` style attribute. ``` BarChart( data=sales_by_region, subtitle=REGIONS, # set the error bar color (a single style applies to every chart) style={"plot_bar_error_color": "#000000"}, title="Monthly unit sales by region (2025)", xlabel="Month", ylabel="Units sold", figsize=FIG_SIZE.FULL_MEDIUM, show_grid=SHOW_GRID.Y, subplots=True, max_cols=2, sharex=True, sharey=True, # show the error bars show_yerr=True, # make sure the y-axis starts at 0 ymin=0, ).show() ``` ### Bar value labels To display the actual value at the edge of each bar, use the `show_values` parameter. The `value_format` parameter controls how the values are formatted. It accepts a Python format string in which the value is named `x` (e.g., `"{x:.1f}"` for one decimal place, `"{x:.0%}"` to show a fraction as a percentage) — the [datachart.constants.VALUE_FORMAT](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.VALUE_FORMAT) constant collects the common ones: | Constant | Format | Description | | ------------------------- | ------------ | --------------------------------------------------------------------------- | | `VALUE_FORMAT.DEFAULT` | `"{x}"` | The value as is. | | `VALUE_FORMAT.INTEGER` | `"{x:.0f}"` | Rounded to an integer. | | `VALUE_FORMAT.DECIMAL` | `"{x:.1f}"` | One decimal place (`DECIMAL_2` and `DECIMAL_3` for two and three). | | `VALUE_FORMAT.PERCENT` | `"{x:.1%}"` | A fraction as a percentage with one decimal place (`PERCENT_INT` for none). | | `VALUE_FORMAT.SCIENTIFIC` | `"{x:.2e}"` | Scientific notation. | | `VALUE_FORMAT.THOUSANDS` | `"{x:,.0f}"` | With a thousands separator. | Positional format strings (`"{:.1f}%"`) and printf-style ones (`"%g"`) work too, which is handy when the value already is a percentage. ``` from datachart.constants import VALUE_FORMAT ``` ``` BarChart( data=sales_total, title="Monthly unit sales (2025)", xlabel="Month", ylabel="Units sold", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, ymin=0, ymax=2000, # show bar value labels show_values=True, # format the values with a thousands separator value_format=VALUE_FORMAT.THOUSANDS, ).show() ``` Bar value labels also work with horizontal bar charts. You can customize the label appearance using style attributes like `plot_bar_value_fontsize`, `plot_bar_value_color`, and `plot_bar_value_padding`. ``` BarChart( data=sales_total, style={ "plot_bar_value_fontsize": 9, "plot_bar_value_color": "#333333", "plot_bar_value_padding": 5, }, title="Monthly unit sales (2025)", xlabel="Units sold", ylabel="Month", figsize=FIG_SIZE.FULL_MEDIUM, show_grid=SHOW_GRID.X, xmin=0, xmax=2000, # horizontal orientation orientation=ORIENTATION.HORIZONTAL, # show bar value labels show_values=True, value_format=VALUE_FORMAT.INTEGER, ).show() ``` ### Axis scales The user can change the axis scale using the `scaley` attribute (`scalex` for horizontal bars). The supported scale options are: | Options | Description | | ---------- | ------------------------ | | `"linear"` | The linear scale. | | `"log"` | The log scale. | | `"symlog"` | The symmetric log scale. | | `"asinh"` | The asinh scale. | Again, to help with the options settings, the [datachart.constants](https://eriknovak.github.io/datachart/0.9.0/references/constants/index.md) module contains the following constants: | Constant | Description | | ------------------------------------------------------------------------------------------------------------------------ | ----------------- | | [datachart.constants.SCALE](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.SCALE) | The axis options. | A logarithmic scale pays off when the values span several orders of magnitude. The hidden cell below defines `populations`, the approximate mid-2024 populations of seven countries in thousands (UN World Population Prospects 2024, rounded) — from about 1.45 billion down to about 10 thousand. ``` from datachart.constants import SCALE ``` On a linear scale the small countries vanish; on a log scale every bar is readable. ``` for scale in [SCALE.LINEAR, SCALE.LOG]: figure = BarChart( data=populations, title=f"Population on the '{scale}' scale", xlabel="Country", ylabel="Population (thousands)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, # set the scale of the y axis scaley=scale, ) figure.show() ``` ## Saving the Chart as an Image To save the chart as an image, use the [datachart.utils.save_figure](https://eriknovak.github.io/datachart/0.9.0/references/utils#datachart.utils.save_figure) function. ``` from datachart.utils import save_figure ``` ``` save_figure(figure, "./fig_bar_chart.png", dpi=300) ``` The figure should be saved in the current working directory. ## Real-World Examples The following examples put the features above to work on real or realistic data. Each one states what its data is and where it comes from; the data itself lives in a hidden cell. ### Example 1: Olympic Medal Table (Grouped Bars with Legend) `medals` holds the gold, silver and bronze medal counts of the six countries that topped the Paris 2024 Olympic medal table (ranked by gold medals; source: the official Paris 2024 medal table). One series per medal type gives a grouped bar chart, colored to match the metals. ``` BarChart( data=medals, subtitle=["Gold", "Silver", "Bronze"], style=[ {"plot_bar_color": "#d4af37"}, # gold {"plot_bar_color": "#a8a9ad"}, # silver {"plot_bar_color": "#cd7f32"}, # bronze ], title="Paris 2024 Olympic medal table", xlabel="Country", ylabel="Medals", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, show_legend=True, ymin=0, ).show() ``` ### Example 2: Quarterly Revenue by Region (Emphasis) `revenue` holds the illustrative quarterly revenue (in million USD) of a company across four sales regions over eight quarters, 2024–2025. The question is how the fastest-growing region compares with the rest, so `emphasis` highlights it and mutes the other three. Muted regions drop out of the legend automatically. ``` BarChart( data=revenue, subtitle=list(REVENUE), # highlight Asia-Pacific, mute the other regions emphasis=["background", "background", "highlight", "background"], title="Quarterly revenue by region", xlabel="Quarter", ylabel="Revenue (million USD)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, show_legend=True, ymin=0, ).show() ``` ### Example 3: Survey Results (Horizontal Bars with Value Labels) `languages` holds the share of respondents who worked with each programming language in the past year, for the ten most-used languages in the Stack Overflow Developer Survey 2024 (all respondents). Horizontal bars keep the long labels readable, and value labels print the exact share on each bar — the values already are percentages, so a positional `"{:.1f}%"` format appends the sign instead of `VALUE_FORMAT.PERCENT` (which would multiply by 100). The data is ordered from least to most used so the most-used language ends up at the top. ``` BarChart( data=languages, style={ "plot_bar_color": "#f48024", "plot_bar_value_fontsize": 9, "plot_bar_value_padding": 4, }, title="Most used programming languages, 2024", xlabel="Share of respondents", figsize=FIG_SIZE.FULL_MEDIUM, show_grid=SHOW_GRID.X, orientation=ORIENTATION.HORIZONTAL, xmin=0, xmax=75, show_values=True, value_format="{:.1f}%", ).show() ``` ### Example 4: Monthly Trade Balance (Diverging Bars) `trade_balance` holds two years of illustrative monthly trade balance figures (exports minus imports, in billion EUR) — a run of deficits in the first year turning into surpluses in the second. Since `BarChart` applies a single color per series, the data is split into a positive and a negative series (see the tip below). ``` BarChart( data=trade_balance, style=[ {"plot_bar_color": "#2a9d8f"}, # surplus {"plot_bar_color": "#e76f51"}, # deficit ], # draw both series at the same positions bar_mode=BAR_MODE.OVERLAY, # mark the zero line hlines={ "y": 0, "style": { "plot_hline_color": "black", "plot_hline_style": LINE_STYLE.SOLID, "plot_hline_width": 1, }, }, title="Monthly trade balance", ylabel="Billion EUR", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, xtickrotate=90, ).show() ``` Tip: Diverging Bar Charts Each month is zero in one of the two series (positive values in one, negative in the other). Drawing them with `bar_mode=BAR_MODE.OVERLAY` puts both series at the same x-positions, so only one bar is visible per month — the visual effect of a single diverging bar chart with two colors. # Pyramid Chart This section showcases the pyramid chart. It contains examples of how to create the pyramid chart using the [datachart.charts.PyramidChart](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.PyramidChart) function. A pyramid chart draws exactly two data series as horizontal bars extending in opposite directions from a shared zero line — the classic population-pyramid layout, useful whenever two groups are compared over the same categories. Looking for a specific customization? Jump straight to the [quick reference](#customizing-the-pyramid-chart), which maps common tasks to the parameter or style attribute that does the job. As mentioned above, the pyramid charts are created using the `PyramidChart` function found in the [datachart.charts](https://eriknovak.github.io/datachart/0.9.0/references/charts/index.md) module. Let's import it: ``` from datachart.charts import PyramidChart ``` ## Pyramid Chart Input Attributes The `PyramidChart` function accepts keyword arguments for chart configuration. The main argument is `data`, which contains exactly two lists of data points: the first list is the left side of the pyramid, the second the right. Both sides are supplied as positive values — the chart mirrors the left side itself, and every visible number (value ticks, value labels) shows the absolute value. Unlike the other chart functions, the axis parameters are spatial: `xlabel`, `xticks`, and `xmax` address the horizontal value axis, and `ylabel` the vertical category axis. The value axis is always symmetric around zero, so there is no `xmin`. ``` PyramidChart( data=[[{ # Exactly two lists of data points: [left_side, right_side] "label": str, # The category label (shared by both sides) "y": Union[int, float], # The bar value, positive for both sides "yerr": Optional[Union[int, float]] # The bar error value }], [...]], style={ # The style of the bars (optional); a list styles each side "plot_bar_*": ..., }, subtitle=Optional[List[str]], # The names of the two sides, used as legend labels title=Optional[str], # The title of the chart xlabel=Optional[str], # The label of the horizontal value axis ylabel=Optional[str], # The label of the vertical category axis figsize=Optional[Tuple[float, float]], # The figure size in inches show_grid=Optional[str], # Which grid lines to show ("both", "x", "y") show_legend=Optional[bool], # Whether to show the legend show_yerr=Optional[bool], # Whether to show error bars on the bars show_values=Optional[bool], # Whether to show bar value labels at the bar ends value_format=Optional[str], # Format of the value labels (VALUE_FORMAT constant or e.g. "{:.1f}%") xmax=Optional[Union[int, float]], # The maximum per-side value; the value axis spans (-xmax, xmax) xticks=Optional[List[Union[int, float]]], # Custom value-axis tick positions, positive; mirrored to both halves xticklabels=Optional[List[str]], # Custom value-axis tick labels, applied to both halves xtickrotate=Optional[int], # Rotation angle of the value-axis tick labels yticks=Optional[List[Union[int, float]]], # Custom category-axis tick positions yticklabels=Optional[List[str]], # Custom category-axis tick labels ytickrotate=Optional[int], # Rotation angle of the category-axis tick labels vlines=Optional[VLinePlotAttrs], # The vertical lines to draw hlines=Optional[HLinePlotAttrs], # The horizontal lines to draw label=Optional[str], # The data key for the labels (default: "label") y=Optional[str], # The data key for the bar values (default: "y") yerr=Optional[str] # The data key for the bar errors (default: "yerr") ) ``` For more details, see the [datachart.charts.PyramidChart](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.PyramidChart) function. ## Basics The examples in this guide share one dataset: the resident register of a city's two districts. The data is constructed in a hidden cell; `riverside` and `hillcrest` hold the population by single year of age (0–79, so 160 bars per pyramid), `riverside_bands` and `hillcrest_bands` aggregate the same register into two-year age bands (80 bars, with the register's estimated error as `yerr`), `riverside_2015`/`hillcrest_2015` hold the register a decade earlier, and `station_in`/`station_out` hold metro station passengers per 15-minute slot. Each data point is a dictionary with a `label` (the age band) and a positive `y` value; the same labels appear on both sides: ``` riverside_bands[:3] ``` **Basic example.** Only the `data` argument is required — exactly two lists of data points, the first drawn to the left and the second to the right. ``` PyramidChart( # add the two sides of the pyramid: [left_side, right_side] data=[riverside_bands, hillcrest_bands] ).show() ``` Both sides extend from the shared zero line at full bar width, the category labels sit at the left edge, and the value ticks show absolute values on both halves. ## Customizing the Pyramid Chart Every customization is either a keyword argument of `PyramidChart` or a style attribute of its `style` dictionary. The table maps common tasks to the one you need and links to the subsection that shows it. | I want to… | Use | See | | ---------------------------------- | ----------------------------- | ----------------------------------------------- | | add a title and axis labels | `title`, `xlabel`, `ylabel` | [Title and axis labels](#title-and-axis-labels) | | name the two sides | `subtitle`, `show_legend` | [Naming the sides](#naming-the-sides) | | resize the figure or show the grid | `figsize`, `show_grid` | [Figure size and grid](#figure-size-and-grid) | | fix the value range or place ticks | `xmax`, `xticks`, `yticks` | [Axis limits and ticks](#axis-limits-and-ticks) | | write each bar's value at its end | `show_values`, `value_format` | [Value labels](#value-labels) | | show the error bars | `show_yerr` | [Error bars](#error-bars) | | style the bars, per side | `style` | [Bar style](#bar-style) | | use my own data keys | `label`, `y`, `yerr` | [Custom data keys](#custom-data-keys) | ### Title and axis labels To add the chart title and axis labels, add the `title`, `xlabel` and `ylabel` attributes. The axis parameters are spatial: `xlabel` describes the horizontal value axis and `ylabel` the vertical category axis. ``` PyramidChart( data=[riverside_bands, hillcrest_bands], # add the title and the axis labels title="Residents by age band", xlabel="Residents", ylabel="Age band", ).show() ``` ### Naming the sides The `subtitle` attribute names the two sides, in the same order as `data`; with `show_legend=True` the names appear in the legend. ``` PyramidChart( data=[riverside_bands, hillcrest_bands], # name the sides and show the legend subtitle=["Riverside", "Hillcrest"], show_legend=True, title="Residents by age band", ).show() ``` ### Figure size and grid The figure size is set with `figsize` — the [datachart.constants](https://eriknovak.github.io/datachart/0.9.0/references/constants) module provides the `FIG_SIZE` options — and the grid is turned on with `show_grid`. On a pyramid the vertical grid lines (`"x"`) are usually the useful ones, since they mark the value steps on both halves; a taller figure gives a dense pyramid's bands room to breathe. ``` from datachart.constants import FIG_SIZE, SHOW_GRID ``` ``` PyramidChart( data=[riverside_bands, hillcrest_bands], title="Residents by age band", # a taller figure and vertical grid lines figsize=FIG_SIZE.FULL_TALL, show_grid=SHOW_GRID.X, ).show() ``` ### Axis limits and ticks The value axis is always symmetric around zero. The `xmax` attribute sets the maximum per-side value, so the axis spans `(-xmax, xmax)`; passing `xmin` raises a `ValueError`. The `xticks` attribute places custom value ticks: the positions are given as positive values and each is mirrored to both halves. The `xticklabels` attribute (same length as `xticks`) replaces the tick labels on both halves, and `xtickrotate` rotates them. ``` PyramidChart( data=[riverside_bands, hillcrest_bands], title="Residents by age band", # fix the per-side range and label the value axis in thousands xmax=2600, xticks=[0, 1000, 2000], xticklabels=["0", "1k", "2k"], ).show() ``` The category axis keeps the usual `yticks`, `yticklabels`, and `ytickrotate` controls. They matter most on dense pyramids: the single-year register has 80 bands per side, far too many to label individually, so tick positions every tenth band keep the axis readable. ``` PyramidChart( data=[riverside, hillcrest], title="Residents by year of age", ylabel="Age", # 80 single-year bands per side: label every tenth one yticks=list(range(0, 80, 10)), ).show() ``` ### Value labels The `show_values` attribute writes each bar's value at its end, formatted via `value_format` — a `VALUE_FORMAT` constant or any printf/format-style string. The labels show the absolute value on both sides. On a dense pyramid, shrink them with the `plot_bar_value_fontsize` style attribute so the rows stay separate. ``` PyramidChart( data=[riverside_bands, hillcrest_bands], title="Residents by age band", # write each bar's count at its end, in a small font show_values=True, value_format="%.0f", style={"plot_bar_value_fontsize": 6}, figsize=FIG_SIZE.FULL_TALL, ).show() ``` ### Error bars The `show_yerr` attribute draws the `yerr` values as error bars at the bar ends — on a pyramid they extend along the value axis, symmetrically on both sides of the bar end. ``` PyramidChart( data=[riverside_bands, hillcrest_bands], title="Residents by age band", # draw the register's estimated error at the bar ends show_yerr=True, ).show() ``` ### Bar style Pyramid bars obey the same `plot_bar_*` style attributes as the bar chart; see the [datachart.typings](https://eriknovak.github.io/datachart/0.9.0/references/typings) module for the full family. A single `style` dictionary applies to both sides; a list of two styles the sides individually. Without explicit colors, the two sides take the first two colors of the theme's palette — themes therefore style pyramids out of the box. ``` PyramidChart( data=[riverside_bands, hillcrest_bands], subtitle=["Riverside", "Hillcrest"], show_legend=True, title="Residents by age band", # style each side individually style=[ {"plot_bar_color": "#2a6f97"}, {"plot_bar_color": "#61a5c2", "plot_bar_hatch": "///"}, ], ).show() ``` ### Custom data keys If the data points use different key names, the `label`, `y`, and `yerr` attributes remap them — either one name for both sides or a list of two. ``` riverside_counts = [ {"band": p["label"], "residents": p["y"]} for p in riverside_bands ] hillcrest_counts = [ {"band": p["label"], "residents": p["y"]} for p in hillcrest_bands ] PyramidChart( data=[riverside_counts, hillcrest_counts], # remap the data keys label="band", y="residents", title="Residents by age band", ).show() ``` ## Composing Pyramids One `PyramidChart` call makes one pyramid. For small multiples, compose rendered figures with [datachart.utils.Grid](https://eriknovak.github.io/datachart/0.9.0/references/utils#datachart.utils.Grid) — each pyramid keeps its mirrored axis inside its own cell. Overlaying a pyramid onto other charts with [datachart.utils.Panel](https://eriknovak.github.io/datachart/0.9.0/references/utils#datachart.utils.Panel) is not supported and raises a `ValueError`, since unmirrored data on a mirrored axis would be misleading. ``` from datachart.utils import Grid decade_ticks = list(range(0, 80, 10)) Grid( [ PyramidChart( data=[riverside_2015, hillcrest_2015], subtitle=["Riverside", "Hillcrest"], title="2015", xmax=1400, yticks=decade_ticks, ), PyramidChart( data=[riverside, hillcrest], subtitle=["Riverside", "Hillcrest"], title="2025", xmax=1400, yticks=decade_ticks, ), ], max_cols=2, figsize=(12, 4.5), ).show() ``` ## Saving the Chart as an Image To save the chart as an image, use the [datachart.utils.save_figure](https://eriknovak.github.io/datachart/0.9.0/references/utils#datachart.utils.save_figure) function. ``` from datachart.utils import save_figure ``` ``` figure = PyramidChart( data=[riverside_bands, hillcrest_bands], title="Residents by age band", ) save_figure(figure, "./fig_pyramid_chart.png", dpi=300) ``` The figure should be saved in the current working directory. ## Real-World Examples ### Example 1: Population Pyramid The classic use: the full single-year register — 160 bars — with named sides, decade ticks, a fixed symmetric range, and vertical grid lines. ``` PyramidChart( data=[riverside, hillcrest], subtitle=["Riverside", "Hillcrest"], title="Resident population by year of age", xlabel="Residents", ylabel="Age", xmax=1400, yticks=list(range(0, 80, 10)), show_legend=True, show_grid=SHOW_GRID.X, figsize=FIG_SIZE.FULL_TALL, ).show() ``` ### Example 2: Passenger Flows by Time of Day The same layout works for any two-group comparison over shared categories — here a metro station's entries against exits across 64 quarter-hour slots (128 bars). The morning peak flows in, the evening peak flows out; hourly tick labels keep the time axis readable. ``` PyramidChart( data=[station_in, station_out], subtitle=["Entries", "Exits"], title="Station passengers by time of day", xlabel="Passengers per 15 min", # one tick per hour over the 15-minute slots yticks=list(range(0, 64, 4)), yticklabels=[station_in[i]["label"] for i in range(0, 64, 4)], show_legend=True, figsize=FIG_SIZE.FULL_TALL, ).show() ``` # Radial Chart This section showcases the radial chart. It contains examples of how to create the radial chart using the [datachart.charts.RadialChart](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.RadialChart) function. Looking for a specific customization? Jump straight to the [quick reference](#customizing-the-radial-chart), which maps common tasks to the parameter or style attribute that does the job. As mentioned above, the radial charts are created using the `RadialChart` function found in the [datachart.charts](https://eriknovak.github.io/datachart/0.9.0/references/charts/index.md) module. Let's import it: ``` from datachart.charts import RadialChart ``` ## Radial Chart Input Attributes The `RadialChart` function accepts keyword arguments for chart configuration. The main argument is `data`, which contains the data points, and `type`, which selects the visual the whole figure draws: `"line"` (default), `"bar"`, `"scatter"`, or `"histogram"`. For a single radial chart, `data` is a list of dictionaries. For multiple radial charts, `data` is a list of lists. The line, bar, and scatter visuals take `label`/`y` points; the labels are placed evenly around the circle. The histogram visual instead takes numeric `x` observations in degrees, binned over \[0, 360). ``` RadialChart( data=[{ # A list of radial data points (or list of lists for multiple charts) "label": str, # The category label (line, bar, and scatter visuals) "y": Union[int, float], # The radial value (line, bar, and scatter visuals) "yerr": Optional[Union[int, float]], # The radial error value "x": Optional[Union[int, float]] # The angular observation in degrees (histogram visual) }], type=Optional[str], # The visual: "line" (default), "bar", "scatter", or "histogram" style={ # The style of the marks (optional); each visual reads its cartesian family "plot_line_*": ..., # the line visual (plus "plot_area_*" for fills and error bands) "plot_bar_*": ..., # the bar visual "plot_scatter_*": ..., # the scatter visual "plot_hist_*": ..., # the histogram visual }, subtitle=Optional[str], # The subtitle of the chart (or list for multiple charts) emphasis=Optional[str], # "highlight" or "background" (or list for multiple charts) title=Optional[str], # The title of the chart xlabel=Optional[str], # The angular-axis label (the categories around the circle) ylabel=Optional[str], # The radial-axis label (the values) figsize=Optional[Tuple[float, float]], # The figure size in inches show_grid=Optional[str], # Which grid lines to show ("both", "x", "y") show_legend=Optional[bool], # Whether to show the legend show_yerr=Optional[bool], # Whether to show the radial error band (line visual) show_area=Optional[bool], # Whether to fill the area inside the line (line visual) show_values=Optional[bool], # Whether to write each mark's value at its tip show_tip_labels=Optional[bool], # Whether to move the category labels to the mark tips show_border=Optional[bool], # Whether to draw the outer border circle value_format=Optional[str], # Format of the value labels (VALUE_FORMAT constant or e.g. "{:.1f}%") bar_mode=Optional[str], # How multiple bar series share the circle ("group", "stack", "overlay") num_bins=Optional[int], # Number of angular bins (histogram visual) startangle=Optional[Union[str, int, float]], # Where the first label sits: a compass point ("N", "NE", ...) or degrees direction=Optional[str], # Which way the angles run ("clockwise", "counterclockwise") innerradius=Optional[float], # The donut hole, as a fraction (0-1) of the radial extent subplots=Optional[bool], # Whether to draw each chart in its own polar subplot max_cols=Optional[int], # Maximum number of subplots per row sharex=Optional[bool], # Whether subplots share the angular axis sharey=Optional[bool], # Whether subplots share the radial range scaley=Optional[str], # The radial-axis scale ("linear", "log", "symlog", "asinh") ymin=Optional[Union[int, float]], # The radial-axis range ymax=Optional[Union[int, float]], label=Optional[str], # the key holding the category label (default: "label") x=Optional[str], # the key holding the angular observation (default: "x") y=Optional[str], # the key holding the radial value (default: "y") yerr=Optional[str], # the key holding the radial error value (default: "yerr") ) ``` For more details, see the [datachart.charts.RadialChart](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.RadialChart) function. ## Basics The examples in this guide share one dataset: a year of weather measurements at a small coastal station. The data is hard-coded in a hidden cell; `wind_by_direction` holds the average wind speed for each of the eight compass directions (with the gust standard deviation as `yerr`), `wind_directions` holds the raw wind direction observations in degrees, and `sunshine_by_month` holds the monthly sunshine hours. Each data point is a dictionary with a `label` (the compass direction) and a `y` value: ``` wind_by_direction[:3] ``` **Basic example.** Only the `data` argument is required to draw the radial chart. ``` RadialChart( # add the data to the chart data=wind_by_direction ).show() ``` The labels are placed evenly around the circle, starting at the top (north) and running clockwise — the compass and clock convention. The line closes its own loop, and the radial value labels are drawn on top of the marks so they stay readable. ## Customizing the Radial Chart Every customization is either a keyword argument of `RadialChart` or a style attribute of its `style` dictionary. The table maps common tasks to the one you need and links to the subsection that shows it. | I want to… | Use | See | | --------------------------------------- | --------------------------------------------- | --------------------------------------------------------------- | | add a title and axis labels | `title`, `xlabel`, `ylabel` | [Title and axis labels](#title-and-axis-labels) | | pick the visual | `type` | [The radial visuals](#the-radial-visuals) | | resize the figure or show the grid | `figsize`, `show_grid` | [Figure size and grid](#figure-size-and-grid) | | rotate where the circle starts | `startangle` | [Start angle and direction](#start-angle-and-direction) | | flip the angular direction | `direction` | [Start angle and direction](#start-angle-and-direction) | | cut a donut hole in the middle | `innerradius` | [Inner radius](#inner-radius) | | style the marks | `style` with the visual's `plot_*` attributes | [Mark style](#mark-style) | | highlight or mute a series | `emphasis` | [Emphasis](#emphasis) | | stack multiple bar series | `bar_mode` | [Bar mode](#bar-mode) | | split series into their own subplots | `subplots`, `max_cols` | [Subplots](#subplots) | | show an error band or fill the area | `show_yerr`, `show_area` | [Error bands and filled areas](#error-bands-and-filled-areas) | | write values or labels at the mark tips | `show_values`, `show_tip_labels` | [Values and labels at the tips](#values-and-labels-at-the-tips) | | hide the outer border circle | `show_border` | [Values and labels at the tips](#values-and-labels-at-the-tips) | | use a log radial axis | `scaley` | [Radial axis scale](#radial-axis-scale) | ### Title and axis labels To add the chart title and axis labels, add the `title`, `xlabel` and `ylabel` attributes. On a polar plot the `xlabel` describes the angular axis (the categories around the circle) and the `ylabel` the radial axis (the values). The radial range can be fixed with `ymin` and `ymax`. ``` RadialChart( data=wind_by_direction, # add the title and the axis labels title="Average wind speed by direction", ylabel="Wind speed (km/h)", ymin=0, ).show() ``` ### The radial visuals The `type` attribute selects the mark family the whole figure draws. To help with the options settings, the [datachart.constants](https://eriknovak.github.io/datachart/0.9.0/references/constants) module provides the `RADIAL_TYPE` constant. | Options | Description | | ----------------------- | ------------------------------------------------------------------------------------- | | `RADIAL_TYPE.LINE` | The line (radar) visual. Default. | | `RADIAL_TYPE.BAR` | The bar visual, one sector per label. | | `RADIAL_TYPE.SCATTER` | The scatter visual. | | `RADIAL_TYPE.HISTOGRAM` | The angular histogram (wind rose) visual, binning degree observations over \[0, 360). | ``` from datachart.constants import RADIAL_TYPE ``` ``` RadialChart( data=wind_by_direction, # draw one bar sector per compass direction type=RADIAL_TYPE.BAR, title="Average wind speed by direction", ).show() ``` The histogram visual takes raw angular observations in degrees and bins them over the full circle; the `num_bins` attribute sets the number of angular bins. This is the classic wind rose: ``` RadialChart( data=wind_directions, type=RADIAL_TYPE.HISTOGRAM, # bin the directions into 16 sectors over the full circle num_bins=16, title="Wind direction frequency", ).show() ``` ### Figure size and grid The figure size is set with `figsize` — the [datachart.constants](https://eriknovak.github.io/datachart/0.9.0/references/constants) module provides the `FIG_SIZE` options — and the polar grid is turned on with `show_grid`. The grid is always drawn below the marks, so bars never hide behind grid lines. ``` from datachart.constants import FIG_SIZE, SHOW_GRID ``` ``` RadialChart( data=wind_by_direction, type=RADIAL_TYPE.BAR, title="Average wind speed by direction", # resize the figure and show the full polar grid figsize=FIG_SIZE.SQUARE, show_grid=SHOW_GRID.BOTH, ).show() ``` ### Start angle and direction By default the first label sits at the top (north) and the angles run clockwise. The `startangle` attribute moves the starting point — either a compass location (`"N"`, `"NE"`, `"E"`, `"SE"`, `"S"`, `"SW"`, `"W"`, `"NW"`) or a numeric compass bearing in degrees clockwise from north. The `direction` attribute flips which way the angles increase; the [datachart.constants](https://eriknovak.github.io/datachart/0.9.0/references/constants) module provides the `DIRECTION` constant with the `CLOCKWISE` and `COUNTERCLOCKWISE` options. ``` from datachart.constants import DIRECTION ``` ``` RadialChart( data=sunshine_by_month, type=RADIAL_TYPE.BAR, title="Monthly sunshine hours", # start at the right and run counterclockwise (the math convention) startangle="E", direction=DIRECTION.COUNTERCLOCKWISE, ).show() ``` ### Inner radius The `innerradius` attribute cuts a donut hole in the middle of the chart — a fraction between 0 and 1 of the radial extent. A hole keeps the innermost values readable, since sectors near the center otherwise shrink to slivers. ``` RadialChart( data=sunshine_by_month, type=RADIAL_TYPE.BAR, title="Monthly sunshine hours", # reserve the middle 25% of the radius for the hole innerradius=0.25, ).show() ``` ### Mark style Radial marks obey the same style attributes as their cartesian cousins: the line visual reads `plot_line_*` (and `plot_area_*` for fills), the bar visual `plot_bar_*`, the scatter visual `plot_scatter_*`, and the histogram visual `plot_hist_*`. See the [datachart.typings](https://eriknovak.github.io/datachart/0.9.0/references/typings) module for the attributes of each style family. Themes therefore style radial charts out of the box. ``` RadialChart( data=wind_by_direction, title="Average wind speed by direction", # style the line just like a cartesian line chart style={ "plot_line_color": "#aa3355", "plot_line_width": 2, "plot_line_style": "--", "plot_line_marker": "o", }, ).show() ``` ### Emphasis When a chart carries several series, the story is often about one of them. The `emphasis` attribute expresses that directly: `"highlight"` bolds a series and brings it to the front, `"background"` mutes a series (the theme's muted color at a lower alpha, drawn behind the others and left out of the legend), and `None` leaves a series unchanged. For multiple charts, `emphasis` is a list aligned with `data`, just like `subtitle` and `style`. ``` # the same station in two years: this year is the story wind_last_year = [ {"label": d, "y": s} for d, s in zip(COMPASS, [12.8, 12.9, 9.6, 8.2, 8.9, 15.1, 17.2, 15.3]) ] wind_this_year = [{"label": p["label"], "y": p["y"]} for p in wind_by_direction] RadialChart( data=[wind_last_year, wind_this_year], subtitle=["Last year", "This year"], # mute last year, highlight this year emphasis=["background", "highlight"], title="Average wind speed by direction", show_legend=True, ).show() ``` ## Multiple Radial Charts To plot multiple radial charts in the same figure, pass a list of lists as `data`. All series share the figure's one `type`; to mix visuals in one polar plot, compose rendered figures with [datachart.utils.Panel](https://eriknovak.github.io/datachart/0.9.0/references/utils#datachart.utils.Panel). ### Sub-chart subtitles The `subtitle` attribute names the individual series; with `show_legend=True` the names appear in the legend. ``` RadialChart( data=[wind_last_year, wind_this_year], # add the subtitles and show the legend subtitle=["Last year", "This year"], show_legend=True, title="Average wind speed by direction", ).show() ``` ### Bar mode Multiple bar series share the circle the same way cartesian bars share the axis, via `bar_mode`: `"group"` (side-by-side within each sector, the default), `"stack"` (on top of each other), or `"overlay"`. The [datachart.constants](https://eriknovak.github.io/datachart/0.9.0/references/constants) module provides the `BAR_MODE` constant. ``` from datachart.constants import BAR_MODE ``` ``` # sunshine hours split into morning and afternoon morning = [{"label": p["label"], "y": round(p["y"] * 0.42)} for p in sunshine_by_month] afternoon = [{"label": p["label"], "y": round(p["y"] * 0.58)} for p in sunshine_by_month] RadialChart( data=[morning, afternoon], type=RADIAL_TYPE.BAR, # stack the two series in each sector bar_mode=BAR_MODE.STACK, subtitle=["Morning", "Afternoon"], show_legend=True, title="Monthly sunshine hours", ).show() ``` ### Subplots To display each series in its own polar subplot, set `subplots=True`. The `max_cols` attribute controls how many subplots sit in one row, and `sharey=True` gives every subplot the same radial range so the shapes stay comparable. ``` RadialChart( data=[wind_last_year, wind_this_year], subtitle=["Last year", "This year"], # one polar subplot per series, sharing the radial range subplots=True, max_cols=2, sharey=True, figsize=FIG_SIZE.FULL_SHORT, ).show() ``` ## Additional Features ### Error bands and filled areas The line visual supports the same enrichments as the line chart: `show_yerr=True` draws a band of `yerr` around the line, and `show_area=True` fills the polygon the line encloses. ``` RadialChart( data=wind_by_direction, # draw the gust standard deviation as a band around the line show_yerr=True, title="Average wind speed by direction", ).show() ``` ``` RadialChart( data=wind_by_direction, # fill the polygon the line encloses show_area=True, title="Average wind speed by direction", ).show() ``` ### Values and labels at the tips The `show_values` attribute writes each mark's value at its tip, rotated along the spoke (formatted via `value_format`, exactly like the bar chart's value labels). The `show_tip_labels` attribute instead moves the category labels from the ring around the circle to the mark tips — each label hugs the outermost mark on its spoke and flips on the left half so it always reads outward. Together with `show_border=False`, which hides the outer border circle, this gives the classic circular-barplot look. ``` RadialChart( data=wind_by_direction, type=RADIAL_TYPE.BAR, # write each bar's value at its tip show_values=True, value_format="%.1f", title="Average wind speed by direction", ).show() ``` ``` RadialChart( data=[morning, afternoon], type=RADIAL_TYPE.BAR, bar_mode=BAR_MODE.STACK, # the month labels ride the bar tips; no border circle show_tip_labels=True, show_border=False, innerradius=0.3, subtitle=["Morning", "Afternoon"], show_legend=True, title="Monthly sunshine hours", figsize=FIG_SIZE.SQUARE, ).show() ``` ### Radial axis scale The radial (value) axis can change scale with `scaley`, exactly like a cartesian y-axis. The angular axis has no scale to change — passing `scalex` raises a `ValueError`, as do `vlines` and `hlines`, which have no geometric meaning on a polar plot. ``` from datachart.constants import SCALE RadialChart( data=[{"label": d, "y": y} for d, y in zip(COMPASS, [3, 30, 8, 300, 15, 80, 5, 150])], type=RADIAL_TYPE.SCATTER, # spread values spanning two orders of magnitude scaley=SCALE.LOG, title="Particle counts by direction", ).show() ``` ## Saving the Chart as an Image To save the chart as an image, use the [datachart.utils.save_figure](https://eriknovak.github.io/datachart/0.9.0/references/utils#datachart.utils.save_figure) function. ``` from datachart.utils import save_figure ``` ``` figure = RadialChart( data=wind_by_direction, title="Average wind speed by direction", ) save_figure(figure, "./fig_radial_chart.png", dpi=300) ``` The figure should be saved in the current working directory. ## Real-World Examples ### Example 1: Wind Rose (Angular Histogram) The classic use of a radial chart: how often the wind blows from each direction. The raw degree observations are binned into 16 sectors; the compass start angle and clockwise direction are the defaults. ``` RadialChart( data=wind_directions, type=RADIAL_TYPE.HISTOGRAM, num_bins=16, title="Wind rose — coastal station", figsize=FIG_SIZE.SQUARE, show_grid=SHOW_GRID.BOTH, ).show() ``` ### Example 2: Skill Radar (Line with Area) A radar (spider) chart comparing two profiles over the same skill set. The filled areas make the overall footprint of each profile easy to compare, and the legend names them. ``` SKILLS = ["Python", "Statistics", "Visualization", "ML", "Databases", "Communication"] candidate_a = [{"label": s, "y": y} for s, y in zip(SKILLS, [9, 7, 8, 6, 5, 8])] candidate_b = [{"label": s, "y": y} for s, y in zip(SKILLS, [6, 8, 5, 9, 8, 6])] RadialChart( data=[candidate_a, candidate_b], subtitle=["Candidate A", "Candidate B"], show_area=True, show_legend=True, ymin=0, ymax=10, title="Interview skill assessment", figsize=FIG_SIZE.SQUARE, ).show() ``` ### Example 3: Seasonal Activity Clock (Stacked Donut Bars) Monthly visitor numbers at a mountain hut, split by weekday and weekend visits. The stacked bars run like a clock — January at the top, months clockwise — and the donut hole keeps the quiet winter months readable. ``` weekday_visits = [ {"label": m, "y": v} for m, v in zip(MONTHS, [180, 210, 380, 690, 1150, 1580, 1920, 1860, 1240, 760, 320, 200]) ] weekend_visits = [ {"label": m, "y": v} for m, v in zip(MONTHS, [340, 390, 640, 1050, 1710, 2260, 2840, 2750, 1880, 1170, 520, 380]) ] RadialChart( data=[weekday_visits, weekend_visits], type=RADIAL_TYPE.BAR, bar_mode=BAR_MODE.STACK, subtitle=["Weekdays", "Weekends"], show_legend=True, innerradius=0.3, title="Mountain hut visitors by month", figsize=FIG_SIZE.SQUARE, ).show() ``` # Histogram This section showcases the histogram. It contains examples of how to create histograms using the [datachart.charts.Histogram](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.Histogram) function. Looking for a specific customization? Jump straight to the [quick reference](#customizing-the-histogram), which maps common tasks to the parameter or style attribute that does the job. As mentioned above, the histograms are created using the `Histogram` function found in the [datachart.charts](https://eriknovak.github.io/datachart/0.9.0/references/charts/index.md) module. Let's import it: ``` from datachart.charts import Histogram ``` ## Histogram Input Attributes The `Histogram` function accepts keyword arguments for chart configuration. The main argument is `data`, which contains the values to bin. For a single histogram, `data` is a list of dictionaries. For multiple histograms, `data` is a list of lists. ``` Histogram( data=[{ # A list of histogram data points (or list of lists for multiple charts) "x": Union[int, float], # The value to bin }], style={ # The style of the histogram (optional) "plot_hist_color": Optional[str], # The color of the histogram (hex color code) "plot_hist_alpha": Optional[float], # The alpha of the histogram (how visible it is) "plot_hist_zorder": Optional[int], # The zorder of the histogram "plot_hist_fill": Optional[bool], # Whether the bars are filled "plot_hist_hatch": Optional[HATCH_STYLE], # The hatch pattern of the bars "plot_hist_type": Optional[HISTOGRAM_TYPE], # The histogram type (bar, step, etc.) "plot_hist_align": Optional[str], # The bar alignment within the bin ("left", "mid", "right") "plot_hist_edge_width": Optional[float], # The edge width of the bars "plot_hist_edge_color": Optional[str], # The edge color of the bars (hex color code) "plot_xticks_label_rotate": Optional[float], # The x-axis tick label rotation "plot_yticks_label_rotate": Optional[float], # The y-axis tick label rotation }, subtitle=Optional[str], # The subtitle of the chart (or list for multiple charts) emphasis=Optional[str], # "highlight" or "background" (or list for multiple charts) title=Optional[str], # The title of the chart xlabel=Optional[str], # The x-axis label ylabel=Optional[str], # The y-axis label figsize=Optional[Tuple[float, float]], # The figure size in inches show_grid=Optional[str], # Which grid lines to show ("both", "x", "y") aspect_ratio=Optional[str], # The aspect ratio of the axes ("auto", "equal") show_legend=Optional[bool], # Whether to show the legend num_bins=Optional[int], # The number of bins (default: 20) orientation=Optional[str], # The orientation of the bars ("vertical", "horizontal") show_density=Optional[bool], # Whether to show the density instead of the count show_cumulative=Optional[bool], # Whether to show the cumulative distribution subplots=Optional[bool], # Whether to draw each chart in its own subplot max_cols=Optional[int], # Maximum number of subplots per row sharex=Optional[bool], # Whether subplots share the x-axis sharey=Optional[bool], # Whether subplots share the y-axis scalex=Optional[str], # The x-axis scale ("linear", "log", "symlog", "asinh") scaley=Optional[str], # The y-axis scale ("linear", "log", "symlog", "asinh") xmin=Optional[Union[int, float]], # The x-axis range xmax=Optional[Union[int, float]], ymin=Optional[Union[int, float]], # The y-axis range ymax=Optional[Union[int, float]], xticks=Optional[List[Union[int, float]]], # the x-axis ticks xticklabels=Optional[List[str]], # the x-axis tick labels (must be same length as xticks) xtickrotate=Optional[int], # the x-axis tick labels rotation yticks=Optional[List[Union[int, float]]], # the y-axis ticks yticklabels=Optional[List[str]], # the y-axis tick labels (must be same length as yticks) ytickrotate=Optional[int], # the y-axis tick labels rotation vlines=Optional[Union[dict, List[dict]]], # the vertical lines hlines=Optional[Union[dict, List[dict]]], # the horizontal lines x=Optional[str], # the key holding the value to bin (default: "x") ) ``` For more details, see the [datachart.charts.Histogram](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.Histogram) function. ## Basics The examples in this guide share one dataset: the flipper length (in millimeters) and body mass (in grams) of the 342 penguins of the [Palmer penguins](https://allisonhorst.github.io/palmerpenguins/) dataset, measured on three islands of the Palmer Archipelago, Antarctica, and released under CC0. The data is hard-coded in a hidden cell; `penguins` holds one point per penguin, and `penguins_by_species` holds one list per species — Adelie, Chinstrap and Gentoo — in the order of `SPECIES`. Each data point is a dictionary with an `x` value — here the flipper length — which the histogram bins and counts. The other keys are carried along and ignored — the histogram reads `x` only: ``` penguins[:3] ``` **Basic example.** Only the `data` argument is required to draw the histogram. ``` Histogram( # add the data to the chart data=penguins ).show() ``` ## Customizing the Histogram Every customization is either a keyword argument of `Histogram` or a `plot_hist_*` attribute of its `style` dictionary. The table maps common tasks to the one you need and links to the subsection that shows it. | I want to… | Use | See | | --------------------------------------- | ------------------------------------------------------------------------------------------ | ------------------------------------------------------------- | | add a title and axis labels | `title`, `xlabel`, `ylabel` | [Title, axis labels and ticks](#title-axis-labels-and-ticks) | | set custom tick positions and labels | `xticks`, `xticklabels`, `yticks`, `yticklabels` | [Title, axis labels and ticks](#title-axis-labels-and-ticks) | | rotate the tick labels | `xtickrotate`, `ytickrotate` | [Title, axis labels and ticks](#title-axis-labels-and-ticks) | | fix the axis range | `xmin`, `xmax`, `ymin`, `ymax` | [Title, axis labels and ticks](#title-axis-labels-and-ticks) | | resize the figure | `figsize` | [Figure size and grid](#figure-size-and-grid) | | show grid lines | `show_grid` | [Figure size and grid](#figure-size-and-grid) | | change how finely the values are binned | `num_bins` | [Number of bins](#number-of-bins) | | change the bar color or transparency | `style={"plot_hist_color": ..., "plot_hist_alpha": ...}` | [Histogram style](#histogram-style) | | draw the histogram as a step outline | `style={"plot_hist_type": ...}` | [Histogram style](#histogram-style) | | hatch or outline the bars | `style={"plot_hist_hatch": ..., "plot_hist_edge_width": ..., "plot_hist_edge_color": ...}` | [Histogram style](#histogram-style) | | draw the bars horizontally | `orientation` | [Orientation](#orientation) | | highlight one series, mute the rest | `emphasis` | [Emphasis](#emphasis) | | mark a threshold or a reference value | `vlines`, `hlines` | [Reference lines](#reference-lines) | | compare several series in one chart | `data` as a list of lists, `subtitle`, `show_legend` | [Multiple Histograms](#multiple-histograms) | | stack or overlay the series | `bar_mode` | [Multiple Histograms](#multiple-histograms) | | draw each series in its own subplot | `subplots`, `sharex`, `sharey`, `max_cols` | [Subplots](#subplots) | | show densities or cumulative counts | `show_density`, `show_cumulative` | [Histogram Views](#histogram-views) | | overlay a smooth density curve | `stats.kde1d`, `Panel` | [Density curve](#density-curve) | | use a logarithmic axis | `scalex`, `scaley` | [Axis scales](#axis-scales) | | plot data with other key names | `x` | [Custom data keys](#custom-data-keys) | | save the chart to a file | `save_figure` | [Saving the Chart as an Image](#saving-the-chart-as-an-image) | The full list of style attributes is in the [datachart.typings.HistStyleAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.HistStyleAttrs) type; the full list of parameters is in the [datachart.charts.Histogram](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.Histogram) reference. ### Title, axis labels and ticks To add the chart title and axis labels, add the `title`, `xlabel` and `ylabel` attributes. The tick positions and their labels can be set with `xticks` and `xticklabels` (or `yticks` and `yticklabels`) — here the flipper length is ticked every 10 mm. Tick labels can be rotated with `xtickrotate` (or `ytickrotate`), and the axis range can be fixed with `xmin`, `xmax`, `ymin` and `ymax`. ``` FLIPPER_TICKS = [170, 180, 190, 200, 210, 220, 230] Histogram( data=penguins, # add the title title="Flipper length of Palmer penguins", # add the x and y axis labels xlabel="Flipper length (mm)", ylabel="Number of penguins", # tick the flipper length every 10 mm xticks=FLIPPER_TICKS, # fix the x-axis range xmin=170, xmax=235, ).show() ``` ### Figure size and grid To change the figure size, add the `figsize` attribute. The `figsize` attribute can be a tuple (width, height), values are in inches. The `datachart` package provides a [datachart.constants.FIG_SIZE](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.FIG_SIZE) constant, which contains some of the predefined figure sizes. To add the grid, add the `show_grid` attribute. The possible options are: | Option | Description | | -------- | ----------------------------------------------- | | `"both"` | shows both the x-axis and the y-axis gridlines. | | `"x"` | shows only the x-axis grid lines. | | `"y"` | shows only the y-axis grid lines. | Again, `datachart` provides a [datachart.constants.SHOW_GRID](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.SHOW_GRID) constant, which contains the supported options. For a vertical histogram the counts are read off the y-axis, so `"y"` is usually all the grid a histogram needs. ``` from datachart.constants import FIG_SIZE, SHOW_GRID ``` ``` Histogram( data=penguins, title="Flipper length of Palmer penguins", xlabel="Flipper length (mm)", ylabel="Number of penguins", xticks=FLIPPER_TICKS, # add to determine the figure size figsize=FIG_SIZE.FULL_SHORT, # add to show the grid lines show_grid=SHOW_GRID.Y, ).show() ``` ### Number of bins The histogram splits the range of the values into equal-width bins and counts the values in each. By default there are 20 bins; the `num_bins` attribute changes that. Fewer bins smooth the distribution, more bins expose its detail — and its noise. The flipper lengths run from 172 to 231 mm: with 8 bins the distribution is reduced to a coarse silhouette, with 40 bins every bin is about 1.5 mm wide and the two peaks — the Adelie and Chinstrap penguins around 190 mm, the Gentoo penguins around 215 mm — stand apart, at the price of jagged bars. ``` for num_bins in [8, 40]: Histogram( data=penguins, title=f"Flipper length of Palmer penguins in {num_bins} bins", xlabel="Flipper length (mm)", ylabel="Number of penguins", xticks=FLIPPER_TICKS, figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, # change the number of bins num_bins=num_bins, ).show() ``` ### Histogram style To change the histogram style, add the `style` attribute with the corresponding attributes. The supported attributes are shown in the [datachart.typings.HistStyleAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.HistStyleAttrs) type, which contains the following attributes: | Attribute | Description | | ---------------------------- | ---------------------------------------------------------------- | | `"plot_hist_color"` | The color of the histogram (hex color code). | | `"plot_hist_alpha"` | The alpha of the histogram (how visible it is). | | `"plot_hist_zorder"` | The zorder of the histogram. | | `"plot_hist_fill"` | Whether the bars are filled. | | `"plot_hist_hatch"` | The hatch pattern of the bars. | | `"plot_hist_type"` | The histogram type (bar, step, etc.). | | `"plot_hist_align"` | The bar alignment within the bin (`"left"`, `"mid"`, `"right"`). | | `"plot_hist_edge_width"` | The edge width of the bars. | | `"plot_hist_edge_color"` | The edge color of the bars (hex color code). | | `"plot_xticks_label_rotate"` | The rotation of the x-axis tick labels. | | `"plot_yticks_label_rotate"` | The rotation of the y-axis tick labels. | Again, to help with the style settings, the [datachart.constants](https://eriknovak.github.io/datachart/0.9.0/references/constants/index.md) module contains the following constants: | Constant | Description | | ------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------ | | [datachart.constants.HATCH_STYLE](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.HATCH_STYLE) | The hatch pattern of the bars. | | [datachart.constants.HISTOGRAM_TYPE](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.HISTOGRAM_TYPE) | The histogram type. | The histogram type decides how the bins are drawn: | Type | Description | | -------------- | ----------------------------------------------- | | `"bar"` | One bar per bin (the default). | | `"step"` | An unfilled outline that steps from bin to bin. | | `"stepfilled"` | A filled outline that steps from bin to bin. | The type is a per-series render style; how several series share the axis is the `bar_mode` argument's job (see [Multiple Histograms](#multiple-histograms)). For `"step"` the outline is the mark itself, so it draws in the series color at the theme's line width; `plot_hist_edge_color` and `plot_hist_edge_width` override that explicitly. The example below changes the color, transparency, hatch, outline and type of the histogram in one go. Any attribute you leave out keeps the value of the active theme. ``` from datachart.constants import HATCH_STYLE, HISTOGRAM_TYPE ``` ``` Histogram( data=penguins, # define the style of the histogram style={ "plot_hist_color": "#e76f51", "plot_hist_alpha": 0.6, "plot_hist_hatch": HATCH_STYLE.DIAGONAL, "plot_hist_edge_width": 1.5, "plot_hist_edge_color": "#1d3557", "plot_hist_type": HISTOGRAM_TYPE.STEP_FILLED, }, title="Flipper length of Palmer penguins", xlabel="Flipper length (mm)", ylabel="Number of penguins", xticks=FLIPPER_TICKS, figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, ).show() ``` ### Orientation To draw the bars horizontally, add the `orientation` attribute, which supports the following values: | Value | Description | | -------------- | -------------------------------------------- | | `"vertical"` | The bars rise from the x-axis (the default). | | `"horizontal"` | The bars extend from the y-axis. | Again, to help with the settings, the [datachart.constants](https://eriknovak.github.io/datachart/0.9.0/references/constants/index.md) module contains the [datachart.constants.ORIENTATION](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.ORIENTATION) constant. With horizontal bars the binned values sit on the y-axis and the counts on the x-axis, so the axis labels, the ticks and the grid swap places too. ``` from datachart.constants import ORIENTATION ``` ``` Histogram( data=penguins, title="Flipper length of Palmer penguins", # the flipper length is now on the y-axis xlabel="Number of penguins", ylabel="Flipper length (mm)", yticks=FLIPPER_TICKS, figsize=FIG_SIZE.FULL_MEDIUM, # change the grid to match the change in orientation show_grid=SHOW_GRID.X, # change the orientation of the bars orientation=ORIENTATION.HORIZONTAL, ).show() ``` ### Emphasis When a chart carries several series, the story is often about one of them. The `emphasis` attribute expresses that directly: `"highlight"` thickens the outline of a series and brings it to the front, `"background"` mutes a series (the theme's muted color at a lower alpha, drawn behind the others), and `None` leaves a series unchanged. For multiple charts, `emphasis` is a list aligned with `data`, just like `subtitle` and `style`. Only emphasized-or-unset series appear in the legend — background series drop out of it. The role strings are also available as the [datachart.constants.EMPHASIS](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.EMPHASIS) constants. Emphasis also changes how the histograms are drawn: when any series carries an emphasis role, the histograms draw individually, overlaid on shared bins, instead of stacked on top of each other — a muted background stacked under the highlight would make no sense. The example highlights the Gentoo penguins against the other two species. See the [Highlighting](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/styling/highlighting/index.md) guide for how emphasis works across all chart types and themes. ``` Histogram( data=penguins_by_species, subtitle=SPECIES, # mute the Adelie and Chinstrap penguins, highlight the Gentoo penguins emphasis=["background", "background", "highlight"], title="Flipper length of Palmer penguins", xlabel="Flipper length (mm)", ylabel="Number of penguins", xticks=FLIPPER_TICKS, figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, show_legend=True, ).show() ``` ### Reference lines Reference lines mark a threshold or a reference value on the chart. **Vertical lines.** Use the `vlines` argument with the [datachart.typings.VLinePlotAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.VLinePlotAttrs) typing, which is either a `dict` or a `List[dict]` where each dictionary contains some of the following attributes: ``` { "x": Union[int, float], # The x-axis value "ymin": Optional[Union[int, float]], # The minimum y-axis value "ymax": Optional[Union[int, float]], # The maximum y-axis value "style": { # The style of the line (optional) "plot_vline_color": Optional[str], # The color of the line (hex color code) "plot_vline_style": Optional[LineStyle], # The line style (solid, dashed, etc.) "plot_vline_width": Optional[float], # The width of the line "plot_vline_alpha": Optional[float], # The alpha of the line (how visible the line is) }, "label": Optional[str], # The label of the line (shown in the legend) } ``` **Horizontal lines.** Use the `hlines` argument with the [datachart.typings.HLinePlotAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.HLinePlotAttrs) typing, which has the same shape with `y`, `xmin`, `xmax` and `plot_hline_*` style attributes. On a histogram a vertical line marks a value on the binned axis — a mean, a cut-off, a specification limit — while a horizontal line marks a count. The example marks the mean (201 mm) and the median (197 mm) of the flipper lengths; the gap between the two is the mark of the long-flippered Gentoo penguins pulling the mean to the right. The line labels appear in the legend. ``` from datachart.constants import LINE_STYLE ``` ``` Histogram( data=penguins, # name the series for the legend subtitle="all species", # add vertical lines at the mean and the median flipper length vlines=[ { "x": 201, "label": "mean", "style": { "plot_vline_color": "#1d3557", "plot_vline_style": LINE_STYLE.DASHED, "plot_vline_width": 1.5, }, }, { "x": 197, "label": "median", "style": { "plot_vline_color": "#e9a03b", "plot_vline_style": LINE_STYLE.DOTTED, "plot_vline_width": 1.5, }, }, ], title="Flipper length of Palmer penguins", xlabel="Flipper length (mm)", ylabel="Number of penguins", xticks=FLIPPER_TICKS, figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, show_legend=True, ).show() ``` ## Multiple Histograms To create multiple histograms, pass a list of lists to the `data` argument. Each inner list represents the data for one histogram. Per-chart attributes like `subtitle`, `style` and `emphasis` can be passed as lists, where each element corresponds to a chart. Multiple charts pattern For multiple charts, `data` becomes a list of lists, and per-chart attributes like `subtitle` and `style` become lists where each element applies to the corresponding chart. The `penguins_by_species` dataset is such a list of lists, one series per species. By default, multiple histograms in one chart are binned on shared bins and **stacked** on top of each other, so the outline of the stack is the histogram of all the values together and each color shows a species' share of every bin. Pass `bar_mode="overlay"` to draw the series individually over each other instead. Separate series can also be styled separately: a single `style` dictionary applies to every chart, while a list of dictionaries styles each chart on its own (`None` keeps the theme style for that chart). ``` Histogram( # use a list of lists to define multiple histograms data=penguins_by_species, # style can be a list (one per chart) or a single dict (applies to all) style=[ {"plot_hist_color": "#e76f51"}, {"plot_hist_color": "#2a9d8f"}, None, # keep the theme style for the third chart ], title="Flipper length of Palmer penguins", xlabel="Flipper length (mm)", ylabel="Number of penguins", xticks=FLIPPER_TICKS, figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, ).show() ``` ### Sub-chart subtitles We can name each chart by passing a list of subtitles to the `subtitle` argument. In addition, to help with discerning which chart is which, use the `show_legend` argument to show the legend of the charts. ``` Histogram( data=penguins_by_species, # add a subtitle to each chart subtitle=SPECIES, title="Flipper length of Palmer penguins", xlabel="Flipper length (mm)", ylabel="Number of penguins", xticks=FLIPPER_TICKS, figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, # show the legend show_legend=True, ).show() ``` ### Subplots To draw each chart in its own subplot, add the `subplots` attribute. The chart's `subtitle` are then added at the top of each subplot, while the `title`, `xlabel` and `ylabel` are positioned to be global for all charts. The `max_cols` attribute limits the number of subplots per row. Each subplot bins its own values and scales its own axes, so the three histograms are not yet comparable — the next section fixes that. ``` Histogram( data=penguins_by_species, subtitle=SPECIES, title="Flipper length of Palmer penguins", xlabel="Flipper length (mm)", ylabel="Number of penguins", figsize=FIG_SIZE.FULL_MEDIUM, show_grid=SHOW_GRID.Y, # show each chart in its own subplot subplots=True, # at most two subplots per row max_cols=2, ).show() ``` ### Sharing the x-axis and/or y-axis across subplots To share the x-axis and/or y-axis across subplots, add the `sharex` and/or `sharey` attributes, which are boolean values that specify whether to share the axis across all subplots. With a shared x-axis the subplots also share their bins, so the species line up bin for bin; with a shared y-axis the bar heights become comparable and the smaller Chinstrap sample (68 penguins against 151 Adelie) no longer fills its subplot. ``` Histogram( data=penguins_by_species, subtitle=SPECIES, title="Flipper length of Palmer penguins", xlabel="Flipper length (mm)", ylabel="Number of penguins", xticks=FLIPPER_TICKS, figsize=FIG_SIZE.FULL_MEDIUM, show_grid=SHOW_GRID.Y, subplots=True, max_cols=2, # share the x-axis across subplots sharex=True, # share the y-axis across subplots sharey=True, ).show() ``` ## Histogram Views A histogram counts values per bin by default. Two attributes change what the bars measure: `show_density` turns the counts into a probability density, and `show_cumulative` accumulates the bins from left to right. They apply to every chart in the figure, and they combine. ### Density distribution view To show the histograms as a density distribution, add the `show_density` attribute. The bars are scaled so that their total area is 1 — the bar heights are densities rather than counts, and the y-axis no longer depends on the sample size. That is what makes samples of different sizes comparable: per count, the 151 Adelie penguins tower over the 68 Chinstrap penguins; per density, the two species have distributions of about the same width, just shifted. ``` Histogram( data=penguins_by_species, subtitle=SPECIES, title="Flipper length of Palmer penguins", xlabel="Flipper length (mm)", ylabel="Density", xticks=FLIPPER_TICKS, figsize=FIG_SIZE.FULL_MEDIUM, show_grid=SHOW_GRID.Y, subplots=True, max_cols=2, sharex=True, sharey=True, # show the density instead of the count show_density=True, ).show() ``` ### Density curve A density histogram depends on where its bins fall; a kernel density estimate smooths the same values into a curve that does not. [datachart.utils.stats.kde1d](https://eriknovak.github.io/datachart/0.9.0/references/utils/stats/#datachart.utils.stats.kde1d) computes it and returns the `{x, y}` points a [datachart.charts.LineChart](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.LineChart) draws, so there is no separate density chart: overlay the curve on the density histogram with [datachart.utils.Panel](https://eriknovak.github.io/datachart/0.9.0/references/utils/#datachart.utils.Panel). Both integrate to 1, so they share the y-axis. This is how a KDE chart is built from raw values: estimate the curve, then draw it. The `bandwidth` sets how smooth the curve is — a [datachart.constants.BANDWIDTH](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.BANDWIDTH) rule (Scott's by default) or a scalar factor, where smaller values follow the values more closely — and `show_area` fills the curve, the way a density plot is usually drawn. ``` from datachart.charts import LineChart from datachart.utils import Panel from datachart.utils.stats import kde1d ``` ``` # the flipper lengths, smoothed into a density curve: what a KDE chart draws flipper_density = kde1d([point["x"] for point in penguins]) flipper_density[:3] ``` ``` Panel( [ Histogram(data=penguins, subtitle="binned", show_density=True), # the curve over the bars LineChart(data=flipper_density, subtitle="kernel density", show_area=True), ], title="Flipper length of Palmer penguins", xlabel="Flipper length (mm)", ylabel_left="Density", show_legend=True, show_grid=SHOW_GRID.Y, figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` ### Cumulative distribution view To show the histograms as a cumulative distribution, add the `show_cumulative` attribute. Each bar then holds the count of all the values up to and including its bin, so the bars climb from left to right and the last bar reaches the sample size. The cumulative view answers "how many penguins have flippers shorter than *x*?" directly — at the 200 mm mark nearly every Adelie penguin is already counted, seven in ten Chinstrap penguins, and not a single Gentoo penguin. ``` Histogram( data=penguins_by_species, subtitle=SPECIES, title="Flipper length of Palmer penguins", xlabel="Flipper length (mm)", ylabel="Number of penguins", xticks=FLIPPER_TICKS, figsize=FIG_SIZE.FULL_MEDIUM, show_grid=SHOW_GRID.Y, subplots=True, max_cols=2, sharex=True, sharey=True, # show the cumulative count show_cumulative=True, ).show() ``` ### Cumulative & density distribution view The `show_density` and `show_cumulative` attributes combine into the empirical cumulative distribution: every bar holds the share of the values up to its bin, the last bar reaches 1, and the species become comparable regardless of how many penguins were measured: four out of five Gentoo penguins have flippers longer than any Adelie penguin. ``` Histogram( data=penguins_by_species, subtitle=SPECIES, title="Flipper length of Palmer penguins", xlabel="Flipper length (mm)", ylabel="Cumulative share", xticks=FLIPPER_TICKS, figsize=FIG_SIZE.FULL_MEDIUM, show_grid=SHOW_GRID.Y, subplots=True, max_cols=2, sharex=True, sharey=True, # show the cumulative density show_density=True, show_cumulative=True, ).show() ``` ## Additional Features ### Axis scales The user can change the axis scale using the `scalex` and `scaley` attributes. The supported scale options are: | Options | Description | | ---------- | ------------------------ | | `"linear"` | The linear scale. | | `"log"` | The log scale. | | `"symlog"` | The symmetric log scale. | | `"asinh"` | The asinh scale. | Again, to help with the options settings, the [datachart.constants](https://eriknovak.github.io/datachart/0.9.0/references/constants/index.md) module contains the following constants: | Constant | Description | | ------------------------------------------------------------------------------------------------------------------------ | ----------------- | | [datachart.constants.SCALE](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.SCALE) | The axis options. | On a histogram the scale of the count axis is the one that usually matters. Bins in the tails of a distribution hold a handful of values and are barely visible next to the peak on a linear scale; a logarithmic y-axis gives every occupied bin a visible bar and shows how quickly the tails fall off. Note that the bins themselves stay equal-width on the data scale whichever axis scale is applied. ``` from datachart.constants import SCALE ``` ``` for scale in [SCALE.LINEAR, SCALE.LOG]: Histogram( data=penguins, title=f"Flipper length of Palmer penguins on the '{scale}' scale", xlabel="Flipper length (mm)", ylabel="Number of penguins", xticks=FLIPPER_TICKS, figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, num_bins=40, # set the scale of the y axis scaley=scale, ).show() ``` ### Custom data keys By default, the `data` items are dictionaries with the key `x` holding the value to bin. Data that comes from elsewhere rarely calls its columns `x`, and renaming every key just to plot it is a chore. Instead, tell `Histogram` which key to read with the `x` argument. The `penguin_records` list below stores the same penguins under their natural names, and the example bins their body mass instead of their flipper length. ``` penguin_records = [ { "species": species, "flipper_length_mm": flipper, "body_mass_g": mass, } for species in SPECIES for flipper, mass in PENGUINS[species] ] penguin_records[:3] ``` ``` figure = Histogram( data=penguin_records, # specify which key holds the value to bin x="body_mass_g", title="Body mass of Palmer penguins", xlabel="Body mass (g)", ylabel="Number of penguins", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, num_bins=30, ) figure.show() ``` ## Saving the Chart as an Image To save the chart as an image, use the [datachart.utils.save_figure](https://eriknovak.github.io/datachart/0.9.0/references/utils#datachart.utils.save_figure) function. ``` from datachart.utils import save_figure ``` ``` save_figure(figure, "./fig_histogram.png", dpi=300) ``` The figure should be saved in the current working directory. ## Real-World Examples The following examples put the features above to work on real or realistic data. Each one states what its data is and where it comes from; the data itself lives in a hidden cell. ### Example 1: Marathon Finish Times (Bimodal Shape and Reference Lines) `finish_times` holds the finish times, in minutes, of 3,000 illustrative marathon runners drawn from a seeded generator: a faster group of club runners finishing around 3:35 and a larger recreational group around 4:30, so the distribution has two peaks. The finish time is the kind of value people think of in round numbers, so `xticks` label the axis in hours and `vlines` mark the 3, 4 and 5 hour milestones most runners set themselves. Sixty bins make each bin about four minutes wide. ``` HOUR_TICKS = [150, 180, 210, 240, 270, 300, 330, 360] HOUR_TICK_LABELS = ["2:30", "3:00", "3:30", "4:00", "4:30", "5:00", "5:30", "6:00"] Histogram( data=finish_times, subtitle="finishers", # mark the round-hour milestones vlines=[ { "x": minutes, "label": f"{minutes // 60}:00 finish", "style": { "plot_vline_color": "#1d3557", "plot_vline_style": LINE_STYLE.DASHED, "plot_vline_width": 1.5, }, } for minutes in [180, 240, 300] ], title="Marathon finish times", xlabel="Finish time (h:mm)", ylabel="Number of runners", # label the ticks in hours xticks=HOUR_TICKS, xticklabels=HOUR_TICK_LABELS, figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, num_bins=60, show_legend=True, ).show() ``` ### Example 2: Session Duration of an A/B Test (Emphasis and Density View) `session_durations` holds two series of illustrative session durations, in minutes, from an A/B test of a redesigned onboarding flow: 5,000 sessions of the control group and the 600 sessions of the much smaller variant group, both drawn from seeded log-normal generators. The question is whether the variant moved the distribution, so `emphasis` mutes the control group into a background reference and highlights the variant. With the roles set, the two histograms are overlaid on shared bins rather than stacked; `show_density` puts the samples on the same footing despite their very different sizes. The muted series drops out of the legend automatically. ``` Histogram( data=session_durations, subtitle=["control", "variant"], # mute the control group, highlight the variant emphasis=["background", "highlight"], title="Session duration with the redesigned onboarding", xlabel="Session duration (minutes)", ylabel="Density", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, num_bins=50, xmax=30, # compare the shapes, not the sample sizes show_density=True, show_legend=True, ).show() ``` ### Example 3: Request Latency (Log Scale and Density View) `latencies` holds the response time, in milliseconds, of 20,000 illustrative requests to a web service drawn from a seeded log-normal generator — the typical request answers in about 40 ms, but a long tail of slow requests stretches out to several hundred milliseconds. On a linear count axis the tail is invisible next to the peak, so `scaley` switches the y-axis to a log scale and every occupied bin gets a visible bar. `show_density` makes the y-axis independent of how many requests were sampled, and `vlines` mark the 200 ms latency objective that the tail has to stay under. ``` Histogram( data=latencies, subtitle="requests", # mark the latency objective vlines={ "x": 200, "label": "200 ms objective", "style": { "plot_vline_color": "#e76f51", "plot_vline_style": LINE_STYLE.DASHED, "plot_vline_width": 1.5, }, }, title="Request latency", xlabel="Response time (ms)", ylabel="Density", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, num_bins=80, # show the tail on a logarithmic density axis show_density=True, scaley=SCALE.LOG, show_legend=True, ).show() ``` ### Example 4: Daily Rainfall at Four Stations (Subplots, Shared Axes and Custom Data Keys) `rainfall_by_station` holds one series per weather station: the rainfall, in millimeters, on each of the wet days of one illustrative year at four stations of differing climates — a dry station with frequent light showers up to a wet station with occasional downpours — drawn from seeded gamma generators. The readings are stored under `rainfall_mm`, so the key is mapped with the `x` argument; `subplots` gives each station its own panel and `sharex` and `sharey` put the panels on the same bins and the same count axis, so a bar in one panel means the same as a bar in another. ``` Histogram( data=rainfall_by_station, # the readings are stored as "rainfall_mm" x="rainfall_mm", subtitle=list(STATIONS), title="Daily rainfall on wet days", xlabel="Rainfall (mm)", ylabel="Number of days", figsize=FIG_SIZE.FULL_MEDIUM, show_grid=SHOW_GRID.Y, num_bins=30, # one panel per station, on the same bins and count axis subplots=True, max_cols=2, sharex=True, sharey=True, ).show() ``` # Box Plot This section showcases the box plot. It contains examples of how to create box plots using the [datachart.charts.BoxPlot](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.BoxPlot) function. Looking for a specific customization? Jump straight to the [quick reference](#customizing-the-box-plot), which maps common tasks to the parameter or style attribute that does the job. As mentioned above, the box plots are created using the `BoxPlot` function found in the [datachart.charts](https://eriknovak.github.io/datachart/0.9.0/references/charts/index.md) module. Let's import it: ``` from datachart.charts import BoxPlot ``` ## Box Plot Input Attributes The `BoxPlot` function accepts keyword arguments for chart configuration. The main argument is `data`, which contains the data points. For a single box plot, `data` is a list of dictionaries; the points that share a `label` form one box. For multiple box plots, `data` is a list of lists. ``` BoxPlot( data=[{ # A list of box data points (or list of lists for multiple charts) "label": str, # The category label "value": Union[int, float], # The numeric value }], style={ # The style of the box (optional) "plot_box_color": Union[str, None], # The fill color of the box "plot_box_alpha": Union[float, None], # The alpha of the box "plot_box_linewidth": Union[int, float, None], # The line width of the box "plot_box_edgecolor": Union[str, None], # The edge color of the box "plot_box_outlier_marker": Union[str, None], # The outlier marker style "plot_box_outlier_size": Union[int, float, None], # The outlier marker size "plot_box_outlier_color": Union[str, None], # The outlier marker color "plot_box_outlier_edge_color": Union[str, None], # The outlier marker edge color "plot_box_median_color": Union[str, None], # The median line color "plot_box_median_linewidth": Union[int, float, None], # The median line width "plot_box_whisker_color": Union[str, None], # The whisker line color "plot_box_whisker_linewidth": Union[int, float, None], # The whisker line width "plot_box_cap_color": Union[str, None], # The cap line color "plot_box_cap_linewidth": Union[int, float, None], # The cap line width }, subtitle=Optional[str], # The subtitle of the chart (or list for multiple charts) title=Optional[str], # The title of the chart xlabel=Optional[str], # The x-axis label ylabel=Optional[str], # The y-axis label emphasis=Optional[Union[str, List[Optional[str]]]], # The emphasis role per box label ("background", "highlight", None) figsize=Optional[Tuple[float, float]], # The figure size in inches show_grid=Optional[str], # Which grid lines to show ("both", "x", "y") show_outliers=Optional[bool], # Whether to show outliers (default: True) show_notch=Optional[bool], # Whether to show notched boxes (default: False) orientation=Optional[ORIENTATION], # The orientation of the boxes scaley=Optional[str], # The y-axis scale ("linear", "log", ...) xmin=Optional[Union[int, float]], # The x-axis range xmax=Optional[Union[int, float]], ymin=Optional[Union[int, float]], # The y-axis range ymax=Optional[Union[int, float]], subplots=Optional[bool], # Whether to draw each chart in its own subplot (required for multiple charts) max_cols=Optional[int], # Maximum number of subplots per row sharex=Optional[bool], # Whether subplots share the x-axis sharey=Optional[bool], # Whether subplots share the y-axis xticks=Optional[List[Union[int, float]]], # the x-axis ticks xticklabels=Optional[List[str]], # the x-axis tick labels (must be same length as xticks) xtickrotate=Optional[int], # the x-axis tick labels rotation yticks=Optional[List[Union[int, float]]], # the y-axis ticks yticklabels=Optional[List[str]], # the y-axis tick labels (must be same length as yticks) ytickrotate=Optional[int], # the y-axis tick labels rotation vlines=Optional[Union[dict, List[dict]]], # the vertical lines hlines=Optional[Union[dict, List[dict]]], # the horizontal lines label=Optional[str], # The key in data holding the category label (default: "label") value=Optional[str], # The key in data holding the numeric value (default: "value") ) ``` For more details, see the [datachart.charts.BoxPlot](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.BoxPlot) function. ## Basics The examples in this guide share one dataset: the body mass of the 342 penguins of the [Palmer penguins](https://allisonhorst.github.io/palmerpenguins/) dataset (CC0), three species measured on the islands of the Palmer Archipelago in Antarctica. The data is hard-coded in a hidden cell, which keeps the sex and the flipper length of every penguin alongside its species — the later sections and examples reuse them. `chart_data` holds the body mass (in g) of every penguin, labeled with its species. The data is a flat list of dictionaries, one per data point, each with a `label` and a `value`. The points that share a `label` are grouped into one box, so three species give three boxes: ``` chart_data[:3] ``` **Basic example.** Only the `data` argument is required to draw the box plot. Each box spans the middle half of its values (the first to the third quartile), the line inside it is the median, the whiskers reach the furthest values within 1.5 times the box height, and the values beyond the whiskers are drawn as outliers. ``` BoxPlot( # add the data to the chart data=chart_data ).show() ``` ## Customizing the Box Plot Every customization is either a keyword argument of `BoxPlot` or a `plot_box_*` attribute of its `style` dictionary. The table maps common tasks to the one you need and links to the subsection that shows it. | I want to… | Use | See | | ------------------------------------------------ | --------------------------------------------------------------------------------- | --------------------------------------------------------------- | | add a title and axis labels | `title`, `xlabel`, `ylabel` | [Title and axis labels](#title-and-axis-labels) | | resize the figure | `figsize` | [Figure size and grid](#figure-size-and-grid) | | show the grid lines | `show_grid` | [Figure size and grid](#figure-size-and-grid) | | change the box fill, edge or transparency | `style={"plot_box_color": ..., "plot_box_edgecolor": ..., "plot_box_alpha": ...}` | [Box style](#box-style) | | style the median, whiskers and caps | `style={"plot_box_median_color": ..., "plot_box_whisker_color": ..., ...}` | [Box style](#box-style) | | style the outlier markers | `style={"plot_box_outlier_marker": ..., "plot_box_outlier_size": ..., ...}` | [Box style](#box-style) | | draw the boxes horizontally | `orientation` | [Box orientation](#box-orientation) | | hide the outliers | `show_outliers` | [Showing and hiding outliers](#showing-and-hiding-outliers) | | show the confidence interval of the median | `show_notch` | [Notched box plots](#notched-box-plots) | | highlight one box, mute the rest | `emphasis` | [Emphasis](#emphasis) | | draw a threshold or reference line | `hlines`, `vlines` | [Reference lines](#reference-lines) | | draw the observations or a violin with the boxes | `Panel` | [Boxes with swarms and violins](#boxes-with-swarms-and-violins) | | compare several datasets side by side | `data` as a list of lists, `subtitle`, `subplots` | [Multiple Box Plots](#multiple-box-plots) | | arrange the subplots | `max_cols`, `sharex`, `sharey` | [Shared axes across subplots](#shared-axes-across-subplots) | | draw every subplot horizontally | `orientation` | [Subplot orientation](#subplot-orientation) | | save the chart to a file | `save_figure` | [Saving the Chart as an Image](#saving-the-chart-as-an-image) | The full list of style attributes is in the [datachart.typings.BoxStyleAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.BoxStyleAttrs) type; the full list of parameters is in the [datachart.charts.BoxPlot](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.BoxPlot) reference. ### Title and axis labels To add the chart title and axis labels, add the `title`, `xlabel` and `ylabel` attributes. ``` BoxPlot( data=chart_data, # add the title title="Body mass of Palmer penguins", # add the x and y axis labels xlabel="Species", ylabel="Body mass (g)", ).show() ``` ### Figure size and grid To change the figure size, add the `figsize` attribute. The `figsize` attribute can be a tuple (width, height), values are in inches. The `datachart` package provides a [datachart.constants.FIG_SIZE](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.FIG_SIZE) constant, which contains some of the predefined figure sizes. To add the grid, add the `show_grid` attribute. The possible options are: | Option | Description | | -------- | ----------------------------------------------- | | `"both"` | shows both the x-axis and the y-axis gridlines. | | `"x"` | shows only the x-axis grid lines. | | `"y"` | shows only the y-axis grid lines. | Again, `datachart` provides a [datachart.constants.SHOW_GRID](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.SHOW_GRID) constant, which contains the supported options. The values of a vertical box plot are read off the y-axis, so the y-axis grid lines are the ones that help. ``` from datachart.constants import FIG_SIZE, SHOW_GRID ``` ``` BoxPlot( data=chart_data, title="Body mass of Palmer penguins", xlabel="Species", ylabel="Body mass (g)", # add to determine the figure size figsize=FIG_SIZE.FULL_SHORT, # add to show the grid lines show_grid=SHOW_GRID.Y, ).show() ``` ### Box style To change the box style, add the `style` attribute with the corresponding attributes. The supported attributes are shown in the [datachart.typings.BoxStyleAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.BoxStyleAttrs) type, which contains the following attributes: | Attribute | Description | | ------------------------------- | ----------------------------------------------- | | `"plot_box_color"` | The fill color of the box (hex color code). | | `"plot_box_alpha"` | The alpha of the box (how visible the box is). | | `"plot_box_linewidth"` | The line width of the box border. | | `"plot_box_edgecolor"` | The edge color of the box (hex color code). | | `"plot_box_outlier_marker"` | The outlier marker style. | | `"plot_box_outlier_size"` | The outlier marker size. | | `"plot_box_outlier_color"` | The outlier marker color (hex color code). | | `"plot_box_outlier_edge_color"` | The outlier marker edge color (hex color code). | | `"plot_box_median_color"` | The median line color (hex color code). | | `"plot_box_median_linewidth"` | The median line width. | | `"plot_box_whisker_color"` | The whisker line color (hex color code). | | `"plot_box_whisker_linewidth"` | The whisker line width. | | `"plot_box_cap_color"` | The cap line color (hex color code). | | `"plot_box_cap_linewidth"` | The cap line width. | Again, to help with the style settings, the [datachart.constants](https://eriknovak.github.io/datachart/0.9.0/references/constants/index.md) module contains the following constants: | Constant | Description | | ------------------------------------------------------------------------------------------------------------------------------------ | ------------------------- | | [datachart.constants.LINE_MARKER](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.LINE_MARKER) | The outlier marker style. | The `style` applies to every box of the chart. The median is the one line every reader looks for, so it earns a contrasting color and a heavier width; the outlier attributes style the two Chinstrap outliers. Any attribute you leave out keeps the value of the active theme. ``` from datachart.constants import LINE_MARKER ``` ``` BoxPlot( data=chart_data, # define the style of the boxes style={ "plot_box_color": "#6baed6", "plot_box_edgecolor": "#08519c", "plot_box_linewidth": 1.5, "plot_box_median_color": "#d62728", "plot_box_median_linewidth": 2, "plot_box_outlier_marker": LINE_MARKER.DIAMOND, "plot_box_outlier_size": 5, "plot_box_outlier_color": "#08519c", }, title="Body mass of Palmer penguins", xlabel="Species", ylabel="Body mass (g)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, ).show() ``` ### Box orientation To change the orientation of the boxes, add the `orientation` attribute, which supports the following values: | Value | Description | | -------------- | ------------------------------------------------------------------------ | | `"vertical"` | The boxes are vertical, one per category along the x-axis (the default). | | `"horizontal"` | The boxes are horizontal, one per category along the y-axis. | Again, `datachart` provides a [datachart.constants.ORIENTATION](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.ORIENTATION) constant, which contains the supported options. Horizontal boxes swap the roles of the axes: the categories move to the y-axis and the values to the x-axis, so the axis labels and the grid follow. ``` from datachart.constants import ORIENTATION ``` ``` BoxPlot( data=chart_data, # change the orientation of the boxes orientation=ORIENTATION.HORIZONTAL, title="Body mass of Palmer penguins", # swap the axis labels to match the orientation xlabel="Body mass (g)", ylabel="Species", figsize=FIG_SIZE.FULL_SHORT, # the values are now read off the x-axis show_grid=SHOW_GRID.X, ).show() ``` ### Showing and hiding outliers By default, the values beyond the whiskers are drawn as outliers. To hide them, add the `show_outliers` attribute set to `False`. The Chinstrap penguins have two: one of 2,700 g and one of 4,800 g, far from the 3,700 g median. With the outliers hidden the whiskers stay where they are — they still end at the furthest values within 1.5 times the box height — so hiding outliers changes what is drawn, not what the boxes summarize. ``` for show_outliers in [True, False]: BoxPlot( data=chart_data, # show or hide the values beyond the whiskers show_outliers=show_outliers, title=f"Body mass of Palmer penguins (outliers {'shown' if show_outliers else 'hidden'})", xlabel="Species", ylabel="Body mass (g)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, ).show() ``` ### Notched box plots To draw notched boxes, add the `show_notch` attribute set to `True`. The notch marks a confidence interval around the median: if the notches of two boxes do not overlap, their medians differ with some confidence. The notch narrows with the number of values — the 68 Chinstrap penguins get a wider notch than the 151 Adelie — and the Adelie and Chinstrap notches overlap, so their medians cannot be told apart, while the Gentoo are heavier beyond doubt. ``` BoxPlot( data=chart_data, # draw the confidence interval of the median as a notch show_notch=True, title="Body mass of Palmer penguins", xlabel="Species", ylabel="Body mass (g)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, ).show() ``` ### Emphasis To draw attention to one box, add the `emphasis` attribute. Box plots never overlay, so the `emphasis` list aligns with the box **labels** of one call, in the order the labels first appear in the data — here Adelie, Chinstrap, Gentoo. Each entry is one of the following roles: | Role | Description | | -------------- | ------------------------------------------------------------------------------------------------------------------------------- | | `"background"` | Mutes the box: it takes the muted color of the active theme, and its whiskers, caps, median and outliers mute together with it. | | `"highlight"` | Bolds the box edges and the median line. | | `None` | Leaves the box unchanged. | A single value instead of a list applies the role to every box. Again, `datachart` provides a [datachart.constants.EMPHASIS](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.EMPHASIS) constant, which contains the supported roles. The example puts the Gentoo box under scrutiny and pushes the other two species into the background. See the [Highlighting](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/styling/highlighting/index.md) guide for the full model — how the muted color follows the theme and how emphasis works across the other charts. ``` from datachart.constants import EMPHASIS ``` ``` BoxPlot( data=chart_data, # one role per box label: Adelie, Chinstrap, Gentoo emphasis=[EMPHASIS.BACKGROUND, EMPHASIS.BACKGROUND, EMPHASIS.HIGHLIGHT], title="Body mass of Palmer penguins", xlabel="Species", ylabel="Body mass (g)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, ).show() ``` ### Reference lines A reference line puts a threshold or a summary value next to the boxes. To add horizontal lines, add the `hlines` attribute with the [datachart.typings.HLinePlotAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.HLinePlotAttrs) typing, which is either a `dict` or a `List[dict]` where each dictionary contains some of the following attributes: ``` { "y": Union[int, float], # The y-axis value "xmin": Optional[Union[int, float]], # The minimum x-axis value "xmax": Optional[Union[int, float]], # The maximum x-axis value "style": { # The style of the line (optional) "plot_hline_color": Optional[str], # The color of the line (hex color code) "plot_hline_style": Optional[LineStyle], # The line style (solid, dashed, etc.) "plot_hline_width": Optional[float], # The width of the line "plot_hline_alpha": Optional[float], # The alpha of the line (how visible the line is) }, "label": Optional[str], # The label of the line } ``` Vertical lines work the same way through the `vlines` attribute and the [datachart.typings.VLinePlotAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.VLinePlotAttrs) typing, with `x`, `ymin`, `ymax` and `plot_vline_*` style attributes in place of their horizontal counterparts. The line style takes a [datachart.constants.LINE_STYLE](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.LINE_STYLE) value. The example marks the mean body mass of all 342 penguins, which shows at a glance that the whole Gentoo box sits above it. ``` from datachart.constants import LINE_STYLE ``` ``` mean_mass = sum(penguin["value"] for penguin in chart_data) / len(chart_data) BoxPlot( data=chart_data, # add a horizontal line at the mean body mass of all penguins hlines={ "y": mean_mass, "style": { "plot_hline_color": "#d62728", "plot_hline_style": LINE_STYLE.DASHED, "plot_hline_width": 1.5, "plot_hline_alpha": 0.8, }, }, title="Body mass of Palmer penguins", xlabel="Species", ylabel="Body mass (g)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, ).show() ``` ### Boxes with swarms and violins A box summarizes its group; a [datachart.charts.SwarmPlot](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.SwarmPlot) shows every observation and a [datachart.charts.ViolinPlot](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.ViolinPlot) the shape of the distribution. Over the same labels the three draw at the same positions, so they compose with [datachart.utils.Panel](https://eriknovak.github.io/datachart/0.9.0/references/utils/#datachart.utils.Panel). The points draw above the boxes; hide the outliers, which the swarm already shows. ``` from datachart.charts import SwarmPlot, ViolinPlot from datachart.utils import Panel ``` ``` Panel( [ # the boxes summarize the groups; the swarm already draws the outliers BoxPlot(data=chart_data, show_outliers=False), SwarmPlot(data=chart_data), ], title="Body mass of Palmer penguins", xlabel="Species", ylabel_left="Body mass (g)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, ).show() ``` A violin body behind the boxes adds the distribution shape: draw it with `inner=None`, since the box supplies the summaries, and give the box a white fill so it reads over the body. One box plot and one violin plot per panel; swarms may repeat. ``` Panel( [ # the body only; the box plot supplies the summaries ViolinPlot(data=chart_data, inner=None, style={"plot_violin_alpha": 0.3}), BoxPlot( data=chart_data, show_outliers=False, style={"plot_box_color": "#FFFFFF", "plot_box_alpha": 0.9}, ), SwarmPlot(data=chart_data, style={"plot_swarm_size": 12}), ], title="Body mass of Palmer penguins", xlabel="Species", ylabel_left="Body mass (g)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, ).show() ``` ## Multiple Box Plots To create multiple box plots, pass a list of lists to the `data` argument. Each inner list holds the data points of one chart, which is drawn in its own subplot with the `subtitle` at the top and the `title`, `xlabel` and `ylabel` positioned to be global for all charts. Per-chart attributes like `subtitle` and `style` can be passed as lists, where each element corresponds to a chart; a single value applies to every chart. Subplots required for multiple datasets When using multiple datasets (list of lists), you **must** set `subplots=True`. Box plots do not support overlaying multiple datasets on a single axis. The example draws the body mass and the flipper length of the three species side by side. The two charts hold different quantities, so each gets its own subtitle with its unit and there is no global `ylabel`. ``` BoxPlot( # use a list of lists to define multiple box plots data=[chart_data, flipper_data], # add a subtitle to each chart subtitle=["Body mass (g)", "Flipper length (mm)"], title="Palmer penguins", xlabel="Species", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, # draw each chart in its own subplot subplots=True, ).show() ``` ### Shared axes across subplots To share the x-axis and/or y-axis across subplots, add the `sharex` and/or `sharey` attributes, which are boolean values that specify whether to share the axis across all subplots; a shared axis is labeled once, on the outer subplots only. The `max_cols` attribute limits the number of subplots per row — with `max_cols=1` the charts stack vertically. Which axis to share follows from the orientation: the two vertical charts have the species on the x-axis, so stacked with `sharex` the species are labeled once, under the bottom chart, while the values are different quantities and keep their own y-axis. ``` BoxPlot( data=[chart_data, flipper_data], subtitle=["Body mass (g)", "Flipper length (mm)"], title="Palmer penguins", xlabel="Species", figsize=FIG_SIZE.FULL_MEDIUM, show_grid=SHOW_GRID.Y, subplots=True, # stack the charts in one column max_cols=1, # share the x-axis across subplots sharex=True, ).show() ``` ### Subplot orientation The `orientation` attribute changes the orientation of every subplot at once. Horizontal boxes move the species to the y-axis, so side by side it is now `sharey` that labels them once, next to the left chart. ``` figure = BoxPlot( data=[chart_data, flipper_data], subtitle=["Body mass (g)", "Flipper length (mm)"], # change the orientation of the boxes in every subplot orientation=ORIENTATION.HORIZONTAL, title="Palmer penguins", ylabel="Species", figsize=FIG_SIZE.FULL_SHORT, # the values are now read off the x-axis show_grid=SHOW_GRID.X, subplots=True, # the species are now on the y-axis sharey=True, ) figure.show() ``` ## Saving the Chart as an Image To save the chart as an image, use the [datachart.utils.save_figure](https://eriknovak.github.io/datachart/0.9.0/references/utils#datachart.utils.save_figure) function. ``` from datachart.utils import save_figure ``` ``` save_figure(figure, "./fig_box_plot.png", dpi=300) ``` The figure should be saved in the current working directory. ## Real-World Examples The following examples put the features above to work on real or realistic data. Each one states what its data is and where it comes from; the data itself lives in a hidden cell. ### Example 1: Model Benchmark Across Seeds (Emphasis) `benchmark` holds the illustrative test accuracy of five models, each trained and evaluated with 20 random seeds, drawn from a seeded generator. Reporting one number per model hides how much of the difference between them is seed noise; one box per model shows the spread and the median together. The question is which model to ship, so `emphasis` highlights the model with the best median accuracy and pushes the other four into the background — the highlighted box keeps its color and gets bold edges, the muted ones become context. A short figure and the y-axis grid make the small differences in accuracy readable. ``` BEST_MODEL = "Deep + aug." BoxPlot( data=benchmark, # highlight the best model, mute the rest emphasis=[ EMPHASIS.HIGHLIGHT if model == BEST_MODEL else EMPHASIS.BACKGROUND for model in MODELS ], title=f"Test accuracy across {N_SEEDS} seeds", xlabel="Model", ylabel="Accuracy", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, ).show() ``` ### Example 2: Daily Temperatures by Month (Horizontal Boxes and Many Categories) `daily_temperatures` holds one year of daily mean temperatures (in °C) in Ljubljana, drawn from a seeded generator around the published 1991–2020 monthly climate normals of the city's weather station, with the larger day-to-day swings of winter. Twelve boxes are the case for horizontal boxes: the months stack from January at the bottom to December at the top, every label stays legible, and the temperature axis gets the full figure width, which a taller figure makes room for. The outliers are kept — an unusually cold or warm day is exactly what a reader of this chart looks for — and a dashed `vlines` reference marks the freezing point, so the months with days below zero are the boxes that cross it. ``` BoxPlot( data=daily_temperatures, # twelve labeled boxes read best top to bottom orientation=ORIENTATION.HORIZONTAL, # mark the freezing point vlines={ "x": 0, "style": { "plot_vline_color": "#4c72b0", "plot_vline_style": LINE_STYLE.DASHED, "plot_vline_width": 1.5, }, }, title="Daily mean temperature in Ljubljana", xlabel="Temperature (°C)", ylabel="Month", figsize=FIG_SIZE.FULL_MEDIUM, show_grid=SHOW_GRID.X, ).show() ``` ### Example 3: Service Response Times (Skewed Data, Outliers and an SLA Line) `response_times` holds the illustrative response time (in ms) of 200 requests to each of four services, drawn from a seeded log-normal generator: most requests are fast and a long tail of slow ones stretches each distribution upwards, as in most latency data. A dashed `hlines` reference marks the 500 ms service level agreement. Drawn twice, once with and once without outliers, the two charts show why the default keeps them on skewed data: the slow requests are the outliers, so hiding them hides exactly the requests that breach the agreement — without them Search looks safely below the line, with them its slowest requests cross it and the Reports tail stretches to well over a second. ``` for show_outliers in [True, False]: BoxPlot( data=response_times, # the slow requests are the outliers; hiding them hides the SLA breaches show_outliers=show_outliers, # mark the service level agreement hlines={ "y": SLA_MS, "style": { "plot_hline_color": "#d62728", "plot_hline_style": LINE_STYLE.DASHED, "plot_hline_width": 1.5, }, }, title=f"Response time of {N_REQUESTS} requests per service (outliers {'shown' if show_outliers else 'hidden'})", xlabel="Service", ylabel="Response time (ms)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, ).show() ``` ### Example 4: Penguin Body Mass by Sex (Multiple Box Plots and a Shared Value Axis) `body_mass_by_sex` splits the body mass of the Palmer penguins from the hidden cell of the [Basics](#basics) section into the 165 female and the 168 male penguins (the 9 penguins without a recorded sex are left out). Each sex gets its own chart, named with a list of `subtitle`, and `sharey` puts both on the same mass axis, so the boxes are comparable across the two subplots: the males of every species are heavier than the females, and the gap is largest for the Gentoo. The `xlabel` and `ylabel` label the species and the unit once for both. ``` BoxPlot( data=body_mass_by_sex, # one subtitle per chart subtitle=SEXES, title="Body mass of Palmer penguins by sex", xlabel="Species", ylabel="Body mass (g)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, subplots=True, # the same mass axis for both charts, so the boxes are comparable sharey=True, ).show() ``` # Violin Plot This section showcases the violin plot. It contains examples of how to create violin plots using the [datachart.charts.ViolinPlot](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.ViolinPlot) function. Looking for a specific customization? Jump straight to the [quick reference](#customizing-the-violin-chart), which maps common tasks to the parameter or style attribute that does the job. As mentioned above, the violin plots are created using the `ViolinPlot` function found in the [datachart.charts](https://eriknovak.github.io/datachart/0.9.0/references/charts/index.md) module. Let's import it: ``` from datachart.charts import ViolinPlot ``` ## Violin Plot Input Attributes The `ViolinPlot` function accepts keyword arguments for chart configuration. The main argument is `data`, which contains the data points. For a single violin plot, `data` is a list of dictionaries; the points that share a `label` form one violin. For multiple violin plots, `data` is a list of lists. ``` ViolinPlot( data=[{ # A list of violin data points (or list of lists for multiple charts) "label": str, # The category label "value": Union[int, float], # The numeric value }], style={ # The style of the violin (optional) "plot_violin_color": Union[str, None], # The fill color of the body "plot_violin_alpha": Union[float, None], # The alpha of the body "plot_violin_linewidth": Union[int, float, None], # The line width of the body edge "plot_violin_edgecolor": Union[str, None], # The edge color of the body (default: the fill) "plot_violin_width": Union[int, float, None], # The maximum width of the body "plot_violin_inner_color": Union[str, None], # The color of the inner marks (default: the font color) "plot_violin_inner_linewidth": Union[int, float, None], # The line width of the inner marks "plot_violin_median_color": Union[str, None], # The color of the median dot "plot_violin_median_size": Union[int, float, None], # The size of the median dot }, subtitle=Optional[str], # The subtitle of the chart (or list for multiple charts) title=Optional[str], # The title of the chart xlabel=Optional[str], # The x-axis label ylabel=Optional[str], # The y-axis label emphasis=Optional[Union[str, List[Optional[str]]]], # The emphasis role per violin label ("background", "highlight", None) inner=Optional[str], # The inner marks ("box", "quartiles", "median", None; default: "box") bandwidth=Optional[Union[str, float]], # The KDE bandwidth ("scott", "silverman", or a number; default: "scott") split=Optional[str], # The key in data whose two values split each violin in half figsize=Optional[Tuple[float, float]], # The figure size in inches show_grid=Optional[str], # Which grid lines to show ("both", "x", "y") show_legend=Optional[bool], # Whether to show the legend (the split values) orientation=Optional[ORIENTATION], # The orientation of the violins scaley=Optional[str], # The y-axis scale ("linear", "log", ...) xmin=Optional[Union[int, float]], # The x-axis range xmax=Optional[Union[int, float]], ymin=Optional[Union[int, float]], # The y-axis range ymax=Optional[Union[int, float]], subplots=Optional[bool], # Whether to draw each chart in its own subplot (required for multiple charts) max_cols=Optional[int], # Maximum number of subplots per row sharex=Optional[bool], # Whether subplots share the x-axis sharey=Optional[bool], # Whether subplots share the y-axis xticks=Optional[List[Union[int, float]]], # the x-axis ticks xticklabels=Optional[List[str]], # the x-axis tick labels (must be same length as xticks) xtickrotate=Optional[int], # the x-axis tick labels rotation yticks=Optional[List[Union[int, float]]], # the y-axis ticks yticklabels=Optional[List[str]], # the y-axis tick labels (must be same length as yticks) ytickrotate=Optional[int], # the y-axis tick labels rotation vlines=Optional[Union[dict, List[dict]]], # the vertical lines hlines=Optional[Union[dict, List[dict]]], # the horizontal lines label=Optional[str], # The key in data holding the category label (default: "label") value=Optional[str], # The key in data holding the numeric value (default: "value") ) ``` For more details, see the [datachart.charts.ViolinPlot](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.ViolinPlot) function. ## Basics The examples in this guide share one dataset: the body mass of the 342 penguins of the [Palmer penguins](https://allisonhorst.github.io/palmerpenguins/) dataset (CC0), three species measured on the islands of the Palmer Archipelago in Antarctica — the same data the [Box Plot](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/charts/boxplot/index.md) guide uses. The data is hard-coded in a hidden cell, which keeps the flipper length of every penguin alongside its species. `chart_data` holds the body mass (in g) of every penguin, labeled with its species and carrying its sex. The data is a flat list of dictionaries, one per data point, each with a `label` and a `value`; extra keys like `sex` are ignored until a section asks for them. The points that share a `label` are grouped into one violin, so three species give three violins: ``` chart_data[:3] ``` **Basic example.** Only the `data` argument is required to draw the violin plot. Each body is a kernel density estimate of its values, mirrored around the category position and scaled to the same maximum width; inside it, a thin bar spans the middle half of the values (the first to the third quartile), the line through it reaches the furthest values within 1.5 times the bar height, and the dot is the median. Where a box plot draws these summaries alone, the violin shows the shape of the distribution around them: the Gentoo are the heaviest species, and the Adelie have a wider spread than their box would suggest. ``` ViolinPlot( # add the data to the chart data=chart_data ).show() ``` ## Customizing the Violin Plot Every customization is either a keyword argument of `ViolinPlot` or a `plot_violin_*` attribute of its `style` dictionary. The table maps common tasks to the one you need and links to the subsection that shows it. | I want to… | Use | See | | ------------------------------------------------------ | ------------------------------------------------------------------------------------------ | --------------------------------------------------------------- | | add a title and axis labels | `title`, `xlabel`, `ylabel` | [Title and axis labels](#title-and-axis-labels) | | resize the figure | `figsize` | [Figure size and grid](#figure-size-and-grid) | | show the grid lines | `show_grid` | [Figure size and grid](#figure-size-and-grid) | | change the body fill, edge or transparency | `style={"plot_violin_color": ..., "plot_violin_edgecolor": ..., "plot_violin_alpha": ...}` | [Violin style](#violin-style) | | style the inner marks and the median dot | `style={"plot_violin_inner_color": ..., "plot_violin_median_color": ..., ...}` | [Violin style](#violin-style) | | change what is drawn inside the body | `inner` | [Inner marks](#inner-marks) | | smooth or sharpen the body | `bandwidth` | [Bandwidth](#bandwidth) | | compare two groups within each category | `split`, `show_legend` | [Split violins](#split-violins) | | draw the violins horizontally | `orientation` | [Violin orientation](#violin-orientation) | | highlight one violin, mute the rest | `emphasis` | [Emphasis](#emphasis) | | draw a threshold or reference line | `hlines`, `vlines` | [Reference lines](#reference-lines) | | draw a box plot or the observations inside the violins | `Panel` | [Violins with boxes and swarms](#violins-with-boxes-and-swarms) | | compare several datasets side by side | `data` as a list of lists, `subtitle`, `subplots` | [Multiple Violin Plots](#multiple-violin-charts) | | arrange the subplots | `max_cols`, `sharex`, `sharey` | [Shared axes across subplots](#shared-axes-across-subplots) | | save the chart to a file | `save_figure` | [Saving the Chart as an Image](#saving-the-chart-as-an-image) | The full list of style attributes is in the [datachart.typings.ViolinStyleAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.ViolinStyleAttrs) type; the full list of parameters is in the [datachart.charts.ViolinPlot](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.ViolinPlot) reference. ### Title and axis labels To add the chart title and axis labels, add the `title`, `xlabel` and `ylabel` attributes. ``` ViolinPlot( data=chart_data, # add the title title="Body mass of Palmer penguins", # add the x and y axis labels xlabel="Species", ylabel="Body mass (g)", ).show() ``` ### Figure size and grid To change the figure size, add the `figsize` attribute. The `figsize` attribute can be a tuple (width, height), values are in inches. The `datachart` package provides a [datachart.constants.FIG_SIZE](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.FIG_SIZE) constant, which contains some of the predefined figure sizes. To add the grid, add the `show_grid` attribute. The possible options are: | Option | Description | | -------- | ----------------------------------------------- | | `"both"` | shows both the x-axis and the y-axis gridlines. | | `"x"` | shows only the x-axis grid lines. | | `"y"` | shows only the y-axis grid lines. | Again, `datachart` provides a [datachart.constants.SHOW_GRID](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.SHOW_GRID) constant, which contains the supported options. The values of a vertical violin are read off the y-axis, so the y-axis grid lines are the ones that help. ``` from datachart.constants import FIG_SIZE, SHOW_GRID ``` ``` ViolinPlot( data=chart_data, title="Body mass of Palmer penguins", xlabel="Species", ylabel="Body mass (g)", # add to determine the figure size figsize=FIG_SIZE.FULL_SHORT, # add to show the grid lines show_grid=SHOW_GRID.Y, ).show() ``` ### Violin style To change the violin style, add the `style` attribute with the corresponding attributes. The supported attributes are shown in the [datachart.typings.ViolinStyleAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.ViolinStyleAttrs) type: the `plot_violin_color`, `plot_violin_edgecolor`, `plot_violin_alpha`, `plot_violin_linewidth` and `plot_violin_width` attributes style the body, the `plot_violin_inner_*` attributes the marks inside it, and the `plot_violin_median_*` attributes the median dot. The `style` applies to every violin of the chart. The body fill defaults to the theme's color cycle and the edge to the fill; the inner marks default to the theme's font color, so they read on any fill, and the median dot is white to stand out on the dark quartile bar. Any attribute you leave out keeps the value of the active theme. ``` ViolinPlot( data=chart_data, # define the style of the violins style={ "plot_violin_color": "#6baed6", "plot_violin_edgecolor": "#08519c", "plot_violin_linewidth": 1.5, "plot_violin_alpha": 0.6, "plot_violin_width": 0.6, "plot_violin_inner_color": "#08519c", "plot_violin_inner_linewidth": 1.5, "plot_violin_median_color": "#d62728", "plot_violin_median_size": 6, }, title="Body mass of Palmer penguins", xlabel="Species", ylabel="Body mass (g)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, ).show() ``` ### Inner marks To change what is drawn inside each body, add the `inner` attribute, which supports the following values: | Value | Description | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | | `"box"` | A thin bar from the first to the third quartile, a line reaching the furthest values within 1.5 times the bar height, and a median dot (the default). | | `"quartiles"` | A dashed median line and dotted first and third quartile lines, each as wide as the body at that value. | | `"median"` | A single solid median line, as wide as the body at that value. | | `None` | The body only. | Again, `datachart` provides a [datachart.constants.VIOLIN_INNER](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.VIOLIN_INNER) constant, which contains the supported options. The `"box"` marks summarize the values the way a box plot does; the `"quartiles"` lines show the same quartiles without hiding the shape behind them, and are the better choice when the bodies are narrow or the figure is small. ``` from datachart.constants import VIOLIN_INNER ``` ``` for inner in [VIOLIN_INNER.BOX, VIOLIN_INNER.QUARTILES, VIOLIN_INNER.MEDIAN, None]: ViolinPlot( data=chart_data, # change the marks drawn inside the bodies inner=inner, title=f"Body mass of Palmer penguins (inner={inner!r})", xlabel="Species", ylabel="Body mass (g)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, ).show() ``` ### Bandwidth The body is a Gaussian kernel density estimate, and the `bandwidth` attribute sets how wide its kernel is. It takes one of the following values: | Value | Description | | ------------- | ------------------------------------------------------------------------------------------------- | | `"scott"` | Scott's rule of thumb, scaled to the number of values (the default). | | `"silverman"` | Silverman's rule of thumb, about 6% wider than Scott's — the two look nearly the same. | | a number | A factor applied to the standard deviation of the values; smaller is sharper, larger is smoother. | Again, `datachart` provides a [datachart.constants.BANDWIDTH](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.BANDWIDTH) constant, which contains the supported rules. A small factor follows every bump of the data and a large one smooths the body into a single hump; the two rules of thumb sit in between and shrink the kernel as the number of values grows. The shape can change more than the summary marks, which are computed from the values and never from the estimate. ``` from datachart.constants import BANDWIDTH for bandwidth in [0.15, BANDWIDTH.SCOTT, 0.6]: ViolinPlot( data=chart_data, # sharpen or smooth the bodies bandwidth=bandwidth, title=f"Body mass of Palmer penguins (bandwidth={bandwidth!r})", xlabel="Species", ylabel="Body mass (g)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, ).show() ``` ### Split violins To compare two groups within each category, add the `split` attribute with the name of the key in `data` that holds the group of each point. The key must take **exactly two** distinct values across the data; each violin is then cut in half, the left half drawn from the points with the first value and the right half from the points with the second, in the order the values first appear. The halves take the first two colors of the theme's multiple-series palette, each keeps its own inner marks, and `show_legend` lists the two values. The penguins carry their sex, so `split="sex"` puts the female penguins of each species on the left and the males on the right. A handful of penguins have no recorded sex, which would be a third value, so they are filtered out first. ``` sexed_data = [penguin for penguin in chart_data if penguin["sex"] is not None] ViolinPlot( data=sexed_data, # split every violin by the sex of the penguins split="sex", # list the two split values in the legend show_legend=True, title="Body mass of Palmer penguins by sex", xlabel="Species", ylabel="Body mass (g)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, ).show() ``` The `inner` attribute applies to both halves; with `"quartiles"` each half gets its own quartile lines, which makes the difference between the medians easy to read across the centre line. ``` ViolinPlot( data=sexed_data, split="sex", # quartile lines in each half inner=VIOLIN_INNER.QUARTILES, show_legend=True, title="Body mass of Palmer penguins by sex", xlabel="Species", ylabel="Body mass (g)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, ).show() ``` ### Violin orientation To change the orientation of the violins, add the `orientation` attribute, which supports the following values: | Value | Description | | -------------- | -------------------------------------------------------------------------- | | `"vertical"` | The violins are vertical, one per category along the x-axis (the default). | | `"horizontal"` | The violins are horizontal, one per category along the y-axis. | Again, `datachart` provides a [datachart.constants.ORIENTATION](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.ORIENTATION) constant, which contains the supported options. Horizontal violins swap the roles of the axes: the categories move to the y-axis and the values to the x-axis, so the axis labels and the grid follow. ``` from datachart.constants import ORIENTATION ``` ``` ViolinPlot( data=chart_data, # change the orientation of the violins orientation=ORIENTATION.HORIZONTAL, title="Body mass of Palmer penguins", # swap the axis labels to match the orientation xlabel="Body mass (g)", ylabel="Species", figsize=FIG_SIZE.FULL_SHORT, # the values are now read off the x-axis show_grid=SHOW_GRID.X, ).show() ``` ### Emphasis To draw attention to one violin, add the `emphasis` attribute. As with box plots, the `emphasis` list aligns with the violin **labels** of one call, in the order the labels first appear in the data — here Adelie, Chinstrap, Gentoo. Each entry is one of the following roles: | Role | Description | | -------------- | ---------------------------------------------------------------------------------------------------------------- | | `"background"` | Mutes the violin: the body takes the muted color of the active theme, and its inner marks mute together with it. | | `"highlight"` | Bolds the body edge. | | `None` | Leaves the violin unchanged. | A single value instead of a list applies the role to every violin. Again, `datachart` provides a [datachart.constants.EMPHASIS](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.EMPHASIS) constant, which contains the supported roles. The example puts the Gentoo violin under scrutiny and pushes the other two species into the background. See the [Highlighting](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/styling/highlighting/index.md) guide for the full picture. ``` from datachart.constants import EMPHASIS ``` ``` ViolinPlot( data=chart_data, # one role per violin label: Adelie, Chinstrap, Gentoo emphasis=[EMPHASIS.BACKGROUND, EMPHASIS.BACKGROUND, EMPHASIS.HIGHLIGHT], title="Body mass of Palmer penguins", xlabel="Species", ylabel="Body mass (g)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, ).show() ``` ### Reference lines A reference line puts a threshold or a summary value next to the violins. To add horizontal lines, add the `hlines` attribute with the [datachart.typings.HLinePlotAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.HLinePlotAttrs) typing, which is either a `dict` or a `List[dict]`; vertical lines work the same way through the `vlines` attribute and the [datachart.typings.VLinePlotAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.VLinePlotAttrs) typing. The [Box Plot](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/charts/boxplot/#reference-lines) guide lists every attribute of a line. The example marks the mean body mass of all penguins. ``` from datachart.constants import LINE_STYLE ``` ``` mean_mass = sum(penguin["value"] for penguin in chart_data) / len(chart_data) ViolinPlot( data=chart_data, # add a horizontal line at the mean body mass of all penguins hlines={ "y": mean_mass, "style": { "plot_hline_color": "#d62728", "plot_hline_style": LINE_STYLE.DASHED, "plot_hline_width": 1.5, "plot_hline_alpha": 0.8, }, }, title="Body mass of Palmer penguins", xlabel="Species", ylabel="Body mass (g)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, ).show() ``` ### Violins with boxes and swarms A violin and a box plot over the same labels draw at the same positions, so the two compose with [datachart.utils.Panel](https://eriknovak.github.io/datachart/0.9.0/references/utils#datachart.utils.Panel): the violin with `inner=None` supplies the shape, and the [datachart.charts.BoxPlot](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.BoxPlot) drawn over it supplies the full box with its whiskers, caps and outliers. Both charts must group the same labels in the same order; one violin plot and one box plot per panel. ``` from datachart.charts import BoxPlot, SwarmPlot from datachart.utils import Panel ``` ``` Panel( [ # the body only; the box plot supplies the summaries ViolinPlot(data=chart_data, inner=None), BoxPlot( data=chart_data, style={"plot_box_color": "#FFFFFF", "plot_box_alpha": 0.9}, ), ], title="Body mass of Palmer penguins", xlabel="Species", ylabel_left="Body mass (g)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, ).show() ``` A [datachart.charts.SwarmPlot](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.SwarmPlot) puts every observation inside the body instead: the points draw above the violin, so lower the body's alpha to keep them legible. The two also compose with the box in one panel — the violin outlines the distribution, the box summarizes it, and the swarm shows the data. ``` Panel( [ # the body only, faded behind the points ViolinPlot(data=chart_data, inner=None, style={"plot_violin_alpha": 0.3}), SwarmPlot(data=chart_data), ], title="Body mass of Palmer penguins", xlabel="Species", ylabel_left="Body mass (g)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, ).show() ``` ``` Panel( [ ViolinPlot(data=chart_data, inner=None, style={"plot_violin_alpha": 0.3}), BoxPlot( data=chart_data, show_outliers=False, style={"plot_box_color": "#FFFFFF", "plot_box_alpha": 0.9}, ), SwarmPlot(data=chart_data, style={"plot_swarm_size": 12}), ], title="Body mass of Palmer penguins", xlabel="Species", ylabel_left="Body mass (g)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, ).show() ``` ## Multiple Violin Plots To create multiple violin plots, pass a list of lists to the `data` argument. Each inner list holds the data points of one chart, which is drawn in its own subplot with the `subtitle` at the top and the `title`, `xlabel` and `ylabel` positioned to be global for all charts. Per-chart attributes like `subtitle` and `style` can be passed as lists, where each element corresponds to a chart; a single value applies to every chart. Subplots required for multiple datasets When using multiple datasets (list of lists), you **must** set `subplots=True`. Violin plots do not support overlaying multiple datasets on a single axis; to compare two groups within each category, use `split` instead. The example draws the body mass and the flipper length of the three species side by side. The two charts hold different quantities, so each gets its own subtitle with its unit and there is no global `ylabel`. ``` ViolinPlot( # use a list of lists to define multiple violin plots data=[chart_data, flipper_data], # add a subtitle to each chart subtitle=["Body mass (g)", "Flipper length (mm)"], title="Palmer penguins", xlabel="Species", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, # draw each chart in its own subplot subplots=True, ).show() ``` ### Shared axes across subplots To share the x-axis and/or y-axis across subplots, add the `sharex` and/or `sharey` attributes, which are boolean values that specify whether to share the axis across all subplots; a shared axis is labeled once, on the outer subplots only. The `max_cols` attribute limits the number of subplots per row — with `max_cols=1` the charts stack vertically. The `orientation` attribute changes the orientation of every subplot at once: horizontal violins move the species to the y-axis, so side by side it is `sharey` that labels them once, next to the left chart. ``` figure = ViolinPlot( data=[chart_data, flipper_data], subtitle=["Body mass (g)", "Flipper length (mm)"], # change the orientation of the violins in every subplot orientation=ORIENTATION.HORIZONTAL, title="Palmer penguins", ylabel="Species", figsize=FIG_SIZE.FULL_SHORT, # the values are now read off the x-axis show_grid=SHOW_GRID.X, subplots=True, # the species are now on the y-axis sharey=True, ) figure.show() ``` ## Saving the Chart as an Image To save the chart as an image, use the [datachart.utils.save_figure](https://eriknovak.github.io/datachart/0.9.0/references/utils#datachart.utils.save_figure) function. ``` from datachart.utils import save_figure ``` ``` save_figure(figure, "./fig_violin_plot.png", dpi=300) ``` The figure should be saved in the current working directory. ## Real-World Examples The following examples put the features above to work on real or realistic data. Each one states what its data is and where it comes from; the data itself lives in a hidden cell. ### Example 1: Service Response Times (Bimodal Data and a Box Comparison) `response_times` holds the illustrative response time (in ms) of 300 requests to each of three services, drawn from a seeded generator. Two of the services answer some requests from a cache and the rest from the database, so their response times have two modes — fast cache hits and slow misses — with nothing in between. A box plot reduces each service to one median and one spread, which puts the median of the cached services in a gap where no request actually lands; the violin shows the two humps, and its `"quartiles"` lines make the same point without hiding them. The `Panel` on the right draws the two charts over each other for the comparison. ``` from datachart.utils import Grid violins = ViolinPlot( data=response_times, # quartile lines keep the two humps visible inner=VIOLIN_INNER.QUARTILES, title="Violin plot", xlabel="Service", ylabel="Response time (ms)", show_grid=SHOW_GRID.Y, ) boxes = Panel( [ ViolinPlot(data=response_times, inner=None, style={"plot_violin_alpha": 0.3}), BoxPlot(data=response_times, show_outliers=False), ], title="Box plot over the body", xlabel="Service", show_grid=SHOW_GRID.Y, ) Grid( [[violins, boxes]], title=f"Response time of {N_REQUESTS} requests per service", figsize=FIG_SIZE.FULL_SHORT, sharey=True, ).show() ``` ### Example 2: Model Benchmark Across Seeds (Split by Evaluation Split) `benchmark` holds the illustrative accuracy of four models, each trained with 20 random seeds and evaluated on both the validation and the test split, drawn from a seeded generator. One violin per model split by the evaluation split shows two things at once: how much of the difference between models is seed noise, and whether a model that looks best on validation holds up on test. The `emphasis` mutes the models that are out of the running so the comparison of the two contenders stands out. ``` CONTENDERS = {"Deep", "Deep + aug."} ViolinPlot( data=benchmark, # the left half is the validation split, the right half the test split split="split", inner=VIOLIN_INNER.QUARTILES, show_legend=True, # mute the models that are out of the running emphasis=[None if model in CONTENDERS else EMPHASIS.BACKGROUND for model in MODELS], title=f"Accuracy across {N_SEEDS} seeds", xlabel="Model", ylabel="Accuracy", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, ).show() ``` # Swarm Plot This section showcases the swarm plot. It contains examples of how to create swarm plots using the [datachart.charts.SwarmPlot](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.SwarmPlot) function. Looking for a specific customization? Jump straight to the [quick reference](#customizing-the-swarm-chart), which maps common tasks to the parameter or style attribute that does the job. As mentioned above, the swarm plots are created using the `SwarmPlot` function found in the [datachart.charts](https://eriknovak.github.io/datachart/0.9.0/references/charts/index.md) module. Let's import it: ``` from datachart.charts import SwarmPlot ``` ## Swarm Plot Input Attributes The `SwarmPlot` function accepts keyword arguments for chart configuration. The main argument is `data`, which contains the data points. For a single swarm plot, `data` is a list of dictionaries; the points that share a `label` form one group. For multiple swarm plots, `data` is a list of lists. ``` SwarmPlot( data=[{ # A list of data points (or list of lists for multiple charts) "label": str, # The category label "value": Union[int, float], # The numeric value }], style={ # The style of the points (optional) "plot_swarm_color": Union[str, None], # The point color "plot_swarm_alpha": Union[float, None], # The alpha of the points "plot_swarm_size": Union[int, float, None], # The point size "plot_swarm_marker": Union[str, None], # The point marker shape "plot_swarm_edge_width": Union[int, float, None], # The edge width of the points "plot_swarm_edge_color": Union[str, None], # The edge color of the points "plot_swarm_zorder": Union[int, float, None], # The zorder of the points }, title: Union[str, None], # The chart title (optional) xlabel: Union[str, None], # The x-axis label (optional) ylabel: Union[str, None], # The y-axis label (optional) subtitle: Union[str, List[str], None], # The subtitle(s), used as legend labels (optional) emphasis: Union[str, List[str], None], # The emphasis role(s), aligned with the group labels (optional) mode: Union[str, None], # "swarm" (the default) or "strip" (optional) jitter: Union[float, None], # The strip jitter width, a fraction of the category width (optional) orientation: Union[str, None], # "vertical" (the default) or "horizontal" (optional) scaley: Union[str, None], # The value axis scale (optional) figsize: Union[Tuple[float, float], None], # The figure size (optional) show_legend: Union[bool, None], # Whether to show the legend (optional) show_grid: Union[str, None], # Which grid lines to show (optional) subplots: Union[bool, None], # Whether to draw each chart in its own subplot (optional) max_cols: Union[int, None], # The maximum number of subplot columns (optional) sharex: Union[bool, None], # Whether the subplots share the x-axis (optional) sharey: Union[bool, None], # Whether the subplots share the y-axis (optional) hlines: Union[dict, List[dict], None], # The horizontal reference lines (optional) vlines: Union[dict, List[dict], None], # The vertical reference lines (optional) label: Union[str, None], # The key name in `data` holding the label (optional) value: Union[str, None], # The key name in `data` holding the value (optional) ) ``` For more details, see the [datachart.charts.SwarmPlot](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.SwarmPlot) function. ## Basics The examples in this guide share one dataset: the body mass of the 342 penguins of the [Palmer penguins](https://allisonhorst.github.io/palmerpenguins/) dataset (CC0), three species measured on the islands of the Palmer Archipelago in Antarctica. The data is hard-coded in a hidden cell, which keeps the sex and the flipper length of every penguin alongside its species — the later sections and examples reuse them. `chart_data` holds the body mass (in g) of every penguin, labeled with its species. The data is a flat list of dictionaries, one per data point, each with a `label` and a `value`. The points that share a `label` are grouped into one swarm, so three species give three swarms: ``` chart_data[:3] ``` **Basic example.** Only the `data` argument is required to draw the swarm plot. Every penguin is one point at its species' position, and the points spread sideways just far enough not to cover each other, so the width of a swarm at any height shows how many penguins weigh that much. ``` SwarmPlot( # add the data to the chart data=chart_data ).show() ``` ## Customizing the Swarm Plot Every customization is either a keyword argument of `SwarmPlot` or a `plot_swarm_*` attribute of its `style` dictionary. The table maps common tasks to the one you need and links to the subsection that shows it. | I want to… | Use | See | | --------------------------------------------- | ---------------------------------------------------------------------------------- | --------------------------------------------------------------- | | add a title and axis labels | `title`, `xlabel`, `ylabel` | [Title and axis labels](#title-and-axis-labels) | | resize the figure | `figsize` | [Figure size and grid](#figure-size-and-grid) | | show the grid lines | `show_grid` | [Figure size and grid](#figure-size-and-grid) | | change the point color, size or transparency | `style={"plot_swarm_color": ..., "plot_swarm_size": ..., "plot_swarm_alpha": ...}` | [Point style](#point-style) | | change the point marker or edge | `style={"plot_swarm_marker": ..., "plot_swarm_edge_color": ..., ...}` | [Point style](#point-style) | | jitter the points instead of packing them | `mode`, `jitter` | [Swarm and strip modes](#swarm-and-strip-modes) | | draw the swarms horizontally | `orientation` | [Swarm orientation](#swarm-orientation) | | highlight one group, mute the rest | `emphasis` | [Emphasis](#emphasis) | | draw a threshold or reference line | `hlines`, `vlines` | [Reference lines](#reference-lines) | | put the points on top of a box or violin plot | `Panel` | [Swarms over boxes and violins](#swarms-over-boxes-and-violins) | | draw several datasets on one chart | `data` as a list of lists, `subtitle` | [Multiple Swarm Plots](#multiple-swarm-plots) | | draw each dataset in its own subplot | `subplots`, `max_cols`, `sharex`, `sharey` | [Subplots](#subplots) | | use a logarithmic value axis | `scaley` | [Logarithmic scale](#logarithmic-scale) | | save the chart to a file | `save_figure` | [Saving the Chart as an Image](#saving-the-chart-as-an-image) | The full list of style attributes is in the [datachart.typings.SwarmStyleAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.SwarmStyleAttrs) type; the full list of parameters is in the [datachart.charts.SwarmPlot](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.SwarmPlot) reference. ### Title and axis labels To add the chart title and axis labels, add the `title`, `xlabel` and `ylabel` attributes. ``` SwarmPlot( data=chart_data, # add the title title="Body mass of Palmer penguins", # add the x and y axis labels xlabel="Species", ylabel="Body mass (g)", ).show() ``` ### Figure size and grid To change the figure size, add the `figsize` attribute. The `figsize` attribute can be a tuple (width, height), values are in inches. The `datachart` package provides a [datachart.constants.FIG_SIZE](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.FIG_SIZE) constant, which contains predefined figure sizes. To show the grid lines, add the `show_grid` attribute, which supports the values of the [datachart.constants.SHOW_GRID](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.SHOW_GRID) constant. ``` from datachart.constants import FIG_SIZE, SHOW_GRID ``` ``` SwarmPlot( data=chart_data, title="Body mass of Palmer penguins", xlabel="Species", ylabel="Body mass (g)", # add to determine the figure size figsize=FIG_SIZE.FULL_SHORT, # add to show the grid lines show_grid=SHOW_GRID.Y, ).show() ``` ### Point style To change the point style, add the `style` attribute with the corresponding attributes. The supported attributes are shown in the [datachart.typings.SwarmStyleAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.SwarmStyleAttrs) type, which contains the following attributes: | Attribute | Description | | ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `plot_swarm_color` | The point color. | | `plot_swarm_alpha` | The alpha of the points. | | `plot_swarm_size` | The point size, in points squared. The swarm packs the points from this size, so larger points spread wider. | | `plot_swarm_marker` | The point marker shape; see [datachart.constants.LINE_MARKER](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.LINE_MARKER). | | `plot_swarm_edge_width` | The edge width of the points. | | `plot_swarm_edge_color` | The edge color of the points. | | `plot_swarm_zorder` | The zorder of the points. | ``` from datachart.constants import LINE_MARKER ``` ``` SwarmPlot( data=chart_data, # define the style of the points style={ "plot_swarm_color": "#08519c", "plot_swarm_size": 12, "plot_swarm_alpha": 0.6, "plot_swarm_marker": LINE_MARKER.SQUARE, "plot_swarm_edge_color": "#08519c", "plot_swarm_edge_width": 0, }, title="Body mass of Palmer penguins", xlabel="Species", ylabel="Body mass (g)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, ).show() ``` ### Swarm and strip modes The `mode` attribute chooses how the points of a group spread across the category width. It supports the values of the [datachart.constants.SWARM_MODE](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.SWARM_MODE) constant: | Value | Description | | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `"swarm"` | The points are packed so none overlap, from the point size at the moment the chart is drawn (the default). Axis limits changed on the figure afterwards can shift the spacing. | | `"strip"` | The points are jittered uniformly across the category width; `jitter` sets the width of the band as a fraction of the category width (0.4 by default). The jitter is seeded, so the same data draws the same chart. | The strip mode is the faster choice for many thousands of points, where a swarm would fill its whole width anyway. ``` from datachart.constants import SWARM_MODE ``` ``` SwarmPlot( data=chart_data, # jitter the points instead of packing them mode=SWARM_MODE.STRIP, # narrow the jitter band to a quarter of the category width jitter=0.25, title="Body mass of Palmer penguins", xlabel="Species", ylabel="Body mass (g)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, ).show() ``` ### Swarm orientation To change the orientation of the swarms, add the `orientation` attribute, which supports the following values: | Value | Description | | -------------- | ------------------------------------------------------------------------- | | `"vertical"` | The swarms are vertical, one per category along the x-axis (the default). | | `"horizontal"` | The swarms are horizontal, one per category along the y-axis. | The `datachart` package provides the [datachart.constants.ORIENTATION](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.ORIENTATION) constant with these values. ``` from datachart.constants import ORIENTATION ``` ``` SwarmPlot( data=chart_data, # change the orientation of the swarms orientation=ORIENTATION.HORIZONTAL, title="Body mass of Palmer penguins", # swap the axis labels to match the orientation xlabel="Body mass (g)", ylabel="Species", figsize=FIG_SIZE.FULL_SHORT, # the value axis is now the x-axis show_grid=SHOW_GRID.X, ).show() ``` ### Emphasis To draw attention to one group, add the `emphasis` attribute. The `emphasis` list aligns with the group **labels** of one call, in the order the labels first appear in the data — here Adelie, Chinstrap, Gentoo. Each entry is one of the following roles: | Role | Description | | -------------- | ---------------------------------------------------------------- | | `"background"` | Mutes the group's points into the theme's muted color and alpha. | | `"highlight"` | Bolds the edges of the group's points. | | `None` | Leaves the group unchanged. | A single value applies to every group. The [datachart.constants.EMPHASIS](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.EMPHASIS) constant holds the roles; the [highlighting guide](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/styling/highlighting.ipynb) covers emphasis across chart types and themes. ``` from datachart.constants import EMPHASIS ``` ``` SwarmPlot( data=chart_data, # one role per group label: Adelie, Chinstrap, Gentoo emphasis=[EMPHASIS.BACKGROUND, EMPHASIS.BACKGROUND, EMPHASIS.HIGHLIGHT], title="Body mass of Palmer penguins", xlabel="Species", ylabel="Body mass (g)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, ).show() ``` ### Reference lines A reference line puts a threshold or a summary value next to the swarms. To add horizontal lines, add the `hlines` attribute with the [datachart.typings.HLinePlotAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.HLinePlotAttrs) typing, which is either a `dict` or a `List[dict]`; vertical lines use `vlines` and the [datachart.typings.VLinePlotAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.VLinePlotAttrs) typing. ``` from datachart.constants import LINE_STYLE ``` ``` mean_mass = sum(penguin["value"] for penguin in chart_data) / len(chart_data) SwarmPlot( data=chart_data, # add a horizontal line at the mean body mass of all penguins hlines={ "y": mean_mass, "style": { "plot_hline_color": "#d62728", "plot_hline_style": LINE_STYLE.DASHED, "plot_hline_width": 1.5, "plot_hline_alpha": 0.8, }, }, title="Body mass of Palmer penguins", xlabel="Species", ylabel="Body mass (g)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, ).show() ``` ### Swarms over boxes and violins A swarm shows every observation; a box plot summarizes them. To get both, compose a [datachart.charts.BoxPlot](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.BoxPlot) and a `SwarmPlot` of the same data with [datachart.utils.Panel](https://eriknovak.github.io/datachart/0.9.0/references/utils/#datachart.utils.Panel): the groups share their positions, so the points sit on the box centers, and the points draw above the boxes. The box plot's outliers are already in the swarm, so hide them with `show_outliers=False`. ``` from datachart.charts import BoxPlot, ViolinPlot from datachart.utils import Panel ``` ``` Panel( [ # the boxes summarize the groups; the swarm already draws the outliers BoxPlot(data=chart_data, show_outliers=False), SwarmPlot(data=chart_data), ], title="Body mass of Palmer penguins", xlabel="Species", ylabel_left="Body mass (g)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, ).show() ``` To keep the boxes in the background, mute the box plot figure with `emphasis` and let the points carry the color. ``` Panel( [ # mute the boxes into context {"figure": BoxPlot(data=chart_data, show_outliers=False), "emphasis": EMPHASIS.BACKGROUND}, SwarmPlot(data=chart_data), ], title="Body mass of Palmer penguins", xlabel="Species", ylabel_left="Body mass (g)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, ).show() ``` A [datachart.charts.ViolinPlot](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.ViolinPlot) gives the same context as a smooth outline of the distribution. Draw the body only with `inner=None` — the swarm already shows where the values sit — and lower its alpha so the points stay legible. ``` Panel( [ # the body only, faded behind the points ViolinPlot(data=chart_data, inner=None, style={"plot_violin_alpha": 0.3}), SwarmPlot(data=chart_data), ], title="Body mass of Palmer penguins", xlabel="Species", ylabel_left="Body mass (g)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, ).show() ``` All three compose at once: the violin body outlines the distribution, the box summarizes it, and the swarm shows every observation. One box plot and one violin plot per panel; swarms may repeat. ``` Panel( [ ViolinPlot(data=chart_data, inner=None, style={"plot_violin_alpha": 0.3}), # a white box reads over the body; its outliers are in the swarm BoxPlot( data=chart_data, show_outliers=False, style={"plot_box_color": "#FFFFFF", "plot_box_alpha": 0.9}, ), SwarmPlot(data=chart_data, style={"plot_swarm_size": 12}), ], title="Body mass of Palmer penguins", xlabel="Species", ylabel_left="Body mass (g)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, ).show() ``` ## Multiple Swarm Plots To create multiple swarm plots, pass a list of lists to the `data` argument. Each inner list holds the data points of one chart; the charts share one category axis, which lists every label in the order it first appears, and the swarms of the same label overlay at the same position in distinct colors. Per-chart attributes like `subtitle` and `style` can be passed as lists, where each element corresponds to a chart; a single value applies to every chart. The `subtitle` labels the legend. `body_mass_by_sex` splits the penguins of the hidden cell into the 165 female and the 168 male penguins (the 9 penguins without a recorded sex are left out), one list of data points per sex. ``` SEXES = ["Female", "Male"] # one list of data points per sex; the penguins without a recorded sex are left out body_mass_by_sex = [ [ {"label": penguin["species"], "value": mass} for penguin in PENGUINS if penguin["sex"] == sex for mass in penguin["body_mass"] ] for sex in SEXES ] ``` ``` SwarmPlot( # use a list of lists to define multiple swarm plots data=body_mass_by_sex, # one legend entry per chart subtitle=SEXES, title="Body mass of Palmer penguins by sex", xlabel="Species", ylabel="Body mass (g)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, show_legend=True, ).show() ``` ### Subplots To draw each chart in its own subplot, add the `subplots` attribute set to `True`. The `subtitle` becomes the subplot title and the `title`, `xlabel` and `ylabel` are positioned to be global for all charts. The `max_cols` attribute limits the number of columns, and `sharex` and `sharey` share an axis across the subplots; a shared axis is labeled once, on the outer subplots only. ``` SwarmPlot( data=body_mass_by_sex, subtitle=SEXES, title="Body mass of Palmer penguins by sex", xlabel="Species", ylabel="Body mass (g)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, # draw each chart in its own subplot subplots=True, # the same mass axis for both charts sharey=True, ).show() ``` ## Additional Features ### Logarithmic scale To draw the value axis on a logarithmic scale, add the `scaley` attribute with a value of the [datachart.constants.SCALE](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.SCALE) constant. The swarm packs the points in the scaled space, so they stay apart on the log axis as well. `flipper_data` from the hidden cell holds the flipper length (in mm) of every penguin; the span is narrow, so the log axis mostly shows that the packing follows it. ``` from datachart.constants import SCALE ``` ``` SwarmPlot( data=flipper_data, # draw the value axis on a logarithmic scale scaley=SCALE.LOG, title="Flipper length of Palmer penguins", xlabel="Species", ylabel="Flipper length (mm)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, ).show() ``` ### Custom data keys If the data points hold the label and the value under other keys, add the `label` and `value` attributes with the key names, so the data need not be reshaped. ``` flipper_records = [ {"species": penguin["species"], "flipper_mm": length} for penguin in PENGUINS for length in penguin["flipper_length"] ] SwarmPlot( data=flipper_records, # the keys holding the label and the value label="species", value="flipper_mm", title="Flipper length of Palmer penguins", xlabel="Species", ylabel="Flipper length (mm)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, ).show() ``` ## Saving the Chart as an Image To save the chart as an image, use the [datachart.utils.save_figure](https://eriknovak.github.io/datachart/0.9.0/references/utils#datachart.utils.save_figure) function. ``` from datachart.utils import save_figure ``` ``` figure = SwarmPlot( data=chart_data, title="Body mass of Palmer penguins", xlabel="Species", ylabel="Body mass (g)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, ) save_figure(figure, "./fig_swarm_plot.png", dpi=300) ``` The figure should be saved in the current working directory. ## Real-World Examples The following examples put the features above to work on real or realistic data. Each one states what its data is and where it comes from; the data itself lives in a hidden cell. ### Example 1: Model Benchmark Across Seeds (Box Overlay and Emphasis) `benchmark` holds the illustrative test accuracy of five models, each trained and evaluated with 20 random seeds, drawn from a seeded generator. A box plot alone hides that 20 seeds is a small sample; the swarm on top shows every run, so a reader can tell a tight cluster from a wide one that happens to share a median. The best model is highlighted in both layers, the rest muted. ``` BEST_MODEL = "Deep + aug." roles = [EMPHASIS.HIGHLIGHT if model == BEST_MODEL else EMPHASIS.BACKGROUND for model in MODELS] Panel( [ BoxPlot(data=benchmark, show_outliers=False, emphasis=roles), # the same roles align with the same labels in both layers SwarmPlot(data=benchmark, emphasis=roles), ], title=f"Test accuracy across {N_SEEDS} seeds", xlabel="Model", ylabel_left="Test accuracy", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, ).show() ``` ### Example 2: Service Response Times (Strip Mode, Log Scale and an SLA Line) `response_times` holds the illustrative response time (in ms) of 300 requests to each of four services, drawn from a seeded log-normal generator: most requests are fast and a long tail of slow ones stretches each distribution. On a log axis the tail reads at the same resolution as the bulk, and with 1,200 points the strip mode spreads them evenly instead of packing a swarm that would fill its width anyway. The horizontal line marks the service level agreement, so the requests that breach it are the points above it. ``` SwarmPlot( data=response_times, # jitter the many points evenly across the category width mode=SWARM_MODE.STRIP, # the long tail reads at the same resolution as the bulk scaley=SCALE.LOG, # mark the service level agreement hlines={ "y": SLA_MS, "style": { "plot_hline_color": "#d62728", "plot_hline_style": LINE_STYLE.DASHED, "plot_hline_width": 1.5, }, }, style={"plot_swarm_size": 8, "plot_swarm_alpha": 0.5, "plot_swarm_edge_width": 0}, title=f"Response time of {N_REQUESTS} requests per service", xlabel="Service", ylabel="Response time (ms)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, ).show() ``` ### Example 3: Daily Temperatures by Month (Horizontal Swarms and Many Categories) `daily_temperatures` holds one year of daily mean temperatures (in °C) in Ljubljana, drawn from a seeded generator around the published 1991–2020 monthly climate normals of the city's weather station, with the larger day-to-day swings of the winter months. Twelve labeled swarms read best top to bottom, and a vertical line marks the freezing point, so the days below zero are the points to its left. ``` SwarmPlot( data=daily_temperatures, # twelve labeled swarms read best top to bottom orientation=ORIENTATION.HORIZONTAL, # mark the freezing point vlines={ "x": 0, "style": { "plot_vline_color": "#4c72b0", "plot_vline_style": LINE_STYLE.DASHED, "plot_vline_width": 1.5, }, }, style={"plot_swarm_size": 10}, title="Daily mean temperature in Ljubljana", xlabel="Temperature (°C)", ylabel="Month", figsize=FIG_SIZE.FULL_MEDIUM, show_grid=SHOW_GRID.X, ).show() ``` # Raincloud Plot This section showcases the raincloud plot. It contains examples of how to create raincloud plots using the [datachart.charts.RaincloudPlot](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.RaincloudPlot) function. Looking for a specific customization? Jump straight to the [quick reference](#customizing-the-raincloud-plot), which maps common tasks to the parameter or style attribute that does the job. As mentioned above, the raincloud plots are created using the `RaincloudPlot` function found in the [datachart.charts](https://eriknovak.github.io/datachart/0.9.0/references/charts/index.md) module. Let's import it: ``` from datachart.charts import RaincloudPlot ``` ## Raincloud Plot Input Attributes The `RaincloudPlot` function accepts keyword arguments for chart configuration. The main argument is `data`, which contains the data points. For a single raincloud plot, `data` is a list of dictionaries; the points that share a `label` form one group. For multiple raincloud plots, `data` is a list of lists, and each chart draws in its own subplot. ``` RaincloudPlot( data=[{ # A list of data points (or list of lists for multiple charts) "label": str, # The category label "value": Union[int, float], # The numeric value }], style={ # The style of the cloud, the rain, and the box (optional) "plot_violin_color": Union[str, None], # The cloud fill color "plot_violin_alpha": Union[float, None], # The alpha of the cloud "plot_violin_width": Union[int, float, None], # The maximum width of the cloud "plot_swarm_color": Union[str, None], # The rain point color "plot_swarm_size": Union[int, float, None], # The rain point size "plot_swarm_alpha": Union[float, None], # The alpha of the rain points "plot_box_linewidth": Union[int, float, None], # The line width of the box "plot_box_edgecolor": Union[str, None], # The edge color of the box "plot_box_outlier_size": Union[int, float, None], # The outlier marker size }, title: Union[str, None], # The chart title (optional) xlabel: Union[str, None], # The x-axis label (optional) ylabel: Union[str, None], # The y-axis label (optional) subtitle: Union[str, List[str], None], # The subtitle(s), used as subplot titles (optional) emphasis: Union[str, List[str], None], # The emphasis role(s), aligned with the group labels (optional) mode: Union[str, None], # "swarm" (the default) or "strip" for the rain (optional) jitter: Union[float, None], # The strip jitter width, a fraction of the category width (optional) bandwidth: Union[str, float, None], # The cloud's KDE bandwidth rule or factor (optional) show_outliers: Union[bool, None], # Whether the box shows outliers (optional) orientation: Union[str, None], # "vertical" (the default) or "horizontal" (optional) scaley: Union[str, None], # The value axis scale (optional) figsize: Union[Tuple[float, float], None], # The figure size (optional) show_legend: Union[bool, None], # Whether to show the legend, one entry per group (optional) show_grid: Union[str, None], # Which grid lines to show (optional) subplots: Union[bool, None], # Whether to draw each chart in its own subplot (optional) max_cols: Union[int, None], # The maximum number of subplot columns (optional) sharex: Union[bool, None], # Whether the subplots share the x-axis (optional) sharey: Union[bool, None], # Whether the subplots share the y-axis (optional) hlines: Union[dict, List[dict], None], # The horizontal reference lines (optional) vlines: Union[dict, List[dict], None], # The vertical reference lines (optional) label: Union[str, None], # The key name in `data` holding the label (optional) value: Union[str, None], # The key name in `data` holding the value (optional) ) ``` For more details, see the [datachart.charts.RaincloudPlot](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.RaincloudPlot) function. ## Basics The examples in this guide share one dataset: the body mass of the 342 penguins of the [Palmer penguins](https://allisonhorst.github.io/palmerpenguins/) dataset (CC0), three species measured on the islands of the Palmer Archipelago in Antarctica. The data is hard-coded in a hidden cell, which keeps the sex and the flipper length of every penguin alongside its species — the later sections reuse them. `chart_data` holds the body mass (in g) of every penguin, labeled with its species. The data is a flat list of dictionaries, one per data point, each with a `label` and a `value`. The points that share a `label` are grouped into one raincloud, so three species give three rainclouds: ``` chart_data[:3] ``` **Basic example.** Only the `data` argument is required to draw the raincloud plot. Every group draws three parts at its position: the **cloud** on the right, a half violin showing the density of the values; the **box** just left of it, the quartile summary with its outliers; and the **rain** further left, every penguin as one point, packed outward from the box. Each species takes its own color, shared by all three parts, so they read as one group. ``` RaincloudPlot( # add the data to the chart data=chart_data ).show() ``` ## Customizing the Raincloud Plot Every customization is either a keyword argument of `RaincloudPlot` or an attribute of its `style` dictionary: the `plot_violin_*` attributes style the cloud, the `plot_swarm_*` attributes the rain, and the `plot_box_*` attributes the box. The table maps common tasks to the one you need and links to the subsection that shows it. | I want to… | Use | See | | --------------------------------------- | ------------------------------------------------------------------------------------- | ------------------------------------------------------------- | | add a title and axis labels | `title`, `xlabel`, `ylabel` | [Title and axis labels](#title-and-axis-labels) | | resize the figure | `figsize` | [Figure size and grid](#figure-size-and-grid) | | show the grid lines | `show_grid` | [Figure size and grid](#figure-size-and-grid) | | list the groups in a legend | `show_legend` | [Figure size and grid](#figure-size-and-grid) | | change the cloud, rain, or box style | `style={"plot_violin_alpha": ..., "plot_swarm_size": ..., "plot_box_linewidth": ...}` | [Cloud, rain, and box style](#cloud-rain-and-box-style) | | smooth or sharpen the cloud | `bandwidth` | [Cloud bandwidth](#cloud-bandwidth) | | jitter the rain instead of packing it | `mode`, `jitter` | [Rain modes](#rain-modes) | | hide the box outliers | `show_outliers` | [Box outliers](#box-outliers) | | draw the rainclouds horizontally | `orientation` | [Raincloud orientation](#raincloud-orientation) | | highlight one group, mute the rest | `emphasis` | [Emphasis](#emphasis) | | draw a threshold or reference line | `hlines`, `vlines` | [Reference lines](#reference-lines) | | draw each dataset in its own subplot | `data` as a list of lists, `subplots`, `sharex`, `sharey` | [Multiple Raincloud Plots](#multiple-raincloud-plots) | | compose the raincloud with other charts | `Panel`, `Grid` | [Composing rainclouds](#composing-rainclouds) | | use a logarithmic value axis | `scaley` | [Logarithmic scale](#logarithmic-scale) | | save the chart to a file | `save_figure` | [Saving the Chart as an Image](#saving-the-chart-as-an-image) | The full list of style attributes is in the [datachart.typings.RaincloudStyleAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.RaincloudStyleAttrs) type; the full list of parameters is in the [datachart.charts.RaincloudPlot](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.RaincloudPlot) reference. ### Title and axis labels To add the chart title and axis labels, add the `title`, `xlabel` and `ylabel` attributes. ``` RaincloudPlot( data=chart_data, # add the title title="Body mass of Palmer penguins", # add the x and y axis labels xlabel="Species", ylabel="Body mass (g)", ).show() ``` ### Figure size and grid To change the figure size, add the `figsize` attribute. The `figsize` attribute can be a tuple (width, height), values are in inches. The `datachart` package provides a [datachart.constants.FIG_SIZE](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.FIG_SIZE) constant, which contains predefined figure sizes. To show the grid lines, add the `show_grid` attribute, which supports the values of the [datachart.constants.SHOW_GRID](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.SHOW_GRID) constant. To list the groups and their colors, add the `show_legend` attribute. ``` from datachart.constants import FIG_SIZE, SHOW_GRID ``` ``` RaincloudPlot( data=chart_data, title="Body mass of Palmer penguins", xlabel="Species", ylabel="Body mass (g)", # add to determine the figure size figsize=FIG_SIZE.FULL_SHORT, # add to show the grid lines show_grid=SHOW_GRID.Y, # one legend entry per group show_legend=True, ).show() ``` ### Cloud, rain, and box style To change the style of the parts, add the `style` attribute with the corresponding attributes. The supported attributes are shown in the [datachart.typings.RaincloudStyleAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.RaincloudStyleAttrs) type: the cloud takes the [datachart.typings.ViolinStyleAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.ViolinStyleAttrs) body attributes, the rain the [datachart.typings.SwarmStyleAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.SwarmStyleAttrs) attributes, and the box the [datachart.typings.BoxStyleAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.BoxStyleAttrs) attributes. The most common ones are: | Attribute | Description | | ----------------------- | -------------------------------------------------------------------------------------------- | | `plot_violin_color` | The cloud fill color; one color for every group instead of the palette. | | `plot_violin_alpha` | The alpha of the cloud. | | `plot_violin_width` | The maximum width of the cloud, as a fraction of the category width. | | `plot_swarm_color` | The rain point color; one color for every group instead of the palette. | | `plot_swarm_size` | The rain point size, in points squared (6 by default, smaller than a standalone swarm's). | | `plot_swarm_alpha` | The alpha of the rain points. | | `plot_box_linewidth` | The line width of the box. | | `plot_box_edgecolor` | The edge color of the box; the median, whiskers, and caps have their own `plot_box_*_color`. | | `plot_box_outlier_size` | The outlier marker size. | The box takes the group color as its fill and the theme's font color for its edges, median, whiskers, and caps. ``` RaincloudPlot( data=chart_data, # define the style of the cloud, the rain, and the box style={ "plot_violin_alpha": 0.4, "plot_violin_width": 0.9, "plot_swarm_size": 10, "plot_swarm_alpha": 0.5, "plot_box_linewidth": 1.5, }, title="Body mass of Palmer penguins", xlabel="Species", ylabel="Body mass (g)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, ).show() ``` ### Cloud bandwidth The cloud is a kernel density estimate of the values. The `bandwidth` attribute sets how much the estimate smooths: a rule of the [datachart.constants.BANDWIDTH](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.BANDWIDTH) constant (`"scott"`, the default, or `"silverman"`) or a scalar factor, where smaller values follow the data more closely and larger ones smooth it more. ``` RaincloudPlot( data=chart_data, # a narrow bandwidth follows the data closely bandwidth=0.2, title="Body mass of Palmer penguins", xlabel="Species", ylabel="Body mass (g)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, ).show() ``` ### Rain modes The `mode` attribute chooses how the rain spreads across its width. It supports the values of the [datachart.constants.SWARM_MODE](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.SWARM_MODE) constant: | Value | Description | | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `"swarm"` | The points are packed outward from the box so none overlap, from the point size at the moment the chart is drawn (the default). | | `"strip"` | The points are jittered uniformly across the rain width; `jitter` sets the width of the band as a fraction of the category width, like `SwarmPlot`, scaled down to the rain's narrower cell (0.4 by default, which fills the rain width). The jitter is seeded, so the same data draws the same chart. | The strip mode is the faster choice for many thousands of points, where a swarm would fill its whole width anyway. ``` from datachart.constants import SWARM_MODE ``` ``` RaincloudPlot( data=chart_data, # jitter the rain instead of packing it mode=SWARM_MODE.STRIP, # narrow the jitter band to half of the rain width jitter=0.2, title="Body mass of Palmer penguins", xlabel="Species", ylabel="Body mass (g)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, ).show() ``` ### Box outliers The box shows the values beyond 1.5 times the interquartile range as outlier markers. They are already in the rain, so hide them with `show_outliers=False` when the box should stay a plain summary. ``` RaincloudPlot( data=chart_data, # the rain already shows every value show_outliers=False, title="Body mass of Palmer penguins", xlabel="Species", ylabel="Body mass (g)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, ).show() ``` ### Raincloud orientation To change the orientation of the rainclouds, add the `orientation` attribute, which supports the following values: | Value | Description | | -------------- | --------------------------------------------------------------------------------------------------------------------------------------- | | `"vertical"` | The rainclouds are vertical, one per category along the x-axis, the cloud on the right, the box and the rain on its left (the default). | | `"horizontal"` | The rainclouds are horizontal, one per category along the y-axis, the cloud above, the box and the rain below it. | The `datachart` package provides the [datachart.constants.ORIENTATION](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.ORIENTATION) constant with these values. ``` from datachart.constants import ORIENTATION ``` ``` RaincloudPlot( data=chart_data, # change the orientation of the rainclouds orientation=ORIENTATION.HORIZONTAL, title="Body mass of Palmer penguins", # swap the axis labels to match the orientation xlabel="Body mass (g)", ylabel="Species", # a taller figure gives the horizontal rainclouds room figsize=FIG_SIZE.FULL_MEDIUM, # the value axis is now the x-axis show_grid=SHOW_GRID.X, ).show() ``` ### Emphasis To draw attention to one group, add the `emphasis` attribute. The `emphasis` list aligns with the group **labels** of one call, in the order the labels first appear in the data — here Adelie, Chinstrap, Gentoo — and applies to the cloud, the rain, and the box of the group together. Each entry is one of the following roles: | Role | Description | | -------------- | ------------------------------------------------------- | | `"background"` | Mutes the group into the theme's muted color and alpha. | | `"highlight"` | Bolds the edges of the cloud, the rain, and the box. | | `None` | Leaves the group unchanged. | A single value applies to every group. The [datachart.constants.EMPHASIS](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.EMPHASIS) constant holds the roles; the [highlighting guide](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/styling/highlighting.ipynb) covers emphasis across chart types and themes. ``` from datachart.constants import EMPHASIS ``` ``` RaincloudPlot( data=chart_data, # one role per group label: Adelie, Chinstrap, Gentoo emphasis=[EMPHASIS.BACKGROUND, EMPHASIS.BACKGROUND, EMPHASIS.HIGHLIGHT], title="Body mass of Palmer penguins", xlabel="Species", ylabel="Body mass (g)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, ).show() ``` ### Reference lines A reference line puts a threshold or a summary value next to the rainclouds. To add horizontal lines, add the `hlines` attribute with the [datachart.typings.HLinePlotAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.HLinePlotAttrs) typing, which is either a `dict` or a `List[dict]`; vertical lines use `vlines` and the [datachart.typings.VLinePlotAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.VLinePlotAttrs) typing. ``` from datachart.constants import LINE_STYLE ``` ``` mean_mass = sum(penguin["value"] for penguin in chart_data) / len(chart_data) RaincloudPlot( data=chart_data, # add a horizontal line at the mean body mass of all penguins hlines={ "y": mean_mass, "style": { "plot_hline_color": "#d62728", "plot_hline_style": LINE_STYLE.DASHED, "plot_hline_width": 1.5, "plot_hline_alpha": 0.8, }, }, title="Body mass of Palmer penguins", xlabel="Species", ylabel="Body mass (g)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, ).show() ``` ## Multiple Raincloud Plots To create multiple raincloud plots, pass a list of lists to the `data` argument. Each inner list holds the data points of one chart, and every chart draws in its own subplot — three parts per group leave no room to overlay a second dataset at the same positions. The `subtitle` becomes the subplot title and the `title`, `xlabel` and `ylabel` are positioned to be global for all charts. The `max_cols` attribute limits the number of columns, and `sharex` and `sharey` share an axis across the subplots; a shared axis is labeled once, on the outer subplots only. `body_mass_by_sex` splits the penguins of the hidden cell into the 165 female and the 168 male penguins (the 9 penguins without a recorded sex are left out), one list of data points per sex. ``` SEXES = ["Female", "Male"] # one list of data points per sex; the penguins without a recorded sex are left out body_mass_by_sex = [ [ {"label": penguin["species"], "value": mass} for penguin in PENGUINS if penguin["sex"] == sex for mass in penguin["body_mass"] ] for sex in SEXES ] ``` ``` RaincloudPlot( # use a list of lists to define multiple raincloud plots data=body_mass_by_sex, # one subplot title per chart subtitle=SEXES, title="Body mass of Palmer penguins by sex", xlabel="Species", ylabel="Body mass (g)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, # the same mass axis for both charts sharey=True, ).show() ``` ## Composing rainclouds A raincloud figure composes like any other chart. [datachart.utils.Panel](https://eriknovak.github.io/datachart/0.9.0/references/utils/#datachart.utils.Panel) overlays it with other charts on shared axes: the groups keep their positions, so a reference chart of the same categories lines up with them. Here a [datachart.charts.LineChart](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.LineChart) traces the mean body mass across the species, one point per category position. ``` from datachart.charts import LineChart from datachart.utils import Panel SPECIES = ["Adelie", "Chinstrap", "Gentoo"] mean_by_species = [ { "x": i + 1, "y": sum(p["value"] for p in chart_data if p["label"] == species) / sum(1 for p in chart_data if p["label"] == species), } for i, species in enumerate(SPECIES) ] Panel( [ RaincloudPlot(data=chart_data), # the means, one per category position LineChart(data=mean_by_species, style={"plot_line_marker": "o"}), ], title="Body mass of Palmer penguins", xlabel="Species", ylabel_left="Body mass (g)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, ).show() ``` [datachart.utils.Grid](https://eriknovak.github.io/datachart/0.9.0/references/utils/#datachart.utils.Grid) arranges rainclouds next to other figures. A raincloud of the flipper lengths (`flipper_data` from the hidden cell) sits beside the body mass one. ``` from datachart.utils import Grid Grid( [ RaincloudPlot(data=chart_data, title="Body mass (g)"), RaincloudPlot(data=flipper_data, title="Flipper length (mm)"), ], title="Palmer penguins by species", figsize=FIG_SIZE.FULL_SHORT, ).show() ``` ## Additional Features ### Logarithmic scale To draw the value axis on a logarithmic scale, add the `scaley` attribute with a value of the [datachart.constants.SCALE](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.SCALE) constant. The cloud, the rain, and the box all follow the scaled axis. ``` from datachart.constants import SCALE ``` ``` RaincloudPlot( data=chart_data, # draw the value axis on a logarithmic scale scaley=SCALE.LOG, title="Body mass of Palmer penguins", xlabel="Species", ylabel="Body mass (g)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, ).show() ``` ### Custom data keys If the data points hold the label and the value under other keys, add the `label` and `value` attributes with the key names, so the data need not be reshaped. ``` flipper_records = [ {"species": penguin["species"], "flipper_mm": length} for penguin in PENGUINS for length in penguin["flipper_length"] ] RaincloudPlot( data=flipper_records, # the keys holding the label and the value label="species", value="flipper_mm", title="Flipper length of Palmer penguins", xlabel="Species", ylabel="Flipper length (mm)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, ).show() ``` ## Saving the Chart as an Image To save the chart as an image, use the [datachart.utils.save_figure](https://eriknovak.github.io/datachart/0.9.0/references/utils#datachart.utils.save_figure) function. ``` from datachart.utils import save_figure figure = RaincloudPlot( data=chart_data, title="Body mass of Palmer penguins", xlabel="Species", ylabel="Body mass (g)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, ) save_figure(figure, "./fig_raincloud_plot.png", dpi=300) ``` The figure should be saved in the current working directory. # Scatter Chart This section showcases the scatter chart. It contains examples of how to create scatter charts using the [datachart.charts.ScatterChart](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.ScatterChart) function. Looking for a specific customization? Jump straight to the [quick reference](#customizing-the-scatter-chart), which maps common tasks to the parameter or style attribute that does the job. As mentioned above, the scatter charts are created using the `ScatterChart` function found in the [datachart.charts](https://eriknovak.github.io/datachart/0.9.0/references/charts/index.md) module. Let's import it: ``` from datachart.charts import ScatterChart ``` ## Scatter Chart Input Attributes The `ScatterChart` function accepts keyword arguments for chart configuration. The main argument is `data`, which contains the data points. For a single scatter chart, `data` is a list of dictionaries. For multiple scatter charts, `data` is a list of lists. ``` ScatterChart( data=[{ # A list of scatter data points (or list of lists for multiple charts) "x": Union[int, float], # The x-axis value "y": Union[int, float], # The y-axis value "size": Optional[Union[int, float]], # The marker size value (for bubble charts) "hue": Optional[str], # The category for color grouping }], style={ # The style of the scatter markers (optional) "plot_scatter_color": Optional[str], # The color of the markers (hex color code) "plot_scatter_alpha": Optional[float], # The alpha of the markers (how visible they are) "plot_scatter_size": Optional[float], # The size of the markers "plot_scatter_marker": Optional[LINE_MARKER], # The marker shape (circle, square, etc.) "plot_scatter_zorder": Optional[int], # The zorder of the markers "plot_scatter_edge_width": Optional[float], # The edge width of the markers "plot_scatter_edge_color": Optional[str], # The edge color of the markers (hex color code) }, subtitle=Optional[str], # The subtitle of the chart (or list for multiple charts) emphasis=Optional[str], # "highlight" or "background" (or list for multiple charts) title=Optional[str], # The title of the chart xlabel=Optional[str], # The x-axis label ylabel=Optional[str], # The y-axis label figsize=Optional[Tuple[float, float]], # The figure size in inches show_grid=Optional[str], # Which grid lines to show ("both", "x", "y") aspect_ratio=Optional[str], # The aspect ratio of the axes ("auto", "equal") show_legend=Optional[bool], # Whether to show the legend show_regression=Optional[bool], # Whether to show the regression line show_ci=Optional[bool], # Whether to show the confidence interval around the regression line ci_level=Optional[float], # The confidence interval level (default: 0.95) show_correlation=Optional[bool], # Whether to annotate the Pearson correlation coefficient subplots=Optional[bool], # Whether to draw each chart in its own subplot max_cols=Optional[int], # Maximum number of subplots per row sharex=Optional[bool], # Whether subplots share the x-axis sharey=Optional[bool], # Whether subplots share the y-axis scalex=Optional[str], # The x-axis scale ("linear", "log", "symlog", "asinh") scaley=Optional[str], # The y-axis scale ("linear", "log", "symlog", "asinh") xmin=Optional[Union[int, float]], # The x-axis range xmax=Optional[Union[int, float]], ymin=Optional[Union[int, float]], # The y-axis range ymax=Optional[Union[int, float]], xticks=Optional[List[Union[int, float]]], # the x-axis ticks xticklabels=Optional[List[str]], # the x-axis tick labels (must be same length as xticks) xtickrotate=Optional[int], # the x-axis tick labels rotation yticks=Optional[List[Union[int, float]]], # the y-axis ticks yticklabels=Optional[List[str]], # the y-axis tick labels (must be same length as yticks) ytickrotate=Optional[int], # the y-axis tick labels rotation vlines=Optional[Union[dict, List[dict]]], # the vertical lines hlines=Optional[Union[dict, List[dict]]], # the horizontal lines x=Optional[str], # the key holding the x-axis value (default: "x") y=Optional[str], # the key holding the y-axis value (default: "y") size=Optional[str], # the key holding the marker size value (bubble charts) hue=Optional[str], # the key holding the category for color grouping size_range=Optional[Tuple[float, float]], # the (min_size, max_size) range for bubble charts (default: (20, 200)) ) ``` For more details, see the [datachart.charts.ScatterChart](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.ScatterChart) function. ## Basics The examples in this guide share one dataset: the GDP per capita (in US dollars) and life expectancy (in years) of 36 countries, with their continent and population. The data is hard-coded in a hidden cell; `countries` holds one point per country, and `countries_by_continent` holds one list per continent — Africa, the Americas, Asia and Europe — in the order of `CONTINENTS`. The figures are rounded recent public statistics. Each data point is a dictionary with an `x` value (here the GDP per capita) and a `y` value (the life expectancy). The other keys are ignored until a later example asks for them: ``` countries[:3] ``` **Basic example.** Only the `data` argument is required to draw the scatter chart. ``` ScatterChart( # add the data to the chart data=countries ).show() ``` ## Customizing the Scatter Chart Every customization is either a keyword argument of `ScatterChart` or a `plot_scatter_*` attribute of its `style` dictionary. The table maps common tasks to the one you need and links to the subsection that shows it. | I want to… | Use | See | | -------------------------------------- | ------------------------------------------------------------------------ | ------------------------------------------------------------- | | add a title and axis labels | `title`, `xlabel`, `ylabel` | [Title, axis labels and ticks](#title-axis-labels-and-ticks) | | set custom tick positions and labels | `xticks`, `xticklabels`, `yticks`, `yticklabels` | [Title, axis labels and ticks](#title-axis-labels-and-ticks) | | rotate the tick labels | `xtickrotate`, `ytickrotate` | [Title, axis labels and ticks](#title-axis-labels-and-ticks) | | fix the axis range | `xmin`, `xmax`, `ymin`, `ymax` | [Title, axis labels and ticks](#title-axis-labels-and-ticks) | | resize the figure | `figsize` | [Figure size and grid](#figure-size-and-grid) | | show grid lines | `show_grid` | [Figure size and grid](#figure-size-and-grid) | | change the marker color or shape | `style={"plot_scatter_color": ..., "plot_scatter_marker": ...}` | [Scatter style](#scatter-style) | | change the marker size or transparency | `style={"plot_scatter_size": ..., "plot_scatter_alpha": ...}` | [Scatter style](#scatter-style) | | outline the markers | `style={"plot_scatter_edge_width": ..., "plot_scatter_edge_color": ...}` | [Scatter style](#scatter-style) | | color the points by a category | `hue`, `show_legend` | [Hue grouping](#hue-grouping) | | scale the markers by a value | `size`, `size_range` | [Bubble chart](#bubble-chart) | | fit a regression line | `show_regression`, `show_ci`, `ci_level`, `show_correlation` | [Regression line](#regression-line) | | fix the aspect ratio of the axes | `aspect_ratio` | [Aspect ratio](#aspect-ratio) | | highlight one series, mute the rest | `emphasis` | [Emphasis](#emphasis) | | mark a threshold or a reference value | `hlines`, `vlines` | [Reference lines](#reference-lines) | | compare several series in one chart | `data` as a list of lists, `subtitle`, `show_legend` | [Multiple Scatter Charts](#multiple-scatter-charts) | | draw each series in its own subplot | `subplots`, `sharex`, `sharey`, `max_cols` | [Subplots](#subplots) | | use a logarithmic axis | `scalex`, `scaley` | [Axis scales](#axis-scales) | | plot data with other key names | `x`, `y`, `size`, `hue` | [Custom data keys](#custom-data-keys) | | save the chart to a file | `save_figure` | [Saving the Chart as an Image](#saving-the-chart-as-an-image) | The full list of style attributes is in the [datachart.typings.ScatterStyleAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.ScatterStyleAttrs) type; the full list of parameters is in the [datachart.charts.ScatterChart](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.ScatterChart) reference. ### Title, axis labels and ticks To add the chart title and axis labels, add the `title`, `xlabel` and `ylabel` attributes. The tick positions and their labels can be set with `xticks` and `xticklabels` (or `yticks` and `yticklabels`) — here the GDP per capita ticks are labeled in thousands of dollars. Tick labels can be rotated with `xtickrotate` (or `ytickrotate`), and the axis range can be fixed with `xmin`, `xmax`, `ymin` and `ymax`. ``` GDP_TICKS = [0, 25_000, 50_000, 75_000, 100_000] GDP_TICK_LABELS = ["$0", "$25k", "$50k", "$75k", "$100k"] ScatterChart( data=countries, # add the title title="Life expectancy vs. GDP per capita", # add the x and y axis labels xlabel="GDP per capita (USD)", ylabel="Life expectancy (years)", # label the GDP ticks in thousands of dollars xticks=GDP_TICKS, xticklabels=GDP_TICK_LABELS, # fix the y-axis range ymin=50, ymax=90, ).show() ``` ### Figure size and grid To change the figure size, add the `figsize` attribute. The `figsize` attribute can be a tuple (width, height), values are in inches. The `datachart` package provides a [datachart.constants.FIG_SIZE](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.FIG_SIZE) constant, which contains some of the predefined figure sizes. To add the grid, add the `show_grid` attribute. The possible options are: | Option | Description | | -------- | ----------------------------------------------- | | `"both"` | shows both the x-axis and the y-axis gridlines. | | `"x"` | shows only the x-axis grid lines. | | `"y"` | shows only the y-axis grid lines. | Again, `datachart` provides a [datachart.constants.SHOW_GRID](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.SHOW_GRID) constant, which contains the supported options. ``` from datachart.constants import FIG_SIZE, SHOW_GRID ``` ``` ScatterChart( data=countries, title="Life expectancy vs. GDP per capita", xlabel="GDP per capita (USD)", ylabel="Life expectancy (years)", xticks=GDP_TICKS, xticklabels=GDP_TICK_LABELS, # add to determine the figure size figsize=FIG_SIZE.FULL_SHORT, # add to show the grid lines show_grid=SHOW_GRID.BOTH, ).show() ``` ### Scatter style To change the marker style, add the `style` attribute with the corresponding attributes. The supported attributes are shown in the [datachart.typings.ScatterStyleAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.ScatterStyleAttrs) type, which contains the following attributes: | Attribute | Description | | --------------------------- | ------------------------------------------------ | | `"plot_scatter_color"` | The color of the markers (hex color code). | | `"plot_scatter_alpha"` | The alpha of the markers (how visible they are). | | `"plot_scatter_size"` | The size of the markers. | | `"plot_scatter_marker"` | The marker shape (circle, square, etc.). | | `"plot_scatter_zorder"` | The zorder of the markers. | | `"plot_scatter_edge_width"` | The edge width of the markers. | | `"plot_scatter_edge_color"` | The edge color of the markers (hex color code). | Again, to help with the style settings, the [datachart.constants](https://eriknovak.github.io/datachart/0.9.0/references/constants/index.md) module contains the following constants: | Constant | Description | | ------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------- | | [datachart.constants.LINE_MARKER](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.LINE_MARKER) | The marker shape (circle, square, etc.) | The example below changes the color, transparency, size, shape and outline of the markers in one go. Any attribute you leave out keeps the value of the active theme. ``` from datachart.constants import LINE_MARKER ``` ``` ScatterChart( data=countries, # define the style of the markers style={ "plot_scatter_color": "#e76f51", "plot_scatter_alpha": 0.7, "plot_scatter_size": 80, "plot_scatter_marker": LINE_MARKER.DIAMOND, "plot_scatter_edge_width": 1, "plot_scatter_edge_color": "#1d3557", }, title="Life expectancy vs. GDP per capita", xlabel="GDP per capita (USD)", ylabel="Life expectancy (years)", xticks=GDP_TICKS, xticklabels=GDP_TICK_LABELS, figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.BOTH, ).show() ``` ### Hue grouping To color the points by a categorical variable, add the `hue` attribute with the name of the key that holds the category — here the `continent` key of each country. Each category gets its own color from the theme's palette and its own legend entry, so `show_legend` tells the continents apart. ``` ScatterChart( data=countries, # color the points by continent hue="continent", title="Life expectancy vs. GDP per capita", xlabel="GDP per capita (USD)", ylabel="Life expectancy (years)", xticks=GDP_TICKS, xticklabels=GDP_TICK_LABELS, figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.BOTH, # show the legend with the continent names show_legend=True, ).show() ``` ### Bubble chart To scale the markers by a third variable, add the `size` attribute with the name of the key that holds the value — here the `population` key. The values are mapped linearly onto the marker area range given by `size_range` (the default is `(20, 200)`): the smallest value gets the smallest marker, the largest the largest. With populations from 2 million to 1.4 billion, the upper end is raised so that the gap between the two is visible. An outline and a lower alpha keep overlapping bubbles readable. `hue` and `size` combine freely. Note that the sizes are scaled within each hue group, so the largest country of every continent gets the largest bubble. ``` ScatterChart( data=countries, hue="continent", # scale the markers by population size="population", # widen the range of marker areas size_range=(20, 800), style={ "plot_scatter_alpha": 0.6, "plot_scatter_edge_width": 0.5, "plot_scatter_edge_color": "#1d3557", }, title="Life expectancy vs. GDP per capita, sized by population", xlabel="GDP per capita (USD)", ylabel="Life expectancy (years)", xticks=GDP_TICKS, xticklabels=GDP_TICK_LABELS, figsize=FIG_SIZE.FULL_MEDIUM, show_grid=SHOW_GRID.BOTH, show_legend=True, ).show() ``` ### Regression line To fit a straight line through the points, add the `show_regression` attribute. `show_ci` draws the confidence band around the line and `ci_level` sets its level (the default is 0.95); `show_correlation` annotates the chart with the Pearson correlation coefficient. The line is fitted to the plotted values. Life expectancy grows with the *order of magnitude* of GDP per capita rather than with GDP itself, so the example plots `log10` of the GDP per capita and labels the ticks with the dollar amounts they stand for. With `hue` the regression is fitted to all groups together. ``` import math countries_log_gdp = [{**point, "x": math.log10(point["x"])} for point in countries] ScatterChart( data=countries_log_gdp, # fit a regression line through the points show_regression=True, # draw the 95% confidence band around the line show_ci=True, ci_level=0.95, # annotate the correlation coefficient show_correlation=True, title="Life expectancy vs. GDP per capita", xlabel="GDP per capita (USD)", ylabel="Life expectancy (years)", # the x values are log10(GDP); label them with the dollar amounts xticks=[3, 4, 5], xticklabels=["$1k", "$10k", "$100k"], figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.BOTH, ).show() ``` ### Aspect ratio The `aspect_ratio` attribute fixes the aspect ratio of the axes rather than of the figure: `"auto"` (the default) lets the axes fill the figure, `"equal"` keeps one data unit the same length on both axes. It makes sense when both axes share a unit — distances, coordinates, a predicted value against a measured one — which dollars and years do not. The supported values are in the [datachart.constants.ASPECT_RATIO](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.ASPECT_RATIO) constant; the [European cities example](#example-4-european-cities-bubble-chart-with-an-equal-aspect-ratio) below draws a map with it. ### Emphasis When a chart carries several series, the story is often about one of them. The `emphasis` attribute expresses that directly: `"highlight"` gives the markers a contrasting edge and brings them to the front, `"background"` mutes a series (the theme's muted color at a lower alpha, drawn behind the others), and `None` leaves a series unchanged. For multiple charts, `emphasis` is a list aligned with `data`, just like `subtitle` and `style`. Only emphasized-or-unset series appear in the legend — background series drop out of it. The role strings are also available as the [datachart.constants.EMPHASIS](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.EMPHASIS) constants. The example highlights the European countries against the rest of the world, passed as two series. See the [Highlighting](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/styling/highlighting/index.md) guide for how emphasis works across all chart types and themes. ``` europe = [point for point in countries if point["continent"] == "Europe"] rest_of_world = [point for point in countries if point["continent"] != "Europe"] ScatterChart( data=[rest_of_world, europe], subtitle=["other continents", "Europe"], # mute the rest of the world, highlight Europe emphasis=["background", "highlight"], title="Life expectancy vs. GDP per capita", xlabel="GDP per capita (USD)", ylabel="Life expectancy (years)", xticks=GDP_TICKS, xticklabels=GDP_TICK_LABELS, figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.BOTH, show_legend=True, ).show() ``` ### Reference lines Reference lines mark a threshold or a reference value on the chart. **Horizontal lines.** Use the `hlines` argument with the [datachart.typings.HLinePlotAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.HLinePlotAttrs) typing, which is either a `dict` or a `List[dict]` where each dictionary contains some of the following attributes: ``` { "y": Union[int, float], # The y-axis value "xmin": Optional[Union[int, float]], # The minimum x-axis value "xmax": Optional[Union[int, float]], # The maximum x-axis value "style": { # The style of the line (optional) "plot_hline_color": Optional[str], # The color of the line (hex color code) "plot_hline_style": Optional[LineStyle], # The line style (solid, dashed, etc.) "plot_hline_width": Optional[float], # The width of the line "plot_hline_alpha": Optional[float], # The alpha of the line (how visible the line is) }, "label": Optional[str], # The label of the line (shown in the legend) } ``` **Vertical lines.** Use the `vlines` argument with the [datachart.typings.VLinePlotAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.VLinePlotAttrs) typing, which has the same shape with `x`, `ymin`, `ymax` and `plot_vline_*` style attributes. The example marks the world averages — a life expectancy of 73 years and a GDP per capita of $13,000 — so the lines split the countries into four quadrants. The line labels appear in the legend. ``` from datachart.constants import LINE_STYLE ``` ``` ScatterChart( data=countries, hue="continent", # add a horizontal line at the world average life expectancy hlines={ "y": 73, "label": "world average life expectancy", "style": { "plot_hline_color": "#1d3557", "plot_hline_style": LINE_STYLE.DASHED, "plot_hline_width": 1.5, }, }, # add a vertical line at the world average GDP per capita vlines={ "x": 13_000, "label": "world average GDP per capita", "style": { "plot_vline_color": "#e9a03b", "plot_vline_style": LINE_STYLE.DOTTED, "plot_vline_width": 1.5, }, }, title="Life expectancy vs. GDP per capita", xlabel="GDP per capita (USD)", ylabel="Life expectancy (years)", xticks=GDP_TICKS, xticklabels=GDP_TICK_LABELS, figsize=FIG_SIZE.FULL_MEDIUM, show_grid=SHOW_GRID.BOTH, show_legend=True, ).show() ``` ## Multiple Scatter Charts To create multiple scatter charts, pass a list of lists to the `data` argument. Each inner list represents the data for one chart. Per-chart attributes like `subtitle`, `style` and `emphasis` can be passed as lists, where each element corresponds to a chart. Multiple charts pattern For multiple charts, `data` becomes a list of lists, and per-chart attributes like `subtitle` and `style` become lists where each element applies to the corresponding chart. The `countries_by_continent` dataset is such a list of lists, one series per continent. Unlike `hue`, which colors the groups of one series, separate series can also be styled separately: a single `style` dictionary applies to every chart, while a list of dictionaries styles each chart on its own (`None` keeps the theme style for that chart). ``` ScatterChart( # use a list of lists to define multiple scatter charts data=countries_by_continent, # style can be a list (one per chart) or a single dict (applies to all) style=[ {"plot_scatter_marker": LINE_MARKER.CIRCLE}, {"plot_scatter_marker": LINE_MARKER.SQUARE}, {"plot_scatter_marker": LINE_MARKER.TRIANGLE}, None, # keep the theme style for the fourth chart ], title="Life expectancy vs. GDP per capita", xlabel="GDP per capita (USD)", ylabel="Life expectancy (years)", xticks=GDP_TICKS, xticklabels=GDP_TICK_LABELS, figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.BOTH, ).show() ``` ### Sub-chart subtitles We can name each chart by passing a list of subtitles to the `subtitle` argument. In addition, to help with discerning which chart is which, use the `show_legend` argument to show the legend of the charts. ``` ScatterChart( data=countries_by_continent, # add a subtitle to each chart subtitle=CONTINENTS, title="Life expectancy vs. GDP per capita", xlabel="GDP per capita (USD)", ylabel="Life expectancy (years)", xticks=GDP_TICKS, xticklabels=GDP_TICK_LABELS, figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.BOTH, # show the legend show_legend=True, ).show() ``` ### Subplots To draw each chart in its own subplot, add the `subplots` attribute. The chart's `subtitle` are then added at the top of each subplot, while the `title`, `xlabel` and `ylabel` are positioned to be global for all charts. The `max_cols` attribute limits the number of subplots per row. ``` ScatterChart( data=countries_by_continent, subtitle=CONTINENTS, title="Life expectancy vs. GDP per capita", xlabel="GDP per capita (USD)", ylabel="Life expectancy (years)", xticks=GDP_TICKS, xticklabels=GDP_TICK_LABELS, figsize=FIG_SIZE.FULL_MEDIUM, show_grid=SHOW_GRID.BOTH, # show each chart in its own subplot subplots=True, # at most two subplots per row max_cols=2, ).show() ``` ### Sharing the x-axis and/or y-axis across subplots To share the x-axis and/or y-axis across subplots, add the `sharex` and/or `sharey` attributes, which are boolean values that specify whether to share the axis across all subplots. With shared axes the continents become directly comparable — Africa's cluster no longer fills its subplot. ``` ScatterChart( data=countries_by_continent, subtitle=CONTINENTS, title="Life expectancy vs. GDP per capita", xlabel="GDP per capita (USD)", ylabel="Life expectancy (years)", xticks=GDP_TICKS, xticklabels=GDP_TICK_LABELS, figsize=FIG_SIZE.FULL_MEDIUM, show_grid=SHOW_GRID.BOTH, subplots=True, max_cols=2, # share the x-axis across subplots sharex=True, # share the y-axis across subplots sharey=True, ).show() ``` ## Additional Features ### Axis scales The user can change the axis scale using the `scalex` and `scaley` attributes. The supported scale options are: | Options | Description | | ---------- | ------------------------ | | `"linear"` | The linear scale. | | `"log"` | The log scale. | | `"symlog"` | The symmetric log scale. | | `"asinh"` | The asinh scale. | Again, to help with the options settings, the [datachart.constants](https://eriknovak.github.io/datachart/0.9.0/references/constants/index.md) module contains the following constants: | Constant | Description | | ------------------------------------------------------------------------------------------------------------------------ | ----------------- | | [datachart.constants.SCALE](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.SCALE) | The axis options. | A logarithmic scale pays off when the values span several orders of magnitude. GDP per capita runs from $1,000 to over $100,000: on a linear scale the poorer half of the countries piles up against the y-axis, on a log scale the relationship with life expectancy straightens out and every country gets room. ``` from datachart.constants import SCALE ``` ``` for scale in [SCALE.LINEAR, SCALE.LOG]: figure = ScatterChart( data=countries, hue="continent", title=f"Life expectancy vs. GDP per capita on the '{scale}' scale", xlabel="GDP per capita (USD)", ylabel="Life expectancy (years)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.BOTH, show_legend=True, # set the scale of the x axis scalex=scale, ) figure.show() ``` ### Custom data keys By default, the `data` items are dictionaries with the keys `x` and `y`, and `size` and `hue` name whichever keys hold the bubble size and the category. Data that comes from elsewhere rarely calls its columns `x` and `y`, and renaming every key just to plot it is a chore. Instead, tell `ScatterChart` which keys to read with the `x` and `y` arguments. The `country_records` list below stores the same countries under their natural names. ``` country_records = [ { "country": name, "continent": continent, "gdp_per_capita": gdp, "life_expectancy": life, "population": population, } for name, (continent, gdp, life, population) in COUNTRIES.items() ] country_records[:3] ``` ``` figure = ScatterChart( data=country_records, # specify which keys hold the x and y values x="gdp_per_capita", y="life_expectancy", # and which hold the bubble size and the category size="population", hue="continent", size_range=(20, 800), style={ "plot_scatter_alpha": 0.6, "plot_scatter_edge_width": 0.5, "plot_scatter_edge_color": "#1d3557", }, title="Life expectancy vs. GDP per capita, sized by population", xlabel="GDP per capita (USD)", ylabel="Life expectancy (years)", figsize=FIG_SIZE.FULL_MEDIUM, show_grid=SHOW_GRID.BOTH, show_legend=True, scalex=SCALE.LOG, ) figure.show() ``` ## Saving the Chart as an Image To save the chart as an image, use the [datachart.utils.save_figure](https://eriknovak.github.io/datachart/0.9.0/references/utils#datachart.utils.save_figure) function. ``` from datachart.utils import save_figure ``` ``` save_figure(figure, "./fig_scatter_chart.png", dpi=300) ``` The figure should be saved in the current working directory. ## Real-World Examples The following examples put the features above to work on real or realistic data. Each one states what its data is and where it comes from; the data itself lives in a hidden cell. ### Example 1: Model Accuracy vs. Parameter Count (Regression Line and Confidence Interval) `model_accuracy` holds the benchmark accuracy of 24 illustrative language models with 0.1 to 100 billion parameters. Accuracy grows with the logarithm of the model size, so the points are plotted against `log10` of the parameter count (with the ticks labeled in billions) and `show_regression` fits the scaling trend, `show_ci` draws its 90% confidence band and `show_correlation` reports how tight the trend is. The run-to-run noise comes from a seeded random generator. ``` ScatterChart( data=model_accuracy, style={"plot_scatter_alpha": 0.8}, # fit the scaling trend and its 90% confidence band show_regression=True, show_ci=True, ci_level=0.9, # report the correlation coefficient show_correlation=True, title="Benchmark accuracy vs. model size", xlabel="Parameters", ylabel="Accuracy (%)", # the x values are log10(parameters); label them in billions xticks=[-1, 0, 1, 2], xticklabels=["0.1B", "1B", "10B", "100B"], figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.BOTH, ).show() ``` ### Example 2: Penguin Morphometrics (Hue Grouping and Custom Data Keys) `penguins` holds the bill length and flipper length of 120 illustrative penguins of three species, 40 per species, drawn from a seeded Gaussian around the species means of the Palmer penguins dataset. The measurements are stored under `bill_length` and `flipper_length`, so the keys are mapped with the `x` and `y` arguments, and `hue` colors each species so the three clusters — and the overlap between Adelie and Chinstrap flippers — stand out. ``` ScatterChart( data=penguins, # the points are stored as "bill_length" and "flipper_length" x="bill_length", y="flipper_length", # color the points by species hue="species", style={ "plot_scatter_alpha": 0.7, "plot_scatter_edge_width": 0.5, "plot_scatter_edge_color": "#1d3557", }, title="Penguin flipper length vs. bill length", xlabel="Bill length (mm)", ylabel="Flipper length (mm)", figsize=FIG_SIZE.FULL_MEDIUM, show_grid=SHOW_GRID.BOTH, show_legend=True, ).show() ``` ### Example 3: One Sweep Among Many (Emphasis) `tuning_runs` holds two series of illustrative hyperparameter tuning runs, each run a point of training time against validation accuracy: 150 runs of a broad random search and the 12 runs of a final, narrowed-down sweep. The question is whether the final sweep actually beat the search, so `emphasis` mutes the random search into a background cloud and highlights the sweep. Muted series drop out of the legend automatically; both series are drawn from seeded random generators. ``` ScatterChart( data=tuning_runs, subtitle=["random search", "final sweep"], # mute the random search, highlight the final sweep emphasis=["background", "highlight"], title="Validation accuracy of the tuning runs", xlabel="Training time (minutes)", ylabel="Validation accuracy (%)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.BOTH, show_legend=True, ).show() ``` ### Example 4: European Cities (Bubble Chart with an Equal Aspect Ratio) `cities` holds the longitude, latitude and metropolitan population (in millions, rounded) of 21 European cities. Plotting longitude against latitude turns the scatter chart into a map, which only keeps its shape if a degree is the same length on both axes — hence `aspect_ratio`. `size` scales each bubble by population and `size_range` is widened so that the capitals dominate the map the way they dominate the continent. ``` from datachart.constants import ASPECT_RATIO ``` ``` ScatterChart( data=cities, # scale the bubbles by population size="population", size_range=(30, 900), style={ "plot_scatter_alpha": 0.5, "plot_scatter_edge_width": 0.8, "plot_scatter_edge_color": "#1d3557", }, title="Metropolitan population of European cities", xlabel="Longitude (°E)", ylabel="Latitude (°N)", figsize=FIG_SIZE.FULL_MEDIUM, show_grid=SHOW_GRID.BOTH, # keep one degree the same length on both axes aspect_ratio=ASPECT_RATIO.EQUAL, ).show() ``` # Heatmap This section showcases the heatmap. It contains examples of how to create heatmaps using the [datachart.charts.Heatmap](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.Heatmap) function. Looking for a specific customization? Jump straight to the [quick reference](#customizing-the-heatmap), which maps common tasks to the parameter or style attribute that does the job. As mentioned above, the heatmaps are created using the `Heatmap` function found in the [datachart.charts](https://eriknovak.github.io/datachart/0.9.0/references/charts/index.md) module. Let's import it: ``` from datachart.charts import Heatmap ``` ## Heatmap Input Attributes The `Heatmap` function accepts keyword arguments for chart configuration. The main argument is `data`, which contains the heatmap grid. For a single heatmap, `data` is a dictionary with the 2D matrix `z` (a `None` cell is left blank) and the optional `x` and `y` labels of its columns and rows. For multiple heatmaps, `data` is a list of such dictionaries. ``` Heatmap( data={ # The heatmap grid (or list of grids for multiple charts) "x": Optional[List[Union[str, int, float]]], # The column labels, one per column of z (optional) "y": Optional[List[Union[str, int, float]]], # The row labels, one per row of z (optional) "z": List[List[Union[int, float, None]]], # The heatmap matrix }, style={ # The style of the heatmap (optional) "plot_heatmap_cmap": Optional[Union[str, List[str]]], # The colormap (palette name or list of hex colors) "plot_heatmap_alpha": Optional[float], # The alpha of the heatmap (how visible it is) "plot_heatmap_font_size": Optional[Union[int, float, str]], # The font size of the cell values "plot_heatmap_font_color": Optional[str], # The font color of the cell values (hex color code) "plot_heatmap_font_style": Optional[FONT_STYLE], # The font style of the cell values (normal, italic, etc.) "plot_heatmap_font_weight": Optional[FONT_WEIGHT], # The font weight of the cell values (normal, bold, etc.) "plot_heatmap_frame_color": Optional[str], # The color of the frame around the heatmap (hex color code) "plot_heatmap_edge_width": Optional[float], # The width of the borders between the cells (0 draws none) "plot_heatmap_edge_color": Optional[str], # The color of the borders between the cells (hex color code) }, subtitle=Optional[str], # The subtitle of the chart (or list for multiple charts) title=Optional[str], # The title of the chart xlabel=Optional[str], # The x-axis label ylabel=Optional[str], # The y-axis label figsize=Optional[Tuple[float, float]], # The figure size in inches aspect_ratio=Optional[str], # The aspect ratio of the cells ("auto", "equal") show_colorbars=Optional[bool], # Whether to show the colorbar show_heatmap_values=Optional[bool], # Whether to write the values into the cells valfmt=Optional[str], # The format of the cell values (or list for multiple charts) colorbar={ # The colorbar configuration (or list for multiple charts) "orientation": Optional[ORIENTATION], # The colorbar orientation ("vertical", "horizontal") }, norm=Optional[str], # The value normalization ("linear", "log", "symlog", "asinh", "logit"; or list for multiple charts) vmin=Optional[float], # The value mapped to the first color (or list for multiple charts) vmax=Optional[float], # The value mapped to the last color (or list for multiple charts) show_grid=Optional[str], # Which grid lines to show ("both", "x", "y") show_legend=Optional[bool], # Whether to show the legend (not typical for heatmaps) xmin=Optional[Union[int, float]], # The x-axis range (column indices) xmax=Optional[Union[int, float]], ymin=Optional[Union[int, float]], # The y-axis range (row indices) ymax=Optional[Union[int, float]], max_cols=Optional[int], # Maximum number of subplots per row sharex=Optional[bool], # Whether subplots share the x-axis sharey=Optional[bool], # Whether subplots share the y-axis xticks=Optional[List[Union[int, float]]], # the x-axis ticks (column indices) xticklabels=Optional[List[str]], # the x-axis tick labels (must be same length as xticks) xtickrotate=Optional[int], # the x-axis tick labels rotation yticks=Optional[List[Union[int, float]]], # the y-axis ticks (row indices) yticklabels=Optional[List[str]], # the y-axis tick labels (must be same length as yticks) ytickrotate=Optional[int], # the y-axis tick labels rotation ) ``` For more details, see the [datachart.charts.Heatmap](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.Heatmap) function. ## Basics The examples in this guide share one dataset: the monthly climate of six cities. `temperatures` holds the mean air temperature (in °C) and `precipitation` the mean rainfall (in mm) of every month, rounded from the published 1991–2020 climate normals of the cities' weather stations. The data is hard-coded in a hidden cell; each matrix has one row per city, in the order of `CITIES`, and one column per month, in the order of `MONTHS`. The data is a dictionary: `z` is a plain 2D list where each inner list is one row of the heatmap and each value in it is one cell, while `x` and `y` name its columns and rows. The first row is drawn at the top, the first column at the left: ``` {key: value[:2] for key, value in temperatures.items()} ``` **Basic example.** Only the `data` argument is required to draw the heatmap. Every cell is colored by its value: the lowest value gets the first color of the colormap, the highest the last. The `x` and `y` labels become the tick labels of the axes; without them, the axes are ticked with the cell indices. ``` Heatmap( # add the data to the chart data=temperatures ).show() ``` ## Customizing the Heatmap Every customization is either a keyword argument of `Heatmap` or a `plot_heatmap_*` attribute of its `style` dictionary. The table maps common tasks to the one you need and links to the subsection that shows it. | I want to… | Use | See | | -------------------------------------- | ---------------------------------------------------------------------------- | ----------------------------------------------------------------- | | add a title and axis labels | `title`, `xlabel`, `ylabel` | [Title and axis labels](#title-and-axis-labels) | | name the rows and columns | `xticks`, `xticklabels`, `yticks`, `yticklabels` | [Ticks and labels](#ticks-and-labels) | | rotate the tick labels | `xtickrotate`, `ytickrotate` | [Ticks and labels](#ticks-and-labels) | | resize the figure | `figsize` | [Figure size and aspect ratio](#figure-size-and-aspect-ratio) | | keep the cells square | `aspect_ratio` | [Figure size and aspect ratio](#figure-size-and-aspect-ratio) | | show the colorbar | `show_colorbars`, `colorbar` | [Colorbar and cell values](#colorbar-and-cell-values) | | write the values into the cells | `show_heatmap_values`, `valfmt` | [Colorbar and cell values](#colorbar-and-cell-values) | | change the colormap or transparency | `style={"plot_heatmap_cmap": ..., "plot_heatmap_alpha": ...}` | [Heatmap style](#heatmap-style) | | style the cell values | `style={"plot_heatmap_font_size": ..., "plot_heatmap_font_color": ..., ...}` | [Heatmap style](#heatmap-style) | | change the frame color | `style={"plot_heatmap_frame_color": ...}` | [Heatmap style](#heatmap-style) | | draw borders between the cells | `style={"plot_heatmap_edge_width": ..., "plot_heatmap_edge_color": ...}` | [Heatmap style](#heatmap-style) | | fix the value range of the colormap | `vmin`, `vmax` | [Normalization](#normalization) | | spread skewed values over the colormap | `norm` | [Normalization](#normalization) | | highlight one series, mute the rest | not supported | [Emphasis](#emphasis) | | compare several matrices side by side | `data` as a list of matrices, `subtitle` | [Multiple Heatmap Charts](#multiple-heatmap-charts) | | arrange the subplots | `max_cols`, `sharex`, `sharey` | [Subplot layout and shared axes](#subplot-layout-and-shared-axes) | | save the chart to a file | `save_figure` | [Saving the Chart as an Image](#saving-the-chart-as-an-image) | The full list of style attributes is in the [datachart.typings.HeatmapStyleAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.HeatmapStyleAttrs) type; the full list of parameters is in the [datachart.charts.Heatmap](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.Heatmap) reference. ### Title and axis labels To add the chart title and axis labels, add the `title`, `xlabel` and `ylabel` attributes. ``` Heatmap( data=temperatures, # add the title title="Mean monthly temperature", # add the x and y axis labels xlabel="Month", ylabel="City", ).show() ``` ### Ticks and labels A heatmap places column *j* at `x = j` and row *i* at `y = i`, counting from zero. The `x` and `y` labels of the data name these positions; to tick the axes differently, add the `xticks` and `yticks` attributes with the indices to tick and the `xticklabels` and `yticklabels` attributes with their labels — an explicit `xticks`/`xticklabels` (`yticks`/`yticklabels`) pair overrides the `x` (`y`) labels of the data. Here every third month is ticked. Tick labels can be rotated with `xtickrotate` and `ytickrotate`, whichever labels are shown. ``` Heatmap( data=temperatures, title="Mean monthly temperature", xlabel="Month", ylabel="City", # tick every third month instead of the `x` labels xticks=[0, 3, 6, 9], xticklabels=["Jan", "Apr", "Jul", "Oct"], # rotate the row labels ytickrotate=45, ).show() ``` ### Figure size and aspect ratio To change the figure size, add the `figsize` attribute. The `figsize` attribute can be a tuple (width, height), values are in inches. The `datachart` package provides a [datachart.constants.FIG_SIZE](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.FIG_SIZE) constant, which contains some of the predefined figure sizes. By default the cells stretch to fill the figure, so their shape follows `figsize`. To keep the cells square whatever the figure size, add the `aspect_ratio` attribute. The possible options are: | Option | Description | | --------- | ------------------------------------------------- | | `"auto"` | the cells stretch to fill the axes (the default). | | `"equal"` | the cells are square; the axes shrink to fit. | Again, `datachart` provides a [datachart.constants.ASPECT_RATIO](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.ASPECT_RATIO) constant, which contains the supported options. A 6 × 12 matrix in a short figure is a natural fit for square cells. ``` from datachart.constants import FIG_SIZE, ASPECT_RATIO ``` ``` Heatmap( data=temperatures, title="Mean monthly temperature", xlabel="Month", ylabel="City", # add to determine the figure size figsize=FIG_SIZE.FULL_SHORT, # keep the cells square aspect_ratio=ASPECT_RATIO.EQUAL, ).show() ``` ### Colorbar and cell values A heatmap on its own shows which cells are higher and which are lower, not by how much. Two attributes add the numbers back: `show_colorbars` draws the colorbar that maps the colors to values, and `show_heatmap_values` writes every value into its cell. On dark cells the value is written in white automatically, so it stays legible across the whole colormap. The colorbar is vertical and sits to the right of the heatmap; to draw it horizontally, add the `colorbar` attribute with the [datachart.typings.HeatmapColorbarAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.HeatmapColorbarAttrs) typing, whose `orientation` takes a [datachart.constants.ORIENTATION](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.ORIENTATION) value. To format the values written into the cells, add the `valfmt` attribute, which is a `string` depicting how to format the values. Examples of such formats are: | Format | Description | | ----------- | ---------------------------------------------------------- | | `"{x}"` | Formats the value as is (no change to the value). | | `"{x:.0f}"` | Formats the value as an integer (rounds floats). | | `"{x:.2f}"` | Formats the value as a float with two decimal places. | | `"{x:.2%}"` | Formats the value as a percentage with two decimal places. | Required presence of `x` To format the heatmap values, the `x` value must be present in the string. For instance `"{z:.2f}"` is not a valid format, and `z` should be replaced with `x`. Again, to help with the settings, the [datachart.constants](https://eriknovak.github.io/datachart/0.9.0/references/constants/index.md) module contains the following constants: | Constant | Description | | -------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- | | [datachart.constants.VALUE_FORMAT](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.VALUE_FORMAT) | The predefined value formats. | | [datachart.constants.ORIENTATION](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.ORIENTATION) | The colorbar orientation. | The temperatures are given to one decimal place, so the example formats the cells with `VALUE_FORMAT.DECIMAL`. ``` from datachart.constants import VALUE_FORMAT ``` ``` Heatmap( data=temperatures, title="Mean monthly temperature", xlabel="Month", ylabel="City", figsize=FIG_SIZE.FULL_MEDIUM, # add to show the colorbar show_colorbars=True, # add to write the values into the cells show_heatmap_values=True, # format the values with one decimal place valfmt=VALUE_FORMAT.DECIMAL, ).show() ``` ### Heatmap style To change the heatmap style, add the `style` attribute with the corresponding attributes. The supported attributes are shown in the [datachart.typings.HeatmapStyleAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.HeatmapStyleAttrs) type, which contains the following attributes: | Attribute | Description | | ---------------------------- | ------------------------------------------------------------------------------- | | `"plot_heatmap_cmap"` | The colormap used to draw the heatmap (a palette name or a list of hex colors). | | `"plot_heatmap_alpha"` | The alpha of the heatmap (how visible it is). | | `"plot_heatmap_font_size"` | The font size of the cell values. | | `"plot_heatmap_font_color"` | The font color of the cell values. | | `"plot_heatmap_font_style"` | The font style of the cell values (normal, italic, etc.). | | `"plot_heatmap_font_weight"` | The font weight of the cell values (normal, bold, etc.). | | `"plot_heatmap_frame_color"` | The color of the frame drawn around the heatmap. | | `"plot_heatmap_edge_width"` | The width of the borders drawn between the cells (0, the default, draws none). | | `"plot_heatmap_edge_color"` | The color of the borders drawn between the cells. | Again, to help with the style settings, the [datachart.constants](https://eriknovak.github.io/datachart/0.9.0/references/constants/index.md) module contains the following constants: | Constant | Description | | ------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------- | | [datachart.constants.COLORS](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.COLORS) | The predefined colormaps. | | [datachart.constants.FONT_STYLE](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.FONT_STYLE) | The font style (normal, italic, etc.). | | [datachart.constants.FONT_WEIGHT](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.FONT_WEIGHT) | The font weight (normal, bold, etc.). | The colormap is the style choice that matters most. Sequential palettes such as `COLORS.Blues` or `COLORS.YlOrRd` run from light to dark and suit values with a natural zero; diverging palettes such as `COLORS.Coolwarm` or `COLORS.RdBu` run through a neutral middle and suit values with a meaningful center. All predefined palettes are rendered in the [Colormaps](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/styling/colormaps/index.md) guide. The cells touch by default; a `plot_heatmap_edge_width` above zero draws borders between them in the `plot_heatmap_edge_color`, which separates neighboring cells of similar shade. Any attribute you leave out keeps the value of the active theme. ``` from datachart.constants import COLORS, FONT_STYLE, FONT_WEIGHT ``` ``` Heatmap( data=temperatures, # define the style of the heatmap style={ "plot_heatmap_cmap": COLORS.YlOrRd, "plot_heatmap_alpha": 0.9, "plot_heatmap_font_size": 7, "plot_heatmap_font_style": FONT_STYLE.ITALIC, "plot_heatmap_font_weight": FONT_WEIGHT.BOLD, "plot_heatmap_frame_color": "#b5442c", "plot_heatmap_edge_width": 1, "plot_heatmap_edge_color": "#FFFFFF", }, title="Mean monthly temperature", xlabel="Month", ylabel="City", figsize=FIG_SIZE.FULL_MEDIUM, show_colorbars=True, show_heatmap_values=True, valfmt=VALUE_FORMAT.DECIMAL, ).show() ``` ### Normalization The colors of a heatmap come from a two-step mapping: the values are first normalized to the 0–1 range, then each normalized value picks its color from the colormap. Both steps can be adjusted. **Value range.** By default the smallest value in the matrix maps to the first color and the largest to the last. The `vmin` and `vmax` attributes pin those endpoints instead. With a diverging colormap this is what puts the neutral middle color on a meaningful value: the temperatures run from −6.7 to 28.5 °C, so with the default range the white center of `COLORS.Coolwarm` would land on about 11 °C. Pinning the range to −30 … 30 °C places it on the freezing point, and every blue cell is a month below zero. ``` Heatmap( data=temperatures, style={"plot_heatmap_cmap": COLORS.Coolwarm}, # pin the value range so that 0 °C sits in the middle of the colormap vmin=-30, vmax=30, title="Mean monthly temperature", xlabel="Month", ylabel="City", figsize=FIG_SIZE.FULL_MEDIUM, show_colorbars=True, show_heatmap_values=True, valfmt=VALUE_FORMAT.DECIMAL, ).show() ``` **Normalization.** The `norm` attribute changes how the values are spread over the 0–1 range. The possible options are: | Option | Description | | ---------- | --------------------------------------------------------------------------------- | | `"linear"` | Linear normalization (the default). | | `"log"` | Log normalization. Non-positive values have no logarithm and are left blank. | | `"symlog"` | Symmetric log normalization: linear near zero, logarithmic beyond. | | `"asinh"` | Inverse hyperbolic sine normalization: like `"symlog"`, with a smooth transition. | | `"logit"` | Logit normalization, for values strictly between 0 and 1. | Again, `datachart` provides a [datachart.constants.NORMALIZE](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.NORMALIZE) constant, which contains the supported options. Note that `norm` is distinct from the `scalex` and `scaley` attributes of the other charts, which scale an axis — here it is the colors that are rescaled. A non-linear normalization earns its place on skewed data. The `precipitation` matrix runs from Cairo's rain-free summer to Singapore's 290 mm December: on the linear normalization Singapore claims the dark end of the colormap and the seasonal cycles of the other four cities are flattened into pale blues, while the symmetric log normalization spreads the lower values out and the wet and dry seasons of every city show. ``` from datachart.constants import NORMALIZE ``` ``` for norm in [NORMALIZE.LINEAR, NORMALIZE.SYMLOG]: Heatmap( data=precipitation, # change how the values are spread over the colormap norm=norm, title=f"Mean monthly precipitation with the '{norm}' normalization", xlabel="Month", ylabel="City", figsize=FIG_SIZE.FULL_MEDIUM, show_colorbars=True, show_heatmap_values=True, valfmt=VALUE_FORMAT.INTEGER, ).show() ``` ### Emphasis The other charts accept an `emphasis` attribute that highlights one series and mutes the rest. The heatmap does not: a heatmap is a single raster layer, not a set of series, so there is nothing to bring forward or push back, and `Heatmap` raises a `ValueError` if `emphasis` is passed. To draw attention to part of a heatmap, use the tools above instead — a diverging colormap with a pinned value range, or `vmin` and `vmax` that saturate everything outside the range of interest. See the [Highlighting](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/styling/highlighting/index.md) guide for how emphasis works on the charts that support it. ## Multiple Heatmap Charts To create multiple heatmaps, pass a list of grids to the `data` argument. Each grid is drawn in its own subplot — two rasters cannot share one set of axes — with the `subtitle` at the top of each subplot and the `title`, `xlabel` and `ylabel` positioned to be global for all charts. Per-chart attributes like `subtitle`, `style`, `valfmt`, `norm`, `vmin`, `vmax` and `colorbar` can be passed as lists, where each element corresponds to a chart; a single value applies to every chart. Multiple charts pattern For multiple charts, `data` becomes a list of grids, and per-chart attributes like `subtitle`, `style` and `valfmt` become lists where each element applies to the corresponding chart. The example draws the temperatures and the precipitation of the six cities side by side. The two grids hold different quantities, so each gets its own subtitle and its own colormap through a list of `style` dictionaries (`None` keeps the theme style for that chart). Twelve columns side by side leave no room for the cell values; the next section stacks the charts and writes them in. ``` Heatmap( # use a list of grids to define multiple heatmaps data=[temperatures, precipitation], # add a subtitle to each chart subtitle=["Temperature (°C)", "Precipitation (mm)"], # style can be a list (one per chart) or a single dict (applies to all) style=[ {"plot_heatmap_cmap": COLORS.YlOrRd}, None, # keep the theme style for the second chart ], title="Monthly climate", xlabel="Month", ylabel="City", xtickrotate=90, figsize=FIG_SIZE.FULL_MEDIUM, show_colorbars=True, ).show() ``` ### Subplot layout and shared axes The `max_cols` attribute limits the number of subplots per row — with `max_cols=1` the charts stack vertically, which gives a wide matrix the full figure width and room for the cell values. Like `style`, `valfmt` can be a list with one format per chart: the temperatures keep their decimal place, the precipitation is written as integers. To share the x-axis and/or y-axis across subplots, add the `sharex` and/or `sharey` attributes, which are boolean values that specify whether to share the axis across all subplots; a shared axis is labeled once, on the outer subplots only. ``` figure = Heatmap( data=[temperatures, precipitation], subtitle=["Temperature (°C)", "Precipitation (mm)"], style=[ {"plot_heatmap_cmap": COLORS.YlOrRd}, None, ], # format the values of each chart on its own valfmt=[VALUE_FORMAT.DECIMAL, VALUE_FORMAT.INTEGER], title="Monthly climate", xlabel="Month", ylabel="City", figsize=FIG_SIZE.FULL_TALL, show_colorbars=True, show_heatmap_values=True, # stack the charts in one column max_cols=1, # share the x-axis across subplots sharex=True, ) figure.show() ``` ## Saving the Chart as an Image To save the chart as an image, use the [datachart.utils.save_figure](https://eriknovak.github.io/datachart/0.9.0/references/utils#datachart.utils.save_figure) function. ``` from datachart.utils import save_figure ``` ``` save_figure(figure, "./fig_heatmap.png", dpi=300) ``` The figure should be saved in the current working directory. ## Real-World Examples The following examples put the features above to work on real or realistic data. Each one states what its data is and where it comes from; the data itself lives in a hidden cell. ### Example 1: Correlation Matrix (Diverging Colormap and Pinned Value Range) `correlations` holds the Pearson correlation between the four body measurements — bill length, bill depth, flipper length and body mass — of the 342 penguins of the [Palmer penguins](https://allisonhorst.github.io/palmerpenguins/) dataset (CC0). A correlation matrix is the textbook case for a diverging colormap: the sign matters as much as the size, so `COLORS.Coolwarm` is pinned to the −1 … 1 range with `vmin` and `vmax`, which puts white on zero and the same shade on equal correlations of either sign. The variable names label both axes, `VALUE_FORMAT.DECIMAL_2` writes the coefficients into the cells, and `ASPECT_RATIO.EQUAL` keeps the matrix square. ``` Heatmap( data=correlations, # a diverging colormap, pinned so that zero sits on white style={"plot_heatmap_cmap": COLORS.Coolwarm}, vmin=-1, vmax=1, title="Correlation of Palmer penguin measurements", # the variable names come from the `x` and `y` labels of the data xtickrotate=45, figsize=FIG_SIZE.SQUARE, aspect_ratio=ASPECT_RATIO.EQUAL, show_colorbars=True, show_heatmap_values=True, valfmt=VALUE_FORMAT.DECIMAL_2, ).show() ``` ### Example 2: Confusion Matrix (Integer Cell Values and Class Labels) `confusion` holds the illustrative confusion matrix of a topic classifier evaluated on 1,000 news articles, 250 in each of four topics: each row is the true topic, each column the predicted one, and each cell the number of articles. The diagonal holds the correct predictions; the off-diagonal cells show which topics get mixed up — here business and politics articles for one another. The class names label both axes, `VALUE_FORMAT.INTEGER` writes the counts into the cells, and the sequential default colormap makes the diagonal stand out. The colorbar is left out — the cell values already carry the numbers. ``` Heatmap( data=confusion, title="Topic classifier on 1,000 news articles", xlabel="Predicted topic", ylabel="True topic", figsize=FIG_SIZE.SQUARE, aspect_ratio=ASPECT_RATIO.EQUAL, # write the counts into the cells show_heatmap_values=True, valfmt=VALUE_FORMAT.INTEGER, ).show() ``` ### Example 3: Contributions Calendar (Blank Cells, Sparse Ticks and Skewed Counts) `contributions` holds the number of commits on each day of 2025 by one illustrative developer, drawn from a seeded generator: most weekdays see a few commits, weekends rarely any, and two release weeks in March and September see a burst of them. The matrix is laid out like the GitHub contributions graph — one row per weekday from Monday to Sunday, one column per week of the year — and the days before January 1 and after December 31 in the first and last week are `None`, so they are left blank. The calendar only makes sense with square cells (`ASPECT_RATIO.EQUAL`) and a wide, short figure; `yticks` label every other weekday, `xticks` mark the week each month starts in (`month_weeks`, computed in the hidden cell), the colormap is GitHub's green scale passed as a list of hex colors, and white cell borders (`plot_heatmap_edge_width` and `plot_heatmap_edge_color`) stand in for the gaps between GitHub's squares. The release weeks would drown the everyday commits on a linear colormap, so `NORMALIZE.ASINH` spreads the low counts over the greens. There is no colorbar: the calendar is read by pattern, not by value. ``` # the green scale of the GitHub contributions graph, from no commits to many GITHUB_GREENS = ["#ebedf0", "#9be9a8", "#40c463", "#30a14e", "#216e39"] Heatmap( data={"z": contributions}, style={ "plot_heatmap_cmap": GITHUB_GREENS, # white borders separate the days like the gaps in the GitHub graph "plot_heatmap_edge_width": 1, "plot_heatmap_edge_color": "#FFFFFF", }, # spread the everyday counts over the colormap despite the release weeks norm=NORMALIZE.ASINH, title=f"Contributions in {YEAR}", # label every other weekday yticks=[0, 2, 4], yticklabels=["Mon", "Wed", "Fri"], # mark the week each month starts in xticks=month_weeks, xticklabels=MONTHS, figsize=(9.7, 2.0), aspect_ratio=ASPECT_RATIO.EQUAL, show_colorbars=False, ).show() ``` ### Example 4: Comparing Two Classifiers (Multiple Heatmaps and a Shared Value Range) `confusions` holds the illustrative confusion matrices of two topic classifiers evaluated on the same 1,000 news articles as Example 2: the baseline model and a fine-tuned one. The question is whether the fine-tuning cleared up the business–politics confusion, so the two matrices are drawn side by side as multiple heatmaps, named with a list of `subtitle` and styled with a list of `style` dictionaries — grey for the baseline, blue for the new model. A single `vmin` and `vmax` pins both charts to the same 0 … 250 range, so an equally dark cell means an equally large count in either chart; `sharey` labels the true topics once. ``` Heatmap( data=confusions, subtitle=["Baseline", "Fine-tuned"], style=[ {"plot_heatmap_cmap": COLORS.Greys}, {"plot_heatmap_cmap": COLORS.Blues}, ], # the same value range for both charts, so the shades are comparable vmin=0, vmax=250, title="Topic classifiers on 1,000 news articles", xlabel="Predicted topic", ylabel="True topic", xtickrotate=45, figsize=(6.3, 4.0), aspect_ratio=ASPECT_RATIO.EQUAL, show_heatmap_values=True, valfmt=VALUE_FORMAT.INTEGER, # label the true topics once sharey=True, ).show() ``` # Contour Chart This section showcases the contour chart. It contains examples of how to create contour charts using the [datachart.charts.ContourChart](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.ContourChart) function. Looking for a specific customization? Jump straight to the [quick reference](#customizing-the-contour-chart), which maps common tasks to the parameter or style attribute that does the job. As mentioned above, the contour charts are created using the `ContourChart` function found in the [datachart.charts](https://eriknovak.github.io/datachart/0.9.0/references/charts/index.md) module. Let's import it: ``` from datachart.charts import ContourChart ``` ## Contour Chart Input Attributes The `ContourChart` function accepts keyword arguments for chart configuration. The main argument is `data`, which contains the gridded surface. For a single contour chart, `data` is a dictionary with the 2-D `z` grid and the optional `x` and `y` axis values; for multiple contour charts, `data` is a list of such dictionaries. ``` ContourChart( data={ # The gridded surface (or list of surfaces for multiple charts) "x": Union[List[Union[int, float]], None], # The x-axis values, one per column of z (the column indices by default) "y": Union[List[Union[int, float]], None], # The y-axis values, one per row of z (the row indices by default) "z": List[List[Union[int, float]]], # The 2-D grid of surface values, one row per y and one column per x }, style={ # The style of the contour chart (optional) "plot_contour_color": Optional[str], # The iso-line color (the panel's color cycle by default) "plot_contour_cmap": Optional[Union[str, List[str]]], # The colormap of the filled bands (the heatmap colormap by default) "plot_contour_line_width": Optional[Union[int, float]], # The iso-line width (the line chart width by default) "plot_contour_line_style": Optional[str], # The iso-line style "plot_contour_alpha": Optional[float], # The alpha of the contour "plot_contour_zorder": Optional[Union[int, float]], # The z-order of the contour "plot_contour_label_font_size": Optional[Union[int, float]], # The font size of the inline level labels "plot_contour_label_font_color": Optional[str], # The color of the inline level labels (the line color by default) }, title: Optional[str], # The title of the chart xlabel: Optional[str], # The x-axis label ylabel: Optional[str], # The y-axis label subtitle: Optional[Union[str, List[str]]], # The subtitle(s), also used as legend labels emphasis: Optional[Union[str, List[Optional[str]]]], # The emphasis role(s) of the iso-lines ("background", "highlight", None) figsize: Optional[Tuple[float, float]], # The size of the figure xmin: Optional[Union[int, float]], # The minimum x-axis value xmax: Optional[Union[int, float]], # The maximum x-axis value ymin: Optional[Union[int, float]], # The minimum y-axis value ymax: Optional[Union[int, float]], # The maximum y-axis value show_legend: Optional[bool], # Whether to show the legend show_grid: Optional[str], # Which grid lines to show ("both", "x", "y"); off by default for filled contours filled: Optional[bool], # Whether to fill the bands between the levels instead of drawing iso-lines levels: Optional[Union[str, int, List[float]]], # The level rule ("auto", "rice", "fd"), a target count, or explicit level values show_labels: Optional[bool], # Whether to write the level values along the iso-lines show_colorbars: Optional[bool], # Whether to show the colorbar of filled contours aspect_ratio: Optional[str], # The aspect ratio of the axes ("auto", "equal") scalex: Optional[str], # The x-axis scale ("linear", "log", ...) scaley: Optional[str], # The y-axis scale ("linear", "log", ...) subplots: Optional[bool], # Whether to create a separate subplot for each chart max_cols: Optional[int], # The maximum number of columns in the subplots sharex: Optional[bool], # Whether to share the x-axis across the subplots sharey: Optional[bool], # Whether to share the y-axis across the subplots norm: Optional[Union[str, List[str]]], # The value normalization of the colormap vmin: Optional[Union[float, List[float]]], # The minimum value of the colormap range vmax: Optional[Union[float, List[float]]], # The maximum value of the colormap range valfmt: Optional[Union[str, List[str]]], # The format of the inline level labels (e.g. "{x:.1f}") xticks: Optional[List[Union[int, float]]], # The x-axis tick positions xticklabels: Optional[List[str]], # The x-axis tick labels xtickrotate: Optional[int], # The rotation of the x-axis tick labels yticks: Optional[List[Union[int, float]]], # The y-axis tick positions yticklabels: Optional[List[str]], # The y-axis tick labels ytickrotate: Optional[int], # The rotation of the y-axis tick labels vlines: Optional[Union[dict, List[dict]]], # The vertical reference lines hlines: Optional[Union[dict, List[dict]]], # The horizontal reference lines colorbar: Optional[Union[dict, List[dict]]], # The colorbar configuration(s) ({"orientation": ...}) texts: Optional[Union[dict, List[dict]]], # The text annotations ) ``` For more details, see the [datachart.charts.ContourChart](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.ContourChart) function. ## Basics The examples in this guide share one surface: the [Himmelblau function](https://en.wikipedia.org/wiki/Himmelblau%27s_function), a classic test surface for optimization algorithms with four minima of equal depth and one local maximum between them. `chart_data` samples it on a 120×120 grid over the −5 … 5 square: `x` and `y` hold the grid coordinates and `z` the function value at every grid point, one row per `y` and one column per `x`. ``` import numpy as np GRID = np.linspace(-5, 5, 120) X, Y = np.meshgrid(GRID, GRID) # the Himmelblau function, sampled on the grid himmelblau = (X**2 + Y - 11) ** 2 + (X + Y**2 - 7) ** 2 chart_data = {"x": GRID.tolist(), "y": GRID.tolist(), "z": himmelblau.tolist()} ``` The data is a dictionary with the grid coordinates and the surface. The `z` grid is a list of rows, one per `y` value, and each row holds one value per `x` value; `x` and `y` are optional — without them the grid is drawn over its cell indices: ``` [len(chart_data["x"]), len(chart_data["y"]), len(chart_data["z"]), len(chart_data["z"][0])] ``` **Basic example.** Only the `data` argument is required to draw the contour chart. The surface is cut at a handful of round values and every cut is drawn as an iso-line — a line of equal value, like the elevation lines of a map. The lines take the chart's color, so a lone contour chart matches a lone line chart; closed loops mark the minima and maxima of the surface. ``` ContourChart( # add the data to the chart data=chart_data ).show() ``` ## Customizing the Contour Chart Every customization is either a keyword argument of `ContourChart` or a `plot_contour_*` attribute of its `style` dictionary. The table maps common tasks to the one you need and links to the subsection that shows it. | I want to… | Use | See | | ---------------------------------------- | ------------------------------------------------------------------- | ------------------------------------------------------------- | | add a title and axis labels | `title`, `xlabel`, `ylabel` | [Title and axis labels](#title-and-axis-labels) | | resize the figure | `figsize` | [Figure size and grid](#figure-size-and-grid) | | show or hide the grid lines | `show_grid` | [Figure size and grid](#figure-size-and-grid) | | fill the bands between the levels | `filled=True` | [Filled contours and colorbar](#filled-contours-and-colorbar) | | add a colorbar | `show_colorbars=True`, `colorbar={"orientation": ...}` | [Filled contours and colorbar](#filled-contours-and-colorbar) | | write the level values on the lines | `show_labels=True`, `valfmt` | [Inline labels](#inline-labels) | | choose how many levels cut the surface | `levels` | [Levels](#levels) | | change the line color, width, or style | `style={"plot_contour_color": ..., "plot_contour_line_width": ...}` | [Contour style](#contour-style) | | change the colormap of the fills | `style={"plot_contour_cmap": ...}` | [Contour style](#contour-style) | | pin or rescale the colormap range | `vmin`, `vmax`, `norm` | [Normalization](#normalization) | | overlay several surfaces | `data=[...]`, `subtitle`, `show_legend` | [Multiple Contour Charts](#multiple-contour-charts) | | draw each surface in its own subplot | `subplots=True`, `max_cols`, `sharex`, `sharey` | [Subplots and shared axes](#subplots-and-shared-axes) | | highlight one surface among several | `emphasis` | [Emphasis](#emphasis) | | draw the contours over a scatter chart | `Panel` | [Composing contours](#composing-contours) | | keep one unit equal on both axes | `aspect_ratio` | [Aspect ratio](#aspect-ratio) | | mark a position with a reference line | `vlines`, `hlines` | [Reference lines](#reference-lines) | | estimate the density of scattered points | `stats.kde2d`, `bandwidth` | [Density of scattered points](#density-of-scattered-points) | ### Title and axis labels To add the chart title and axis labels, add the `title`, `xlabel` and `ylabel` attributes. ``` ContourChart( data=chart_data, # add the title title="Himmelblau function", # add the x and y axis labels xlabel="x", ylabel="y", ).show() ``` ### Figure size and grid To change the figure size, add the `figsize` attribute. The `figsize` attribute can be a tuple (width, height), values are in inches. The `datachart` package provides a [datachart.constants.FIG_SIZE](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.FIG_SIZE) constant, which contains predefined figure sizes. To change which grid lines are shown, add the `show_grid` attribute, which supports the values of the [datachart.constants.SHOW_GRID](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.SHOW_GRID) constant — iso-lines draw over the theme's default grid, so both axes can be gridded to read positions off the lines. ``` from datachart.constants import FIG_SIZE, SHOW_GRID ``` ``` ContourChart( data=chart_data, title="Himmelblau function", xlabel="x", ylabel="y", # add to determine the figure size figsize=FIG_SIZE.FULL_SHORT, # add to show the grid lines on both axes show_grid=SHOW_GRID.BOTH, ).show() ``` ### Filled contours and colorbar To fill the bands between the levels instead of drawing iso-lines, add the `filled` attribute. A filled contour colors every band by its value with the colormap — the heatmap colormap by default — so the low and the high regions of the surface read at a glance; the grid is left off, as the bands would cover it. To map the colors back to values, add the `show_colorbars` attribute, which draws the colorbar to the right of the chart; to draw it horizontally instead, add the `colorbar` attribute with the [datachart.typings.HeatmapColorbarAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.HeatmapColorbarAttrs) typing, whose `orientation` takes a value of the [datachart.constants.ORIENTATION](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.ORIENTATION) constant. ``` from datachart.constants import ORIENTATION ``` ``` ContourChart( data=chart_data, # fill the bands between the levels filled=True, # add the colorbar, drawn above the chart show_colorbars=True, colorbar={"orientation": ORIENTATION.HORIZONTAL}, title="Himmelblau function", xlabel="x", ylabel="y", figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` ### Inline labels To write the value of every level along its iso-line, add the `show_labels` attribute. The labels are formatted by the `valfmt` attribute, a format string with the value named `x` (e.g. `"{x:.1f}"`); the [datachart.constants.VALUE_FORMAT](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.VALUE_FORMAT) constant holds the common ones. The labels take the line color and a font two points smaller than the general font, which the `plot_contour_label_font_size` and `plot_contour_label_font_color` style attributes override. ``` from datachart.constants import VALUE_FORMAT ``` ``` ContourChart( data=chart_data, # write the level values along the lines, as integers show_labels=True, valfmt=VALUE_FORMAT.INTEGER, title="Himmelblau function", xlabel="x", ylabel="y", figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` ### Levels The `levels` attribute chooses which values cut the surface. It takes one of the following: | Value | Description | | ---------- | ------------------------------------------------------------------------------------------------------------------------------ | | `"auto"` | Matplotlib's own choice: about eight round values across the range of the surface (the default). | | `"rice"` | The Rice rule: `2 * n ** (1/3)` levels, where `n` is the per-axis resolution of the grid — about ten levels on a 120×120 grid. | | `"fd"` | The Freedman–Diaconis rule: the value range over `2 * IQR * n ** (-1/3)` — about twice as dense as Rice on the same grid. | | an integer | A target number of levels, snapped to round values. | | a list | The exact level values to draw. | The `datachart` package provides the [datachart.constants.CONTOUR_LEVELS](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.CONTOUR_LEVELS) constant with the rules. The rules follow the grid resolution rather than the surface, so they are opt-ins; for a surface whose range spans orders of magnitude, an explicit list of levels is usually the best choice. ``` from datachart.constants import CONTOUR_LEVELS ``` ``` ContourChart( data=chart_data, # cut the surface by the Rice rule levels=CONTOUR_LEVELS.RICE, show_labels=True, valfmt=VALUE_FORMAT.INTEGER, title="Himmelblau function", xlabel="x", ylabel="y", figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` The Himmelblau function is flat around its minima and steep at the corners, so evenly spaced levels crowd the corners and leave the middle empty. A list of hand-picked levels, dense near zero and sparse further up, follows the shape of the surface instead: ``` ContourChart( data=chart_data, # explicit levels: dense near the minima, sparse up the slopes levels=[2, 10, 30, 60, 100, 150, 250, 400, 600], show_labels=True, valfmt=VALUE_FORMAT.INTEGER, title="Himmelblau function", xlabel="x", ylabel="y", figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` ### Contour style To change the contour style, add the `style` attribute with the corresponding attributes. The supported attributes are shown in the [datachart.typings.ContourStyleAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.ContourStyleAttrs) type, which contains the following attributes: | Attribute | Description | | --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `"plot_contour_color"` | The color of the iso-lines; the panel's color cycle by default. | | `"plot_contour_cmap"` | The colormap of the filled bands (a palette name or a list of hex colors); the heatmap colormap by default. Iso-lines take it only when it is set, colored by level from its darker part. | | `"plot_contour_line_width"` | The width of the iso-lines; the line chart width by default. | | `"plot_contour_line_style"` | The style of the iso-lines (solid, dashed, ...). | | `"plot_contour_alpha"` | The alpha of the contour (how visible it is). | | `"plot_contour_zorder"` | The z-order of the contour among the other layers. | | `"plot_contour_label_font_size"` | The font size of the inline level labels. | | `"plot_contour_label_font_color"` | The color of the inline level labels; the line color by default. | The `datachart` package provides the [datachart.constants.LINE_STYLE](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.LINE_STYLE) constant with the line styles and the [datachart.constants.COLORS](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.COLORS) constant with the colormaps. ``` from datachart.constants import COLORS, LINE_STYLE ``` ``` ContourChart( data=chart_data, # define the style of the contour style={ "plot_contour_color": "#d62728", "plot_contour_line_width": 1.0, "plot_contour_line_style": LINE_STYLE.DASHED, "plot_contour_label_font_size": 7, "plot_contour_label_font_color": "#333333", }, levels=[2, 10, 30, 60, 100, 150, 250, 400, 600], show_labels=True, valfmt=VALUE_FORMAT.INTEGER, title="Himmelblau function", xlabel="x", ylabel="y", figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` With a colormap set, the iso-lines are colored by their level instead of drawing in one color — the low levels in the lighter shades, the high ones in the darker. The colormap is sampled from its darker part, since the lightest shades of a sequential colormap would vanish on the white background: ``` ContourChart( data=chart_data, # color the iso-lines by level style={"plot_contour_cmap": COLORS.Viridis}, levels=[2, 10, 30, 60, 100, 150, 250, 400, 600], title="Himmelblau function", xlabel="x", ylabel="y", figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` ### Normalization The colors of a filled contour come from a two-step mapping: the level values are first normalized to the 0–1 range, then each normalized value picks its color from the colormap. Both steps can be adjusted. **Value range.** By default the lowest level maps to the first color and the highest to the last. The `vmin` and `vmax` attributes pin those endpoints instead, which keeps the shades comparable across charts of the same quantity. **Normalization.** The `norm` attribute changes how the values are spread over the 0–1 range; the options are the values of the [datachart.constants.NORMALIZE](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.NORMALIZE) constant (`"linear"`, `"log"`, `"symlog"`, `"asinh"`, `"logit"`). The Himmelblau function ranges from 0 to about 900 while its interesting part sits below 50: with log-spaced levels and the log normalization every band takes an equally distinct shade, where the linear normalization would spend most of the colormap on the empty corners. ``` from datachart.constants import NORMALIZE ``` ``` ContourChart( data=chart_data, filled=True, show_colorbars=True, # log-spaced levels, spread evenly over the colormap levels=[1, 3, 10, 30, 100, 300, 1000], norm=NORMALIZE.LOG, title="Himmelblau function", xlabel="x", ylabel="y", figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` ## Multiple Contour Charts To create multiple contour charts, pass a list of surfaces to the `data` argument. Each surface is drawn as its own set of iso-lines on the same axes, in its own color, and the `subtitle` of each chart becomes its legend label; `subplots=True` draws each surface in its own subplot instead. Several filled contours would cover each other, so fills are best kept to subplots. `species_density` holds three surfaces from the [Palmer penguins](https://allisonhorst.github.io/palmerpenguins/) dataset (CC0): the density of the 342 penguins of each species over their flipper length and body mass. The measurements are hard-coded in a hidden cell as `PENGUINS`; the cell below turns them into surfaces with [datachart.utils.stats.kde2d](https://eriknovak.github.io/datachart/0.9.0/references/utils/stats/#datachart.utils.stats.kde2d) — this is how a KDE chart is built from raw points (see [Density of scattered points](#density-of-scattered-points)). Every species is evaluated on one shared 80×80 grid, the range of all penguins padded by 10%, so the surfaces line up in subplots; the density is scaled to penguins per mm of flipper length and kg of body mass. The cell also keeps every penguin as a point in `penguin_points` for the later sections. ``` from datachart.utils.stats import kde2d, minimum, maximum SPECIES = ["Adelie", "Chinstrap", "Gentoo"] # one grid shared by every species: the range of all penguins, padded by 10% ALL_LENGTHS = [length for record in PENGUINS for length in record["flipper_length"]] ALL_MASSES = [mass for record in PENGUINS for mass in record["body_mass"]] def padded_range(values, padding=0.1): lo, hi = minimum(values), maximum(values) return lo - padding * (hi - lo), hi + padding * (hi - lo) def density(records): # a Gaussian kernel density of the (flipper length, body mass) points surface = kde2d( [length for record in records for length in record["flipper_length"]], [mass for record in records for mass in record["body_mass"]], gridsize=80, xlim=padded_range(ALL_LENGTHS), ylim=padded_range(ALL_MASSES), ) # per mm of flipper length and kg of body mass surface["z"] = (np.array(surface["z"]) * 1000).tolist() return surface # one surface per species: what a KDE chart draws species_density = [ density([p for p in PENGUINS if p["species"] == species]) for species in SPECIES ] # every penguin as a point penguin_points = [ {"x": length, "y": mass} for record in PENGUINS for length, mass in zip(record["flipper_length"], record["body_mass"]) ] ``` ``` ContourChart( # use a list of surfaces to define multiple contour charts data=species_density, # one legend label per chart subtitle=SPECIES, show_legend=True, # the same number of levels on every surface levels=5, title="Palmer penguins by species", xlabel="Flipper length (mm)", ylabel="Body mass (g)", figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` ### Subplots and shared axes To draw each surface in its own subplot, add the `subplots` attribute. The `subtitle` becomes the subplot title and the `title`, `xlabel` and `ylabel` are positioned to be global for all charts. The `max_cols` attribute limits the number of columns, and `sharex` and `sharey` share an axis across the subplots; a shared axis is labeled once, on the outer subplots only. Per-chart attributes like `subtitle`, `style`, `valfmt`, `norm`, `vmin`, `vmax` and `colorbar` can be passed as lists, where each element corresponds to a chart; a single value applies to every chart. ``` ContourChart( data=species_density, subtitle=SPECIES, # one filled subplot per species filled=True, subplots=True, max_cols=3, # the same axes for every species sharex=True, sharey=True, title="Palmer penguins by species", xlabel="Flipper length (mm)", ylabel="Body mass (g)", figsize=FIG_SIZE.FULL_SHORT, ).show() ``` ### Emphasis To draw attention to one surface among several, add the `emphasis` attribute. The `emphasis` list aligns with the charts of one call, and each entry is one of the following roles: | Role | Description | | -------------- | ------------------------------------------------------------------------------------------------------ | | `"background"` | Mutes the iso-lines into the theme's muted color and alpha, behind the others, without a legend entry. | | `"highlight"` | Bolds the iso-lines and brings them to the front. | | `None` | Leaves the chart unchanged. | A single value applies to every chart. Emphasis mutes and bolds lines, so it applies to iso-lines only; a filled contour takes the colormap and raises a `ValueError` when `emphasis` is passed. The [datachart.constants.EMPHASIS](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.EMPHASIS) constant holds the roles; the [highlighting guide](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/styling/highlighting.ipynb) covers emphasis across chart types and themes. ``` from datachart.constants import EMPHASIS ``` ``` ContourChart( data=species_density, subtitle=SPECIES, # one role per chart: Adelie, Chinstrap, Gentoo emphasis=[EMPHASIS.BACKGROUND, EMPHASIS.BACKGROUND, EMPHASIS.HIGHLIGHT], show_legend=True, levels=5, title="Palmer penguins by species", xlabel="Flipper length (mm)", ylabel="Body mass (g)", figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` ## Composing contours A contour figure composes like any other chart. [datachart.utils.Panel](https://eriknovak.github.io/datachart/0.9.0/references/utils/#datachart.utils.Panel) overlays it with other charts on shared axes — the natural pairing is a [datachart.charts.ScatterChart](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.ScatterChart) of the points behind a density, so the iso-lines show where the points concentrate. Every contour takes the next color of the panel's cycle, so the species stay distinct from the points. ``` from datachart.charts import ScatterChart from datachart.utils import Panel Panel( [ ScatterChart(data=penguin_points, subtitle="Penguins"), # the species densities, as iso-lines over the points ContourChart(data=species_density, subtitle=SPECIES, levels=4), ], title="Palmer penguins", xlabel="Flipper length (mm)", ylabel_left="Body mass (g)", show_legend=True, figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` [datachart.utils.Grid](https://eriknovak.github.io/datachart/0.9.0/references/utils/#datachart.utils.Grid) arranges contour figures next to other figures. A filled contour of the Himmelblau function spans the top row; the species densities sit below it, next to the labeled iso-lines of the same function. ``` from datachart.utils import Grid Grid( [ [ContourChart(data=chart_data, filled=True, show_colorbars=True, title="Himmelblau function")], [ ContourChart(data=species_density, subtitle=SPECIES, levels=5, show_legend=True, title="Palmer penguins"), ContourChart(data=chart_data, show_labels=True, valfmt=VALUE_FORMAT.INTEGER, title="Himmelblau levels"), ], ], figsize=FIG_SIZE.FULL_TALL, ).show() ``` ## Additional Features ### Aspect ratio By default the axes stretch to fill the figure, so a square grid may draw as a rectangle. To keep one unit equal on both axes, add the `aspect_ratio` attribute with a value of the [datachart.constants.ASPECT_RATIO](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.ASPECT_RATIO) constant — on a surface whose axes share a unit, like the Himmelblau function, the loops around the minima then keep their true shape. ``` from datachart.constants import ASPECT_RATIO ``` ``` ContourChart( data=chart_data, # keep one unit equal on both axes aspect_ratio=ASPECT_RATIO.EQUAL, levels=[2, 10, 30, 60, 100, 150, 250, 400, 600], title="Himmelblau function", xlabel="x", ylabel="y", figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` ### Reference lines A reference line marks a position on the surface. To add vertical lines, add the `vlines` attribute with the [datachart.typings.VLinePlotAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.VLinePlotAttrs) typing, which is either a `dict` or a `List[dict]`; horizontal lines use `hlines` and the [datachart.typings.HLinePlotAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.HLinePlotAttrs) typing. Here the lines cross at the minimum of the Himmelblau function at (3, 2). ``` ContourChart( data=chart_data, # cross-hairs on the minimum at (3, 2) vlines={"x": 3, "style": {"plot_vline_style": LINE_STYLE.DASHED}}, hlines={"y": 2, "style": {"plot_hline_style": LINE_STYLE.DASHED}}, levels=[2, 10, 30, 60, 100, 150, 250, 400, 600], title="Himmelblau function", xlabel="x", ylabel="y", figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` ### Density of scattered points A contour chart of a density is the two-dimensional counterpart of a histogram: it shows where scattered points concentrate. [datachart.utils.stats.kde2d](https://eriknovak.github.io/datachart/0.9.0/references/utils/stats/#datachart.utils.stats.kde2d) estimates that density with a Gaussian kernel and returns the `{x, y, z}` surface `ContourChart` takes, so there is no separate density chart — `ContourChart(kde2d(x, y))` is it. The `bandwidth` sets how smooth the estimate is: a [datachart.constants.BANDWIDTH](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.BANDWIDTH) rule (Scott's by default) or a scalar factor that replaces the rule, where smaller values follow the points more closely. The grid extends past the points by `cut` bandwidths, so the outer contours close instead of being clipped; `xlim` and `ylim` fix the grid instead, so several surfaces share one — the per-species densities of this guide are all evaluated over the range of every penguin, padded by 10%, so they line up in subplots. Here the density of all 342 penguins over their flipper length and body mass is drawn as filled bands, with a colorbar for the density; the [Composing contours](#composing-contours) section overlays the per-species densities on the points themselves. ``` from datachart.utils.stats import kde2d ``` ``` ContourChart( # the density of the penguins over flipper length and body mass data=kde2d( [point["x"] for point in penguin_points], [point["y"] for point in penguin_points], ), filled=True, show_colorbars=True, levels=8, title="Density of the Palmer penguins", xlabel="Flipper length (mm)", ylabel="Body mass (g)", figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` ## Saving the Chart as an Image To save the chart as an image, use the [datachart.utils.save_figure](https://eriknovak.github.io/datachart/0.9.0/references/utils#datachart.utils.save_figure) function. ``` from datachart.utils import save_figure figure = ContourChart( data=chart_data, filled=True, show_colorbars=True, title="Himmelblau function", xlabel="x", ylabel="y", figsize=FIG_SIZE.FULL_MEDIUM, ) save_figure(figure, "./fig_contour_chart.png", dpi=300) ``` The figure should be saved in the current working directory. ## Real-World Examples The following examples put the features above to work on real or realistic data. Each one states what its data is and where it comes from; the data itself lives in a hidden cell. ### Example 1: Optimizer Path on a Loss Landscape (Log Surface, Labels, and Panel) `rosenbrock` samples the [Rosenbrock function](https://en.wikipedia.org/wiki/Rosenbrock_function), the standard test surface for optimizers: a long, curved, flat-bottomed valley with the minimum at (1, 1), which gradient methods find easily but converge along slowly. Its values span six orders of magnitude, so the surface is drawn as `log(1 + z)` — the log keeps the valley floor visible where the raw values would flatten everything but the rim. `descent` traces 2,000 steps of plain gradient descent from (−1.5, 2.5), computed in the hidden cell, every 40th step kept as a point: the path drops into the valley within a few steps, then crawls along its floor toward the minimum. A `Panel` overlays the path, a `LineChart` with markers, on the labeled iso-lines — pinned to the primary axis with `y_axis`, as the panel would otherwise put the narrow path on a secondary value axis; the levels follow the Freedman–Diaconis rule, denser than the default, so the narrow valley gets its own lines. ``` from datachart.charts import LineChart Panel( [ ContourChart( data=rosenbrock, subtitle="log(1 + Rosenbrock)", levels=CONTOUR_LEVELS.FD, show_labels=True, valfmt=VALUE_FORMAT.DECIMAL, ), { "figure": LineChart( data=descent, subtitle="Gradient descent", style={"plot_line_marker": "o", "plot_line_width": 1.2}, ), # the path shares the surface's axes "y_axis": "left", }, ], title="Gradient descent on the Rosenbrock function", xlabel="x", ylabel_left="y", show_legend=True, figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` ### Example 2: Where the Species Overlap (Filled Subplots, Shared Levels, and Colorbars) `species_density` from the multiple-charts section holds the density of each penguin species over flipper length and body mass. Drawn as filled subplots that share one explicit `levels` list — every chart is cut at the same values, so the same shade means the same density — the species are comparable: Gentoo penguins are heavier and longer-flippered than the other two, whose densities overlap almost entirely. A colorbar on each chart maps the shades back to the density, and `sharex` and `sharey` label the shared axes once. ``` ContourChart( data=species_density, subtitle=SPECIES, filled=True, subplots=True, max_cols=3, sharex=True, sharey=True, # the same levels on every chart, so the shades are comparable levels=[0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08], show_colorbars=True, style={"plot_contour_cmap": COLORS.YlGnBu}, title="Density of the Palmer penguins by species", xlabel="Flipper length (mm)", ylabel="Body mass (g)", figsize=FIG_SIZE.FULL_SHORT, ).show() ``` # Hexbin Chart This section showcases the hexbin chart. It contains examples of how to create hexbin charts using the [datachart.charts.HexbinChart](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.HexbinChart) function. Looking for a specific customization? Jump straight to the [quick reference](#customizing-the-hexbin-chart), which maps common tasks to the parameter or style attribute that does the job. As mentioned above, the hexbin charts are created using the `HexbinChart` function found in the [datachart.charts](https://eriknovak.github.io/datachart/0.9.0/references/charts/index.md) module. Let's import it: ``` from datachart.charts import HexbinChart ``` ## Hexbin Chart Input Attributes The `HexbinChart` function accepts keyword arguments for chart configuration. The main argument is `data`, which contains the points to bin. For a single hexbin chart, `data` is a dictionary with the `x` and `y` columns and an optional `c` column of per-point values; for multiple hexbin charts, `data` is a list of such dictionaries. ``` HexbinChart( data={ # The points to bin (or list of them for multiple charts) "x": List[Union[int, float]], # The x values of the points "y": List[Union[int, float]], # The y values of the points, one per x "c": Optional[List[Union[int, float]]], # The value of each point; when given, the hexagons show its aggregate instead of the count }, style={ # The style of the hexbin chart (optional) "plot_hexbin_cmap": Optional[Union[str, List[str]]], # The colormap of the hexagons (the heatmap colormap by default) "plot_hexbin_alpha": Optional[float], # The alpha of the hexagons "plot_hexbin_edge_width": Optional[Union[int, float]], # The width of the hexagon edges (0, no edges, by default) "plot_hexbin_edge_color": Optional[str], # The color of the hexagon edges "plot_hexbin_gridsize": Optional[int], # The number of hexagons across the x-axis when gridsize is not set }, title: Optional[str], # The title of the chart xlabel: Optional[str], # The x-axis label ylabel: Optional[str], # The y-axis label subtitle: Optional[Union[str, List[str]]], # The subtitle(s) of the charts figsize: Optional[Tuple[float, float]], # The size of the figure xmin: Optional[Union[int, float]], # The minimum x-axis value xmax: Optional[Union[int, float]], # The maximum x-axis value ymin: Optional[Union[int, float]], # The minimum y-axis value ymax: Optional[Union[int, float]], # The maximum y-axis value show_grid: Optional[str], # Which grid lines to show ("both", "x", "y"); off by default show_colorbars: Optional[bool], # Whether to show the colorbar(s); on by default aspect_ratio: Optional[str], # The aspect ratio of the axes ("auto", "equal") scalex: Optional[str], # The x-axis scale ("linear", "log", ...) scaley: Optional[str], # The y-axis scale ("linear", "log", ...) subplots: Optional[bool], # Whether to create a separate subplot for each chart max_cols: Optional[int], # The maximum number of columns in the subplots sharex: Optional[bool], # Whether to share the x-axis across the subplots sharey: Optional[bool], # Whether to share the y-axis across the subplots gridsize: Optional[Union[int, List[int]]], # The number of hexagons across the x-axis (30 by default) reduce: Optional[Union[str, List[str]]], # How the c values in a hexagon collapse into its color ("mean", "sum", "median", "min", "max") mincnt: Optional[Union[int, List[int]]], # The point count below which a hexagon stays blank norm: Optional[Union[str, List[str]]], # The value normalization of the colormap vmin: Optional[Union[float, List[float]]], # The minimum value of the colormap range vmax: Optional[Union[float, List[float]]], # The maximum value of the colormap range valfmt: Optional[Union[str, List[str]]], # The format of the colorbar tick labels (e.g. "{x:.0f}") xticks: Optional[List[Union[int, float]]], # The x-axis tick positions xticklabels: Optional[List[str]], # The x-axis tick labels xtickrotate: Optional[int], # The rotation of the x-axis tick labels yticks: Optional[List[Union[int, float]]], # The y-axis tick positions yticklabels: Optional[List[str]], # The y-axis tick labels ytickrotate: Optional[int], # The rotation of the y-axis tick labels vlines: Optional[Union[dict, List[dict]]], # The vertical reference lines hlines: Optional[Union[dict, List[dict]]], # The horizontal reference lines colorbar: Optional[Union[dict, List[dict]]], # The colorbar configuration(s) ({"orientation": ...}) texts: Optional[Union[dict, List[dict]]], # The text annotations ) ``` For more details, see the [datachart.charts.HexbinChart](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.HexbinChart) function. ## Basics The examples in this guide share one dataset: 8,000 apartment listings of a mid-sized city — the floor area of each apartment, its monthly rent, and the number of days it stayed on the market. The listings are simulated in the hidden cell below from the shape real rental markets have: floor areas cluster around 60 m² with a long tail of large apartments, the rent grows with the area at a rate that varies by district, and small, cheap apartments go fastest. Eight thousand points are far too many for a scatter chart to show anything but a blob; the hexbin chart bins them. The data is a dictionary of columns: `x` holds the floor area of every listing, `y` its rent, and `c` its days on the market — one value per listing in each column. A `c` column switches the hexagons from counting the points to aggregating its values, so the hidden cell also keeps `points`, the `x` and `y` columns alone, for the charts that count: ``` {key: values[:5] for key, values in listings.items()} ``` **Basic example.** Only the `data` argument is required to draw the hexbin chart. The plane is tiled with hexagons and every hexagon is colored by the number of listings falling in it, with a colorbar mapping the colors back to counts. Every hexagon of the tiling is drawn, the empty ones at the lowest color, so a single far-off listing — one large, expensive apartment here — stretches the tiling over a lot of blank plane; the [Minimum count](#minimum-count) section trims it. ``` HexbinChart( # add the data to the chart data=points ).show() ``` ## Customizing the Hexbin Chart Every customization is either a keyword argument of `HexbinChart` or a `plot_hexbin_*` attribute of its `style` dictionary. The table maps common tasks to the one you need and links to the subsection that shows it. | I want to… | Use | See | | ------------------------------------------ | ---------------------------------------------------------------- | ------------------------------------------------- | | add a title and axis labels | `title`, `xlabel`, `ylabel` | [Title and axis labels](#title-and-axis-labels) | | resize the figure | `figsize` | [Figure size and grid](#figure-size-and-grid) | | show the grid lines | `show_grid` | [Figure size and grid](#figure-size-and-grid) | | hide or reorient the colorbar | `show_colorbars=False`, `colorbar={"orientation": ...}` | [Colorbar](#colorbar) | | make the hexagons larger or smaller | `gridsize` | [Grid size](#grid-size) | | leave the sparse hexagons blank | `mincnt` | [Minimum count](#minimum-count) | | spread heavy-tailed counts over the colors | `norm`, `vmin`, `vmax` | [Normalization](#normalization) | | color the hexagons by a value | `data={"c": ...}`, `reduce` | [Aggregating a value](#aggregating-a-value) | | change the colormap or draw hexagon edges | `style={"plot_hexbin_cmap": ..., "plot_hexbin_edge_width": ...}` | [Hexagon style](#hexagon-style) | | draw each dataset in its own subplot | `subplots=True`, `max_cols`, `sharex`, `sharey` | [Multiple Hexbin Charts](#multiple-hexbin-charts) | | draw points or lines over the hexagons | `Panel` | [Composing hexbins](#composing-hexbins) | | keep one unit equal on both axes | `aspect_ratio` | [Aspect ratio](#aspect-ratio) | | mark a position with a reference line | `vlines`, `hlines` | [Reference lines](#reference-lines) | | render the chart in another theme | `config.set_theme` | [Themes](#themes) | ### Title and axis labels To add the chart title and axis labels, add the `title`, `xlabel` and `ylabel` attributes. ``` HexbinChart( data=points, # add the title title="Apartment listings", # add the x and y axis labels xlabel="Floor area (m²)", ylabel="Rent (€/month)", ).show() ``` ### Figure size and grid To change the figure size, add the `figsize` attribute. The `figsize` attribute can be a tuple (width, height), values are in inches. The `datachart` package provides a [datachart.constants.FIG_SIZE](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.FIG_SIZE) constant, which contains predefined figure sizes. The grid is off by default, as the hexagons would cover it; to show it anyway, add the `show_grid` attribute, which supports the values of the [datachart.constants.SHOW_GRID](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.SHOW_GRID) constant — the grid lines draw over the hexagons. ``` from datachart.constants import FIG_SIZE, SHOW_GRID ``` ``` HexbinChart( data=points, title="Apartment listings", xlabel="Floor area (m²)", ylabel="Rent (€/month)", # add to determine the figure size figsize=FIG_SIZE.FULL_SHORT, # add to show the grid lines on both axes show_grid=SHOW_GRID.BOTH, ).show() ``` ### Colorbar The colorbar maps the hexagon colors back to their values and is drawn to the right of the chart by default. To hide it, set the `show_colorbars` attribute to `False`; to draw it horizontally instead, add the `colorbar` attribute with the [datachart.typings.HeatmapColorbarAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.HeatmapColorbarAttrs) typing, whose `orientation` takes a value of the [datachart.constants.ORIENTATION](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.ORIENTATION) constant. The `valfmt` attribute formats its tick labels with a format string with the value named `x`; the [datachart.constants.VALUE_FORMAT](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.VALUE_FORMAT) constant holds the common ones. ``` from datachart.constants import ORIENTATION, VALUE_FORMAT ``` ``` HexbinChart( data=points, # draw the colorbar above the chart, with integer ticks colorbar={"orientation": ORIENTATION.HORIZONTAL}, valfmt=VALUE_FORMAT.INTEGER, title="Apartment listings", xlabel="Floor area (m²)", ylabel="Rent (€/month)", figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` ### Grid size The `gridsize` attribute sets how many hexagons tile the x-axis — 30 by default, from the `plot_hexbin_gridsize` config value. Fewer hexagons are larger and hold more points each, so the colors are smoother but the shape coarser; more hexagons resolve finer structure until they hold too few points to color reliably. ``` HexbinChart( data=points, # twelve large hexagons across the x-axis gridsize=12, title="Apartment listings", xlabel="Floor area (m²)", ylabel="Rent (€/month)", figsize=FIG_SIZE.FULL_SHORT, ).show() ``` ### Minimum count Every hexagon of the tiling is drawn by default, including the empty ones at the lowest color, so the tiling fills the bounding box of the points. To leave the sparse hexagons blank, add the `mincnt` attribute: a hexagon is drawn only when at least that many points fall in it, which trims the tiling down to where the listings actually are. ``` HexbinChart( data=points, # blank hexagons with fewer than five listings mincnt=5, title="Apartment listings", xlabel="Floor area (m²)", ylabel="Rent (€/month)", figsize=FIG_SIZE.FULL_SHORT, ).show() ``` ### Normalization The colors come from a two-step mapping: the hexagon values are first normalized to the 0–1 range, then each normalized value picks its color from the colormap. Counts are heavy-tailed — a few hexagons in the densest cluster hold dozens of listings while most hold a handful — so on the linear default nearly every hexagon draws in the palest shades. The `norm` attribute changes the normalization; the [datachart.constants.NORMALIZE](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.NORMALIZE) constant holds the supported values, and `NORMALIZE.LOG` spreads the counts so the tail of the distribution is visible. A log scale needs positive values, so pair it with `mincnt=1` to leave the empty hexagons out. The `vmin` and `vmax` attributes pin the range instead of taking it from the data. ``` from datachart.constants import NORMALIZE ``` ``` HexbinChart( data=points, # log-scaled counts, so the sparse tail stays visible norm=NORMALIZE.LOG, mincnt=1, title="Apartment listings", xlabel="Floor area (m²)", ylabel="Rent (€/month)", figsize=FIG_SIZE.FULL_SHORT, ).show() ``` ### Aggregating a value With a `c` column in the data, the hexagons show an aggregate of the `c` values of their points instead of the point count. The `reduce` attribute picks the aggregate with a value of the [datachart.constants.HEXBIN_REDUCE](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.HEXBIN_REDUCE) constant — the mean by default, or the sum, median, minimum, or maximum. Only the hexagons holding at least one point are drawn, as an empty hexagon has nothing to aggregate. Here `c` is the number of days a listing stayed on the market, so the chart below shows how long the apartments of every size and price took to rent: the mean rises with the floor area and, at every area, with the rent. A diverging colormap suits a value with a natural middle; the [Hexagon style](#hexagon-style) section shows how to set it. ``` from datachart.constants import HEXBIN_REDUCE ``` ``` HexbinChart( # x, y, and the per-point c to aggregate data=listings, # the mean of the c values in every hexagon reduce=HEXBIN_REDUCE.MEAN, # aggregates of a few points are noisy; blank the sparse hexagons mincnt=3, title="Days on the market", xlabel="Floor area (m²)", ylabel="Rent (€/month)", figsize=FIG_SIZE.FULL_SHORT, ).show() ``` The other aggregates answer other questions. The maximum finds the listings that stayed longest — the outliers — where the mean smooths them away: ``` HexbinChart( data=listings, # the longest-listed apartment in every hexagon reduce=HEXBIN_REDUCE.MAX, mincnt=3, title="Longest time on the market", xlabel="Floor area (m²)", ylabel="Rent (€/month)", figsize=FIG_SIZE.FULL_SHORT, ).show() ``` ### Hexagon style To change the hexagon style, add the `style` attribute with the corresponding attributes. The supported attributes are shown in the [datachart.typings.HexbinStyleAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.HexbinStyleAttrs) typing. The `plot_hexbin_cmap` attribute sets the colormap — the heatmap colormap by default — from the [datachart.constants.COLORS](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.COLORS) constant or a list of colors; `plot_hexbin_edge_width` and `plot_hexbin_edge_color` draw an edge around every hexagon, which separates the tiles where the colors run together. ``` from datachart.constants import COLORS ``` ``` HexbinChart( data=listings, reduce=HEXBIN_REDUCE.MEAN, mincnt=3, # define the style of the hexagons style={ "plot_hexbin_cmap": COLORS.RdBu, "plot_hexbin_edge_width": 0.6, "plot_hexbin_edge_color": "#FFFFFF", }, gridsize=20, title="Days on the market", xlabel="Floor area (m²)", ylabel="Rent (€/month)", figsize=FIG_SIZE.FULL_SHORT, ).show() ``` !!! note "No emphasis" ``` A hexbin chart is a single colormapped layer, so it does not take the `emphasis` attribute of the series charts: there is no series color to mute or highlight. To draw attention to a region, overlay a marker or a reference line instead (see [Composing hexbins](#composing-hexbins) and [Reference lines](#reference-lines)). ``` ## Multiple Hexbin Charts To create multiple hexbin charts, pass a list of datasets to the `data` argument and add the `subplots` attribute to draw each in its own subplot. Hexagons are opaque, so several datasets on one axes would hide each other; subplots keep them comparable. The `subtitle` becomes the subplot title and the `title`, `xlabel` and `ylabel` are positioned to be global for all charts. The `max_cols` attribute limits the number of columns, and `sharex` and `sharey` share an axis across the subplots; a shared axis is labeled once, on the outer subplots only. Per-chart attributes like `subtitle`, `style`, `gridsize`, `reduce`, `mincnt`, `norm`, `vmin`, `vmax`, `valfmt` and `colorbar` can be passed as lists, where each element corresponds to a chart; a single value applies to every chart. The listings split by district in the hidden cell, as `by_district` (with `c`) and `points_by_district` (without): the three per-m² rates of the simulation stand in for a cheap, a mid-priced, and an expensive district. ``` HexbinChart( # use a list of datasets to define multiple hexbin charts data=points_by_district, # one subplot title per chart subtitle=DISTRICTS, subplots=True, max_cols=3, # the same axes for every district sharex=True, sharey=True, # the same color range on every chart, so the shades are comparable vmin=0, vmax=60, mincnt=1, gridsize=20, title="Apartment listings by district", xlabel="Floor area (m²)", ylabel="Rent (€/month)", figsize=(12, 4), ).show() ``` ## Composing hexbins A hexbin figure composes like any other chart. [datachart.utils.Panel](https://eriknovak.github.io/datachart/0.9.0/references/utils/#datachart.utils.Panel) overlays it with other charts on shared axes — the natural pairing is a [datachart.charts.ScatterChart](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.ScatterChart) of a few points of interest drawn over the density of all of them, or a [datachart.charts.LineChart](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.LineChart) of a fitted trend. Here a random sample of 60 listings sits on the hexagons, with white edges so the tiles read under the points; the hexbin's colorbar is left off, as the panel's legend labels the points. ``` from datachart.charts import ScatterChart from datachart.utils import Panel sample = rng.choice(N_LISTINGS, 60, replace=False) Panel( [ HexbinChart( data=points, style={"plot_hexbin_edge_width": 0.5, "plot_hexbin_edge_color": "#FFFFFF"}, show_colorbars=False, ), # a sample of the listings, as points over the hexagons ScatterChart( data=[{"x": listings["x"][i], "y": listings["y"][i]} for i in sample], subtitle="Sampled listings", ), ], title="Apartment listings", xlabel="Floor area (m²)", ylabel_left="Rent (€/month)", show_legend=True, figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` [datachart.utils.Grid](https://eriknovak.github.io/datachart/0.9.0/references/utils/#datachart.utils.Grid) arranges hexbin figures next to other figures. The count of the listings spans the top row; the days on the market and a histogram of the rents share the bottom one. ``` from datachart.charts import Histogram from datachart.utils import Grid Grid( [ [HexbinChart(data=points, mincnt=1, norm=NORMALIZE.LOG, title="Listings")], [ HexbinChart( data=listings, reduce=HEXBIN_REDUCE.MEAN, mincnt=3, title="Days on the market", ), Histogram( data=[{"x": value} for value in listings["y"]], title="Rent (€/month)", ), ], ], figsize=(10, 7), ).show() ``` ## Additional Features ### Aspect ratio By default the axes stretch to fill the figure, so the hexagons are regular on the screen but the two axes have different scales. When both axes share a unit — two coordinates, two scores on the same scale — add the `aspect_ratio` attribute with a value of the [datachart.constants.ASPECT_RATIO](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.ASPECT_RATIO) constant to keep one unit equal on both. The hidden cell scales the listings to z-scores, so both axes read in standard deviations. ``` from datachart.constants import ASPECT_RATIO ``` ``` HexbinChart( data=standardized, # keep one unit equal on both axes aspect_ratio=ASPECT_RATIO.EQUAL, mincnt=1, title="Apartment listings (standardized)", xlabel="Floor area (z-score)", ylabel="Rent (z-score)", figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` ### Reference lines A reference line marks a position on the plane. To add vertical lines, add the `vlines` attribute with the [datachart.typings.VLinePlotAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.VLinePlotAttrs) typing; for horizontal lines, add the `hlines` attribute with the [datachart.typings.HLinePlotAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.HLinePlotAttrs) typing. The lines below mark the median floor area and rent, which split the listings into four quadrants. ``` from datachart.constants import LINE_STYLE ``` ``` HexbinChart( data=points, # the median area and rent, as dashed cross-hairs vlines={ "x": float(np.median(listings["x"])), "label": "Median area", "style": {"plot_vline_style": LINE_STYLE.DASHED}, }, hlines={ "y": float(np.median(listings["y"])), "label": "Median rent", "style": {"plot_hline_style": LINE_STYLE.DASHED}, }, mincnt=1, title="Apartment listings", xlabel="Floor area (m²)", ylabel="Rent (€/month)", figsize=FIG_SIZE.FULL_SHORT, ).show() ``` ### Themes A theme sets the colormap and the furniture of every chart at once; see the [Theme Gallery](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/styling/theme-gallery.ipynb) for the whole suite under each. Apply one with [datachart.config.Config.set_theme](https://eriknovak.github.io/datachart/0.9.0/references/config/#datachart.config.Config.set_theme) from the [datachart.constants.THEME](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.THEME) constant, and reset the configuration afterwards so the following charts draw in the default. ``` from datachart.config import config from datachart.constants import THEME config.set_theme(THEME.INK) figure = HexbinChart( data=points, mincnt=1, title="Apartment listings", xlabel="Floor area (m²)", ylabel="Rent (€/month)", figsize=FIG_SIZE.FULL_SHORT, ) config.reset_config() figure.show() ``` ## Saving the Chart as an Image To save the chart as an image, use the [datachart.utils.save_figure](https://eriknovak.github.io/datachart/0.9.0/references/utils#datachart.utils.save_figure) function. ``` from datachart.utils import save_figure figure = HexbinChart( data=points, mincnt=1, norm=NORMALIZE.LOG, title="Apartment listings", xlabel="Floor area (m²)", ylabel="Rent (€/month)", figsize=FIG_SIZE.FULL_MEDIUM, ) save_figure(figure, "./fig_hexbin_chart.png", dpi=300) ``` The figure should be saved in the current working directory. ## Real-World Examples The following examples put the features above to work on realistic data. Each one states what its data is and where it comes from; the data itself lives in a hidden cell. ### Example 1: Price per Square Meter Across the City (Aggregation, Diverging Colors, and a Trend) `listings` from the sections above holds the area, rent, and days on the market of 8,000 apartments. The hidden cell derives the rent per square meter of every listing — the number a renter compares across sizes — and a linear fit of the rent on the area. Colored by the mean rent per square meter, the hexagons show what the counts hide: at every floor area the listings stack into three bands, one per district rate, and the expensive band grows thinner toward the large apartments. A diverging colormap centered on the city-wide mean by `vmin` and `vmax` splits the plane into the cheaper-than-average blues and the pricier reds, and the `Panel` lays the fitted rent over the tiles, pinned to the primary axis with `y_axis`. ``` from datachart.charts import LineChart Panel( [ HexbinChart( data={"x": listings["x"], "y": listings["y"], "c": per_m2}, reduce=HEXBIN_REDUCE.MEAN, mincnt=3, # a diverging colormap centered on the city-wide mean; the "_r" # suffix reverses it, so the cheap side is blue style={"plot_hexbin_cmap": "RdBu_r"}, vmin=CITY_MEAN - 5, vmax=CITY_MEAN + 5, valfmt="{x:.0f} €/m²", gridsize=24, ), { "figure": LineChart( data=fit, subtitle=f"Fitted rent ({slope:.1f} €/m² + {intercept:.0f} €)", style={"plot_line_color": "#1F1F1F", "plot_line_style": LINE_STYLE.DASHED}, ), # the fit shares the hexbin's axes "y_axis": "left", }, ], title="Rent per square meter", xlabel="Floor area (m²)", ylabel_left="Rent (€/month)", show_legend=True, figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` ### Example 2: Which Apartments Rent Fastest, by District (Subplots, Shared Range, and Log Counts) `by_district` from the multiple-charts section splits the listings into the three districts. The top row counts the listings of every district on a log scale, so the sparse edges of the cheaper districts stay visible next to their dense cores; the bottom row shows the mean days on the market under one shared `vmin`/`vmax`, so the same shade means the same wait in every district. Read down a column: the center's apartments are fewer, pricier, and slower to rent at every size, while the outskirts turn over their small apartments within a couple of weeks. The two `HexbinChart` figures, each a row of subplots, stack as the two rows of a `Grid`. ``` Grid( [ [ HexbinChart( data=points_by_district, subtitle=DISTRICTS, subplots=True, max_cols=3, sharex=True, sharey=True, norm=NORMALIZE.LOG, mincnt=1, gridsize=18, title="Listings (log count)", ) ], [ HexbinChart( data=by_district, subtitle=DISTRICTS, subplots=True, max_cols=3, sharex=True, sharey=True, reduce=HEXBIN_REDUCE.MEAN, mincnt=3, # the same range on every chart, so the shades are comparable vmin=10, vmax=50, gridsize=18, style={"plot_hexbin_cmap": COLORS.YlOrRd}, title="Days on the market (mean)", ) ], ], xlabel="Floor area (m²)", ylabel="Rent (€/month)", figsize=(12, 8), ).show() ``` # Sankey Chart This section showcases the Sankey chart. It contains examples of how to create Sankey charts using the [datachart.charts.SankeyChart](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.SankeyChart) function. Looking for a specific customization? Jump straight to the [quick reference](#customizing-the-sankey-chart), which maps common tasks to the parameter or style attribute that does the job. As mentioned above, the Sankey charts are created using the `SankeyChart` function found in the [datachart.charts](https://eriknovak.github.io/datachart/0.9.0/references/charts/index.md) module. Let's import it: ``` from datachart.charts import SankeyChart ``` ## Sankey Chart Input Attributes The `SankeyChart` function accepts keyword arguments for chart configuration. The main argument is `data`, which contains the flows to draw. A Sankey is a `{"links": [...]}` dict whose links are `{"source", "target", "value"}` records; a node is the string that names it, which is also its drawn label. A list of such dicts draws one Sankey per subplot. ``` SankeyChart( data={ # The flows (or a list of such dicts, one Sankey per subplot) "links": [ { "source": str, # The node the flow leaves "target": str, # The node the flow enters "value": Union[int, float], # The size of the flow; must be greater than 0 }, ... ], }, nodes=Optional[List[List[str]]], # The node columns left to right, each top to bottom (inferred by default) column_labels=Optional[List[str]], # One heading per column show_values=Optional[bool], # Whether to write each flow's value on its ribbon value_format=Optional[str], # The format of the ribbon values, a VALUE_FORMAT constant or a format string style={ # The style of the chart (optional; a list for multiple charts) "plot_sankey_node_width": Optional[float], # The node bar width as a fraction of the horizontal span (0.04 by default) "plot_sankey_node_pad": Optional[float], # The vertical span shared by the gaps of the tallest column (0.1 by default) "plot_sankey_node_edge_color": Optional[str], # The node stroke color "plot_sankey_node_edge_width": Optional[float], # The node stroke width "plot_sankey_link_color": Optional[str], # Which node colors a ribbon: "source" (default), "target", or "grey" "plot_sankey_link_alpha": Optional[float], # The ribbon alpha (0.4 by default) "plot_sankey_label_halo_width": Optional[float], # The white halo behind the labels; 0 disables it (2 by default) }, subtitle=Optional[str], # The chart subtitle (or list for multiple charts) title=Optional[str], # The chart title figsize=Optional[Tuple[float, float]], # The figure size subplots=Optional[bool], # Whether to draw each chart in its own subplot max_cols=Optional[int], # The maximum number of subplot columns texts=Optional[Union[dict, List[dict]]], # The text annotations ) ``` For more details, see the [datachart.charts.SankeyChart](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.SankeyChart) function. ## Basics The examples in this guide share one dataset: the 2,201 people aboard the Titanic, counted by class (first, second, third, or crew), sex, and whether they survived. The counts are the classic `Titanic` table shipped with R, with children and adults combined, and live in the hidden cell below. Survival is a textbook flow story: everyone starts in a class, passes through the sex column, and ends up survived or lost — and a Sankey chart shows where each group went. The data is one dict with a `links` list. Every link is a record with a `source` node, a `target` node, and the `value` that flows between them; the node names double as the labels: ``` titanic["links"][:3] + titanic["links"][-2:] ``` **Basic example.** Only the `data` argument is required to draw the Sankey chart. Each node's column is its longest path from any source — the classes on the left, the sexes in the middle, the outcomes on the right — and within a column the nodes keep the order they first appear in the links. A node's height is the larger of what flows in and what flows out, so the columns balance; the ribbons take the color of the node they leave. ``` SankeyChart( # add the data to the chart data=titanic ).show() ``` ## Customizing the Sankey Chart Every customization is either a keyword argument of `SankeyChart` or a `plot_*` attribute of its `style` dictionary. The table maps common tasks to the one you need and links to the subsection that shows it. | I want to… | Use | See | | ----------------------------------------- | -------------------------------------------------------------------- | ------------------------------------------------------------------- | | add a title | `title` | [Title and figure size](#title-and-figure-size) | | resize the figure | `figsize` | [Title and figure size](#title-and-figure-size) | | set the columns or reorder the nodes | `nodes` | [Node columns](#node-columns) | | head the columns | `column_labels` | [Column labels and ribbon values](#column-labels-and-ribbon-values) | | write the flow values on the ribbons | `show_values`, `value_format` | [Column labels and ribbon values](#column-labels-and-ribbon-values) | | change the node width, gaps, or stroke | `style={"plot_sankey_node_width": ..., "plot_sankey_node_pad": ...}` | [Node and ribbon style](#node-and-ribbon-style) | | color the ribbons by target, or grey them | `style={"plot_sankey_link_color": "target"}` | [Node and ribbon style](#node-and-ribbon-style) | | drop the halo behind the labels | `style={"plot_sankey_label_halo_width": 0}` | [Node and ribbon style](#node-and-ribbon-style) | | annotate a point of the chart | `texts` | [Text annotations](#text-annotations) | | draw several Sankeys side by side | `subplots` | [Subplots](#subplots) | | arrange a Sankey next to other charts | `Grid` | [Composing Sankeys](#composing-sankeys) | ### Title and figure size To add the chart title, add the `title` attribute. A Sankey has no axes, so there are no axis labels to set. To change the figure size, add the `figsize` attribute. The `figsize` attribute can be a tuple (width, height), values are in inches. The `datachart` package provides a [datachart.constants.FIG_SIZE](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.FIG_SIZE) constant, which contains predefined figure sizes. ``` from datachart.constants import FIG_SIZE ``` ``` SankeyChart( data=titanic, # add the title title="Survival on the Titanic", # add to determine the figure size figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` ### Node columns By default a node's column is its longest path from any source, and a node that stops early — a leaf reached in one hop — stays in the column it was reached in rather than being pushed to the right edge. To set the columns yourself, add the `nodes` attribute: a list of columns, left to right, each a list of node names top to bottom. It must name every node in the links exactly once, and it also fixes the vertical order, so it is the way to sort the nodes. The example puts the women above the men and the survivors above the lost, so the largest flows cross the least. ``` SankeyChart( data=titanic, # three columns; the order within each is top to bottom nodes=[ ["1st", "2nd", "3rd", "Crew"], ["Female", "Male"], ["Survived", "Lost"], ], title="Survival on the Titanic", figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` ### Column labels and ribbon values To head the columns, add the `column_labels` attribute with one label per column, left to right; the headings sit above the columns in the subtitle style. To write each flow's value on its ribbon, add the `show_values` attribute; the `value_format` attribute formats the values and supports the values of the [datachart.constants.VALUE_FORMAT](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.VALUE_FORMAT) constant or any `"{x:.1f}"`, `"{:.1f}%"`, or `"%g"` style string. Each value sits at the end of its ribbon, just before the node it flows into, behind the same halo as the labels; a ribbon too thin for its value slides it along the ribbon to the first clear spot. ``` from datachart.constants import VALUE_FORMAT ``` ``` SankeyChart( data=titanic, nodes=[["1st", "2nd", "3rd", "Crew"], ["Female", "Male"], ["Survived", "Lost"]], # head the three columns column_labels=["Class", "Sex", "Outcome"], # write the counts on the ribbons show_values=True, value_format=VALUE_FORMAT.THOUSANDS, title="Survival on the Titanic", figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` ### Node and ribbon style To change the node and ribbon style, add the `style` attribute with the corresponding attributes. The supported attributes are shown in the [datachart.typings.SankeyStyleAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.SankeyStyleAttrs) typing. `plot_sankey_node_width` is the width of the node bars and `plot_sankey_node_pad` the vertical room shared by the gaps of the tallest column, both as fractions of the drawing; `plot_sankey_node_edge_color` and `plot_sankey_node_edge_width` draw the stroke around every node. `plot_sankey_link_color` picks which node colors a ribbon: `"source"` (the default) traces where a flow comes from, `"target"` where it goes, and `"grey"` keeps the ribbons neutral so only the nodes carry color; `plot_sankey_link_alpha` is the ribbon alpha. The labels sit over the ribbons behind a white halo of `plot_sankey_label_halo_width`; set it to `0` to drop the halo. The example colors the ribbons by their target, so the two outcomes read across the whole chart, and widens the nodes. ``` SankeyChart( data=titanic, nodes=[["1st", "2nd", "3rd", "Crew"], ["Female", "Male"], ["Survived", "Lost"]], # ribbons in the color of the node they enter style={ "plot_sankey_link_color": "target", "plot_sankey_link_alpha": 0.5, "plot_sankey_node_width": 0.06, "plot_sankey_node_pad": 0.15, }, title="Survival on the Titanic", figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` ### Text annotations To place text on the chart, add the `texts` attribute with the [datachart.typings.TextAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.TextAttrs) typing. Each annotation sets its `text` and position; the Sankey spans `0`–`1` on both axes, with the columns spread across the horizontal span and the tallest column filling the vertical one, so axes fractions (`"coords": "axes"`) and data coordinates are nearly the same thing. The annotation below states the overall survival rate. ``` survived = sum(o["Survived"] for o in TITANIC.values()) total = sum(sum(o.values()) for o in TITANIC.values()) SankeyChart( data=titanic, nodes=[["1st", "2nd", "3rd", "Crew"], ["Female", "Male"], ["Survived", "Lost"]], # the overall survival rate, above the right column texts={ "text": f"{100 * survived / total:.0f}% survived", "x": 0.98, "y": 0.98, "coords": "axes", "style": {"plot_text_halign": "right"}, }, title="Survival on the Titanic", figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` ## Multiple Sankey Charts ### Subplots A list of Sankeys draws each in its own subplot; there is no overlay of two Sankeys on one axes, so `subplots` is implied. The `subtitle` becomes the subplot title and the `title` is positioned to be global for all charts. The `max_cols` attribute limits the number of columns. The example splits the flows by sex, so each Sankey shows the classes going straight to their outcome. ``` SankeyChart( # one Sankey per sex data=by_sex, subtitle=["Female", "Male"], max_cols=2, title="Survival on the Titanic by sex", figsize=(12, 4), ).show() ``` ### Composing Sankeys A Sankey owns its axes: there is no shared coordinate space to overlay other charts on, so [datachart.utils.Panel](https://eriknovak.github.io/datachart/0.9.0/references/utils/#datachart.utils.Panel) rejects a Sankey figure. [datachart.utils.Grid](https://eriknovak.github.io/datachart/0.9.0/references/utils/#datachart.utils.Grid) arranges it next to other figures as an ordinary cell. The grid pairs the Sankey with a [datachart.charts.BarChart](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.BarChart) of the survival rate per class. ``` from datachart.charts import BarChart from datachart.utils import Grid rates = {} for (cls, sex), outcomes in TITANIC.items(): counts = rates.setdefault(cls, [0, 0]) counts[0] += outcomes["Survived"] counts[1] += sum(outcomes.values()) flows = SankeyChart( data=titanic, nodes=[["1st", "2nd", "3rd", "Crew"], ["Female", "Male"], ["Survived", "Lost"]], title="Who survived", ) rate = BarChart( data=[{"label": cls, "y": 100 * s / n} for cls, (s, n) in rates.items()], title="Survival rate (%)", ymax=100, ) Grid([[flows, rate]], figsize=(12, 4)).show() ``` ### Themes A theme sets the palette, the node stroke and the fonts of every chart at once; see the [Theme Gallery](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/styling/theme-gallery.ipynb) for the whole suite under each. Apply one with [datachart.config.Config.set_theme](https://eriknovak.github.io/datachart/0.9.0/references/config/#datachart.config.Config.set_theme) from the [datachart.constants.THEME](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.THEME) constant, and reset the configuration afterwards so the following charts draw in the default again. ``` from datachart.config import config from datachart.constants import THEME config.set_theme(THEME.INK) figure = SankeyChart( data=titanic, nodes=[["1st", "2nd", "3rd", "Crew"], ["Female", "Male"], ["Survived", "Lost"]], title="Survival on the Titanic", figsize=FIG_SIZE.FULL_MEDIUM, ) config.reset_config() figure.show() ``` ## Saving the Chart as an Image To save the chart as an image, use the [datachart.utils.save_figure](https://eriknovak.github.io/datachart/0.9.0/references/utils#datachart.utils.save_figure) function. ``` from datachart.utils import save_figure figure = SankeyChart( data=titanic, nodes=[["1st", "2nd", "3rd", "Crew"], ["Female", "Male"], ["Survived", "Lost"]], title="Survival on the Titanic", ) save_figure(figure, "./fig_sankey_chart.png", dpi=300) ``` The figure should be saved in the current working directory. ## Real-World Examples The following examples put the features above to work. Each one states what it shows; any derived data lives in a hidden cell. ### Example 1: Label Agreement Between Annotators (Three Columns and Ribbons by Source) Two annotators labeled the same 150 sentences as positive, neutral, or negative, and an adjudicator settled the final label. The hidden cell holds the confusion counts. With the ribbons colored by source, the wide straight ribbons are the agreements and the thin crossing ones the disagreements — and the third column shows which annotator the adjudicator sided with. ``` SankeyChart( data=agreement, title="Label transitions from annotator A to B to the final label", figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` ### Example 2: A Signup Funnel (Explicit Columns, Grey Ribbons, and an Annotation) A thousand visitors either bounce or sign up; the signups activate or churn, and the activated ones pay or stay on the free tier. The hidden cell holds the counts. By default each drop-off would sit in the column where it happens; the explicit `nodes` keep that layout but put the drop-offs below the continuing flow at every stage, so the funnel narrows from the top. Grey ribbons leave the color to the nodes, and the annotation states the conversion. ``` SankeyChart( data=funnel, nodes=[["Visited"], ["Signed up", "Bounced"], ["Activated", "Churned"], ["Paid", "Free tier"]], style={"plot_sankey_link_color": "grey"}, texts={"text": "9% of visitors pay", "x": 0.98, "y": 0.02, "coords": "axes", "style": {"plot_text_halign": "right"}}, title="Signup funnel", figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` # Parallel Coordinates This section showcases the parallel coordinates chart. It contains examples of how to create parallel coordinates charts using the [datachart.charts.ParallelCoords](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.ParallelCoords) function. A parallel coordinates chart draws one vertical axis per variable and one line per data point, connecting its values across the axes. It shows many variables of many records at once, which makes it a natural fit for comparing groups in multivariate data — species of animals, models of cars, runs of a hyperparameter search. Looking for a specific customization? Jump straight to the [quick reference](#customizing-the-parallel-coordinates), which maps common tasks to the parameter or style attribute that does the job. As mentioned above, the parallel coordinates charts are created using the `ParallelCoords` function found in the [datachart.charts](https://eriknovak.github.io/datachart/0.9.0/references/charts/index.md) module. Let's import it: ``` from datachart.charts import ParallelCoords ``` ## Parallel Coordinates Input Attributes The `ParallelCoords` function accepts keyword arguments for chart configuration. The main argument is `data`, which contains the data points. Each data point is a dictionary whose keys are the dimension names and whose values are numeric or categorical (string). For a single chart, `data` is a list of data points; for multiple charts drawn on the same axes, `data` is a list of such lists. ``` ParallelCoords( data=[{ # A list of data points (or list of lists for multiple charts) "dim1": Union[int, float], # Numeric dimension "dim2": Union[int, float], # Numeric dimension "dim3": str, # Categorical dimension (string) # ... more dimensions }], style={ # The style of the chart (optional; or list for multiple charts) "plot_parallel_color": Optional[str], # The color of the lines (hex color code; overrides hue) "plot_parallel_alpha": Optional[float], # The alpha of the lines (how visible they are) "plot_parallel_width": Optional[float], # The width of the lines "plot_parallel_style": Optional[LINE_STYLE], # The line style (solid, dashed, etc.) "plot_parallel_marker": Optional[LINE_MARKER], # The marker drawn where a line crosses an axis "plot_parallel_zorder": Optional[int], # The draw order of the lines "plot_parallel_axis_color": Optional[str], # The color of the vertical axes (hex color code) "plot_parallel_axis_width": Optional[float], # The width of the vertical axes "plot_parallel_axis_zorder": Optional[int], # The draw order of the vertical axes "plot_parallel_tick_color": Optional[str], # The color of the tick marks (hex color code) "plot_parallel_tick_width": Optional[float], # The width of the tick marks "plot_parallel_tick_length": Optional[float], # The length of the tick marks (in axis spacings) "plot_parallel_tick_label_size": Optional[float], # The font size of the tick labels "plot_parallel_tick_label_color": Optional[str], # The font color of the tick labels (hex color code) "plot_parallel_tick_label_bg_color": Optional[str], # The background color of the tick labels (hex color code) "plot_parallel_tick_label_bg_alpha": Optional[float], # The background alpha of the tick labels "plot_parallel_dim_label_size": Optional[float], # The font size of the dimension labels "plot_parallel_dim_label_color": Optional[str], # The font color of the dimension labels (hex color code) "plot_parallel_dim_label_rotation": Optional[float], # The rotation of the dimension labels (degrees) "plot_parallel_dim_label_pad": Optional[float], # The padding between the axes and the dimension labels }, subtitle=Optional[str], # The subtitle of the chart (accepted, not drawn; or list for multiple charts) title=Optional[str], # The title of the chart xlabel=Optional[str], # The x-axis label ylabel=Optional[str], # The y-axis label figsize=Optional[Tuple[float, float]], # The figure size in inches show_legend=Optional[bool], # Whether to show the legend (of the hue categories) show_grid=Optional[str], # Which grid lines to show (accepted; the chart draws none) dimensions=Optional[List[str]], # The dimensions to draw, in order (default: every key but the hue) hue=Optional[str], # The key to color the lines by (categorical or numeric; or list for multiple charts) category_orders=Optional[Dict[str, List[str]]], # The order of the categories of categorical dimensions emphasis=Optional[Union[str, List[Optional[str]]]], # The emphasis role of every row ("background", "highlight"; or one role for all rows) ) ``` **Dimension types.** Every dimension is one vertical axis, and each axis runs from its smallest value at the bottom to its largest at the top: - **Numeric dimensions** are normalized to the 0–1 range of the axis, with tick marks at 0 %, 25 %, 50 %, 75 % and 100 % labeled with the actual values. - **Categorical dimensions** are detected from their string values and spaced evenly along the axis, with one labeled tick mark per category. The categories are sorted alphabetically unless `category_orders` says otherwise. For more details, see the [datachart.charts.ParallelCoords](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.ParallelCoords) function. ## Basics The examples in this guide share one dataset: a sample of 30 penguins from the [Palmer penguins](https://allisonhorst.github.io/palmerpenguins/) dataset (CC0), ten of each species. Every penguin has four body measurements — bill length and depth (in mm), flipper length (in mm) and body mass (in g) — and three categorical attributes: its species, sex and the island it was observed on. The data is hard-coded in a hidden cell as `penguins`, a list of one dictionary per penguin. The data is a plain list of dictionaries: each dictionary is one data point (one line of the chart), and each key is one dimension (one axis): ``` penguins[:2] ``` **Basic example.** Only the `data` argument is required to draw the chart. Every key becomes an axis, in the order the keys first appear: the four measurements as numeric axes, and the species, island and sex as categorical axes with one tick per category. Each penguin is one line, drawn in the theme's default color. ``` ParallelCoords( # add the data to the chart data=penguins ).show() ``` ## Customizing the Parallel Coordinates Every customization is either a keyword argument of `ParallelCoords` or a `plot_parallel_*` attribute of its `style` dictionary. The table maps common tasks to the one you need and links to the subsection that shows it. | I want to… | Use | See | | -------------------------------------------- | ------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | | add a title and axis labels | `title`, `xlabel`, `ylabel` | [Title and axis labels](#title-and-axis-labels) | | resize the figure | `figsize` | [Figure size](#figure-size) | | choose and order the axes | `dimensions` | [Selecting dimensions](#selecting-dimensions) | | color the lines by a category | `hue`, `show_legend` | [Hue](#hue) | | color the lines by a value | `hue` on a numeric key | [Hue](#hue) | | order the categories on an axis | `category_orders` | [Example 1: Car Specs](#example-1-car-specs-categorical-axes-and-category-order) | | change the line color, transparency or width | `style={"plot_parallel_color": ..., "plot_parallel_alpha": ..., ...}` | [Line style](#line-style) | | style the vertical axes | `style={"plot_parallel_axis_color": ..., "plot_parallel_axis_width": ..., ...}` | [Axis style](#axis-style) | | style the tick marks and their labels | `style={"plot_parallel_tick_color": ..., "plot_parallel_tick_label_size": ..., ...}` | [Tick marks and labels](#tick-marks-and-labels) | | style the dimension labels | `style={"plot_parallel_dim_label_size": ..., "plot_parallel_dim_label_rotation": ..., ...}` | [Dimension labels](#dimension-labels) | | highlight some rows, mute the rest | `emphasis` | [Emphasis](#emphasis) | | overlay several sets of data points | `data` as a list of lists, `style` and `hue` as lists | [Multiple Parallel Coordinates Charts](#multiple-parallel-coordinates-charts) | | save the chart to a file | `save_figure` | [Saving the Chart as an Image](#saving-the-chart-as-an-image) | The full list of style attributes is in the [datachart.typings.ParallelCoordsStyleAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.ParallelCoordsStyleAttrs) type; the full list of parameters is in the [datachart.charts.ParallelCoords](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.ParallelCoords) reference. ### Title and axis labels To add the chart title and axis labels, add the `title`, `xlabel` and `ylabel` attributes. The y-axis label describes what the height of a line means — the position of every value within the range of its axis — so it is rarely needed; the x-axis label names what the axes are. ``` ParallelCoords( data=penguins, # add the title title="Palmer penguins", # add the x and y axis labels xlabel="Measurement", ylabel="Position within the range", ).show() ``` ### Figure size To change the figure size, add the `figsize` attribute. The `figsize` attribute can be a tuple (width, height), values are in inches. The `datachart` package provides a [datachart.constants.FIG_SIZE](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.FIG_SIZE) constant, which contains some of the predefined figure sizes. A parallel coordinates chart grows with the number of axes, so a wide figure keeps the tick labels of neighboring axes apart. The `show_grid` attribute of the other charts is accepted as well, but it has nothing to draw here: the chart has no y-axis ticks, and its x positions are the vertical axes themselves — they are the grid. ``` from datachart.constants import FIG_SIZE ``` ``` ParallelCoords( data=penguins, title="Palmer penguins", # add to determine the figure size figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` ### Selecting dimensions By default every key of the data points is an axis, except the `hue` key. To draw a subset of the keys, or to draw them in a different order, add the `dimensions` attribute with the list of keys. The order matters: patterns are easiest to read between neighboring axes, so put the dimensions you want to compare next to each other. The example drops the island and sex and puts the flipper length next to the body mass, the two measurements that grow together. The four measurements are the axes of most examples below, so they are kept in `MEASUREMENTS`. ``` MEASUREMENTS = ["bill length", "bill depth", "flipper length", "body mass"] ParallelCoords( data=penguins, title="Palmer penguins", # choose the axes and their order dimensions=MEASUREMENTS + ["species"], figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` ### Hue To color the lines by one of the keys, add the `hue` attribute with its name. The key is dropped from the auto-detected dimensions — list it in `dimensions` to keep it as an axis as well. **Categorical hue.** When the hue values are strings, every category gets its own color from the theme's `color_parallel_hue` palette, and `show_legend` adds the legend that names them. Coloring by species is what turns the penguin sample into three readable groups: the Gentoo are the heaviest with the longest flippers, the Adelie have the shortest bills, and the Chinstrap sit in between with the deepest bills. ``` ParallelCoords( data=penguins, title="Palmer penguins", dimensions=MEASUREMENTS, # color the lines by the species hue="species", # show the legend that names the species show_legend=True, figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` **Numeric hue.** When the hue values are numbers, the lines are colored continuously along the theme's `color_parallel_hue_continuous` ramp, from the lightest color at the smallest value to the darkest at the largest. There is no legend for a continuous hue — the axis of the hue key, kept in `dimensions`, is the scale. Coloring by the body mass makes the heaviest penguins the darkest lines on every axis. ``` ParallelCoords( data=penguins, title="Palmer penguins", # keep the hue key (the body mass) as an axis dimensions=MEASUREMENTS, # color the lines continuously by the body mass hue="body mass", figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` ### Line style To change the style of the lines, add the `style` attribute with the corresponding attributes. The supported attributes are shown in the [datachart.typings.ParallelCoordsStyleAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.ParallelCoordsStyleAttrs) type; the ones that style the lines are: | Attribute | Description | | ------------------------ | ------------------------------------------------------------------------------------------------------------------------- | | `"plot_parallel_color"` | The color of the lines. It overrides the hue colors, so leave it out when coloring by `hue`. | | `"plot_parallel_alpha"` | The alpha of the lines (how visible they are). | | `"plot_parallel_width"` | The width of the lines. | | `"plot_parallel_style"` | The line style (solid, dashed, etc.). | | `"plot_parallel_marker"` | The marker drawn where a line crosses an axis (none by default). | | `"plot_parallel_zorder"` | The draw order of the lines (1 by default); the axes are drawn at `plot_parallel_axis_zorder` (2 by default), above them. | Again, to help with the style settings, the [datachart.constants](https://eriknovak.github.io/datachart/0.9.0/references/constants/index.md) module contains the following constants: | Constant | Description | | ------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------- | | [datachart.constants.LINE_STYLE](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.LINE_STYLE) | The line style (solid, dashed, etc.). | | [datachart.constants.LINE_MARKER](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.LINE_MARKER) | The line markers (circle, square, etc.). | The alpha is the attribute that matters most: lines overlap by nature, and a lower alpha lets the dense regions show as darker bands while every single line stays traceable. A marker on the axis crossings shows where the values actually sit, which helps on the categorical axes where many lines meet at the same tick. Any attribute you leave out keeps the value of the active theme. ``` from datachart.constants import LINE_STYLE, LINE_MARKER ``` ``` ParallelCoords( data=penguins, # define the style of the lines style={ "plot_parallel_color": "#2a6f97", "plot_parallel_alpha": 0.35, "plot_parallel_width": 1.5, "plot_parallel_style": LINE_STYLE.SOLID, "plot_parallel_marker": LINE_MARKER.CIRCLE, }, title="Palmer penguins", dimensions=MEASUREMENTS + ["species"], figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` ### Axis style The vertical axes have their own style attributes: | Attribute | Description | | ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | | `"plot_parallel_axis_color"` | The color of the vertical axes. | | `"plot_parallel_axis_width"` | The width of the vertical axes. | | `"plot_parallel_axis_zorder"` | The draw order of the vertical axes (2 by default, above the lines). The tick marks and their labels are drawn just above the axes. | The default axes are black and heavier than the lines, so they read as the frame of the chart. Lighter, thinner axes hand the attention to the lines, which suits a chart whose story is in the data rather than in the scales. ``` ParallelCoords( data=penguins, # define the style of the vertical axes style={ "plot_parallel_axis_color": "#9a9a9a", "plot_parallel_axis_width": 1.0, }, title="Palmer penguins", dimensions=MEASUREMENTS, hue="species", show_legend=True, figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` ### Tick marks and labels Every axis carries tick marks — five on a numeric axis, one per category on a categorical axis — and each tick mark has a label. Both have their own style attributes: | Attribute | Description | | ------------------------------------- | ---------------------------------------------------------------------------------------------- | | `"plot_parallel_tick_color"` | The color of the tick marks. | | `"plot_parallel_tick_width"` | The width of the tick marks. | | `"plot_parallel_tick_length"` | The length of the tick marks, as a fraction of the spacing between two axes (0.02 by default). | | `"plot_parallel_tick_label_size"` | The font size of the tick labels. | | `"plot_parallel_tick_label_color"` | The font color of the tick labels. | | `"plot_parallel_tick_label_bg_color"` | The background color of the tick labels. | | `"plot_parallel_tick_label_bg_alpha"` | The background alpha of the tick labels. | The tick labels sit right next to the axes, where the lines cross, so they are drawn on a background box that keeps them legible over the lines; the box is white at 80 % alpha by default. The example tones the tick marks down to match the grey axes of the previous section, enlarges the labels and gives them an opaque light box so no line shows through. ``` ParallelCoords( data=penguins, style={ "plot_parallel_axis_color": "#9a9a9a", "plot_parallel_axis_width": 1.0, # define the style of the tick marks "plot_parallel_tick_color": "#9a9a9a", "plot_parallel_tick_width": 1.0, "plot_parallel_tick_length": 0.04, # define the style of the tick labels "plot_parallel_tick_label_size": 9, "plot_parallel_tick_label_color": "#4a4a4a", "plot_parallel_tick_label_bg_color": "#f3f3f3", "plot_parallel_tick_label_bg_alpha": 1.0, }, title="Palmer penguins", dimensions=MEASUREMENTS, hue="species", show_legend=True, figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` ### Dimension labels The dimension labels name the axes along the bottom of the chart. Their style attributes are: | Attribute | Description | | ------------------------------------ | ------------------------------------------------------------------------------- | | `"plot_parallel_dim_label_size"` | The font size of the dimension labels. | | `"plot_parallel_dim_label_color"` | The font color of the dimension labels. | | `"plot_parallel_dim_label_rotation"` | The rotation of the dimension labels, in degrees. | | `"plot_parallel_dim_label_pad"` | The padding between the bottom of the axes and the dimension labels, in points. | Rotation is the attribute to reach for when the labels are long or the axes many: rotated labels no longer run into each other. A larger pad keeps them clear of the bottom tick labels. ``` ParallelCoords( data=penguins, # define the style of the dimension labels style={ "plot_parallel_dim_label_size": 11, "plot_parallel_dim_label_color": "#2a6f97", "plot_parallel_dim_label_rotation": 20, "plot_parallel_dim_label_pad": 14, }, title="Palmer penguins", figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` ### Emphasis When the story is about some of the rows, the `emphasis` attribute tells the rest to step back. It takes one role per data point, aligned with the rows of `data` (a single string applies the same role to every row): - `"background"` mutes a row: it takes the active theme's `muted_color` at `muted_alpha`, gets a thinner line, drops behind the other rows, and claims no hue color and no legend entry. - `"highlight"` bolds a row and brings it to the front of the rows — but stays below the axes, tick marks and labels, so the scales remain readable. - `None` draws the row unchanged. The role strings are also available as constants in [datachart.constants.EMPHASIS](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.EMPHASIS). Because the background rows leave the legend, a hue legend over an emphasized chart names only the groups that are still colored. The example singles out the Chinstrap penguins: they are highlighted, the other two species are muted, and the legend names the Chinstrap alone. See the [Highlighting](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/styling/highlighting/index.md) guide for how emphasis works across the other charts and in composed figures. ``` from datachart.constants import EMPHASIS ``` ``` ParallelCoords( data=penguins, # one role per row: highlight the Chinstrap, mute the other species emphasis=[ EMPHASIS.HIGHLIGHT if p["species"] == "Chinstrap" else EMPHASIS.BACKGROUND for p in penguins ], title="Palmer penguins: the Chinstrap", dimensions=MEASUREMENTS, hue="species", show_legend=True, figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` ## Multiple Parallel Coordinates Charts To draw several sets of data points on one chart, pass a list of lists to the `data` argument. The sets share the axes: the dimensions are the union of their keys, and every axis is normalized over the values of all sets together, so the same value lands at the same height whichever set it belongs to. What the sets do not share is their style: `style` and `hue` can be passed as lists, where each element applies to the corresponding set (a single value applies to every set), so one set can be drawn in a color of its own while another is colored by its hue. The `subtitle` attribute is accepted for consistency with the other charts, but a parallel coordinates chart has no per-set heading to draw it in — the sets are told apart by their style or by the hue legend. Multiple charts pattern For multiple charts, `data` becomes a list of lists of data points, and per-chart attributes like `style` and `hue` become lists where each element applies to the corresponding chart. The axes of multiple charts come from the keys of the data points, so each set is reduced to the keys it should be drawn on. The example separates the Gentoo penguins from the other two species: the Adelie and Chinstrap are drawn as a light grey context, the Gentoo in a bold color on top. The per-dimension ranges are the same as in the previous examples, because they are computed over both sets. ``` # keep only the measurements: the keys of the data points are the axes gentoo = [{k: p[k] for k in MEASUREMENTS} for p in penguins if p["species"] == "Gentoo"] others = [{k: p[k] for k in MEASUREMENTS} for p in penguins if p["species"] != "Gentoo"] figure = ParallelCoords( # use a list of lists to define multiple charts data=[others, gentoo], # style can be a list (one per chart) or a single dict (applies to all) style=[ {"plot_parallel_color": "#c0c0c0", "plot_parallel_alpha": 0.8}, {"plot_parallel_color": "#0f7173", "plot_parallel_width": 2.0}, ], title="Palmer penguins: the Gentoo against the rest", figsize=FIG_SIZE.FULL_MEDIUM, ) figure.show() ``` ## Saving the Chart as an Image To save the chart as an image, use the [datachart.utils.save_figure](https://eriknovak.github.io/datachart/0.9.0/references/utils#datachart.utils.save_figure) function. ``` from datachart.utils import save_figure ``` ``` save_figure(figure, "./fig_parallel_coords.png", dpi=300) ``` The figure should be saved in the current working directory. ## Real-World Examples The following examples put the features above to work on real or realistic data. Each one states what its data is and where it comes from; the data itself lives in a hidden cell. ### Example 1: Car Specs (Categorical Axes and Category Order) `cars` holds the specifications of 30 cars from the [Auto MPG](https://archive.ics.uci.edu/dataset/9/auto+mpg) dataset of the UCI Machine Learning Repository (CC BY 4.0), which describes cars sold in the United States between 1970 and 1982: the number of cylinders, the horsepower, the weight (in lb), the fuel consumption (in mpg) and the region of origin. The sample spans the three regions and the whole range from heavy V8 sedans to small four-cylinder imports. Every car also has a `model` name. It is a label, not a variable — as a categorical axis it would have 30 ticks — so `dimensions` lists the axes to draw and leaves it out. The origin is both the `hue` and the last axis, which fans the lines out into the three regions at the right edge. Its categories would be sorted alphabetically (Europe, Japan, USA); `category_orders` puts the USA at the bottom and Japan at the top instead — the order the regions take on the mpg axis next to it — so the lines reach the last axis without crossing. The chart then tells the dataset's story at a glance: the American cars have the most cylinders, the most horsepower and the heaviest bodies, and travel the fewest miles per gallon; the Japanese cars are the mirror image. ``` ParallelCoords( data=cars, title="Cars of the 1970s: specifications by region of origin", # the model name is a label, not an axis dimensions=["cylinders", "horsepower", "weight (lb)", "mpg", "origin"], # color the lines by the origin, and keep the origin as the last axis hue="origin", show_legend=True, # order the origins instead of sorting them alphabetically category_orders={"origin": ["USA", "Europe", "Japan"]}, style={"plot_parallel_alpha": 0.7, "plot_parallel_width": 1.5}, figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` ### Example 2: Hyperparameter Search (Numeric Hue) `runs` holds the 24 runs of an illustrative hyperparameter search of an image classifier, in the shape a tracking tool such as Weights & Biases or Optuna reports them: each run is one combination of optimizer, learning rate, batch size, dropout and number of epochs, and the validation accuracy it reached. The learning rate was sampled on a logarithmic grid from 10⁻⁴ to 10⁻², so it is stored as its base-10 logarithm — on a linear axis the raw values would pile up at the bottom. A parallel coordinates chart is the standard view of such a search, and its one question is which settings lead to a high score. Coloring the lines by the accuracy answers it: with the numeric `hue`, every run is shaded along the continuous ramp from the lightest (worst) to the darkest (best), and the dark lines can be followed back across the hyperparameter axes. The accuracy is kept as the last axis, so the ramp can be read off it. Here the best runs cluster around Adam, a learning rate of 10⁻³, a moderate dropout and the full 30 epochs, while the runs at either end of the learning-rate axis stay pale. ``` ParallelCoords( data=runs, title="Hyperparameter search: 24 runs colored by validation accuracy", # keep the accuracy as the last axis, so the color ramp can be read off it dimensions=RUN_COLUMNS, # color the lines continuously by the accuracy hue="accuracy", style={"plot_parallel_alpha": 0.8, "plot_parallel_width": 1.5}, figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` ### Example 3: Best Runs (Emphasis) The same search, asked a sharper question: what do the three best runs have in common? The numeric hue grades every run; `emphasis` answers a yes-or-no question instead. The three runs with the highest accuracy are picked in code and given the `"highlight"` role, every other run the `"background"` role, so the field becomes a muted grey context and the three best runs are the only colored lines. The highlighted rows keep their hue color — here the categorical hue on the optimizer — and because the muted rows leave the legend, it names only the optimizer the best runs used. All three ran Adam at a learning rate of 10⁻³ with a dropout of 0.2 to 0.3 for 25 to 30 epochs; the batch size is what they disagree on. ``` best = sorted(runs, key=lambda run: run["accuracy"])[-3:] ParallelCoords( data=runs, # highlight the three best runs, mute the rest emphasis=[ EMPHASIS.HIGHLIGHT if run in best else EMPHASIS.BACKGROUND for run in runs ], title="Hyperparameter search: the three best runs", dimensions=RUN_COLUMNS, # the highlighted runs keep their hue color; the muted ones leave the legend hue="optimizer", show_legend=True, figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` # Composition & Utilities # Composition & Utilities The [datachart.utils](https://eriknovak.github.io/datachart/0.9.0/references/utils/index.md) module of the `datachart` package provides the figure composition functions and various utilities for data visualization. These include: - The [datachart.utils.Panel](https://eriknovak.github.io/datachart/0.9.0/references/utils/#datachart.utils.Panel) function for overlaying multiple charts on a single plot with optional dual y-axes, as illustrated in the [panel](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/utility/panel/index.md) section. - The [datachart.utils.Grid](https://eriknovak.github.io/datachart/0.9.0/references/utils/#datachart.utils.Grid) function for arranging multiple charts in a grid layout, as illustrated in the [grid](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/utility/grid/index.md) section. - The `texts` chart parameter and the [datachart.utils.Annotate](https://eriknovak.github.io/datachart/0.9.0/references/utils/#datachart.utils.Annotate) function for attaching text annotations to charts and finished figures, as illustrated in the [text annotations](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/utility/annotations/index.md) section. - The [datachart.utils.stats](https://eriknovak.github.io/datachart/0.9.0/references/utils/stats/index.md) module for statistical calculations, as illustrated in the [stats](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/utility/stats/index.md) section. - The [datachart.utils.save_figure](https://eriknovak.github.io/datachart/0.9.0/references/utils/#datachart.utils.save_figure) function for saving figures into files, as showcased in the [charts](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/charts/index.md) section. # Panel This section showcases the panel. It contains examples of how to overlay several charts in one coordinate space using the [datachart.utils.Panel](https://eriknovak.github.io/datachart/0.9.0/references/utils/#datachart.utils.Panel) function. Looking for a specific customization? Jump straight to the [quick reference](#customizing-the-panel), which maps common tasks to the parameter or per-figure option that does the job. A panel does not draw data of its own: it takes figures already drawn by the chart functions of the [datachart.charts](https://eriknovak.github.io/datachart/0.9.0/references/charts/index.md) module — any of the charts from the [Charts](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/charts/index.md) guides — and redraws them into one coordinate space, with a shared x-axis and up to two y-axes. Where the [Grid](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/utility/grid/index.md) keeps every figure in a coordinate space of its own, the panel reads them against each other on shared axes: reach for a grid to compare charts side by side, and for a panel to overlay them. The `Panel` function is found in the [datachart.utils](https://eriknovak.github.io/datachart/0.9.0/references/utils/index.md) module. Let's import it, together with the two chart functions the examples below overlay: ``` from datachart.charts import BarChart, LineChart from datachart.utils import Panel ``` ## Panel Input Attributes The `Panel` function accepts a list of figures as its first argument and keyword arguments for the panel configuration. Each item of the list is either a bare figure returned by a chart function, or a dictionary with the figure and its per-figure options. ``` Panel( [ # A list of figures to overlay, each one either Figure, # a bare datachart figure, or { # a dict with the figure and its per-figure options "figure": Figure, # The datachart figure (required) "y_axis": Optional[str], # Which y-axis the figure is drawn on ("auto", "left", "right") "z_order": Optional[int], # The drawing order (higher values are drawn on top) "legend_label": Optional[str], # The legend label (overrides the chart subtitle) "emphasis": Optional[str], # The emphasis role of the figure ("background", "highlight") }, ], title=Optional[str], # The title of the panel xlabel=Optional[str], # The x-axis label ylabel_left=Optional[str], # The left y-axis label ylabel_right=Optional[str], # The right y-axis label figsize=Optional[Tuple[float, float]], # The figure size in inches show_legend=Optional[bool], # Whether to show the legend (default: False) show_grid=Optional[str], # Which grid lines to show ("both", "x", "y") auto_secondary_axis=Optional[float], # The scale ratio above which a figure moves to the right y-axis xmin=Optional[Union[int, float]], # The x-axis range xmax=Optional[Union[int, float]], ymin=Optional[Union[int, float]], # The left y-axis range ymax=Optional[Union[int, float]], ymin_right=Optional[Union[int, float]], # The right y-axis range ymax_right=Optional[Union[int, float]], bar_mode=Optional[BAR_MODE], # How overlaid bar charts share the axis ("group", "stack", "overlay") ) ``` For more details, see the [datachart.utils.Panel](https://eriknovak.github.io/datachart/0.9.0/references/utils/#datachart.utils.Panel) function. The reference is generated from the function itself, so it always lists the current parameters and per-figure options. ## Basics The examples in this guide share one dataset: the monthly climate normals of Ljubljana's weather station — the mean temperature (in °C) and the total precipitation (in mm) of each month, rounded from the published values. Plotted together they form a *climograph*, the standard chart of a climate: precipitation as bars, temperature as a line, each on its own y-axis. The data lives in a hidden cell. A panel overlays figures, so the first step is to draw each chart on its own. The precipitation is a bar chart with one labeled bar per month; the temperature is a line chart whose `x` values are the month indices, so its points land on the bars. The `subtitle` of each chart becomes its label in the panel legend: ``` precipitation = BarChart(data=precipitation_data, subtitle="Precipitation (mm)") temperature = LineChart(data=temperature_data, subtitle="Temperature (°C)") ``` **Basic example.** Only the list of figures is required to draw the panel. The figures are drawn in the order given, the months of the bar chart label the shared x-axis, and the y-axes are assigned automatically: the temperature spans about 20 units while the precipitation spans about 80, so the temperature moves to a second y-axis on the right. The [Axis assignment](#axis-assignment) section explains the rule and how to override it. ``` Panel( # add the figures to the panel [precipitation, temperature] ).show() ``` ## Customizing the Panel Every customization is either a keyword argument of `Panel` or a per-figure option of the dictionary wrapping a figure. The table maps common tasks to the one you need and links to the subsection that shows it. | I want to… | Use | See | | ----------------------------------- | ------------------------------------------------------------------ | ------------------------------------------------------------- | | add a title and axis labels | `title`, `xlabel`, `ylabel_left`, `ylabel_right` | [Title and axis labels](#title-and-axis-labels) | | resize the figure | `figsize` | [Figure size and grid](#figure-size-and-grid) | | show the grid lines | `show_grid` | [Figure size and grid](#figure-size-and-grid) | | show which figure is which | `show_legend`, the charts' `subtitle`, per-figure `"legend_label"` | [Legend](#legend) | | put a figure on the right y-axis | per-figure `"y_axis"` | [Axis assignment](#axis-assignment) | | tune the automatic axis assignment | `auto_secondary_axis` | [Axis assignment](#axis-assignment) | | bring a figure to the front | per-figure `"z_order"` | [Drawing order](#drawing-order) | | highlight one figure, mute the rest | per-figure `"emphasis"` | [Emphasis](#emphasis) | | limit the axes | `xmin`, `xmax`, `ymin`, `ymax`, `ymin_right`, `ymax_right` | [Axis limits](#axis-limits) | | overlay several bar charts | `bar_mode` | [Bar mode](#bar-mode) | | add a figure to an existing panel | nest `Panel` figures | [Nesting panels](#nesting-panels) | | overlay horizontal bars | `orientation` on the bar charts, the same `Panel` parameters | [Horizontal panels](#horizontal-panels) | | change the defaults of every panel | `config.update_config` with the `overlay_*` settings | [Panel configuration](#panel-configuration) | | save the panel to a file | `save_figure` | [Saving the Chart as an Image](#saving-the-chart-as-an-image) | The full list of parameters and per-figure options is in the [datachart.utils.Panel](https://eriknovak.github.io/datachart/0.9.0/references/utils/#datachart.utils.Panel) function. The look of each figure — colors, line widths, markers — is set on the chart itself through its `style` attribute; see the guide of each chart in the [Charts](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/charts/index.md) section. ### Title and axis labels To add the panel title and axis labels, add the `title`, `xlabel`, `ylabel_left` and `ylabel_right` attributes. The panel has one x-axis and up to two y-axes, so the y-axis label is given per side; `ylabel_right` is only drawn when a figure is assigned to the right y-axis. ``` Panel( [precipitation, temperature], # add the title title="Climate of Ljubljana", # add the x and y axis labels xlabel="Month", ylabel_left="Precipitation (mm)", ylabel_right="Temperature (°C)", ).show() ``` ### Figure size and grid To change the figure size, add the `figsize` attribute. The `figsize` attribute can be a tuple (width, height), values are in inches. The `datachart` package provides a [datachart.constants.FIG_SIZE](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.FIG_SIZE) constant, which contains the most common figure sizes. To add the grid, add the `show_grid` attribute. The possible options are: | Option | Description | | -------- | ----------------------------------------------- | | `"both"` | shows both the x-axis and the y-axis gridlines. | | `"x"` | shows only the x-axis grid lines. | | `"y"` | shows only the y-axis grid lines. | Again, `datachart` provides a [datachart.constants.SHOW_GRID](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.SHOW_GRID) constant, which contains the supported options. The grid follows the left y-axis. ``` from datachart.constants import FIG_SIZE, SHOW_GRID ``` ``` Panel( [precipitation, temperature], title="Climate of Ljubljana", xlabel="Month", ylabel_left="Precipitation (mm)", ylabel_right="Temperature (°C)", # add to determine the figure size figsize=FIG_SIZE.FULL_SHORT, # add to show the grid lines show_grid=SHOW_GRID.Y, ).show() ``` ### Legend To show the legend, add the `show_legend` attribute set to `True`. The legend merges the entries of every figure and labels each one with the `subtitle` of its chart; when the panel has two y-axes, an `(L)` or `(R)` suffix tells which axis an entry is read against. To label a figure differently in the panel than on its own, wrap it in a dictionary and add the `"legend_label"` option, which overrides the subtitle: ``` Panel( [ # override the subtitle of the chart in the legend {"figure": precipitation, "legend_label": "Precipitation"}, {"figure": temperature, "legend_label": "Mean temperature"}, ], title="Climate of Ljubljana", xlabel="Month", ylabel_left="Precipitation (mm)", ylabel_right="Temperature (°C)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, # add to show the legend show_legend=True, ).show() ``` ### Axis assignment To choose the y-axis a figure is drawn on, wrap it in a dictionary and add the `"y_axis"` option, which supports the following values: | Value | Description | | --------- | ------------------------------------------------------------------ | | `"auto"` | The panel picks the axis from the scale of the data (the default). | | `"left"` | The figure is drawn on the left y-axis. | | `"right"` | The figure is drawn on the right y-axis. | In `"auto"` mode the panel compares the span of the values of each figure: figures whose spans differ by more than the `auto_secondary_axis` ratio (default `3.0`) are put on different y-axes, the larger group on the left. The temperature spans about 20 units and the precipitation about 80, a ratio of about 4, which is why the [basic example](#basics) already has two y-axes. An explicit `"y_axis"` is the robust choice whenever you know which axis a figure belongs to — the data can change, the assignment should not: ``` Panel( [ # assign each figure to its y-axis explicitly {"figure": precipitation, "y_axis": "left"}, {"figure": temperature, "y_axis": "right"}, ], title="Climate of Ljubljana", xlabel="Month", ylabel_left="Precipitation (mm)", ylabel_right="Temperature (°C)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, show_legend=True, ).show() ``` To keep the automatic assignment but make it more or less eager, add the `auto_secondary_axis` attribute with the ratio of your choice. A ratio above the 4 of this dataset keeps both figures on the left y-axis, where the temperature is squeezed against the bottom — the reason the panel splits the axes in the first place: ``` Panel( [precipitation, temperature], # only split the axes when the spans differ more than tenfold auto_secondary_axis=10.0, title="Climate of Ljubljana", xlabel="Month", ylabel_left="Precipitation (mm) / Temperature (°C)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, show_legend=True, ).show() ``` ### Drawing order The figures are drawn in the order given, later ones on top of earlier ones. To change the order, wrap a figure in a dictionary and add the `"z_order"` option: figures with a higher value are drawn on top of figures with a lower value, whatever their position in the list. When no `"z_order"` is given, each chart type takes the default of its kind from the [panel configuration](#panel-configuration) — bars and histograms sit behind lines and scatter points, so a line is never hidden by the bars it is read against. The example reverses that: the bars are drawn over the line. ``` Panel( [ # draw the bars on top of the line {"figure": precipitation, "y_axis": "left", "z_order": 2}, {"figure": temperature, "y_axis": "right", "z_order": 1}, ], title="Climate of Ljubljana", xlabel="Month", ylabel_left="Precipitation (mm)", ylabel_right="Temperature (°C)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, show_legend=True, ).show() ``` ### Emphasis To draw attention to one figure, wrap the figures in dictionaries and add the `"emphasis"` option, which applies one role to every layer of the figure: | Role | Description | | -------------- | ----------------------------------------------------------------------------------------------------------------------------------- | | `"background"` | Mutes the figure: it takes the muted color of the active theme, is pushed behind the other figures, and is dropped from the legend. | | `"highlight"` | Bolds the figure and brings it to the front of the data layers. | | `None` | Leaves the figure unchanged. | Again, `datachart` provides a [datachart.constants.EMPHASIS](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.EMPHASIS) constant, which contains the supported options; the [Highlighting](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/styling/highlighting/index.md) guide covers the emphasis vocabulary across the package. Here the precipitation is context and the temperature the message: ``` from datachart.constants import EMPHASIS ``` ``` Panel( [ # mute the bars, bold the line {"figure": precipitation, "y_axis": "left", "emphasis": EMPHASIS.BACKGROUND}, {"figure": temperature, "y_axis": "right", "emphasis": EMPHASIS.HIGHLIGHT}, ], title="Climate of Ljubljana", xlabel="Month", ylabel_left="Precipitation (mm)", ylabel_right="Temperature (°C)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, show_legend=True, ).show() ``` ### Axis limits To set the range of an axis, add the `xmin`, `xmax`, `ymin` and `ymax` attributes; `ymin` and `ymax` apply to the left y-axis, `ymin_right` and `ymax_right` to the right one. Limits set on the individual charts are not carried over, the panel owns its axes. With labeled bars the x positions are the indices of the labels, so half-integer limits cut between two months. The example zooms in on April to September and starts both y-axes at zero, which puts the two quantities on an honest footing and leaves room for the legend: ``` Panel( [ {"figure": precipitation, "y_axis": "left"}, {"figure": temperature, "y_axis": "right"}, ], # zoom in on April to September xmin=2.5, xmax=8.5, # start both y-axes at zero ymin=0, ymax=200, ymin_right=0, ymax_right=30, title="Climate of Ljubljana", xlabel="Month", ylabel_left="Precipitation (mm)", ylabel_right="Temperature (°C)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, show_legend=True, ).show() ``` ### Bar mode When several bar charts are overlaid, the `bar_mode` attribute decides how their bars share each category, with the following values: | Value | Description | | ----------- | ----------------------------------------------------------------------- | | `"group"` | The bars of each category are drawn side by side (the default). | | `"stack"` | The bars of each category are stacked on top of each other. | | `"overlay"` | The bars of each category are drawn over each other, with transparency. | Again, `datachart` provides a [datachart.constants.BAR_MODE](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.BAR_MODE) constant, which contains the supported options. The example splits the precipitation into the rain and the snow of each month — the split is illustrative — and stacks them, so the bars add up to the monthly total while the temperature line stays on its own axis: ``` from datachart.constants import BAR_MODE ``` ``` # an illustrative split of the monthly precipitation into snow (cold months) and rain SNOW_SHARE = [0.5, 0.4, 0.15, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.1, 0.4] snow = BarChart( data=[ {"label": month, "y": round(total * share)} for month, total, share in zip(MONTHS, PRECIPITATION, SNOW_SHARE) ], subtitle="Snow (mm)", ) rain = BarChart( data=[ {"label": month, "y": round(total * (1 - share))} for month, total, share in zip(MONTHS, PRECIPITATION, SNOW_SHARE) ], subtitle="Rain (mm)", ) Panel( [ {"figure": rain, "y_axis": "left"}, {"figure": snow, "y_axis": "left"}, {"figure": temperature, "y_axis": "right"}, ], # stack the bars of the two bar charts bar_mode=BAR_MODE.STACK, # headroom above the tallest stack ymin=0, ymax=175, title="Climate of Ljubljana", xlabel="Month", ylabel_left="Precipitation (mm)", ylabel_right="Temperature (°C)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, show_legend=True, ).show() ``` ### Nesting panels Panel figures nest: `Panel([Panel([f1, f2]), f3])` is equivalent to `Panel([f1, f2, f3])`, to any depth. A nested panel contributes its figures with their per-figure options intact, while the panel-level settings — title, labels, limits — always come from the outermost call. This makes it easy to add a figure to a panel you have already built, such as the stacked precipitation above extended with the temperature: ``` # an existing panel... precipitation_panel = Panel( [ {"figure": rain, "y_axis": "left"}, {"figure": snow, "y_axis": "left"}, ], bar_mode=BAR_MODE.STACK, ) # ...later extended with an additional figure Panel( [precipitation_panel, {"figure": temperature, "y_axis": "right"}], bar_mode=BAR_MODE.STACK, ymin=0, ymax=175, title="Climate of Ljubljana", xlabel="Month", ylabel_left="Precipitation (mm)", ylabel_right="Temperature (°C)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, show_legend=True, ).show() ``` ### Horizontal panels A panel takes its orientation from the figures it holds: it is horizontal when every bar chart (and histogram) in it is horizontal, vertical otherwise, and mixing the two raises a `ValueError`. Line and scatter figures have no orientation of their own and follow the panel — in a horizontal panel their `x` runs along the categories and their `y` along the values, so the same temperature line overlays vertical and horizontal bars. The parameters keep their names but address the axes by role. The *value axis* carries the quantities (x in a horizontal panel) and the *category axis* the labels (y): `ylabel_left`, `ylabel_right`, `ymin`, `ymax`, `ymin_right` and `ymax_right` refer to the value axes, `xlabel`, `xmin` and `xmax` to the category axis. The secondary value axis sits at the top, so `"y_axis": "right"` places a figure on the top axis and the legend marks the two with `(B)` and `(T)`. Only `show_grid` keeps its literal meaning — it names the gridlines you see. ``` from datachart.constants import ORIENTATION # horizontal bars make the panel horizontal precipitation_h = BarChart( data=precipitation_data, subtitle="Precipitation (mm)", orientation=ORIENTATION.HORIZONTAL, ) Panel( [ {"figure": precipitation_h, "y_axis": "left"}, # "right" is the top value axis in a horizontal panel {"figure": temperature, "y_axis": "right"}, ], title="Climate of Ljubljana", # the category axis (y) and the two value axes (bottom and top) xlabel="Month", ylabel_left="Precipitation (mm)", ylabel_right="Temperature (°C)", # start both value axes at zero ymin=0, ymin_right=0, figsize=(10, 6), # gridlines keep their literal spelling: vertical lines along the values show_grid=SHOW_GRID.X, show_legend=True, ).show() ``` ## Panel Configuration The defaults the panel falls back on — the automatic axis threshold, the transparency of overlaid bars and histograms, the default drawing order of each chart type, the bar mode — are part of the global configuration, under the keys that start with `overlay_`. They are changed like any other setting, through [datachart.config.config.update_config](https://eriknovak.github.io/datachart/0.9.0/references/config/#datachart.config.Config.update_config); see the [Config](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/styling/config/index.md) guide for the configuration system as a whole. The current keys and their values in the active theme are: ``` from datachart.config import config {key: value for key, value in config.config.items() if key.startswith("overlay_")} ``` A setting given to `Panel` directly, such as `auto_secondary_axis` or `bar_mode`, always wins over the configuration. The configuration is the place for a default that should hold for every panel of a document: ``` config.update_config( { # split the y-axes sooner "overlay_auto_threshold": 2.0, # draw overlaid bars more transparent "overlay_bar_alpha": 0.5, } ) Panel( [precipitation, temperature], title="Climate of Ljubljana", xlabel="Month", ylabel_left="Precipitation (mm)", ylabel_right="Temperature (°C)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, show_legend=True, ).show() # restore the defaults for the rest of the guide config.reset_config() ``` ## Saving the Chart as an Image To save the panel as an image, use the [datachart.utils.save_figure](https://eriknovak.github.io/datachart/0.9.0/references/utils/#datachart.utils.save_figure) function. ``` from datachart.utils import save_figure ``` ``` figure = Panel( [ {"figure": precipitation, "y_axis": "left"}, {"figure": temperature, "y_axis": "right"}, ], title="Climate of Ljubljana", xlabel="Month", ylabel_left="Precipitation (mm)", ylabel_right="Temperature (°C)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, show_legend=True, ) save_figure(figure, "./fig_panel.png", dpi=300) ``` The figure should be saved in the current working directory. ## Real-World Examples The following examples put the features above to work on real or realistic data. Each one states what its data is and where it comes from; the data itself lives in a hidden cell. The chart functions they overlay are imported as needed; any chart from the [Charts](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/charts/index.md) guides can take part in a panel. ### Example 1: Enzyme Kinetics (Observed Points and a Fitted Model) `observed` holds the illustrative reaction velocity of an enzyme at 15 substrate concentrations, drawn from the Michaelis–Menten equation with seeded measurement noise, and `model` the noise-free curve at 100 concentrations. Overlaying the measurements as a scatter chart and the model as a line chart is the standard way to show how well a model explains the data; the two share the same units, so they share one y-axis and the default `"auto"` assignment leaves it at that. ``` from datachart.charts import ScatterChart Panel( [ ScatterChart(data=observed, subtitle="Observed"), LineChart(data=model, subtitle="Michaelis-Menten model"), ], title="Enzyme kinetics", xlabel="Substrate concentration (μM)", ylabel_left="Reaction velocity (μmol/min)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.BOTH, show_legend=True, ).show() ``` ### Example 2: Cell Size Distribution (Histogram and a Fitted Curve) `diameters` holds the illustrative diameter (in μm) of 250 cells measured under a microscope, drawn from a seeded normal generator, and `normal_fit` the normal density with the same mean and standard deviation, scaled to the bin width and the sample size so it is comparable with the histogram counts. The curve is drawn on top of the histogram by default — histograms take the background drawing order — and reads against it on the same y-axis. ``` from datachart.charts import Histogram Panel( [ Histogram(data=diameters, num_bins=N_BINS, subtitle="Measured diameters"), LineChart(data=normal_fit, subtitle="Normal fit"), ], title="Cell size distribution", xlabel="Cell diameter (μm)", ylabel_left="Number of cells", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, show_legend=True, ).show() ``` ### Example 3: Cell Viability Under Treatment (Grouped Bars and a Trend Line) `viability_24h` and `viability_48h` hold the illustrative viability (in % of the untreated control) of cells after 24 and 48 hours under four treatments, and `viability_mean` the mean of the two. Two bar charts in a panel are grouped side by side by the default `bar_mode`, and the `"z_order"` of the line lifts the mean above both so it is never hidden behind a bar. The chart `style` keeps the two time points in two greys so the red trend line carries the message. ``` Panel( [ BarChart(data=viability_24h, subtitle="24 h", style={"plot_bar_color": "#95a5a6"}), BarChart(data=viability_48h, subtitle="48 h", style={"plot_bar_color": "#7f8c8d"}), { "figure": LineChart( data=viability_mean, subtitle="Mean", style={"plot_line_color": "#d62728", "plot_line_width": 2.5}, ), # draw the trend line over the bars "z_order": 3, }, ], title="Cell viability under treatment", xlabel="Treatment", ylabel_left="Viability (% of control)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, show_legend=True, ).show() ``` ### Example 4: Seismic Monitoring (Emphasis on the Events) `baseline` holds 200 minutes of illustrative ground acceleration (in g) of a seismometer at rest, drawn from a seeded generator, and `tremor` and `earthquake` two events — a minor tremor and a larger earthquake — as bell-shaped bursts over the same baseline. The baseline is context: the `"background"` emphasis mutes it and drops it from the legend, so the two events, each in its own chart and color, are what the reader sees. The events dwarf the baseline — a span ratio of about 12 — so the default axis assignment would move the baseline to its own y-axis and blow it up; raising `auto_secondary_axis` above that ratio keeps every figure on one scale, the whole point being that the events stand out against the baseline. ``` Panel( [ # the baseline is context: mute it {"figure": LineChart(data=baseline, subtitle="Background"), "emphasis": EMPHASIS.BACKGROUND}, LineChart(data=tremor, subtitle="Tremor (M 3.2)", style={"plot_line_color": "#f39c12"}), LineChart(data=earthquake, subtitle="Earthquake (M 4.8)", style={"plot_line_color": "#e74c3c"}), ], # one scale for everything, so the events stand out against the baseline auto_secondary_axis=20.0, title="Seismic monitoring", xlabel="Time (minutes)", ylabel_left="Ground acceleration (g)", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.Y, show_legend=True, ).show() ``` # Grid This section showcases the grid. It contains examples of how to arrange several charts in a grid of cells using the [datachart.utils.Grid](https://eriknovak.github.io/datachart/0.9.0/references/utils/#datachart.utils.Grid) function. Looking for a specific customization? Jump straight to the [quick reference](#customizing-the-grid), which maps common tasks to the parameter or layout option that does the job. A grid does not draw data of its own: it takes figures already drawn by the chart functions of the [datachart.charts](https://eriknovak.github.io/datachart/0.9.0/references/charts/index.md) module — any of the charts from the [Charts](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/charts/index.md) guides — and redraws each one into its own cell of one combined figure. Where the [Panel](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/utility/panel/index.md) overlays figures in one coordinate space, the grid keeps every figure in a coordinate space of its own: reach for a panel to read series against each other, and for a grid to compare them side by side. The `Grid` function is found in the [datachart.utils](https://eriknovak.github.io/datachart/0.9.0/references/utils/index.md) module. Let's import it, together with the two chart functions the examples below arrange: ``` from datachart.charts import BarChart, LineChart from datachart.utils import Grid ``` ## Grid Input Attributes The `Grid` function accepts a list of figures as its first argument and keyword arguments for the grid configuration. The list comes in two forms: nested rows, where each inner list is one row of the grid, or a flat list that the grid arranges automatically. ``` Grid( [ # Nested rows: each inner list is one grid row of [Figure, Figure], # bare datachart figures, where [Figure, None], # None leaves a blank cell ], # or [ # A flat list arranged automatically, each item either Figure, # a bare datachart figure, or { # a dict with the figure and its layout options "figure": Figure, # The datachart figure (required) "layout_spec": Optional[dict], # The cell of the figure ("row", "col", "rowspan", "colspan") }, ], title=Optional[str], # The title of the grid xlabel=Optional[str], # The x-axis label of the whole grid, drawn once ylabel=Optional[str], # The y-axis label of the whole grid, drawn once max_cols=int, # The column cap of the flat-list automatic layout (default: 4) figsize=Optional[Tuple[float, float]], # The figure size in inches (default: calculated from the first figure) sharex=bool, # Whether the cells share the x-axis (default: False) sharey=bool, # Whether the cells share the y-axis (default: False) ) ``` For more details, see the [datachart.utils.Grid](https://eriknovak.github.io/datachart/0.9.0/references/utils/#datachart.utils.Grid) function. The reference is generated from the function itself, so it always lists the current parameters and layout options. ## Basics The examples in this guide share one dataset: the monthly climate normals of Slovenian weather stations — for Ljubljana the mean temperature (in °C), the total precipitation (in mm), the sunshine duration (in hours) and the mean relative humidity (in %) of each month, and for two contrasting stations, coastal Portorož and mountain Kredarica, the mean temperature. The values are rounded from the published normals. The data lives in a hidden cell. A grid arranges figures, so the first step is to draw each chart on its own. The `title` of a chart becomes the heading of its cell in the grid (with the `subtitle` as the fallback), so each part is named where it is drawn: ``` temperature = LineChart(data=temperature_data, title="Temperature (°C)") precipitation = BarChart(data=precipitation_data, title="Precipitation (mm)") sunshine = BarChart(data=sunshine_data, title="Sunshine (hours)") humidity = LineChart(data=humidity_data, title="Humidity (%)") ``` **Basic example.** Only the list of figures is required to draw the grid. A flat list is arranged automatically into rows of up to `max_cols` cells, so two figures make one row of two. Each cell keeps its own axes and scales — the [Sharing axes](#sharing-axes) section shows how to align them: ``` Grid( # add the figures to the grid [temperature, precipitation] ).show() ``` ## Customizing the Grid Every customization is either a keyword argument of `Grid` or the shape of the list it is given — nested rows, or a flat list with layout options. The table maps common tasks to the one you need and links to the subsection that shows it. | I want to… | Use | See | | ------------------------------------ | ------------------------------- | ------------------------------------------------------------- | | add a title over the whole grid | `title` | [Title and axis labels](#title-and-axis-labels) | | label the axes once for every cell | `xlabel`, `ylabel` | [Title and axis labels](#title-and-axis-labels) | | let the grid lay the figures out | a flat list, `max_cols` | [Automatic layout](#automatic-layout) | | set the rows myself | nested rows | [Nested rows](#nested-rows) | | leave a cell blank | `None` in a row | [Nested rows](#nested-rows) | | resize the figure | `figsize` | [Figure size](#figure-size) | | compare the cells on one scale | `sharex`, `sharey` | [Sharing axes](#sharing-axes) | | span a figure across rows or columns | per-figure `"layout_spec"` | [Irregular layouts](#irregular-layouts) | | use a grid or a panel as one cell | nest `Grid` and `Panel` figures | [Nesting grids and panels](#nesting-grids-and-panels) | | save the grid to a file | `save_figure` | [Saving the Chart as an Image](#saving-the-chart-as-an-image) | The full list of parameters is in the [datachart.utils.Grid](https://eriknovak.github.io/datachart/0.9.0/references/utils/#datachart.utils.Grid) function. The look of each figure — colors, line widths, markers, labels — is set on the chart itself through its attributes and `style`; see the guide of each chart in the [Charts](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/charts/index.md) section. ### Title and axis labels To add a title over the whole grid, add the `title` attribute. The heading of each cell comes from its own chart — the `title` given to the chart function — so the grid title names the composition and the cell headings name the parts: ``` Grid( [temperature, precipitation], # add the title of the whole grid title="Climate of Ljubljana", ).show() ``` When every cell measures the same quantities, labeling each one repeats the same words. Add the `xlabel` and `ylabel` attributes instead: each is drawn once for the whole grid — below the bottom row and to the left of the leftmost column — while the cells keep their own headings. A nested grid keeps its own labels inside its cell. ``` Grid( [temperature, precipitation], title="Climate of Ljubljana", # one label per axis for the whole grid xlabel="Month", ylabel="Monthly normal", ).show() ``` ### Automatic layout With a flat list, the grid computes the layout on its own: the `max_cols` attribute caps the number of columns (at 4 by default), and the number of rows follows from the number of figures. Cells left over in the last row stay hidden. The four charts of the dataset with `max_cols=2` make a 2×2 grid: ``` Grid( [temperature, precipitation, sunshine, humidity], # cap the automatic layout at two columns max_cols=2, title="Climate of Ljubljana", ).show() ``` ### Nested rows To set the layout yourself, pass nested rows: every inner list is one row of the grid, in the order given. Rows need not be equally long — the cells of a shorter row stretch to fill the width — so a single-figure row becomes a full-width headline: ``` Grid( [ # the first row: one figure stretched across the full width [temperature], # the second row: three figures side by side [precipitation, sunshine, humidity], ], title="Climate of Ljubljana", ).show() ``` To leave a cell empty instead of stretching its neighbors, put `None` in its place: ``` Grid( [ [temperature, precipitation], # None keeps the second cell of the row blank [sunshine, None], ], title="Climate of Ljubljana", ).show() ``` ### Figure size To change the figure size, add the `figsize` attribute. The `figsize` attribute can be a tuple (width, height), values are in inches; when it is not given, it is calculated from the size of the first figure and the shape of the grid. The `datachart` package provides a [datachart.constants.FIG_SIZE](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.FIG_SIZE) constant, which contains the most common figure sizes: ``` from datachart.constants import FIG_SIZE ``` ``` Grid( [temperature, precipitation, sunshine, humidity], max_cols=2, title="Climate of Ljubljana", # add to determine the figure size figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` ### Sharing axes Each cell scales its axes to its own data. That serves unrelated quantities, but misleads when the cells hold the same quantity: drawn with free y-axes, the temperatures of the three stations all fill their cell, and the curves look interchangeable — ``` station_charts = [ LineChart(data=[{"x": i, "y": value} for i, value in enumerate(temps)], title=station) for station, temps in STATION_TEMPERATURES.items() ] Grid( station_charts, title="Mean monthly temperature (°C)", figsize=FIG_SIZE.FULL_SHORT, ).show() ``` — although Kredarica, an alpine station at 2,514 m, is some fifteen degrees colder than the coast. To read every cell against the same scale, add the `sharex` and `sharey` attributes: `sharex=True` shares the x-axis across the cells and `sharey=True` the y-axis. In an automatic (flat-list) grid, shared axes are also labeled only once per row or column, which declutters the cells: ``` Grid( station_charts, # read every cell against the same y-axis sharey=True, title="Mean monthly temperature (°C)", figsize=FIG_SIZE.FULL_SHORT, ).show() ``` ### Irregular layouts Nested rows cover most layouts; for a figure that spans several rows or columns, wrap the figures of a flat list in dictionaries and add the `"layout_spec"` option — a dict with the `"row"` and `"col"` of the cell and its `"rowspan"` and `"colspan"`. Nested rows and `layout_spec` cannot be mixed in one call. Here the temperature takes the left column top to bottom, with two charts stacked to its right: ``` Grid( [ # the temperature spans both rows of the left column {"figure": temperature, "layout_spec": {"row": 0, "col": 0, "rowspan": 2, "colspan": 1}}, {"figure": precipitation, "layout_spec": {"row": 0, "col": 1, "rowspan": 1, "colspan": 1}}, {"figure": sunshine, "layout_spec": {"row": 1, "col": 1, "rowspan": 1, "colspan": 1}}, ], title="Climate of Ljubljana", ).show() ``` ### Nesting grids and panels Grid figures nest: a grid placed in a cell occupies exactly that cell and rebuilds its layout inside it, to any depth. The nested grid keeps its own title — drawn as a heading spanning its subgrid — and its own `sharex`/`sharey` among its own cells, while the outer grid's settings apply only to its top-level cells. [Panel](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/utility/panel/index.md) figures nest the same way, so an overlay can take one cell of a grid; the reverse — a grid inside a panel — raises a `ValueError`. ``` from datachart.utils import Panel # a panel as one cell: the climograph of the Panel guide climograph = Panel( [ {"figure": precipitation, "legend_label": "Precipitation (mm)"}, {"figure": temperature, "legend_label": "Temperature (°C)"}, ], show_legend=True, ) # a grid as another cell, with its own title and shared x-axis sun_and_moisture = Grid( [[sunshine], [humidity]], title="Sun and moisture", sharex=True, ) Grid( [[climograph, sun_and_moisture]], title="Climate of Ljubljana", figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` ## Saving the Chart as an Image To save the grid as an image, use the [datachart.utils.save_figure](https://eriknovak.github.io/datachart/0.9.0/references/utils/#datachart.utils.save_figure) function. ``` from datachart.utils import save_figure ``` ``` figure = Grid( [temperature, precipitation, sunshine, humidity], max_cols=2, title="Climate of Ljubljana", figsize=FIG_SIZE.FULL_MEDIUM, ) save_figure(figure, "./fig_grid.png", dpi=300) ``` The figure should be saved in the current working directory. ## Real-World Examples The following examples put the features above to work on realistic data. Each one states what its data is and where it comes from; the data itself lives in a hidden cell. The chart functions they arrange are imported as needed; any chart from the [Charts](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/charts/index.md) guides can take a cell of a grid. ### Example 1: Multi-Site Clinical Trial Dashboard (Nested Rows) `recruitment` holds the illustrative cumulative number of patients recruited over 12 weeks at four trial sites, `adverse_events` the number of adverse events reported per site, and `retention` the share of recruited patients still enrolled (in %). The recruitment trend is the headline of the dashboard, so nested rows stretch it across the full top row — one multi-series line chart with its own legend — with the two per-site summaries side by side below it. ``` recruitment = LineChart( data=recruitment_data, subtitle=SITES, title="Cumulative recruitment (patients)", xlabel="Week", show_legend=True, ) adverse = BarChart(data=adverse_data, title="Adverse events") retention = BarChart(data=retention_data, title="Retention (%)") Grid( [ # the headline chart stretches across the full top row [recruitment], [adverse, retention], ], title="Multi-site clinical trial", figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` ### Example 2: Lab Sensor Monitoring (Shared Axes) `sensors` holds 48 hours of illustrative temperature readings from six sensors — three lab rooms kept at 21 °C, two incubators at 37 °C, and a cold room at 4 °C — drawn from a seeded generator around each setpoint. All six measure the same quantity, so `sharex` and `sharey` put them on one scale: the three regimes separate at a glance, and any sensor drifting from its band would stand out immediately. ``` Grid( [LineChart(data=data, title=location) for location, data in sensors.items()], max_cols=3, # one scale for all sensors: the three temperature regimes separate sharex=True, sharey=True, title="Temperature sensors (°C, 48 h)", figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` ### Example 3: Chromatography Run Report (Irregular Layout) `chromatogram` holds an illustrative chromatogram — the detector absorbance over 30 minutes with three seeded peaks, `calibration` the peak area of five standards of known concentration, and `peak_areas` the integrated area of the three sample peaks. The chromatogram is the record of the run, so a `"layout_spec"` spans it across both rows of the left column, with the calibration line and the quantification stacked to its right. ``` from datachart.charts import ScatterChart Grid( [ # the chromatogram spans both rows of the left column { "figure": LineChart( data=chromatogram, title="Chromatogram", xlabel="Retention time (min)", ylabel="Absorbance (AU)", ), "layout_spec": {"row": 0, "col": 0, "rowspan": 2, "colspan": 2}, }, { "figure": ScatterChart( data=calibration, title="Calibration", xlabel="Concentration (μM)", ylabel="Peak area", ), "layout_spec": {"row": 0, "col": 2, "rowspan": 1, "colspan": 1}, }, { "figure": BarChart(data=peak_areas, title="Peak areas"), "layout_spec": {"row": 1, "col": 2, "rowspan": 1, "colspan": 1}, }, ], title="Chromatography run report", figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` ### Example 4: City Climate Small Multiples `city_temperatures` holds the mean monthly temperature (in °C) of eight European cities, rounded from the published climate normals. Small multiples — one small cell per group, identical axes everywhere — let the eye sweep across many groups and compare shapes rather than read single values; `sharex` and `sharey` are what make the cells comparable. Here the shape is the climate: maritime cities (Reykjavík, London, Lisbon) draw flat curves, continental ones (Helsinki, Moscow) wide seasonal swings, and Mediterranean ones (Madrid, Athens) sit high on the shared scale — all visible at a glance, from cells far too small to read a single degree off. ``` Grid( [LineChart(data=data, title=city) for city, data in city_data.items()], max_cols=4, # identical axes make the eight cells comparable sharex=True, sharey=True, title="Mean monthly temperature", # the shared quantity is named once, not in every cell xlabel="Month", ylabel="Temperature (°C)", figsize=FIG_SIZE.FULL_MEDIUM, ).show() ``` # Text Annotations This section showcases text annotations. It contains examples of how to attach explanatory text to charts — naming a series, explaining an outlier, calling out a point — with the `texts` parameter that every chart function accepts, and how to add texts to an already rendered figure with the [datachart.utils.Annotate](https://eriknovak.github.io/datachart/0.9.0/references/utils/#datachart.utils.Annotate) function. Looking for a specific customization? Jump straight to the [quick reference](#customizing-the-texts), which maps common tasks to the attribute or style key that does the job. ## Text Input Attributes Every chart function takes a `texts` parameter: a single text annotation or a list of them. Each annotation is a dictionary: ``` { "text": str, # The annotation text (required) "x": Union[int, float], # The x-axis position of the text "y": Union[int, float], # The y-axis position of the text "coords": Optional[str], # The coordinate system of the position: "data" (default) or "axes" "target": Optional[tuple], # The (x, y) data point the connector points to; no target, no connector "style": Optional[dict], # Per-text style overrides (the plot_text_* style attributes) } ``` With multiple charts drawn as subplots, a list of lists assigns the annotations per chart, exactly as `vlines` and `hlines` do. For the full definitions, see the [datachart.typings.TextAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.TextAttrs) and [datachart.typings.TextStyleAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.TextStyleAttrs) typings. ``` from datachart.charts import BarChart, LineChart from datachart.utils import Annotate, Panel from datachart.constants import ARROW_STYLE, FIG_SIZE ``` ## Basics The examples in this guide share one dataset: the monthly climate normals of Ljubljana's weather station — the mean temperature (in °C) and the total precipitation (in mm) of each month, rounded from the published values. The data lives in a hidden cell. A text annotation is declared with the chart. By default its position is in data coordinates, and giving it a `target` draws a connector from the text to that data point: ``` LineChart( data=temperature_data, title="Climate of Ljubljana", xlabel="Month", ylabel="Temperature (°C)", figsize=FIG_SIZE.FULL_SHORT, xticks=list(range(12)), xticklabels=MONTHS, texts={ "text": "July is the warmest month", "x": 0.3, "y": 17.5, "target": (6, 22.0), }, ).show() ``` Because the annotation is part of the chart declaration — not an afterthought drawn onto the figure — it follows the active theme and survives figure composition: composing the figure with [Panel](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/utility/panel/index.md) or [Grid](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/utility/grid/index.md) redraws the annotation with the chart. ## Customizing the Texts Every customization is either an attribute of the annotation dictionary or a `plot_text_*` style key in its `style` dictionary. The table maps common tasks to the one you need and links to the subsection that shows it. | I want to… | Use | See | | --------------------------------------------- | ------------------------------------------- | ----------------------------------------------------------- | | place a note at a data point | `x`, `y` (data coordinates by default) | [Placement and coordinates](#placement-and-coordinates) | | pin a note to the figure, whatever the limits | `"coords": "axes"` | [Placement and coordinates](#placement-and-coordinates) | | point at a data point | `target` | [Placement and coordinates](#placement-and-coordinates) | | change the connector look | `"style": {"plot_text_arrow_style": ...}` | [Connector looks](#connector-looks) | | restyle the text or its box | the `plot_text_*` keys in `style` | [Text and box style](#text-and-box-style) | | hide the background box | `"style": {"plot_text_box_visible": False}` | [Text and box style](#text-and-box-style) | | annotate an already rendered figure | `Annotate(figure, texts)` | [Annotating finished figures](#annotating-finished-figures) | | change the defaults for every chart | the `plot_text_*` configuration keys | [Text configuration](#text-configuration) | ### Placement and Coordinates The text position is interpreted in data coordinates by default, so the note moves with the data. With `"coords": "axes"` the position becomes a fraction of the axes — `(0, 0)` the bottom-left corner, `(1, 1)` the top-right — which keeps the note in place whatever the axis limits are. The `target` is **always** in data coordinates: an axes-placed note still points at its data point. One annotation carries one target; several connectors mean several annotations. ``` LineChart( data=temperature_data, title="Climate of Ljubljana", ylabel="Temperature (°C)", figsize=FIG_SIZE.FULL_SHORT, xticks=list(range(12)), xticklabels=MONTHS, ymax=30, texts=[ # pinned to the axes: stays in the corner whatever the limits {"text": "normals 1991-2020", "x": 0.02, "y": 0.94, "coords": "axes"}, # placed on the axes, pointing at a data point { "text": "below freezing only in January", "x": 0.16, "y": 0.3, "coords": "axes", "target": (0, 0.8), }, ], ).show() ``` ### Connector Looks The connector's look is set by the `plot_text_arrow_style` style key, whose values are named by the [datachart.constants.ARROW_STYLE](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.ARROW_STYLE) constant. Each value is a complete look — the line shape, its curvature, and the gap on the text side. The default is the curved plain line, `ARROW_STYLE.CURVE`: ``` looks = [ (ARROW_STYLE.CURVE, 0.03, 0.62), (ARROW_STYLE.CURVE_ARROW, 0.28, 0.9), (ARROW_STYLE.TOUCHING, 0.7, 0.88), (ARROW_STYLE.ARROW, 0.66, 0.3), ] LineChart( data=temperature_data, title="The connector looks", ylabel="Temperature (°C)", figsize=FIG_SIZE.FULL_MEDIUM, xticks=list(range(12)), xticklabels=MONTHS, texts=[ { "text": look, "x": x, "y": y, "coords": "axes", "target": (index * 3 + 1, TEMPERATURE[index * 3 + 1]), "style": {"plot_text_arrow_style": look}, } for index, (look, x, y) in enumerate(looks) ], ).show() ``` The connector also places itself: it leaves the box from the side facing the target, a curved look bows toward the side with the most open space — away from the chart's data — and a connector shorter than its own gaps straightens, then disappears entirely. A look is a starting point, not a straitjacket: the individual `plot_text_arrow_*` keys override single properties of it — `plot_text_arrow_curve` pins the bow (side and depth) exactly, and `plot_text_arrow_color` and `plot_text_arrow_width` restyle the stroke. A raw matplotlib arrow style string (such as `"-|>"`) is also accepted. ### Text and Box Style The text and its background box are styled by the `plot_text_*` keys of the annotation's `style` dictionary — the same keys that live in every theme, so a per-text override changes exactly one annotation. The box can be hidden entirely for a quieter, label-like note: ``` LineChart( data=temperature_data, title="Climate of Ljubljana", ylabel="Temperature (°C)", figsize=FIG_SIZE.FULL_SHORT, xticks=list(range(12)), xticklabels=MONTHS, texts=[ # a quiet, boxless comment { "text": "mean monthly temperature", "x": 0.02, "y": 0.92, "coords": "axes", "style": {"plot_text_box_visible": False, "plot_text_color": "#7F8C8D"}, }, # a loud one, restyled box and text { "text": "summer plateau", "x": 0.48, "y": 0.6, "coords": "axes", "target": (7, 21.4), "style": { "plot_text_weight": "bold", "plot_text_box_facecolor": "#FFF6E0", "plot_text_box_edgecolor": "#F28E2B", "plot_text_arrow_color": "#F28E2B", }, }, ], ).show() ``` ## Annotating Finished Figures A figure that is already rendered — by a chart function or by [Panel](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/utility/panel/index.md) — is annotated post hoc with the [datachart.utils.Annotate](https://eriknovak.github.io/datachart/0.9.0/references/utils/#datachart.utils.Annotate) function. It returns a **new** figure with the texts added, leaving the source figure untouched; the annotations become part of the new figure's chart declaration, so they compose onward like any other. Grid figures and multi-subplot figures are rejected: annotate the sources before composing them. ``` precipitation = BarChart(data=precipitation_data, subtitle="Precipitation (mm)") temperature = LineChart(data=temperature_data, subtitle="Temperature (°C)") climograph = Panel( [precipitation, temperature], title="Climate of Ljubljana", xlabel="Month", ylabel_left="Precipitation (mm)", ylabel_right="Temperature (°C)", figsize=FIG_SIZE.FULL_SHORT, show_legend=True, ) Annotate( climograph, texts={ "text": "autumn rains peak", "x": 0.40, "y": 0.91, "coords": "axes", "target": (8, 147), }, ).show() ``` ## Text Configuration The defaults every annotation falls back on — the font, the box face and edge, the connector look and color — are part of the global configuration, under the keys that start with `plot_text_`. Every predefined theme sets them to match its own look, and they are changed like any other setting, through [datachart.config.config.update_config](https://eriknovak.github.io/datachart/0.9.0/references/config/#datachart.config.Config.update_config); see the [Config](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/styling/config/index.md) guide for the configuration system as a whole. The current keys and their values in the active theme are: ``` from datachart.config import config {key: value for key, value in config.config.items() if key.startswith("plot_text_")} ``` A `plot_text_*` key in an annotation's `style` dictionary always wins over the configuration. The configuration is the place for a default that should hold for every annotation of a document. # Statistics This section showcases the utility functions found in the [datachart.utils.stats](https://eriknovak.github.io/datachart/0.9.0/references/utils/stats) module. Let us start by importing the supporting libraries: ``` import random ``` ## Statistics Submodule The [dataset.utils.stats](https://eriknovak.github.io/datachart/0.9.0/references/utils/stats) submodule contains functions for calculating statistics. To showcase its use, let us create a list of random numbers: ``` random_values = random.sample(range(1, 100), 10) random_values ``` Let us now showcase the functions in the `stats` module. ### Count The `count` function returns the number of elements in the list. ``` from datachart.utils.stats import count ``` ``` count(random_values) ``` ### Sum The `sum_values` function returns the sum of all values in the list. ``` from datachart.utils.stats import sum_values ``` ``` sum_values(random_values) ``` ### Mean The `mean` function returns the mean of the values. ``` from datachart.utils.stats import mean ``` ``` mean(random_values) ``` ### Median The `median` function returns the median of the values. ``` from datachart.utils.stats import median ``` ``` median(random_values) ``` ### Standard Deviation The `stdev` function returns the standard deviation of the values. ``` from datachart.utils.stats import stdev ``` ``` stdev(random_values) ``` ### Variance The `variance` function returns the variance of the values. Variance is the square of the standard deviation. ``` from datachart.utils.stats import variance ``` ``` variance(random_values) ``` ### Quantile The `quantile` function returns the quantile of the values. ``` from datachart.utils.stats import quantile ``` Show the 25th quantile: ``` quantile(random_values, 25) ``` Show the 75th quantile: ``` quantile(random_values, 75) ``` ### Interquartile Range (IQR) The `iqr` function returns the interquartile range, which is the difference between the 75th percentile (Q3) and 25th percentile (Q1). It is useful for identifying outliers and understanding the spread of the middle 50% of the data. ``` from datachart.utils.stats import iqr ``` ``` iqr(random_values) ``` ### Minimum The `minimum` function returns the minimum of the values. ``` from datachart.utils.stats import minimum ``` ``` minimum(random_values) ``` ### Maximum The `maximum` function returns the maximum of the values. ``` from datachart.utils.stats import maximum ``` ``` maximum(random_values) ``` ### Correlation The `correlation` function calculates the Pearson correlation coefficient between two lists of values. It measures the linear relationship between the datasets, ranging from -1 (perfect negative correlation) to 1 (perfect positive correlation). ``` from datachart.utils.stats import correlation ``` Create a second list of random values to compare: ``` random_values_2 = random.sample(range(1, 100), 10) random_values_2 ``` ``` correlation(random_values, random_values_2) ``` ### Kernel density estimate The `kde1d` function estimates the density of a list of values with a Gaussian kernel and returns it as `{x, y}` points, ready to draw as a [datachart.charts.LineChart](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.LineChart) — over a density [datachart.charts.Histogram](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.Histogram) of the same values, for instance. The `bandwidth` is a rule of [datachart.constants.BANDWIDTH](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.BANDWIDTH) or a scalar factor, `gridsize` the number of points, and `cut` how many bandwidths the curve extends past the extremes (`xlim` fixes the range instead). ``` from datachart.utils.stats import kde1d ``` ``` curve = kde1d(random_values, gridsize=5) curve ``` The `kde2d` function does the same for `(x, y)` points and returns the `{x, y, z}` surface a [datachart.charts.ContourChart](https://eriknovak.github.io/datachart/0.9.0/references/charts/#datachart.charts.ContourChart) draws — the density contours of a scattered dataset. The `gridsize` can be one number or an `(x, y)` pair of column and row counts, and `xlim`/`ylim` fix the grid so several surfaces share it. ``` from datachart.utils.stats import kde2d ``` ``` surface = kde2d(random_values, random_values_2, gridsize=3) surface ``` Under development This theme is still under development. If you are interested in improving it, please let us know. # Styling # Styling The styling guides cover everything that controls how charts look: the global configuration, the predefined themes and how to create your own, emphasis for highlighting data, and the available colormaps. | Guide | Description | | --------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- | | [config](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/styling/config/index.md) | Showcases the use of the `config` module to customize the global style. | | [themes](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/styling/themes/index.md) | How to apply the predefined themes and create your own. | | [theme gallery](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/styling/theme-gallery/index.md) | Showcases the themes across basic charts and research-style figures. | | [highlighting](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/styling/highlighting/index.md) | Emphasizing and muting data series with the `emphasis` option. | | [colormaps](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/styling/colormaps/index.md) | Showcases the existing colormaps available via the `COLORS` constant. | # Config This section showcases how to use the [datachart.config](https://eriknovak.github.io/datachart/0.9.0/references/config/index.md) module to customize the global style of the `datachart` package. Let's start by importing the necessary functions to help us work with the `datachart.config` module. ``` from datachart.config import config ``` The `config` instance is a global configuration that the users can interact with. It allows them to customize the global style of the `datachart` package. Furthemore, the instance is of the [datachart.config.Config](https://eriknovak.github.io/datachart/0.9.0/references/config/#datachart.config.Config) class. Under development This theme is still under development. If you are interested in improving it, please let us know. # Themes This section showcases the themes found in the [datachart.themes](https://eriknovak.github.io/datachart/0.9.0/references/themes/index.md) module and how to customize them. Six predefined themes are available: `DEFAULT`, `GREYSCALE`, `MINIMAL`, `MATERIAL`, `INK`, and `HATCH` — each named for its visual trait — see the [Theme Gallery](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/styling/theme-gallery/index.md) for every theme rendered across the full range of chart types. Themes may also carry defaults for chart settings ([ThemeDefaultAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.ThemeDefaultAttrs)): `chart_default_show_grid` supplies the grid when a chart call leaves `show_grid` unset (every predefined theme ships a muted `"y"` grid), `chart_default_show_values` does the same for bar value labels (on in `MINIMAL`, `MATERIAL`, and `HATCH`), and `plot_hatch_cycle` assigns hatch patterns per bar/histogram series (only `HATCH` ships one). An explicit chart setting always wins over the theme default. Let's start by importing the necessary functions to help us work with the `datachart.themes` module. ``` import random import numpy as np from datachart.charts import ( BarChart, LineChart, ScatterChart, ) from datachart.constants import FIG_SIZE, LINE_STYLE, SHOW_GRID ``` ``` from datachart.config import config ``` To get the supported themes, you have to load them from the `datachart.themes` module. ``` from datachart.constants import THEME ``` The [datachart.constants.THEME](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.THEME) module contains all the predefined themes. ## Applying a Theme Applying a theme replaces the whole global configuration, so set it before building the charts it should style: ``` config.set_theme(THEME.MINIMAL) BarChart( data=[{"label": f"cat{idx}", "y": 10 + 5 * idx} for idx in range(5)], title="Bar chart under THEME.MINIMAL", figsize=FIG_SIZE.FULL_SHORT, ).show() ``` To return to the default theme, reset the configuration: ``` config.reset_config() ``` See the [Theme Gallery](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/styling/theme-gallery/index.md) for every predefined theme rendered across the full range of chart types. ## Creating Your Own Theme Adding the theme to the `datachart` package If you think the theme would be useful and would like it to be added to the `datachart` package, please create a pull request to add it. The user can create their own theme by defining a new dictionary that has the same structure as the [StyleAttrs](https://eriknovak.github.io/datachart/0.9.0/references/typings/#datachart.typings.StyleAttrs) type. For instance, one can copy the bellow definition of the default theme and modify the values to customize the theme. ``` from datachart.typings import StyleAttrs from datachart.constants import COLORS, FONT_STYLE, FONT_WEIGHT, LINE_DRAW_STYLE ``` ``` CUSTOM_THEME: StyleAttrs = { "color_general_singular": COLORS.Blues, "color_general_multiple": COLORS.Spectral, "font_general_family": "sans-serif", "font_general_sansserif": ["Helvetica", "Arial"], "font_general_color": "#000000", "font_general_size": 11, "font_general_style": FONT_STYLE.NORMAL, "font_general_weight": FONT_WEIGHT.NORMAL, "font_title_size": 12, "font_title_color": "#000000", "font_title_style": FONT_STYLE.NORMAL, "font_title_weight": FONT_WEIGHT.NORMAL, "font_subtitle_size": 11, "font_subtitle_color": "#000000", "font_subtitle_style": FONT_STYLE.NORMAL, "font_subtitle_weight": FONT_WEIGHT.NORMAL, "font_xlabel_size": 10, "font_xlabel_color": "#000000", "font_xlabel_style": FONT_STYLE.NORMAL, "font_xlabel_weight": FONT_WEIGHT.NORMAL, "font_ylabel_size": 10, "font_ylabel_color": "#000000", "font_ylabel_style": FONT_STYLE.NORMAL, "font_ylabel_weight": FONT_WEIGHT.NORMAL, "axes_spines_top_visible": True, "axes_spines_right_visible": True, "axes_spines_bottom_visible": True, "axes_spines_left_visible": True, "axes_spines_width": 0.5, "axes_spines_zorder": 100, "axes_ticks_length": 2, "axes_ticks_label_size": 9, "plot_legend_shadow": False, "plot_legend_frameon": True, "plot_legend_alignment": "left", "plot_legend_font_size": 9, "plot_legend_title_size": 10, "plot_legend_label_color": "#000000", "plot_area_alpha": 0.3, "plot_area_color": None, "plot_area_linewidth": 0, "plot_area_hatch": None, "plot_area_zorder": 3, "plot_grid_alpha": 1, "plot_grid_color": "#E6E6E6", "plot_grid_linewidth": 0.5, "plot_grid_linestyle": LINE_STYLE.SOLID, "plot_grid_zorder": 0, "plot_line_color": None, "plot_line_style": LINE_STYLE.SOLID, "plot_line_marker": None, "plot_line_width": 1, "plot_line_alpha": 1.0, "plot_line_drawstyle": LINE_DRAW_STYLE.DEFAULT, "plot_line_zorder": 3, "plot_bar_color": None, "plot_bar_alpha": 1.0, "plot_bar_width": 0.8, "plot_bar_zorder": 3, "plot_bar_hatch": None, "plot_bar_edge_width": 0.5, "plot_bar_edge_color": "#000000", "plot_bar_error_color": "#000000", "plot_hist_color": None, "plot_hist_alpha": 1.0, "plot_hist_zorder": 3, "plot_hist_fill": None, "plot_hist_hatch": None, "plot_hist_type": "bar", "plot_hist_align": "mid", "plot_hist_edge_width": 0.5, "plot_hist_edge_color": "#000000", "plot_vline_color": None, "plot_vline_style": LINE_STYLE.SOLID, "plot_vline_width": 1, "plot_vline_alpha": 1.0, "plot_hline_color": None, "plot_hline_style": LINE_STYLE.SOLID, "plot_hline_width": 1, "plot_hline_alpha": 1.0, "plot_heatmap_cmap": COLORS.Blues, "plot_heatmap_alpha": 1.0, "plot_heatmap_font_size": 9, "plot_heatmap_font_color": "#000000", "plot_heatmap_font_style": FONT_STYLE.NORMAL, "plot_heatmap_font_weight": FONT_WEIGHT.NORMAL, } ``` Once you define the theme, you can use it by updating the `config` module in the following way: ``` from datachart.config import config ``` ``` config.update_config(CUSTOM_THEME) ``` Once you do this, all the plots will use the custom theme. **Bar Chart** ``` BarChart( data=[ {"label": f"xx{id}", "y": 100 * (id + 1) * random.random()} for id in range(10) ], vlines=[{"x": 2 * i} for i in range(1, 4)], hlines={"y": 400}, title="Title", xlabel="the global x-axis label", ylabel="the global y-axis label", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.BOTH, xmin=-0.5, xmax=9.5, ).show() ``` **Line Chart** ``` LineChart( data=[ [{"x": x / 10, "y": np.cos(x / 2)} for x in range(21)], [{"x": x / 10, "y": np.sin(x / 2)} for x in range(21)], ], subtitle=["cosine", "sine"], title="Title", xlabel="the global x-axis label", ylabel="the global y-axis label", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.BOTH, show_legend=True, ).show() ``` **Scatter Chart** ``` chart_data_bubble_hue = [ { "x": random.uniform(0, 10), "y": random.uniform(0, 10), "population": random.uniform(100, 1000), "region": random.choice(["North", "South", "East", "West"]) } for _ in range(50) ] ``` ``` ScatterChart( data=chart_data_bubble_hue, size="population", hue="region", size_range=(30, 250), title="Title", xlabel="the global x-axis label", ylabel="the global y-axis label", figsize=FIG_SIZE.FULL_SHORT, show_grid=SHOW_GRID.BOTH, show_legend=True, ).show() ``` ## Registering a Theme To make a custom theme switchable by name — like the predefined ones — register it with `config.register_theme`. Missing attributes are filled from the default theme, so a partial override works too: ``` config.register_theme("custom", CUSTOM_THEME) config.set_theme("custom") ``` This is also how a private companion package can ship its own themes: register them on import and users apply them with `config.set_theme("")`. ``` config.reset_config() ``` Finally, reset the configuration back to the default theme: ``` config.reset_config() ``` # Theme Gallery This gallery renders the same suite of example charts — the basic chart types plus research-style figures — under each of the six predefined themes, composed into one grid per chart group so the whole suite is visible at a glance. The groups follow the [charts index](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/charts/index.md) — trends and comparisons, distributions, relationships, composition — so each tile sits next to the guide that documents it. The available themes are: | Theme | Character | | ----------------- | ---------------------------------------------------------- | | `THEME.DEFAULT` | Tableau-style categorical palette, open spines, soft grid. | | `THEME.GREYSCALE` | Monochrome, print-friendly. | | `THEME.INK` | Diversified YlGnBu palette with navy ink accents. | | `THEME.MINIMAL` | Accent blue with deep grays, no spines, flat bars. | | `THEME.MATERIAL` | Google palette, bottom spine only, light grid. | | `THEME.HATCH` | Hatch cycle, black edges, dotted grid, value labels. | Themes also carry *defaults for chart settings*: every theme shows a muted y-grid unless a chart call sets `show_grid` itself, `MINIMAL`, `MATERIAL`, and `HATCH` label bar values by default, and `HATCH` hatches bar series via its hatch cycle — which is why the very same chart code below renders with grids, value labels, and hatches that differ per theme. An explicit setting always wins. The small-multiples example is itself a `Grid`; grid figures nest inside `Grid`, so it takes one cell of each theme's composition grid. The sample data shared by every theme suite is defined in a hidden cell. The whole suite is built by one function (in a hidden cell), so every theme renders the exact same chart code — grids, value labels, and hatches come from the theme's own defaults. `pair` supplies the two accent colors used where a chart styles lines explicitly (trend/forecast/walk examples). Intermediate figures that only exist to feed a `Panel` are closed as we go, so only the group grids are displayed. The small-multiples `Grid` nests as one composition cell and rebuilds its own layout there; the nested charts on the block's edges keep their y-axes inline with the gallery column's axes. ## Default The modernized default: Tableau-style palette, white bar edges, open spines, soft y-grid from the theme default. ### Trends and Comparisons ### Distributions ### Relationships ### Flows ### Composition ## Greyscale Monochrome and print-friendly, with the same open spines and muted grid treatment. ### Trends and Comparisons ### Distributions ### Relationships ### Flows ### Composition ## Ink The diversified YlGnBu palette (`COLORS.PaperYlGnBu`) with navy ink edges, print-ready. ### Trends and Comparisons ### Distributions ### Relationships ### Flows ### Composition ## Minimal Accent blue with deep grays, no spines or tick marks, flat bars — and bar value labels on by default. ### Trends and Comparisons ### Distributions ### Relationships ### Flows ### Composition ## Material The Google palette with a bottom spine only and a light solid grid; value labels default to on. ### Trends and Comparisons ### Distributions ### Relationships ### Flows ### Composition ## Hatch Black edges, dotted grid — and the hatch cycle (`""`, `"//"`, `".."`) applied per bar series, so grouped bars stay distinguishable in black-and-white print. ### Trends and Comparisons ### Distributions ### Relationships ### Flows ### Composition ______________________________________________________________________ Applying a theme replaces the whole global configuration, so remember to call `config.set_theme(...)` (or `config.reset_config()`) before building the charts it should style. See the [themes how-to](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/styling/themes/index.md) for customizing themes attribute by attribute. ``` config.reset_config() ``` # Highlighting When a figure carries many series, the story is usually about one of them: one model run among its competitors, one cohort inside the population, one trend over raw observations. The `emphasis` parameter expresses that relationship directly — per chart, not via global styling: - `"background"` mutes a series: it takes the active theme's `muted_color` at `muted_alpha`, gets thinner strokes, drops behind the other series, claims no color-cycle slot, and is excluded from the legend. - `"highlight"` bolds a series and brings it to the front of the data layers (never above axes or reference lines). It keeps its theme-assigned color and legend entry. - Leaving it unset (`None`) draws the series exactly as before. `emphasis` is accepted by `LineChart`, `BarChart`, `ScatterChart`, `Histogram`, `ParallelCoords` (per data row), and `BoxPlot` (per box label), and as a per-figure `"emphasis"` option in `Panel`. Because muting derives from the theme's `muted_color`/`muted_alpha` attributes, background series harmonize with whatever theme is active. The role strings are also available as constants: `datachart.constants.EMPHASIS.BACKGROUND` and `EMPHASIS.HIGHLIGHT`. ``` import numpy as np from datachart.charts import ( BoxPlot, Histogram, LineChart, ParallelCoords, ScatterChart, ) from datachart.utils import Panel from datachart.config import config from datachart.constants import THEME ``` ## One Walk Among Many The `emphasis` list aligns with the charts, like `style` and `subtitle`. Background walks fade into context; the highlighted walk keeps its cycle color and doubles its line width. Only emphasized-or-unset series appear in the legend. ``` def walk(seed, n=60): rng = np.random.RandomState(seed) return [{"x": i, "y": float(v)} for i, v in enumerate(np.cumsum(rng.randn(n)))] walks = [walk(seed) for seed in range(6)] figure = LineChart( data=walks, subtitle=[f"run {i}" for i in range(6)], emphasis=["background", "background", "background", None, "highlight", "background"], show_legend=True, title="One walk among many", ) figure.show() ``` ## The Same Figure Under Another Theme Muting is defined by the theme's `muted_color` and `muted_alpha` attributes, so the same chart code stays harmonious under any theme — no hand-picked greys. ``` config.set_theme(THEME.MATERIAL) figure = LineChart( data=walks, subtitle=[f"run {i}" for i in range(6)], emphasis=["background", "background", "background", None, "highlight", "background"], show_legend=True, title="One walk among many (MATERIAL)", ) figure.show() config.reset_config() ``` ## A Cohort Inside a Scatter Cloud A highlighted scatter series keeps its marker size but gains a contrasting edge; the background cloud recedes without disappearing. ``` rng = np.random.RandomState(3) population = [ {"x": float(x), "y": float(x * 0.8 + rng.randn() * 2)} for x in rng.rand(80) * 20 ] cohort = [ {"x": float(x), "y": float(x * 1.4 + 4 + rng.randn())} for x in rng.rand(20) * 20 ] figure = ScatterChart( data=[population, cohort], subtitle=["population", "cohort"], emphasis=["background", "highlight"], show_legend=True, title="Cohort against the population", ) figure.show() ``` ## Best Runs in Parallel Coordinates For `ParallelCoords` the `emphasis` list aligns with the data **rows**. Highlighted rows come forward but stay below the axis furniture, so the axis lines and tick labels remain readable. ``` rng = np.random.RandomState(11) runs = [ { "speed": float(rng.rand() * 10), "cost": float(rng.rand() * 100), "score": float(rng.rand()), } for _ in range(15) ] best = sorted(range(len(runs)), key=lambda i: runs[i]["score"])[-2:] figure = ParallelCoords( data=runs, dimensions=["speed", "cost", "score"], emphasis=["highlight" if i in best else "background" for i in range(len(runs))], title="Best runs", ) figure.show() ``` ## A Cohort Against a Reference Distribution Multi-series histograms normally draw stacked. Stacking a muted background is meaningless, so as soon as any series carries an emphasis role the histograms draw individually overlaid — on shared bins, with the background distribution behind the cohort. ``` rng = np.random.RandomState(7) reference = [{"x": float(v)} for v in rng.randn(400) * 1.4 + 0.5] cohort = [{"x": float(v)} for v in rng.randn(160) * 0.8 + 2.0] figure = Histogram( data=[reference, cohort], subtitle=["reference", "cohort"], emphasis=["background", None], num_bins=18, show_legend=True, title="Cohort vs reference", ) figure.show() ``` ## Per-Label Emphasis in a Box Plot Box charts never overlay, so their `emphasis` aligns with the box **labels** of one call. Whiskers, caps, medians, and outliers mute together with their box; a highlighted box gets bolder edges and a bolder median. ``` rng = np.random.RandomState(9) data = [ {"label": lab, "value": float(v + off)} for lab, off in [("A", 0.0), ("B", 2.0), ("C", 1.0), ("D", 3.0)] for v in rng.randn(30) ] figure = BoxPlot( data=data, emphasis=["background", None, "highlight", "background"], title="One group under scrutiny", ) figure.show() ``` ## Composing Context and Focus with Panel `Panel` accepts a per-figure `"emphasis"` option next to `y_axis`, `z_order`, and `legend_label`. The role applies to every layer of that figure — here the raw observations become context under a highlighted trend. The muted figure drops out of the legend automatically. ``` rng = np.random.RandomState(5) observations = [{"x": float(v)} for v in rng.randn(400)] xs = np.linspace(-3.5, 3.5, 60) trend = [{"x": float(x), "y": float(60 * np.exp(-x * x / 2))} for x in xs] hist_fig = Histogram(data=observations, num_bins=24, subtitle="observations") trend_fig = LineChart(data=trend, subtitle="trend") figure = Panel( [ {"figure": hist_fig, "emphasis": "background"}, {"figure": trend_fig, "emphasis": "highlight"}, ], title="Trend over observations", show_legend=True, ) figure.show() ``` Composed parallel-coordinates figures also normalize against shared per-dimension ranges inside a `Panel`, so a muted context figure and a highlighted runs figure line up on the same axis scales. # Colormaps This section shows the different colormaps that are available in `datachart` module. The colormaps are used to customize the colors of the charts. `datachart` uses [pypalettes](https://y-sunflower.github.io/pypalettes/) under the hood, giving you access to **2500+ color palettes**. A curated selection of popular palettes is available via the [datachart.constants.COLORS](https://eriknovak.github.io/datachart/0.9.0/references/constants/#datachart.constants.COLORS) constant, but you can use any valid pypalettes palette name directly. The predefined palettes include: - **Sequential**: `Blues`, `Greens`, `Oranges`, `Purples`, `Reds`, `Sunset2`, `YlGnBu`, `YlOrRd`, `PuBuGn` - **Diverging**: `RdBu`, `BrBG`, `PuOr`, `Spectral`, `RdYlBu`, `RdYlGn` - **Categorical**: `Pastel`, `Set2`, `Accent`, `Dark2`, `Paired`, `Set1` - **Grayscale**: `Greys` (print-friendly) - **Color-blind friendly**: `Viridis`, `Cividis`, `Inferno`, `Plasma` ``` from typing import List, Tuple import numpy as np import matplotlib.pyplot as plt ``` ``` from datachart.constants import COLORS from datachart.utils._internal.colors import get_colormap ``` ``` def plot_color_gradients(cmap_list: List[Tuple[str, str]], n_sections: int = 256): """Plots the gradients of multiple colormaps. Args: cmap_list (List[Tuple[str, str]]): The list of colormaps to plot. n_sections (int, optional): The number of sections to plot. Defaults to 256. """ gradient = np.linspace(0, 1, n_sections) gradient = np.vstack((gradient, gradient)) # Create figure and adjust figure height to number of colormaps nrows = len(cmap_list) figh = 0.35 + 0.15 + (nrows + (nrows - 1) * 0.1) * 0.22 fig, axs = plt.subplots(nrows=nrows + 1, figsize=(8.2, figh)) fig.subplots_adjust(top=1 - 0.35 / figh, bottom=0.15 / figh, left=0.2, right=0.99) axs[0].set_title(f"datachart colormaps", fontsize=14) for ax, (name, value) in zip(axs, cmap_list): ax.imshow(gradient, aspect="auto", cmap=get_colormap(value)) ax.text( -0.01, 0.5, name, va="center", ha="right", fontsize=10, transform=ax.transAxes, ) # Turn off *all* ticks & spines, not just the ones with colormaps. for ax in axs: ax.set_axis_off() ``` ``` cmap_list = [ ("COLORS.Blues", COLORS.Blues), ("COLORS.Greens", COLORS.Greens), ("COLORS.Oranges", COLORS.Oranges), ("COLORS.Purples", COLORS.Purples), ("COLORS.Reds", COLORS.Reds), ("COLORS.Sunset2", COLORS.Sunset2), ("COLORS.YlGnBu", COLORS.YlGnBu), ("COLORS.YlOrRd", COLORS.YlOrRd), ("COLORS.PuBuGn", COLORS.PuBuGn), ("COLORS.RdBu", COLORS.RdBu), ("COLORS.BrBG", COLORS.BrBG), ("COLORS.PuOr", COLORS.PuOr), ("COLORS.Spectral", COLORS.Spectral), ("COLORS.RdYlBu", COLORS.RdYlBu), ("COLORS.RdYlGn", COLORS.RdYlGn), ("COLORS.Pastel", COLORS.Pastel), ("COLORS.Set2", COLORS.Set2), ("COLORS.Accent", COLORS.Accent), ("COLORS.Dark2", COLORS.Dark2), ("COLORS.Paired", COLORS.Paired), ("COLORS.Set1", COLORS.Set1), ("COLORS.Greys", COLORS.Greys), ("COLORS.Viridis", COLORS.Viridis), ("COLORS.Cividis", COLORS.Cividis), ("COLORS.Inferno", COLORS.Inferno), ("COLORS.Plasma", COLORS.Plasma) ] ``` **Continuous scales** ``` plot_color_gradients(cmap_list=cmap_list) ``` **Discrete scales** ``` # change the number of sections `n_sections` plot_color_gradients(cmap_list=cmap_list, n_sections=10) ``` **Custom datachart palettes** Besides the pypalettes names, `datachart` registers a few palettes of its own, resolved before pypalettes: `COLORS.PaperYlGnBu` (the diversified YlGnBu categorical palette used by the publication theme) and `COLORS.PaperAccent` (a two-color blue/red accent pair). Unlike pypalettes names, these cycle through their exact colors instead of interpolating. ``` plot_color_gradients( cmap_list=[ ("COLORS.PaperYlGnBu", COLORS.PaperYlGnBu), ("COLORS.PaperAccent", COLORS.PaperAccent), ], n_sections=6, ) ``` # API Reference # Datachart Module ## datachart `Datachart` is a data visualization package. The `datachart` package provides utilities for easier data visualization. It provides a set of modules and utilities for data visualization, creating different charts and plots. It also provides methods for defining your own plot styles, and support for calculating the statistics. | MODULE | DESCRIPTION | | ----------- | ----------------------------------------------------------------------------- | | `charts` | The module containing the methods for creating different charts. | | `utils` | The module containing the utility classes and methods. | | `config` | The module containing the utility for customizing the plot styles. | | `themes` | The module containing the predefined style themes. | | `constants` | The module containing the predefined constants used for easier plot creation. | | `typings` | The module containing all of the typings used across the module. | # Charts Module ## datachart.charts Module containing the `charts`. The `charts` module contains the methods to create the plots and figures, grouped by the question they answer. | FUNCTION | DESCRIPTION | | ------------------ | --------------------------------------- | | `LineChart` | Creates the line chart. | | `StackedAreaChart` | Creates the stacked area chart. | | `BarChart` | Creates the bar chart. | | `PyramidChart` | Creates the pyramid chart. | | `RadialChart` | Creates the radial chart. | | `Histogram` | Creates the histogram. | | `BoxPlot` | Creates the box plot. | | `ViolinPlot` | Creates the violin plot. | | `SwarmPlot` | Creates the swarm plot. | | `RaincloudPlot` | Creates the raincloud plot. | | `ScatterChart` | Creates the scatter chart. | | `Heatmap` | Creates the heatmap. | | `ContourChart` | Creates the contour chart. | | `HexbinChart` | Creates the hexbin chart. | | `ParallelCoords` | Creates the parallel coordinates chart. | | `SankeyChart` | Creates the Sankey chart. | ## Trends and Comparisons ### datachart.charts.LineChart ``` LineChart( data: Union[ List[LineDataPointAttrs], List[List[LineDataPointAttrs]], ], *, title: Optional[str] = None, xlabel: Optional[str] = None, ylabel: Optional[str] = None, subtitle: Optional[ Union[str, List[Optional[str]]] ] = None, emphasis: Optional[ Union[EMPHASIS, str, List[Optional[str]]] ] = None, figsize: Optional[ Union[FIG_SIZE, Tuple[float, float]] ] = None, xmin: Optional[Union[int, float]] = None, xmax: Optional[Union[int, float]] = None, ymin: Optional[Union[int, float]] = None, ymax: Optional[Union[int, float]] = None, show_legend: Optional[bool] = None, show_grid: Optional[Union[SHOW_GRID, str]] = None, show_yerr: Optional[bool] = None, show_area: Optional[bool] = None, aspect_ratio: Optional[Union[ASPECT_RATIO, str]] = None, scalex: Optional[Union[SCALE, str]] = None, scaley: Optional[Union[SCALE, str]] = None, subplots: Optional[bool] = None, max_cols: Optional[int] = None, sharex: Optional[bool] = None, sharey: Optional[bool] = None, style: Optional[ Union[ LineStyleAttrs, List[Optional[LineStyleAttrs]] ] ] = None, xticks: Optional[ Union[ List[Union[int, float]], List[List[Union[int, float]]], ] ] = None, xticklabels: Optional[ Union[List[str], List[List[str]]] ] = None, xtickrotate: Optional[ Union[int, List[Optional[int]]] ] = None, yticks: Optional[ Union[ List[Union[int, float]], List[List[Union[int, float]]], ] ] = None, yticklabels: Optional[ Union[List[str], List[List[str]]] ] = None, ytickrotate: Optional[ Union[int, List[Optional[int]]] ] = None, vlines: Optional[ Union[ VLinePlotAttrs, List[VLinePlotAttrs], List[ Union[ VLinePlotAttrs, List[VLinePlotAttrs], None, ] ], ] ] = None, hlines: Optional[ Union[ HLinePlotAttrs, List[HLinePlotAttrs], List[ Union[ HLinePlotAttrs, List[HLinePlotAttrs], None, ] ], ] ] = None, texts: Optional[ Union[ TextAttrs, List[TextAttrs], List[Union[TextAttrs, List[TextAttrs], None]], ] ] = None, x: Optional[Union[str, List[Optional[str]]]] = None, y: Optional[Union[str, List[Optional[str]]]] = None, yerr: Optional[Union[str, List[Optional[str]]]] = None ) -> plt.Figure ``` Creates the line chart. Lines connect ordered (x, y) points to show how a value changes along a continuous axis, typically time. Use it for trends, growth, and comparing the trajectories of several series on the same scale. For unordered categories use BarChart; for unconnected samples use ScatterChart. Examples: ``` >>> from datachart.charts import LineChart >>> figure = LineChart( ... data=[ ... {"x": 1, "y": 5}, ... {"x": 2, "y": 10}, ... {"x": 3, "y": 15}, ... {"x": 4, "y": 20}, ... {"x": 5, "y": 25} ... ], ... title="Basic Line Chart", ... xlabel="X", ... ylabel="Y" ... ) ``` | PARAMETER | DESCRIPTION | | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `data` | The data points for the line chart(s). Can be a single list of data points for one chart, or a list of lists for multiple charts/subplots. **TYPE:** `Union[List[LineDataPointAttrs], List[List[LineDataPointAttrs]]]` | | `title` | The title of the chart. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `xlabel` | The x-axis label. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `ylabel` | The y-axis label. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `subtitle` | The subtitle(s) for individual charts. Used as legend labels. **TYPE:** `Optional[Union[str, List[Optional[str]]]]` **DEFAULT:** `None` | | `emphasis` | The emphasis role(s) for individual charts, aligned like style: "background" mutes a chart (theme muted color, lowered alpha, thinner line, behind the others, no legend entry), "highlight" bolds it and brings it to the front, None leaves it unchanged. **TYPE:** `Optional[Union[EMPHASIS, str, List[Optional[str]]]]` **DEFAULT:** `None` | | `figsize` | The size of the figure. **TYPE:** `Optional[Union[FIG_SIZE, Tuple[float, float]]]` **DEFAULT:** `None` | | `xmin` | The minimum x-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `xmax` | The maximum x-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `ymin` | The minimum y-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `ymax` | The maximum y-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `show_legend` | Whether to show the legend. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `show_grid` | Which grid lines to show (e.g., "both", "x", "y"). **TYPE:** `Optional[Union[SHOW_GRID, str]]` **DEFAULT:** `None` | | `show_yerr` | Whether to show y-axis error bars. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `show_area` | Whether to show the area under the line. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `aspect_ratio` | The aspect ratio of the axes ("auto" or "equal"). See ASPECT_RATIO. **TYPE:** `Optional[Union[ASPECT_RATIO, str]]` **DEFAULT:** `None` | | `scalex` | The x-axis scale (e.g., "log", "linear"). **TYPE:** `Optional[Union[SCALE, str]]` **DEFAULT:** `None` | | `scaley` | The y-axis scale (e.g., "log", "linear"). **TYPE:** `Optional[Union[SCALE, str]]` **DEFAULT:** `None` | | `subplots` | Whether to create separate subplots for each chart. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `max_cols` | Maximum number of columns in subplots (when subplots=True). **TYPE:** `Optional[int]` **DEFAULT:** `None` | | `sharex` | Whether to share the x-axis in subplots. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `sharey` | Whether to share the y-axis in subplots. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `style` | Style configuration(s) for the line(s). **TYPE:** `Optional[Union[LineStyleAttrs, List[Optional[LineStyleAttrs]]]]` **DEFAULT:** `None` | | `xticks` | Custom x-axis tick positions. **TYPE:** `Optional[Union[List[Union[int, float]], List[List[Union[int, float]]]]]` **DEFAULT:** `None` | | `xticklabels` | Custom x-axis tick labels. **TYPE:** `Optional[Union[List[str], List[List[str]]]]` **DEFAULT:** `None` | | `xtickrotate` | Rotation angle for x-axis tick labels. **TYPE:** `Optional[Union[int, List[Optional[int]]]]` **DEFAULT:** `None` | | `yticks` | Custom y-axis tick positions. **TYPE:** `Optional[Union[List[Union[int, float]], List[List[Union[int, float]]]]]` **DEFAULT:** `None` | | `yticklabels` | Custom y-axis tick labels. **TYPE:** `Optional[Union[List[str], List[List[str]]]]` **DEFAULT:** `None` | | `ytickrotate` | Rotation angle for y-axis tick labels. **TYPE:** `Optional[Union[int, List[Optional[int]]]]` **DEFAULT:** `None` | | `vlines` | Vertical line(s) to plot. **TYPE:** `Optional[Union[VLinePlotAttrs, List[VLinePlotAttrs], List[Union[VLinePlotAttrs, List[VLinePlotAttrs], None]]]]` **DEFAULT:** `None` | | `hlines` | Horizontal line(s) to plot. **TYPE:** `Optional[Union[HLinePlotAttrs, List[HLinePlotAttrs], List[Union[HLinePlotAttrs, List[HLinePlotAttrs], None]]]]` **DEFAULT:** `None` | | `texts` | Text annotation(s) to draw. **TYPE:** `Optional[Union[TextAttrs, List[TextAttrs], List[Union[TextAttrs, List[TextAttrs], None]]]]` **DEFAULT:** `None` | | `x` | The key name in data for x-axis values (default: "x"). **TYPE:** `Optional[Union[str, List[Optional[str]]]]` **DEFAULT:** `None` | | `y` | The key name in data for y-axis values (default: "y"). **TYPE:** `Optional[Union[str, List[Optional[str]]]]` **DEFAULT:** `None` | | `yerr` | The key name in data for y-axis error values (default: "yerr"). **TYPE:** `Optional[Union[str, List[Optional[str]]]]` **DEFAULT:** `None` | | RETURNS | DESCRIPTION | | ------------ | ------------------------------------- | | `plt.Figure` | The figure containing the line chart. | ### datachart.charts.StackedAreaChart ``` StackedAreaChart( data: Union[ List[LineDataPointAttrs], List[List[LineDataPointAttrs]], ], *, baseline: Optional[Union[BASELINE, str]] = None, title: Optional[str] = None, xlabel: Optional[str] = None, ylabel: Optional[str] = None, subtitle: Optional[ Union[str, List[Optional[str]]] ] = None, emphasis: Optional[ Union[EMPHASIS, str, List[Optional[str]]] ] = None, figsize: Optional[ Union[FIG_SIZE, Tuple[float, float]] ] = None, xmin: Optional[Union[int, float]] = None, xmax: Optional[Union[int, float]] = None, ymin: Optional[Union[int, float]] = None, ymax: Optional[Union[int, float]] = None, show_legend: Optional[bool] = None, show_grid: Optional[Union[SHOW_GRID, str]] = None, aspect_ratio: Optional[Union[ASPECT_RATIO, str]] = None, scalex: Optional[Union[SCALE, str]] = None, scaley: Optional[Union[SCALE, str]] = None, subplots: Optional[bool] = None, max_cols: Optional[int] = None, sharex: Optional[bool] = None, sharey: Optional[bool] = None, style: Optional[ Union[ StackedAreaStyleAttrs, List[Optional[StackedAreaStyleAttrs]], ] ] = None, xticks: Optional[ Union[ List[Union[int, float]], List[List[Union[int, float]]], ] ] = None, xticklabels: Optional[ Union[List[str], List[List[str]]] ] = None, xtickrotate: Optional[ Union[int, List[Optional[int]]] ] = None, yticks: Optional[ Union[ List[Union[int, float]], List[List[Union[int, float]]], ] ] = None, yticklabels: Optional[ Union[List[str], List[List[str]]] ] = None, ytickrotate: Optional[ Union[int, List[Optional[int]]] ] = None, vlines: Optional[ Union[ VLinePlotAttrs, List[VLinePlotAttrs], List[ Union[ VLinePlotAttrs, List[VLinePlotAttrs], None, ] ], ] ] = None, hlines: Optional[ Union[ HLinePlotAttrs, List[HLinePlotAttrs], List[ Union[ HLinePlotAttrs, List[HLinePlotAttrs], None, ] ], ] ] = None, texts: Optional[ Union[ TextAttrs, List[TextAttrs], List[Union[TextAttrs, List[TextAttrs], None]], ] ] = None, x: Optional[Union[str, List[Optional[str]]]] = None, y: Optional[Union[str, List[Optional[str]]]] = None ) -> plt.Figure ``` Creates the stacked area chart. Stacked areas fill each series on top of the previous one along an ordered axis, so the top edge traces the total and the bands show how it splits into parts — class proportions over time, traffic by channel per year. Every series must share the same `x` values. Use it for composition that changes along an axis; for the trajectories themselves use LineChart, and for composition at a few discrete categories use BarChart with `bar_mode="stack"`. Added in 0.9.0 Examples: ``` >>> from datachart.charts import StackedAreaChart >>> figure = StackedAreaChart( ... data=[ ... [{"x": 1, "y": 3}, {"x": 2, "y": 4}, {"x": 3, "y": 5}], ... [{"x": 1, "y": 2}, {"x": 2, "y": 3}, {"x": 3, "y": 1}], ... ], ... subtitle=["Mobile", "Desktop"], ... title="Traffic by Device", ... xlabel="Year", ... ylabel="Visits", ... ) ``` | PARAMETER | DESCRIPTION | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `data` | The data points for the stacked series. A single list of points draws one band; a list of lists draws one band per series, the first at the bottom. Every series must hold the same x values in the same order. **TYPE:** `Union[List[LineDataPointAttrs], List[List[LineDataPointAttrs]]]` | | `baseline` | Where the first series starts: "zero" (default), "percent" (each x normalised to 100), "sym" (centred on zero), "wiggle" or "weighted_wiggle" (streamgraph baselines). See BASELINE. **TYPE:** `Optional[Union[BASELINE, str]]` **DEFAULT:** `None` | | `title` | The title of the chart. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `xlabel` | The x-axis label. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `ylabel` | The y-axis label. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `subtitle` | The subtitle(s) for individual series. Used as legend labels. **TYPE:** `Optional[Union[str, List[Optional[str]]]]` **DEFAULT:** `None` | | `emphasis` | The emphasis role(s) for individual series, aligned like style: "background" mutes a band (theme muted color, lowered alpha, no legend entry), "highlight" brings it to the front, None leaves it unchanged. **TYPE:** `Optional[Union[EMPHASIS, str, List[Optional[str]]]]` **DEFAULT:** `None` | | `figsize` | The size of the figure. **TYPE:** `Optional[Union[FIG_SIZE, Tuple[float, float]]]` **DEFAULT:** `None` | | `xmin` | The minimum x-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `xmax` | The maximum x-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `ymin` | The minimum y-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `ymax` | The maximum y-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `show_legend` | Whether to show the legend. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `show_grid` | Which grid lines to show (e.g., "both", "x", "y"). **TYPE:** `Optional[Union[SHOW_GRID, str]]` **DEFAULT:** `None` | | `aspect_ratio` | The aspect ratio of the axes ("auto" or "equal"). See ASPECT_RATIO. **TYPE:** `Optional[Union[ASPECT_RATIO, str]]` **DEFAULT:** `None` | | `scalex` | The x-axis scale (e.g., "log", "linear"). **TYPE:** `Optional[Union[SCALE, str]]` **DEFAULT:** `None` | | `scaley` | The y-axis scale (e.g., "log", "linear"). **TYPE:** `Optional[Union[SCALE, str]]` **DEFAULT:** `None` | | `subplots` | Whether to draw each series unstacked in its own subplot. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `max_cols` | Maximum number of columns in subplots (when subplots=True). **TYPE:** `Optional[int]` **DEFAULT:** `None` | | `sharex` | Whether to share the x-axis in subplots. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `sharey` | Whether to share the y-axis in subplots. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `style` | Style configuration(s) for the band(s). **TYPE:** `Optional[Union[StackedAreaStyleAttrs, List[Optional[StackedAreaStyleAttrs]]]]` **DEFAULT:** `None` | | `xticks` | Custom x-axis tick positions. **TYPE:** `Optional[Union[List[Union[int, float]], List[List[Union[int, float]]]]]` **DEFAULT:** `None` | | `xticklabels` | Custom x-axis tick labels. **TYPE:** `Optional[Union[List[str], List[List[str]]]]` **DEFAULT:** `None` | | `xtickrotate` | Rotation angle for x-axis tick labels. **TYPE:** `Optional[Union[int, List[Optional[int]]]]` **DEFAULT:** `None` | | `yticks` | Custom y-axis tick positions. **TYPE:** `Optional[Union[List[Union[int, float]], List[List[Union[int, float]]]]]` **DEFAULT:** `None` | | `yticklabels` | Custom y-axis tick labels. **TYPE:** `Optional[Union[List[str], List[List[str]]]]` **DEFAULT:** `None` | | `ytickrotate` | Rotation angle for y-axis tick labels. **TYPE:** `Optional[Union[int, List[Optional[int]]]]` **DEFAULT:** `None` | | `vlines` | Vertical line(s) to plot. **TYPE:** `Optional[Union[VLinePlotAttrs, List[VLinePlotAttrs], List[Union[VLinePlotAttrs, List[VLinePlotAttrs], None]]]]` **DEFAULT:** `None` | | `hlines` | Horizontal line(s) to plot. **TYPE:** `Optional[Union[HLinePlotAttrs, List[HLinePlotAttrs], List[Union[HLinePlotAttrs, List[HLinePlotAttrs], None]]]]` **DEFAULT:** `None` | | `texts` | Text annotation(s) to draw. **TYPE:** `Optional[Union[TextAttrs, List[TextAttrs], List[Union[TextAttrs, List[TextAttrs], None]]]]` **DEFAULT:** `None` | | `x` | The key name in data for x-axis values (default: "x"). **TYPE:** `Optional[Union[str, List[Optional[str]]]]` **DEFAULT:** `None` | | `y` | The key name in data for y-axis values (default: "y"). **TYPE:** `Optional[Union[str, List[Optional[str]]]]` **DEFAULT:** `None` | | RETURNS | DESCRIPTION | | ------------ | --------------------------------------------- | | `plt.Figure` | The figure containing the stacked area chart. | | RAISES | DESCRIPTION | | ------------ | ---------------------------------------------------------------------------------- | | `ValueError` | If the series do not share the same x values, or baseline is not a BASELINE value. | ### datachart.charts.BarChart ``` BarChart( data: Union[ List[BarDataPointAttrs], List[List[BarDataPointAttrs]], ], *, title: Optional[str] = None, xlabel: Optional[str] = None, ylabel: Optional[str] = None, subtitle: Optional[ Union[str, List[Optional[str]]] ] = None, emphasis: Optional[ Union[EMPHASIS, str, List[Optional[str]]] ] = None, figsize: Optional[ Union[FIG_SIZE, Tuple[float, float]] ] = None, xmin: Optional[Union[int, float]] = None, xmax: Optional[Union[int, float]] = None, ymin: Optional[Union[int, float]] = None, ymax: Optional[Union[int, float]] = None, show_legend: Optional[bool] = None, show_grid: Optional[Union[SHOW_GRID, str]] = None, show_yerr: Optional[bool] = None, show_values: Optional[bool] = None, value_format: Optional[Union[VALUE_FORMAT, str]] = None, aspect_ratio: Optional[Union[ASPECT_RATIO, str]] = None, orientation: Optional[ Union[ORIENTATION, str] ] = ORIENTATION.VERTICAL, bar_mode: Optional[Union[BAR_MODE, str]] = None, scalex: Optional[Union[SCALE, str]] = None, scaley: Optional[Union[SCALE, str]] = None, subplots: Optional[bool] = None, max_cols: Optional[int] = None, sharex: Optional[bool] = None, sharey: Optional[bool] = None, style: Optional[ Union[BarStyleAttrs, List[Optional[BarStyleAttrs]]] ] = None, xticks: Optional[ Union[ List[Union[int, float]], List[List[Union[int, float]]], ] ] = None, xticklabels: Optional[ Union[List[str], List[List[str]]] ] = None, xtickrotate: Optional[ Union[int, List[Optional[int]]] ] = None, yticks: Optional[ Union[ List[Union[int, float]], List[List[Union[int, float]]], ] ] = None, yticklabels: Optional[ Union[List[str], List[List[str]]] ] = None, ytickrotate: Optional[ Union[int, List[Optional[int]]] ] = None, vlines: Optional[ Union[ VLinePlotAttrs, List[VLinePlotAttrs], List[ Union[ VLinePlotAttrs, List[VLinePlotAttrs], None, ] ], ] ] = None, hlines: Optional[ Union[ HLinePlotAttrs, List[HLinePlotAttrs], List[ Union[ HLinePlotAttrs, List[HLinePlotAttrs], None, ] ], ] ] = None, texts: Optional[ Union[ TextAttrs, List[TextAttrs], List[Union[TextAttrs, List[TextAttrs], None]], ] ] = None, label: Optional[Union[str, List[Optional[str]]]] = None, y: Optional[Union[str, List[Optional[str]]]] = None, yerr: Optional[Union[str, List[Optional[str]]]] = None ) -> plt.Figure ``` Creates the bar chart. Bars compare a numeric value across discrete categories: each label gets a bar whose length encodes its value. Use it when the categories are few and unordered (or ordinal) and the question is "which is bigger, and by how much"; several series can be grouped, stacked, or overlaid via `bar_mode`. For a continuous x-axis reach for LineChart, for distributions for Histogram. Examples: ``` >>> from datachart.charts import BarChart >>> figure = BarChart( ... data=[ ... {"label": "cat1", "y": 5}, ... {"label": "cat2", "y": 10}, ... {"label": "cat3", "y": 15}, ... {"label": "cat4", "y": 20}, ... {"label": "cat5", "y": 25} ... ], ... title="Basic Bar Chart", ... xlabel="LABEL", ... ylabel="Y" ... ) ``` | PARAMETER | DESCRIPTION | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `data` | The data points for the bar chart(s). Can be a single list of data points for one chart, or a list of lists for multiple charts/subplots. **TYPE:** `Union[List[BarDataPointAttrs], List[List[BarDataPointAttrs]]]` | | `title` | The title of the chart. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `xlabel` | The x-axis label. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `ylabel` | The y-axis label. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `subtitle` | The subtitle(s) for individual charts. Used as legend labels. **TYPE:** `Optional[Union[str, List[Optional[str]]]]` **DEFAULT:** `None` | | `emphasis` | The emphasis role(s) for individual charts, aligned like style: "background" mutes a chart (theme muted color, lowered alpha, behind the others, no legend entry), "highlight" bolds its edges and brings it to the front, None leaves it unchanged. See EMPHASIS. **TYPE:** `Optional[Union[EMPHASIS, str, List[Optional[str]]]]` **DEFAULT:** `None` | | `figsize` | The size of the figure as (width, height) in inches. See FIG_SIZE. **TYPE:** `Optional[Union[FIG_SIZE, Tuple[float, float]]]` **DEFAULT:** `None` | | `xmin` | The minimum x-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `xmax` | The maximum x-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `ymin` | The minimum y-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `ymax` | The maximum y-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `show_legend` | Whether to show the legend. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `show_grid` | Which grid lines to show ("both", "x", "y"). See SHOW_GRID. **TYPE:** `Optional[Union[SHOW_GRID, str]]` **DEFAULT:** `None` | | `show_yerr` | Whether to show y-axis error bars. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `show_values` | Whether to show bar value labels at the edge of each bar. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `value_format` | Format string for bar value labels: a VALUE_FORMAT constant or any "{x:.1f}", "{:.1f}%", or "%g" style string. **TYPE:** `Optional[Union[VALUE_FORMAT, str]]` **DEFAULT:** `None` | | `aspect_ratio` | The aspect ratio of the axes ("auto" or "equal"). See ASPECT_RATIO. **TYPE:** `Optional[Union[ASPECT_RATIO, str]]` **DEFAULT:** `None` | | `bar_mode` | How multiple bar series share the axis: "group" (side-by-side), "stack" (stacked), or "overlay" (overlapping). See BAR_MODE. **TYPE:** `Optional[Union[BAR_MODE, str]]` **DEFAULT:** `None` | | `orientation` | The orientation of the bars ("vertical" or "horizontal"). See ORIENTATION. **TYPE:** `Optional[Union[ORIENTATION, str]]` **DEFAULT:** `ORIENTATION.VERTICAL` | | `scalex` | The x-axis scale ("linear", "log", "symlog", "asinh"). Useful for horizontal bars. See SCALE. **TYPE:** `Optional[Union[SCALE, str]]` **DEFAULT:** `None` | | `scaley` | The y-axis scale ("linear", "log", "symlog", "asinh"). Useful for vertical bars. See SCALE. **TYPE:** `Optional[Union[SCALE, str]]` **DEFAULT:** `None` | | `subplots` | Whether to create separate subplots for each chart. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `max_cols` | Maximum number of columns in subplots (when subplots=True). **TYPE:** `Optional[int]` **DEFAULT:** `None` | | `sharex` | Whether to share the x-axis in subplots. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `sharey` | Whether to share the y-axis in subplots. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `style` | Style configuration(s) for the bar(s). **TYPE:** `Optional[Union[BarStyleAttrs, List[Optional[BarStyleAttrs]]]]` **DEFAULT:** `None` | | `xticks` | Custom x-axis tick positions. **TYPE:** `Optional[Union[List[Union[int, float]], List[List[Union[int, float]]]]]` **DEFAULT:** `None` | | `xticklabels` | Custom x-axis tick labels. **TYPE:** `Optional[Union[List[str], List[List[str]]]]` **DEFAULT:** `None` | | `xtickrotate` | Rotation angle for x-axis tick labels. **TYPE:** `Optional[Union[int, List[Optional[int]]]]` **DEFAULT:** `None` | | `yticks` | Custom y-axis tick positions. **TYPE:** `Optional[Union[List[Union[int, float]], List[List[Union[int, float]]]]]` **DEFAULT:** `None` | | `yticklabels` | Custom y-axis tick labels. **TYPE:** `Optional[Union[List[str], List[List[str]]]]` **DEFAULT:** `None` | | `ytickrotate` | Rotation angle for y-axis tick labels. **TYPE:** `Optional[Union[int, List[Optional[int]]]]` **DEFAULT:** `None` | | `vlines` | Vertical line(s) to plot. **TYPE:** `Optional[Union[VLinePlotAttrs, List[VLinePlotAttrs], List[Union[VLinePlotAttrs, List[VLinePlotAttrs], None]]]]` **DEFAULT:** `None` | | `hlines` | Horizontal line(s) to plot. **TYPE:** `Optional[Union[HLinePlotAttrs, List[HLinePlotAttrs], List[Union[HLinePlotAttrs, List[HLinePlotAttrs], None]]]]` **DEFAULT:** `None` | | `texts` | Text annotation(s) to draw. **TYPE:** `Optional[Union[TextAttrs, List[TextAttrs], List[Union[TextAttrs, List[TextAttrs], None]]]]` **DEFAULT:** `None` | | `label` | The key name in data for label values (default: "label"). **TYPE:** `Optional[Union[str, List[Optional[str]]]]` **DEFAULT:** `None` | | `y` | The key name in data for y-axis values (default: "y"). **TYPE:** `Optional[Union[str, List[Optional[str]]]]` **DEFAULT:** `None` | | `yerr` | The key name in data for y-axis error values (default: "yerr"). **TYPE:** `Optional[Union[str, List[Optional[str]]]]` **DEFAULT:** `None` | | RETURNS | DESCRIPTION | | ------------ | ------------------------------------ | | `plt.Figure` | The figure containing the bar chart. | ### datachart.charts.PyramidChart ``` PyramidChart( data: List[List[BarDataPointAttrs]], *, title: Optional[str] = None, xlabel: Optional[str] = None, ylabel: Optional[str] = None, subtitle: Optional[ Union[str, List[Optional[str]]] ] = None, figsize: Optional[ Union[FIG_SIZE, Tuple[float, float]] ] = None, xmin: Optional[Union[int, float]] = None, xmax: Optional[Union[int, float]] = None, show_legend: Optional[bool] = None, show_grid: Optional[Union[SHOW_GRID, str]] = None, show_yerr: Optional[bool] = None, show_values: Optional[bool] = None, value_format: Optional[Union[VALUE_FORMAT, str]] = None, style: Optional[ Union[BarStyleAttrs, List[Optional[BarStyleAttrs]]] ] = None, xticks: Optional[List[Union[int, float]]] = None, xticklabels: Optional[List[str]] = None, xtickrotate: Optional[int] = None, yticks: Optional[List[Union[int, float]]] = None, yticklabels: Optional[List[str]] = None, ytickrotate: Optional[int] = None, vlines: Optional[ Union[VLinePlotAttrs, List[VLinePlotAttrs]] ] = None, hlines: Optional[ Union[HLinePlotAttrs, List[HLinePlotAttrs]] ] = None, texts: Optional[ Union[TextAttrs, List[TextAttrs]] ] = None, label: Optional[Union[str, List[Optional[str]]]] = None, y: Optional[Union[str, List[Optional[str]]]] = None, yerr: Optional[Union[str, List[Optional[str]]]] = None ) -> plt.Figure ``` Creates the pyramid chart. A pyramid chart draws exactly two series as horizontal bars mirrored around a shared category axis, the first series to the left and the second to the right: the classic age-sex population pyramid. Use it to compare the distribution of two groups over the same ordered categories, such as age bands, where the symmetry (or lack of it) is the message. Both series are supplied as positive values; value ticks and labels show absolute values. Unlike the other chart fronts, the axis parameters are spatial: `xlabel`, `xticks`, and `xmax` address the horizontal value axis, and `ylabel` the vertical category axis. Added in v0.8.0 Examples: ``` >>> from datachart.charts import PyramidChart >>> figure = PyramidChart( ... data=[ ... [ ... {"label": "0-14", "y": 12}, ... {"label": "15-29", "y": 18}, ... {"label": "30-44", "y": 22}, ... ], ... [ ... {"label": "0-14", "y": 11}, ... {"label": "15-29", "y": 19}, ... {"label": "30-44", "y": 24}, ... ], ... ], ... subtitle=["Group A", "Group B"], ... title="Basic Pyramid Chart", ... show_legend=True, ... ) ``` | PARAMETER | DESCRIPTION | | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `data` | Exactly two lists of data points — the first is the left side, the second the right. Values are positive for both sides; the chart mirrors the left side itself. **TYPE:** `List[List[BarDataPointAttrs]]` | | `title` | The title of the chart. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `xlabel` | The label of the horizontal value axis. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `ylabel` | The label of the vertical category axis. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `subtitle` | The names of the two sides. Used as legend labels. **TYPE:** `Optional[Union[str, List[Optional[str]]]]` **DEFAULT:** `None` | | `figsize` | The size of the figure as (width, height) in inches. See FIG_SIZE. **TYPE:** `Optional[Union[FIG_SIZE, Tuple[float, float]]]` **DEFAULT:** `None` | | `xmin` | Not supported; the value axis is always symmetric around zero. Raises when passed. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `xmax` | The maximum per-side value; the value axis spans (-xmax, xmax). **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `show_legend` | Whether to show the legend. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `show_grid` | Which grid lines to show ("both", "x", "y"). See SHOW_GRID. **TYPE:** `Optional[Union[SHOW_GRID, str]]` **DEFAULT:** `None` | | `show_yerr` | Whether to show error bars on the bars. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `show_values` | Whether to show bar value labels at the edge of each bar. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `value_format` | Format string for bar value labels: a VALUE_FORMAT constant or any "{x:.1f}", "{:.1f}%", or "%g" style string. **TYPE:** `Optional[Union[VALUE_FORMAT, str]]` **DEFAULT:** `None` | | `style` | Style configuration(s) for the bars, per side. **TYPE:** `Optional[Union[BarStyleAttrs, List[Optional[BarStyleAttrs]]]]` **DEFAULT:** `None` | | `xticks` | Custom value-axis tick positions, as positive values; each is mirrored to both halves. **TYPE:** `Optional[List[Union[int, float]]]` **DEFAULT:** `None` | | `xticklabels` | Custom value-axis tick labels (same length as xticks), applied to both mirrored halves. **TYPE:** `Optional[List[str]]` **DEFAULT:** `None` | | `xtickrotate` | Rotation angle for value-axis tick labels. **TYPE:** `Optional[int]` **DEFAULT:** `None` | | `yticks` | Custom category-axis tick positions. **TYPE:** `Optional[List[Union[int, float]]]` **DEFAULT:** `None` | | `yticklabels` | Custom category-axis tick labels. **TYPE:** `Optional[List[str]]` **DEFAULT:** `None` | | `ytickrotate` | Rotation angle for category-axis tick labels. **TYPE:** `Optional[int]` **DEFAULT:** `None` | | `vlines` | Vertical line(s) to plot. **TYPE:** `Optional[Union[VLinePlotAttrs, List[VLinePlotAttrs]]]` **DEFAULT:** `None` | | `hlines` | Horizontal line(s) to plot. **TYPE:** `Optional[Union[HLinePlotAttrs, List[HLinePlotAttrs]]]` **DEFAULT:** `None` | | `texts` | Text annotation(s) to draw. **TYPE:** `Optional[Union[TextAttrs, List[TextAttrs]]]` **DEFAULT:** `None` | | `label` | The key name in data for label values (default: "label"). **TYPE:** `Optional[Union[str, List[Optional[str]]]]` **DEFAULT:** `None` | | `y` | The key name in data for the bar values (default: "y"). **TYPE:** `Optional[Union[str, List[Optional[str]]]]` **DEFAULT:** `None` | | `yerr` | The key name in data for the bar error values (default: "yerr"). **TYPE:** `Optional[Union[str, List[Optional[str]]]]` **DEFAULT:** `None` | | RETURNS | DESCRIPTION | | ------------ | ---------------------------------------- | | `plt.Figure` | The figure containing the pyramid chart. | ### datachart.charts.RadialChart ``` RadialChart( data: Union[ List[RadialDataPointAttrs], List[List[RadialDataPointAttrs]], ], *, type: Optional[Union[RADIAL_TYPE, str]] = None, title: Optional[str] = None, xlabel: Optional[str] = None, ylabel: Optional[str] = None, subtitle: Optional[ Union[str, List[Optional[str]]] ] = None, emphasis: Optional[ Union[EMPHASIS, str, List[Optional[str]]] ] = None, figsize: Optional[ Union[FIG_SIZE, Tuple[float, float]] ] = None, ymin: Optional[Union[int, float]] = None, ymax: Optional[Union[int, float]] = None, show_legend: Optional[bool] = None, show_grid: Optional[Union[SHOW_GRID, str]] = None, show_yerr: Optional[bool] = None, show_area: Optional[bool] = None, show_values: Optional[bool] = None, show_tip_labels: Optional[bool] = None, show_border: Optional[bool] = None, value_format: Optional[str] = None, bar_mode: Optional[Union[BAR_MODE, str]] = None, num_bins: Optional[int] = None, startangle: Optional[Union[str, int, float]] = None, direction: Optional[Union[DIRECTION, str]] = None, innerradius: Optional[float] = None, scalex: Optional[Union[SCALE, str]] = None, scaley: Optional[Union[SCALE, str]] = None, subplots: Optional[bool] = None, max_cols: Optional[int] = None, sharex: Optional[bool] = None, sharey: Optional[bool] = None, style: Optional[ Union[ _RadialStyleAttrs, List[Optional[_RadialStyleAttrs]], ] ] = None, texts: Optional[ Union[ TextAttrs, List[TextAttrs], List[Union[TextAttrs, List[TextAttrs], None]], ] ] = None, vlines: Optional[dict] = None, hlines: Optional[dict] = None, label: Optional[Union[str, List[Optional[str]]]] = None, x: Optional[Union[str, List[Optional[str]]]] = None, y: Optional[Union[str, List[Optional[str]]]] = None, yerr: Optional[Union[str, List[Optional[str]]]] = None ) -> plt.Figure ``` Creates the radial chart. A radial chart plots series on polar axes: as a line (radar) profile, an area, bars, or a histogram, chosen with `type`. Use the radar form to compare a few entities across several metrics on a shared scale, and the bar and histogram forms for cyclic categories such as hours, weekdays, or compass directions. Added in v0.8.0 Examples: ``` >>> from datachart.charts import RadialChart >>> figure = RadialChart( ... data=[ ... {"label": "N", "y": 5}, ... {"label": "E", "y": 10}, ... {"label": "S", "y": 15}, ... {"label": "W", "y": 20} ... ], ... title="Basic Radial Chart" ... ) ``` | PARAMETER | DESCRIPTION | | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `data` | The data points for the radial chart(s). Can be a single list of data points for one chart, or a list of lists for multiple charts/subplots. The line, bar, and scatter visuals take label/y points whose labels are placed evenly around the circle; the histogram visual takes numeric x observations in degrees, binned over \[0, 360). **TYPE:** `Union[List[RadialDataPointAttrs], List[List[RadialDataPointAttrs]]]` | | `type` | The visual the whole figure draws: "line" (default), "bar", "scatter", or "histogram". See RADIAL_TYPE. **TYPE:** `Optional[Union[RADIAL_TYPE, str]]` **DEFAULT:** `None` | | `title` | The title of the chart. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `xlabel` | The angular-axis label. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `ylabel` | The radial-axis label. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `subtitle` | The subtitle(s) for individual charts. Used as legend labels. **TYPE:** `Optional[Union[str, List[Optional[str]]]]` **DEFAULT:** `None` | | `emphasis` | The emphasis role(s) for individual charts, aligned like style: "background" mutes a chart, "highlight" bolds it, None leaves it unchanged. **TYPE:** `Optional[Union[EMPHASIS, str, List[Optional[str]]]]` **DEFAULT:** `None` | | `figsize` | The size of the figure. **TYPE:** `Optional[Union[FIG_SIZE, Tuple[float, float]]]` **DEFAULT:** `None` | | `ymin` | The minimum radial-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `ymax` | The maximum radial-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `show_legend` | Whether to show the legend. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `show_grid` | Which grid lines to show (e.g., "both", "x", "y"). **TYPE:** `Optional[Union[SHOW_GRID, str]]` **DEFAULT:** `None` | | `show_yerr` | Whether to show the radial error band (line visual). **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `show_area` | Whether to fill the area inside the line (line visual). **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `show_values` | Whether to write each mark's value at its tip, rotated along the spoke. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `show_tip_labels` | Whether to write the category labels at the mark tips, rotated along their spokes, instead of around the circle. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `show_border` | Whether to draw the outer border circle. Defaults to the theme's spine visibility; False hides it. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `value_format` | Format for the values written by show_values — a printf format (e.g. "%.1f") or a {x}-style string. See VALUE_FORMAT. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `bar_mode` | How multiple bar series share the circle: "group", "stack", or "overlay" (bar visual). See BAR_MODE. **TYPE:** `Optional[Union[BAR_MODE, str]]` **DEFAULT:** `None` | | `num_bins` | The number of angular bins over \[0, 360) (histogram visual). **TYPE:** `Optional[int]` **DEFAULT:** `None` | | `startangle` | Where the first point sits: a compass location ("N", "NE", "E", "SE", "S", "SW", "W", "NW") or a numeric compass bearing in degrees clockwise from north. Defaults to "N". **TYPE:** `Optional[Union[str, int, float]]` **DEFAULT:** `None` | | `direction` | Which way the angles increase: "clockwise" (default) or "counterclockwise". See DIRECTION. **TYPE:** `Optional[Union[DIRECTION, str]]` **DEFAULT:** `None` | | `innerradius` | The donut hole, as a fraction (0 \<= f < 1) of the radial extent. Defaults to 0. **TYPE:** `Optional[float]` **DEFAULT:** `None` | | `scalex` | Not supported; the angular axis has no scale. Raises when passed. **TYPE:** `Optional[Union[SCALE, str]]` **DEFAULT:** `None` | | `scaley` | The radial-axis scale (e.g., "log", "linear"). **TYPE:** `Optional[Union[SCALE, str]]` **DEFAULT:** `None` | | `subplots` | Whether to create separate polar subplots for each chart. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `max_cols` | Maximum number of columns in subplots (when subplots=True). **TYPE:** `Optional[int]` **DEFAULT:** `None` | | `sharex` | Whether to share the angular axis in subplots. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `sharey` | Whether to share the radial axis in subplots. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `style` | Style configuration(s) for the chart(s); radial visuals obey the matching cartesian style family (plot_line\_\*, plot_bar\_\*, plot_hist\_\*, plot_scatter\_\*). **TYPE:** `Optional[Union[_RadialStyleAttrs, List[Optional[_RadialStyleAttrs]]]]` **DEFAULT:** `None` | | `texts` | Text annotation(s) to draw. On the polar axes, data coordinates are (angle in radians, radius); axes-fraction coordinates ("coords": "axes") are often easier. **TYPE:** `Optional[Union[TextAttrs, List[TextAttrs], List[Union[TextAttrs, List[TextAttrs], None]]]]` **DEFAULT:** `None` | | `vlines` | Not supported on a polar axes. Raises when passed. **TYPE:** `Optional[dict]` **DEFAULT:** `None` | | `hlines` | Not supported on a polar axes. Raises when passed. **TYPE:** `Optional[dict]` **DEFAULT:** `None` | | `label` | The key name in data for the category labels (default: "label"). **TYPE:** `Optional[Union[str, List[Optional[str]]]]` **DEFAULT:** `None` | | `x` | The key name in data for the histogram observations (default: "x"). **TYPE:** `Optional[Union[str, List[Optional[str]]]]` **DEFAULT:** `None` | | `y` | The key name in data for radial values (default: "y"). **TYPE:** `Optional[Union[str, List[Optional[str]]]]` **DEFAULT:** `None` | | `yerr` | The key name in data for radial error values (default: "yerr"). **TYPE:** `Optional[Union[str, List[Optional[str]]]]` **DEFAULT:** `None` | | RETURNS | DESCRIPTION | | ------------ | --------------------------------------- | | `plt.Figure` | The figure containing the radial chart. | ## Distributions ### datachart.charts.Histogram ``` Histogram( data: Union[ List[HistDataPointAttrs], List[List[HistDataPointAttrs]], ], *, title: Optional[str] = None, xlabel: Optional[str] = None, ylabel: Optional[str] = None, subtitle: Optional[ Union[str, List[Optional[str]]] ] = None, emphasis: Optional[ Union[EMPHASIS, str, List[Optional[str]]] ] = None, figsize: Optional[ Union[FIG_SIZE, Tuple[float, float]] ] = None, xmin: Optional[Union[int, float]] = None, xmax: Optional[Union[int, float]] = None, ymin: Optional[Union[int, float]] = None, ymax: Optional[Union[int, float]] = None, show_legend: Optional[bool] = None, show_grid: Optional[Union[SHOW_GRID, str]] = None, show_density: Optional[bool] = None, show_cumulative: Optional[bool] = None, aspect_ratio: Optional[Union[ASPECT_RATIO, str]] = None, orientation: Optional[ Union[ORIENTATION, str] ] = ORIENTATION.VERTICAL, bar_mode: Optional[Union[BAR_MODE, str]] = None, num_bins: Optional[int] = None, scalex: Optional[Union[SCALE, str]] = None, scaley: Optional[Union[SCALE, str]] = None, subplots: Optional[bool] = None, max_cols: Optional[int] = None, sharex: Optional[bool] = None, sharey: Optional[bool] = None, style: Optional[ Union[ HistStyleAttrs, List[Optional[HistStyleAttrs]] ] ] = None, xticks: Optional[ Union[ List[Union[int, float]], List[List[Union[int, float]]], ] ] = None, xticklabels: Optional[ Union[List[str], List[List[str]]] ] = None, xtickrotate: Optional[ Union[int, List[Optional[int]]] ] = None, yticks: Optional[ Union[ List[Union[int, float]], List[List[Union[int, float]]], ] ] = None, yticklabels: Optional[ Union[List[str], List[List[str]]] ] = None, ytickrotate: Optional[ Union[int, List[Optional[int]]] ] = None, vlines: Optional[ Union[ VLinePlotAttrs, List[VLinePlotAttrs], List[ Union[ VLinePlotAttrs, List[VLinePlotAttrs], None, ] ], ] ] = None, hlines: Optional[ Union[ HLinePlotAttrs, List[HLinePlotAttrs], List[ Union[ HLinePlotAttrs, List[HLinePlotAttrs], None, ] ], ] ] = None, texts: Optional[ Union[ TextAttrs, List[TextAttrs], List[Union[TextAttrs, List[TextAttrs], None]], ] ] = None, x: Optional[Union[str, List[Optional[str]]]] = None ) -> plt.Figure ``` Creates the histogram. A histogram bins a single numeric variable and draws the count (or density) per bin, revealing the shape of its distribution: center, spread, skew, modes, and outliers. Use it to inspect one variable or compare a few overlaid distributions. For side-by-side group summaries use BoxPlot or ViolinPlot. Examples: ``` >>> from datachart.charts import Histogram >>> figure = Histogram( ... data=[ ... {"x": 1}, ... {"x": 2}, ... {"x": 3}, ... {"x": 4}, ... {"x": 5} ... ], ... title="Basic Histogram", ... xlabel="X", ... ylabel="Y" ... ) ``` | PARAMETER | DESCRIPTION | | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `data` | The data points for the histogram(s). Can be a single list of data points for one chart, or a list of lists for multiple charts/subplots. **TYPE:** `Union[List[HistDataPointAttrs], List[List[HistDataPointAttrs]]]` | | `title` | The title of the chart. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `xlabel` | The x-axis label. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `ylabel` | The y-axis label. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `subtitle` | The subtitle(s) for individual charts. Used as legend labels. **TYPE:** `Optional[Union[str, List[Optional[str]]]]` **DEFAULT:** `None` | | `emphasis` | The emphasis role(s) for individual charts, aligned like style: "background" mutes a chart (theme muted color, lowered alpha, behind the others, no legend entry), "highlight" bolds it and brings it to the front, None leaves it unchanged. When any chart carries a role, the histograms draw individually overlaid instead of stacked. **TYPE:** `Optional[Union[EMPHASIS, str, List[Optional[str]]]]` **DEFAULT:** `None` | | `figsize` | The size of the figure. **TYPE:** `Optional[Union[FIG_SIZE, Tuple[float, float]]]` **DEFAULT:** `None` | | `xmin` | The minimum x-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `xmax` | The maximum x-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `ymin` | The minimum y-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `ymax` | The maximum y-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `show_legend` | Whether to show the legend. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `show_grid` | Which grid lines to show (e.g., "both", "x", "y"). **TYPE:** `Optional[Union[SHOW_GRID, str]]` **DEFAULT:** `None` | | `show_density` | Whether to plot the density histogram. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `show_cumulative` | Whether to plot the cumulative histogram. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `aspect_ratio` | The aspect ratio of the axes ("auto" or "equal"). See ASPECT_RATIO. **TYPE:** `Optional[Union[ASPECT_RATIO, str]]` **DEFAULT:** `None` | | `orientation` | The orientation of the histogram (vertical or horizontal). **TYPE:** `Optional[Union[ORIENTATION, str]]` **DEFAULT:** `ORIENTATION.VERTICAL` | | `bar_mode` | How multiple histogram series share the axis: "stack" (stacked on shared bins, the default) or "overlay" (each series drawn individually over the others). "group" has no histogram meaning and behaves like "overlay". See BAR_MODE. **TYPE:** `Optional[Union[BAR_MODE, str]]` **DEFAULT:** `None` | | `num_bins` | The number of bins to split the data into. **TYPE:** `Optional[int]` **DEFAULT:** `None` | | `scalex` | The x-axis scale (e.g., "log", "linear"). Useful for log-distributed data. **TYPE:** `Optional[Union[SCALE, str]]` **DEFAULT:** `None` | | `scaley` | The y-axis scale (e.g., "log", "linear"). **TYPE:** `Optional[Union[SCALE, str]]` **DEFAULT:** `None` | | `subplots` | Whether to create separate subplots for each chart. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `max_cols` | Maximum number of columns in subplots (when subplots=True). **TYPE:** `Optional[int]` **DEFAULT:** `None` | | `sharex` | Whether to share the x-axis in subplots. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `sharey` | Whether to share the y-axis in subplots. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `style` | Style configuration(s) for the histogram(s). **TYPE:** `Optional[Union[HistStyleAttrs, List[Optional[HistStyleAttrs]]]]` **DEFAULT:** `None` | | `xticks` | Custom x-axis tick positions. **TYPE:** `Optional[Union[List[Union[int, float]], List[List[Union[int, float]]]]]` **DEFAULT:** `None` | | `xticklabels` | Custom x-axis tick labels. **TYPE:** `Optional[Union[List[str], List[List[str]]]]` **DEFAULT:** `None` | | `xtickrotate` | Rotation angle for x-axis tick labels. **TYPE:** `Optional[Union[int, List[Optional[int]]]]` **DEFAULT:** `None` | | `yticks` | Custom y-axis tick positions. **TYPE:** `Optional[Union[List[Union[int, float]], List[List[Union[int, float]]]]]` **DEFAULT:** `None` | | `yticklabels` | Custom y-axis tick labels. **TYPE:** `Optional[Union[List[str], List[List[str]]]]` **DEFAULT:** `None` | | `ytickrotate` | Rotation angle for y-axis tick labels. **TYPE:** `Optional[Union[int, List[Optional[int]]]]` **DEFAULT:** `None` | | `vlines` | Vertical line(s) to plot. **TYPE:** `Optional[Union[VLinePlotAttrs, List[VLinePlotAttrs], List[Union[VLinePlotAttrs, List[VLinePlotAttrs], None]]]]` **DEFAULT:** `None` | | `hlines` | Horizontal line(s) to plot. **TYPE:** `Optional[Union[HLinePlotAttrs, List[HLinePlotAttrs], List[Union[HLinePlotAttrs, List[HLinePlotAttrs], None]]]]` **DEFAULT:** `None` | | `texts` | Text annotation(s) to draw. **TYPE:** `Optional[Union[TextAttrs, List[TextAttrs], List[Union[TextAttrs, List[TextAttrs], None]]]]` **DEFAULT:** `None` | | `x` | The key name in data for x-axis values (default: "x"). **TYPE:** `Optional[Union[str, List[Optional[str]]]]` **DEFAULT:** `None` | | RETURNS | DESCRIPTION | | ------------ | ------------------------------------ | | `plt.Figure` | The figure containing the histogram. | ### datachart.charts.BoxPlot ``` BoxPlot( data: Union[ List[BoxDataPointAttrs], List[List[BoxDataPointAttrs]], ], *, title: Optional[str] = None, xlabel: Optional[str] = None, ylabel: Optional[str] = None, subtitle: Optional[ Union[str, List[Optional[str]]] ] = None, emphasis: Optional[ Union[EMPHASIS, str, List[Optional[str]]] ] = None, figsize: Optional[ Union[FIG_SIZE, Tuple[float, float]] ] = None, xmin: Optional[Union[int, float]] = None, xmax: Optional[Union[int, float]] = None, ymin: Optional[Union[int, float]] = None, ymax: Optional[Union[int, float]] = None, show_legend: Optional[bool] = None, show_grid: Optional[Union[SHOW_GRID, str]] = None, show_outliers: Optional[bool] = None, show_notch: Optional[bool] = None, aspect_ratio: Optional[Union[ASPECT_RATIO, str]] = None, orientation: Optional[ Union[ORIENTATION, str] ] = ORIENTATION.VERTICAL, scaley: Optional[Union[SCALE, str]] = None, subplots: Optional[bool] = None, max_cols: Optional[int] = None, sharex: Optional[bool] = None, sharey: Optional[bool] = None, style: Optional[ Union[BoxStyleAttrs, List[Optional[BoxStyleAttrs]]] ] = None, xticks: Optional[ Union[ List[Union[int, float]], List[List[Union[int, float]]], ] ] = None, xticklabels: Optional[ Union[List[str], List[List[str]]] ] = None, xtickrotate: Optional[ Union[int, List[Optional[int]]] ] = None, yticks: Optional[ Union[ List[Union[int, float]], List[List[Union[int, float]]], ] ] = None, yticklabels: Optional[ Union[List[str], List[List[str]]] ] = None, ytickrotate: Optional[ Union[int, List[Optional[int]]] ] = None, vlines: Optional[ Union[ VLinePlotAttrs, List[VLinePlotAttrs], List[ Union[ VLinePlotAttrs, List[VLinePlotAttrs], None, ] ], ] ] = None, hlines: Optional[ Union[ HLinePlotAttrs, List[HLinePlotAttrs], List[ Union[ HLinePlotAttrs, List[HLinePlotAttrs], None, ] ], ] ] = None, texts: Optional[ Union[ TextAttrs, List[TextAttrs], List[Union[TextAttrs, List[TextAttrs], None]], ] ] = None, label: Optional[Union[str, List[Optional[str]]]] = None, value: Optional[Union[str, List[Optional[str]]]] = None ) -> plt.Figure ``` Creates the box plot. A box plot summarizes a numeric distribution per group by its median, quartiles, whiskers, and outliers. Use it to compare the level and spread of many groups compactly, or to spot skew and outliers, when the full distribution shape is not needed. For shape use ViolinPlot; for the raw points use SwarmPlot. Added in v0.7.0 Examples: ``` >>> from datachart.charts import BoxPlot >>> figure = BoxPlot( ... data=[ ... {"label": "Group A", "value": 10}, ... {"label": "Group A", "value": 15}, ... {"label": "Group A", "value": 12}, ... {"label": "Group B", "value": 20}, ... {"label": "Group B", "value": 25}, ... {"label": "Group B", "value": 22}, ... ], ... title="Basic Box Plot", ... xlabel="Group", ... ylabel="Value" ... ) ``` | PARAMETER | DESCRIPTION | | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `data` | The data points for the box plot(s). Can be a single list of data points for one chart, or a list of lists for multiple charts/subplots. Each data point should have a label (category) and value (numeric). **TYPE:** `Union[List[BoxDataPointAttrs], List[List[BoxDataPointAttrs]]]` | | `title` | The title of the chart. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `xlabel` | The x-axis label. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `ylabel` | The y-axis label. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `subtitle` | The subtitle(s) for individual charts. Used as legend labels. **TYPE:** `Optional[Union[str, List[Optional[str]]]]` **DEFAULT:** `None` | | `emphasis` | The emphasis role(s), aligned with the box labels of one call (a single value applies to every box): "background" mutes a box and its whiskers, caps, median, and outliers, "highlight" bolds the box edges and median, None leaves it unchanged. **TYPE:** `Optional[Union[EMPHASIS, str, List[Optional[str]]]]` **DEFAULT:** `None` | | `figsize` | The size of the figure. **TYPE:** `Optional[Union[FIG_SIZE, Tuple[float, float]]]` **DEFAULT:** `None` | | `xmin` | The minimum x-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `xmax` | The maximum x-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `ymin` | The minimum y-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `ymax` | The maximum y-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `show_legend` | Whether to show the legend. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `show_grid` | Which grid lines to show (e.g., "both", "x", "y"). **TYPE:** `Optional[Union[SHOW_GRID, str]]` **DEFAULT:** `None` | | `show_outliers` | Whether to show outliers. Defaults to True. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `show_notch` | Whether to show notched boxes for median confidence interval. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `aspect_ratio` | The aspect ratio of the axes ("auto" or "equal"). See ASPECT_RATIO. **TYPE:** `Optional[Union[ASPECT_RATIO, str]]` **DEFAULT:** `None` | | `orientation` | The orientation of the boxes (vertical or horizontal). **TYPE:** `Optional[Union[ORIENTATION, str]]` **DEFAULT:** `ORIENTATION.VERTICAL` | | `scaley` | The y-axis scale (e.g., "log", "linear"). **TYPE:** `Optional[Union[SCALE, str]]` **DEFAULT:** `None` | | `subplots` | Whether to create separate subplots for each chart. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `max_cols` | Maximum number of columns in subplots (when subplots=True). **TYPE:** `Optional[int]` **DEFAULT:** `None` | | `sharex` | Whether to share the x-axis in subplots. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `sharey` | Whether to share the y-axis in subplots. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `style` | Style configuration(s) for the box(es). **TYPE:** `Optional[Union[BoxStyleAttrs, List[Optional[BoxStyleAttrs]]]]` **DEFAULT:** `None` | | `xticks` | Custom x-axis tick positions. **TYPE:** `Optional[Union[List[Union[int, float]], List[List[Union[int, float]]]]]` **DEFAULT:** `None` | | `xticklabels` | Custom x-axis tick labels. **TYPE:** `Optional[Union[List[str], List[List[str]]]]` **DEFAULT:** `None` | | `xtickrotate` | Rotation angle for x-axis tick labels. **TYPE:** `Optional[Union[int, List[Optional[int]]]]` **DEFAULT:** `None` | | `yticks` | Custom y-axis tick positions. **TYPE:** `Optional[Union[List[Union[int, float]], List[List[Union[int, float]]]]]` **DEFAULT:** `None` | | `yticklabels` | Custom y-axis tick labels. **TYPE:** `Optional[Union[List[str], List[List[str]]]]` **DEFAULT:** `None` | | `ytickrotate` | Rotation angle for y-axis tick labels. **TYPE:** `Optional[Union[int, List[Optional[int]]]]` **DEFAULT:** `None` | | `vlines` | Vertical line(s) to plot. **TYPE:** `Optional[Union[VLinePlotAttrs, List[VLinePlotAttrs], List[Union[VLinePlotAttrs, List[VLinePlotAttrs], None]]]]` **DEFAULT:** `None` | | `hlines` | Horizontal line(s) to plot. **TYPE:** `Optional[Union[HLinePlotAttrs, List[HLinePlotAttrs], List[Union[HLinePlotAttrs, List[HLinePlotAttrs], None]]]]` **DEFAULT:** `None` | | `texts` | Text annotation(s) to draw. **TYPE:** `Optional[Union[TextAttrs, List[TextAttrs], List[Union[TextAttrs, List[TextAttrs], None]]]]` **DEFAULT:** `None` | | `label` | The key name in data for label/category values (default: "label"). **TYPE:** `Optional[Union[str, List[Optional[str]]]]` **DEFAULT:** `None` | | `value` | The key name in data for numeric values (default: "value"). **TYPE:** `Optional[Union[str, List[Optional[str]]]]` **DEFAULT:** `None` | | RETURNS | DESCRIPTION | | ------------ | ----------------------------------- | | `plt.Figure` | The figure containing the box plot. | ### datachart.charts.ViolinPlot ``` ViolinPlot( data: Union[ List[ViolinDataPointAttrs], List[List[ViolinDataPointAttrs]], ], *, title: Optional[str] = None, xlabel: Optional[str] = None, ylabel: Optional[str] = None, subtitle: Optional[ Union[str, List[Optional[str]]] ] = None, emphasis: Optional[ Union[EMPHASIS, str, List[Optional[str]]] ] = None, figsize: Optional[ Union[FIG_SIZE, Tuple[float, float]] ] = None, xmin: Optional[Union[int, float]] = None, xmax: Optional[Union[int, float]] = None, ymin: Optional[Union[int, float]] = None, ymax: Optional[Union[int, float]] = None, show_legend: Optional[bool] = None, show_grid: Optional[Union[SHOW_GRID, str]] = None, aspect_ratio: Optional[Union[ASPECT_RATIO, str]] = None, orientation: Optional[ Union[ORIENTATION, str] ] = ORIENTATION.VERTICAL, scaley: Optional[Union[SCALE, str]] = None, subplots: Optional[bool] = None, max_cols: Optional[int] = None, sharex: Optional[bool] = None, sharey: Optional[bool] = None, style: Optional[ Union[ ViolinStyleAttrs, List[Optional[ViolinStyleAttrs]], ] ] = None, xticks: Optional[ Union[ List[Union[int, float]], List[List[Union[int, float]]], ] ] = None, xticklabels: Optional[ Union[List[str], List[List[str]]] ] = None, xtickrotate: Optional[ Union[int, List[Optional[int]]] ] = None, yticks: Optional[ Union[ List[Union[int, float]], List[List[Union[int, float]]], ] ] = None, yticklabels: Optional[ Union[List[str], List[List[str]]] ] = None, ytickrotate: Optional[ Union[int, List[Optional[int]]] ] = None, vlines: Optional[ Union[ VLinePlotAttrs, List[VLinePlotAttrs], List[ Union[ VLinePlotAttrs, List[VLinePlotAttrs], None, ] ], ] ] = None, hlines: Optional[ Union[ HLinePlotAttrs, List[HLinePlotAttrs], List[ Union[ HLinePlotAttrs, List[HLinePlotAttrs], None, ] ], ] ] = None, texts: Optional[ Union[ TextAttrs, List[TextAttrs], List[Union[TextAttrs, List[TextAttrs], None]], ] ] = None, label: Optional[Union[str, List[Optional[str]]]] = None, value: Optional[Union[str, List[Optional[str]]]] = None, inner: Optional[ Union[VIOLIN_INNER, str] ] = VIOLIN_INNER.BOX, bandwidth: Optional[ Union[BANDWIDTH, str, float] ] = None, split: Optional[str] = None ) -> plt.Figure ``` Creates the violin plot. A violin plot draws the kernel density estimate of each group's numeric distribution as a mirrored profile, showing shape (multimodality, skew, tails) that a box plot hides. Use it to compare distributions across groups when shape matters and each group has enough samples for a density estimate. Added in 0.9.0 Examples: ``` >>> from datachart.charts import ViolinPlot >>> figure = ViolinPlot( ... data=[ ... {"label": "Group A", "value": 10}, ... {"label": "Group A", "value": 15}, ... {"label": "Group A", "value": 12}, ... {"label": "Group B", "value": 20}, ... {"label": "Group B", "value": 25}, ... {"label": "Group B", "value": 22}, ... ], ... title="Basic Violin Plot", ... xlabel="Group", ... ylabel="Value" ... ) ``` | PARAMETER | DESCRIPTION | | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `data` | The data points for the violin plot(s). Can be a single list of data points for one chart, or a list of lists for multiple charts/subplots. Each data point should have a label (category) and value (numeric). **TYPE:** `Union[List[ViolinDataPointAttrs], List[List[ViolinDataPointAttrs]]]` | | `title` | The title of the chart. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `xlabel` | The x-axis label. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `ylabel` | The y-axis label. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `subtitle` | The subtitle(s) for individual charts (subplots). **TYPE:** `Optional[Union[str, List[Optional[str]]]]` **DEFAULT:** `None` | | `emphasis` | The emphasis role(s), aligned with the violin labels of one call (a single value applies to every violin): "background" mutes a violin body and its inner marks, "highlight" bolds the body edge, None leaves it unchanged. **TYPE:** `Optional[Union[EMPHASIS, str, List[Optional[str]]]]` **DEFAULT:** `None` | | `figsize` | The size of the figure. **TYPE:** `Optional[Union[FIG_SIZE, Tuple[float, float]]]` **DEFAULT:** `None` | | `xmin` | The minimum x-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `xmax` | The maximum x-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `ymin` | The minimum y-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `ymax` | The maximum y-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `show_legend` | Whether to show the legend. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `show_grid` | Which grid lines to show (e.g., "both", "x", "y"). **TYPE:** `Optional[Union[SHOW_GRID, str]]` **DEFAULT:** `None` | | `aspect_ratio` | The aspect ratio of the axes ("auto" or "equal"). See ASPECT_RATIO. **TYPE:** `Optional[Union[ASPECT_RATIO, str]]` **DEFAULT:** `None` | | `orientation` | The orientation of the violins (vertical or horizontal). **TYPE:** `Optional[Union[ORIENTATION, str]]` **DEFAULT:** `ORIENTATION.VERTICAL` | | `scaley` | The y-axis scale (e.g., "log", "linear"). **TYPE:** `Optional[Union[SCALE, str]]` **DEFAULT:** `None` | | `subplots` | Whether to create separate subplots for each chart. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `max_cols` | Maximum number of columns in subplots (when subplots=True). **TYPE:** `Optional[int]` **DEFAULT:** `None` | | `sharex` | Whether to share the x-axis in subplots. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `sharey` | Whether to share the y-axis in subplots. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `style` | Style configuration(s) for the violin(s). **TYPE:** `Optional[Union[ViolinStyleAttrs, List[Optional[ViolinStyleAttrs]]]]` **DEFAULT:** `None` | | `xticks` | Custom x-axis tick positions. **TYPE:** `Optional[Union[List[Union[int, float]], List[List[Union[int, float]]]]]` **DEFAULT:** `None` | | `xticklabels` | Custom x-axis tick labels. **TYPE:** `Optional[Union[List[str], List[List[str]]]]` **DEFAULT:** `None` | | `xtickrotate` | Rotation angle for x-axis tick labels. **TYPE:** `Optional[Union[int, List[Optional[int]]]]` **DEFAULT:** `None` | | `yticks` | Custom y-axis tick positions. **TYPE:** `Optional[Union[List[Union[int, float]], List[List[Union[int, float]]]]]` **DEFAULT:** `None` | | `yticklabels` | Custom y-axis tick labels. **TYPE:** `Optional[Union[List[str], List[List[str]]]]` **DEFAULT:** `None` | | `ytickrotate` | Rotation angle for y-axis tick labels. **TYPE:** `Optional[Union[int, List[Optional[int]]]]` **DEFAULT:** `None` | | `vlines` | Vertical line(s) to plot. **TYPE:** `Optional[Union[VLinePlotAttrs, List[VLinePlotAttrs], List[Union[VLinePlotAttrs, List[VLinePlotAttrs], None]]]]` **DEFAULT:** `None` | | `hlines` | Horizontal line(s) to plot. **TYPE:** `Optional[Union[HLinePlotAttrs, List[HLinePlotAttrs], List[Union[HLinePlotAttrs, List[HLinePlotAttrs], None]]]]` **DEFAULT:** `None` | | `texts` | Text annotation(s) to draw. **TYPE:** `Optional[Union[TextAttrs, List[TextAttrs], List[Union[TextAttrs, List[TextAttrs], None]]]]` **DEFAULT:** `None` | | `label` | The key name in data for label/category values (default: "label"). **TYPE:** `Optional[Union[str, List[Optional[str]]]]` **DEFAULT:** `None` | | `value` | The key name in data for numeric values (default: "value"). **TYPE:** `Optional[Union[str, List[Optional[str]]]]` **DEFAULT:** `None` | | `inner` | The marks drawn inside each body: "box" (quartile bar, 1.5·IQR whisker, median dot), "quartiles" (dashed median, dotted Q1/Q3), "median" (one line), or None (body only). See VIOLIN_INNER. **TYPE:** `Optional[Union[VIOLIN_INNER, str]]` **DEFAULT:** `VIOLIN_INNER.BOX` | | `bandwidth` | The KDE bandwidth: None or "scott" (Scott's rule), "silverman", or a scalar factor. See BANDWIDTH. **TYPE:** `Optional[Union[BANDWIDTH, str, float]]` **DEFAULT:** `None` | | `split` | The key name in data whose exactly two distinct values become the left and right halves of each violin, colored from the multiple palette and listed in the legend. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | RETURNS | DESCRIPTION | | ------------ | -------------------------------------- | | `plt.Figure` | The figure containing the violin plot. | ### datachart.charts.SwarmPlot ``` SwarmPlot( data: Union[ List[SwarmDataPointAttrs], List[List[SwarmDataPointAttrs]], ], *, title: Optional[str] = None, xlabel: Optional[str] = None, ylabel: Optional[str] = None, subtitle: Optional[ Union[str, List[Optional[str]]] ] = None, emphasis: Optional[ Union[EMPHASIS, str, List[Optional[str]]] ] = None, figsize: Optional[ Union[FIG_SIZE, Tuple[float, float]] ] = None, xmin: Optional[Union[int, float]] = None, xmax: Optional[Union[int, float]] = None, ymin: Optional[Union[int, float]] = None, ymax: Optional[Union[int, float]] = None, show_legend: Optional[bool] = None, show_grid: Optional[Union[SHOW_GRID, str]] = None, mode: Union[SWARM_MODE, str] = SWARM_MODE.SWARM, jitter: float = 0.4, aspect_ratio: Optional[Union[ASPECT_RATIO, str]] = None, orientation: Optional[ Union[ORIENTATION, str] ] = ORIENTATION.VERTICAL, scaley: Optional[Union[SCALE, str]] = None, subplots: Optional[bool] = None, max_cols: Optional[int] = None, sharex: Optional[bool] = None, sharey: Optional[bool] = None, style: Optional[ Union[ SwarmStyleAttrs, List[Optional[SwarmStyleAttrs]] ] ] = None, xticks: Optional[ Union[ List[Union[int, float]], List[List[Union[int, float]]], ] ] = None, xticklabels: Optional[ Union[List[str], List[List[str]]] ] = None, xtickrotate: Optional[ Union[int, List[Optional[int]]] ] = None, yticks: Optional[ Union[ List[Union[int, float]], List[List[Union[int, float]]], ] ] = None, yticklabels: Optional[ Union[List[str], List[List[str]]] ] = None, ytickrotate: Optional[ Union[int, List[Optional[int]]] ] = None, vlines: Optional[ Union[ VLinePlotAttrs, List[VLinePlotAttrs], List[ Union[ VLinePlotAttrs, List[VLinePlotAttrs], None, ] ], ] ] = None, hlines: Optional[ Union[ HLinePlotAttrs, List[HLinePlotAttrs], List[ Union[ HLinePlotAttrs, List[HLinePlotAttrs], None, ] ], ] ] = None, texts: Optional[ Union[ TextAttrs, List[TextAttrs], List[Union[TextAttrs, List[TextAttrs], None]], ] ] = None, label: Optional[Union[str, List[Optional[str]]]] = None, value: Optional[Union[str, List[Optional[str]]]] = None ) -> plt.Figure ``` Creates the swarm plot. A swarm plot draws every observation as a point at its group's category position, spread across the category width so the points do not hide each other, making counts and gaps visible. Use it for small-to-medium samples where each observation matters, or overlay it on a BoxPlot with `Panel` (the two share positions). For large samples prefer ViolinPlot. Added in 0.9.0 Examples: ``` >>> from datachart.charts import SwarmPlot >>> figure = SwarmPlot( ... data=[ ... {"label": "Group A", "value": 10}, ... {"label": "Group A", "value": 15}, ... {"label": "Group A", "value": 12}, ... {"label": "Group B", "value": 20}, ... {"label": "Group B", "value": 25}, ... {"label": "Group B", "value": 22}, ... ], ... title="Basic Swarm Plot", ... xlabel="Group", ... ylabel="Value" ... ) ``` | PARAMETER | DESCRIPTION | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `data` | The data points for the swarm plot(s). Can be a single list of data points for one chart, or a list of lists for multiple charts. Each data point should have a label (category) and value (numeric). **TYPE:** `Union[List[SwarmDataPointAttrs], List[List[SwarmDataPointAttrs]]]` | | `title` | The title of the chart. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `xlabel` | The x-axis label. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `ylabel` | The y-axis label. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `subtitle` | The subtitle(s) for individual charts. Used as legend labels. **TYPE:** `Optional[Union[str, List[Optional[str]]]]` **DEFAULT:** `None` | | `emphasis` | The emphasis role(s), aligned with the group labels of one call (a single value applies to every group): "background" mutes a group's points, "highlight" bolds their edges, None leaves them unchanged. **TYPE:** `Optional[Union[EMPHASIS, str, List[Optional[str]]]]` **DEFAULT:** `None` | | `figsize` | The size of the figure. **TYPE:** `Optional[Union[FIG_SIZE, Tuple[float, float]]]` **DEFAULT:** `None` | | `xmin` | The minimum x-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `xmax` | The maximum x-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `ymin` | The minimum y-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `ymax` | The maximum y-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `show_legend` | Whether to show the legend. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `show_grid` | Which grid lines to show (e.g., "both", "x", "y"). **TYPE:** `Optional[Union[SHOW_GRID, str]]` **DEFAULT:** `None` | | `mode` | How the points spread across the category width. See SWARM_MODE: "swarm" packs the points so none overlap, from the marker size at draw time (axis limits changed afterwards can shift the spacing); "strip" jitters them uniformly. **TYPE:** `Union[SWARM_MODE, str]` **DEFAULT:** `SWARM_MODE.SWARM` | | `jitter` | The strip jitter width, as a fraction of the category width. Only used with mode="strip". **TYPE:** `float` **DEFAULT:** `0.4` | | `aspect_ratio` | The aspect ratio of the axes ("auto" or "equal"). See ASPECT_RATIO. **TYPE:** `Optional[Union[ASPECT_RATIO, str]]` **DEFAULT:** `None` | | `orientation` | The orientation of the swarms (vertical or horizontal). **TYPE:** `Optional[Union[ORIENTATION, str]]` **DEFAULT:** `ORIENTATION.VERTICAL` | | `scaley` | The y-axis scale (e.g., "log", "linear"). **TYPE:** `Optional[Union[SCALE, str]]` **DEFAULT:** `None` | | `subplots` | Whether to create separate subplots for each chart. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `max_cols` | Maximum number of columns in subplots (when subplots=True). **TYPE:** `Optional[int]` **DEFAULT:** `None` | | `sharex` | Whether to share the x-axis in subplots. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `sharey` | Whether to share the y-axis in subplots. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `style` | Style configuration(s) for the points. **TYPE:** `Optional[Union[SwarmStyleAttrs, List[Optional[SwarmStyleAttrs]]]]` **DEFAULT:** `None` | | `xticks` | Custom x-axis tick positions. **TYPE:** `Optional[Union[List[Union[int, float]], List[List[Union[int, float]]]]]` **DEFAULT:** `None` | | `xticklabels` | Custom x-axis tick labels. **TYPE:** `Optional[Union[List[str], List[List[str]]]]` **DEFAULT:** `None` | | `xtickrotate` | Rotation angle for x-axis tick labels. **TYPE:** `Optional[Union[int, List[Optional[int]]]]` **DEFAULT:** `None` | | `yticks` | Custom y-axis tick positions. **TYPE:** `Optional[Union[List[Union[int, float]], List[List[Union[int, float]]]]]` **DEFAULT:** `None` | | `yticklabels` | Custom y-axis tick labels. **TYPE:** `Optional[Union[List[str], List[List[str]]]]` **DEFAULT:** `None` | | `ytickrotate` | Rotation angle for y-axis tick labels. **TYPE:** `Optional[Union[int, List[Optional[int]]]]` **DEFAULT:** `None` | | `vlines` | Vertical line(s) to plot. **TYPE:** `Optional[Union[VLinePlotAttrs, List[VLinePlotAttrs], List[Union[VLinePlotAttrs, List[VLinePlotAttrs], None]]]]` **DEFAULT:** `None` | | `hlines` | Horizontal line(s) to plot. **TYPE:** `Optional[Union[HLinePlotAttrs, List[HLinePlotAttrs], List[Union[HLinePlotAttrs, List[HLinePlotAttrs], None]]]]` **DEFAULT:** `None` | | `texts` | Text annotation(s) to draw. **TYPE:** `Optional[Union[TextAttrs, List[TextAttrs], List[Union[TextAttrs, List[TextAttrs], None]]]]` **DEFAULT:** `None` | | `label` | The key name in data for label/category values (default: "label"). **TYPE:** `Optional[Union[str, List[Optional[str]]]]` **DEFAULT:** `None` | | `value` | The key name in data for numeric values (default: "value"). **TYPE:** `Optional[Union[str, List[Optional[str]]]]` **DEFAULT:** `None` | | RETURNS | DESCRIPTION | | ------------ | ------------------------------------- | | `plt.Figure` | The figure containing the swarm plot. | ### datachart.charts.RaincloudPlot ``` RaincloudPlot( data: Union[ List[RaincloudDataPointAttrs], List[List[RaincloudDataPointAttrs]], ], *, title: Optional[str] = None, xlabel: Optional[str] = None, ylabel: Optional[str] = None, subtitle: Optional[ Union[str, List[Optional[str]]] ] = None, emphasis: Optional[ Union[EMPHASIS, str, List[Optional[str]]] ] = None, figsize: Optional[ Union[FIG_SIZE, Tuple[float, float]] ] = None, xmin: Optional[Union[int, float]] = None, xmax: Optional[Union[int, float]] = None, ymin: Optional[Union[int, float]] = None, ymax: Optional[Union[int, float]] = None, show_legend: Optional[bool] = None, show_grid: Optional[Union[SHOW_GRID, str]] = None, show_outliers: Optional[bool] = True, mode: Union[SWARM_MODE, str] = SWARM_MODE.SWARM, jitter: float = 0.4, bandwidth: Optional[ Union[BANDWIDTH, str, float] ] = None, aspect_ratio: Optional[Union[ASPECT_RATIO, str]] = None, orientation: Optional[ Union[ORIENTATION, str] ] = ORIENTATION.VERTICAL, scaley: Optional[Union[SCALE, str]] = None, subplots: Optional[bool] = None, max_cols: Optional[int] = None, sharex: Optional[bool] = None, sharey: Optional[bool] = None, style: Optional[ Union[ RaincloudStyleAttrs, List[Optional[RaincloudStyleAttrs]], ] ] = None, xticks: Optional[ Union[ List[Union[int, float]], List[List[Union[int, float]]], ] ] = None, xticklabels: Optional[ Union[List[str], List[List[str]]] ] = None, xtickrotate: Optional[ Union[int, List[Optional[int]]] ] = None, yticks: Optional[ Union[ List[Union[int, float]], List[List[Union[int, float]]], ] ] = None, yticklabels: Optional[ Union[List[str], List[List[str]]] ] = None, ytickrotate: Optional[ Union[int, List[Optional[int]]] ] = None, vlines: Optional[ Union[ VLinePlotAttrs, List[VLinePlotAttrs], List[ Union[ VLinePlotAttrs, List[VLinePlotAttrs], None, ] ], ] ] = None, hlines: Optional[ Union[ HLinePlotAttrs, List[HLinePlotAttrs], List[ Union[ HLinePlotAttrs, List[HLinePlotAttrs], None, ] ], ] ] = None, texts: Optional[ Union[ TextAttrs, List[TextAttrs], List[Union[TextAttrs, List[TextAttrs], None]], ] ] = None, label: Optional[Union[str, List[Optional[str]]]] = None, value: Optional[Union[str, List[Optional[str]]]] = None ) -> plt.Figure ``` Creates the raincloud plot. A raincloud plot draws each group as a cloud (a half violin of its density), its rain (the raw observations), and a box (the quartile summary) side by side at one category position, all in the group's palette color. Use it when you want the shape, the summary statistics, and the individual observations in a single view, for example when reporting experimental results per condition. Vertical rainclouds keep the cloud on the left; horizontal ones keep it above. Added in 0.9.0 Examples: ``` >>> from datachart.charts import RaincloudPlot >>> figure = RaincloudPlot( ... data=[ ... {"label": "Group A", "value": 10}, ... {"label": "Group A", "value": 15}, ... {"label": "Group A", "value": 12}, ... {"label": "Group B", "value": 20}, ... {"label": "Group B", "value": 25}, ... {"label": "Group B", "value": 22}, ... ], ... title="Basic Raincloud Plot", ... xlabel="Group", ... ylabel="Value" ... ) ``` | PARAMETER | DESCRIPTION | | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `data` | The data points for the raincloud plot(s). Can be a single list of data points for one chart, or a list of lists for multiple charts (drawn as subplots). Each data point should have a label (category) and value (numeric). **TYPE:** `Union[List[RaincloudDataPointAttrs], List[List[RaincloudDataPointAttrs]]]` | | `title` | The title of the chart. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `xlabel` | The x-axis label. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `ylabel` | The y-axis label. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `subtitle` | The subtitle(s) for individual charts. **TYPE:** `Optional[Union[str, List[Optional[str]]]]` **DEFAULT:** `None` | | `emphasis` | The emphasis role(s), aligned with the group labels of one call (a single value applies to every group): "background" mutes a group's cloud, rain, and box, "highlight" bolds their edges, None leaves them unchanged. **TYPE:** `Optional[Union[EMPHASIS, str, List[Optional[str]]]]` **DEFAULT:** `None` | | `figsize` | The size of the figure. **TYPE:** `Optional[Union[FIG_SIZE, Tuple[float, float]]]` **DEFAULT:** `None` | | `xmin` | The minimum x-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `xmax` | The maximum x-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `ymin` | The minimum y-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `ymax` | The maximum y-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `show_legend` | Whether to show the legend; one entry per group. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `show_grid` | Which grid lines to show (e.g., "both", "x", "y"). **TYPE:** `Optional[Union[SHOW_GRID, str]]` **DEFAULT:** `None` | | `show_outliers` | Whether the box shows outliers. **TYPE:** `Optional[bool]` **DEFAULT:** `True` | | `mode` | How the rain spreads across its width. See SWARM_MODE: "swarm" packs the points so none overlap; "strip" jitters them uniformly. **TYPE:** `Union[SWARM_MODE, str]` **DEFAULT:** `SWARM_MODE.SWARM` | | `jitter` | The strip jitter width, as a fraction of the category width like SwarmPlot, scaled down to the rain's narrower cell. Only used with mode="strip". **TYPE:** `float` **DEFAULT:** `0.4` | | `bandwidth` | The cloud's KDE bandwidth: None or "scott" (Scott's rule), "silverman" (Silverman's rule), or a scalar factor. See BANDWIDTH. **TYPE:** `Optional[Union[BANDWIDTH, str, float]]` **DEFAULT:** `None` | | `aspect_ratio` | The aspect ratio of the axes ("auto" or "equal"). See ASPECT_RATIO. **TYPE:** `Optional[Union[ASPECT_RATIO, str]]` **DEFAULT:** `None` | | `orientation` | The orientation of the rainclouds (vertical or horizontal). **TYPE:** `Optional[Union[ORIENTATION, str]]` **DEFAULT:** `ORIENTATION.VERTICAL` | | `scaley` | The y-axis scale (e.g., "log", "linear"). **TYPE:** `Optional[Union[SCALE, str]]` **DEFAULT:** `None` | | `subplots` | Whether to create separate subplots for each chart. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `max_cols` | Maximum number of columns in subplots (when subplots=True). **TYPE:** `Optional[int]` **DEFAULT:** `None` | | `sharex` | Whether to share the x-axis in subplots. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `sharey` | Whether to share the y-axis in subplots. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `style` | Style configuration(s); the violin keys style the cloud, the swarm keys the rain, and the box keys the box. **TYPE:** `Optional[Union[RaincloudStyleAttrs, List[Optional[RaincloudStyleAttrs]]]]` **DEFAULT:** `None` | | `xticks` | Custom x-axis tick positions. **TYPE:** `Optional[Union[List[Union[int, float]], List[List[Union[int, float]]]]]` **DEFAULT:** `None` | | `xticklabels` | Custom x-axis tick labels. **TYPE:** `Optional[Union[List[str], List[List[str]]]]` **DEFAULT:** `None` | | `xtickrotate` | Rotation angle for x-axis tick labels. **TYPE:** `Optional[Union[int, List[Optional[int]]]]` **DEFAULT:** `None` | | `yticks` | Custom y-axis tick positions. **TYPE:** `Optional[Union[List[Union[int, float]], List[List[Union[int, float]]]]]` **DEFAULT:** `None` | | `yticklabels` | Custom y-axis tick labels. **TYPE:** `Optional[Union[List[str], List[List[str]]]]` **DEFAULT:** `None` | | `ytickrotate` | Rotation angle for y-axis tick labels. **TYPE:** `Optional[Union[int, List[Optional[int]]]]` **DEFAULT:** `None` | | `vlines` | Vertical line(s) to plot. **TYPE:** `Optional[Union[VLinePlotAttrs, List[VLinePlotAttrs], List[Union[VLinePlotAttrs, List[VLinePlotAttrs], None]]]]` **DEFAULT:** `None` | | `hlines` | Horizontal line(s) to plot. **TYPE:** `Optional[Union[HLinePlotAttrs, List[HLinePlotAttrs], List[Union[HLinePlotAttrs, List[HLinePlotAttrs], None]]]]` **DEFAULT:** `None` | | `texts` | Text annotation(s) to draw. **TYPE:** `Optional[Union[TextAttrs, List[TextAttrs], List[Union[TextAttrs, List[TextAttrs], None]]]]` **DEFAULT:** `None` | | `label` | The key name in data for label/category values (default: "label"). **TYPE:** `Optional[Union[str, List[Optional[str]]]]` **DEFAULT:** `None` | | `value` | The key name in data for numeric values (default: "value"). **TYPE:** `Optional[Union[str, List[Optional[str]]]]` **DEFAULT:** `None` | | RETURNS | DESCRIPTION | | ------------ | ----------------------------------------- | | `plt.Figure` | The figure containing the raincloud plot. | ## Relationships ### datachart.charts.ScatterChart ``` ScatterChart( data: Union[ List[ScatterDataPointAttrs], List[List[ScatterDataPointAttrs]], ], *, title: Optional[str] = None, xlabel: Optional[str] = None, ylabel: Optional[str] = None, subtitle: Optional[ Union[str, List[Optional[str]]] ] = None, emphasis: Optional[ Union[EMPHASIS, str, List[Optional[str]]] ] = None, figsize: Optional[ Union[FIG_SIZE, Tuple[float, float]] ] = None, xmin: Optional[Union[int, float]] = None, xmax: Optional[Union[int, float]] = None, ymin: Optional[Union[int, float]] = None, ymax: Optional[Union[int, float]] = None, show_legend: Optional[bool] = None, show_grid: Optional[Union[SHOW_GRID, str]] = None, show_regression: Optional[bool] = None, show_ci: Optional[bool] = None, ci_level: Optional[float] = None, show_correlation: Optional[bool] = None, aspect_ratio: Optional[Union[ASPECT_RATIO, str]] = None, scalex: Optional[Union[SCALE, str]] = None, scaley: Optional[Union[SCALE, str]] = None, subplots: Optional[bool] = None, max_cols: Optional[int] = None, sharex: Optional[bool] = None, sharey: Optional[bool] = None, style: Optional[ Union[ ScatterStyleAttrs, List[Optional[ScatterStyleAttrs]], ] ] = None, xticks: Optional[ Union[ List[Union[int, float]], List[List[Union[int, float]]], ] ] = None, xticklabels: Optional[ Union[List[str], List[List[str]]] ] = None, xtickrotate: Optional[ Union[int, List[Optional[int]]] ] = None, yticks: Optional[ Union[ List[Union[int, float]], List[List[Union[int, float]]], ] ] = None, yticklabels: Optional[ Union[List[str], List[List[str]]] ] = None, ytickrotate: Optional[ Union[int, List[Optional[int]]] ] = None, vlines: Optional[ Union[ VLinePlotAttrs, List[VLinePlotAttrs], List[ Union[ VLinePlotAttrs, List[VLinePlotAttrs], None, ] ], ] ] = None, hlines: Optional[ Union[ HLinePlotAttrs, List[HLinePlotAttrs], List[ Union[ HLinePlotAttrs, List[HLinePlotAttrs], None, ] ], ] ] = None, texts: Optional[ Union[ TextAttrs, List[TextAttrs], List[Union[TextAttrs, List[TextAttrs], None]], ] ] = None, x: Optional[Union[str, List[Optional[str]]]] = None, y: Optional[Union[str, List[Optional[str]]]] = None, size: Optional[Union[str, List[Optional[str]]]] = None, hue: Optional[Union[str, List[Optional[str]]]] = None, size_range: Optional[Tuple[float, float]] = None ) -> plt.Figure ``` Creates a scatter chart. Each point is one observation placed by two numeric variables, optionally with a third encoded as marker size. Use it to check whether two variables are related, spot clusters and outliers, and quantify the link with the optional regression line and correlation coefficient. For ordered series use LineChart. Added in v0.7.0 Examples: ``` >>> from datachart.charts import ScatterChart >>> # Basic scatter plot >>> figure = ScatterChart( ... data=[ ... {"x": 1, "y": 5}, ... {"x": 2, "y": 10}, ... {"x": 3, "y": 15}, ... {"x": 4, "y": 20}, ... {"x": 5, "y": 25} ... ], ... title="Basic Scatter Chart", ... xlabel="X", ... ylabel="Y" ... ) >>> >>> # Scatter with hue grouping >>> figure = ScatterChart( ... data=[ ... {"x": 1, "y": 5, "category": "A"}, ... {"x": 2, "y": 10, "category": "B"}, ... ], ... hue="category", ... show_legend=True ... ) >>> >>> # Bubble chart with size variable >>> figure = ScatterChart( ... data=[ ... {"x": 1, "y": 5, "pop": 100}, ... {"x": 2, "y": 10, "pop": 200} ... ], ... size="pop", ... size_range=(20, 200) ... ) >>> >>> # Scatter with regression line >>> figure = ScatterChart( ... data=[...], ... show_regression=True, ... show_ci=True, ... ci_level=0.95 ... ) >>> >>> # Scatter with correlation annotation >>> figure = ScatterChart( ... data=[...], ... show_correlation=True ... ) ``` | PARAMETER | DESCRIPTION | | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `data` | The data points for the scatter chart(s). Can be a single list of data points for one chart, or a list of lists for multiple charts/subplots. **TYPE:** `Union[List[ScatterDataPointAttrs], List[List[ScatterDataPointAttrs]]]` | | `title` | The title of the chart. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `xlabel` | The x-axis label. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `ylabel` | The y-axis label. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `subtitle` | The subtitle(s) for individual charts. Used as legend labels. **TYPE:** `Optional[Union[str, List[Optional[str]]]]` **DEFAULT:** `None` | | `emphasis` | The emphasis role(s) for individual charts, aligned like style: "background" mutes a chart (theme muted color, lowered alpha, behind the others, no legend entry), "highlight" gives it a contrasting edge and brings it to the front, None leaves it unchanged. **TYPE:** `Optional[Union[EMPHASIS, str, List[Optional[str]]]]` **DEFAULT:** `None` | | `figsize` | The size of the figure. **TYPE:** `Optional[Union[FIG_SIZE, Tuple[float, float]]]` **DEFAULT:** `None` | | `xmin` | The minimum x-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `xmax` | The maximum x-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `ymin` | The minimum y-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `ymax` | The maximum y-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `show_legend` | Whether to show the legend. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `show_grid` | Which grid lines to show (e.g., "both", "x", "y"). **TYPE:** `Optional[Union[SHOW_GRID, str]]` **DEFAULT:** `None` | | `show_regression` | Whether to show the regression line. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `show_ci` | Whether to show the confidence interval around the regression line. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `ci_level` | The confidence interval level (default 0.95). **TYPE:** `Optional[float]` **DEFAULT:** `None` | | `show_correlation` | Whether to show the Pearson correlation coefficient (r-value) as an annotation. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `aspect_ratio` | The aspect ratio of the axes ("auto" or "equal"). See ASPECT_RATIO. **TYPE:** `Optional[Union[ASPECT_RATIO, str]]` **DEFAULT:** `None` | | `scalex` | The x-axis scale (e.g., "log", "linear"). **TYPE:** `Optional[Union[SCALE, str]]` **DEFAULT:** `None` | | `scaley` | The y-axis scale (e.g., "log", "linear"). **TYPE:** `Optional[Union[SCALE, str]]` **DEFAULT:** `None` | | `subplots` | Whether to create separate subplots for each chart. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `max_cols` | Maximum number of columns in subplots (when subplots=True). **TYPE:** `Optional[int]` **DEFAULT:** `None` | | `sharex` | Whether to share the x-axis in subplots. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `sharey` | Whether to share the y-axis in subplots. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `style` | Style configuration(s) for the scatter markers. **TYPE:** `Optional[Union[ScatterStyleAttrs, List[Optional[ScatterStyleAttrs]]]]` **DEFAULT:** `None` | | `xticks` | Custom x-axis tick positions. **TYPE:** `Optional[Union[List[Union[int, float]], List[List[Union[int, float]]]]]` **DEFAULT:** `None` | | `xticklabels` | Custom x-axis tick labels. **TYPE:** `Optional[Union[List[str], List[List[str]]]]` **DEFAULT:** `None` | | `xtickrotate` | Rotation angle for x-axis tick labels. **TYPE:** `Optional[Union[int, List[Optional[int]]]]` **DEFAULT:** `None` | | `yticks` | Custom y-axis tick positions. **TYPE:** `Optional[Union[List[Union[int, float]], List[List[Union[int, float]]]]]` **DEFAULT:** `None` | | `yticklabels` | Custom y-axis tick labels. **TYPE:** `Optional[Union[List[str], List[List[str]]]]` **DEFAULT:** `None` | | `ytickrotate` | Rotation angle for y-axis tick labels. **TYPE:** `Optional[Union[int, List[Optional[int]]]]` **DEFAULT:** `None` | | `vlines` | Vertical line(s) to plot. **TYPE:** `Optional[Union[VLinePlotAttrs, List[VLinePlotAttrs], List[Union[VLinePlotAttrs, List[VLinePlotAttrs], None]]]]` **DEFAULT:** `None` | | `hlines` | Horizontal line(s) to plot. **TYPE:** `Optional[Union[HLinePlotAttrs, List[HLinePlotAttrs], List[Union[HLinePlotAttrs, List[HLinePlotAttrs], None]]]]` **DEFAULT:** `None` | | `texts` | Text annotation(s) to draw. **TYPE:** `Optional[Union[TextAttrs, List[TextAttrs], List[Union[TextAttrs, List[TextAttrs], None]]]]` **DEFAULT:** `None` | | `x` | The key name in data for x-axis values (default: "x"). **TYPE:** `Optional[Union[str, List[Optional[str]]]]` **DEFAULT:** `None` | | `y` | The key name in data for y-axis values (default: "y"). **TYPE:** `Optional[Union[str, List[Optional[str]]]]` **DEFAULT:** `None` | | `size` | The key name in data for marker size values (for bubble charts). **TYPE:** `Optional[Union[str, List[Optional[str]]]]` **DEFAULT:** `None` | | `hue` | The key name in data for color grouping (categorical variable). **TYPE:** `Optional[Union[str, List[Optional[str]]]]` **DEFAULT:** `None` | | `size_range` | Tuple of (min_size, max_size) for bubble charts (default: (20, 200)). **TYPE:** `Optional[Tuple[float, float]]` **DEFAULT:** `None` | | RETURNS | DESCRIPTION | | ------------ | ---------------------------------------- | | `plt.Figure` | The figure containing the scatter chart. | ### datachart.charts.Heatmap ``` Heatmap( data: Union[HeatmapDataAttrs, List[HeatmapDataAttrs]], *, title: Optional[str] = None, xlabel: Optional[str] = None, ylabel: Optional[str] = None, subtitle: Optional[ Union[str, List[Optional[str]]] ] = None, emphasis: None = None, figsize: Optional[ Union[FIG_SIZE, Tuple[float, float]] ] = None, xmin: Optional[Union[int, float]] = None, xmax: Optional[Union[int, float]] = None, ymin: Optional[Union[int, float]] = None, ymax: Optional[Union[int, float]] = None, show_legend: Optional[bool] = None, show_grid: Optional[Union[SHOW_GRID, str]] = None, show_colorbars: Optional[bool] = None, show_heatmap_values: Optional[bool] = None, aspect_ratio: Optional[Union[ASPECT_RATIO, str]] = None, subplots: Optional[bool] = None, max_cols: Optional[int] = None, sharex: Optional[bool] = None, sharey: Optional[bool] = None, style: Optional[ Union[ HeatmapStyleAttrs, List[Optional[HeatmapStyleAttrs]], ] ] = None, norm: Optional[Union[str, List[Optional[str]]]] = None, vmin: Optional[ Union[float, List[Optional[float]]] ] = None, vmax: Optional[ Union[float, List[Optional[float]]] ] = None, valfmt: Optional[ Union[VALUE_FORMAT, str, List[Optional[str]]] ] = None, xticks: Optional[ Union[ List[Union[int, float]], List[List[Union[int, float]]], ] ] = None, xticklabels: Optional[ Union[List[str], List[List[str]]] ] = None, xtickrotate: Optional[ Union[int, List[Optional[int]]] ] = None, yticks: Optional[ Union[ List[Union[int, float]], List[List[Union[int, float]]], ] ] = None, yticklabels: Optional[ Union[List[str], List[List[str]]] ] = None, ytickrotate: Optional[ Union[int, List[Optional[int]]] ] = None, colorbar: Optional[ Union[ HeatmapColorbarAttrs, List[Optional[HeatmapColorbarAttrs]], ] ] = None, texts: Optional[ Union[ TextAttrs, List[TextAttrs], List[Union[TextAttrs, List[TextAttrs], None]], ] ] = None ) -> plt.Figure ``` Creates the heatmap. A heatmap maps every cell of a 2-D matrix to a color, so structure in a grid of numbers (correlations, confusion matrices, feature-by-time tables) reads at a glance. Use it when both axes are categorical or gridded and the value is what matters; the color scale, colorbar, and cell value labels are all configurable. Added in v0.4.0 Examples: ``` >>> from datachart.charts import Heatmap >>> figure = Heatmap( ... data={ ... "x": ["a", "b", "c"], ... "y": ["p", "q", "r"], ... "z": [ ... [1, 2, 3], ... [4, 5, 6], ... [7, 8, 9], ... ], ... }, ... title="Basic Heatmap", ... xlabel="X", ... ylabel="Y" ... ) ``` | PARAMETER | DESCRIPTION | | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `data` | The labelled grid(s) for the heatmap(s): one {x, y, z} dict, or a list of them for multiple heatmaps/subplots. z is the 2-D matrix of cell values (rows along y, columns along x; None cells stay blank); x and y are optional tick labels for its columns and rows (any values, the indices by default). An explicit xticks/xticklabels (yticks/yticklabels) overrides them. **TYPE:** `Union[HeatmapDataAttrs, List[HeatmapDataAttrs]]` | | `title` | The title of the chart. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `xlabel` | The x-axis label. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `ylabel` | The y-axis label. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `subtitle` | The subtitle(s) for individual charts. **TYPE:** `Optional[Union[str, List[Optional[str]]]]` **DEFAULT:** `None` | | `emphasis` | Not supported: a heatmap is a single raster layer with no series to mute or highlight. Passing a value raises ValueError. **TYPE:** `None` **DEFAULT:** `None` | | `figsize` | The size of the figure. **TYPE:** `Optional[Union[FIG_SIZE, Tuple[float, float]]]` **DEFAULT:** `None` | | `xmin` | The minimum x-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `xmax` | The maximum x-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `ymin` | The minimum y-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `ymax` | The maximum y-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `show_legend` | Whether to show the legend (not typical for heatmaps). **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `show_grid` | Which grid lines to show (e.g., "both", "x", "y"). **TYPE:** `Optional[Union[SHOW_GRID, str]]` **DEFAULT:** `None` | | `show_colorbars` | Whether to show the colorbar(s). **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `show_heatmap_values` | Whether to show values on the heatmap cells. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `aspect_ratio` | The aspect ratio of the axes ("auto" or "equal"). See ASPECT_RATIO. **TYPE:** `Optional[Union[ASPECT_RATIO, str]]` **DEFAULT:** `None` | | `subplots` | Whether to create separate subplots for each heatmap. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `max_cols` | Maximum number of columns in subplots (when subplots=True). **TYPE:** `Optional[int]` **DEFAULT:** `None` | | `sharex` | Whether to share the x-axis in subplots. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `sharey` | Whether to share the y-axis in subplots. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `style` | Style configuration(s) for the heatmap(s). **TYPE:** `Optional[Union[HeatmapStyleAttrs, List[Optional[HeatmapStyleAttrs]]]]` **DEFAULT:** `None` | | `norm` | Value normalization method(s). **TYPE:** `Optional[Union[str, List[Optional[str]]]]` **DEFAULT:** `None` | | `vmin` | Minimum value(s) for normalization. **TYPE:** `Optional[Union[float, List[Optional[float]]]]` **DEFAULT:** `None` | | `vmax` | Maximum value(s) for normalization. **TYPE:** `Optional[Union[float, List[Optional[float]]]]` **DEFAULT:** `None` | | `valfmt` | Format string(s) for cell values, with the value named x (e.g., "{x:.1f}"). See VALUE_FORMAT. **TYPE:** `Optional[Union[VALUE_FORMAT, str, List[Optional[str]]]]` **DEFAULT:** `None` | | `xticks` | Custom x-axis tick positions. **TYPE:** `Optional[Union[List[Union[int, float]], List[List[Union[int, float]]]]]` **DEFAULT:** `None` | | `xticklabels` | Custom x-axis tick labels. **TYPE:** `Optional[Union[List[str], List[List[str]]]]` **DEFAULT:** `None` | | `xtickrotate` | Rotation angle for x-axis tick labels. **TYPE:** `Optional[Union[int, List[Optional[int]]]]` **DEFAULT:** `None` | | `yticks` | Custom y-axis tick positions. **TYPE:** `Optional[Union[List[Union[int, float]], List[List[Union[int, float]]]]]` **DEFAULT:** `None` | | `yticklabels` | Custom y-axis tick labels. **TYPE:** `Optional[Union[List[str], List[List[str]]]]` **DEFAULT:** `None` | | `ytickrotate` | Rotation angle for y-axis tick labels. **TYPE:** `Optional[Union[int, List[Optional[int]]]]` **DEFAULT:** `None` | | `colorbar` | Colorbar configuration(s). **TYPE:** `Optional[Union[HeatmapColorbarAttrs, List[Optional[HeatmapColorbarAttrs]]]]` **DEFAULT:** `None` | | `texts` | Text annotation(s) to draw. **TYPE:** `Optional[Union[TextAttrs, List[TextAttrs], List[Union[TextAttrs, List[TextAttrs], None]]]]` **DEFAULT:** `None` | | RETURNS | DESCRIPTION | | ------------ | ---------------------------------- | | `plt.Figure` | The figure containing the heatmap. | ### datachart.charts.ContourChart ``` ContourChart( data: Union[ContourDataAttrs, List[ContourDataAttrs]], *, title: Optional[str] = None, xlabel: Optional[str] = None, ylabel: Optional[str] = None, subtitle: Optional[ Union[str, List[Optional[str]]] ] = None, emphasis: Optional[ Union[EMPHASIS, str, List[Optional[str]]] ] = None, figsize: Optional[ Union[FIG_SIZE, Tuple[float, float]] ] = None, xmin: Optional[Union[int, float]] = None, xmax: Optional[Union[int, float]] = None, ymin: Optional[Union[int, float]] = None, ymax: Optional[Union[int, float]] = None, show_legend: Optional[bool] = None, show_grid: Optional[Union[SHOW_GRID, str]] = None, filled: Optional[bool] = None, levels: Optional[ Union[CONTOUR_LEVELS, str, int, List[float]] ] = None, show_labels: Optional[bool] = None, show_colorbars: Optional[bool] = None, aspect_ratio: Optional[Union[ASPECT_RATIO, str]] = None, scalex: Optional[Union[SCALE, str]] = None, scaley: Optional[Union[SCALE, str]] = None, subplots: Optional[bool] = None, max_cols: Optional[int] = None, sharex: Optional[bool] = None, sharey: Optional[bool] = None, style: Optional[ Union[ ContourStyleAttrs, List[Optional[ContourStyleAttrs]], ] ] = None, norm: Optional[Union[str, List[Optional[str]]]] = None, vmin: Optional[ Union[float, List[Optional[float]]] ] = None, vmax: Optional[ Union[float, List[Optional[float]]] ] = None, valfmt: Optional[ Union[VALUE_FORMAT, str, List[Optional[str]]] ] = None, xticks: Optional[ Union[ List[Union[int, float]], List[List[Union[int, float]]], ] ] = None, xticklabels: Optional[ Union[List[str], List[List[str]]] ] = None, xtickrotate: Optional[ Union[int, List[Optional[int]]] ] = None, yticks: Optional[ Union[ List[Union[int, float]], List[List[Union[int, float]]], ] ] = None, yticklabels: Optional[ Union[List[str], List[List[str]]] ] = None, ytickrotate: Optional[ Union[int, List[Optional[int]]] ] = None, vlines: Optional[ Union[ VLinePlotAttrs, List[VLinePlotAttrs], List[ Union[ VLinePlotAttrs, List[VLinePlotAttrs], None, ] ], ] ] = None, hlines: Optional[ Union[ HLinePlotAttrs, List[HLinePlotAttrs], List[ Union[ HLinePlotAttrs, List[HLinePlotAttrs], None, ] ], ] ] = None, colorbar: Optional[ Union[ HeatmapColorbarAttrs, List[Optional[HeatmapColorbarAttrs]], ] ] = None, texts: Optional[ Union[ TextAttrs, List[TextAttrs], List[Union[TextAttrs, List[TextAttrs], None]], ] ] = None ) -> plt.Figure ``` Creates the contour chart. A contour chart draws a surface sampled on a grid — a loss landscape, a 2-D density, a terrain — as iso-lines of equal value, or as filled bands between them. Use it to read the shape of a function of two variables: where its minima and ridges sit and how steeply it changes. Lines overlay on other charts and on each other; fills stand alone, with an optional colorbar. For a per-cell view of a matrix use Heatmap; for the raw points behind a density use ScatterChart. Added in 0.9.0 Examples: ``` >>> from datachart.charts import ContourChart >>> figure = ContourChart( ... data={ ... "x": [0, 1, 2], ... "y": [0, 1, 2], ... "z": [ ... [0, 1, 4], ... [1, 2, 5], ... [4, 5, 8], ... ], ... }, ... title="Basic Contour Chart", ... xlabel="X", ... ylabel="Y" ... ) ``` | PARAMETER | DESCRIPTION | | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `data` | The gridded surface(s): a dictionary with the 2-D z grid and the optional x and y axis values (one per column and per row of z, the indices by default), or a list of them for multiple charts/subplots. **TYPE:** `Union[ContourDataAttrs, List[ContourDataAttrs]]` | | `title` | The title of the chart. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `xlabel` | The x-axis label. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `ylabel` | The y-axis label. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `subtitle` | The subtitle(s) for individual charts. Used as legend labels. **TYPE:** `Optional[Union[str, List[Optional[str]]]]` **DEFAULT:** `None` | | `emphasis` | The emphasis role(s) for individual line contours, aligned like style: "background" mutes a chart (theme muted color, lowered alpha, behind the others, no legend entry), "highlight" bolds it and brings it to the front, None leaves it unchanged. Not supported for filled contours: passing a value with filled=True raises ValueError. **TYPE:** `Optional[Union[EMPHASIS, str, List[Optional[str]]]]` **DEFAULT:** `None` | | `figsize` | The size of the figure. **TYPE:** `Optional[Union[FIG_SIZE, Tuple[float, float]]]` **DEFAULT:** `None` | | `xmin` | The minimum x-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `xmax` | The maximum x-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `ymin` | The minimum y-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `ymax` | The maximum y-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `show_legend` | Whether to show the legend. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `show_grid` | Which grid lines to show (e.g., "both", "x", "y"). Off by default for filled contours. **TYPE:** `Optional[Union[SHOW_GRID, str]]` **DEFAULT:** `None` | | `filled` | Whether to fill the bands between the levels (colored by the colormap) instead of drawing iso-lines (in the chart's color). **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `levels` | Which levels cut the surface: a rule of CONTOUR_LEVELS ("auto", the default, leaves the choice to matplotlib), a target level count, or an explicit list of level values. **TYPE:** `Optional[Union[CONTOUR_LEVELS, str, int, List[float]]]` **DEFAULT:** `None` | | `show_labels` | Whether to write the level values along the iso-lines. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `show_colorbars` | Whether to show the colorbar(s) of filled contours. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `aspect_ratio` | The aspect ratio of the axes ("auto" or "equal"). See ASPECT_RATIO. **TYPE:** `Optional[Union[ASPECT_RATIO, str]]` **DEFAULT:** `None` | | `scalex` | The x-axis scale (e.g., "log", "linear"). **TYPE:** `Optional[Union[SCALE, str]]` **DEFAULT:** `None` | | `scaley` | The y-axis scale (e.g., "log", "linear"). **TYPE:** `Optional[Union[SCALE, str]]` **DEFAULT:** `None` | | `subplots` | Whether to create separate subplots for each chart. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `max_cols` | Maximum number of columns in subplots (when subplots=True). **TYPE:** `Optional[int]` **DEFAULT:** `None` | | `sharex` | Whether to share the x-axis in subplots. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `sharey` | Whether to share the y-axis in subplots. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `style` | Style configuration(s) for the contour chart(s). **TYPE:** `Optional[Union[ContourStyleAttrs, List[Optional[ContourStyleAttrs]]]]` **DEFAULT:** `None` | | `norm` | Value normalization method(s) of the colormap. **TYPE:** `Optional[Union[str, List[Optional[str]]]]` **DEFAULT:** `None` | | `vmin` | Minimum value(s) for normalization. **TYPE:** `Optional[Union[float, List[Optional[float]]]]` **DEFAULT:** `None` | | `vmax` | Maximum value(s) for normalization. **TYPE:** `Optional[Union[float, List[Optional[float]]]]` **DEFAULT:** `None` | | `valfmt` | Format string(s) for the inline level labels, with the value named x (e.g., "{x:.1f}"). See VALUE_FORMAT. **TYPE:** `Optional[Union[VALUE_FORMAT, str, List[Optional[str]]]]` **DEFAULT:** `None` | | `xticks` | Custom x-axis tick positions. **TYPE:** `Optional[Union[List[Union[int, float]], List[List[Union[int, float]]]]]` **DEFAULT:** `None` | | `xticklabels` | Custom x-axis tick labels. **TYPE:** `Optional[Union[List[str], List[List[str]]]]` **DEFAULT:** `None` | | `xtickrotate` | Rotation angle for x-axis tick labels. **TYPE:** `Optional[Union[int, List[Optional[int]]]]` **DEFAULT:** `None` | | `yticks` | Custom y-axis tick positions. **TYPE:** `Optional[Union[List[Union[int, float]], List[List[Union[int, float]]]]]` **DEFAULT:** `None` | | `yticklabels` | Custom y-axis tick labels. **TYPE:** `Optional[Union[List[str], List[List[str]]]]` **DEFAULT:** `None` | | `ytickrotate` | Rotation angle for y-axis tick labels. **TYPE:** `Optional[Union[int, List[Optional[int]]]]` **DEFAULT:** `None` | | `vlines` | Vertical line(s) to plot. **TYPE:** `Optional[Union[VLinePlotAttrs, List[VLinePlotAttrs], List[Union[VLinePlotAttrs, List[VLinePlotAttrs], None]]]]` **DEFAULT:** `None` | | `hlines` | Horizontal line(s) to plot. **TYPE:** `Optional[Union[HLinePlotAttrs, List[HLinePlotAttrs], List[Union[HLinePlotAttrs, List[HLinePlotAttrs], None]]]]` **DEFAULT:** `None` | | `colorbar` | Colorbar configuration(s). **TYPE:** `Optional[Union[HeatmapColorbarAttrs, List[Optional[HeatmapColorbarAttrs]]]]` **DEFAULT:** `None` | | `texts` | Text annotation(s) to draw. **TYPE:** `Optional[Union[TextAttrs, List[TextAttrs], List[Union[TextAttrs, List[TextAttrs], None]]]]` **DEFAULT:** `None` | | RETURNS | DESCRIPTION | | ------------ | ---------------------------------------- | | `plt.Figure` | The figure containing the contour chart. | ### datachart.charts.HexbinChart ``` HexbinChart( data: Union[HexbinDataAttrs, List[HexbinDataAttrs]], *, title: Optional[str] = None, xlabel: Optional[str] = None, ylabel: Optional[str] = None, subtitle: Optional[ Union[str, List[Optional[str]]] ] = None, emphasis: None = None, figsize: Optional[ Union[FIG_SIZE, Tuple[float, float]] ] = None, xmin: Optional[Union[int, float]] = None, xmax: Optional[Union[int, float]] = None, ymin: Optional[Union[int, float]] = None, ymax: Optional[Union[int, float]] = None, show_grid: Optional[Union[SHOW_GRID, str]] = None, show_colorbars: bool = True, aspect_ratio: Optional[Union[ASPECT_RATIO, str]] = None, scalex: Optional[Union[SCALE, str]] = None, scaley: Optional[Union[SCALE, str]] = None, subplots: Optional[bool] = None, max_cols: Optional[int] = None, sharex: Optional[bool] = None, sharey: Optional[bool] = None, style: Optional[ Union[ HexbinStyleAttrs, List[Optional[HexbinStyleAttrs]], ] ] = None, gridsize: Optional[ Union[int, List[Optional[int]]] ] = None, reduce: Optional[ Union[HEXBIN_REDUCE, str, List[Optional[str]]] ] = None, mincnt: Optional[ Union[int, List[Optional[int]]] ] = None, norm: Optional[Union[str, List[Optional[str]]]] = None, vmin: Optional[ Union[float, List[Optional[float]]] ] = None, vmax: Optional[ Union[float, List[Optional[float]]] ] = None, valfmt: Optional[ Union[VALUE_FORMAT, str, List[Optional[str]]] ] = None, xticks: Optional[ Union[ List[Union[int, float]], List[List[Union[int, float]]], ] ] = None, xticklabels: Optional[ Union[List[str], List[List[str]]] ] = None, xtickrotate: Optional[ Union[int, List[Optional[int]]] ] = None, yticks: Optional[ Union[ List[Union[int, float]], List[List[Union[int, float]]], ] ] = None, yticklabels: Optional[ Union[List[str], List[List[str]]] ] = None, ytickrotate: Optional[ Union[int, List[Optional[int]]] ] = None, vlines: Optional[ Union[ VLinePlotAttrs, List[VLinePlotAttrs], List[ Union[ VLinePlotAttrs, List[VLinePlotAttrs], None, ] ], ] ] = None, hlines: Optional[ Union[ HLinePlotAttrs, List[HLinePlotAttrs], List[ Union[ HLinePlotAttrs, List[HLinePlotAttrs], None, ] ], ] ] = None, colorbar: Optional[ Union[ HeatmapColorbarAttrs, List[Optional[HeatmapColorbarAttrs]], ] ] = None, texts: Optional[ Union[ TextAttrs, List[TextAttrs], List[Union[TextAttrs, List[TextAttrs], None]], ] ] = None ) -> plt.Figure ``` Creates the hexbin chart. A hexbin chart tiles the plane with hexagons and colors each by the number of points falling in it — or, with a per-point `c`, by an aggregate of those values. Use it where a scatter chart turns into an opaque blob: thousands of points, overlapping clusters, or a value that varies across the plane. For the points themselves use ScatterChart; for a smooth density estimate use ContourChart on stats.kde2d. Added in 0.9.0 Examples: ``` >>> from datachart.charts import HexbinChart >>> figure = HexbinChart( ... data={ ... "x": [0.1, 0.4, 0.5, 1.2, 1.3, 2.0], ... "y": [0.2, 0.3, 0.6, 1.1, 1.4, 2.1], ... }, ... title="Basic Hexbin Chart", ... xlabel="X", ... ylabel="Y" ... ) ``` | PARAMETER | DESCRIPTION | | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `data` | The points to bin: a dictionary with the x and y columns and an optional c column of per-point values, or a list of them for multiple charts/subplots. **TYPE:** `Union[HexbinDataAttrs, List[HexbinDataAttrs]]` | | `title` | The title of the chart. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `xlabel` | The x-axis label. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `ylabel` | The y-axis label. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `subtitle` | The subtitle(s) for individual charts. **TYPE:** `Optional[Union[str, List[Optional[str]]]]` **DEFAULT:** `None` | | `emphasis` | Not supported: a hexbin chart is a single colormapped layer with no series to mute or highlight. Passing a value raises ValueError. **TYPE:** `None` **DEFAULT:** `None` | | `figsize` | The size of the figure. **TYPE:** `Optional[Union[FIG_SIZE, Tuple[float, float]]]` **DEFAULT:** `None` | | `xmin` | The minimum x-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `xmax` | The maximum x-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `ymin` | The minimum y-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `ymax` | The maximum y-axis value. **TYPE:** `Optional[Union[int, float]]` **DEFAULT:** `None` | | `show_grid` | Which grid lines to show (e.g., "both", "x", "y"). Off by default: the hexagons cover it. **TYPE:** `Optional[Union[SHOW_GRID, str]]` **DEFAULT:** `None` | | `show_colorbars` | Whether to show the colorbar(s). **TYPE:** `bool` **DEFAULT:** `True` | | `aspect_ratio` | The aspect ratio of the axes ("auto" or "equal"). See ASPECT_RATIO. **TYPE:** `Optional[Union[ASPECT_RATIO, str]]` **DEFAULT:** `None` | | `scalex` | The x-axis scale (e.g., "log", "linear"). **TYPE:** `Optional[Union[SCALE, str]]` **DEFAULT:** `None` | | `scaley` | The y-axis scale (e.g., "log", "linear"). **TYPE:** `Optional[Union[SCALE, str]]` **DEFAULT:** `None` | | `subplots` | Whether to create separate subplots for each chart. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `max_cols` | Maximum number of columns in subplots (when subplots=True). **TYPE:** `Optional[int]` **DEFAULT:** `None` | | `sharex` | Whether to share the x-axis in subplots. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `sharey` | Whether to share the y-axis in subplots. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `style` | Style configuration(s) for the hexbin chart(s). **TYPE:** `Optional[Union[HexbinStyleAttrs, List[Optional[HexbinStyleAttrs]]]]` **DEFAULT:** `None` | | `gridsize` | The number of hexagons across the x-axis; the plot_hexbin_gridsize config value by default. **TYPE:** `Optional[Union[int, List[Optional[int]]]]` **DEFAULT:** `None` | | `reduce` | How the c values in a hexagon collapse into its color, one of HEXBIN_REDUCE (the mean by default). Ignored without c, where every hexagon shows its point count. **TYPE:** `Optional[Union[HEXBIN_REDUCE, str, List[Optional[str]]]]` **DEFAULT:** `None` | | `mincnt` | The point count below which a hexagon stays blank; every hexagon is drawn by default. **TYPE:** `Optional[Union[int, List[Optional[int]]]]` **DEFAULT:** `None` | | `norm` | Value normalization method(s) of the colormap; "log" spreads heavy-tailed counts. **TYPE:** `Optional[Union[str, List[Optional[str]]]]` **DEFAULT:** `None` | | `vmin` | Minimum value(s) for normalization. **TYPE:** `Optional[Union[float, List[Optional[float]]]]` **DEFAULT:** `None` | | `vmax` | Maximum value(s) for normalization. **TYPE:** `Optional[Union[float, List[Optional[float]]]]` **DEFAULT:** `None` | | `valfmt` | Format string(s) for the colorbar tick labels, with the value named x (e.g., "{x:.0f}"). See VALUE_FORMAT. **TYPE:** `Optional[Union[VALUE_FORMAT, str, List[Optional[str]]]]` **DEFAULT:** `None` | | `xticks` | Custom x-axis tick positions. **TYPE:** `Optional[Union[List[Union[int, float]], List[List[Union[int, float]]]]]` **DEFAULT:** `None` | | `xticklabels` | Custom x-axis tick labels. **TYPE:** `Optional[Union[List[str], List[List[str]]]]` **DEFAULT:** `None` | | `xtickrotate` | Rotation angle for x-axis tick labels. **TYPE:** `Optional[Union[int, List[Optional[int]]]]` **DEFAULT:** `None` | | `yticks` | Custom y-axis tick positions. **TYPE:** `Optional[Union[List[Union[int, float]], List[List[Union[int, float]]]]]` **DEFAULT:** `None` | | `yticklabels` | Custom y-axis tick labels. **TYPE:** `Optional[Union[List[str], List[List[str]]]]` **DEFAULT:** `None` | | `ytickrotate` | Rotation angle for y-axis tick labels. **TYPE:** `Optional[Union[int, List[Optional[int]]]]` **DEFAULT:** `None` | | `vlines` | Vertical line(s) to plot. **TYPE:** `Optional[Union[VLinePlotAttrs, List[VLinePlotAttrs], List[Union[VLinePlotAttrs, List[VLinePlotAttrs], None]]]]` **DEFAULT:** `None` | | `hlines` | Horizontal line(s) to plot. **TYPE:** `Optional[Union[HLinePlotAttrs, List[HLinePlotAttrs], List[Union[HLinePlotAttrs, List[HLinePlotAttrs], None]]]]` **DEFAULT:** `None` | | `colorbar` | Colorbar configuration(s). **TYPE:** `Optional[Union[HeatmapColorbarAttrs, List[Optional[HeatmapColorbarAttrs]]]]` **DEFAULT:** `None` | | `texts` | Text annotation(s) to draw. **TYPE:** `Optional[Union[TextAttrs, List[TextAttrs], List[Union[TextAttrs, List[TextAttrs], None]]]]` **DEFAULT:** `None` | | RETURNS | DESCRIPTION | | ------------ | --------------------------------------- | | `plt.Figure` | The figure containing the hexbin chart. | ### datachart.charts.ParallelCoords ``` ParallelCoords( data: Union[ List[ParallelCoordsDataPointAttrs], List[List[ParallelCoordsDataPointAttrs]], ], *, title: Optional[str] = None, xlabel: Optional[str] = None, ylabel: Optional[str] = None, subtitle: Optional[ Union[str, List[Optional[str]]] ] = None, emphasis: Optional[ Union[EMPHASIS, str, List[Optional[str]]] ] = None, figsize: Optional[ Union[FIG_SIZE, Tuple[float, float]] ] = None, show_legend: Optional[bool] = None, show_grid: Optional[Union[SHOW_GRID, str]] = None, aspect_ratio: Optional[Union[ASPECT_RATIO, str]] = None, style: Optional[ Union[ ParallelCoordsStyleAttrs, List[Optional[ParallelCoordsStyleAttrs]], ] ] = None, dimensions: Optional[List[str]] = None, hue: Optional[Union[str, List[Optional[str]]]] = None, category_orders: Optional[Dict[str, List[str]]] = None, texts: Optional[ Union[ TextAttrs, List[TextAttrs], List[Union[TextAttrs, List[TextAttrs], None]], ] ] = None ) -> plt.Figure ``` Creates the parallel coordinates chart. Parallel coordinates draw each record as a polyline across one vertical axis per dimension. Use it to explore multivariate data: clusters show as bundles of similar lines, and correlations between neighboring dimensions show as parallel or crossing segments. Works best with a handful of dimensions; color the records by group with `hue` to compare groups. Added in v0.7.0 Examples: ``` >>> from datachart.charts import ParallelCoords >>> figure = ParallelCoords( ... data=[ ... {"sepal_length": 5.1, "sepal_width": 3.5, "petal_length": 1.4, "petal_width": 0.2, "species": "setosa"}, ... {"sepal_length": 4.9, "sepal_width": 3.0, "petal_length": 1.4, "petal_width": 0.2, "species": "setosa"}, ... {"sepal_length": 7.0, "sepal_width": 3.2, "petal_length": 4.7, "petal_width": 1.4, "species": "versicolor"}, ... ], ... title="Iris Dataset", ... hue="species", ... dimensions=["sepal_length", "sepal_width", "petal_length", "petal_width"], ... show_legend=True ... ) ``` | PARAMETER | DESCRIPTION | | ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `data` | The data points for the chart. Each data point is a dictionary where keys are dimension names and values are numeric or string values. Can optionally include a hue key for categorical coloring. **TYPE:** `Union[List[ParallelCoordsDataPointAttrs], List[List[ParallelCoordsDataPointAttrs]]]` | | `title` | The title of the chart. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `xlabel` | The x-axis label. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `ylabel` | The y-axis label. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `subtitle` | The subtitle(s) for individual charts. **TYPE:** `Optional[Union[str, List[Optional[str]]]]` **DEFAULT:** `None` | | `emphasis` | The emphasis role(s), aligned with the data rows (a single value applies to every row): "background" mutes a row (theme muted color, lowered alpha, thinner line, behind the others, no hue legend entry), "highlight" bolds it and brings it to the front among the data rows, None leaves it unchanged. **TYPE:** `Optional[Union[EMPHASIS, str, List[Optional[str]]]]` **DEFAULT:** `None` | | `figsize` | The size of the figure. **TYPE:** `Optional[Union[FIG_SIZE, Tuple[float, float]]]` **DEFAULT:** `None` | | `show_legend` | Whether to show the legend (for hue categories). **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `show_grid` | Which grid lines to show (e.g., "both", "x", "y"). **TYPE:** `Optional[Union[SHOW_GRID, str]]` **DEFAULT:** `None` | | `aspect_ratio` | The aspect ratio of the axes ("auto" or "equal"). See ASPECT_RATIO. **TYPE:** `Optional[Union[ASPECT_RATIO, str]]` **DEFAULT:** `None` | | `style` | Style configuration(s) for the lines. **TYPE:** `Optional[Union[ParallelCoordsStyleAttrs, List[Optional[ParallelCoordsStyleAttrs]]]]` **DEFAULT:** `None` | | `dimensions` | List of dimension names to include and their order. If None, all columns (except hue) are auto-detected. **TYPE:** `Optional[List[str]]` **DEFAULT:** `None` | | `hue` | The key name in data for line coloring. String values color categorically: data points with the same hue value get the same color from color_parallel_hue. Numeric values color continuously along the theme's color_parallel_hue_continuous ramp. **TYPE:** `Optional[Union[str, List[Optional[str]]]]` **DEFAULT:** `None` | | `category_orders` | Dictionary mapping dimension names to lists of category values in the desired order. Example: {"rating": ["Low", "Medium", "High"]}. Categories not in the list will be appended at the end (sorted). **TYPE:** `Optional[Dict[str, List[str]]]` **DEFAULT:** `None` | | `texts` | Text annotation(s) to draw. **TYPE:** `Optional[Union[TextAttrs, List[TextAttrs], List[Union[TextAttrs, List[TextAttrs], None]]]]` **DEFAULT:** `None` | | RETURNS | DESCRIPTION | | ------------ | ----------------------------------------------------- | | `plt.Figure` | The figure containing the parallel coordinates chart. | ## Flows ### datachart.charts.SankeyChart ``` SankeyChart( data: Union[ SankeySingleChartAttrs, List[SankeySingleChartAttrs] ], *, nodes: Optional[List[List[str]]] = None, column_labels: Optional[List[str]] = None, show_values: Optional[bool] = None, value_format: Optional[Union[VALUE_FORMAT, str]] = None, title: Optional[str] = None, subtitle: Optional[ Union[str, List[Optional[str]]] ] = None, emphasis: None = None, figsize: Optional[ Union[FIG_SIZE, Tuple[float, float]] ] = None, subplots: Optional[bool] = None, max_cols: Optional[int] = None, style: Optional[ Union[ SankeyStyleAttrs, List[Optional[SankeyStyleAttrs]], ] ] = None, texts: Optional[ Union[ TextAttrs, List[TextAttrs], List[Union[TextAttrs, List[TextAttrs], None]], ] ] = None ) -> plt.Figure ``` Creates the Sankey chart. A Sankey diagram draws weighted flows between categories: nodes are bars laid out in columns and each flow is a ribbon whose height carries its value — label transitions between annotators, attrition through a signup funnel, energy from source to use. Use it when the question is where a quantity goes; for the totals per category alone use BarChart. Added in 0.9.0 Examples: ``` >>> from datachart.charts import SankeyChart >>> figure = SankeyChart( ... data={ ... "links": [ ... {"source": "Visited", "target": "Signed up", "value": 300}, ... {"source": "Visited", "target": "Bounced", "value": 700}, ... {"source": "Signed up", "target": "Paid", "value": 90}, ... {"source": "Signed up", "target": "Churned", "value": 210}, ... ] ... }, ... title="Signup funnel", ... ) ``` | PARAMETER | DESCRIPTION | | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `data` | The chart data: a {"links": [...]} dict whose links are {"source", "target", "value"} records, or a list of such dicts drawing one Sankey per subplot. A node is the string that names it, which is also its drawn label. **TYPE:** `Union[SankeySingleChartAttrs, List[SankeySingleChartAttrs]]` | | `nodes` | The node columns, left to right, each a list of node names top to bottom. Must name every node in the links exactly once. When omitted, a node's column is its longest path from any source and nodes keep their first-seen order within a column. **TYPE:** `Optional[List[List[str]]]` **DEFAULT:** `None` | | `column_labels` | One heading per column, drawn above it; must match the number of columns. **TYPE:** `Optional[List[str]]` **DEFAULT:** `None` | | `show_values` | Whether to write each flow's value on its ribbon. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `value_format` | The format of the ribbon values: a VALUE_FORMAT constant (default VALUE_FORMAT.DEFAULT) or any "{x:.1f}", "{:.1f}%", or "%g" style string. **TYPE:** `Optional[Union[VALUE_FORMAT, str]]` **DEFAULT:** `None` | | `title` | The title of the chart. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `subtitle` | The subtitle(s) for individual charts. **TYPE:** `Optional[Union[str, List[Optional[str]]]]` **DEFAULT:** `None` | | `emphasis` | Not supported: a Sankey has no series to mute or highlight. Passing a value raises ValueError. **TYPE:** `None` **DEFAULT:** `None` | | `figsize` | The size of the figure. **TYPE:** `Optional[Union[FIG_SIZE, Tuple[float, float]]]` **DEFAULT:** `None` | | `subplots` | Whether to show each chart in its own subplot; several charts always split into subplots. **TYPE:** `Optional[bool]` **DEFAULT:** `None` | | `max_cols` | Maximum number of columns in subplots. **TYPE:** `Optional[int]` **DEFAULT:** `None` | | `style` | Style configuration(s) for the chart(s). **TYPE:** `Optional[Union[SankeyStyleAttrs, List[Optional[SankeyStyleAttrs]]]]` **DEFAULT:** `None` | | `texts` | Text annotation(s) to draw. The columns span 0–1 horizontally and the tallest column 0–1 vertically. **TYPE:** `Optional[Union[TextAttrs, List[TextAttrs], List[Union[TextAttrs, List[TextAttrs], None]]]]` **DEFAULT:** `None` | | RETURNS | DESCRIPTION | | ------------ | --------------------------------------- | | `plt.Figure` | The figure containing the Sankey chart. | | RAISES | DESCRIPTION | | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `ValueError` | If emphasis is given, the links are malformed (missing keys, a value not above zero, a self-link), the links form a cycle, nodes does not name exactly the linked nodes, or column_labels does not match the number of columns. | # Utils Module ## datachart.utils The module containing the `utils`. The `utils` module provides a set of public utilities for the package. This module exports only the public API intended for end users. Internal implementation details are located in the `_internal` submodule and should not be imported directly by external code. | MODULE | DESCRIPTION | | ------- | --------------------------------------------------------------------------- | | `stats` | The module containing the statistics functions (count, mean, median, etc.). | | FUNCTION | DESCRIPTION | | ------------- | --------------------------------------------------------------------------- | | `save_figure` | Saves the figure into a file using the provided format parameters. | | `Panel` | Overlays rendered chart figures on a single plot with optional dual y-axes. | | `Grid` | Arranges rendered chart figures in a grid; nested rows define the layout. | | `Annotate` | Returns a new figure with text annotations added to a rendered figure. | ## Functions ### datachart.utils.save_figure ``` save_figure( figure: plt.Figure, path: str, dpi: int = 300, format: FIG_FORMAT = None, transparent: bool = False, ) -> None ``` Save the figure to a file. Writes the rendered figure to disk in the format given by `format` or, when omitted, by the file extension. Use a vector format (PDF, SVG) for print and papers, PNG with `dpi` >= 300 for raster deliverables, and `transparent=True` to drop the figure background for slides and web pages. The theme is already baked into the figure, so saving never consults the global config. Examples: ``` >>> # 1. create the figure >>> from datachart.charts import LineChart >>> figure = LineChart({...}) ``` ``` >>> # 2. save the figure >>> from datachart.utils.figure import save_figure >>> from datachart.constants import FIG_FORMAT >>> path = "/path/to/save/chart.png" >>> save_figure(figure, path, dpi=300, format=FIG_FORMAT.PNG, transparent=True) ``` | PARAMETER | DESCRIPTION | | ------------- | ------------------------------------------------------------------------------------------------------------------------------------ | | `figure` | The figure to save. **TYPE:** `plt.Figure` | | `path` | The path where the figure is saved. **TYPE:** `str` | | `dpi` | The DPI of the figure. **TYPE:** `int` **DEFAULT:** `300` | | `format` | The format of the figure. If None, the format will be determined from the file extension. **TYPE:** `FIG_FORMAT` **DEFAULT:** `None` | | `transparent` | Whether to make the background transparent. **TYPE:** `bool` **DEFAULT:** `False` | ### datachart.utils.Panel ``` Panel( charts: List[Union[plt.Figure, Dict[str, Any]]], *, title: Optional[str] = None, xlabel: Optional[str] = None, ylabel_left: Optional[str] = None, ylabel_right: Optional[str] = None, figsize: Optional[ Union[FIG_SIZE, Tuple[float, float]] ] = None, show_legend: Optional[bool] = False, show_grid: Optional[str] = None, auto_secondary_axis: Optional[float] = None, xmin: Optional[float] = None, xmax: Optional[float] = None, ymin: Optional[float] = None, ymax: Optional[float] = None, ymin_right: Optional[float] = None, ymax_right: Optional[float] = None, bar_mode: Optional[Union[BAR_MODE, str]] = None ) -> plt.Figure ``` Overlay rendered chart figures in one coordinate space. Combines different chart types (LineChart, BarChart, ScatterChart, Histogram, BoxPlot, SwarmPlot) on a single plot, drawn in the order provided. Two value axes (primary and secondary) are supported for handling different scales. A panel has an orientation, inferred from its figures: it is horizontal when every bar chart and histogram in it is horizontal, vertical otherwise. Mixing the two orientations raises `ValueError`. The *value axis* carries the quantities — y in a vertical panel, x in a horizontal one — and the *category axis* is the other. The parameters keep their spelling but address the axis by role: `ylabel_left`/`ylabel_right`, `ymin`/`ymax` and `ymin_right`/`ymax_right` set the primary/secondary value axis, `xlabel` and `xmin`/`xmax` the category axis. In a horizontal panel the secondary value axis sits at the top, so `"y_axis": "left"` means the bottom axis and `"right"` the top one, and the legend suffixes become `(B)`/`(T)`. Line and scatter figures follow the panel: in a horizontal panel their `x` runs along the category axis and their `y` along the value axis, so the same `LineChart` overlays vertical and horizontal bars. Panel figures nest: `Panel([Panel([f1, f2]), f3])` is equivalent to `Panel([f1, f2, f3])`, to any depth. A nested panel contributes its figures with their per-figure options intact, while panel-level settings (title, labels, limits, ...) always come from the outermost call. Dict options on a nested panel override its per-figure options only when explicitly given. Added in v0.8.0 Examples: ``` >>> from datachart.charts import LineChart, BarChart >>> from datachart.utils import Panel >>> >>> bar_fig = BarChart(data=[{"label": "A", "y": 100}, {"label": "B", "y": 200}]) >>> line_fig = LineChart(data=[{"x": 0, "y": 5}, {"x": 1, "y": 15}]) >>> >>> # Bare figures: automatic axis assignment >>> combined = Panel([bar_fig, line_fig], title="Sales Analysis") >>> >>> # Panels nest: add a figure to an existing panel >>> extended = Panel([combined, line_fig]) >>> >>> # Dicts carry per-figure options >>> combined = Panel( ... [ ... {"figure": bar_fig, "y_axis": "left"}, ... {"figure": line_fig, "y_axis": "right"}, ... ], ... ylabel_left="Count", ... ylabel_right="Average", ... show_legend=True, ... ) >>> >>> # Horizontal bars make a horizontal panel: the line runs along the >>> # categories and "right" is the top value axis >>> hbar_fig = BarChart( ... data=[{"label": "A", "y": 100}, {"label": "B", "y": 200}], ... orientation="horizontal", ... ) >>> combined = Panel( ... [hbar_fig, {"figure": line_fig, "y_axis": "right"}], ... xlabel="Category", ... ylabel_left="Count", ... ylabel_right="Average", ... ) ``` | PARAMETER | DESCRIPTION | | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `charts` | The figures to overlay. Each item is either a bare matplotlib Figure created by a datachart chart function — including another Panel figure, which flattens into this one — or a dict with a "figure" key plus optional per-figure options: - "y_axis": "left", "right", or "auto" (chart figures default to "auto"; a nested panel's figures keep their own assignment). "left"/"right" name the primary/secondary value axis — the bottom/top axis in a horizontal panel - "z_order": Integer for layering control (higher values on top) - "legend_label": Custom legend label (overrides chart subtitle) - "emphasis": "background" or "highlight" role for every layer of this figure. Background layers are muted (theme muted color, lowered alpha, behind the others) and excluded from the legend; highlight layers are bolded and brought to the front among the data layers. A nested panel's figures keep their own roles. **TYPE:** `List[Union[plt.Figure, Dict[str, Any]]]` | | `title` | Title for the combined chart. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `xlabel` | Label for the category axis. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `ylabel_left` | Label for the primary value axis. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `ylabel_right` | Label for the secondary value axis (if using dual axes). **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `figsize` | Size of the figure (width, height) in inches. **TYPE:** `Optional[Union[FIG_SIZE, Tuple[float, float]]]` **DEFAULT:** `None` | | `show_legend` | Whether to show the legend. **TYPE:** `Optional[bool]` **DEFAULT:** `False` | | `show_grid` | Which grid lines to show ("x", "y", "both", or None); these name the matplotlib axes literally. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `auto_secondary_axis` | Threshold ratio for automatic secondary axis creation. Default is taken from config (overlay_auto_threshold, default 3.0). **TYPE:** `Optional[float]` **DEFAULT:** `None` | | `xmin` | Minimum value for the category-axis limits. **TYPE:** `Optional[float]` **DEFAULT:** `None` | | `xmax` | Maximum value for the category-axis limits. **TYPE:** `Optional[float]` **DEFAULT:** `None` | | `ymin` | Minimum value for the primary value-axis limits. **TYPE:** `Optional[float]` **DEFAULT:** `None` | | `ymax` | Maximum value for the primary value-axis limits. **TYPE:** `Optional[float]` **DEFAULT:** `None` | | `ymin_right` | Minimum value for the secondary value-axis limits. **TYPE:** `Optional[float]` **DEFAULT:** `None` | | `ymax_right` | Maximum value for the secondary value-axis limits. **TYPE:** `Optional[float]` **DEFAULT:** `None` | | `bar_mode` | How bar and histogram series share the axis: "group" (side-by-side bars; histograms overlay), "stack" (stacked), or "overlay" (overlapping). Default is taken from config (overlay_bar_mode, default "group"). See BAR_MODE. **TYPE:** `Optional[Union[BAR_MODE, str]]` **DEFAULT:** `None` | | RETURNS | DESCRIPTION | | ------------ | --------------------------------------------------- | | `plt.Figure` | A matplotlib Figure containing the overlaid charts. | | RAISES | DESCRIPTION | | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `ValueError` | If charts is empty, an item is not a figure or a valid dict, a figure cannot be overlaid (missing metadata, Grid figure), or the figures mix horizontal and vertical orientations. | ### datachart.utils.Grid ``` Grid( charts: Union[ List[Union[plt.Figure, Dict[str, Any]]], List[List[Optional[plt.Figure]]], ], *, title: Optional[str] = None, xlabel: Optional[str] = None, ylabel: Optional[str] = None, max_cols: int = 4, figsize: Optional[Tuple[float, float]] = None, sharex: bool = False, sharey: bool = False ) -> plt.Figure ``` Arrange rendered chart figures in a grid. Each figure's chart is redrawn into its grid cell. Nested rows define the layout directly: every inner list is one grid row, and a shorter row's cells stretch to fill the width. A flat list uses an automatic uniform grid governed by `max_cols`, with a `layout_spec` escape hatch for irregular grids (rowspans). Grids nest: a Grid figure placed in a cell occupies exactly that cell and rebuilds its internal layout inside it, to any depth. The nested grid keeps its own title (a heading spanning its subgrid) and its own sharex/sharey among its own cells; the outer grid's sharex/sharey applies only to its top-level cells. Panel figures also nest in a cell; the reverse — a Grid figure inside a Panel — stays an error. Added in v0.8.0 Examples: ``` >>> from datachart.charts import LineChart, BarChart, ScatterChart >>> from datachart.utils import Grid >>> >>> fig1 = LineChart(data=[{"x": i, "y": i**2} for i in range(10)], title="Line") >>> fig2 = BarChart(data=[{"label": "A", "y": 10}, {"label": "B", "y": 20}], title="Bar") >>> fig3 = ScatterChart(data=[{"x": i, "y": i * 2} for i in range(10)], title="Scatter") >>> >>> # Nested rows are the layout: fig1 spans the full top row >>> combined = Grid([[fig1], [fig2, fig3]], title="Dashboard") >>> >>> # None leaves a blank cell >>> combined = Grid([[fig1, fig2], [fig3, None]]) >>> >>> # Flat list: automatic uniform grid >>> combined = Grid([fig1, fig2, fig3], max_cols=2) >>> >>> # Grids nest: a grid figure occupies one cell of the outer grid >>> inner = Grid([[fig1, fig2], [fig3]], title="Inner") >>> combined = Grid([inner, fig1], title="Outer") >>> >>> # Nested rows can hold grid (and Panel) figures too >>> combined = Grid([[inner, fig1], [fig2]]) >>> >>> # Flat list with the layout_spec escape hatch (rowspans) >>> combined = Grid( ... [ ... {"figure": fig1, "layout_spec": {"row": 0, "col": 0, "rowspan": 2, "colspan": 1}}, ... {"figure": fig2, "layout_spec": {"row": 0, "col": 1, "rowspan": 1, "colspan": 1}}, ... {"figure": fig3, "layout_spec": {"row": 1, "col": 1, "rowspan": 1, "colspan": 1}}, ... ] ... ) ``` | PARAMETER | DESCRIPTION | | ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `charts` | Either nested rows — each inner list is one grid row of bare matplotlib Figures (or None for a blank cell) — or a flat list whose items are bare figures or dicts with a "figure" key and an optional "layout_spec" dict ('row', 'col', 'rowspan', 'colspan'). Nested rows and layout_spec cannot be mixed. **TYPE:** `Union[List[Union[plt.Figure, Dict[str, Any]]], List[List[Optional[plt.Figure]]]]` | | `title` | Optional title for the combined figure. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `xlabel` | Optional x-axis label for the whole grid, drawn once below every cell. A nested grid keeps its own as a footer of its cell. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `ylabel` | Optional y-axis label for the whole grid, drawn once to the left of every cell. A nested grid keeps its own beside its cell. **TYPE:** `Optional[str]` **DEFAULT:** `None` | | `max_cols` | Maximum number of columns for the flat-list automatic grid. **TYPE:** `int` **DEFAULT:** `4` | | `figsize` | Size of the combined figure (width, height) in inches. If None, calculated from the first figure's size. **TYPE:** `Optional[Tuple[float, float]]` **DEFAULT:** `None` | | `sharex` | Whether to share the x-axis across all subplots. **TYPE:** `bool` **DEFAULT:** `False` | | `sharey` | Whether to share the y-axis across all subplots. **TYPE:** `bool` **DEFAULT:** `False` | | RETURNS | DESCRIPTION | | ------------ | --------------------------------------------------------------- | | `plt.Figure` | A new matplotlib Figure containing all charts in a grid layout. | | RAISES | DESCRIPTION | | ------------ | ------------------------------------------------------------------------------------------------------------------------- | | `ValueError` | If charts is empty, rows are mixed with flat items, a cell is invalid, or a figure cannot be composed (missing metadata). | ### datachart.utils.Annotate ``` Annotate( figure: plt.Figure, texts: Union[TextAttrs, List[TextAttrs]], ) -> plt.Figure ``` Add text annotations to an already rendered figure. Returns a new figure with the annotations riding the figure's chart metadata, styled by the current theme at call time — so they follow themes and survive `Panel` and `Grid` composition. The source figure and its charts are never modified. Works on any figure whose charts share one coordinate space: chart figures (including polar ones) and `Panel` output. Grid figures and multi-subplot figures (`subplots=True`) are rejected — annotate the sources before composing. Added in v0.8.0 Examples: ``` >>> from datachart.charts import LineChart >>> from datachart.utils import Annotate >>> >>> figure = LineChart(data=[{"x": i, "y": i**2} for i in range(10)]) >>> annotated = Annotate( ... figure, ... texts={ ... "text": "growth accelerates", ... "x": 4, ... "y": 60, ... "target": (7, 49), ... }, ... ) ``` | PARAMETER | DESCRIPTION | | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `figure` | A figure created by a datachart chart function or Panel. **TYPE:** `plt.Figure` | | `texts` | The text annotation(s) to add. Each annotation places text at (x, y) — data coordinates by default, axes fractions with "coords": "axes" — draws a connector to the optional target data point, and takes a per-text style override. **TYPE:** `Union[TextAttrs, List[TextAttrs]]` | | RETURNS | DESCRIPTION | | ------------ | --------------------------------------------------- | | `plt.Figure` | A new matplotlib Figure with the annotations added. | | RAISES | DESCRIPTION | | ------------ | ------------------------------------------------------------------------------------ | | `ValueError` | If the figure has no chart metadata, is a Grid figure, or is a multi-subplot figure. | # Stats Module ## datachart.utils.stats The module containing the `stats` methods. The `stats` module provides methods for calculating statistics. | FUNCTION | DESCRIPTION | | ------------- | ----------------------------------------------------------------- | | `count` | Counts the number of elements in the list. | | `sum_values` | Calculates the sum of the values. | | `mean` | Calculates the mean of the values. | | `median` | Calculates the median of the values. | | `stdev` | Calculates the standard deviation of the values. | | `variance` | Calculates the variance of the values. | | `quantile` | Calculates the quantile of the values. | | `iqr` | Calculates the interquartile range (Q3 - Q1). | | `minimum` | Gets the minimum of the values. | | `maximum` | Gets the maximum of the values. | | `correlation` | Calculates the Pearson correlation coefficient between two lists. | | `kde1d` | Estimates the density of the values as a curve. | | `kde2d` | Estimates the density of the (x, y) points as a gridded surface. | ## Functions ### datachart.utils.stats.count ``` count(values: List[Union[int, float]]) -> int ``` Counts the number of elements in a list. Examples: ``` >>> from datachart.utils.stats import count >>> count([1, 2, 3, 4, 5]) 5 ``` | PARAMETER | DESCRIPTION | | --------- | ------------------------------------------------------- | | `values` | The list of values. **TYPE:** `List[Union[int, float]]` | | RETURNS | DESCRIPTION | | ------- | ----------------------------------- | | `int` | The number of elements in the list. | ### datachart.utils.stats.sum_values ``` sum_values(values: List[Union[int, float]]) -> float ``` Calculates the sum of all values. Added in v0.7.0 Examples: ``` >>> from datachart.utils.stats import sum_values >>> sum_values([1, 2, 3, 4, 5]) 15.0 ``` | PARAMETER | DESCRIPTION | | --------- | ------------------------------------------------------- | | `values` | The list of values. **TYPE:** `List[Union[int, float]]` | | RETURNS | DESCRIPTION | | ------- | ---------------------- | | `float` | The sum of all values. | ### datachart.utils.stats.mean ``` mean(values: List[Union[int, float]]) -> float ``` Calculates the mean of the values. Examples: ``` >>> from datachart.utils.stats import mean >>> mean([1, 2, 3, 4, 5]) 3.0 ``` | PARAMETER | DESCRIPTION | | --------- | ------------------------------------------------------- | | `values` | The list of values. **TYPE:** `List[Union[int, float]]` | | RETURNS | DESCRIPTION | | ------- | ----------------------- | | `float` | The mean of the values. | ### datachart.utils.stats.median ``` median(values: List[Union[int, float]]) -> float ``` Calculates the median of the values. Examples: ``` >>> from datachart.utils.stats import median >>> median([1, 2, 3, 4, 5]) 3.0 ``` | PARAMETER | DESCRIPTION | | --------- | ------------------------------------------------------- | | `values` | The list of values. **TYPE:** `List[Union[int, float]]` | | RETURNS | DESCRIPTION | | ------- | ------------------------- | | `float` | The median of the values. | ### datachart.utils.stats.stdev ``` stdev(values: List[Union[int, float]]) -> float ``` Calculates the standard deviation of the values. Examples: ``` >>> from datachart.utils.stats import stdev >>> stdev([1, 2, 3, 4, 5]) 1.4142135623730951 ``` | PARAMETER | DESCRIPTION | | --------- | ------------------------------------------------------- | | `values` | The list of values. **TYPE:** `List[Union[int, float]]` | | RETURNS | DESCRIPTION | | ------- | ------------------------------------- | | `float` | The standard deviation of the values. | ### datachart.utils.stats.variance ``` variance(values: List[Union[int, float]]) -> float ``` Calculates the variance of the values. Added in v0.7.0 Examples: ``` >>> from datachart.utils.stats import variance >>> variance([1, 2, 3, 4, 5]) 2.0 ``` | PARAMETER | DESCRIPTION | | --------- | ------------------------------------------------------- | | `values` | The list of values. **TYPE:** `List[Union[int, float]]` | | RETURNS | DESCRIPTION | | ------- | --------------------------- | | `float` | The variance of the values. | ### datachart.utils.stats.quantile ``` quantile( values: List[Union[int, float]], q: float ) -> float ``` Calculates the quantile of the values. Examples: ``` >>> from datachart.utils.stats import quantile >>> quantile([1, 2, 3, 4, 5], 25) 2.0 ``` | PARAMETER | DESCRIPTION | | --------- | ------------------------------------------------------- | | `values` | The list of values. **TYPE:** `List[Union[int, float]]` | | `q` | The quantile to calculate (0-100). **TYPE:** `float` | | RETURNS | DESCRIPTION | | ------- | --------------------------- | | `float` | The quantile of the values. | ### datachart.utils.stats.iqr ``` iqr(values: List[Union[int, float]]) -> float ``` Calculates the interquartile range (Q3 - Q1). Added in v0.7.0 The interquartile range is the difference between the 75th percentile (Q3) and the 25th percentile (Q1). It is a measure of statistical dispersion and is useful for identifying outliers. Examples: ``` >>> from datachart.utils.stats import iqr >>> iqr([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) 4.5 ``` | PARAMETER | DESCRIPTION | | --------- | ------------------------------------------------------- | | `values` | The list of values. **TYPE:** `List[Union[int, float]]` | | RETURNS | DESCRIPTION | | ------- | -------------------------------------- | | `float` | The interquartile range of the values. | ### datachart.utils.stats.minimum ``` minimum(values: List[Union[int, float]]) -> float ``` Gets the minimum of the values. Examples: ``` >>> from datachart.utils.stats import minimum >>> minimum([1, 2, 3, 4, 5]) 1 ``` | PARAMETER | DESCRIPTION | | --------- | ------------------------------------------------------- | | `values` | The list of values. **TYPE:** `List[Union[int, float]]` | | RETURNS | DESCRIPTION | | ------- | -------------------------- | | `float` | The minimum of the values. | ### datachart.utils.stats.maximum ``` maximum(values: List[Union[int, float]]) -> float ``` Gets the maximum of the values. Examples: ``` >>> from datachart.utils.stats import maximum >>> maximum([1, 2, 3, 4, 5]) 5 ``` | PARAMETER | DESCRIPTION | | --------- | ------------------------------------------------------- | | `values` | The list of values. **TYPE:** `List[Union[int, float]]` | | RETURNS | DESCRIPTION | | ------- | -------------------------- | | `float` | The maximum of the values. | ### datachart.utils.stats.correlation ``` correlation( x: List[Union[int, float]], y: List[Union[int, float]] ) -> float ``` Calculates the Pearson correlation coefficient between two lists. Added in v0.7.0 The Pearson correlation coefficient measures the linear relationship between two datasets. It ranges from -1 (perfect negative correlation) to 1 (perfect positive correlation), with 0 indicating no linear correlation. Examples: ``` >>> from datachart.utils.stats import correlation >>> correlation([1, 2, 3, 4, 5], [1, 2, 3, 4, 5]) 1.0 >>> correlation([1, 2, 3, 4, 5], [5, 4, 3, 2, 1]) -1.0 ``` | PARAMETER | DESCRIPTION | | --------- | -------------------------------------------------------------- | | `x` | The first list of values. **TYPE:** `List[Union[int, float]]` | | `y` | The second list of values. **TYPE:** `List[Union[int, float]]` | | RETURNS | DESCRIPTION | | ------- | ------------------------------------ | | `float` | The Pearson correlation coefficient. | | RAISES | DESCRIPTION | | ------------ | --------------------------------------- | | `TypeError` | If x or y is not a list or numpy array. | | `ValueError` | If x and y have different lengths. | ### datachart.utils.stats.kde1d ``` kde1d( values: List[Union[int, float]], *, bandwidth: Optional[ Union[BANDWIDTH, str, float] ] = None, gridsize: int = 100, cut: float = 3, xlim: Optional[Tuple[float, float]] = None ) -> List[Dict[str, float]] ``` Estimates the density of the values as a curve. A Gaussian kernel density estimate evaluated on `gridsize` evenly spaced points over the range of the values, extended by `cut` bandwidths on each side so the curve tails off instead of being clipped at the extremes, or over an explicit `xlim` so several curves share one grid. The result is a list of `{x, y}` points ready for `LineChart`; the curve integrates to 1, so it overlays a density `Histogram` of the same values. Added in 0.9.0 Examples: ``` >>> from datachart.utils.stats import kde1d >>> curve = kde1d([1, 2, 2, 3, 3, 3, 4, 4, 5], gridsize=5, cut=0) >>> [round(point["x"], 2) for point in curve] [1.0, 2.0, 3.0, 4.0, 5.0] >>> round(sum(point["y"] for point in curve), 2) 0.94 ``` | PARAMETER | DESCRIPTION | | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `values` | The values to estimate the density of. **TYPE:** `List[Union[int, float]]` | | `bandwidth` | The kernel bandwidth: None or "scott" (Scott's rule), "silverman", or a scalar factor. See BANDWIDTH. **TYPE:** `Optional[Union[BANDWIDTH, str, float]]` **DEFAULT:** `None` | | `gridsize` | The number of points the curve is evaluated on. **TYPE:** `int` **DEFAULT:** `100` | | `cut` | How many bandwidths to extend the grid past the extremes. **TYPE:** `float` **DEFAULT:** `3` | | `xlim` | The (min, max) range of the grid; overrides the padded range. **TYPE:** `Optional[Tuple[float, float]]` **DEFAULT:** `None` | | RETURNS | DESCRIPTION | | ------------------------ | --------------------------------------- | | `List[Dict[str, float]]` | The {x, y} points of the density curve. | | RAISES | DESCRIPTION | | ------------ | --------------------------------------------------------------------------------------- | | `ValueError` | If the bandwidth is invalid, there are fewer than two values, or a value is not finite. | ### datachart.utils.stats.kde2d ``` kde2d( x: List[Union[int, float]], y: List[Union[int, float]], *, bandwidth: Optional[ Union[BANDWIDTH, str, float] ] = None, gridsize: Union[int, Tuple[int, int]] = 100, cut: float = 3, xlim: Optional[Tuple[float, float]] = None, ylim: Optional[Tuple[float, float]] = None ) -> Dict[str, List] ``` Estimates the density of the (x, y) points as a gridded surface. A Gaussian kernel density estimate evaluated on a `gridsize` × `gridsize` grid over the range of the points, extended by `cut` bandwidths on each side so the outer contours close instead of being clipped, or over explicit `xlim`/`ylim` so several surfaces share one grid. The result is an `{x, y, z}` chart dict ready for `ContourChart` — the density chart of a scattered dataset is `ContourChart(kde2d(x, y))`. Added in 0.9.0 Examples: ``` >>> from datachart.utils.stats import kde2d >>> surface = kde2d([1, 2, 3, 4], [1, 3, 2, 4], gridsize=(3, 2), cut=0) >>> surface["x"], surface["y"] ([1.0, 2.5, 4.0], [1.0, 4.0]) >>> [[round(z, 3) for z in row] for row in surface["z"]] [[0.075, 0.038, 0.001], [0.001, 0.038, 0.075]] ``` | PARAMETER | DESCRIPTION | | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x` | The x values of the points. **TYPE:** `List[Union[int, float]]` | | `y` | The y values of the points, one per x value. **TYPE:** `List[Union[int, float]]` | | `bandwidth` | The kernel bandwidth: None or "scott" (Scott's rule), "silverman", or a scalar factor. See BANDWIDTH. **TYPE:** `Optional[Union[BANDWIDTH, str, float]]` **DEFAULT:** `None` | | `gridsize` | The number of grid columns and rows, as one number or an (x, y) pair. **TYPE:** `Union[int, Tuple[int, int]]` **DEFAULT:** `100` | | `cut` | How many bandwidths to extend the grid past the extremes. **TYPE:** `float` **DEFAULT:** `3` | | `xlim` | The (min, max) x range of the grid; overrides the padded range. **TYPE:** `Optional[Tuple[float, float]]` **DEFAULT:** `None` | | `ylim` | The (min, max) y range of the grid; overrides the padded range. **TYPE:** `Optional[Tuple[float, float]]` **DEFAULT:** `None` | | RETURNS | DESCRIPTION | | ----------------- | ------------------------------------------------ | | `Dict[str, List]` | The {x, y, z} chart dict of the density surface. | | RAISES | DESCRIPTION | | ------------ | ----------------------------------------------------------------------------------------------------------------- | | `ValueError` | If the bandwidth is invalid, x and y differ in length, there are fewer than two points, or a value is not finite. | # Config Module ## datachart.config The module containing the `config`. The `config` module contains the configuration objects, enabling the users to globally customize the chart and plot styles. | ATTRIBUTE | DESCRIPTION | | --------- | ---------------------------------------------- | | `config` | The configuration instance. **TYPE:** `Config` | | CLASS | DESCRIPTION | | -------- | ------------------------ | | `Config` | The configuration class. | ## Attributes ### datachart.config.config ``` config: Config = Config() ``` The configuration instance that the users should interact with. ## Classes ### datachart.config.Config The class representing the configuration options. | ATTRIBUTE | DESCRIPTION | | --------- | ----------------------------------------------- | | `config` | The style configuration. **TYPE:** `StyleAttrs` | | METHOD | DESCRIPTION | | ---------------- | ------------------------------------------------ | | `set_theme` | Set the global configuration to match the theme. | | `reset_config` | Resets the global configuration. | | `update_config` | Updates the global configuration. | | `register_theme` | Registers a custom theme for use with set_theme. | | `get` | Gets the associated configuration attribute. | #### __init__ ``` __init__() ``` Initializes the global configuration. #### set_theme ``` set_theme(theme: THEME) -> None ``` Sets the global configuration to match the theme. Replaces the whole style configuration with a deep copy of the theme: one of the `THEME` constants or a name registered with `register_theme`. Use it to switch the look of every chart rendered afterwards; call `update_config` on top for per-attribute tweaks. Added in v0.5.0 Examples: ``` >>> from datachart.constants import THEME >>> from datachart.config import config >>> config.set_theme(THEME.DEFAULT) >>> config.get("theme") 'default' ``` | PARAMETER | DESCRIPTION | | --------- | -------------------------------------- | | `theme` | The theme to be set. **TYPE:** `THEME` | #### register_theme ``` register_theme(name: str, theme: StyleAttrs) -> None ``` Registers a custom theme so it can be applied with `set_theme`. Added in v0.8.1 The theme must define every attribute of the default theme; missing keys are filled from it, unknown keys are rejected. Examples: ``` >>> from datachart.config import config >>> from datachart.themes import DEFAULT_THEME >>> config.register_theme("mine", {**DEFAULT_THEME, "font_general_size": 14}) >>> config.set_theme("mine") >>> config.get("font_general_size") 14 ``` | PARAMETER | DESCRIPTION | | --------- | ---------------------------------------------------------- | | `name` | The theme name, later passed to set_theme. **TYPE:** `str` | | `theme` | The style attributes of the theme. **TYPE:** `StyleAttrs` | #### reset_config ``` reset_config() -> None ``` Resets the global configuration. Restores the default theme, discarding the current theme and every `update_config` override. Use it to return to a known state, for example at the start of a notebook section or between tests. Examples: ``` >>> from datachart.config import config >>> config.reset_config() >>> config.get("theme") 'default' ``` #### update_config ``` update_config(config: StyleAttrs) -> None ``` Updates the global configuration. Overrides individual style attributes on top of the current theme; the change persists until the next `set_theme` or `reset_config`. Use it for global tweaks such as font family or default colors; unknown attribute names are skipped with a warning. Examples: ``` >>> from datachart.config import config >>> config.update_config({"font_general_color": "#FFFFFF"}) >>> config.get("font_general_color") '#FFFFFF' ``` | PARAMETER | DESCRIPTION | | --------- | ------------------------------------------------------------------ | | `config` | The configuration attributes to be updated. **TYPE:** `StyleAttrs` | #### __getitem__ ``` __getitem__(attr: str) -> Any ``` Gets the associated configuration attribute. Examples: ``` >>> from datachart.config import config >>> config["font_general_color"] '#FFFFFF' ``` | PARAMETER | DESCRIPTION | | --------- | ------------------------------------------ | | `attr` | The attribute to retrieve. **TYPE:** `str` | | RETURNS | DESCRIPTION | | ------- | ------------------------------------------------ | | `Any` | The attribute value if present. Otherwise, None. | #### get ``` get(attr: str, default: Any = None) -> Any ``` Gets the associated configuration attribute. Reads one style attribute, falling back to `default` when it is not set. Use it to inspect the active configuration or to build style overrides relative to the current theme. Examples: ``` >>> from datachart.config import config >>> config.get("font_general_color") '#FFFFFF' ``` | PARAMETER | DESCRIPTION | | --------- | ------------------------------------------------------------------------------------------------------- | | `attr` | The attribute to retrieve. **TYPE:** `str` | | `default` | The value to return, if the attribute is not present in the config. **TYPE:** `Any` **DEFAULT:** `None` | | RETURNS | DESCRIPTION | | ------- | --------------------------------------------------------------------- | | `Any` | The attribute value if present. Otherwise, returns the default value. | #### __repr__ ``` __repr__() ``` Represents the configuration as a json string. # Themes Module ## datachart.themes The module containing the `themes`. The `themes` module contains the predefined style themes that are used to visualize the plots. Themes are named for their visual trait, never for a use case or audience. | ATTRIBUTE | DESCRIPTION | | ----------------- | -------------------------------------------------------------------------------------- | | `DEFAULT_THEME` | The default theme style. **TYPE:** `StyleAttrs` | | `GREYSCALE_THEME` | The greyscale theme style. **TYPE:** `StyleAttrs` | | `INK_THEME` | The ink theme style (dark-ink accents, print-ready). **TYPE:** `StyleAttrs` | | `HATCH_THEME` | The hatch theme style (hatch cycle, value labels, dotted grid). **TYPE:** `StyleAttrs` | | `MINIMAL_THEME` | The minimal theme style (accent blue, no spines, flat bars). **TYPE:** `StyleAttrs` | | `MATERIAL_THEME` | The material theme style (Google palette, light grid). **TYPE:** `StyleAttrs` | ## Themes ### datachart.themes.DEFAULT_THEME ``` DEFAULT_THEME: StyleAttrs = make_theme({}) ``` The default theme: the package's baseline palette and furniture. Added in v0.5.0 ### datachart.themes.GREYSCALE_THEME ``` GREYSCALE_THEME: StyleAttrs = make_theme( { "color_general_singular": COLORS.Greys, "color_general_multiple": GREYS, "color_parallel_hue": GREYS, "color_parallel_hue_continuous": [ "#D9D9D9", "#969696", "#525252", "#000000", ], "plot_bar_edge_width": 0.8, "plot_bar_edge_color": "#000000", "plot_sankey_node_edge_color": "#000000", "plot_hist_edge_color": "#000000", "plot_vline_color": "#5D6D7E", "plot_vline_style": LINE_STYLE.DASHED, "plot_hline_color": "#5D6D7E", "plot_hline_style": LINE_STYLE.DASHED, "plot_text_box_edgecolor": "#B0B0B0", "plot_text_arrow_color": "#5D6D7E", "plot_heatmap_cmap": COLORS.Greys, "plot_heatmap_frame_color": "#000000", "plot_regression_color": "#34495E", "plot_box_median_color": "#000000", "plot_violin_edgecolor": "#000000", "plot_violin_inner_color": "#000000", } ) ``` The greyscale theme: shades of grey for print or colorblind-safe output. Added in v0.5.0 ### datachart.themes.INK_THEME ``` INK_THEME: StyleAttrs = make_theme( { "color_general_singular": COLORS.Blues, "color_general_multiple": COLORS.PaperYlGnBu, "color_parallel_hue": COLORS.PaperYlGnBu, "color_parallel_hue_continuous": [ "#C7E9B4", "#7FCDBB", "#41B6C4", "#225EA8", ], "font_general_sansserif": [ "Helvetica", "Arial", "DejaVu Sans", ], "plot_grid_color": "#DDE3E8", "plot_bar_edge_width": 1.0, "plot_bar_edge_color": "#0B1F44", "plot_sankey_node_edge_color": "#0B1F44", "plot_hist_edge_color": "#0B1F44", "plot_vline_color": "#7F8C8D", "plot_vline_style": LINE_STYLE.DASHED, "plot_hline_color": "#7F8C8D", "plot_hline_style": LINE_STYLE.DASHED, "plot_text_box_edgecolor": "#000000", "plot_text_arrow_color": "#000000", "plot_heatmap_cmap": COLORS.YlGnBu, "plot_heatmap_frame_color": "#0B1F44", "plot_scatter_edge_width": 0.6, "plot_scatter_edge_color": "#0B1F44", "plot_swarm_edge_width": 0.6, "plot_swarm_edge_color": "#0B1F44", "plot_regression_color": "#34495E", "plot_parallel_axis_color": "#34495E", "plot_parallel_tick_color": "#34495E", "plot_parallel_tick_label_color": "#34495E", "plot_parallel_dim_label_color": "#34495E", "plot_box_edgecolor": "#34495E", "plot_box_median_color": "#34495E", "plot_violin_edgecolor": "#34495E", "plot_violin_inner_color": "#34495E", } ) ``` The ink theme: dark-ink accents, print-ready. Added in v0.8.0 ### datachart.themes.HATCH_THEME ``` HATCH_THEME: StyleAttrs = make_theme( { "color_general_singular": COLORS.Blues, "color_general_multiple": [ "#5B84C4", "#C85450", "#8C8C8C", "#6C9A78", "#A8C4E8", "#C9A227", ], "color_parallel_hue_continuous": [ "#D3DEF0", "#A8C4E8", "#5B84C4", "#2E4E8F", ], "font_general_sansserif": [ "Helvetica", "Arial", "DejaVu Sans", ], "chart_default_show_values": True, "plot_hatch_cycle": ["", "//", ".."], "plot_grid_color": "#D0D0D0", "plot_grid_linestyle": LINE_STYLE.DOTTED, "plot_grid_alpha": 0.8, "plot_bar_edge_color": "#000000", "plot_sankey_node_edge_color": "#000000", "plot_bar_edge_width": 0.8, "plot_bar_alpha": 1.0, "plot_hist_edge_color": "#000000", "plot_scatter_edge_color": "#000000", "plot_scatter_edge_width": 0.6, "plot_swarm_edge_color": "#000000", "plot_swarm_edge_width": 0.6, "plot_text_box_edgecolor": "#000000", "plot_text_arrow_color": "#000000", "plot_heatmap_cmap": COLORS.Blues, "plot_heatmap_frame_color": "#000000", "plot_violin_edgecolor": "#000000", } ) ``` The hatch theme: hatch cycle, value labels, dotted grid. Added in v0.8.0 ### datachart.themes.MINIMAL_THEME ``` MINIMAL_THEME: StyleAttrs = make_theme( { "color_general_singular": COLORS.Blues, "color_general_multiple": [ "#2B7FFF", "#A9B4BE", "#7C8894", "#525C66", "#2E3740", ], "color_parallel_hue_continuous": [ "#D9D9D9", "#A9B4BE", "#6FA0F5", "#2B7FFF", ], "font_general_color": "#1F1F1F", "font_title_color": "#1F1F1F", "axes_spines_top_visible": False, "axes_spines_right_visible": False, "axes_spines_left_visible": False, "axes_spines_bottom_visible": False, "axes_ticks_length": 0, "chart_default_show_values": True, "plot_grid_color": "#EFEFEF", "plot_grid_alpha": 1.0, "plot_bar_alpha": 1.0, "plot_bar_edge_width": 0, "plot_bar_value_fontsize": 9, "plot_bar_value_color": "#1F1F1F", "plot_hist_edge_width": 0, "plot_line_width": 2.0, "plot_scatter_edge_color": "#FFFFFF", "plot_swarm_edge_color": "#FFFFFF", "plot_text_box_edgecolor": "#CFD8DC", "plot_text_arrow_color": "#9AA4AE", "plot_heatmap_cmap": COLORS.Blues, "plot_heatmap_frame_color": "#9AA4AE", } ) ``` The minimal theme: accent blue, no spines, flat bars. Added in v0.8.0 ### datachart.themes.MATERIAL_THEME ``` MATERIAL_THEME: StyleAttrs = make_theme( { "color_general_singular": COLORS.Blues, "color_general_multiple": [ "#4285F4", "#FBBC04", "#34A853", "#EA4335", "#7BAAF7", "#46BDC6", ], "color_parallel_hue_continuous": [ "#C6DAFC", "#7BAAF7", "#4285F4", "#1B5FD9", ], "font_general_sansserif": [ "Roboto", "Arial", "Helvetica", ], "axes_spines_top_visible": False, "axes_spines_right_visible": False, "axes_spines_left_visible": False, "chart_default_show_values": True, "plot_grid_color": "#E0E0E0", "plot_grid_alpha": 1.0, "plot_grid_linewidth": 0.8, "plot_bar_alpha": 1.0, "plot_bar_edge_width": 0, "plot_hist_edge_width": 0, "plot_line_width": 2.0, "plot_text_box_edgecolor": "#757575", "plot_text_arrow_color": "#757575", "plot_heatmap_cmap": COLORS.Blues, "plot_heatmap_frame_color": "#000000", } ) ``` The material theme: Google palette, light grid. Added in v0.8.0 # Constants Module ## datachart.constants Module containing the `constants`. The `constants` module provides a set of predefined constants used in the package. These include figure size, format, style, and other figure manipulation values. | CLASS | DESCRIPTION | | ------------------- | ---------------------------------------------- | | `FIG_SIZE` | The predefined figure sizes. | | `FIG_FORMAT` | The supported figure formats. | | `FONT_STYLE` | The supported font styles. | | `FONT_WEIGHT` | The supported font weights. | | `LINE_MARKER` | The supported line markers. | | `LINE_STYLE` | The supported line styles. | | `ARROW_STYLE` | The supported text annotation connector looks. | | `LINE_DRAW_STYLE` | The supported line draw styles. | | `HATCH_STYLE` | The supported hatch styles. | | `LEGEND_ALIGN` | The supported legend alignments. | | `LEGEND_LOCATION` | The supported legend locations. | | `HISTOGRAM_TYPE` | The supported histogram types. | | `BAR_MODE` | The supported bar modes. | | `COLORS` | The predefined colors. | | `NORMALIZE` | The supported normalization options. | | `ORIENTATION` | The supported orientations. | | `VIOLIN_INNER` | The supported violin inner marks. | | `BANDWIDTH` | The supported kernel density bandwidth rules. | | `CONTOUR_LEVELS` | The supported contour level rules. | | `HEXBIN_REDUCE` | The supported hexbin aggregations. | | `BASELINE` | The supported stacked area baselines. | | `RADIAL_TYPE` | The supported radial chart visuals. | | `SWARM_MODE` | The supported swarm plot modes. | | `DIRECTION` | The supported angular directions. | | `VALUE_FORMAT` | The predefined value formats. | | `THEME` | The predefined themes. | | `EMPHASIS` | The supported emphasis roles. | | `SHOW_GRID` | The supported show grid options. | | `SCALE` | The supported scale options. | | `ASPECT_RATIO` | The supported aspect ratio options. | | `COLORBAR_LOCATION` | The supported colorbar locations. | ## Figure Constants ### datachart.constants.FIG_SIZE The predefined figure sizes. All values are `(width, height)` in inches, matplotlib's `figsize` unit. Paper figures are anchored to the printable area of an A4 page with standard 2.5 cm margins — a 6.3 x 9.7 in (16.0 x 24.6 cm) text block. `FULL` spans the text-block width; `HALF` spans one of two columns separated by a 0.3 in (0.8 cm) gap (3.0 in / 7.6 cm each). Widths cross with a height — `SHORT` (2.4 in / 6.1 cm), `MEDIUM` (4.8 in / 12.2 cm), or `TALL` (7.2 in / 18.3 cm). Passed as the `figsize` chart setting. Examples: ``` >>> from datachart.constants import FIG_SIZE >>> FIG_SIZE.DEFAULT (6.4, 4.8) ``` | ATTRIBUTE | DESCRIPTION | | -------------- | ---------------------------------------------------------------------------------------------------------------------------------- | | `DEFAULT` | The default figure size. Equals to (6.4, 4.8) in (16.3 x 12.2 cm). **TYPE:** `Tuple[float, float]` | | `FULL_SHORT` | The short, full-width figure size. Equals to (6.3, 2.4) in (16.0 x 6.1 cm). **TYPE:** `Tuple[float, float]` | | `FULL_MEDIUM` | The medium, full-width figure size. Equals to (6.3, 4.8) in (16.0 x 12.2 cm). **TYPE:** `Tuple[float, float]` | | `FULL_TALL` | The tall, full-width figure size. Equals to (6.3, 7.2) in (16.0 x 18.3 cm). **TYPE:** `Tuple[float, float]` | | `HALF_SHORT` | The short, half-width figure size. Equals to (3.0, 2.4) in (7.6 x 6.1 cm). **TYPE:** `Tuple[float, float]` | | `HALF_MEDIUM` | The medium, half-width figure size. Equals to (3.0, 4.8) in (7.6 x 12.2 cm). **TYPE:** `Tuple[float, float]` | | `HALF_TALL` | The tall, half-width figure size. Equals to (3.0, 7.2) in (7.6 x 18.3 cm). **TYPE:** `Tuple[float, float]` | | `HALF_SQUARE` | The square, half-width figure size. Equals to (3.0, 3.0) in (7.6 x 7.6 cm). **TYPE:** `Tuple[float, float]` | | `A4_PORTRAIT` | The A4 portrait printable-area figure size. Equals to (6.3, 9.7) in (16.0 x 24.6 cm). **TYPE:** `Tuple[float, float]` | | `A4_LANDSCAPE` | The A4 landscape printable-area figure size. Equals to (9.7, 6.3) in (24.6 x 16.0 cm). **TYPE:** `Tuple[float, float]` | | `SQUARE` | The square figure size. Equals to (4.8, 4.8) in (12.2 x 12.2 cm). **TYPE:** `Tuple[float, float]` | | `SLIDE_16_9` | The 16:9 slide figure size (PowerPoint/Google Slides). Equals to (13.33, 7.5) in (33.9 x 19.1 cm). **TYPE:** `Tuple[float, float]` | | `SLIDE_4_3` | The 4:3 slide figure size (PowerPoint/Google Slides). Equals to (10.0, 7.5) in (25.4 x 19.1 cm). **TYPE:** `Tuple[float, float]` | | `BEAMER_16_9` | The 16:9 beamer frame figure size. Equals to (6.3, 3.54) in (16.0 x 9.0 cm). **TYPE:** `Tuple[float, float]` | | `BEAMER_4_3` | The 4:3 beamer frame figure size. Equals to (5.04, 3.78) in (12.8 x 9.6 cm). **TYPE:** `Tuple[float, float]` | ### datachart.constants.FIG_FORMAT The supported figure formats. Passed as the `format` argument of save_figure. Examples: ``` >>> from datachart.constants import FIG_FORMAT >>> FIG_FORMAT.DEFAULT "png" ``` | ATTRIBUTE | DESCRIPTION | | --------- | -------------------------------------------------------------------------- | | `DEFAULT` | The default format. Same as FIG_FORMAT.PNG. **TYPE:** `str` | | `SVG` | The svg format. Equals to "svg". **TYPE:** `str` | | `PDF` | The pdf format. Equals to "pdf". **TYPE:** `str` | | `PNG` | The png format. Equals to "png". **TYPE:** `str` | | `WEBP` | The webp format. Equals to "webp". **TYPE:** `str` | | `EPS` | The eps format (Encapsulated PostScript). Equals to "eps". **TYPE:** `str` | | `JPG` | The jpg format. Equals to "jpg". **TYPE:** `str` | | `TIFF` | The tiff format. Equals to "tiff". **TYPE:** `str` | ## Font Constants ### datachart.constants.FONT_STYLE The supported font styles. Examples: ``` >>> from datachart.constants import FONT_STYLE >>> FONT_STYLE.DEFAULT "normal" ``` | ATTRIBUTE | DESCRIPTION | | --------- | ------------------------------------------------------------------ | | `DEFAULT` | The default font style. Same as FONT_STYLE.NORMAL. **TYPE:** `str` | | `NORMAL` | The normal font style. Equals to "normal". **TYPE:** `str` | | `ITALIC` | The italic font style. Equals to "italic". **TYPE:** `str` | | `OBLIQUE` | The oblique font style. Equals to "oblique". **TYPE:** `str` | ### datachart.constants.FONT_WEIGHT The supported font weights. Used by the `font_*_weight` style attributes (general, title, subtitle, axis labels). Examples: ``` >>> from datachart.constants import FONT_WEIGHT >>> FONT_WEIGHT.DEFAULT "normal" ``` | ATTRIBUTE | DESCRIPTION | | ------------- | -------------------------------------------------------------------- | | `DEFAULT` | The default font weight. Same as FONT_WEIGHT.NORMAL. **TYPE:** `str` | | `ULTRA_LIGHT` | The ultra light font weight. Equals to "ultralight". **TYPE:** `str` | | `LIGHT` | The light font weight. Equals to "light". **TYPE:** `str` | | `NORMAL` | The normal font weight. Equals to "normal". **TYPE:** `str` | | `MEDIUM` | The medium font weight. Equals to "medium". **TYPE:** `str` | | `SEMIBOLD` | The semibold font weight. Equals to "semibold". **TYPE:** `str` | | `BOLD` | The bold font weight. Equals to "bold". **TYPE:** `str` | | `EXTRA_BOLD` | The extra bold font weight. Equals to "extra bold". **TYPE:** `str` | | `HEAVY` | The heavy font weight. Equals to "heavy". **TYPE:** `str` | | `BLACK` | The black font weight. Equals to "black". **TYPE:** `str` | ## Line Constants ### datachart.constants.LINE_MARKER The supported line markers. Used by the `plot_line_marker` (line charts) and `plot_scatter_marker` (scatter charts) style attributes. Examples: ``` >>> from datachart.constants import LINE_MARKER >>> LINE_MARKER.PIXEL "," ``` | ATTRIBUTE | DESCRIPTION | | ---------------- | -------------------------------------------------------------- | | `NONE` | No marker. Equals to "". **TYPE:** `str` | | `PIXEL` | The pixel line marker. Equals to ",". **TYPE:** `str` | | `POINT` | The point line marker. Equals to ".". **TYPE:** `str` | | `CIRCLE` | The circle line marker. Equals to "o". **TYPE:** `str` | | `DIAMOND` | The diamond line marker. Equals to "D". **TYPE:** `str` | | `THIN_DIAMOND` | The thin diamond line marker. Equals to "d". **TYPE:** `str` | | `TRIANGLE` | The triangle (up) line marker. Equals to "^". **TYPE:** `str` | | `TRIANGLE_DOWN` | The triangle down line marker. Equals to "v". **TYPE:** `str` | | `TRIANGLE_LEFT` | The triangle left line marker. Equals to "\<". **TYPE:** `str` | | `TRIANGLE_RIGHT` | The triangle right line marker. Equals to ">". **TYPE:** `str` | | `SQUARE` | The square line marker. Equals to "s". **TYPE:** `str` | | `PENTAGON` | The pentagon line marker. Equals to "p". **TYPE:** `str` | | `HEXAGON` | The hexagon line marker. Equals to "h". **TYPE:** `str` | | `STAR` | The star line marker. Equals to "\*". **TYPE:** `str` | | `CROSS` | The cross line marker. Equals to "x". **TYPE:** `str` | | `PLUS` | The plus line marker. Equals to "+". **TYPE:** `str` | | `VLINE` | The vertical line marker. Equals to " | | `HLINE` | The horizontal line marker. Equals to "\_". **TYPE:** `str` | ### datachart.constants.LINE_STYLE The supported line styles. Used by the `plot_line_style` style attribute of line charts. Examples: ``` >>> from datachart.constants import LINE_STYLE >>> LINE_STYLE.SOLID "-" ``` | ATTRIBUTE | DESCRIPTION | | --------- | ------------------------------------------------------- | | `NONE` | No line style. Equals to "". **TYPE:** `str` | | `SOLID` | The solid line style. Equals to "-". **TYPE:** `str` | | `DASHED` | The dashed line style. Equals to "--". **TYPE:** `str` | | `DASHDOT` | The dashdot line style. Equals to "-.". **TYPE:** `str` | | `DOTTED` | The dotted line style. Equals to ":". **TYPE:** `str` | ### datachart.constants.LINE_DRAW_STYLE The supported line draw styles. Used by the `plot_line_drawstyle` style attribute of line charts. Examples: ``` >>> from datachart.constants import LINE_DRAW_STYLE >>> LINE_DRAW_STYLE.DEFAULT "default" ``` | ATTRIBUTE | DESCRIPTION | | ------------ | ----------------------------------------------------------------------- | | `DEFAULT` | The default line draw style. Equals to "default". **TYPE:** `str` | | `STEPS_PRE` | The pre-steps line draw style. Equals to "steps-pre". **TYPE:** `str` | | `STEPS_MID` | The mid-steps line draw style. Equals to "steps-mid". **TYPE:** `str` | | `STEPS_POST` | The post-steps line draw style. Equals to "steps-post". **TYPE:** `str` | ### datachart.constants.ARROW_STYLE The supported text annotation connector looks. Used by the `plot_text_arrow_style` style attribute of text annotations. Each value names a complete connector look — the line shape, curvature, and the gap on the text side. A curved look bows toward the side with the most open space around the chart's data; `plot_text_arrow_curve` pins the bow exactly, and the other `plot_text_arrow_*` style attributes override single properties of the chosen look. A raw matplotlib arrow style string (e.g. `"-|>"`) is also accepted. Examples: ``` >>> from datachart.constants import ARROW_STYLE >>> ARROW_STYLE.CURVE "curve" ``` | ATTRIBUTE | DESCRIPTION | | ------------- | -------------------------------------------------------------------------------------------------- | | `CURVE` | A curved plain line with a small text-side gap. The default. Equals to "curve". **TYPE:** `str` | | `CURVE_ARROW` | The same curve with an arrowhead at the target. Equals to "curve-arrow". **TYPE:** `str` | | `TOUCHING` | A straight plain line starting flush at the text box border. Equals to "touching". **TYPE:** `str` | | `ARROW` | A straight line with an arrowhead at the target. Equals to "arrow". **TYPE:** `str` | ## Style Constants ### datachart.constants.HATCH_STYLE The supported hatch styles. Used by the `plot_bar_hatch` and `plot_hist_hatch` style attributes, and by the `HATCH` theme's hatch cycle. Examples: ``` >>> from datachart.constants import HATCH_STYLE >>> HATCH_STYLE.DEFAULT None ``` | ATTRIBUTE | DESCRIPTION | | ------------------ | ---------------------------------------------------------------- | | `DEFAULT` | The default hatch style. Equals to None. **TYPE:** `str` | | `DIAGONAL` | The diagonal hatch style. Equals to "/". **TYPE:** `str` | | `BACK_DIAGONAL` | The back diagonal hatch style. Equals to "\\". **TYPE:** `str` | | `VERTICAL` | The vertical hatch style. Equals to " | | `HORIZONTAL` | The horizontal hatch style. Equals to "-". **TYPE:** `str` | | `CROSSED` | The crossed hatch style. Equals to "+". **TYPE:** `str` | | `CROSSED_DIAGONAL` | The crossed diagonal hatch style. Equals to "x". **TYPE:** `str` | | `DOTS` | The dots hatch style. Equals to ".". **TYPE:** `str` | | `CIRCLES` | The circles hatch style. Equals to "o". **TYPE:** `str` | | `STARS` | The stars hatch style. Equals to "\*". **TYPE:** `str` | ### datachart.constants.COLORS The predefined colors using [pypalettes](https://y-sunflower.github.io/pypalettes/). All palette names are valid pypalettes identifiers. You can use any of the 2500+ palettes available in pypalettes by passing the palette name as a string. Accepted anywhere a palette is: the `color_general_singular` and `color_general_multiple` config attributes, and the heatmap and parallel coords color settings. All predefined palettes are rendered in the [Colormaps guide](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/styling/colormaps/index.md). Examples: ``` >>> from datachart.constants import COLORS >>> COLORS.Blues 'Blues' ``` | ATTRIBUTE | DESCRIPTION | | ---------------- | ------------------------------------------------------------------------------------------------- | | `Blues` | Sequential blue palette. Equals to "Blues". **TYPE:** `str` | | `Greens` | Sequential green palette. Equals to "Greens". **TYPE:** `str` | | `Oranges` | Sequential orange palette. Equals to "Oranges". **TYPE:** `str` | | `Purples` | Sequential purple palette. Equals to "Purples". **TYPE:** `str` | | `Reds` | Sequential red palette. Equals to "Reds". **TYPE:** `str` | | `Sunset2` | Multi-hue sunset palette. Equals to "Sunset2". **TYPE:** `str` | | `YlGnBu` | Multi-hue yellow-green-blue palette. Equals to "YlGnBu". **TYPE:** `str` | | `YlOrRd` | Multi-hue yellow-orange-red palette. Equals to "YlOrRd". **TYPE:** `str` | | `PuBuGn` | Multi-hue purple-blue-green palette. Equals to "PuBuGn". **TYPE:** `str` | | `GnBu` | Multi-hue green-blue palette. Equals to "GnBu". **TYPE:** `str` | | `Egypt` | Multi-hue Egypt palette. Equals to "Egypt". **TYPE:** `str` | | `Hiroshige` | Multi-hue Hiroshige palette. Equals to "Hiroshige". **TYPE:** `str` | | `Lake` | Multi-hue lake palette. Equals to "Lake". **TYPE:** `str` | | `Neon` | Multi-hue neon palette. Equals to "Neon". **TYPE:** `str` | | `RdBu` | Diverging red-blue palette. Equals to "RdBu". **TYPE:** `str` | | `BrBG` | Diverging brown-blue-green palette. Equals to "BrBG". **TYPE:** `str` | | `PuOr` | Diverging purple-orange palette. Equals to "PuOr". **TYPE:** `str` | | `Spectral` | Diverging spectral palette. Equals to "Spectral". **TYPE:** `str` | | `RdYlBu` | Diverging red-yellow-blue palette. Equals to "RdYlBu". **TYPE:** `str` | | `RdYlGn` | Diverging red-yellow-green palette. Equals to "RdYlGn". **TYPE:** `str` | | `Pastel` | Soft pastel categorical palette. Equals to "Pastel". **TYPE:** `str` | | `Set2` | ColorBrewer Set2 categorical palette. Equals to "Set2". **TYPE:** `str` | | `Accent` | ColorBrewer Accent categorical palette. Equals to "Accent". **TYPE:** `str` | | `Dark2` | ColorBrewer Dark2 categorical palette. Equals to "Dark2". **TYPE:** `str` | | `Paired` | ColorBrewer Paired categorical palette (high contrast). Equals to "Paired". **TYPE:** `str` | | `Set1` | ColorBrewer Set1 categorical palette (high contrast). Equals to "Set1". **TYPE:** `str` | | `Greys` | Grayscale palette for monochrome visualizations. Equals to "Greys". **TYPE:** `str` | | `Viridis` | Perceptually uniform, color-blind friendly. Equals to "Viridis". **TYPE:** `str` | | `Cividis` | Color-blind friendly (optimized for CVD). Equals to "Cividis". **TYPE:** `str` | | `Inferno` | Perceptually uniform, color-blind friendly. Equals to "Inferno". **TYPE:** `str` | | `Plasma` | Perceptually uniform, color-blind friendly. Equals to "Plasma". **TYPE:** `str` | | `Magma` | Perceptually uniform, color-blind friendly. Equals to "Magma". **TYPE:** `str` | | `Turbo` | Rainbow-like but perceptually better. Equals to "Turbo". **TYPE:** `str` | | `OkabeIto` | Okabe-Ito categorical palette, color-blind safe. Equals to "OkabeIto". **TYPE:** `str` | | `OkabeIto_Black` | Okabe-Ito palette including black. Equals to "OkabeIto_Black". **TYPE:** `str` | | `Coolwarm` | Diverging cool-warm palette. Equals to "coolwarm". **TYPE:** `str` | | `Tab10` | Tableau 10-color categorical palette. Equals to "tab10". **TYPE:** `str` | | `Tab20` | Tableau 20-color categorical palette. Equals to "tab20". **TYPE:** `str` | | `PaperYlGnBu` | Diversified YlGnBu categorical palette for publications. Equals to "PaperYlGnBu". **TYPE:** `str` | | `PaperAccent` | Two-color blue/red accent pair for publications. Equals to "PaperAccent". **TYPE:** `str` | ### datachart.constants.THEME The predefined themes. Applied with config.set_theme. Every theme applied to the same set of charts is shown in the [Theme Gallery](https://eriknovak.github.io/datachart/0.9.0/how-to-guides/styling/theme-gallery/index.md). Examples: ``` >>> from datachart.constants import THEME >>> THEME.DEFAULT "default" ``` | ATTRIBUTE | DESCRIPTION | | ----------- | -------------------------------------------------------------------------------------------- | | `DEFAULT` | The default theme. Equals to "default". **TYPE:** `str` | | `GREYSCALE` | The greyscale theme. Equals to "greyscale". **TYPE:** `str` | | `INK` | The ink theme (dark-ink accents, print-ready). Equals to "ink". **TYPE:** `str` | | `HATCH` | The hatch theme (hatch cycle, value labels, dotted grid). Equals to "hatch". **TYPE:** `str` | | `MINIMAL` | The minimal theme (accent blue, no spines, flat bars). Equals to "minimal". **TYPE:** `str` | | `MATERIAL` | The material theme (Google palette, light grid). Equals to "material". **TYPE:** `str` | ### datachart.constants.EMPHASIS The supported emphasis roles. Set per chart via the `emphasis` key in a charts list, or per figure via the `emphasis` argument of Panel. Examples: ``` >>> from datachart.constants import EMPHASIS >>> EMPHASIS.BACKGROUND "background" ``` | ATTRIBUTE | DESCRIPTION | | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | | `BACKGROUND` | Mute a series into context: theme muted color, lowered alpha, thinner strokes, behind the others, no legend entry. Equals to "background". **TYPE:** `str` | | `HIGHLIGHT` | Bold a series and bring it to the front of the data layers; it keeps its color and legend entry. Equals to "highlight". **TYPE:** `str` | ## Legend Constants ### datachart.constants.LEGEND_ALIGN The supported legend alignments. Used by the `plot_legend_alignment` style attribute; aligns the legend's title and entries against each other. Examples: ``` >>> from datachart.constants import LEGEND_ALIGN >>> LEGEND_ALIGN.DEFAULT "left" ``` | ATTRIBUTE | DESCRIPTION | | --------- | ------------------------------------------------------------------------ | | `DEFAULT` | The default legend alignment. Same as LEGEND_ALIGN.LEFT. **TYPE:** `str` | | `CENTER` | The center legend alignment. Equals to "center". **TYPE:** `str` | | `RIGHT` | The right legend alignment. Equals to "right". **TYPE:** `str` | | `LEFT` | The left legend alignment. Equals to "left". **TYPE:** `str` | ### datachart.constants.LEGEND_LOCATION The supported legend locations. Used by the `plot_legend_location` style attribute; places the legend within the chart. Examples: ``` >>> from datachart.constants import LEGEND_LOCATION >>> LEGEND_LOCATION.BEST "best" ``` | ATTRIBUTE | DESCRIPTION | | -------------- | ------------------------------------------------------------ | | `BEST` | Automatic best location. Equals to "best". **TYPE:** `str` | | `UPPER_RIGHT` | Upper right corner. Equals to "upper right". **TYPE:** `str` | | `UPPER_LEFT` | Upper left corner. Equals to "upper left". **TYPE:** `str` | | `LOWER_LEFT` | Lower left corner. Equals to "lower left". **TYPE:** `str` | | `LOWER_RIGHT` | Lower right corner. Equals to "lower right". **TYPE:** `str` | | `RIGHT` | Center right. Equals to "right". **TYPE:** `str` | | `CENTER_LEFT` | Center left. Equals to "center left". **TYPE:** `str` | | `CENTER_RIGHT` | Center right. Equals to "center right". **TYPE:** `str` | | `LOWER_CENTER` | Lower center. Equals to "lower center". **TYPE:** `str` | | `UPPER_CENTER` | Upper center. Equals to "upper center". **TYPE:** `str` | | `CENTER` | Center. Equals to "center". **TYPE:** `str` | ## Chart Constants ### datachart.constants.HISTOGRAM_TYPE The supported histogram types. Passed as the `plot_hist_type` style attribute of histograms: how each series is rendered. How multiple series share the axis is the `bar_mode` setting's job — see `BAR_MODE`. Examples: ``` >>> from datachart.constants import HISTOGRAM_TYPE >>> HISTOGRAM_TYPE.BAR "bar" ``` | ATTRIBUTE | DESCRIPTION | | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `BAR` | The bar histogram style. Equals to "bar". **TYPE:** `str` | | `STEP` | The step histogram style: an unfilled outline in the series color. Stacked series draw as STEP_FILLED, since a stack needs area. Equals to "step". **TYPE:** `str` | | `STEP_FILLED` | The filled step histogram style. Equals to "stepfilled". **TYPE:** `str` | ### datachart.constants.BAR_MODE The supported bar modes. Passed as the `bar_mode` setting of bar charts, histograms, and Panel: how multiple series share the axis. Bar charts and panels default to `GROUP`; histograms default to `STACK`, and treat `GROUP` (which has no histogram meaning) as `OVERLAY`. Examples: ``` >>> from datachart.constants import BAR_MODE >>> BAR_MODE.DEFAULT "group" ``` | ATTRIBUTE | DESCRIPTION | | --------- | ----------------------------------------------------------------------------------------------- | | `DEFAULT` | The default bar mode. Same as BAR_MODE.GROUP. **TYPE:** `str` | | `GROUP` | The series are drawn side by side. Equals to "group". **TYPE:** `str` | | `STACK` | The series are stacked on top of each other. Equals to "stack". **TYPE:** `str` | | `OVERLAY` | The series are drawn over each other at the same position. Equals to "overlay". **TYPE:** `str` | ### datachart.constants.NORMALIZE The supported normalization options. Passed as the heatmap's `norm` attribute: normalizes the cell values before they are mapped to colors. Distinct from SCALE, which sets an axis scale. Examples: ``` >>> from datachart.constants import NORMALIZE >>> NORMALIZE.LINEAR "linear" ``` | ATTRIBUTE | DESCRIPTION | | --------- | ------------------------------------------------------------- | | `LINEAR` | The linear normalization. Equals to "linear". **TYPE:** `str` | | `LOG` | The logistic normalization. Equals to "log". **TYPE:** `str` | | `SYMLOG` | The symlog normalization. Equals to "symlog". **TYPE:** `str` | | `ASINH` | The asinh normalization. Equals to "asinh". **TYPE:** `str` | | `LOGIT` | The logit normalization. Equals to "logit". **TYPE:** `str` | ### datachart.constants.ORIENTATION The supported orientations. Passed as the `orientation` setting of bar charts, histograms, box plots, and violin plots. Examples: ``` >>> from datachart.constants import ORIENTATION >>> ORIENTATION.HORIZONTAL "horizontal" ``` | ATTRIBUTE | DESCRIPTION | | ------------ | ------------------------------------------------------------------- | | `HORIZONTAL` | The horizontal orientation. Equals to "horizontal". **TYPE:** `str` | | `VERTICAL` | The vertical orientation. Equals to "vertical". **TYPE:** `str` | ### datachart.constants.VIOLIN_INNER The supported violin inner marks. Passed as the `inner` setting of violin plots; `None` draws the body only. Examples: ``` >>> from datachart.constants import VIOLIN_INNER >>> VIOLIN_INNER.BOX "box" ``` | ATTRIBUTE | DESCRIPTION | | ----------- | --------------------------------------------------------------------------------------------------------------------------- | | `BOX` | A thin quartile bar, a 1.5·IQR whisker line, and a median dot. Equals to "box". **TYPE:** `str` | | `QUARTILES` | A dashed median line and dotted first and third quartile lines, clipped to the body. Equals to "quartiles". **TYPE:** `str` | | `MEDIAN` | A single solid median line clipped to the body. Equals to "median". **TYPE:** `str` | ### datachart.constants.BANDWIDTH The supported kernel density bandwidth rules. Passed as the `bandwidth` setting of violin plots: the rule of thumb that sizes the Gaussian kernel. A number is also accepted, as a factor applied to the standard deviation of the values — smaller is sharper, larger is smoother. Examples: ``` >>> from datachart.constants import BANDWIDTH >>> BANDWIDTH.DEFAULT "scott" ``` | ATTRIBUTE | DESCRIPTION | | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `DEFAULT` | The default rule. Same as BANDWIDTH.SCOTT. **TYPE:** `str` | | `SCOTT` | Scott's rule of thumb, n \*\* (-1/5) times the standard deviation. Equals to "scott". **TYPE:** `str` | | `SILVERMAN` | Silverman's rule of thumb, (3n/4) \*\* (-1/5) times the standard deviation — about 6% wider than Scott's, so the two look nearly the same. Equals to "silverman". **TYPE:** `str` | ### datachart.constants.CONTOUR_LEVELS The supported contour level rules. Passed as the `levels` setting of contour charts: the rule that picks how many iso-lines (or filled bands) cut the surface. An integer target count or an explicit list of level values is also accepted. Every rule is evaluated on the per-axis resolution of the grid (the square root of its cell count), so a finer grid draws more levels; the count is clamped to the 4–20 range and snapped to round values. Examples: ``` >>> from datachart.constants import CONTOUR_LEVELS >>> CONTOUR_LEVELS.DEFAULT "auto" ``` | ATTRIBUTE | DESCRIPTION | | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | | `DEFAULT` | The default rule. Same as CONTOUR_LEVELS.AUTO. **TYPE:** `str` | | `AUTO` | Matplotlib's own choice, about eight round values across the surface. Equals to "auto". **TYPE:** `str` | | `RICE` | The Rice rule, 2 * n \*\* (1/3) levels — about ten on a 120×120 grid. Equals to "rice". **TYPE:** `str` | | `FD` | The Freedman–Diaconis rule, the value range over 2 * IQR * n \*\* (-1/3) — about twice as dense as Rice on a 120×120 grid. Equals to "fd". **TYPE:** `str` | ### datachart.constants.HEXBIN_REDUCE The supported hexbin aggregations. Passed as the `reduce` attribute of hexbin charts: how the `c` values of the points in a hexagon collapse into the one value that colors it. Ignored without `c`, where every hexagon shows its point count. Examples: ``` >>> from datachart.constants import HEXBIN_REDUCE >>> HEXBIN_REDUCE.DEFAULT "mean" ``` | ATTRIBUTE | DESCRIPTION | | --------- | -------------------------------------------------------------------- | | `DEFAULT` | The default aggregation. Same as HEXBIN_REDUCE.MEAN. **TYPE:** `str` | | `MEAN` | The mean of the c values. Equals to "mean". **TYPE:** `str` | | `SUM` | The sum of the c values. Equals to "sum". **TYPE:** `str` | | `MEDIAN` | The median of the c values. Equals to "median". **TYPE:** `str` | | `MIN` | The smallest c value. Equals to "min". **TYPE:** `str` | | `MAX` | The largest c value. Equals to "max". **TYPE:** `str` | ### datachart.constants.BASELINE The supported stacked area baselines. Passed as the `baseline` attribute of stacked area charts: where the first series starts, and so how the whole stack sits on the y-axis. Examples: ``` >>> from datachart.constants import BASELINE >>> BASELINE.DEFAULT "zero" ``` | ATTRIBUTE | DESCRIPTION | | ----------------- | ------------------------------------------------------------------------------------------------------------ | | `DEFAULT` | The default baseline. Same as BASELINE.ZERO. **TYPE:** `str` | | `ZERO` | The stack starts at zero. Equals to "zero". **TYPE:** `str` | | `PERCENT` | Each x is normalised so the stack spans 0 to 100. Equals to "percent". **TYPE:** `str` | | `SYM` | The stack is centred on zero. Equals to "sym". **TYPE:** `str` | | `WIGGLE` | The baseline minimises the sum of squared slopes. Equals to "wiggle". **TYPE:** `str` | | `WEIGHTED_WIGGLE` | The baseline minimises the size-weighted sum of squared slopes. Equals to "weighted_wiggle". **TYPE:** `str` | ### datachart.constants.RADIAL_TYPE The supported radial chart visuals. Passed as the `type` setting of radial charts: the mark family the whole figure draws. The area visual is the line visual with `show_area=True`; stacked bars are the bar visual with `bar_mode="stack"`. Examples: ``` >>> from datachart.constants import RADIAL_TYPE >>> RADIAL_TYPE.LINE "line" ``` | ATTRIBUTE | DESCRIPTION | | ----------- | -------------------------------------------------------------------------------- | | `LINE` | The line (radar) visual. Equals to "line". **TYPE:** `str` | | `BAR` | The bar visual, one sector per label. Equals to "bar". **TYPE:** `str` | | `SCATTER` | The scatter visual. Equals to "scatter". **TYPE:** `str` | | `HISTOGRAM` | The angular histogram (wind rose) visual. Equals to "histogram". **TYPE:** `str` | ### datachart.constants.SWARM_MODE The supported swarm plot modes. Passed as the `mode` setting of swarm plots: how the points of one group spread across the category width. Examples: ``` >>> from datachart.constants import SWARM_MODE >>> SWARM_MODE.SWARM "swarm" ``` | ATTRIBUTE | DESCRIPTION | | --------- | ------------------------------------------------------------------------------------------------------------ | | `SWARM` | The beeswarm mode: non-overlapping offsets computed from the marker size. Equals to "swarm". **TYPE:** `str` | | `STRIP` | The strip mode: seeded uniform jitter. Equals to "strip". **TYPE:** `str` | ### datachart.constants.DIRECTION The supported angular directions. Passed as the `direction` setting of radial charts: which way the angles increase around the circle. Examples: ``` >>> from datachart.constants import DIRECTION >>> DIRECTION.CLOCKWISE "clockwise" ``` | ATTRIBUTE | DESCRIPTION | | ------------------ | ----------------------------------------------------------------------------------- | | `CLOCKWISE` | The angles increase clockwise. Equals to "clockwise". **TYPE:** `str` | | `COUNTERCLOCKWISE` | The angles increase counterclockwise. Equals to "counterclockwise". **TYPE:** `str` | ### datachart.constants.VALUE_FORMAT The predefined value formats. Passed as the heatmap's `valfmt` attribute (the values drawn in the cells) or the bar chart's `value_format` attribute (the bar value labels). Examples: ``` >>> from datachart.constants import VALUE_FORMAT >>> VALUE_FORMAT.DEFAULT "{x}" ``` | ATTRIBUTE | DESCRIPTION | | ------------- | ------------------------------------------------------------------------------------ | | `DEFAULT` | The default value format. Equals to "{x}". **TYPE:** `str` | | `INTEGER` | The integer value format (works on floats too). Equals to "{x:.0f}". **TYPE:** `str` | | `DECIMAL` | The decimal value format (1 decimal place). Equals to "{x:.1f}". **TYPE:** `str` | | `DECIMAL_2` | The decimal value format (2 decimal places). Equals to "{x:.2f}". **TYPE:** `str` | | `DECIMAL_3` | The decimal value format (3 decimal places). Equals to "{x:.3f}". **TYPE:** `str` | | `PERCENT` | The percentage value format (1 decimal place). Equals to "{x:.1%}". **TYPE:** `str` | | `PERCENT_INT` | The percentage value format (no decimals). Equals to "{x:.0%}". **TYPE:** `str` | | `SCIENTIFIC` | The scientific notation format. Equals to "{x:.2e}". **TYPE:** `str` | | `THOUSANDS` | The thousands separator format. Equals to "{x:,.0f}". **TYPE:** `str` | ### datachart.constants.SHOW_GRID The supported show grid options. Passed as the `show_grid` chart setting: which grid lines to draw. When unset (or `NONE`), the theme's `chart_default_show_grid` fills in. Examples: ``` >>> from datachart.constants import SHOW_GRID >>> SHOW_GRID.DEFAULT None ``` | ATTRIBUTE | DESCRIPTION | | --------- | ----------------------------------------------------------------------------- | | `DEFAULT` | The default show grid. Same as SHOW_GRID.NONE. **TYPE:** `str` | | `NONE` | No explicit grid; the theme default applies. Equals to None. **TYPE:** `None` | | `X` | Show the x-axis grid. Equals to "x". **TYPE:** `str` | | `Y` | Show the y-axis grid. Equals to "y". **TYPE:** `str` | | `BOTH` | Show both the x- and y-axis grid. Equals to "both". **TYPE:** `str` | ### datachart.constants.SCALE The supported scale options. Passed as the `scalex`/`scaley` chart settings to set an axis scale. Distinct from NORMALIZE, which normalizes heatmap colors. Examples: ``` >>> from datachart.constants import SCALE >>> SCALE.DEFAULT "linear" ``` | ATTRIBUTE | DESCRIPTION | | --------- | -------------------------------------------------------- | | `DEFAULT` | The default scale. Same as SCALE.LINEAR. **TYPE:** `str` | | `LINEAR` | The linear scale. Equals to "linear". **TYPE:** `str` | | `LOG` | The log scale. Equals to "log". **TYPE:** `str` | | `SYMLOG` | The symlog scale. Equals to "symlog". **TYPE:** `str` | | `ASINH` | The asinh scale. Equals to "asinh". **TYPE:** `str` | ### datachart.constants.ASPECT_RATIO The supported aspect ratio options. Passed as the `aspect_ratio` chart setting: the ratio of the y-unit to the x-unit on screen. Examples: ``` >>> from datachart.constants import ASPECT_RATIO >>> ASPECT_RATIO.DEFAULT "auto" ``` | ATTRIBUTE | DESCRIPTION | | --------- | -------------------------------------------------------------------- | | `DEFAULT` | The default aspect ratio. Same as ASPECT_RATIO.AUTO. **TYPE:** `str` | | `AUTO` | Automatic aspect ratio. Equals to "auto". **TYPE:** `str` | | `EQUAL` | Equal aspect ratio (1:1). Equals to "equal". **TYPE:** `str` | ### datachart.constants.COLORBAR_LOCATION The supported colorbar locations. Examples: ``` >>> from datachart.constants import COLORBAR_LOCATION >>> COLORBAR_LOCATION.RIGHT "right" ``` | ATTRIBUTE | DESCRIPTION | | --------- | ----------------------------------------------------------- | | `RIGHT` | Right side of the chart. Equals to "right". **TYPE:** `str` | | `LEFT` | Left side of the chart. Equals to "left". **TYPE:** `str` | | `TOP` | Top of the chart. Equals to "top". **TYPE:** `str` | | `BOTTOM` | Bottom of the chart. Equals to "bottom". **TYPE:** `str` | # Typings Module ## datachart.typings Module containing the `typings`. The `typings` module contains the typings for all chart components. The module is intended to contain the typings for easier input value format checkup. | CLASS | DESCRIPTION | | -------------------------------- | --------------------------------------------------------------- | | `ChartCommonAttrs` | The chart attributes common to all chart types. | | `VLinePlotAttrs` | The vertical line plot attributes. | | `HLinePlotAttrs` | The horizontal line plot attributes. | | `TextAttrs` | The text annotation attributes. | | `LineSingleChartAttrs` | The single chart attributes for the line chart. | | `LineDataPointAttrs` | The data point attributes for the line chart. | | `StackedAreaSingleChartAttrs` | The single chart attributes for the stacked area chart. | | `SankeySingleChartAttrs` | The single chart attributes for the Sankey chart. | | `SankeyLinkAttrs` | The link record attributes for the Sankey chart. | | `BarSingleChartAttrs` | The single chart attributes for the bar chart. | | `BarDataPointAttrs` | The data point attributes for the bar chart. | | `HistogramSingleChartAttrs` | The single chart attributes for the histogram chart. | | `HistDataPointAttrs` | The data point attributes for the histogram chart. | | `HeatmapSingleChartAttrs` | The single chart attributes for the heatmap chart. | | `HeatmapDataAttrs` | The data attributes for the heatmap chart. | | `HeatmapColorbarAttrs` | The heatmap colorbar attributes. | | `ContourSingleChartAttrs` | The single chart attributes for the contour chart. | | `ContourDataAttrs` | The data attributes for the contour chart. | | `HexbinSingleChartAttrs` | The single chart attributes for the hexbin chart. | | `HexbinDataAttrs` | The data attributes for the hexbin chart. | | `ScatterSingleChartAttrs` | The single chart attributes for the scatter chart. | | `ScatterDataPointAttrs` | The data point attributes for the scatter chart. | | `BoxSingleChartAttrs` | The single chart attributes for the box plot. | | `BoxDataPointAttrs` | The data point attributes for the box plot. | | `SwarmSingleChartAttrs` | The single chart attributes for the swarm plot. | | `SwarmDataPointAttrs` | The data point attributes for the swarm plot. | | `ViolinSingleChartAttrs` | The single chart attributes for the violin plot. | | `ViolinDataPointAttrs` | The data point attributes for the violin plot. | | `RaincloudSingleChartAttrs` | The single chart attributes for the raincloud plot. | | `RaincloudDataPointAttrs` | The data point attributes for the raincloud plot. | | `ParallelCoordsSingleChartAttrs` | The single chart attributes for the parallel coordinates chart. | | `ParallelCoordsDataPointAttrs` | The data point attributes for the parallel coordinates chart. | | `RadialSingleChartAttrs` | The single chart attributes for the radial chart. | | `RadialDataPointAttrs` | The data point attributes for the radial chart. | | `StyleAttrs` | The style typing. | | `ColorStyleAttrs` | The typing for the general color style. | | `FontStyleAttrs` | The typing for the font style. | | `AxesStyleAttrs` | The typing for the axes style. | | `LegendStyleAttrs` | The typing for the legend style. | | `AreaStyleAttrs` | The typing for the area style. | | `GridStyleAttrs` | The typing for the grid style. | | `LineStyleAttrs` | The typing for the line style. | | `StackedAreaStyleAttrs` | The typing for the stacked area chart style. | | `SankeyStyleAttrs` | The typing for the Sankey chart style. | | `BarStyleAttrs` | The typing for the bar style. | | `HistStyleAttrs` | The typing for the histogram style. | | `VLineStyleAttrs` | The typing for the vertical line style. | | `HLineStyleAttrs` | The typing for the horizontal line style. | | `TextStyleAttrs` | The typing for the text annotation style. | | `HeatmapStyleAttrs` | The typing for the heatmap style. | | `ContourStyleAttrs` | The typing for the contour chart style. | | `HexbinStyleAttrs` | The typing for the hexbin chart style. | | `ScatterStyleAttrs` | The typing for the scatter chart style. | | `RegressionStyleAttrs` | The typing for the regression line style. | | `BoxStyleAttrs` | The typing for the box plot style. | | `SwarmStyleAttrs` | The typing for the swarm plot style. | | `ViolinStyleAttrs` | The typing for the violin plot style. | | `RaincloudStyleAttrs` | The typing for the raincloud plot style. | | `ParallelCoordsStyleAttrs` | The typing for the parallel coordinates chart style. | | `ThemeDefaultAttrs` | The typing for theme-driven defaults and cycles. | ## Chart Typings ### Common Chart Typings #### datachart.typings.ChartCommonAttrs Bases: `TypedDict` The chart attributes common to all chart types. | ATTRIBUTE | DESCRIPTION | | -------------- | -------------------------------------------------------------------------------------------------------------------- | | `title` | The title of the charts. **TYPE:** `Union[str, None]` | | `xlabel` | The xlabel of the charts. **TYPE:** `Union[str, None]` | | `ylabel` | The ylabel of the charts. **TYPE:** `Union[str, None]` | | `figsize` | The size of the figure. **TYPE:** `Union[FIG_SIZE, Tuple[float, float], None]` | | `xmin` | Determine the minimum x-axis value. **TYPE:** `Union[int, float, None]` | | `xmax` | Determine the maximum x-axis value. **TYPE:** `Union[int, float, None]` | | `ymin` | Determine the minimum y-axis value. **TYPE:** `Union[int, float, None]` | | `ymax` | Determine the maximum y-axis value. **TYPE:** `Union[int, float, None]` | | `show_legend` | Whether or not to show the legend. **TYPE:** `Union[bool, None]` | | `show_grid` | Determine which grid lines to show. **TYPE:** `Union[SHOW_GRID, str, None]` | | `aspect_ratio` | The aspect ratio of the charts. **TYPE:** `Union[ASPECT_RATIO, str, None]` | | `subplots` | Whether or not to create a separate subplot for each chart. **TYPE:** `Union[bool, None]` | | `max_cols` | The maximum number of columns in the subplots. Active only when subplots is True. **TYPE:** `Union[int, None]` | | `sharex` | Whether or not to share the x-axis in the subplots. Active only when subplots is True. **TYPE:** `Union[bool, None]` | | `sharey` | Whether or not to share the y-axis in the subplots. Active only when subplots is True. **TYPE:** `Union[bool, None]` | #### datachart.typings.VLinePlotAttrs Bases: `TypedDict` The vertical line plot attributes. | ATTRIBUTE | DESCRIPTION | | --------- | ---------------------------------------------------------------------------- | | `x` | The x-axis position of the line. **TYPE:** `Union[int, float]` | | `ymin` | The minimum y-axis position value. **TYPE:** `Union[int, float, None]` | | `ymax` | The maximum y-axis position value. **TYPE:** `Union[int, float, None]` | | `style` | The vertical line style attributes. **TYPE:** `Union[VLineStyleAttrs, None]` | | `label` | The label of the vertical line. **TYPE:** `Union[str, None]` | #### datachart.typings.HLinePlotAttrs Bases: `TypedDict` The horizontal line plot attributes. | ATTRIBUTE | DESCRIPTION | | --------- | ------------------------------------------------------------------------------ | | `y` | The x-axis position of the line. **TYPE:** `Union[int, float]` | | `xmin` | The minimum y-axis position value. **TYPE:** `Union[int, float, None]` | | `xmax` | The maximum y-axis position value. **TYPE:** `Union[int, float, None]` | | `style` | The horizontal line style attributes. **TYPE:** `Union[HLineStyleAttrs, None]` | | `label` | The label of the horizontal line. **TYPE:** `Union[str, None]` | #### datachart.typings.TextAttrs Bases: `TypedDict` The text annotation attributes. | ATTRIBUTE | DESCRIPTION | | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `text` | The annotation text. **TYPE:** `str` | | `x` | The x-axis position of the text. **TYPE:** `Union[int, float]` | | `y` | The y-axis position of the text. **TYPE:** `Union[int, float]` | | `coords` | The coordinate system of the text position: "data" (default) or "axes" (axes fraction, 0–1). **TYPE:** `Union[str, None]` | | `target` | The data point the connector points to, always in data coordinates. When present, a connector is drawn from the text to the target. **TYPE:** `Union[Tuple[Union[int, float], Union[int, float]], None]` | | `style` | The per-text style attributes. **TYPE:** `Union[TextStyleAttrs, None]` | ### Line Chart Typings #### datachart.typings.LineSingleChartAttrs Bases: `TypedDict` The single chart attributes for the line chart. | ATTRIBUTE | DESCRIPTION | | ------------- | ----------------------------------------------------------------------------------------------------------- | | `data` | The list of data points defining the line chart. **TYPE:** `List[LineDataPointAttrs]` | | `subtitle` | The subtitle of the line chart. Also used as the label in the legend. **TYPE:** `Union[str, None]` | | `xlabel` | The xlabel of the line chart. **TYPE:** `Union[str, None]` | | `ylabel` | The ylabel of the line chart. **TYPE:** `Union[str, None]` | | `style` | The style of the line chart. **TYPE:** `Union[LineStyleAttrs, None]` | | `xticks` | The xtick positions list. **TYPE:** `Union[int, float, None]` | | `xticklabels` | The xtick labels. **TYPE:** `Union[List[str], None]` | | `xtickrotate` | The xtick rotation value. **TYPE:** `Union[int, None]` | | `yticks` | the ytick position list. **TYPE:** `Union[int, float, None]` | | `yticklabels` | The ytick labels. **TYPE:** `Union[List[str], None]` | | `ytickrotate` | The ytick rotation value. **TYPE:** `Union[int, None]` | | `vlines` | The vertical lines to be plot. **TYPE:** `Union[VLinePlotAttrs, List[VLinePlotAttrs], None]` | | `hlines` | The horizontal lines to be plot. **TYPE:** `Union[HLinePlotAttrs, List[HLinePlotAttrs], None]` | | `texts` | The text annotations to be drawn. **TYPE:** `Union[TextAttrs, List[TextAttrs], None]` | | `x` | The key name in data that contains the x-axis value. Defaults to "x". **TYPE:** `Union[str, None]` | | `y` | The key name in data that contains the y-axis value. Defaults to "y". **TYPE:** `Union[str, None]` | | `yerr` | The key name in data that contains the y-axis error value. Defaults to "yerr". **TYPE:** `Union[str, None]` | #### datachart.typings.LineDataPointAttrs Bases: `TypedDict` The data point attributes for the line chart. | ATTRIBUTE | DESCRIPTION | | --------- | --------------------------------------------------------------- | | `x` | The x-axis value. **TYPE:** `Union[int, float]` | | `y` | The y-axis value. **TYPE:** `Union[int, float]` | | `yerr` | The y-axis error value. **TYPE:** `Optional[Union[int, float]]` | ### Bar Chart Typings #### datachart.typings.BarSingleChartAttrs Bases: `TypedDict` The single chart attributes for the bar chart. | ATTRIBUTE | DESCRIPTION | | ------------- | ----------------------------------------------------------------------------------------------------------- | | `data` | The list of data points defining the bar chart. **TYPE:** `List[BarDataPointAttrs]` | | `subtitle` | The subtitle of the bar chart. Also used as the label in the legend. **TYPE:** `Union[str, None]` | | `xlabel` | The xlabel of the bar chart. **TYPE:** `Union[str, None]` | | `ylabel` | The ylabel of the bar chart. **TYPE:** `Union[str, None]` | | `style` | The style of the bar chart. **TYPE:** `Union[BarStyleAttrs, None]` | | `xticks` | The xtick positions list. **TYPE:** `Union[int, float, None]` | | `xticklabels` | The xtick labels. **TYPE:** `Union[List[str], None]` | | `xtickrotate` | The xtick rotation value. **TYPE:** `Union[int, None]` | | `yticks` | the ytick position list. **TYPE:** `Union[int, float, None]` | | `yticklabels` | The ytick labels. **TYPE:** `Union[List[str], None]` | | `ytickrotate` | The ytick rotation value. **TYPE:** `Union[int, None]` | | `vlines` | The vertical lines to be plot. **TYPE:** `Union[VLinePlotAttrs, List[VLinePlotAttrs], None]` | | `hlines` | The horizontal lines to be plot. **TYPE:** `Union[HLinePlotAttrs, List[HLinePlotAttrs], None]` | | `texts` | The text annotations to be drawn. **TYPE:** `Union[TextAttrs, List[TextAttrs], None]` | | `label` | The key name in data that contains the label value. Defaults to "label". **TYPE:** `Union[str, None]` | | `y` | The key name in data that contains the y-axis value. Defaults to "y". **TYPE:** `Union[str, None]` | | `yerr` | The key name in data that contains the y-axis error value. Defaults to "yerr". **TYPE:** `Union[str, None]` | #### datachart.typings.BarDataPointAttrs Bases: `TypedDict` The data point attributes for the bar chart. | ATTRIBUTE | DESCRIPTION | | --------- | --------------------------------------------------------------- | | `label` | The label. **TYPE:** `str` | | `y` | The y-axis value. **TYPE:** `Union[int, float]` | | `yerr` | The y-axis error value. **TYPE:** `Optional[Union[int, float]]` | ### Histogram Typings #### datachart.typings.HistogramSingleChartAttrs Bases: `TypedDict` The single chart attributes for the histogram chart. | ATTRIBUTE | DESCRIPTION | | ------------- | ------------------------------------------------------------------------------------------------------- | | `data` | The list of data points defining the histogram chart. **TYPE:** `List[HistDataPointAttrs]` | | `subtitle` | The subtitle of the histogram chart. Also used as the label in the legend. **TYPE:** `Union[str, None]` | | `xlabel` | The xlabel of the histogram chart. **TYPE:** `Union[str, None]` | | `ylabel` | The ylabel of the histogram chart. **TYPE:** `Union[str, None]` | | `style` | The style of the histogram chart. **TYPE:** `Union[HistStyleAttrs, None]` | | `xticks` | The xtick positions list. **TYPE:** `Union[int, float, None]` | | `xticklabels` | The xtick labels. **TYPE:** `Union[List[str], None]` | | `xtickrotate` | The xtick rotation value. **TYPE:** `Union[int, None]` | | `yticks` | the ytick position list. **TYPE:** `Union[int, float, None]` | | `yticklabels` | The ytick labels. **TYPE:** `Union[List[str], None]` | | `ytickrotate` | The ytick rotation value. **TYPE:** `Union[int, None]` | | `vlines` | The vertical lines to be plot. **TYPE:** `Union[VLinePlotAttrs, List[VLinePlotAttrs], None]` | | `hlines` | The horizontal lines to be plot. **TYPE:** `Union[HLinePlotAttrs, List[HLinePlotAttrs], None]` | | `texts` | The text annotations to be drawn. **TYPE:** `Union[TextAttrs, List[TextAttrs], None]` | | `x` | The key name in data that contains the x-axis value. Defaults to "x". **TYPE:** `Union[str, None]` | #### datachart.typings.HistDataPointAttrs Bases: `TypedDict` The data point attributes for the histogram chart. | ATTRIBUTE | DESCRIPTION | | --------- | ----------------------------------------------- | | `x` | The x-axis value. **TYPE:** `Union[int, float]` | ### Heatmap Typings #### datachart.typings.HeatmapSingleChartAttrs Bases: `TypedDict` The single chart attributes for the heatmap chart. | ATTRIBUTE | DESCRIPTION | | ------------- | ----------------------------------------------------------------------------------------------------- | | `data` | The labelled grid defining the heatmap chart. **TYPE:** `HeatmapDataAttrs` | | `subtitle` | The subtitle of the heatmap chart. Also used as the label in the legend. **TYPE:** `Union[str, None]` | | `xlabel` | The xlabel of the heatmap chart. **TYPE:** `Union[str, None]` | | `ylabel` | The ylabel of the heatmap chart. **TYPE:** `Union[str, None]` | | `style` | The style of the heatmap chart. **TYPE:** `Union[HeatmapStyleAttrs, None]` | | `norm` | The value normalization. **TYPE:** `Union[NORMALIZE, str, None]` | | `vmin` | The minimum value to normalize the data points. **TYPE:** `Union[str, None]` | | `vmax` | The maximum value to normalize the data points. **TYPE:** `Union[str, None]` | | `xticks` | The xtick positions list. **TYPE:** `Union[int, float, None]` | | `xticklabels` | The xtick labels. **TYPE:** `Union[List[str], None]` | | `xtickrotate` | The xtick rotation value. **TYPE:** `Union[int, None]` | | `yticks` | the ytick position list. **TYPE:** `Union[int, float, None]` | | `yticklabels` | The ytick labels. **TYPE:** `Union[List[str], None]` | | `ytickrotate` | The ytick rotation value. **TYPE:** `Union[int, None]` | | `colorbar` | The heatmap colorbar attributes. **TYPE:** `Union[HeatmapColorbarAttrs, None]` | | `texts` | The text annotations to be drawn. **TYPE:** `Union[TextAttrs, List[TextAttrs], None]` | #### datachart.typings.HeatmapDataAttrs Bases: `TypedDict` The data attributes for the heatmap chart. | ATTRIBUTE | DESCRIPTION | | --------- | ----------------------------------------------------------------------------------------------------------------------------- | | `x` | The column labels, one per column of z. Defaults to the column indices. **TYPE:** `Union[List[Union[str, int, float]], None]` | | `y` | The row labels, one per row of z. Defaults to the row indices. **TYPE:** `Union[List[Union[str, int, float]], None]` | | `z` | The 2-D grid of cell values, one row per y and one column per x. **TYPE:** `List[List[Union[int, float, None]]]` | #### datachart.typings.HeatmapColorbarAttrs Bases: `TypedDict` The heatmap colorbar attributes. | ATTRIBUTE | DESCRIPTION | | ------------- | ---------------------------------------------------------- | | `orientation` | The orientation. **TYPE:** `Union[ORIENTATION, str, None]` | ### Scatter Chart Typings #### datachart.typings.ScatterSingleChartAttrs Bases: `TypedDict` The single chart attributes for the scatter chart. | ATTRIBUTE | DESCRIPTION | | ------------- | ----------------------------------------------------------------------------------------------------- | | `data` | The list of data points defining the scatter chart. **TYPE:** `List[ScatterDataPointAttrs]` | | `subtitle` | The subtitle of the scatter chart. Also used as the label in the legend. **TYPE:** `Union[str, None]` | | `xlabel` | The xlabel of the scatter chart. **TYPE:** `Union[str, None]` | | `ylabel` | The ylabel of the scatter chart. **TYPE:** `Union[str, None]` | | `style` | The style of the scatter chart. **TYPE:** `Union[ScatterStyleAttrs, None]` | | `xticks` | The xtick positions list. **TYPE:** `Union[int, float, None]` | | `xticklabels` | The xtick labels. **TYPE:** `Union[List[str], None]` | | `xtickrotate` | The xtick rotation value. **TYPE:** `Union[int, None]` | | `yticks` | The ytick position list. **TYPE:** `Union[int, float, None]` | | `yticklabels` | The ytick labels. **TYPE:** `Union[List[str], None]` | | `ytickrotate` | The ytick rotation value. **TYPE:** `Union[int, None]` | | `vlines` | The vertical lines to be plot. **TYPE:** `Union[VLinePlotAttrs, List[VLinePlotAttrs], None]` | | `hlines` | The horizontal lines to be plot. **TYPE:** `Union[HLinePlotAttrs, List[HLinePlotAttrs], None]` | | `texts` | The text annotations to be drawn. **TYPE:** `Union[TextAttrs, List[TextAttrs], None]` | | `x` | The key name in data that contains the x-axis value. Defaults to "x". **TYPE:** `Union[str, None]` | | `y` | The key name in data that contains the y-axis value. Defaults to "y". **TYPE:** `Union[str, None]` | | `size` | The key name in data that contains the marker size value. **TYPE:** `Union[str, None]` | | `hue` | The key name in data that contains the hue/category value. **TYPE:** `Union[str, None]` | #### datachart.typings.ScatterDataPointAttrs Bases: `TypedDict` The data point attributes for the scatter chart. | ATTRIBUTE | DESCRIPTION | | --------- | ---------------------------------------------------------------------------- | | `x` | The x-axis value. **TYPE:** `Union[int, float]` | | `y` | The y-axis value. **TYPE:** `Union[int, float]` | | `size` | The marker size (for bubble charts). **TYPE:** `Optional[Union[int, float]]` | | `hue` | The category for color grouping. **TYPE:** `Optional[str]` | ### Box Chart (Box Plot) Typings #### datachart.typings.BoxSingleChartAttrs Bases: `TypedDict` The single chart attributes for the box plot. | ATTRIBUTE | DESCRIPTION | | ------------- | ----------------------------------------------------------------------------------------------------- | | `data` | The list of data points defining the box plot. **TYPE:** `List[BoxDataPointAttrs]` | | `subtitle` | The subtitle of the box plot. Also used as the label in the legend. **TYPE:** `Union[str, None]` | | `xlabel` | The xlabel of the box plot. **TYPE:** `Union[str, None]` | | `ylabel` | The ylabel of the box plot. **TYPE:** `Union[str, None]` | | `style` | The style of the box plot. **TYPE:** `Union[BoxStyleAttrs, None]` | | `xticks` | The xtick positions list. **TYPE:** `Union[int, float, None]` | | `xticklabels` | The xtick labels. **TYPE:** `Union[List[str], None]` | | `xtickrotate` | The xtick rotation value. **TYPE:** `Union[int, None]` | | `yticks` | The ytick position list. **TYPE:** `Union[int, float, None]` | | `yticklabels` | The ytick labels. **TYPE:** `Union[List[str], None]` | | `ytickrotate` | The ytick rotation value. **TYPE:** `Union[int, None]` | | `vlines` | The vertical lines to be plot. **TYPE:** `Union[VLinePlotAttrs, List[VLinePlotAttrs], None]` | | `hlines` | The horizontal lines to be plot. **TYPE:** `Union[HLinePlotAttrs, List[HLinePlotAttrs], None]` | | `texts` | The text annotations to be drawn. **TYPE:** `Union[TextAttrs, List[TextAttrs], None]` | | `label` | The key name in data that contains the label value. Defaults to "label". **TYPE:** `Union[str, None]` | | `value` | The key name in data that contains the value. Defaults to "value". **TYPE:** `Union[str, None]` | #### datachart.typings.BoxDataPointAttrs Bases: `TypedDict` The data point attributes for the box plot. | ATTRIBUTE | DESCRIPTION | | --------- | ------------------------------------------------ | | `label` | The category label. **TYPE:** `str` | | `value` | The numeric value. **TYPE:** `Union[int, float]` | ### Swarm Plot Typings #### datachart.typings.SwarmSingleChartAttrs Bases: `TypedDict` The single chart attributes for the swarm plot. | ATTRIBUTE | DESCRIPTION | | ------------- | ----------------------------------------------------------------------------------------------------- | | `data` | The list of data points defining the swarm plot. **TYPE:** `List[SwarmDataPointAttrs]` | | `subtitle` | The subtitle of the swarm plot. Also used as the label in the legend. **TYPE:** `Union[str, None]` | | `xlabel` | The xlabel of the swarm plot. **TYPE:** `Union[str, None]` | | `ylabel` | The ylabel of the swarm plot. **TYPE:** `Union[str, None]` | | `style` | The style of the swarm plot. **TYPE:** `Union[SwarmStyleAttrs, None]` | | `xticks` | The xtick positions list. **TYPE:** `Union[int, float, None]` | | `xticklabels` | The xtick labels. **TYPE:** `Union[List[str], None]` | | `xtickrotate` | The xtick rotation value. **TYPE:** `Union[int, None]` | | `yticks` | The ytick position list. **TYPE:** `Union[int, float, None]` | | `yticklabels` | The ytick labels. **TYPE:** `Union[List[str], None]` | | `ytickrotate` | The ytick rotation value. **TYPE:** `Union[int, None]` | | `vlines` | The vertical lines to be plot. **TYPE:** `Union[VLinePlotAttrs, List[VLinePlotAttrs], None]` | | `hlines` | The horizontal lines to be plot. **TYPE:** `Union[HLinePlotAttrs, List[HLinePlotAttrs], None]` | | `texts` | The text annotations to be drawn. **TYPE:** `Union[TextAttrs, List[TextAttrs], None]` | | `label` | The key name in data that contains the label value. Defaults to "label". **TYPE:** `Union[str, None]` | | `value` | The key name in data that contains the value. Defaults to "value". **TYPE:** `Union[str, None]` | ### datachart.typings.SwarmDataPointAttrs Bases: `TypedDict` The data point attributes for the swarm plot. | ATTRIBUTE | DESCRIPTION | | --------- | ------------------------------------------------ | | `label` | The category label. **TYPE:** `str` | | `value` | The numeric value. **TYPE:** `Union[int, float]` | ### Violin Plot Typings #### datachart.typings.ViolinSingleChartAttrs Bases: `TypedDict` The single chart attributes for the violin plot. | ATTRIBUTE | DESCRIPTION | | ------------- | ----------------------------------------------------------------------------------------------------- | | `data` | The list of data points defining the violin plot. **TYPE:** `List[ViolinDataPointAttrs]` | | `subtitle` | The subtitle of the violin plot. Also used as the label in the legend. **TYPE:** `Union[str, None]` | | `xlabel` | The xlabel of the violin plot. **TYPE:** `Union[str, None]` | | `ylabel` | The ylabel of the violin plot. **TYPE:** `Union[str, None]` | | `style` | The style of the violin plot. **TYPE:** `Union[ViolinStyleAttrs, None]` | | `xticks` | The xtick positions list. **TYPE:** `Union[int, float, None]` | | `xticklabels` | The xtick labels. **TYPE:** `Union[List[str], None]` | | `xtickrotate` | The xtick rotation value. **TYPE:** `Union[int, None]` | | `yticks` | The ytick position list. **TYPE:** `Union[int, float, None]` | | `yticklabels` | The ytick labels. **TYPE:** `Union[List[str], None]` | | `ytickrotate` | The ytick rotation value. **TYPE:** `Union[int, None]` | | `vlines` | The vertical lines to be plot. **TYPE:** `Union[VLinePlotAttrs, List[VLinePlotAttrs], None]` | | `hlines` | The horizontal lines to be plot. **TYPE:** `Union[HLinePlotAttrs, List[HLinePlotAttrs], None]` | | `texts` | The text annotations to be drawn. **TYPE:** `Union[TextAttrs, List[TextAttrs], None]` | | `label` | The key name in data that contains the label value. Defaults to "label". **TYPE:** `Union[str, None]` | | `value` | The key name in data that contains the value. Defaults to "value". **TYPE:** `Union[str, None]` | #### datachart.typings.ViolinDataPointAttrs Bases: `TypedDict` The data point attributes for the violin plot. | ATTRIBUTE | DESCRIPTION | | --------- | ------------------------------------------------ | | `label` | The category label. **TYPE:** `str` | | `value` | The numeric value. **TYPE:** `Union[int, float]` | ### Raincloud Plot Typings #### datachart.typings.RaincloudSingleChartAttrs Bases: `TypedDict` The single chart attributes for the raincloud plot. | ATTRIBUTE | DESCRIPTION | | ------------- | ----------------------------------------------------------------------------------------------------- | | `data` | The list of data points defining the raincloud plot. **TYPE:** `List[RaincloudDataPointAttrs]` | | `subtitle` | The subtitle of the raincloud plot. **TYPE:** `Union[str, None]` | | `xlabel` | The xlabel of the raincloud plot. **TYPE:** `Union[str, None]` | | `ylabel` | The ylabel of the raincloud plot. **TYPE:** `Union[str, None]` | | `style` | The style of the raincloud plot. **TYPE:** `Union[RaincloudStyleAttrs, None]` | | `xticks` | The xtick positions list. **TYPE:** `Union[int, float, None]` | | `xticklabels` | The xtick labels. **TYPE:** `Union[List[str], None]` | | `xtickrotate` | The xtick rotation value. **TYPE:** `Union[int, None]` | | `yticks` | The ytick position list. **TYPE:** `Union[int, float, None]` | | `yticklabels` | The ytick labels. **TYPE:** `Union[List[str], None]` | | `ytickrotate` | The ytick rotation value. **TYPE:** `Union[int, None]` | | `vlines` | The vertical lines to be plot. **TYPE:** `Union[VLinePlotAttrs, List[VLinePlotAttrs], None]` | | `hlines` | The horizontal lines to be plot. **TYPE:** `Union[HLinePlotAttrs, List[HLinePlotAttrs], None]` | | `texts` | The text annotations to be drawn. **TYPE:** `Union[TextAttrs, List[TextAttrs], None]` | | `label` | The key name in data that contains the label value. Defaults to "label". **TYPE:** `Union[str, None]` | | `value` | The key name in data that contains the value. Defaults to "value". **TYPE:** `Union[str, None]` | #### datachart.typings.RaincloudDataPointAttrs Bases: `TypedDict` The data point attributes for the raincloud plot. | ATTRIBUTE | DESCRIPTION | | --------- | ------------------------------------------------ | | `label` | The category label. **TYPE:** `str` | | `value` | The numeric value. **TYPE:** `Union[int, float]` | ### Parallel Coordinates Plot Typings #### datachart.typings.ParallelCoordsSingleChartAttrs Bases: `TypedDict` The single chart attributes for the parallel coordinates chart. | ATTRIBUTE | DESCRIPTION | | ----------------- | -------------------------------------------------------------------------------------- | | `data` | The list of data points. **TYPE:** `List[ParallelCoordsDataPointAttrs]` | | `subtitle` | The subtitle of the chart. **TYPE:** `Union[str, None]` | | `xlabel` | The xlabel of the chart. **TYPE:** `Union[str, None]` | | `ylabel` | The ylabel of the chart. **TYPE:** `Union[str, None]` | | `style` | The style of the chart. **TYPE:** `Union[ParallelCoordsStyleAttrs, None]` | | `dimensions` | The dimensions to include and their order. **TYPE:** `Union[List[str], None]` | | `hue` | The key name in data for categorical coloring. **TYPE:** `Union[str, None]` | | `category_orders` | Custom order for categorical dimensions. **TYPE:** `Union[Dict[str, List[str]], None]` | | `texts` | The text annotations to be drawn. **TYPE:** `Union[TextAttrs, List[TextAttrs], None]` | #### datachart.typings.ParallelCoordsDataPointAttrs Bases: `TypedDict` The data point attributes for the parallel coordinates chart. A dictionary where keys are dimension names and values are numeric values. Can optionally include a 'hue' key for categorical coloring. | ATTRIBUTE | DESCRIPTION | | --------- | ---------------------------------------------------------- | | `hue` | The category for color grouping. **TYPE:** `Optional[str]` | ### Radial Chart Typings #### datachart.typings.RadialSingleChartAttrs Bases: `TypedDict` The single chart attributes for the radial chart. | ATTRIBUTE | DESCRIPTION | | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------- | | `data` | The list of data points defining the radial chart. **TYPE:** `List[RadialDataPointAttrs]` | | `subtitle` | The subtitle of the radial chart. Also used as the label in the legend. **TYPE:** `Union[str, None]` | | `style` | The style of the radial chart, matching its visual. **TYPE:** `Union[LineStyleAttrs, BarStyleAttrs, HistStyleAttrs, ScatterStyleAttrs, None]` | | `texts` | The text annotations to be drawn. **TYPE:** `Union[TextAttrs, List[TextAttrs], None]` | | `label` | The key name in data that contains the category label. Defaults to "label". **TYPE:** `Union[str, None]` | | `x` | The key name in data that contains the angular observation. Defaults to "x". **TYPE:** `Union[str, None]` | | `y` | The key name in data that contains the radial value. Defaults to "y". **TYPE:** `Union[str, None]` | | `yerr` | The key name in data that contains the radial error value. Defaults to "yerr". **TYPE:** `Union[str, None]` | #### datachart.typings.RadialDataPointAttrs Bases: `TypedDict` The data point attributes for the radial chart. The line, bar, and scatter visuals take `label`/`y` points whose labels are placed evenly around the circle; the histogram visual takes numeric `x` observations in degrees. | ATTRIBUTE | DESCRIPTION | | --------- | ---------------------------------------------------------------------------------------------- | | `label` | The category label (line, bar, and scatter visuals). **TYPE:** `str` | | `y` | The radial value (line, bar, and scatter visuals). **TYPE:** `Union[int, float]` | | `yerr` | The radial error value. **TYPE:** `Optional[Union[int, float]]` | | `x` | The angular observation in degrees (histogram visual). **TYPE:** `Optional[Union[int, float]]` | ## Style Typings ### datachart.typings.StyleAttrs Bases: `ColorStyleAttrs`, `FontStyleAttrs`, `AxesStyleAttrs`, `LegendStyleAttrs`, `AreaStyleAttrs`, `GridStyleAttrs`, `LineStyleAttrs`, `StackedAreaStyleAttrs`, `SankeyStyleAttrs`, `BarStyleAttrs`, `HistStyleAttrs`, `VLineStyleAttrs`, `HLineStyleAttrs`, `TextStyleAttrs`, `HeatmapStyleAttrs`, `ContourStyleAttrs`, `HexbinStyleAttrs`, `ScatterStyleAttrs`, `RegressionStyleAttrs`, `BoxStyleAttrs`, `SwarmStyleAttrs`, `ViolinStyleAttrs`, `ParallelCoordsStyleAttrs`, `ThemeDefaultAttrs` The style attributes. Combines all style typings. ### datachart.typings.ColorStyleAttrs Bases: `TypedDict` The typing for the general color style. | ATTRIBUTE | DESCRIPTION | | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `color_general_singular` | The general color for the singular-typed charts. **TYPE:** `Union[COLORS, str, None]` | | `color_general_multiple` | The general color for the multiple-typed charts (palette name or list of hex colors). **TYPE:** `Union[COLORS, str, List[str], None]` | | `color_parallel_hue` | The color palette for parallel coords hue categories (palette name or list of hex colors). **TYPE:** `Union[COLORS, str, List[str], None]` | | `color_parallel_hue_continuous` | The sequential ramp for parallel coords numeric hue columns (palette name or list of hex colors). **TYPE:** `Union[COLORS, str, List[str], None]` | | `muted_color` | The color applied to background-emphasis layers. **TYPE:** `Union[str, None]` | | `muted_alpha` | The alpha applied to background-emphasis layers. **TYPE:** `Union[float, None]` | ### datachart.typings.FontStyleAttrs Bases: `TypedDict` The typing for the font style. | ATTRIBUTE | DESCRIPTION | | ------------------------ | ------------------------------------------------------------------------------------------------- | | `font_general_family` | The general font family. **TYPE:** `Union[str, None]` | | `font_general_sansserif` | The general sans-serif font. **TYPE:** `Union[List[str], None]` | | `font_general_serif` | The general serif font stack, used when the family is "serif". **TYPE:** `Union[List[str], None]` | | `font_general_color` | The general font color. **TYPE:** `Union[str, None]` | | `font_general_size` | The general font size. **TYPE:** `Union[int, float, str, None]` | | `font_general_style` | The general font style. **TYPE:** `Union[FONT_STYLE, str, None]` | | `font_general_weight` | The general font weight. **TYPE:** `Union[FONT_WEIGHT, str, None]` | | `font_title_size` | The title font size. **TYPE:** `Union[int, float, str, None]` | | `font_title_color` | The title font color. **TYPE:** `Union[str, None]` | | `font_title_style` | The title font style. **TYPE:** `Union[FONT_STYLE, str, None]` | | `font_title_weight` | The title font weight. **TYPE:** `Union[FONT_WEIGHT, str, None]` | | `font_subtitle_size` | The subtitle font size. **TYPE:** `Union[int, float, str, None]` | | `font_subtitle_color` | The subtitle font color. **TYPE:** `Union[str, None]` | | `font_subtitle_style` | The subtitle font style. **TYPE:** `Union[FONT_STYLE, None]` | | `font_subtitle_weight` | The subtitle font weight. **TYPE:** `Union[FONT_WEIGHT, None]` | | `font_xlabel_size` | The xlabel font size. **TYPE:** `Union[int, float, str, None]` | | `font_xlabel_color` | The xlabel font color. **TYPE:** `Union[str, None]` | | `font_xlabel_style` | The xlabel font style. **TYPE:** `Union[FONT_STYLE, str, None]` | | `font_xlabel_weight` | The xlabel font weight. **TYPE:** `Union[FONT_WEIGHT, str, None]` | | `font_ylabel_size` | The ylabel font size. **TYPE:** `Union[int, float, str, None]` | | `font_ylabel_color` | The ylabel font color. **TYPE:** `Union[str, None]` | | `font_ylabel_style` | The ylabel font style. **TYPE:** `Union[FONT_STYLE, str, None]` | | `font_ylabel_weight` | The ylabel font weight. **TYPE:** `Union[FONT_WEIGHT, str, None]` | ### datachart.typings.AxesStyleAttrs Bases: `TypedDict` The typing for the axes style. | ATTRIBUTE | DESCRIPTION | | ---------------------------- | ----------------------------------------------------------------- | | `axes_spines_top_visible` | Make the top plot spine visible. **TYPE:** `Union[bool, None]` | | `axes_spines_right_visible` | Make the right plot spine visible. **TYPE:** `Union[bool, None]` | | `axes_spines_bottom_visible` | Make the bottom plot spine visible. **TYPE:** `Union[bool, None]` | | `axes_spines_left_visible` | Make the left plot spine visible. **TYPE:** `Union[bool, None]` | | `axes_spines_width` | The width of the spines. **TYPE:** `Union[int, float, None]` | | `axes_spines_zorder` | The zorder of the spines. **TYPE:** `Union[int, None]` | | `axes_ticks_length` | The length of the ticks. **TYPE:** `Union[int, float, None]` | | `axes_ticks_label_size` | The size of the tick labels. **TYPE:** `Union[int, float, None]` | ### datachart.typings.LegendStyleAttrs Bases: `TypedDict` The typing for the legend style. | ATTRIBUTE | DESCRIPTION | | ------------------------- | ------------------------------------------------------------------------- | | `plot_legend_shadow` | Show the legends shadow. **TYPE:** `Union[bool, None]` | | `plot_legend_frameon` | Show the legends frame. **TYPE:** `Union[bool, None]` | | `plot_legend_alignment` | The legend alignment. **TYPE:** `Union[LEGEND_ALIGN, str, None]` | | `plot_legend_location` | The legend location. **TYPE:** `Union[LEGEND_LOCATION, str, None]` | | `plot_legend_font_size` | The font size within the legend. **TYPE:** `Union[int, float, str, None]` | | `plot_legend_title_size` | The title size of the legend. **TYPE:** `Union[int, float, str, None]` | | `plot_legend_label_color` | The label color of the legend. **TYPE:** `Union[str, None]` | ### datachart.typings.AreaStyleAttrs Bases: `TypedDict` The typing for the area style. | ATTRIBUTE | DESCRIPTION | | --------------------- | ---------------------------------------------------------------------- | | `plot_area_alpha` | The alpha value of the area. **TYPE:** `Union[float, None]` | | `plot_area_color` | The color of the area. **TYPE:** `Union[str, None]` | | `plot_area_linewidth` | The line width of the area. **TYPE:** `Union[int, float, None]` | | `plot_area_hatch` | The hatch style of the area. **TYPE:** `Union[HATCH_STYLE, str, None]` | | `plot_area_zorder` | The zorder of the area. **TYPE:** `Union[int, None]` | ### datachart.typings.GridStyleAttrs Bases: `TypedDict` The typing for the grid style. | ATTRIBUTE | DESCRIPTION | | --------------------- | -------------------------------------------------------------------- | | `plot_grid_alpha` | The alpha value of the grid. **TYPE:** `Union[float, None]` | | `plot_grid_color` | The color of the grid. **TYPE:** `Union[str, None]` | | `plot_grid_linewidth` | The line width of the grid. **TYPE:** `Union[int, float, None]` | | `plot_grid_linestyle` | The line style of the grid. **TYPE:** `Union[LINE_STYLE, str, None]` | | `plot_grid_zorder` | The zorder of the grid. **TYPE:** `Union[int, None]` | ### datachart.typings.LineStyleAttrs Bases: `TypedDict` The typing for the line chart style. | ATTRIBUTE | DESCRIPTION | | -------------------------- | --------------------------------------------------------------------------------------- | | `plot_line_color` | The line color. **TYPE:** `Union[str, None]` | | `plot_line_alpha` | The alpha value of the line. **TYPE:** `Union[float, None]` | | `plot_line_style` | The line style. **TYPE:** `Union[LINE_STYLE, str, None]` | | `plot_line_marker` | The line marker. **TYPE:** `Union[LINE_MARKER, str, None]` | | `plot_line_width` | The line width. **TYPE:** `Union[int, float, None]` | | `plot_line_drawstyle` | The line draw style. **TYPE:** `Union[LINE_DRAW_STYLE, str, None]` | | `plot_line_zorder` | The zorder of the line. **TYPE:** `Union[int, float, None]` | | `plot_xticks_label_rotate` | The label rotation of the xticks in the line chart. **TYPE:** `Union[int, float, None]` | | `plot_yticks_label_rotate` | The label rotation of the yticks in the line chart. **TYPE:** `Union[int, float, None]` | ### datachart.typings.BarStyleAttrs Bases: `TypedDict` The typing for the bar chart style. | ATTRIBUTE | DESCRIPTION | | -------------------------- | -------------------------------------------------------------------------------------- | | `plot_bar_color` | The bar color. **TYPE:** `Union[str, None]` | | `plot_bar_alpha` | The alpha value of the bar. **TYPE:** `Union[float, None]` | | `plot_bar_width` | The width of the bar. **TYPE:** `Union[int, float, None]` | | `plot_bar_zorder` | The zorder of the bar. **TYPE:** `Union[int, float, None]` | | `plot_bar_hatch` | The hatch style of the bar. **TYPE:** `Union[HATCH_STYLE, str, None]` | | `plot_bar_edge_width` | The edge width of the bar. **TYPE:** `Union[int, float, None]` | | `plot_bar_edge_color` | The edge color of the bar. **TYPE:** `Union[str, None]` | | `plot_bar_error_color` | The color of the error line of the bar. **TYPE:** `Union[str, None]` | | `plot_bar_value_fontsize` | The font size of the bar value labels. **TYPE:** `Union[int, float, None]` | | `plot_bar_value_color` | The color of the bar value labels. **TYPE:** `Union[str, None]` | | `plot_bar_value_padding` | The padding between bar edge and value label. **TYPE:** `Union[int, float, None]` | | `plot_xticks_label_rotate` | The label rotation of the xticks in the bar chart. **TYPE:** `Union[int, float, None]` | | `plot_yticks_label_rotate` | The label rotation of the yticks in the bar chart. **TYPE:** `Union[int, float, None]` | ### datachart.typings.HistStyleAttrs Bases: `TypedDict` The typing for the histogram chart style. | ATTRIBUTE | DESCRIPTION | | -------------------------- | -------------------------------------------------------------------------------------------- | | `plot_hist_color` | The color of the histogram. **TYPE:** `Union[str, None]` | | `plot_hist_alpha` | The alpha value of the histogram. **TYPE:** `Union[float, None]` | | `plot_hist_zorder` | The zorder of the histogram. **TYPE:** `Union[int, float, None]` | | `plot_hist_fill` | The fill of the histogram. **TYPE:** `Union[str, None]` | | `plot_hist_hatch` | The hatch style in the histogram. **TYPE:** `Union[HATCH_STYLE, str, None]` | | `plot_hist_type` | The type of the histogram. **TYPE:** `Union[HISTOGRAM_TYPE, str, None]` | | `plot_hist_align` | The alignment of the histogram. **TYPE:** `Union[str, None]` | | `plot_hist_edge_width` | The edge width of the histogram. **TYPE:** `Union[int, float, None]` | | `plot_hist_edge_color` | The edge color of the histogram. **TYPE:** `Union[str, None]` | | `plot_xticks_label_rotate` | The label rotation of the xticks in the histogram chart. **TYPE:** `Union[int, float, None]` | | `plot_yticks_label_rotate` | The label rotation of the yticks in the histogram chart. **TYPE:** `Union[int, float, None]` | ### datachart.typings.VLineStyleAttrs Bases: `TypedDict` The typing for the vertical line style. | ATTRIBUTE | DESCRIPTION | | ------------------ | ------------------------------------------------------------------------ | | `plot_vline_color` | The color of the vertical line. **TYPE:** `Union[str, None]` | | `plot_vline_style` | The style of the vertical line. **TYPE:** `Union[LINE_STYLE, str, None]` | | `plot_vline_width` | The width of the vertical line. **TYPE:** `Union[int, float, None]` | | `plot_vline_alpha` | The alpha value of the vertical line. **TYPE:** `Union[float, None]` | ### datachart.typings.HLineStyleAttrs Bases: `TypedDict` The typing for the horizontal line style. | ATTRIBUTE | DESCRIPTION | | ------------------ | -------------------------------------------------------------------------- | | `plot_hline_color` | The color of the horizontal line. **TYPE:** `Union[str, None]` | | `plot_hline_style` | The style of the horizontal line. **TYPE:** `Union[LINE_STYLE, str, None]` | | `plot_hline_width` | The width of the horizontal line. **TYPE:** `Union[int, float, None]` | | `plot_hline_alpha` | The alpha value of the horizontal line. **TYPE:** `Union[float, None]` | ### datachart.typings.TextStyleAttrs Bases: `TypedDict` The typing for the text annotation style. | ATTRIBUTE | DESCRIPTION | | -------------------------- | --------------------------------------------------------------------------------------------------------------- | | `plot_text_color` | The text color; falls back to the general font color. **TYPE:** `Union[str, None]` | | `plot_text_size` | The text font size. **TYPE:** `Union[int, float, str, None]` | | `plot_text_weight` | The text font weight. **TYPE:** `Union[FONT_WEIGHT, str, None]` | | `plot_text_halign` | The horizontal alignment of the text. **TYPE:** `Union[str, None]` | | `plot_text_valign` | The vertical alignment of the text. **TYPE:** `Union[str, None]` | | `plot_text_alpha` | The alpha value of the text. **TYPE:** `Union[float, None]` | | `plot_text_box_visible` | Whether to draw the background box. **TYPE:** `Union[bool, None]` | | `plot_text_box_style` | The matplotlib box style (e.g. "round,pad=0.4"). **TYPE:** `Union[str, None]` | | `plot_text_box_facecolor` | The face color of the box. **TYPE:** `Union[str, None]` | | `plot_text_box_edgecolor` | The edge color of the box. **TYPE:** `Union[str, None]` | | `plot_text_box_edge_width` | The edge width of the box. **TYPE:** `Union[int, float, None]` | | `plot_text_box_alpha` | The alpha value of the box. **TYPE:** `Union[float, None]` | | `plot_text_arrow_style` | The connector look (see ARROW_STYLE) or a raw matplotlib arrow style. **TYPE:** `Union[ARROW_STYLE, str, None]` | | `plot_text_arrow_curve` | The connector curvature; overrides the look's own. **TYPE:** `Union[float, None]` | | `plot_text_arrow_color` | The connector color. **TYPE:** `Union[str, None]` | | `plot_text_arrow_width` | The connector line width. **TYPE:** `Union[int, float, None]` | ### datachart.typings.HeatmapStyleAttrs Bases: `TypedDict` The typing for the heatmap chart style. | ATTRIBUTE | DESCRIPTION | | -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | | `plot_heatmap_cmap` | The color map of the heatmap (palette name, list of hex colors, or colormap). **TYPE:** `Union[str, List[str], colors.LinearSegmentedColormap, None]` | | `plot_heatmap_alpha` | The alpha value of the heatmap. **TYPE:** `Union[float, None]` | | `plot_heatmap_font_size` | The font size of the heatmap. **TYPE:** `Union[int, float, str, None]` | | `plot_heatmap_font_color` | The font color of the heatmap. **TYPE:** `Union[str, None]` | | `plot_heatmap_font_style` | The font style of the heatmap. **TYPE:** `Union[FONT_STYLE, str, None]` | | `plot_heatmap_font_weight` | The font weight of the heatmap. **TYPE:** `Union[FONT_WEIGHT, str, None]` | | `plot_heatmap_frame_color` | The color of the frame always drawn around heatmap axes. **TYPE:** `Union[str, None]` | | `plot_heatmap_edge_width` | The width of the borders drawn between the cells (0 draws none). **TYPE:** `Union[int, float, None]` | | `plot_heatmap_edge_color` | The color of the borders drawn between the cells. **TYPE:** `Union[str, None]` | ### datachart.typings.ScatterStyleAttrs Bases: `TypedDict` The typing for the scatter chart style. | ATTRIBUTE | DESCRIPTION | | ------------------------- | -------------------------------------------------------------- | | `plot_scatter_color` | The scatter marker color. **TYPE:** `Union[str, None]` | | `plot_scatter_alpha` | The alpha value of the markers. **TYPE:** `Union[float, None]` | | `plot_scatter_size` | The marker size. **TYPE:** `Union[int, float, None]` | | `plot_scatter_marker` | The marker shape. **TYPE:** `Union[LINE_MARKER, str, None]` | | `plot_scatter_zorder` | The zorder of the scatter. **TYPE:** `Union[int, float, None]` | | `plot_scatter_edge_width` | The edge width of markers. **TYPE:** `Union[int, float, None]` | | `plot_scatter_edge_color` | The edge color of markers. **TYPE:** `Union[str, None]` | ### datachart.typings.RegressionStyleAttrs Bases: `TypedDict` The typing for regression line style. | ATTRIBUTE | DESCRIPTION | | -------------------------- | ---------------------------------------------------------------- | | `plot_regression_color` | The regression line color. **TYPE:** `Union[str, None]` | | `plot_regression_alpha` | The alpha of the regression line. **TYPE:** `Union[float, None]` | | `plot_regression_width` | The line width. **TYPE:** `Union[int, float, None]` | | `plot_regression_style` | The line style. **TYPE:** `Union[LINE_STYLE, str, None]` | | `plot_regression_ci_alpha` | Confidence interval alpha. **TYPE:** `Union[float, None]` | ### datachart.typings.BoxStyleAttrs Bases: `TypedDict` The typing for the box plot style. | ATTRIBUTE | DESCRIPTION | | ----------------------------- | --------------------------------------------------------------------- | | `plot_box_color` | The box fill color. **TYPE:** `Union[str, None]` | | `plot_box_alpha` | The alpha value of the box. **TYPE:** `Union[float, None]` | | `plot_box_linewidth` | The line width of the box. **TYPE:** `Union[int, float, None]` | | `plot_box_edgecolor` | The edge color of the box. **TYPE:** `Union[str, None]` | | `plot_box_outlier_marker` | The outlier marker style. **TYPE:** `Union[LINE_MARKER, str, None]` | | `plot_box_outlier_size` | The outlier marker size. **TYPE:** `Union[int, float, None]` | | `plot_box_outlier_color` | The outlier marker color. **TYPE:** `Union[str, None]` | | `plot_box_outlier_edge_color` | The outlier marker edge color. **TYPE:** `Union[str, None]` | | `plot_box_median_color` | The median line color. **TYPE:** `Union[str, None]` | | `plot_box_median_linewidth` | The median line width. **TYPE:** `Union[int, float, None]` | | `plot_box_whisker_color` | The whisker line color. **TYPE:** `Union[str, None]` | | `plot_box_whisker_linewidth` | The whisker line width. **TYPE:** `Union[int, float, None]` | | `plot_box_cap_color` | The cap line color. **TYPE:** `Union[str, None]` | | `plot_box_cap_linewidth` | The cap line width. **TYPE:** `Union[int, float, None]` | | `plot_xticks_label_rotate` | The label rotation of the xticks. **TYPE:** `Union[int, float, None]` | | `plot_yticks_label_rotate` | The label rotation of the yticks. **TYPE:** `Union[int, float, None]` | ### datachart.typings.SwarmStyleAttrs Bases: `TypedDict` The typing for the swarm plot style. | ATTRIBUTE | DESCRIPTION | | ----------------------- | ----------------------------------------------------------------- | | `plot_swarm_color` | The point color. **TYPE:** `Union[str, None]` | | `plot_swarm_alpha` | The alpha value of the points. **TYPE:** `Union[float, None]` | | `plot_swarm_size` | The point size. **TYPE:** `Union[int, float, None]` | | `plot_swarm_marker` | The point marker shape. **TYPE:** `Union[LINE_MARKER, str, None]` | | `plot_swarm_zorder` | The zorder of the points. **TYPE:** `Union[int, float, None]` | | `plot_swarm_edge_width` | The edge width of the points. **TYPE:** `Union[int, float, None]` | | `plot_swarm_edge_color` | The edge color of the points. **TYPE:** `Union[str, None]` | ### datachart.typings.ViolinStyleAttrs Bases: `TypedDict` The typing for the violin plot style. | ATTRIBUTE | DESCRIPTION | | ----------------------------- | -------------------------------------------------------------------------------------- | | `plot_violin_color` | The violin fill color. **TYPE:** `Union[str, None]` | | `plot_violin_alpha` | The alpha value of the violin body. **TYPE:** `Union[float, None]` | | `plot_violin_linewidth` | The line width of the body edge. **TYPE:** `Union[int, float, None]` | | `plot_violin_edgecolor` | The edge color of the body; defaults to the fill. **TYPE:** `Union[str, None]` | | `plot_violin_width` | The maximum width of the body. **TYPE:** `Union[int, float, None]` | | `plot_violin_inner_color` | The color of the inner marks; defaults to the font color. **TYPE:** `Union[str, None]` | | `plot_violin_inner_linewidth` | The line width of the inner marks. **TYPE:** `Union[int, float, None]` | | `plot_violin_median_color` | The color of the median dot. **TYPE:** `Union[str, None]` | | `plot_violin_median_size` | The size of the median dot. **TYPE:** `Union[int, float, None]` | ### datachart.typings.RaincloudStyleAttrs Bases: `ViolinStyleAttrs`, `SwarmStyleAttrs`, `BoxStyleAttrs` The typing for the raincloud plot style. The union of the violin (cloud), swarm (rain), and box style keys; each key styles its own part of the raincloud. ### datachart.typings.ParallelCoordsStyleAttrs Bases: `TypedDict` The typing for the parallel coordinates chart style. | ATTRIBUTE | DESCRIPTION | | ----------------------------------- | --------------------------------------------------------------------------- | | `plot_parallel_color` | The line color. **TYPE:** `Union[str, None]` | | `plot_parallel_alpha` | The alpha value of the lines. **TYPE:** `Union[float, None]` | | `plot_parallel_width` | The line width. **TYPE:** `Union[int, float, None]` | | `plot_parallel_style` | The line style. **TYPE:** `Union[LINE_STYLE, str, None]` | | `plot_parallel_marker` | The marker style for data points. **TYPE:** `Union[LINE_MARKER, str, None]` | | `plot_parallel_zorder` | The draw order of data lines. **TYPE:** `Union[int, None]` | | `plot_parallel_axis_color` | The vertical axis line color. **TYPE:** `Union[str, None]` | | `plot_parallel_axis_width` | The vertical axis line width. **TYPE:** `Union[int, float, None]` | | `plot_parallel_axis_zorder` | The vertical axis line draw order. **TYPE:** `Union[int, None]` | | `plot_parallel_tick_color` | The tick mark color. **TYPE:** `Union[str, None]` | | `plot_parallel_tick_width` | The tick mark line width. **TYPE:** `Union[int, float, None]` | | `plot_parallel_tick_length` | The tick mark length. **TYPE:** `Union[float, None]` | | `plot_parallel_tick_label_size` | The tick label font size. **TYPE:** `Union[int, float, None]` | | `plot_parallel_tick_label_color` | The tick label font color. **TYPE:** `Union[str, None]` | | `plot_parallel_tick_label_bg_color` | The tick label background color. **TYPE:** `Union[str, None]` | | `plot_parallel_tick_label_bg_alpha` | The tick label background alpha. **TYPE:** `Union[float, None]` | | `plot_parallel_dim_label_size` | The dimension label font size. **TYPE:** `Union[int, float, None]` | | `plot_parallel_dim_label_color` | The dimension label font color. **TYPE:** `Union[str, None]` | | `plot_parallel_dim_label_rotation` | The dimension label rotation. **TYPE:** `Union[int, float, None]` | | `plot_parallel_dim_label_pad` | The dimension label padding from axis. **TYPE:** `Union[int, float, None]` | ### datachart.typings.ThemeDefaultAttrs Bases: `TypedDict` The typing for theme-driven defaults and cycles. | ATTRIBUTE | DESCRIPTION | | --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `chart_default_show_grid` | The theme default for show_grid, applied when a chart call leaves it unset. Never applies to heatmaps. None means the theme has no opinion. **TYPE:** `Union[SHOW_GRID, str, None]` | | `chart_default_show_values` | The theme default for show_values, applied when a chart call leaves it unset. None means the theme has no opinion. **TYPE:** `Union[bool, None]` | | `plot_hatch_cycle` | The hatch patterns assigned per bar/histogram series, parallel to the color cycle. An explicit per-chart hatch style wins. None disables the cycle. **TYPE:** `Union[List[str], None]` |