Charts#

Chart.js#

{chartjs} renderer#

This directive creates a chart based on Chart.js.

Pre-defined renderers can be used by specifying their name as a directive argument, and providing arguments in the directive content as a JSON5 object (without enclosing {}).

```{chartjs} chart
type: 'bar',
data: {
  labels: ['Monday', 'Tuesday', 'Wednesday'],
  datasets: [{
    label: "Option A",
    data: [7, 11, 3],
    borderWidth: 1, borderColor: '#36a2eb', hoverBorderColor: '#36a2eb',
    backgroundColor: '#36a2eb33',
  }],
},
options: {
  scales: {y: {beginAtZero: true}},
  plugins: {legend: {display: false}},
},
```

Custom renderers can be defined in JavaScript, by importing the chart module, adding rendering functions to render, and calling chart() (or one of the other renderers) in the rendering function.

```{chartjs} vBar
```

<script type="module">
const {chart, render} = await tdoc.import('tdoc/chart.js');

const colors = ['#36a2eb', '#ff6384', '#4bc0c0', '#ff9f40', '#9966ff',
                '#ffcd56', '#c9cbcf'];
render.vBar = el => {
  return chart(el, {
    type: 'bar',
    data: {
      labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
      datasets: [{data: [65, 59, 80, 81, 56, 55, 40]}],
    },
    options: {
      borderWidth: 1, borderColor: colors, hoverBorderColor: colors,
      backgroundColor: colors.map(c => `${c}33`),
      scales: {y: {beginAtZero: true}},
    },
  });
};
</script>

Defaults can be set via the chartjs metadata, and are merged into Chart.defaults.

chartjs directives generate <tdoc-dyn type="chartjs"> elements, and their controller property is the Chart instance returned by the renderer.

Options

:class: name [name...] (IDs)#

A space-separated list of CSS classes to add to the chart container.

:style: property: value; [property: value; ...]#

CSS styles to apply to the chart container.

Renderers#

This section describes the pre-defined renderers. Custom renderers can be added in JavaScript via render.

chart#

This renderer displays a chart from a static JSON config. The directive content is passed directly to chart(), after extracting dynamic annotation specifications from the annotations key. The whole config is provided as data to annotation generators.

```{chartjs} chart
type: 'bar',
data: {
  labels: ['Monday', 'Tuesday', 'Wednesday'],
  datasets: [{
    label: "Option A",
    data: [7, 11, 3],
    borderWidth: 1, borderColor: '#36a2eb', hoverBorderColor: '#36a2eb',
    backgroundColor: '#36a2eb33',
  }],
},
options: {
  scales: {y: {beginAtZero: true}},
  plugins: {legend: {display: false}},
},
annotations: {hLine: {y: 5, label: ''}}
```

venn#

This renderer works the same as chart, but it sets some defaults to simplify the creation of Venn diagrams.

  • The chart type is set to venn.

  • The background plugin is enabled and configured to set a solid white background.

  • A border is set on the containing element, unless the no-border class is present.

histogram#

This renderer displays the histogram of a sample or a distribution.

  • sample: The statistical sample for which to plot the histogram, an array of values or [value, count] pairs.

  • distribution: The distribution for which to plot the histogram, an array of [x, count] pairs where x is the lower bound of the bin, and the last element must have a zero (or undefined) count.

  • uniform: Use bins of uniform width (default) to compute the distribution from the sample. The keys define how the bins are computed:

    • count: The number of bins.

    • max: The largest value that needs to be handled. When unset, this is derived from the sample.

    • min: The lower limit of the first bin. When unset, this is derived from the sample.

    • origin (default: 0): The origin of the binning when width is set and min isn't.

    • width: The width of the bins. When unset, this is derived from count and the sample.

  • custom: Use custom bins to compute the distribution from the sample. The value is an array of bin boundaries.

  • normalize (default: false): When true, represent frequencies instead of counts.

  • options: Options to merge into the options field of the chart.

  • annotations: An object or array of objects containing dynamic annotation specifications.

```{chartjs} histogram
uniform: {min: 0, max: 24, width: 2},
sample: [
  10, 9, 11, 10, 9, 8, 6, 9, 10, 10, 7, 10, 9, 13, 15, 11, 8, 13, 7, 7,
  9, 7, 10, 12, 9, 10, 12, 15, 10, 8, 9, 11, 12, 9, 6, 17, 8, 13, 11, 16,
],
options: {
  borderWidth: 0.5, borderColor: '#36a2eb', backgroundColor: '#36a2eb33',
  scales: {y: {title: {display: true, text: "Occurrences"}}}
},
annotations: {median: {}},
```

densityFunction#

