Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@
- `sqlpage.fetch_with_meta` now correctly documents server JSON responses sent under `json_body`, not `body`.
- Datagrid rows with an icon or image no longer display an unnecessary en-dash placeholder, and an explicitly empty description remains empty.
- Tooltip title text is now inhertis the same colour as the tooltip text.
- Charts can display reference lines. A row with a `yline` is drawn as a line across the chart at that value of the y axis, with the row's `label` and `color` for its text and its color. Reference lines are rows, so a chart can have as many of them as the query returns. A line follows its axis, so on a `horizontal` bar chart a `yline` is drawn down the chart rather than across it. They are not added to the total of a `stacked` chart, and are not filled in an `area` chart.
- Charts can display reference lines. A row with a `yline` is drawn as a line across the chart at that value of the y axis, and a row with `xline` marks a position on the x axis. `label` and `color` set the line's text and its color. Reference lines are rows, so a chart can have as many of them as the query returns. A line follows its axis, so on a `horizontal` bar chart a `yline` is drawn down the chart rather than across it. They are not added to the total of a `stacked` chart, and are not filled in an `area` chart.
- Charts can display reference lines. A row with a `yline` is drawn as a line across the chart at that value of the y axis, and a row with an `xline` marks a position on the x axis. Adding `yline_end` or `xline_end` makes a line a band, and the row's `label` and `color` set its text and its color. Reference lines are rows, so a chart can have as many of them as the query returns. Each one follows its own axis, so on a `horizontal` bar chart a `yline` is drawn down the chart rather than across it. They are not added to the total of a `stacked` chart, and are not filled in an `area` chart.

## v0.45

Expand Down
18 changes: 11 additions & 7 deletions examples/official-site/sqlpage/migrations/01_documentation.sql
Original file line number Diff line number Diff line change
Expand Up @@ -689,7 +689,9 @@ INSERT INTO parameter(component, name, description, type, top_level, optional) S
('value', 'An alias for parameter "y"', 'REAL', FALSE, TRUE),
('series', 'If multiple series are represented and share the same y-axis, this parameter can be used to distinguish between them.', 'TEXT', FALSE, TRUE),
('yline', 'Draws a reference line across the chart at this value of the y axis instead of plotting a point, to show a limit such as a quota or an alarm threshold. Not drawn if it falls outside of the axis, so set ymax when the limit is above the data.', 'REAL', FALSE, TRUE),
('yline_end', 'Makes the yline a band instead of a line, reaching to this value.', 'REAL', FALSE, TRUE),
('xline', 'Draws a reference line across the chart at this position of the x axis instead of plotting a point, to mark an event such as a deployment. A date or a timestamp when time is set, otherwise one of the x values.', 'TEXT', FALSE, TRUE),
('xline_end', 'Makes the xline a band instead of a line, reaching to this value.', 'TEXT', FALSE, TRUE),
('color', 'The name of a color for the reference line this row draws. Grey by default.', 'COLOR', FALSE, TRUE)
) x;
INSERT INTO example(component, description, properties) VALUES
Expand Down Expand Up @@ -800,7 +802,7 @@ The `color` property sets the color of each series separately, in order.
A row with a `yline` is not plotted as a data point, but drawn as a line across
the whole chart, at that value of the y axis. Use it for the limit that the data
should be read against: a disk quota, an alarm threshold, a service level
objective.
objective. Add `yline_end` to make it a band instead of a line.

Reference lines are rows, so they come from a query like everything else,
and a chart can have as many of them as the query returns:
Expand All @@ -820,7 +822,7 @@ so set `ymax` when the limit is above the data.
{"component":"chart", "title": "CPU temperature", "type": "line", "time": true,
"ytitle": "°C", "ymax": 100, "color": "azure", "marker": 4},
{"yline": 70, "label": "target", "color": "green"},
{"yline": 90, "label": "throttling", "color": "red"},
{"yline": 90, "yline_end": 100, "label": "throttling", "color": "red"},
{"x": "2024-05-01T08:00:00Z", "y": 52},
{"x": "2024-05-01T09:00:00Z", "y": 58},
{"x": "2024-05-01T10:00:00Z", "y": 71},
Expand All @@ -833,13 +835,14 @@ so set `ymax` when the limit is above the data.
## Marking events

`xline` is the counterpart of `yline`: it marks a position on the x axis instead
of a value on the y axis, for a moment rather than a limit. A single query can
draw a whole log of them:
of a value on the y axis. On its own it marks a moment, like a deployment.
With `xline_end`, it covers everything in between, like an incident or a
maintenance window. A single query can draw a whole log of them:

