Skip to content
KONIGI Patterns

Dashboards / Charts and data displays / Calendar heatmap

‹ 3 of 22 ›

Calendar heatmap

People need to spot recurring patterns and gaps in daily activity.

Updated September 10, 2026

Problem

A long series of daily values can make weekly and seasonal patterns difficult to see.

Solution

Show one cell per day in a calendar grid, using color intensity for the value. Align weekdays consistently so repeated busy or quiet days form visible patterns.

Label the date range and color scale. Provide the date and exact value on interaction, and distinguish missing data from a recorded zero.

Choose color ranges that reveal useful differences without letting one extreme day flatten the rest. For hourly patterns, use a grid of hours against weekdays instead.

Use when

People need to find recurring calendar patterns across a long period, rather than compare precise daily values.

Don’t use when

Exact values matter, or the period is short. A month of data in this layout is four columns and a line chart says more. Also poor for anything without a weekly cycle, where the row structure encodes nothing and only adds work.

Trade-offs

Color gives only an approximate reading, and the chosen range strongly affects what stands out. Small cells are difficult to read on phones or distant screens. An empty-looking day may be misread unless missing and low values are distinct.

Checklist

  • Does this data actually have a weekly or seasonal cycle worth showing?
  • Is the colour scale continuous or bucketed, and does that suit the question?
  • Is the range clamped so one outlier does not flatten the rest?
  • Is the scale legend present, with real values on it?
  • Does a zero-value day look different from a day with no data?
  • Are weekends or non-working days distinguished where that matters?
  • Which day does the week start on, and does it match the audience’s convention?
  • Is there a hover giving the date and the exact value?
  • Does the grid stay legible at the size it renders at?
  • Would viewers import GitHub’s “activity” reading and misinterpret a pale cell?

Compare

GitHub’s contribution graph is the reference implementation and the reason the pattern needs no explaining, using coarse intensity buckets that make the rhythm legible while making individual days deliberately approximate. Grafana has no calendar-layout panel in core, so teams reach for community plugins or reshape data into the standard heatmap, losing the calendar semantics that make the layout worth having. Datadog applies the punch-card variant to incident and alert timing, which is the strongest operational use of the idea because on-call load genuinely has an hour-of-day shape. Observable and D3 are where most bespoke versions get built, which is why the pattern is common in one-off analyses and rare inside monitoring products.

Heatmap is the general grid form. Cohort grid aligns groups by time since joining. Sequential and diverging scales defines the color range.

Status history shows states rather than quantities. Time series is useful when changes in value matter more than calendar rhythm.

Calendar heatmap anatomy A year of daily activity, one cell per day, weeks as columns and weekdays as rows. The two weekend rows are consistently pale across the whole chart, and a fortnight off in July is a pale vertical gap. Both readings come from the layout rather than from anything anyone labelled. A year in a strip Jan Mar May Jul Sep Nov Sun Tue Thu Sat 1 2 Less More 3 1 EVERY ROW IS ONE WEEKDAY So a weekend effect is two consistently pale rows running the whole width, which no line chart shows without being asked. 2 EVERY COLUMN IS ONE WEEK So a quiet fortnight is a pale vertical gap. Both readings come from the arrangement, not from anything anyone labelled. 3 COARSE BUCKETS, ON PURPOSE A handful of intensity steps rather than a continuous ramp. It makes the rhythm readable and makes individual days approximate — a day with four and a day with forty can land on the same shade. Right for the rhythm, wrong for magnitude. The variant worth knowing is the punch card: hour of day against day of week, which is the better answer for anything with a daily shape rather than a weekly one.
Wireframe — the pattern's anatomy, not any one product's version of it

Implementation

A heatmap whose x-axis is the calendar, so weekly rhythm and holidays become visible. The empty cell has to differ from the zero cell or a quiet week reads as missing data.

