feat: implement new Data interface + review PlotlyBarChart API and docs + hide BucketViewer and OpenLayers
This commit is contained in:
parent
3aac4dabf9
commit
88f6199d18
@ -1,7 +1,8 @@
|
||||
import { QueryClient, QueryClientProvider, useQuery } from "react-query";
|
||||
import { Plotly } from "./Plotly";
|
||||
import Papa, { ParseConfig } from "papaparse";
|
||||
import LoadingSpinner from "./LoadingSpinner";
|
||||
import { QueryClient, QueryClientProvider, useQuery } from 'react-query';
|
||||
import { Plotly } from './Plotly';
|
||||
import Papa, { ParseConfig } from 'papaparse';
|
||||
import LoadingSpinner from './LoadingSpinner';
|
||||
import { Data } from '../types/properties';
|
||||
|
||||
const queryClient = new QueryClient();
|
||||
|
||||
@ -17,7 +18,7 @@ async function getCsv(url: string, bytes: number) {
|
||||
|
||||
async function parseCsv(
|
||||
file: string,
|
||||
parsingConfig: ParseConfig,
|
||||
parsingConfig: ParseConfig
|
||||
): Promise<any> {
|
||||
return new Promise((resolve, reject) => {
|
||||
Papa.parse(file, {
|
||||
@ -39,43 +40,40 @@ async function parseCsv(
|
||||
}
|
||||
|
||||
export interface PlotlyBarChartProps {
|
||||
url?: string;
|
||||
data?: { [key: string]: number | string }[];
|
||||
rawCsv?: string;
|
||||
randomId?: number;
|
||||
data: Data;
|
||||
uniqueId?: number;
|
||||
bytes?: number;
|
||||
parsingConfig?: ParseConfig;
|
||||
xAxis: string;
|
||||
yAxis: string;
|
||||
lineLabel?: string;
|
||||
// TODO: commented out because this doesn't work. I believe
|
||||
// this would only make any difference on charts with multiple
|
||||
// traces.
|
||||
// lineLabel?: string;
|
||||
title?: string;
|
||||
}
|
||||
|
||||
export const PlotlyBarChart: React.FC<PlotlyBarChartProps> = ({
|
||||
url,
|
||||
data,
|
||||
rawCsv,
|
||||
bytes = 5132288,
|
||||
parsingConfig = {},
|
||||
xAxis,
|
||||
yAxis,
|
||||
lineLabel,
|
||||
title = "",
|
||||
// lineLabel,
|
||||
title = '',
|
||||
}) => {
|
||||
const randomId = Math.random();
|
||||
const uniqueId = Math.random();
|
||||
return (
|
||||
// Provide the client to your App
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<PlotlyBarChartInner
|
||||
url={url}
|
||||
data={data}
|
||||
rawCsv={rawCsv}
|
||||
randomId={randomId}
|
||||
uniqueId={uniqueId}
|
||||
bytes={bytes}
|
||||
parsingConfig={parsingConfig}
|
||||
xAxis={xAxis}
|
||||
yAxis={yAxis}
|
||||
lineLabel={lineLabel ?? yAxis}
|
||||
// lineLabel={lineLabel ?? yAxis}
|
||||
title={title}
|
||||
/>
|
||||
</QueryClientProvider>
|
||||
@ -83,30 +81,28 @@ export const PlotlyBarChart: React.FC<PlotlyBarChartProps> = ({
|
||||
};
|
||||
|
||||
const PlotlyBarChartInner: React.FC<PlotlyBarChartProps> = ({
|
||||
url,
|
||||
data,
|
||||
rawCsv,
|
||||
randomId,
|
||||
uniqueId,
|
||||
bytes,
|
||||
parsingConfig,
|
||||
xAxis,
|
||||
yAxis,
|
||||
lineLabel,
|
||||
// lineLabel,
|
||||
title,
|
||||
}) => {
|
||||
if (data) {
|
||||
if (data.values) {
|
||||
return (
|
||||
<div className="w-full" style={{ height: "500px" }}>
|
||||
<div className="w-full" style={{ height: '500px' }}>
|
||||
<Plotly
|
||||
layout={{
|
||||
title,
|
||||
}}
|
||||
data={[
|
||||
{
|
||||
x: data.map((d) => d[xAxis]),
|
||||
y: data.map((d) => d[yAxis]),
|
||||
type: "bar",
|
||||
name: lineLabel,
|
||||
x: data.values.map((d) => d[xAxis]),
|
||||
y: data.values.map((d) => d[yAxis]),
|
||||
type: 'bar',
|
||||
// name: lineLabel,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
@ -114,18 +110,18 @@ const PlotlyBarChartInner: React.FC<PlotlyBarChartProps> = ({
|
||||
);
|
||||
}
|
||||
const { data: csvString, isLoading: isDownloadingCSV } = useQuery(
|
||||
["dataCsv", url, randomId],
|
||||
() => getCsv(url as string, bytes ?? 5132288),
|
||||
{ enabled: !!url },
|
||||
['dataCsv', data.url, uniqueId],
|
||||
() => getCsv(data.url as string, bytes ?? 5132288),
|
||||
{ enabled: !!data.url }
|
||||
);
|
||||
const { data: parsedData, isLoading: isParsing } = useQuery(
|
||||
["dataPreview", csvString, randomId],
|
||||
['dataPreview', csvString, uniqueId],
|
||||
() =>
|
||||
parseCsv(
|
||||
rawCsv ? (rawCsv as string) : (csvString as string),
|
||||
parsingConfig ?? {},
|
||||
data.csv ? (data.csv as string) : (csvString as string),
|
||||
parsingConfig ?? {}
|
||||
),
|
||||
{ enabled: rawCsv ? true : !!csvString },
|
||||
{ enabled: data.csv ? true : !!csvString }
|
||||
);
|
||||
if (isParsing || isDownloadingCSV)
|
||||
<div className="w-full flex justify-center items-center h-[500px]">
|
||||
@ -133,7 +129,7 @@ const PlotlyBarChartInner: React.FC<PlotlyBarChartProps> = ({
|
||||
</div>;
|
||||
if (parsedData)
|
||||
return (
|
||||
<div className="w-full" style={{ height: "500px" }}>
|
||||
<div className="w-full" style={{ height: '500px' }}>
|
||||
<Plotly
|
||||
layout={{
|
||||
title,
|
||||
@ -142,8 +138,8 @@ const PlotlyBarChartInner: React.FC<PlotlyBarChartProps> = ({
|
||||
{
|
||||
x: parsedData.data.map((d: any) => d[xAxis]),
|
||||
y: parsedData.data.map((d: any) => d[yAxis]),
|
||||
type: "bar",
|
||||
name: lineLabel,
|
||||
type: 'bar',
|
||||
// name: lineLabel, TODO: commented out because this doesn't work
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
@ -8,7 +8,8 @@ export * from './components/OpenLayers/OpenLayers';
|
||||
export * from './components/Map';
|
||||
export * from './components/PdfViewer';
|
||||
export * from "./components/Excel";
|
||||
export * from "./components/BucketViewer";
|
||||
// NOTE: hidden for now
|
||||
// export * from "./components/BucketViewer";
|
||||
export * from "./components/Iframe";
|
||||
export * from "./components/Plotly";
|
||||
export * from "./components/PlotlyLineChart";
|
||||
|
||||
11
packages/components/src/types/properties.ts
Normal file
11
packages/components/src/types/properties.ts
Normal file
@ -0,0 +1,11 @@
|
||||
/*
|
||||
* All components should use this interface for
|
||||
* its data property.
|
||||
* Based on vega.
|
||||
*
|
||||
*/
|
||||
export interface Data {
|
||||
url?: string;
|
||||
values?: { [key: string]: number | string }[];
|
||||
csv?: string;
|
||||
}
|
||||
@ -1,6 +1,9 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
|
||||
import { PlotlyBarChart, PlotlyBarChartProps } from '../src/components/PlotlyBarChart';
|
||||
import {
|
||||
PlotlyBarChart,
|
||||
PlotlyBarChartProps,
|
||||
} from '../src/components/PlotlyBarChart';
|
||||
|
||||
// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction
|
||||
const meta: Meta = {
|
||||
@ -8,39 +11,44 @@ const meta: Meta = {
|
||||
component: PlotlyBarChart,
|
||||
tags: ['autodocs'],
|
||||
argTypes: {
|
||||
url: {
|
||||
description:
|
||||
'CSV Url to be parsed and used as data source',
|
||||
},
|
||||
data: {
|
||||
description:
|
||||
'Data to be displayed. as an array of key value pairs \n\n E.g.: [{ year: 1850, temperature: -0.41765878 }, { year: 1851, temperature: -0.2333498 }, ...]',
|
||||
},
|
||||
rawCsv: {
|
||||
description:
|
||||
'Raw csv data to be parsed and used as data source',
|
||||
'Data to be displayed. \n\n \
|
||||
Must be an object with one of the following properties: `url`, `values` or `csv` \n\n \
|
||||
`url`: URL pointing to a CSV file. \n\n \
|
||||
`values`: array of objects (check out [this example](/?path=/story/components-plotlybarchart--from-data-points)) \n\n \
|
||||
`csv`: string with valid CSV (check out [this example](/?path=/story/components-plotlybarchart--from-inline-csv)) \n\n \
|
||||
',
|
||||
},
|
||||
bytes: {
|
||||
// TODO: likely this should be an extra option on the data parameter,
|
||||
// specific to URLs
|
||||
description:
|
||||
'How many bytes to read from the url',
|
||||
"How many bytes to read from the url so that the entire file doesn's have to be fetched.",
|
||||
},
|
||||
parsingConfig: {
|
||||
description: 'If using url or rawCsv, this parsing config will be used to parse the data. Optional, check https://www.papaparse.com/ for more info',
|
||||
description:
|
||||
'If using URL or CSV, this parsing config will be used to parse the data. Optional, check https://www.papaparse.com/ for more info.',
|
||||
},
|
||||
title: {
|
||||
description: 'Title to display on the chart. Optional.',
|
||||
},
|
||||
lineLabel: {
|
||||
description: 'Label to display on the line, Optional, will use yAxis if not provided',
|
||||
},
|
||||
// TODO: commented out because this doesn't work
|
||||
// lineLabel: {
|
||||
// description:
|
||||
// 'Label to display on the line, Optional, will use yAxis if not provided',
|
||||
// },
|
||||
xAxis: {
|
||||
description:
|
||||
'Name of the X axis on the data. Required when the "data" parameter is an URL.',
|
||||
'Name of the column header or object property that represents the X-axis on the data.',
|
||||
},
|
||||
yAxis: {
|
||||
description:
|
||||
'Name of the Y axis on the data. Required when the "data" parameter is an URL.',
|
||||
'Name of the column header or object property that represents the Y-axis on the data.',
|
||||
},
|
||||
uniqueId: {
|
||||
description: 'Provide a unique ID to help with cache revalidation of the fetched data.'
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@ -49,25 +57,45 @@ export default meta;
|
||||
type Story = StoryObj<PlotlyBarChartProps>;
|
||||
|
||||
export const FromDataPoints: Story = {
|
||||
name: 'Line chart from array of data points',
|
||||
name: 'Bar chart from array of data points',
|
||||
args: {
|
||||
data: [
|
||||
{year: '1850', temperature: -0.41765878},
|
||||
{year: '1851', temperature: -0.2333498},
|
||||
{year: '1852', temperature: -0.22939907},
|
||||
{year: '1853', temperature: -0.27035445},
|
||||
{year: '1854', temperature: -0.29163003},
|
||||
],
|
||||
data: {
|
||||
values: [
|
||||
{ year: '1850', temperature: -0.41765878 },
|
||||
{ year: '1851', temperature: -0.2333498 },
|
||||
{ year: '1852', temperature: -0.22939907 },
|
||||
{ year: '1853', temperature: -0.27035445 },
|
||||
{ year: '1854', temperature: -0.29163003 },
|
||||
],
|
||||
},
|
||||
xAxis: 'year',
|
||||
yAxis: 'temperature',
|
||||
},
|
||||
};
|
||||
|
||||
export const FromURL: Story = {
|
||||
name: 'Line chart from URL',
|
||||
name: 'Bar chart from URL',
|
||||
args: {
|
||||
title: 'Apple Stock Prices',
|
||||
url: 'https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv',
|
||||
data: {
|
||||
url: 'https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv',
|
||||
},
|
||||
xAxis: 'Date',
|
||||
yAxis: 'AAPL.Open',
|
||||
},
|
||||
};
|
||||
|
||||
export const FromInlineCSV: Story = {
|
||||
name: 'Bar chart from inline CSV',
|
||||
args: {
|
||||
title: 'Apple Stock Prices',
|
||||
data: {
|
||||
csv: `Date,AAPL.Open,AAPL.High,AAPL.Low,AAPL.Close,AAPL.Volume,AAPL.Adjusted,dn,mavg,up,direction
|
||||
2015-02-17,127.489998,128.880005,126.919998,127.830002,63152400,122.905254,106.7410523,117.9276669,129.1142814,Increasing
|
||||
2015-02-18,127.629997,128.779999,127.449997,128.720001,44891700,123.760965,107.842423,118.9403335,130.0382439,Increasing
|
||||
2015-02-19,128.479996,129.029999,128.330002,128.449997,37362400,123.501363,108.8942449,119.8891668,130.8840887,Decreasing
|
||||
2015-02-20,128.619995,129.5,128.050003,129.5,48948400,124.510914,109.7854494,120.7635001,131.7415509,Increasing`,
|
||||
},
|
||||
xAxis: 'Date',
|
||||
yAxis: 'AAPL.Open',
|
||||
},
|
||||
|
||||
@ -1,3 +1,6 @@
|
||||
// NOTE: this component was renamed with .bkp so that it's hidden
|
||||
// from the Storybook app
|
||||
|
||||
import { type Meta, type StoryObj } from '@storybook/react';
|
||||
|
||||
import {
|
||||
@ -1,3 +1,6 @@
|
||||
// NOTE: this component was renamed with .bkp so that it's hidden
|
||||
// from the Storybook app
|
||||
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import React from 'react';
|
||||
import OpenLayers from '../src/components/OpenLayers/OpenLayers';
|
||||
Loading…
x
Reference in New Issue
Block a user