This renderer displays the density function of a sample.

  • sample: The statistical sample for which to plot the density function, an array of values or [value, count] pairs.

  • min: The minimum value to represent on the horizontal axis.

  • max: The maximum value to represent on the horizontal axis.

  • step: The smallest tick interval to represent on the horizontal axis.

  • width (default: 5): The width of the bars in pixels.

  • normalize (default: false): When true, represent frequencies instead of counts.

  • options: Options to merge into the options field of the chart.

  • annotations: An object or array of objects containing dynamic annotation specifications.

```{chartjs} densityFunction
min: 0, max: 24, step: 2,
sample: [
  [6, 2], [7, 4], [8, 4], [9, 8], [10, 8], [11, 4], [12, 3], [13, 3], [15, 2],
  [16, 1], [17, 1],
],
options: {
  backgroundColor: '#36a2eb',
  scales: {y: {title: {display: true, text: "Occurrences"}}},
},
annotations: {median: {}},
```

cumulativeDistributionFunction#

This renderer displays the cumulative distribution function of a sample or a distribution.

  • sample: The statistical sample for which to plot the CDF, an array of values or [value, count] pairs.

  • distribution: The distribution for which to plot the CDF, an array of [x, count] pairs where x is the lower bound of the bin, and the last element must have a zero (or undefined) count.

  • min: The minimum value to represent on the horizontal axis.

  • max: The maximum value to represent on the horizontal axis.

  • step: The smallest tick interval to represent on the horizontal axis.

  • normalize (default: true): When true, represent cumulative frequencies instead of counts.

  • options: Options to merge into the options field of the chart.

  • annotations: An object or array of objects containing dynamic annotation specifications.

```{chartjs} cumulativeDistributionFunction
min: 0, max: 24, step: 2,
sample: [
  [2, 1], [4, 3], [6, 7], [8, 8], [10, 2], [12, 1], [14, 6], [16, 9], [18, 8],
  [20, 5],
],
options: {
  borderColor: '#36a2eb',
  scales: {y: {title: {display: true, text: "Cumulative frequency"}}},
},
annotations: {median: {}},
```

Annotations#

Annotations are additional elements added to a graph by chartjs-plugin-annotation. While static annotations can be added directly via options.plugins.annotation.annotations and don't need special support, dynamic annotations are computed from chart data and are implemented via annotations.

An annotation specification is an object where each key specifies an annotation generator, and the value specifies the arguments to the generator, as an object. Moreover, the options key provides additional attributes to merge into the generated options.plugins.annotation.annotations entries. It can be set either in the specification or as an annotation argument.

For example, the following annotation specification adds vertical lines for the median, minimum, maximum, 1st and 3rd quartile and 5th and 95th percentile of a sample or distribution provided by a renderer. The median is colored magenta, while the others are colored red.

{
  median: {options: {borderColor: '#9966ff'}},
  min: {}, max: {}, quartile: {k: [1, 3]}, percentile: {p: [5, 95]},
  options: {borderColor: '#ff6384'},
}

The following annotation generators are pre-defined:

  • Generic annotations:

    • hLine: {y, label}: A horizontal line with the given text label. y can be an array to add multiple lines.

    • vLine: {x, label}: A vertical line with the given text label. x can be an array to add multiple lines.

  • Statistical annotations: These annotations get either a sample or a distribution from the renderer, as a {sample, distribution} object. If a renderer provides both a sample and a distribution, the dist argument specifies which should be used (false → sample, true → distribution).

    • count: {f = 1, dist = false, label}: A horizontal line at f times the sample or distribution count. f can be an array to add multiple lines.

    • min: {dist = false, label}: A vertical line at the minimum of the sample or distribution.

    • max: {dist = false, label}: A vertical line at the maximum of the sample or distribution.

    • median: {dist = false, label}: A vertical line at the median of the sample or distribution.

    • quartile: {k, dist = false, label}: A vertical line at the kth quartile of the sample or distribution. k can be an array to add multiple quartiles.

    • percentile: {p, dist = false, label}: A vertical line at the pth percentile of the sample or distribution. p can be an array to add multiple percentiles.

    • quantile: {p, dist = false, label}: A vertical line at the pth quantile of the sample or distribution. p can be an array to add multiple quantiles.

    • mean: {dist = false, label}: A vertical line at the mean of the sample or distribution.

    • stdDev: {f, population = false, dist = false, label}: A vertical line at f times the standard deviation from the mean. f can be an array to add multiple lines. When population is true, use the population deviation instead of the sample deviation.

    • avgDev: {f, from = 'median', dist = false, label}: A vertical line at f times the average deviation from the median (from = 'median') or mean (from = 'mean'). f can be an array to add multiple lines.

    • mode: {k, dist = true, label}: A vertical line at the kth mode of the sample or distribution. k can be an array to add multiple lines. If k is missing, a line is added for each mode.

