Skip to content

Commit

Permalink
Log axis option for bar and line graphs, and consolidated graph confi…
Browse files Browse the repository at this point in the history
…g props into single graphConfig object
  • Loading branch information
tombch committed Nov 11, 2024
1 parent e4c9e70 commit ca4b446
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 97 deletions.
108 changes: 66 additions & 42 deletions lib/components/Graphs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { useMemo } from "react";
import { useQuery } from "@tanstack/react-query";
import Plotly from "plotly.js-basic-dist";
import createPlotlyComponent from "react-plotly.js/factory";
import { Template } from "plotly.js-basic-dist";
import { ProjectField, ResultType } from "../types";
import { Template, AxisType } from "plotly.js-basic-dist";
import { ProjectField, ResultType, GraphConfig } from "../types";
import { StatsProps } from "../interfaces";
import graphStyles from "../utils/graphStyles";

Expand All @@ -15,32 +15,30 @@ interface BaseGraphProps {
title: string;
xTitle?: string;
yTitle?: string;
yAxisType?: string;
legendTitle?: string;
layout?: Record<string, unknown>;
darkMode: boolean;
uirevision: string;
}

interface GraphProps extends StatsProps {
field: string;
}

interface GroupedGraphProps extends GraphProps {
groupBy: string;
groupMode?: string;
graphConfig: GraphConfig;
}

