Calendar heatmap
Telemetry as a grid of days: one cell per calendar day, colored by that day’s value. Switch between week, month and year, and scroll back through earlier periods. The widget drives its own time window and always requests a one-day aggregation interval, so the platform reduces each day server-side and the cell shows exactly that aggregate. Days with no telemetry read as no data rather than as zero, and days still to come are drawn as not yet. Clicking a day hands its bounds to a widget action.
Who it’s for
Anyone trying to answer “which days were unusual, and is there a weekly or seasonal pattern here?” for a single telemetry key. A line chart compresses weeks of readings into one crowded axis; a calendar of shaded days makes the weekly rhythm, the seasonal drift, and the days a device went quiet all visible at once, the way a real calendar makes a pattern of appointments visible.
What it does
A daily energy key that dips every weekend and drifts upward over a season shows as a grid of days shaded from pale to deep green. The weekly dip reads as a faint stripe every sixth and seventh column, and the seasonal rise reads as the whole grid gradually darkening across the months — both patterns a 90-day line chart would show only as noise.
- Three periods in one widget — week as a row of days, month as a wall calendar, year as a contribution-style grid.
- Steps back through history — the arrows move one period at a time, up to 40 periods back, and the widget always reopens on the current period.
- Drives its own time window, always at a one-day aggregation interval, so the platform reduces each day on the server rather than in the browser.
- Three visual states beyond a value — a day with no telemetry reads as no data rather than as zero, a day still to come reads as not yet, and today gets its own outline while it’s still accumulating.
- Click a day to drill down — hands its exact start and end to a widget action.
- No external libraries — the grid is SVG built by the widget itself, so it works on installations with no internet access.
- The color scale isn’t anchored at zero by default — it fits whatever range the shown period actually has, which keeps a quiet week from flattening into a single color, but also means colors aren’t comparable between two periods unless you fix the scale yourself.
How to set up
Data keys
One datasource, one timeseries key.
| Key | Role | Type | Description |
|---|---|---|---|
| any timeseries key | The value bucketed into its calendar day | Timeseries | Numeric values, and numeric strings that parse as numbers, are accepted; anything else counts as no reading. Units and decimals come from the key, falling back to the widget’s own. |
Day value
What a cell actually shows depends on the widget’s own time window aggregation, not on a setting here:
| Aggregation | A cell shows | Footer reads |
|---|---|---|
| Sum | the day’s total | ”Sum per day” |
| Average | the day’s mean | ”Average per day” |
| Minimum / Maximum | the day’s extreme | ”Daily minimum” / “Daily maximum” |
| Count | how many raw readings arrived | ”Readings per day” |
| None | raw readings reduced in the browser using “How to combine a day’s readings” | that setting’s own label |
“How to combine a day’s readings” (sum, average, minimum, maximum, last value of the day, or number of readings) only takes effect when the aggregation above is set to None. With any other aggregation, the platform has already reduced each day, and this setting is ignored — set the aggregation type itself rather than this label, since a setting that disagreed with the platform’s own reduction would only mislabel the number.
How to customize
Period
- Which period opens first — Period shown when the widget loads.
- Let people switch between week, month and year — the back and forward arrows stay available either way.
- Which day starts the week — First day of the week.
Cell colors
- Take the ramp from the data key’s own color, or set the two ends yourself with Color of the highest level and Color of the lowest level.
- How many discrete color levels — Number of color levels.
- No-data and not-yet colors — Color of days with no readings, Color of days that have not happened yet.
- Fit the scale to what’s shown, or fix it — Color scale: automatic (not comparable between periods) or a fixed Scale minimum and Scale maximum (comparable).
Grid and labels
- Space between day cells — Gap between days.
- Which labels appear — month or weekday names at the top, the weekday column in the year view, day numbers in the week and month views.
- Label and day-number fonts and colors — sizes are treated as a ceiling; text shrinks on small cells rather than overlapping.
Label formats
- How weekday and month names are written — Weekday label, Month label; both shorten further on their own when a cell is too narrow for the chosen form.
Legend
- Show the color legend, and the line explaining it — Show the color legend, Show what the colors mean.
- Its font and color.
Tooltip
- Its background, text color and font.
- The date format shown in the tooltip.
Period selector
- The accent color for the selected period tab and today’s outline — defaults to the platform’s own theme color, and is ignored when the cell color comes from the data key.
- Its font and text color.
Interaction
- Whether clicking a day does anything — does nothing, or triggers the “Day click” widget action.
Tips
- Leave “Use dashboard timewindow” off, as shipped — the widget computes its own period and pushes that window down on its own, and two time-window pickers competing over the same subscription is the one setup that won’t work.
- Days are bucketed at midnight in the browser’s local timezone, and the window sent to the platform is aligned to those same midnights. Viewing the same dashboard from another timezone can shift a reading into the adjacent cell.
- Wire the “Day click” action to a dashboard state’s time window, using its
dayStartTsanddayEndTsparameters, for a one-click drill-down into that day;value,readingsandperiodare also passed along. Days in the future aren’t clickable. - Cells read best from about a 6×5 grid of widget units for the week and month views, and about 12×3 for the year view.
Share Your Widget with the Community
Built a custom widget? Export it as a JSON from ThingsBoard and publish it to the IoT Hub through a simple 4-step wizard (Upload, Listing, Readme, Review & Submit). Share it with thousands of ThingsBoard developers worldwide and get featured in the catalog.