Tokens
--card--muted--muted-foreground--border--scale-seq-1--scale-seq-2--scale-seq-3--scale-seq-4--scale-seq-5
JanFebMarAprMayJunJulAugSepOctNovDecSunTueThuSat2023-01-01: 0 deploys2023-01-02: 0 deploys2023-01-03: 2 deploys2023-01-04: 0 deploys2023-01-05: 0 deploys2023-01-06: 2 deploys2023-01-07: 0 deploys2023-01-08: 0 deploys2023-01-09: 1 deploys2023-01-10: 3 deploys2023-01-11: 1 deploys2023-01-12: 1 deploys2023-01-13: 3 deploys2023-01-14: 0 deploys2023-01-15: 0 deploys2023-01-16: 1 deploys2023-01-17: 1 deploys2023-01-18: 3 deploys2023-01-19: 3 deploys2023-01-20: 3 deploys2023-01-21: 0 deploys2023-01-22: 0 deploys2023-01-23: 2 deploys2023-01-24: 2 deploys2023-01-25: 1 deploys2023-01-26: 3 deploys2023-01-27: 1 deploys2023-01-28: 0 deploys2023-01-29: 0 deploys2023-01-30: 1 deploys2023-01-31: 3 deploys2023-02-01: 3 deploys2023-02-02: 8 deploys2023-02-03: 3 deploys2023-02-04: 0 deploys2023-02-05: 0 deploys2023-02-06: 4 deploys2023-02-07: 2 deploys2023-02-08: 4 deploys2023-02-09: 7 deploys2023-02-10: 2 deploys2023-02-11: 0 deploys2023-02-12: 0 deploys2023-02-13: 1 deploys2023-02-14: 3 deploys2023-02-15: 2 deploys2023-02-16: 5 deploys2023-02-17: 2 deploys2023-02-18: 0 deploys2023-02-19: 2 deploys2023-02-20: 1 deploys2023-02-21: 8 deploys2023-02-22: 7 deploys2023-02-23: 2 deploys2023-02-24: 7 deploys2023-02-25: 0 deploys2023-02-26: 0 deploys2023-02-27: 2 deploys2023-02-28: 5 deploys2023-03-01: 1 deploys2023-03-02: 6 deploys2023-03-03: 6 deploys2023-03-04: 0 deploys2023-03-05: 1 deploys2023-03-06: 12 deploys2023-03-07: 1 deploys2023-03-08: 3 deploys2023-03-09: 5 deploys2023-03-10: 4 deploys2023-03-11: 3 deploys2023-03-12: 0 deploys2023-03-13: 7 deploys2023-03-14: 8 deploys2023-03-15: 5 deploys2023-03-16: 2 deploys2023-03-17: 11 deploys2023-03-18: 2 deploys2023-03-19: 3 deploys2023-03-20: 10 deploys2023-03-21: 10 deploys2023-03-22: 2 deploys2023-03-23: 4 deploys2023-03-24: 10 deploys2023-03-25: 3 deploys2023-03-26: 3 deploys2023-03-27: 12 deploys2023-03-28: 11 deploys2023-03-29: 12 deploys2023-03-30: 5 deploys2023-03-31: 5 deploys2023-04-01: 3 deploys2023-04-02: 1 deploys2023-04-03: 6 deploys2023-04-04: 16 deploys2023-04-05: 8 deploys2023-04-06: 3 deploys2023-04-07: 6 deploys2023-04-08: 1 deploys2023-04-09: 3 deploys2023-04-10: 11 deploys2023-04-11: 5 deploys2023-04-12: 6 deploys2023-04-13: 27 deploys2023-04-14: 11 deploys2023-04-15: 1 deploys2023-04-16: 2 deploys2023-04-17: 4 deploys2023-04-18: 8 deploys2023-04-19: 10 deploys2023-04-20: 6 deploys2023-04-21: 6 deploys2023-04-22: 3 deploys2023-04-23: 3 deploys2023-04-24: 30 deploys2023-04-25: 5 deploys2023-04-26: 10 deploys2023-04-27: 23 deploys2023-04-28: 11 deploys2023-04-29: 3 deploys2023-04-30: 2 deploys2023-05-01: 8 deploys2023-05-02: 14 deploys2023-05-03: 6 deploys2023-05-04: 15 deploys2023-05-05: 11 deploys2023-05-06: 2 deploys2023-05-07: 3 deploys2023-05-08: 12 deploys2023-05-09: 5 deploys2023-05-10: 14 deploys2023-05-11: 15 deploys2023-05-12: 8 deploys2023-05-13: 1 deploys2023-05-14: 1 deploys2023-05-15: 5 deploys2023-05-16: 4 deploys2023-05-17: 18 deploys2023-05-18: 25 deploys2023-05-19: 28 deploys2023-05-20: 1 deploys2023-05-21: 2 deploys2023-05-22: 20 deploys2023-05-23: 18 deploys2023-05-24: 25 deploys2023-05-25: 13 deploys2023-05-26: 8 deploys2023-05-27: 3 deploys2023-05-28: 1 deploys2023-05-29: 26 deploys2023-05-30: 17 deploys2023-05-31: 14 deploys2023-06-01: 21 deploys2023-06-02: 20 deploys2023-06-03: 3 deploys2023-06-04: 1 deploys2023-06-05: 28 deploys2023-06-06: 21 deploys2023-06-07: 20 deploys2023-06-08: 13 deploys2023-06-09: 23 deploys2023-06-10: 2 deploys2023-06-11: 3 deploys2023-06-12: 22 deploys2023-06-13: 30 deploys2023-06-14: 17 deploys2023-06-15: 6 deploys2023-06-16: 25 deploys2023-06-17: 1 deploys2023-06-18: 2 deploys2023-06-19: 27 deploys2023-06-20: 6 deploys2023-06-21: 4 deploys2023-06-22: 29 deploys2023-06-23: 23 deploys2023-06-24: 2 deploys2023-06-25: 3 deploys2023-06-26: 14 deploys2023-06-27: 4 deploys2023-06-28: 29 deploys2023-06-29: 5 deploys2023-06-30: 17 deploys2023-07-01: 1 deploys2023-07-02: 1 deploys2023-07-03: 27 deploys2023-07-04: 27 deploys2023-07-05: 24 deploys2023-07-06: 16 deploys2023-07-07: 11 deploys2023-07-08: 3 deploys2023-07-09: 2 deploys2023-07-10: 18 deploys2023-07-11: 19 deploys2023-07-12: 10 deploys2023-07-13: 13 deploys2023-07-14: 6 deploys2023-07-15: 1 deploys2023-07-16: 0 deploys2023-07-17: 0 deploys2023-07-18: 0 deploys2023-07-19: 0 deploys2023-07-20: 0 deploys2023-07-21: 0 deploys2023-07-22: 0 deploys2023-07-23: 0 deploys2023-07-24: 0 deploys2023-07-25: 0 deploys2023-07-26: 0 deploys2023-07-27: 0 deploys2023-07-28: 0 deploys2023-07-29: 0 deploys2023-07-30: 1 deploys2023-07-31: 12 deploys2023-08-01: 4 deploys2023-08-02: 15 deploys2023-08-03: 20 deploys2023-08-04: 4 deploys2023-08-05: 1 deploys2023-08-06: 1 deploys2023-08-07: 23 deploys2023-08-08: 12 deploys2023-08-09: 15 deploys2023-08-10: 26 deploys2023-08-11: 24 deploys2023-08-12: 1 deploys2023-08-13: 1 deploys2023-08-14: 7 deploys2023-08-15: 7 deploys2023-08-16: 23 deploys2023-08-17: 9 deploys2023-08-18: 14 deploys2023-08-19: 3 deploys2023-08-20: 1 deploys2023-08-21: 4 deploys2023-08-22: 5 deploys2023-08-23: 10 deploys2023-08-24: 5 deploys2023-08-25: 13 deploys2023-08-26: 2 deploys2023-08-27: 3 deploys2023-08-28: 2 deploys2023-08-29: 8 deploys2023-08-30: 12 deploys2023-08-31: 4 deploys2023-09-01: 13 deploys2023-09-02: 2 deploys2023-09-03: 0 deploys2023-09-04: 7 deploys2023-09-05: 15 deploys2023-09-06: 7 deploys2023-09-07: 13 deploys2023-09-08: 15 deploys2023-09-09: 1 deploys2023-09-10: 3 deploys2023-09-11: 6 deploys2023-09-12: 8 deploys2023-09-13: 15 deploys2023-09-14: 8 deploys2023-09-15: 15 deploys2023-09-16: 2 deploys2023-09-17: 1 deploys2023-09-18: 7 deploys2023-09-19: 4 deploys2023-09-20: 7 deploys2023-09-21: 1 deploys2023-09-22: 8 deploys2023-09-23: 0 deploys2023-09-24: 3 deploys2023-09-25: 3 deploys2023-09-26: 1 deploys2023-09-27: 2 deploys2023-09-28: 4 deploys2023-09-29: 2 deploys2023-09-30: 1 deploys2023-10-01: 0 deploys2023-10-02: 5 deploys2023-10-03: 2 deploys2023-10-04: 7 deploys2023-10-05: 3 deploys2023-10-06: 3 deploys2023-10-07: 2 deploys2023-10-08: 0 deploys2023-10-09: 6 deploys2023-10-10: 2 deploys2023-10-11: 1 deploys2023-10-12: 2 deploys2023-10-13: 2 deploys2023-10-14: 1 deploys2023-10-15: 0 deploys2023-10-16: 4 deploys2023-10-17: 4 deploys2023-10-18: 5 deploys2023-10-19: 1 deploys2023-10-20: 2 deploys2023-10-21: 0 deploys2023-10-22: 0 deploys2023-10-23: 6 deploys2023-10-24: 3 deploys2023-10-25: 8 deploys2023-10-26: 3 deploys2023-10-27: 2 deploys2023-10-28: 0 deploys2023-10-29: 0 deploys2023-10-30: 1 deploys2023-10-31: 2 deploys2023-11-01: 3 deploys2023-11-02: 2 deploys2023-11-03: 1 deploys2023-11-04: 0 deploys2023-11-05: 0 deploys2023-11-06: 3 deploys2023-11-07: 3 deploys2023-11-08: 3 deploys2023-11-09: 2 deploys2023-11-10: 1 deploys2023-11-11: 0 deploys2023-11-12: 0 deploys2023-11-13: 3 deploys2023-11-14: 2 deploys2023-11-15: 2 deploys2023-11-16: 1 deploys2023-11-17: 1 deploys2023-11-18: 0 deploys2023-11-19: 0 deploys2023-11-20: 3 deploys2023-11-21: 1 deploys2023-11-22: 2 deploys2023-11-23: 2 deploys2023-11-24: 3 deploys2023-11-25: 0 deploys2023-11-26: 0 deploys2023-11-27: 0 deploys2023-11-28: 1 deploys2023-11-29: 3 deploys2023-11-30: 1 deploys2023-12-01: 2 deploys2023-12-02: 0 deploys2023-12-03: 0 deploys2023-12-04: 0 deploys2023-12-05: 0 deploys2023-12-06: 3 deploys2023-12-07: 2 deploys2023-12-08: 3 deploys2023-12-09: 0 deploys2023-12-10: 0 deploys2023-12-11: 0 deploys2023-12-12: 2 deploys2023-12-13: 0 deploys2023-12-14: 2 deploys2023-12-15: 1 deploys2023-12-16: 0 deploys2023-12-17: 0 deploys2023-12-18: 0 deploys2023-12-19: 3 deploys2023-12-20: 0 deploys2023-12-21: 0 deploys2023-12-22: 0 deploys2023-12-23: 0 deploys2023-12-24: 0 deploys2023-12-25: 0 deploys2023-12-26: 1 deploys2023-12-27: 0 deploys2023-12-28: 2 deploys2023-12-29: 1 deploys2023-12-30: 0 deploys2023-12-31: no data
LessMoreNo data

