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

Table Groups & Standalone Delta Component #1761

Closed hughess closed 1 month ago

hughess commented 2 months ago

Table Groups

Adds groups to DataTable. Groups can either be accordion or section. For now, this is limited to one level of groups, but will be expanded to allow nested groups in future versions.

subtotals are generated using the supplied groups from the groupBy prop and can be configured in the same way as the total row - using the totalAgg prop within each Column

Accordion

<DataTable data={orders} groupBy=category subtotals=true totalRow=true> 
    <Column id=state totalAgg=countDistinct totalFmt='0 "states"'/> 
    <Column id=category totalAgg=Total/> 
    <Column id=item  totalAgg=countDistinct totalFmt='0 "items"'/> 
    <Column id=orders contentType=colorscale/> 
    <Column id=sales fmt=usd0k/> 
    <Column id=growth contentType=delta fmt=pct totalAgg=weightedMean weightCol=sales/> 
</DataTable>

tbl-accordion-configured

Section

<DataTable data={orders} groupBy=category groupType=section subtotals=true totalRow=true totalRowColor=#fff0cc> 
    <Column id=state totalAgg=countDistinct totalFmt='[=1]0 "state";0 "states"'/> 
    <Column id=category totalAgg=Total/> 
    <Column id=item  totalAgg=countDistinct totalFmt='0 "items"'/> 
    <Column id=orders contentType=colorscale/> 
    <Column id=sales fmt=usd1k/> 
    <Column id=growth contentType=delta neutralMin=-0.02 neutralMax=0.02 fmt=pct1 totalAgg=weightedMean weightCol=sales /> 
</DataTable>

tbl-section-configured

Standalone Delta Component

This PR also adds a standalone Delta component which can be used in the same way the Value component is used.

<Delta data={sales} column=growth fmt=pct1 />

delta-pos

Symbol Position

symbolPosition (right is default, see left below):

<Delta data={sales} column=growth fmt=pct1 symbolPosition=left/>

delta-left

Chip

chip=true formats the Delta with a background and border:

<Delta data={sales} column=growth fmt=pct1 chip=true />

delta-chip-pos delta-chip-neg delta-chip-neut

Neutral Range

Inspired by this Twitter thread: https://twitter.com/archieemwood/status/1762286734845653103 Allows you to set a range for neutral values using neutralMin and neutralMax. Values appear in grey with a dash instead of an arrow:

<Delta data={sales} column=growth fmt=pct1 neutralMin=-0.4 neutralMax=0.4 />

delta-neut

Checklist

changeset-bot[bot] commented 2 months ago

🦋 Changeset detected

Latest commit: 993c60a448bf64488a0b7201661a5ede485ed09f

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 4 packages | Name | Type | | ----------------------------- | ----- | | @evidence-dev/core-components | Patch | | @evidence-dev/evidence | Patch | | @evidence-dev/components | Patch | | evidence-test-environment | Patch |

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

vercel[bot] commented 2 months ago

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
docs ✅ Ready (Inspect) Visit Preview 💬 Add feedback Mar 28, 2024 2:54am
netlify[bot] commented 2 months ago

Deploy Preview for evidence-development-workspace ready!

Name Link
Latest commit 993c60a448bf64488a0b7201661a5ede485ed09f
Latest deploy log https://app.netlify.com/sites/evidence-development-workspace/deploys/6604dbb38661df0008db42ae
Deploy Preview https://deploy-preview-1761--evidence-development-workspace.netlify.app
Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

hughess commented 2 months ago

@ItsMeBrianD @csjh I've refactored quite a lot of this into smaller components and ripped out as much CSS as I could. There's still duplication in a few places, but I think when we USQL-ify this component we'll have a good opportunity to decide what the right long-term structure should be.

Some challenges I ran into:

netlify[bot] commented 1 month ago

Deploy Preview for evidence-docs failed. Why did it fail? →

Name Link
Latest commit 4b12eef2ca28dca3052e299703820b9746e307d9
Latest deploy log https://app.netlify.com/sites/evidence-docs/deploys/65fb5eb6fa95430008dfe255
hughess commented 1 month ago

Paused this due to some performance issues showing up when putting a large query (>100k rows) into DataTable.

Initially thought this was due to the new component structure (having a TableCell for every td). I think that does have a negative impact, but the bulk of the issue is caused by this block for the Fullscreen feature.

When this is included, in combo with the TableCell component, it generates a TableCell for every cell in the query (which in my test query was 1.5 million cells). When this code is removed, TableCells are only generated for the visible cells in the table (150 in my test query):

{#if !isFullPage}
    <Fullscreen bind:open={fullscreen}>
        <!-- header and last row are 22.5+22.5 = 45px, middle rows are 23 -->
        {@const ROW_HEIGHT = 23}
        {@const Y_AXIS_PADDING = 45 + 234}
        <div class="pl-8 pt-4">
            <svelte:self
                {...$$props}
                rows={1 + Math.round((innerHeight - Y_AXIS_PADDING) / ROW_HEIGHT)}
                isFullPage
            >
                {#each $props.columns as column}
                    <Column {...column} />
                {/each}
            </svelte:self>
        </div>
    </Fullscreen>
{/if}
hughess commented 1 month ago

@csjh in the code snippet above, what's the purpose of the isFullPage variable? Should that be replaced with fullscreen?

csjh commented 1 month ago

No, isFullPage indicates whether or not the current DataTable is a full page DataTable (i.e. an instance of the svelte:self one)

csjh commented 1 month ago

It shouldn't work any different than

<DataTable rows={some_number}>
  <Column {...some_column_props} />
</DataTable>

which is why I'm confused how it would suddenly generate a million TableCells (though some_number is higher so some_number would be higher than usual)

hughess commented 1 month ago

Ah got it, so maybe it should be {#if !isFullPage && fullscreen}?

csjh commented 1 month ago

I don't think so, that would slow down the modal opening quite a bit

How were you testing how many times it rendered? A global variable?

hughess commented 1 month ago

I just put a console log in the TableCell component.

I got 1.5M logs on page load, then a pause, then 150 logs. Then when clicking full screen I got 450 logs

after commenting out that section I got 150 logs on page load

csjh commented 1 month ago

Hmm OK, it's probably the DataTable accidentally being run recursively somehow, thanks

csjh commented 1 month ago

Ahh this was funny, it was because during SSR and initial render the innerHeight in rows={1 + Math.round((innerHeight - Y_AXIS_PADDING) / ROW_HEIGHT)} was undefined, which caused it to be rows={NaN}, which caused every row to be rendered very unnecessarily

hughess commented 1 month ago

Oh wow, nice find!

netlify[bot] commented 1 month ago

Deploy Preview for evidence-test-env failed. Why did it fail? →

Name Link
Latest commit cd4d3b68002ed5f807ff9998a4b1f5055281a4be
Latest deploy log https://app.netlify.com/sites/evidence-test-env/deploys/6604b6f3633f9700087ec397