Zopra/Charts
Guide
Getting startedAll chartsWhich chart to use?Domain specific
Base charts7
XY ChartTrendCandlestickHeatmapState TimelineFlame GraphBar Gauge
Derived charts73
Time SeriesHistogramStatus HistoryStatGaugeHoneyCombTracesNode GraphHeikin-AshiRenkoKagiPoint & FigureParetoIshikawaControl ChartBland-AltmanLollipopDumbbellSlopeBumpBack-to-BackWaterfallBulletFunnelMekkoForestBarcodeBeeswarmRidgelineHorizonSpectrogramAttention MapWaffleVennUpSetWarped WaffleWord CloudGanttSankeySankey MatrixTreemap ForceChord DiagramCircosArc DiagramAlluvialSankey FunnelDendrogramIcicleSunburstSpiderNightingale RoseParallel CoordinatesOscilloscopeEfficient FrontierPhase PortraitPoincaré MapBifurcationH-R DiagramRamachandranHarkerRoot LocusRadiation PatternQuiverHodographSmith ChartEye DiagramSequence LogoTernaryTernary ContourPiperStüveTephigramChoropleth

Charts/Base

Bar Gauge

<BarGauge /> · 14 examples

A filled bar for each value against a known range, coloured by how close it is to trouble.

Overview

A bar chart answers how big is each thing? A bar gauge answers a different and more anxious question: how full is each thing? Disk at 83%. Error budget at 12%. A queue holding 9,400 of a possible 10,000. The bar has a known start and a known end, and the interesting information is where the fill sits between them and what colour it has turned.

The idea comes from the instrument panel: the fuel gauge, the thermometer tube, the signal meter on an old stereo. All of them exist because a number is slow to read and a length is quick. The dashboards of the last decade took that one trick and put forty of them on a screen, which is why you will find it described as a bar gauge in monitoring tools and bullet graph by people who have read Stephen Few.

In zopra-charts there are three looks. The default gradient shows which thresholds a bar has crossed. The LCD style chops the bar into discrete cells, like a meter in a recording studio, which is easier to count at a distance. The basic style is a quiet rectangle for dashboards that already have enough going on. All three share one idea: the range is fixed, and the bar is honest about it.

Props

API

<BarGauge> shows one or more values as bars filled between a minimum and a maximum, coloured by thresholds or a colour scheme. If you have used Grafana's Bar Gauge panel, see Coming from Grafana.

use zopra_charts::*;
  • <BarGauge>
  • Where the bars come from
  • Display options
  • Range, colour and thresholds
  • Value text
  • Enums and types
  • Coming from Grafana

Not sure which option fits? See the guide.


<BarGauge>

PropTypeDefault
dataVec<T>, Signal<Vec<T>>, Frame<N>, Signal<Frame<N>>, or your own Datasetrequired
nameFn(&T) -> &strfield names for a Frame
valueFn(&T) -> f64field values for a Frame
reduceReduceone bar per row with value; the last value of each field for a Frame
fields&'static [&'static str]every field of a Frame
displayBarDisplayGradient
value_modeValueModeColor
name_placementNamePlacementAuto
text_modeTextModeAuto
orientationBarOrientationAuto
show_unfilledbooltrue
sizingSizingAuto
title_size, value_sizePixelsfitted to the space
min, maxf640. and 100.
thresholdsThresholdsyour theme's good colour, then its bad colour from 80
colorGaugeColorThresholds
formatFn(f64) -> SharedStringnone
decimalsusizeup to 3, trailing zeros dropped
legendLegendLegend::hidden()
classTailwind classesfills its parent
keyanything Into<ElementId>–

Where the bars come from

DataPropsBars
rows of your own typename and valueone per row
rows of your own typevalue and reduce={Reduce::Calc(..)}one bar summarising every row
a Framenoneone per field, showing its last value
a Framereduce={Reduce::Calc(Calc::Mean)}one per field, summarised with the calc
a Framereduce={Reduce::All { limit: Some(20) }}one per cell, row by row, up to the limit
a Framefields={&["api", "web"]}only those fields

name returns a borrowed string, so there's nothing to clone:

<BarGauge data={disks} name={|d: &Disk| d.mount.as_str()} value={|d| d.used} />
Reduce
VariantMeaning
Reduce::Calc(Calc)one value per field, using any Calc: Last, Mean, Max, …
Reduce::All { limit }every value; limit: None shows them all

Display options