const useSummaryQuery = (props: GraphProps) => {
return useQuery({
queryKey: ["results", props.project, props.field],
queryKey: ["results", props.project, props.graphConfig.field],
queryFn: async () => {
return props
.httpPathHandler(`projects/${props.project}/?summarise=${props.field}`)
.httpPathHandler(
`projects/${props.project}/?summarise=${props.graphConfig.field}`
)
.then((response) => response.json())
.then((data) => {
const field_data = data.data.map((record: ResultType) => {
// Convert null field value to empty string
let field_value = record[props.field];
let field_value = record[props.graphConfig.field];
if (field_value === null) {
field_value = "";
} else {
Expand All @@ -59,13 +57,18 @@ const useSummaryQuery = (props: GraphProps) => {
});
};

const useGroupedSummaryQuery = (props: GroupedGraphProps) => {
const useGroupedSummaryQuery = (props: GraphProps) => {
return useQuery({
queryKey: ["results", props.project, props.field, props.groupBy],
queryKey: [
"results",
props.project,
props.graphConfig.field,
props.graphConfig.groupBy,
],
queryFn: async () => {
return props
.httpPathHandler(
`projects/${props.project}/?summarise=${props.field}&summarise=${props.groupBy}`
`projects/${props.project}/?summarise=${props.graphConfig.field}&summarise=${props.graphConfig.groupBy}`
)
.then((response) => response.json())
.then((data) => {
Expand All @@ -76,15 +79,15 @@ const useGroupedSummaryQuery = (props: GroupedGraphProps) => {

data.data.forEach((record: ResultType) => {
// Convert null field value to empty string
let field_value = record[props.field];
let field_value = record[props.graphConfig.field];
if (field_value === null) {
field_value = "";
} else {
field_value = field_value.toString();
}

// Convert null group-by value to empty string
let group_by_value = record[props.groupBy];
let group_by_value = record[props.graphConfig.groupBy];
if (group_by_value === null) {
group_by_value = "";
} else {
Expand Down Expand Up @@ -172,7 +175,11 @@ function BaseGraph(props: BaseGraphProps) {
height: 330,
template: props.darkMode ? (graphStyles as Template) : undefined,
xaxis: { title: props.xTitle },
yaxis: { title: props.yTitle },
yaxis: {
title:
props.yAxisType === "log" ? `log(${props.yTitle})` : props.yTitle,
type: (props.yAxisType ? props.yAxisType : "linear") as AxisType,
},
legend: { title: { text: props.legendTitle } },
showlegend: props.legendTitle ? true : false,
colorway: [
Expand Down Expand Up @@ -222,10 +229,11 @@ function ScatterGraph(props: GraphProps) {
mode: "lines+markers",
},
]}
title={getTitle(props.projectFields, props.field, data)}
xTitle={props.field}
title={getTitle(props.projectFields, props.graphConfig.field, data)}
xTitle={props.graphConfig.field}
yTitle="count"
uirevision={props.field}
yAxisType={props.graphConfig.yAxisType}
uirevision={props.graphConfig.field}
/>
);
}
Expand All @@ -238,6 +246,18 @@ function BarGraph(props: GraphProps) {
},
} = useSummaryQuery(props);

let layout: Record<string, string> = {};
let yTitle = "count";

if (props.graphConfig.groupMode === "stack") {
layout = { barmode: "stack" };
} else if (props.graphConfig.groupMode === "group") {
layout = { barmode: "group" };
} else if (props.graphConfig.groupMode === "norm") {
layout = { barmode: "stack", barnorm: "percent" };
yTitle = "percentage";
}

return (
<BaseGraph
{...props}
Expand All @@ -248,10 +268,12 @@ function BarGraph(props: GraphProps) {
type: "bar",
},
]}
title={getTitle(props.projectFields, props.field, data)}
xTitle={props.field}
yTitle="count"
uirevision={props.field}
title={getTitle(props.projectFields, props.graphConfig.field, data)}
xTitle={props.graphConfig.field}
yTitle={yTitle}
yAxisType={props.graphConfig.yAxisType}
layout={layout}
uirevision={props.graphConfig.field}
/>
);
}
Expand All @@ -275,14 +297,14 @@ function PieGraph(props: GraphProps) {
marker: { color: "#198754" },
},
]}
title={getTitle(props.projectFields, props.field, data)}
legendTitle={props.field}
uirevision={props.field}
title={getTitle(props.projectFields, props.graphConfig.field, data)}
legendTitle={props.graphConfig.field}
uirevision={props.graphConfig.field}
/>
);
}

function GroupedScatterGraph(props: GroupedGraphProps) {
function GroupedScatterGraph(props: GraphProps) {
const {
data = new Map<string, { field_data: string[]; count_data: number[] }>(),
} = useGroupedSummaryQuery(props);
Expand All @@ -305,19 +327,20 @@ function GroupedScatterGraph(props: GroupedGraphProps) {
data={graphData}
title={getGroupedTitle(
props.projectFields,
props.field,
props.groupBy,
props.graphConfig.field,
props.graphConfig.groupBy,
data
)}
xTitle={props.field}
xTitle={props.graphConfig.field}
yTitle="count"
legendTitle={props.groupBy}
uirevision={`${props.field}-${props.groupBy}`}
yAxisType={props.graphConfig.yAxisType}
legendTitle={props.graphConfig.groupBy}
uirevision={`${props.graphConfig.field}-${props.graphConfig.groupBy}`}
/>
);
}

function GroupedBarGraph(props: GroupedGraphProps) {
function GroupedBarGraph(props: GraphProps) {
const {
data = new Map<string, { field_data: string[]; count_data: number[] }>(),
} = useGroupedSummaryQuery(props);
Expand All @@ -336,11 +359,11 @@ function GroupedBarGraph(props: GroupedGraphProps) {
let layout: Record<string, string> = {};
let yTitle = "count";

if (props.groupMode === "stack") {
if (props.graphConfig.groupMode === "stack") {
layout = { barmode: "stack" };
} else if (props.groupMode === "group") {
} else if (props.graphConfig.groupMode === "group") {
layout = { barmode: "group" };
} else if (props.groupMode === "norm") {
} else if (props.graphConfig.groupMode === "norm") {
layout = { barmode: "stack", barnorm: "percent" };
yTitle = "percentage";
}
Expand All @@ -351,15 +374,16 @@ function GroupedBarGraph(props: GroupedGraphProps) {
data={graphData}
title={getGroupedTitle(
props.projectFields,
props.field,
props.groupBy,
props.graphConfig.field,
props.graphConfig.groupBy,
data
)}
xTitle={props.field}
xTitle={props.graphConfig.field}
yTitle={yTitle}
legendTitle={props.groupBy}
yAxisType={props.graphConfig.yAxisType}
legendTitle={props.graphConfig.groupBy}
layout={layout}
uirevision={`${props.field}-${props.groupBy}`}
uirevision={`${props.graphConfig.field}-${props.graphConfig.groupBy}`}
/>
);
}
Expand Down
Loading

0 comments on commit ca4b446

Please sign in to comment.