CalendarHeatmap.tsxLays days out by date, buckets values against thresholds the caller names, and draws a missing day as an outline rather than as zero.

/**
 * The layout is the encoding. Every row is one weekday and every column is
 * one week, so a weekend effect and a quiet fortnight are both visible from
 * the arrangement alone. Colour is bucketed on purpose: a handful of steps
 * makes the rhythm readable and makes individual days approximate, and the
 * exact value lives in the hover.
 *
 * `null` is a day with no data. It is drawn as an outline, because a day that
 * was not measured is a different fact from a day whose value was zero.
 */
const CELL = 10, GAP = 2, STEP = CELL + GAP;
const DAY = 86_400_000;
const MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
const DAYS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
/** Full class names, because Tailwind only ships the ones it can see. */
const FILL = ["fill-muted", "fill-scale-seq-1", "fill-scale-seq-2", "fill-scale-seq-3", "fill-scale-seq-4", "fill-scale-seq-5"];

export function CalendarHeatmap({ start, values, thresholds, unit, weekStart = 0, onSelect }: {
  /** ISO date of values[0]. */
  start: string;
  /** One entry per consecutive day. `null` means no sample arrived. */
  values: (number | null)[];
  /** Lower bound of each coloured step, ascending: five of them for a five-step ramp.
   *  Required, so the legend can show real values rather than "less" and "more" alone. */
  thresholds: number[];
  unit: string;
  weekStart?: 0 | 1;
  onSelect?: (date: string, value: number | null) => void;
}) {
  const t0 = Date.parse(start);
  const row = (t: number) => (new Date(t).getUTCDay() - weekStart + 7) % 7;
  const gridStart = t0 - row(t0) * DAY;
  const days = values.map((value, i) => {
    const t = t0 + i * DAY;
    return { t, value, col: Math.floor((t - gridStart) / (7 * DAY)), row: row(t) };
  });
  const cols = days[days.length - 1].col + 1;
  const bucket = (v: number) => thresholds.filter((th) => v >= th).length;
  const iso = (t: number) => new Date(t).toISOString().slice(0, 10);
  const monthStarts = days.filter((d) => new Date(d.t).getUTCDate() === 1 || d === days[0]);
  const left = 30, top = 16;
  const width = left + cols * STEP, height = top + 7 * STEP;

  return (
    <div>
      <svg width={width} height={height} viewBox={`0 0 ${width} ${height}`} role="img" aria-label={`${unit} per day from ${start}`} className="block max-w-full">
        {monthStarts.map((d) => (
          <text key={d.t} x={left + d.col * STEP} y={10} className="fill-muted-foreground text-[10px]">{MONTHS[new Date(d.t).getUTCMonth()]}</text>
        ))}
        {[0, 2, 4, 6].map((r) => (
          <text key={r} x={left - 6} y={top + r * STEP + CELL - 1} textAnchor="end" className="fill-muted-foreground text-[10px]">{DAYS[(r + weekStart) % 7]}</text>
        ))}
        {days.map((d) => (
          <rect
            key={d.t}
            x={left + d.col * STEP}
            y={top + d.row * STEP}
            width={CELL}
            height={CELL}
            rx={1.5}
            className={d.value === null ? "fill-none stroke-border" : FILL[bucket(d.value)]}
            onClick={onSelect && (() => onSelect(iso(d.t), d.value))}
          >
            <title>{`${iso(d.t)}: ${d.value === null ? "no data" : `${d.value} ${unit}`}`}</title>
          </rect>
        ))}
      </svg>

      <div className="mt-3 flex items-center gap-1.5 text-[10px] text-muted-foreground" style={{ marginLeft: left }}>
        <span>Less</span>
        {FILL.map((cls, i) => (
          <svg key={cls} width={CELL} height={CELL} aria-hidden="true">
            <rect width={CELL} height={CELL} rx={1.5} className={cls}>
              <title>{i === 0 ? `0 ${unit}` : i === FILL.length - 1 ? `${thresholds[i - 1]}+ ${unit}` : `${thresholds[i - 1]}–${thresholds[i] - 1} ${unit}`}</title>
            </rect>
          </svg>
        ))}
        <span>More</span>
        <svg width={CELL} height={CELL} aria-hidden="true" className="ml-3"><rect x={0.5} y={0.5} width={CELL - 1} height={CELL - 1} rx={1.5} className="fill-none stroke-border" /></svg>
        <span>No data</span>
      </div>
    </div>
  );
}