PropEffect
displayGradient fills the bar with a blend of the colours it passes through. Lcd lights up separate cells. Basic is a flat bar with a solid edge.
orientationHorizontal stacks the bars as rows. Vertical lays them out as columns. Auto picks columns when the area is wider than it is tall.
name_placementTop puts the name above the bar, Left beside it, Hidden hides it. Auto places it on top when the row is taller than 40px, otherwise on the left. Vertical bars always show the name underneath.
text_modeValue, Name, ValueAndName or None. Auto shows the name when there's more than one bar or you provide a name accessor.
value_modeColor draws the value in the bar's colour, Text in the normal text colour, Hidden hides it.
show_unfilledDraws the empty part of the track. Ignored in Lcd mode.
sizingAuto divides the space evenly, with rows between 16 and 300px tall and columns at least 8px wide. Sizing::Manual { min_width, min_height, max_height } sets those limits yourself.
title_size, value_sizeFixed text sizes instead of sizes fitted to the space.

When the bars need more room than the area has, the ones that don't fit are cut off.

Range, colour and thresholds

The bar's length is its value's position between min and max. Values above max fill the bar, and values below min or missing (NaN) show only a sliver.

GaugeColor
VariantColour of each bar
GaugeColor::Thresholdsthe threshold step the value has reached
GaugeColor::Palettethe next colour from your theme's palette, one per bar
GaugeColor::Scheme(Scheme)the value's position between min and max on a colour scheme
GaugeColor::Fixed(Hsla)one colour for every bar

In Gradient mode, thresholds and schemes also blend along the bar: with thresholds the bar passes through each step it has reached, and with a scheme it shows the whole scheme along the track. In Lcd mode, each cell takes the colour for its own position.

Thresholds
static STEPS: LazyLock<[(f64, Hsla); 3]> =
    LazyLock::new(|| [(f64::NEG_INFINITY, rgb(0x40a02b).into()), (60., rgb(0xdf8e1d).into()), (85., rgb(0xd20f39).into())]);

thresholds={Thresholds::absolute(&STEPS[..])}
ConstructorStep values are
Thresholds::absolute(steps)values in the same units as the data
Thresholds::percentage(steps)percentages of the min–max range, from 0 to 100

The first step is the base colour, used for everything below the second step, so its value doesn't matter. Each later step applies from its value upwards. Steps take a Vec or a &'static slice; a static slice costs nothing to rebuild on every render.

Value text

The value is shown using format if you set it, otherwise with decimals, otherwise with up to three decimals and the trailing zeros dropped.

format={|v| format!("{v:.0} GiB").into()}

Enums and types

TypeValues
BarDisplayGradient (default), Lcd, Basic
ValueModeColor (default), Text, Hidden
NamePlacementAuto (default), Top, Left, Hidden
TextModeAuto (default), ValueAndName, Value, Name, None
BarOrientationAuto (default), Horizontal, Vertical
SizingAuto (default), Manual { min_width, min_height, max_height }
ReduceCalc(Calc), All { limit }
ThresholdsModeAbsolute, Percentage
GaugeColorThresholds (default), Palette, Scheme(Scheme), Fixed(Hsla)

Coming from Grafana

Grafana optionHere
Display modedisplay
Value displayvalue_mode
Name placementname_placement
Text modetext_mode
Show unfilled areashow_unfilled
Bar size, Min width, Min height, Max heightsizing
Orientationorientation
Value options: Calculation / All values / Limitreduce
Value options: Fieldsfields
Text size: title / valuetitle_size, value_size
Min, Maxmin, max
Thresholds (absolute / percentage)thresholds
Color schemecolor
Unit, Decimalsformat, decimals
Legendlegend

Not available here: value mappings, data links, and the colour schemes that need Grafana's field-colour registry. Use GaugeColor::Scheme with any scheme from your theme instead.

Run them

14 examples

Press Run to load an example into the live render at the top of the page. Open one to read its code.

How to read it

  1. 01Look at the colour before the length. Green or red tells you whether to keep reading.
  2. 02Then compare lengths down the list. Bars share one scale, so a longer bar is a fuller one, across rows or columns.
  3. 03In LCD mode, count lit cells: it is easier at a distance than judging a smooth edge.
  4. 04Hover a bar for its exact value. The name sits with each bar, and the text can be set to show names, values or both.

When to use it, and when not to

Reach for it when

  • Each value has a known range and you care how full it is: disk, memory, quota, SLO budget, queue against capacity.
  • You are comparing many things against the same limits, such as forty hosts with the same disk size.
  • The reader needs a verdict (fine, watch it, fix it) faster than they need a number. Colour thresholds do the work.
  • You have a table of series and want the latest value, or the mean or the peak, of each.

Skip it when

  • The values have no natural maximum. A bar with an invented max is a bar chart with a confusing coat on.
  • The point is how a value changed. Use Trend or Time Series. One gauge is one moment.
  • You need to compare sizes rather than fullness. A plain bar chart is the honest one there.
  • A single value with a target and context deserves a Bullet chart, which has room for the comparative marker.

The math behind it

Fill

Each bar has a value vvv and the gauge has a range [a,b][a, b][a,b] set by min and max. The filled fraction is the position of the value inside the range. It is capped at one on the high side, and a value that is not a number is drawn empty.

