Skip to content

Commit

Permalink
Display and sort by percentages in TopN subcharts (#82)
Browse files Browse the repository at this point in the history
* Switch to EuiSplitPanel for subcharts

* Add percentages to subcharts

* Simplify subchart ordering

* Simplify calculating percentages per category
  • Loading branch information
jbcrail authored and rockdaboot committed Jul 4, 2022
1 parent 56a24a9 commit ac367f5
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 49 deletions.
43 changes: 34 additions & 9 deletions src/plugins/profiling/common/topn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,12 @@ import {

import { StackFrameMetadata } from './profiling';

export interface TopNSample {
export interface CountPerTime {
Timestamp: number;
Count: number;
}

export interface TopNSample extends CountPerTime {
Category: string;
}

Expand Down Expand Up @@ -62,15 +65,37 @@ export function createTopNSamples(histogram: AggregationsHistogramAggregate): To
return orderBy(samples, ['Timestamp', 'Count', 'Category'], ['asc', 'desc', 'asc']);
}

export function groupSamplesByCategory(samples: TopNSample[]) {
const series = new Map();
export interface TopNSubchart {
Category: string;
Percentage: number;
Series: CountPerTime[];
}

export function groupSamplesByCategory(samples: TopNSample[]): TopNSubchart[] {
const seriesByCategory = new Map<string, CountPerTime[]>();
let total = 0;

for (let i = 0; i < samples.length; i++) {
const v = samples[i];
if (!series.has(v.Category)) {
series.set(v.Category, []);
const sample = samples[i];

if (!seriesByCategory.has(sample.Category)) {
seriesByCategory.set(sample.Category, []);
}
const value = series.get(v.Category);
value.push([v.Timestamp, v.Count]);
const series = seriesByCategory.get(sample.Category)!;
series.push({ Timestamp: sample.Timestamp, Count: sample.Count });

total += sample.Count;
}
return series;

const subcharts: TopNSubchart[] = [];
for (const [category, series] of seriesByCategory) {
const totalPerCategory = series.reduce((sum, { Count }) => sum + Count, 0);
subcharts.push({
Category: category,
Percentage: (totalPerCategory / total) * 100,
Series: series,
});
}

return orderBy(subcharts, ['Percentage', 'Category'], ['desc', 'asc']);
}
2 changes: 1 addition & 1 deletion src/plugins/profiling/public/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ function App({ fetchTopN, fetchElasticFlamechart }: Props) {

const [topn, setTopN] = useState({
samples: [],
series: new Map(),
subcharts: [],
});

const [elasticFlamegraph, setElasticFlamegraph] = useState({});
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/profiling/public/components/bar-chart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export const BarChart: React.FC<BarChartProps> = ({ id, name, height, data, x, y
return (
<Chart size={{ height }}>
<Settings showLegend={false} />
<BarSeries id={id} name={name} data={data} xScaleType="time" xAccessor={0} yAccessors={[1]} />
<BarSeries id={id} name={name} data={data} xScaleType="time" xAccessor={x} yAccessors={[y]} />
<Axis id="bottom-axis" position="bottom" tickFormat={timeFormatter('YYYY-MM-DD HH:mm:ss')} />
<Axis id="left-axis" position="left" showGridLines tickFormat={(d) => Number(d).toFixed(0)} />
</Chart>
Expand Down
79 changes: 43 additions & 36 deletions src/plugins/profiling/public/components/chart-grid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,59 +9,66 @@
import React, { useContext, useEffect } from 'react';

import {
EuiCard,
EuiFlexGrid,
EuiFlexGroup,
EuiFlexItem,
EuiNotificationBadge,
EuiSpacer,
EuiSplitPanel,
EuiTitle,
} from '@elastic/eui';

import { TopNContext } from './contexts/topn';
import { BarChart } from './bar-chart';
import { TopNContext } from './contexts/topn';
import { TopNSubchart } from '../../common/topn';

export interface ChartGridProps {
maximum: number;
}

export const ChartGrid: React.FC<ChartGridProps> = ({ maximum }) => {
const ctx = useContext(TopNContext);
const printSubCharts = (series: any) => {
let keys: string[] = Array.from(series.keys());
const ncharts = Math.min(maximum, series.size);
keys = keys.slice(0, ncharts);
function printSubCharts(subcharts: TopNSubchart[], maximum: number) {
const ncharts = Math.min(maximum, subcharts.length);

const charts = [];
for (let i = 0; i < ncharts; i++) {
const subdata = ctx.series.get(keys[i]);
const uniqueID = `bar-chart-${i}`;
const charts = [];
for (let i = 0; i < ncharts; i++) {
const subchart = subcharts[i];
const uniqueID = `bar-chart-${i}`;

const barchart = (
<BarChart id={uniqueID} name={keys[i]} height={200} data={subdata} x="x" y="y" />
);
const barchart = (
<BarChart
id={uniqueID}
name={subchart.Category}
height={200}
data={subchart.Series}
x="Timestamp"
y="Count"
/>
);

const title = (
<div>
const title = (
<EuiFlexGroup gutterSize="m">
<EuiFlexItem grow={false}>
<EuiNotificationBadge>{i + 1}</EuiNotificationBadge>
&emsp;
{keys[i]}
</div>
);
</EuiFlexItem>
<EuiFlexItem>{subchart.Category}</EuiFlexItem>
<EuiFlexItem grow={false}>{subchart.Percentage.toFixed(2)}%</EuiFlexItem>
</EuiFlexGroup>
);

const card = (
<EuiCard
layout="horizontal"
onClick={() => {}}
title={title}
display="plain"
description={barchart}
/>
);
const card = (
<EuiSplitPanel.Outer>
<EuiSplitPanel.Inner>{title}</EuiSplitPanel.Inner>
<EuiSplitPanel.Inner>{barchart}</EuiSplitPanel.Inner>
</EuiSplitPanel.Outer>
);

charts.push(<EuiFlexItem>{card}</EuiFlexItem>);
}
return charts;
};
charts.push(<EuiFlexItem>{card}</EuiFlexItem>);
}
return charts;
}

export const ChartGrid: React.FC<ChartGridProps> = ({ maximum }) => {
const ctx = useContext(TopNContext);

useEffect(() => {
console.log(new Date().toISOString(), 'updated chart-grid');
Expand All @@ -71,11 +78,11 @@ export const ChartGrid: React.FC<ChartGridProps> = ({ maximum }) => {
<>
<EuiSpacer />
<EuiTitle size="s">
<h1>Top {ctx.series.size}</h1>
<h1>Top {ctx.subcharts.length}</h1>
</EuiTitle>
<EuiSpacer />
<EuiFlexGrid columns={2} gutterSize="s">
{printSubCharts(ctx.series)}
{printSubCharts(ctx.subcharts, maximum)}
</EuiFlexGrid>
</>
);
Expand Down
4 changes: 2 additions & 2 deletions src/plugins/profiling/public/components/stacktrace-nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,9 @@ export const StackTraceNavigation = ({ index, projectID, n, timeRange, fetchTopN
(response: TopNSamples) => {
console.log(new Date().toISOString(), 'finished payload retrieval');
const samples = response.TopN;
const series = groupSamplesByCategory(samples);
const subcharts = groupSamplesByCategory(samples);
const samplesWithoutZero = samples.filter((sample: TopNSample) => sample.Count > 0);
setTopN({ samples: samplesWithoutZero, series });
setTopN({ samples: samplesWithoutZero, subcharts });
console.log(new Date().toISOString(), 'updated local state');
}
);
Expand Down

0 comments on commit ac367f5

Please sign in to comment.