deploys.tsThe year's counts, one row per week. The quiet fortnight and the pale weekend rows are in the data, not the drawing.

/**
 * Deploys per day for 2023, one row per week starting on Sunday, 1 January.
 * The two quiet columns in July are the fortnight the team was off. The
 * weekend rows are quiet all year, and nothing has to be labelled for the
 * reader to see either.
 */
export const START = "2023-01-01";

export const WEEKS: number[][] = [
  [ 0,  0,  2,  0,  0,  2,  0],
  [ 0,  1,  3,  1,  1,  3,  0],
  [ 0,  1,  1,  3,  3,  3,  0],
  [ 0,  2,  2,  1,  3,  1,  0],
  [ 0,  1,  3,  3,  8,  3,  0],
  [ 0,  4,  2,  4,  7,  2,  0],
  [ 0,  1,  3,  2,  5,  2,  0],
  [ 2,  1,  8,  7,  2,  7,  0],
  [ 0,  2,  5,  1,  6,  6,  0],
  [ 1, 12,  1,  3,  5,  4,  3],
  [ 0,  7,  8,  5,  2, 11,  2],
  [ 3, 10, 10,  2,  4, 10,  3],
  [ 3, 12, 11, 12,  5,  5,  3],
  [ 1,  6, 16,  8,  3,  6,  1],
  [ 3, 11,  5,  6, 27, 11,  1],
  [ 2,  4,  8, 10,  6,  6,  3],
  [ 3, 30,  5, 10, 23, 11,  3],
  [ 2,  8, 14,  6, 15, 11,  2],
  [ 3, 12,  5, 14, 15,  8,  1],
  [ 1,  5,  4, 18, 25, 28,  1],
  [ 2, 20, 18, 25, 13,  8,  3],
  [ 1, 26, 17, 14, 21, 20,  3],
  [ 1, 28, 21, 20, 13, 23,  2],
  [ 3, 22, 30, 17,  6, 25,  1],
  [ 2, 27,  6,  4, 29, 23,  2],
  [ 3, 14,  4, 29,  5, 17,  1],
  [ 1, 27, 27, 24, 16, 11,  3],
  [ 2, 18, 19, 10, 13,  6,  1],
  [ 0,  0,  0,  0,  0,  0,  0],
  [ 0,  0,  0,  0,  0,  0,  0],
  [ 1, 12,  4, 15, 20,  4,  1],
  [ 1, 23, 12, 15, 26, 24,  1],
  [ 1,  7,  7, 23,  9, 14,  3],
  [ 1,  4,  5, 10,  5, 13,  2],
  [ 3,  2,  8, 12,  4, 13,  2],
  [ 0,  7, 15,  7, 13, 15,  1],
  [ 3,  6,  8, 15,  8, 15,  2],
  [ 1,  7,  4,  7,  1,  8,  0],
  [ 3,  3,  1,  2,  4,  2,  1],
  [ 0,  5,  2,  7,  3,  3,  2],
  [ 0,  6,  2,  1,  2,  2,  1],
  [ 0,  4,  4,  5,  1,  2,  0],
  [ 0,  6,  3,  8,  3,  2,  0],
  [ 0,  1,  2,  3,  2,  1,  0],
  [ 0,  3,  3,  3,  2,  1,  0],
  [ 0,  3,  2,  2,  1,  1,  0],
  [ 0,  3,  1,  2,  2,  3,  0],
  [ 0,  0,  1,  3,  1,  2,  0],
  [ 0,  0,  0,  3,  2,  3,  0],
  [ 0,  0,  2,  0,  2,  1,  0],
  [ 0,  0,  3,  0,  0,  0,  0],
  [ 0,  0,  1,  0,  2,  1,  0],
];