The bar's length in pixels is the available extent EEE along the gauge's axis times that fraction. The fraction is the same whether the bars are drawn as rows or columns. Only the axis changes.

f=min⁡ ⁣(v−ab−a, 1),length=f⋅Ef = \min\!\left(\frac{v - a}{b - a},\ 1\right), \qquad \text{length} = f \cdot Ef=min(b−av−a​, 1),length=f⋅E

Thresholds

Colours come from threshold steps, each a value and a colour, with the first step covering everything below the second. Thresholds::absolute states steps in the units of the data. Thresholds::percentage states them as percentages of the range, so a step ppp is at the value below, and the thresholds follow min and max when those change.

The default gauge turns from the theme's good colour to its bad colour at 80. The step's position along the bar is its fraction sss, which is where the gradient marks it.

xp=a+(b−a) p100,s=x−ab−a (absolute),s=p100 (percentage)x_p = a + (b - a)\,\frac{p}{100}, \qquad s = \frac{x - a}{b - a} \ \text{(absolute)}, \quad s = \frac{p}{100} \ \text{(percentage)}xp​=a+(b−a)100p​,s=b−ax−a​ (absolute),s=100p​ (percentage)

LCD cells

The LCD style divides the extent into n=⌊E/12⌋n = \lfloor E / 12 \rfloorn=⌊E/12⌋ cells of about 12 px including the gap. Cell kkk stands for the value a+(b−a) k/na + (b - a)\,k/na+(b−a)k/n and takes its colour from that value, so the bar changes colour exactly where the thresholds are. It is lit when that value is at or below the current one, and unlit cells are drawn faintly.

The consequence is that LCD bars are quantised. A value that is 41% of the way across lights 41% of the cells rounded down to a whole cell, and that is the price for being countable.

cell k lit  ⟺  a+(b−a)kn≤v,n=⌊E12⌋\text{cell } k \text{ lit} \iff a + (b - a)\frac{k}{n} \le v, \qquad n = \left\lfloor \frac{E}{12} \right\rfloorcell k lit⟺a+(b−a)nk​≤v,n=⌊12E​⌋

Real life usage

Forty-one hosts and a quiet red bar

Gustavo ran the storage fleet for a university research cluster in Valparaiso: forty-one machines, each with a 12-terabyte scratch disk, each used by a rotating cast of graduate students who regarded deletion as a thing that happened to other people's files.

The monitoring was a table. Forty-one rows, hostnames in one column, used percentage in the next. Every Monday Gustavo scrolled it, squinted at the numbers, and tried to remember which of them were considered bad. A rule in the alerting system paged him at 95%, which is roughly like a fire alarm that goes off when the building is already hot.

In February a disk filled to 100% in the middle of a three-day simulation. The run was lost. The student who owned it was gracious, in the way people are when they plan to mention it in their thesis acknowledgements.

Gustavo wanted the table to look like what it was, a list of things with a limit. He used <BarGauge> from zopra-charts: one bar per host, fed from the same time series he already collected, reduced to the latest value of each field, with percentage thresholds at 70 for amber and 85 for red so the colours moved if a disk was ever resized.

He picked the LCD display because the wall monitor was across the room, and the lit cells were countable from the door. The default horizontal rows with names on the left fit all forty-one on one screen.

Within a week the wall told a story the table had hidden. Eleven bars were amber, and three of those had been climbing by roughly 4 per cent a day. Gustavo emailed those three owners with a screenshot and a date, and not a word more.

No simulation has been lost since. The monitor in the corridor is now referred to as the thermometer, and students walk by and, with a kind of fond dread, count their cells.

Pitfalls

  • Invented maximum. If max is a number you made up, every bar's fullness is a statement about your imagination. Use a real capacity.
  • Thresholds that do not follow the range. Absolute thresholds stay put when you change min and max. Percentage ones move with them. Pick the one you mean.
  • Pale bars with white text. Use value_mode={ValueMode::Text} so the numbers stay readable on a light colour.
  • Palette colours used as a verdict. GaugeColor::Palette tells bars apart, it does not judge them. Reserve red for bad.
  • Building threshold lists in render. A vec![..] in your component is rebuilt every time. Put them in a static.

From around the web

Watch and read

YouTubeBeginners Guide - Visualizing Bar Gauges in Grafana | Grafana LabsGrafanaOfficial Grafana walkthrough of the bar gauge panel and its options.

Keep going

Related charts

GaugeOne value on a dial, when a single number deserves the whole panel.BulletOne bar with a target marker and qualitative ranges behind it.StatWhen you want the number big and a sparkline behind it.
PreviousFlame GraphNextTime Series

On this page

  • Live
  • Overview
  • API
  • Examples
  • How to read it
  • When to use it
  • The math
  • Story
  • Pitfalls
  • Watch and read
  • Related