Skip to content

Commit

Permalink
Charts QA fixes.
Browse files Browse the repository at this point in the history
- Add sort prop
- Chart should have a title and description prop
- Truncated X axis in mixed charts
- Make the charts animate to the new state instead of flicker
- Error display as in old latitude
  • Loading branch information
andresgutgon committed Mar 19, 2024
1 parent ebfe5a1 commit 97dca2f
Show file tree
Hide file tree
Showing 58 changed files with 1,233 additions and 1,126 deletions.
12 changes: 12 additions & 0 deletions .changeset/empty-drinks-push.md
@@ -0,0 +1,12 @@
---
"@latitude-data/svelte": minor
"@latitude-data/client": minor
"@latitude-data/server": minor
---

- Add sort prop to charts
- Add title and description to charts
- Fix truncated label in charts
- Animate chart data changes
- Improve chart error display (will be changed in a future PR)
- Display generic error on charts when a query fails in production
1 change: 1 addition & 0 deletions .nvmrc
@@ -0,0 +1 @@
v18.7.0
6 changes: 4 additions & 2 deletions apps/server/src/lib/errors/handler.ts
@@ -1,9 +1,11 @@
import { NotFoundError } from '.'

export default function handleError(e: Error) {
if (e instanceof NotFoundError) {
const isPro = import.meta.env.PROD
const clientError = isPro ? new Error('There was an error in this query') : e as Error
if (clientError instanceof NotFoundError) {
return new Response(e.message, { status: 404 })
}

return new Response(e.message, { status: 500 })
return new Response(clientError.message, { status: 500 })
}
14 changes: 14 additions & 0 deletions apps/server/src/routes/api/queries/[...query]/server.test.ts
Expand Up @@ -133,4 +133,18 @@ describe('GET endpoint', () => {
expect(response.status).toBe(404)
expect(await response.text()).toBe('Query file not found')
})

it('return generic error when is production', async () => {
import.meta.env.PROD = true
mockRunQuery.mockRejectedValue(new Error('Query execution failed'))

const response = await GET({
params: { query: 'testQuery' },
url: new URL('http://localhost'),
})

expect(response.status).toBe(500)
expect(await response.text()).toBe('There was an error in this query')
})

})
1 change: 1 addition & 0 deletions apps/server/vite.config.ts
@@ -1,5 +1,6 @@
import { sveltekit } from '@sveltejs/kit/vite'
import { defineConfig } from 'vite'

// eslint-disable-next-line
// @ts-ignore
import autoImport from '@latitude-data/sveltekit-autoimport'
Expand Down
217 changes: 217 additions & 0 deletions docs/snippets/charts/common.mdx
@@ -0,0 +1,217 @@
## Properties
To configure and customize the chart, you can add properties, some of which are required and some of which are optional.

<ParamField path="query" type="string" required>
The name of your `.sql` file from which your chart will get the data. It's not necessary to specify the full path, just the name, because we will search all folders until we find it
</ParamField>

<ParamField path="x" type="string | array" required>
Specify a column name to return from your query. This will be the data in the horizontal (x) axis.