Custom dynamic annotations can be defined by setting functions as attributes of annotations. Annotation generator functions receive the arguments from the annotation specification as their first argument, and the data from the renderer as their second argument, and return an array of annotation values to be added to options.plugins.annotation.annotations.

```{chartjs} chart
type: 'bar',
data: {
  labels: ['Monday', 'Tuesday', 'Wednesday'],
  datasets: [{data: [7, 11, 3]}],
},
annotations: {valueLabels: {label: 'Value: '}}
```

<script type="module">
const {annotations} = await tdoc.import('tdoc/chart.js');

annotations.valueLabels = ({label}, config) => {
  return config.data.datasets[0].data.map((v, i) => ({
    type: 'label', content: `${label ?? ''}${v}`,
    xValue: i, yValue: v, yAdjust: -15,
  }));
};
</script>

Plugins#

Chart.js plugins are implemented in JavaScript and managed via plugins. Plugins can be referenced by name by using strings as elements of the plugins attribute of the chart config.

The following plugins are pre-defined:

  • background: Paint the chart background. The following options are supported:

    • color: Fill the background with the given solid color.

    • gradient: Fill the background with a gradient.

      • type: The type of gradient; one of linear, conic or radial.

      • from, to: The endpoints of the gradient. For linear gradients, the endpoints are [x, y] tuples, where x is a fraction of the chart width and y a fraction of the chart height. For radial gradients, the endpoints are [x, y, r] tuples, where r is a fraction of the minimum between the chart width and height.

      • stops: The gradient stops, a list of [offset, color] tuples, where the offset is between 0 and 1.

Custom plugins can be registered by assigning them as attributes of plugins. The plugin id is automatically set to the name of the attribute, and that's also the name to use for the options of the plugin.

```{chartjs} chart
type: 'bar',
data: {
  labels: ['Monday', 'Tuesday', 'Wednesday'],
  datasets: [{data: [7, 11, 3]}],
},
plugins: ['backgroundGradient'],
options: {
  plugins: {
    backgroundGradient: {
      from: [0, 0], to: [0, 1], stops: [[0, '#fee'], [1, '#efe']],
    },
  },
},
```

<script type="module">
const {plugins} = await tdoc.import('tdoc/chart.js');

plugins.backgroundGradient = {
    beforeDraw(chart, args, options) {
        if (options.stops === undefined) return;
        const {ctx} = chart;
        ctx.save();
        ctx.globalCompositeOperation = 'destination-over';
        const grad = ctx.createLinearGradient(
          options.from[0] * chart.width, options.from[1] * chart.height,
          options.to[0] * chart.width, options.to[1] * chart.height);
        for (const [p, c] of options.stops) grad.addColorStop(p, c);
        ctx.fillStyle = grad;
        ctx.fillRect(0, 0, chart.width, chart.height);
        ctx.restore();
    },
};
</script>

tdoc/chart.js#

This module (source) provides functionality related to chartjs directives.

Module globals

chart.render#

An object containing named rendering functions. In addition to the pre-defined renderers described above, custom renderers can be added by setting functions as object attributes. Rendering functions receive the wrapper DOM element as their first argument, and the content of the directive as a JSON object as their second argument.

```{chartjs} randomBars
count: 3, min: 10, max: 50,
```
```{chartjs} randomBars
count: 5, min: 100, max: 500,
```

<script type="module">
const [core, {chart, render}] = await tdoc.import('tdoc/core.js', 'tdoc/chart.js');

render.randomBars = (el, {count, min, max}) => {
  const labels = [], data = [];
  for (let i = 0; i < count; ++i) {
    labels.push(`L${i + 1}`);
    data.push(core.randomInt(min, max));
  }
  return chart(el, {
    type: 'bar',
    data: {
      labels,
      datasets: [{data}],
    },
    options: {
      borderWidth: 1, borderColor: '#36a2eb', hoverBorderColor: '#36a2eb',
      backgroundColor: '#36a2eb33',
      scales: {y: {beginAtZero: true}},
      plugins: {legend: {display: false}},
    },
  })
};
</script>
chart.attrs#

An object containing named attribute sets. Custom sets can be defined by assigning to object attributes.

chart.annotations#

An object containing annotation generators. Custom annotations can be defined by assigning to object attributes.

chart.plugins#

An object containing plugins. Custom plugins can be defined by assigning to object attributes.

Functions

chart.chart(el, config)#

Render the content of a chartjs directive.

Arguments:
  • el (HTMLElement) -- The wrapper DOM element that will contain the chart.

  • config (Object|Array) -- The chart configuration, passed to the Chart constructor. If an Array of configs is provided, they are merged.

Returns:

A Promise that resolves to the created Chart instance.