Wrap a <table> in a
<figure class="mixed-chart"> to draw it as columns, lines and areas on one plot.
The class on each series header picks how that series is drawn.
The markup is the same as for a line
chart. Give a header cell column to draw that series
as columns from zero, or area for a line with a fading
fill under it. Any other series is a line, and
dashed dashes it. Columns sit behind the lines.
A legend names the series. A tooltip follows the pointer or the arrow keys
from row to row, with a point on each line. Add toggle to the figure to make each legend item a button that shows or hides its series, as on the line chart.
| Month | Revenue | Target |
|---|---|---|
| Jan | $62 | $65 |
| Feb | $71 | $65 |
| Mar | $68 | $70 |
| Apr | $80 | $70 |
| May | $76 | $75 |
| Jun | $89 | $75 |
<figure class="mixed-chart">
<figcaption>Revenue against target, $K</figcaption>
<table>
<thead>
<tr><th>Month</th><th class="column">Revenue</th><th class="dashed">Target</th></tr>
</thead>
<tbody>
<tr><th>Jan</th><td>$62</td><td>$65</td></tr>
<tr><th>Feb</th><td>$71</td><td>$65</td></tr>
<!-- … -->
</tbody>
</table>
</figure>
Second scale
Add end to a series header to draw that series against a second scale.
The second scale fits that series' own values, so a series in other units
or of another size still fills the plot. Without end, series share one scale.
To fix the second scale, set data-end-min and data-end-max on the
figure, as data-min and
data-max fix the first.
Add axis to label both scales at round values. The first
scale's labels sit beside the plot's start, with a grid line at each. The second
scale's labels run along its end. When neither scale has a fixed end, the second scale
stretches to as many steps as the first, so its labels share the
same grid lines. The labels repeat each scale's currency or percent
sign and are hidden from assistive technology. Without
axis, name both units in the caption or the headers.
| Month | Spend | Conversions |
|---|---|---|
| Jan | $12 | 340 |
| Feb | $15 | 410 |
| Mar | $14 | 390 |
| Apr | $18 | 480 |
| May | $20 | 520 |
| Jun | $22 | 610 |
<figure class="mixed-chart axis">
<figcaption>Ad spend ($K) and conversions</figcaption>
<table>
<thead>
<tr><th>Month</th><th class="column">Spend</th><th class="end">Conversions</th></tr>
</thead>
<tbody>
<tr><th>Jan</th><td>$12</td><td>340</td></tr>
<!-- … -->
</tbody>
</table>
</figure>
Areas
An area series fills down to the bottom of the plot.
In this example, traffic is an area and the bounce rate is a dashed line on a
second scale from 0% to 100%.
| Month | Traffic | Bounce rate |
|---|---|---|
| Jan | 8.2 | 58% |
| Feb | 9.4 | 55% |
| Mar | 10.1 | 52% |
| Apr | 9.8 | 54% |
| May | 11.6 | 49% |
| Jun | 12.4 | 46% |
<figure class="mixed-chart" data-end-min="0" data-end-max="100">
<figcaption>Traffic (thousands of visits) and bounce rate</figcaption>
<table>
<thead>
<tr><th>Month</th><th class="area">Traffic</th><th class="dashed end">Bounce rate</th></tr>
</thead>
<tbody>
<tr><th>Jan</th><td>8.2</td><td>58%</td></tr>
<!-- … -->
</tbody>
</table>
</figure>
All three kinds fit on one plot. Several series can share the second scale. Here the margin and the growth rate are both percentages from 0 to 35, and revenue keeps the first scale.
| Month | Revenue | Profit margin | Customer growth |
|---|---|---|---|
| Jan | $420 | 18% | 4% |
| Feb | $460 | 19% | 5% |
| Mar | $510 | 21% | 6% |
| Apr | $480 | 20% | 5% |
| May | $560 | 22% | 7% |
| Jun | $610 | 24% | 8% |
| Jul | $590 | 23% | 7% |
| Aug | $640 | 25% | 9% |
| Sep | $700 | 27% | 10% |
| Oct | $680 | 26% | 9% |
| Nov | $750 | 28% | 11% |
| Dec | $820 | 30% | 13% |
<figure class="mixed-chart" data-end-min="0" data-end-max="35">
<figcaption>Revenue ($K), profit margin and customer growth</figcaption>
<table>
<thead>
<tr>
<th>Month</th>
<th class="column">Revenue</th>
<th class="area end">Profit margin</th>
<th class="dashed end">Customer growth</th>
</tr>
</thead>
<tbody>
<tr><th>Jan</th><td>$420</td><td>18%</td><td>4%</td></tr>
<!-- … -->
</tbody>
</table>
</figure>
Stacked columns
Add stacked to stack the column series into one column per
row, so a reader sees both the parts and the total. Lines and areas
keep their own values, such as a target to compare the totals
with. Columns on the second scale stack in their own column beside
the first. List them after the others. points marks
each value on the lines with a dot, and straight draws
straight lines between them instead of a curve.
| Month | Online | Store | Target |
|---|---|---|---|
| Jan | 38 | 24 | 65 |
| Feb | 44 | 27 | 65 |
| Mar | 41 | 27 | 70 |
| Apr | 52 | 28 | 70 |
| May | 49 | 27 | 75 |
| Jun | 58 | 31 | 75 |
<figure class="mixed-chart axis stacked points straight">
<figcaption>Revenue by channel ($K) against target</figcaption>
<table>
<thead>
<tr><th>Month</th><th class="column">Online</th><th class="column">Store</th><th class="dashed">Target</th></tr>
</thead>
<tbody>
<tr><th>Jan</th><td>38</td><td>24</td><td>65</td></tr>
<!-- … -->
</tbody>
</table>
</figure>
Chart cards
Put a chart in a card with the figures it explains. The card adds
no chart styles. Set the plot's height with
--md-comp-mixed-chart-height.
- Support tickets
- 190
- Resolved in 3.9h on average
| Month | Tickets | Hours to resolve |
|---|---|---|
| Jan | 142 | 5.2 |
| Feb | 158 | 4.8 |
| Mar | 130 | 5.5 |
| Apr | 175 | 4.3 |
| May | 160 | 4.6 |
| Jun | 190 | 3.9 |
<article class="outlined">
<div class="p-4">
<dl class="stats my-0">
<div>
<dt>Support tickets</dt>
<dd>190</dd>
<dd class="stat-change up">Resolved in 3.9h on average</dd>
</div>
</dl>
<figure class="mixed-chart" style="--md-comp-mixed-chart-height: 120px">
<figcaption class="visually-hidden">Tickets and resolution time by month</figcaption>
<table><!-- … --></table>
</figure>
</div>
</article>
For a trend beside a figure that already explains it, add sparkline.
It draws a 48px chart with no grid, labels, legend or tooltip.
Values and colors
The chart reads cells as a line chart does. A cell's number is its
data-value, or its text without currency signs, percent
signs or grouping commas. The tooltip shows each cell's text as
written. A scale with columns always includes zero. Otherwise it
spans its values with a tenth to spare at each end. The data attributes or the
min and max options override that range.
A gap breaks a line and leaves a column's slot empty.
Series take primary, tertiary,
secondary and on-surface-variant in
column order, whatever their kind. A fifth series repeats the first
color.
Accessibility
The table is the chart's text alternative. Give it a header row and
a header cell per row, and name the chart with a
<figcaption>. There is no y axis, so put the
units in the caption, the headers or the cells. The chart hides its drawn marks,
labels and legend from assistive technology.
The plot is one Tab stop, named by the caption. Left and right move between rows. Home and End jump to the ends, and Escape hides the tooltip. In a right-to-left page, the rows and the arrows run right to left. On a touch screen, tap a row to show it. The tooltip is a polite live region, so a screen reader announces each row's values as the tooltip moves. A sparkline is not focusable.
Readers can tell dashed lines from solid ones without color. In forced colors, the marks keep their colors so the legend still matches them.
JavaScript
AutoInit() starts every .mixed-chart. To
start one yourself, call MixedChart.init. After you change its
table, call update() to redraw it in place. Or put
data-watch on the figure, and the chart redraws itself. The columns,
lines and areas move from their old values to the new ones, as in
the line and column charts. With reduced motion, they appear at
once. The mixed chart has the line chart's
methods and options. min and max apply to
the first scale.
const chart = Expressive.MixedChart.init(document.querySelector('.mixed-chart'));
chart.show(2); // highlight the third row; -1 hides the tooltip
chart.update(); // redraw from the table; focus and the highlighted row stay
chart.destroy(); // remove the drawing and show the table again
Tokens
Override these on the .mixed-chart.
| Token | Default |
|---|---|
--md-comp-mixed-chart-height | 240px, the plot's height; 48px for a sparkline |
--md-comp-mixed-chart-column-width | 50% of each row's width |
--md-comp-mixed-chart-shape | 4px, a column's end radius |
--md-comp-mixed-chart-line-width | 3px; 2px for a sparkline |
--md-comp-mixed-chart-grid-color | outline-variant |
--md-comp-mixed-chart-axis-width | 48px, the room on each side of the plot for axis labels |
--md-comp-mixed-chart-color-1 … -4 | primary, tertiary, secondary, on-surface-variant |
For a selective Sass build, include "mixed-chart" in $components.