```sql
select started_at as xline, summary as label,
select started_at as xline, ended_at as xline_end, summary as label,
case severity when ''outage'' then ''red'' else ''orange'' end as color
from deployments where started_at > $since;
from incidents where started_at > $since;
```

When `time` is set, an `xline` is a date or a timestamp, written like the `x` of
Expand All @@ -848,7 +851,8 @@ a data point. On a chart with text labels on the x axis, it is one of those labe
{"component":"chart", "title": "Request latency", "type": "area", "time": true,
"ytitle": "ms", "color": "blue-lt", "marker": 3},
{"xline": "2024-05-01T10:00:00Z", "label": "deploy", "color": "green"},
{"xline": "2024-05-01T11:30:00Z", "label": "incident", "color": "red"},
{"xline": "2024-05-01T11:30:00Z", "xline_end": "2024-05-01T13:00:00Z",
"label": "incident", "color": "red"},
{"x": "2024-05-01T08:00:00Z", "y": 120},
{"x": "2024-05-01T09:00:00Z", "y": 134},
{"x": "2024-05-01T10:00:00Z", "y": 128},
Expand Down
12 changes: 8 additions & 4 deletions sqlpage/apexcharts.js
Original file line number Diff line number Diff line change
Expand Up @@ -134,15 +134,19 @@ sqlpage_chart = (() => {
* @returns {object[]} apexcharts axis annotations
*/
function reference_lines(rows, column, axis, to_axis_value) {
const on_axis = (value) => {
if (value == null) return null;
const placed = to_axis_value(value);
return Number.isNaN(placed) ? null : placed;
};
return rows.flatMap((row) => {
const value = row[`${column}line`];
if (value == null) return [];
const from = to_axis_value(value);
if (Number.isNaN(from)) return [];
const from = on_axis(row[`${column}line`]);
if (from == null) return [];
const color = reference_color(row.color);
return [
{
[axis]: from,
[`${axis}2`]: on_axis(row[`${column}line_end`]),
borderColor: color,
fillColor: color,
strokeDashArray: 4,
Expand Down
4 changes: 2 additions & 2 deletions sqlpage/templates/chart.handlebars
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@
{{~#if (gt @row_index 0)}},{{/if~}}
{{~#if (or xline yline)~}}
{
"xline": {{~stringify xline}},
"yline": {{~stringify yline}},
"xline": {{~stringify xline}}, "xline_end": {{~stringify xline_end}},
"yline": {{~stringify yline}}, "yline_end": {{~stringify yline_end}},
"label": {{~stringify label}}, "color": {{~stringify color}}
}
{{~else~}}
Expand Down
18 changes: 14 additions & 4 deletions tests/end-to-end/official-site.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,9 @@ test("stacked chart raises a series only where it has a value", async ({
expect(Number(gpu[1].y)).toBeLessThan(Number(cpu[1].y));
});

test("chart draws a reference line for every yline", async ({ page }) => {
test("chart draws a yline as a line and a yline_end as a band", async ({
page,
}) => {
await page.goto(`${BASE}/documentation.sql?component=chart#component`);

const temperature = page.locator(".card", {
Expand All @@ -85,13 +87,18 @@ test("chart draws a reference line for every yline", async ({ page }) => {
await expect(temperature.locator(".apexcharts-canvas")).toBeVisible();

const annotations = temperature.locator(".apexcharts-yaxis-annotations");
const lines = annotations.locator("line");
const bands = annotations.locator(".apexcharts-annotation-rect");

await expect(annotations.locator("line")).toHaveCount(2);
await expect(lines).toHaveCount(1);
await expect(bands).toHaveCount(1);
await expect(annotations.getByText("target")).toBeVisible();
await expect(annotations.getByText("throttling")).toBeVisible();
});

test("chart draws a reference line for every xline", async ({ page }) => {
test("chart draws an xline as a line and an xline_end as a band", async ({
page,
}) => {
await page.goto(`${BASE}/documentation.sql?component=chart#component`);

const latency = page.locator(".card", {
Expand All @@ -100,8 +107,11 @@ test("chart draws a reference line for every xline", async ({ page }) => {
await expect(latency.locator(".apexcharts-canvas")).toBeVisible();

const annotations = latency.locator(".apexcharts-xaxis-annotations");
const lines = annotations.locator("line");
const bands = annotations.locator(".apexcharts-annotation-rect");

await expect(annotations.locator("line")).toHaveCount(2);
await expect(lines).toHaveCount(1);
await expect(bands).toHaveCount(1);
await expect(annotations.getByText("deploy")).toBeVisible();
await expect(annotations.getByText("incident")).toBeVisible();
});
Expand Down
Loading