mirror of
https://github.com/datahub-project/datahub.git
synced 2025-12-28 02:17:53 +00:00
feat(stats): show size in bytes and scale at y=min (#8375)
This commit is contained in:
parent
91ebb0706a
commit
c57037eb86
@ -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
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user