[See the section Axis X and Y](#axis-x-and-y-options) to learn more about the options.
</ParamField>

<ParamField path="y" type="string | array" required>
Specify the array of series you want to visualize. Each serie has the column name that your query and other properties.

[See the section Axis X and Y](#axis-x-and-y-options) to learn more about the options.
</ParamField>

<ParamField path="title" type="string">
The title of your chart.
</ParamField>

<ParamField path="description" type="string">
You can add a brief description of your chart
</ParamField>

<ParamField path="order" type="string | object">
Specify the order of the data returned by your query. It can be a string with the column name or an object with the column name and the order.

[See the section order](#order-options) to learn more about the order options
</ParamField>

<ParamField path="xAxisFormat" type="array">
It allows you to customize how the information is displayed in the given axis. It contains several options.

[See the section xAxisFormat](#axis-x-and-y-options) to learn more about the options.
</ParamField>

<ParamField path="yAxisFormat" type="array">
It allows you to customize how the information is displayed in the given axis. It contains several options.

[See the section yAxisFormat](#axis-x-and-y-options) to learn more about the options.
</ParamField>

<ParamField path="animation" type="boolean">
Specifies whether or not to show an animation when the page loads.
</ParamField>

<ParamField path="xTitle" type="string">
A custom name to display as the title of your (x) axis.
</ParamField>

<ParamField path="yTitle" type="string">
A custom name to display as the title of your (y) axis.
</ParamField>

<ParamField path="swapAxis" type="boolean">
Swap the axis orientation. Visually swap the (x) axis with the (y) axis.
</ParamField>

<ParamField path="config" type="array">
Contains some options to customize your chart.

[See the Config section](#config) to learn more about the options.
</ParamField>

### Axis X and Y Options

Both `x` and `y` can contain multiple data series, so instead of specifying just a column name, you need to create a list of series using the following properties:

<ParamField path="name" type="string">
Specify a column name returned by your query.
</ParamField>

<ParamField path="chartType" type="string">
This prop tells the chart how to display the data. The options are:
- `line`
- `bar`
- `area`

`*` If you are using `<BarChart />`, `<LineChart />`, `<AreaChart />` this is not necessary. But if you're
using `<MixedChart />` you can specify `chartType` in each series to display the data in different ways. And if you're using `<ScatterChart />` you don't need to specify `chartType` because it's the only option available.
</ParamField>

<ParamField path="axisIndex" type="string">
Specifies the group within an axis. Imagine 3 series that belong to the left side of the Y-axis, 2 of them need one specific format but the rest need another. axisIndex helps to define different formats for series on the same side of the axis.

The options for this property are numbers: `0`, `1`, `2`...

How this link to axisFormat is by the order of the object in the arra of axisFormat. `1` will be the second object in the list, `0` is the first object in the list...
</ParamField>

Example of syntax for multiple series:

```
y={[
{name: 'column_name'},
{name: 'column_name', axisIndex: '0'},
{name: 'column_name', axisIndex: '1'}
]}
```

#### Pivoted table
If you have a pivoted table where you have multiple columns with names like sum_users, sum_amount, sum_orders, (...) and you need to add all the columns without typing all the names you can use:

- `prefix_` + `*`
- `*` + `suffix`

Example to add all columns starting wiht `sum_`:
```
y={[
{name: 'sum_*'},
]}
```

### Order Options
The order property can be a string with the column name or an object with the column name and the order.

<ParamField path="column" type="string">
The column name to order the data.
</ParamField>

<ParamField path="order" type="string">
The column name to order the data. Options are: `asc` and `desc`
</ParamField>

<ParamField path="incomparable" type="string">
When "numeric" is compared with "non-numeric-string", or either of them is compared with other types of value, they are not comparable. So we call the latter one as "incomparable" and treat it as "min value" or "max value" according to the prop `incomparable`: 'min' | 'max'. This feature usually helps to decide whether to put the empty values (like `null`, `undefined`, `NaN`, `''`, `'-'`) or other illegal values to the head or tail.
</ParamField>

<ParamField path="parser" type="string">
If intending to sort time values (JS Date instance or time string like `2012-03-12 11:13:54`), parser: `time` should be specified.
If intending to sort values with unit suffix (like `'33%'`, `'16px'`), need to use parser: `number`.
</ParamField>

Example of syntax for multiple column order:

```
order={[
{name: 'column_a', order: 'asc'},
{name: 'column_b', order: 'desc', incomparable: 'min', parser: 'time' },
]}
```

### Axis Format

Example of different axis format. The order of the array will determine the axisIndex where `0` = the first format in the list.

```
yAxisFormat={[
{type: 'value', stack: 'true'},
{type: 'category', stack: 'false'},
{type: 'value', stack: 'false;}
]}
```
<ParamField path="type" type="string">
The format of the data displayed in the axis. The options are:
- `category`
- `value`
- `time`
- `log`
</ParamField>

<ParamField path="stack" type="boolean">
Display the data series of the given axis on top of each other, visualizing cumulative totals or comparisons over time.
</ParamField>

<ParamField path="showAxis" type="boolean">
Display the axis info (labels, numbers...) in the chart or not.
</ParamField>

<ParamField path="rotate" type="number">
Allow to display the axis values with a tilt to avoid overlapping between them.
</ParamField>

<ParamField path="displayName" type="string | null">
The axis title to display.
</ParamField>

<ParamField path="showAxisTitle" type="boolean">
Whether or not to show the title of the axis.
</ParamField>

<ParamField path="showSplitLine" type="boolean">
Specifies whether or not to show the value indicator with a split line.
</ParamField>

<ParamField path="axisAlign" type="boolean">
Specifies the side of the axis
- `start`: in axis (x) means left and for (y) axis means top.
- `end`: in axis (x) means right and for (y) axis means bottom.
</ParamField>

### Config
Allows you to add more configuration and customize your chart.

<ParamField path="showDots" type="boolean">
Show a dot or not at the intersection of the values.
</ParamField>

<ParamField path="showZoom" type="boolean">
Display a zoom control for the displayed data.
</ParamField>

<ParamField path="showValues" type="boolean">
Display the values directly on the chart.
</ParamField>

<ParamField path="showLegend" type="boolean">
Display the color legend for each series displayed.
</ParamField>

<ParamField path="showDecal" type="boolean">
Add a visual pattern to each series to help colorblind people distinguish them.
</ParamField>

29 changes: 13 additions & 16 deletions docs/visualizations/others/funnel-chart.mdx
Expand Up @@ -9,24 +9,21 @@ The Funnel chart visualizes sequential stages in a process, showing decreasing q
## Preparation
The query `.sql` file that the Funnel chart accepts must contain only 2 columns, one for the labels and another one for the values.

| labels | values |
| ----------- | -------- |
| Pending | 245 |
| In Progress | 120 |
| Closed | 32 |

| values | labels |
| -------- | ----------- |
| 245 | Pending |
| 120 | In Progress |
| 32 | Closed |

## Syntax
You can use `<FunnelChart ... />` to add it to your view. Within the tag you must add the properties to configure the chart.

``` js
<FunnelChart
query='orders_evolution'
config={{
sort: descending,
showColorGradient: false,
showLabels: true
}}
sort='descending'
showColorGradient={false}
showLabels={true}
/>
```

Expand All @@ -37,13 +34,13 @@ To configure and customize the chart, you can add properties, some of which are
The name of your `.sql` file from which your chart will get the data. It's not necessary to specify the full path, just the name, because we will search all folders until we find it
</ParamField>

<ParamField path="config" type="array">
Contains some options to customize your chart.

[See the Config section](#config) to learn more about the options.
<ParamField path="sort" type="string" required>
The order in which the data will be displayed. It can be `ascending` or `descending`. Default `descending`.
</ParamField>

### Config
<ParamField path="orientation" type="string" required>
The orientation of the chart. It can be `vertical` or `horizontal`. Default `vertical`.
</ParamField>

<ParamField path="showColorGradient" type="boolean">
Whether the color of each layer is a gradient or whether each layer is a different color.
Expand Down

0 comments on commit 97dca2f

Please sign in to comment.