evidence-dev / evidence

Business intelligence as code: build fast, interactive data visualizations in pure SQL and markdown
https://evidence.dev
MIT License
3.44k stars 167 forks source link

Native XmR Charts #1950

Open mcrascal opened 2 weeks ago

mcrascal commented 2 weeks ago

Feature Description

Add support for XmR charts

Goal of Feature

One line invocation of the XmR chart type

Current Solution / Workarounds

@matsonj has an implementation as a custom component

Alternatives

Be unable to tell the difference between routine and exceptional variation in a time series.

matsonj commented 2 weeks ago

Would it be helpful to add code snippets of how I am using the <chart> component today to accomplish this over on https://twitter.evidence.app/tests/ ?

mcrascal commented 2 weeks ago

@matsonj for sure

matsonj commented 2 weeks ago

Alright, consider a dataset with two columns, x & value, called “my_data”, and ordered by x.

We first need to calculate some metrics on it.

Average

    from ${my_data}
    select avg(value) as avg_num1

Moving Range

    from ${my_data}
    select x, value, lag(value, 1) over (order by x) as lag_value, abs(value - lag(value, 1) over (order by x)) as diff

Avg Moving Range

    from ${moving_range}
    select avg(diff) as avg_diff,
        stddev(diff) as std_dev_diff

Next set some values for in js for use in the charts

<script>

  $: var_avg = average[0].avg_num1;

  $: var_diff = avg_moving_range[0].avg_diffl;

</script>

Finally we can build the chart.

<LineChart
      title=“My Data - X Plot"
      data={my_data}
      chartAreaHeight=150
      x=x
      y=value
      yMin={(parseFloat(var_diff)*-2.66+var_avg)*1.2}
      colorPalette={
        [
        '#010203'] }
      yGridlines=false
      xBaseline=false
      markers=true
      markerShape=circle
      markerSize=7
      labels=true>
      <ReferenceLine 
        y={parseFloat(var_avg)} 
        hideValue=true
        lineWidth=1
        lineColor=#FF0000 />
      <ReferenceLine 
        y={parseFloat(var_diff)*2.66+var_avg}
        hideValue=true
        lineWidth=1
        lineColor=#4682b4 />
      <ReferenceLine 
        y={parseFloat(var_diff)*-2.66+var_avg}
        hideValue=true
        lineWidth=1
        lineColor=#4682b4 />
    </LineChart>
    <LineChart
      title="My Data - MR Plot"
      data={moving_range}
      chartAreaHeight=75
      x=x
      y=diff
      colorPalette={
        [
        '#010203'] }
      yGridlines=false
      xBaseline=false
      markers=true
      markerShape=circle
      markerSize=7
      labels=true>
      <ReferenceLine 
        y={parseFloat(var_diff)} 
        hideValue=true
        lineWidth=1
        lineColor=#FF0000 />
      <ReferenceLine 
        y={parseFloat(var_diff)*2.66+var_diff}
        hideValue=true
        lineWidth=1
        lineColor=#4682b4 />
    </LineChart>

Obviously, some of the aesthetic choices here are mine and I don’t really care on durability of them (i.e. marker size, chart height). There are a few bits not yet implemented here as well.

matsonj commented 2 weeks ago

I think ideally, this could all be simplified into something like this:

<XmrChart
  data={my_data}
  x=x
  y=value
  dividers={some_array}
  controlLines={another_array} />

The annoying part is honestly doing all the math in sql/js, so bundling the calculations in the component is the key unlock. Additionally, supporting divider lines means that the ReferenceLine prop won’t work, since they must start & end at each divider.