feat(stats): show size in bytes and scale at y=min (#8375)

This commit is contained in:
Joshua Eilers 2023-07-06 10:19:40 -07:00 committed by GitHub
parent 91ebb0706a
commit c57037eb86
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 103 additions and 22 deletions

View File

@ -7,6 +7,15 @@ import Legend from './Legend';
import { addInterval } from '../../shared/time/timeUtils';
import { formatNumber } from '../../shared/formatNumber';
type ScaleConfig = {
type: 'time' | 'timeUtc' | 'linear' | 'band' | 'ordinal';
includeZero?: boolean;
};
type AxisConfig = {
formatter: (tick: number) => string;
};
type Props = {
chartData: TimeSeriesChartType;
width: number;
@ -20,9 +29,16 @@ type Props = {
crossHairLineColor?: string;
};
insertBlankPoints?: boolean;
yScale?: ScaleConfig;
yAxis?: AxisConfig;
};
const MARGIN_SIZE = 40;
const MARGIN = {
TOP: 40,
RIGHT: 45,
BOTTOM: 40,
LEFT: 40,
};
function insertBlankAt(ts: number, newLine: Array<NumericDataPoint>) {
const dateString = new Date(ts).toISOString();
@ -60,7 +76,16 @@ export function computeLines(chartData: TimeSeriesChartType, insertBlankPoints:
return returnLines;
}
export const TimeSeriesChart = ({ chartData, width, height, hideLegend, style, insertBlankPoints }: Props) => {
export const TimeSeriesChart = ({
chartData,
width,
height,
hideLegend,
style,
insertBlankPoints,
yScale,
yAxis,
}: Props) => {
const ordinalColorScale = scaleOrdinal<string, string>({
domain: chartData.lines.map((data) => data.name),
range: lineColors.slice(0, chartData.lines.length),
@ -75,9 +100,13 @@ export const TimeSeriesChart = ({ chartData, width, height, hideLegend, style, i
ariaLabel={chartData.title}
width={width}
height={height}
margin={{ top: MARGIN_SIZE, right: MARGIN_SIZE, bottom: MARGIN_SIZE, left: MARGIN_SIZE }}
margin={{ top: MARGIN.TOP, right: MARGIN.RIGHT, bottom: MARGIN.BOTTOM, left: MARGIN.LEFT }}
xScale={{ type: 'time' }}
yScale={{ type: 'linear' }}
yScale={
yScale ?? {
type: 'linear',
}
}
renderTooltip={({ datum }) => (
<div>
<div>{new Date(Number(datum.x)).toDateString()}</div>
@ -89,7 +118,7 @@ export const TimeSeriesChart = ({ chartData, width, height, hideLegend, style, i
<XAxis axisStyles={{ stroke: style && style.axisColor, strokeWidth: style && style.axisWidth }} />
<YAxis
axisStyles={{ stroke: style && style.axisColor, strokeWidth: style && style.axisWidth }}
tickFormat={(tick) => formatNumber(tick)}
tickFormat={(tick) => (yAxis?.formatter ? yAxis.formatter(tick) : formatNumber(tick))}
/>
{lines.map((line, i) => (
<LineSeries

View File

@ -10,6 +10,7 @@ import { Message } from '../../../../../../shared/Message';
import { LookbackWindow } from '../lookbackWindows';
import { ANTD_GRAY } from '../../../../constants';
import PrefixedSelect from './shared/PrefixedSelect';
import { formatBytes } from '../../../../../../shared/formatNumber';
// TODO: Reuse stat sections.
const StatSection = styled.div`
@ -167,6 +168,7 @@ export default function HistoricalStats({ urn, lookbackWindow }: Props) {
*/
const rowCountChartValues = extractChartValuesFromTableProfiles(profiles, 'rowCount');
const columnCountChartValues = extractChartValuesFromTableProfiles(profiles, 'columnCount');
const sizeChartValues = extractChartValuesFromTableProfiles(profiles, 'sizeInBytes');
/**
* Compute Column Stat chart data.
@ -192,6 +194,24 @@ export default function HistoricalStats({ urn, lookbackWindow }: Props) {
'uniqueProportion',
);
const bytesFormatter = (num: number) => {
const formattedBytes = formatBytes(num);
return `${formattedBytes.number} ${formattedBytes.unit}`;
};
const placeholderChart = (
<StatChart
title="Placeholder"
tickInterval={graphTickInterval}
dateRange={{ start: '', end: '' }}
values={[]}
visible={false}
/>
);
const placeholderVerticalDivider = (
<ChartDivider type="vertical" height={360} width={1} style={{ visibility: 'hidden' }} />
);
return (
<>
{profilesLoading && <Message type="loading" content="Loading..." style={{ marginTop: '10%' }} />}
@ -216,6 +236,18 @@ export default function HistoricalStats({ urn, lookbackWindow }: Props) {
values={columnCountChartValues}
/>
</ChartRow>
<ChartDivider type="horizontal" height={1} width={400} />
<ChartRow>
<StatChart
title="Size Over Time"
tickInterval={graphTickInterval}
dateRange={graphDateRange}
values={sizeChartValues}
yAxis={{ formatter: bytesFormatter }}
/>
{placeholderVerticalDivider}
{placeholderChart}
</ChartRow>
</StatSection>
<StatSection>
<ColumnStatsHeader>

View File

@ -4,6 +4,7 @@ import styled from 'styled-components';
import { DatasetProfile } from '../../../../../../../../types.generated';
import ColumnStats from '../../snapshot/ColumnStats';
import TableStats from '../../snapshot/TableStats';
import { formatBytes, formatNumberWithoutAbbreviation } from '../../../../../../../shared/formatNumber';
export const ChartTable = styled(Table)`
margin-top: 16px;
@ -13,6 +14,12 @@ export type Props = {
profiles: Array<DatasetProfile>;
};
const bytesFormatter = (bytes: number) => {
const formattedBytes = formatBytes(bytes);
const fullBytes = formatNumberWithoutAbbreviation(bytes);
return `${formattedBytes.number} ${formattedBytes.unit} (${fullBytes} bytes)`;
};
export default function ProfilingRunsChart({ profiles }: Props) {
const [showModal, setShowModal] = useState(false);
const [selectedProfileIndex, setSelectedProfileIndex] = useState(-1);
@ -33,6 +40,7 @@ export default function ProfilingRunsChart({ profiles }: Props) {
timestamp: `${profileDate.toLocaleDateString()} at ${profileDate.toLocaleTimeString()}`,
rowCount: profile.rowCount?.toString() || 'unknown',
columnCount: profile.columnCount?.toString() || 'unknown',
sizeInBytes: profile.sizeInBytes ? bytesFormatter(profile.sizeInBytes) : 'unknown',
};
});
@ -59,6 +67,11 @@ export default function ProfilingRunsChart({ profiles }: Props) {
key: 'Column Count',
dataIndex: 'columnCount',
},
{
title: 'Size',
key: 'Size',
dataIndex: 'sizeInBytes',
},
];
const selectedProfile = (selectedProfileIndex >= 0 && profiles[selectedProfileIndex]) || undefined;

View File

@ -14,8 +14,9 @@ const ChartTitle = styled(Typography.Text)`
}
`;
const ChartCard = styled(Card)`
const ChartCard = styled(Card)<{ visible: boolean }>`
box-shadow: ${(props) => props.theme.styles['box-shadow']};
visibility: ${(props) => (props.visible ? 'visible' : 'hidden')}; ;
`;
type Point = {
@ -23,11 +24,17 @@ type Point = {
value: number;
};
type AxisConfig = {
formatter: (tick: number) => string;
};
export type Props = {
title: string;
values: Array<Point>;
tickInterval: DateInterval;
dateRange: DateRange;
yAxis?: AxisConfig;
visible?: boolean;
};
/**
@ -41,7 +48,7 @@ const DEFAULT_AXIS_WIDTH = 2;
/**
* Time Series Chart with a single line.
*/
export default function StatChart({ title, values, tickInterval: interval, dateRange }: Props) {
export default function StatChart({ title, values, tickInterval: interval, dateRange, yAxis, visible = true }: Props) {
const timeSeriesData = useMemo(
() =>
values
@ -56,22 +63,10 @@ export default function StatChart({ title, values, tickInterval: interval, dateR
[values],
);
const chartData = {
title,
lines: [
{
name: 'line_1',
data: timeSeriesData,
},
],
interval,
dateRange,
};
return (
<ChartCard>
<ChartCard visible={visible}>
<ChartContainer>
<ChartTitle>{chartData.title}</ChartTitle>
<ChartTitle>{title}</ChartTitle>
<TimeSeriesChart
style={{
lineColor: DEFAULT_LINE_COLOR,
@ -79,9 +74,21 @@ export default function StatChart({ title, values, tickInterval: interval, dateR
axisWidth: DEFAULT_AXIS_WIDTH,
}}
hideLegend
chartData={chartData}
chartData={{
title,
lines: [
{
name: 'line_1',
data: timeSeriesData,
},
],
interval,
dateRange,
}}
width={360}
height={300}
yScale={{ type: 'linear', includeZero: false }}
yAxis={yAxis}
/>
</ChartContainer>
</ChartCard>