demo.tsxHow it is called: a year of deploys with five real thresholds on the legend and one unsampled day at the end.

import { CalendarHeatmap } from "./CalendarHeatmap";
import { START, WEEKS } from "./deploys";

/**
 * A year of deploys. The data stops on 30 December, so the last day of the
 * year has no sample and draws as an outline rather than as a quiet day.
 */
export default function Demo() {
  return (
    <div className="w-fit rounded-lg border bg-card p-4">
      <CalendarHeatmap
        start={START}
        values={[...WEEKS.flat(), null]}
        thresholds={[1, 4, 9, 16, 31]}
        unit="deploys"
        onSelect={(date, value) => console.log(date, value)}
      />
    </div>
  );
}
What it renders. Identical markup in all three panes, with only the token values changing.

Examples

Screenshots are grouped by product and include the capture date. Dashed boxes highlight this pattern. Notes appear below each screenshot and when you hover over a box.

GitHub

The contribution calendar shows daily activity using a small set of color levels.

Profile / contribution graph September 11, 2026 github.com, signed out (public profile) medium · light · desktop-web
GitHub arranges daily contributions by week and weekday, with a yearly total above the grid. The five color levels make the calendar compact but limit precise comparisons between days. In this active profile, many cells have similar shades, making variation harder to see. The weekday rows still provide a useful way to look for recurring gaps or patterns.
Show 1 more example Hide the rest

Tableau Public

Published workbooks show how individual authors arrange charts and interactions in Tableau.

Emergency Department / Clinical Dashboard September 11, 2026 Tableau Public embed view; emergency department patient flow workbook dense · light · desktop-web
This workbook analyzes emergency-department activity rather than showing a live bed board. Its hour-by-weekday grid makes recurring busy periods easy to locate. Monthly small multiples support seasonal comparison on a shared scale. The color ramps need careful labeling: a diverging scale on a count or duration needs a meaningful center, not an unexplained midpoint.