propeldata/ui-kit

[RFC] Pie chart support for Leaderboard

Closed this issue · 0 comments

Summary

The UI Kit should provide a pie chart component.

What's the problem?

While developers can create pie charts using custom components and Query Hooks, there are still details they must work through:

  • What query or queries should be used to fetch the data?
  • How should the component be themed?

Pie charts are so common that we should offer a first-class implementation of them, so that developers don't have to set up custom components or make these decisions — they can just get to visualizing.

What are the requirements?

  • The pie chart will (at least initially) support a single dimension per segment.
  • The pie chart will allow visualizing N segments.
  • The pie chart will show an N+1-th segment with a configurable label for all other dimensions (for example, "Other").

Detailed design

How do we query the data?

The most important part of the design is "how do we query the data?" Propel's GraphQL API does not (yet) offer a pie chart API, but what would we expect from one? Probably it would look very similar to a Leaderboard query, but it would also support fetching a "total". By subtracting the N segments from the total, we can determine the N+1-th segment containing all other values.

For example, imagine we have a data set with

  • 100 values labeled "A".
  • 50 values labeled "B".
  • 50 values labeled "C", "D", or "E".

Then, the total is 200. If we run the queries below asking for two segments, we'd expect the following responses.

Note that we pass filters1 and filters2. filters2 must include all of filters1, but it must also exclude entries with dimension values matching the N segments. For example, if filters1 is empty, filters2 must be equivalent to

dimension != 'A' AND dimension != 'B'
GraphQL Queries JSON Response
query PieChart1(
  $metric: MetricInput!
  $timeRange: TimeRangeInput!
  $timeZone: String
  $dimension: String!
  $sort: Sort
  $segments: Int!
  $filters1: [FilterInput!]
) {
  leaderboard(input: {
    metric: $metric
    timeRange: $timeRange
    timeZone: $timeZone
    dimensions: [{
      columnName: $dimension
    }]
    sort: $sort
    rowLimit: $segments
    filters: $filters1
  }) {
    rows
  }
}
query PieChart2(
  $metric: MetricInput!
  $timeRange: TimeRangeInput!
  $timeZone: String
  $filters2: [FilterInput!]
) {
  counter(input: {
    metric: $metric
    timeRange: $timeRange
    timeZone: $timeZone
    filters: $filters2
  }) {
    value
  }
}
{
  "data": {
    "leaderboard": {
      "rows": [
        ["A", "100"],
        ["B", "50"]
      ]
    }
  }
}
{
  "data": {
    "counter": {
      "value": "200"
    }
  }
}

In the UI Kit, we could determine that the N+1-th segment should be proportional to 200 - 100 - 50 = 50 in the resulting pie chart.

Rejected query idea
GraphQL Query JSON Response
query PieChart(
  $metric: MetricInput!
  $timeRange: TimeRangeInput!
  $timeZone: String
  $dimension: String!
  $sort: Sort
  $segments: Int!
  $filters: [FilterInput!]
) {

  leaderboard(input: {
    metric: $metric
    timeRange: $timeRange
    timeZone: $timeZone
    dimensions: [{
      columnName: $dimension
    }]
    sort: $sort
    rowLimit: $segments
    filters: $filters
  }) {
    rows
  }

  counter(input: {
    metric: $metric
    timeRange: $timeRange
    timeZone: $timeZone
    filters: $filters
  }) {
    value
  }
}
{
  "data": {
    "leaderboard": {
      "rows": [
        ["A", "100"],
        ["B", "50"]
      ]
    },
    "counter": {
      "value": "200"
    }
  }
}

This seems to work for COUNT metrics. Does it work for SUM metrics? It seems like the "correct" way to handle SUM metrics is to actually issue a subsequent counter query that explicitly filters out the top N segments.

Theming and styling

Here is a screenshot from a recent Figma:

image

There should be props for

  • Switching between "pie" and "doughnut" styles (this is really about the diameter of the inner "hole", if any).
  • Whether to show a total in the middle of the chart, and whether to include a label.
  • Whether to show a total above the chart, and whether to include a label.
  • What style of table to show below the chart, if any.
  • Including/excluding the legend using existing Chart.js props.

Additionally, there should be callbacks for interactivity with the segments (for example, "onhover", etc.).

Drawbacks

  • The pie chart component would ideally use a dedicated pie chart API that Propel's GraphQL API offer. Because Propel's GraphQL API does not (yet) offer this, we instead simulate it in the frontend, which leads to more code. If Propel's GraphQL API gains a pie chart API, we can eventually delete the frontend code which simulates it.

Alternatives

Developers can continue to create pie charts using custom components and Query Hooks.

Adoption strategy

Pie charts will be a new component, and so they can be added in a minor version. They do not represent a breaking change.

Unresolved questions

  • Is the table below the pie chart just an embedded leaderboard?
  • Review the Figma. For example, what happens when you hover and/or select a segment?
  • Review the query. @markandrus thinks we may need to issue two queries, rather than one.
  • Should we allow including/excluding the "Other" dimension based on a prop? Or should we always include it?