Skip to content

Commit

Permalink
Add HeatmapObservable plot type
Browse files Browse the repository at this point in the history
  • Loading branch information
plmrry committed Nov 6, 2023
1 parent a87410e commit 127f192
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 0 deletions.
3 changes: 3 additions & 0 deletions flatfront-astro/src/lib/components/ObservablePlot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ type ObservablePlotType = ReturnType<typeof Plot.plot>;
export default function ObservablePlot({ plot }: { plot: ObservablePlotType }) {
const ref = React.useRef<HTMLDivElement>(null);
React.useEffect(() => {
for (const svg of plot.querySelectorAll(`svg`)) {
svg.style.background = `transparent`;
}
ref.current.append(plot);
return () => plot.remove();
}, [plot]);
Expand Down
5 changes: 5 additions & 0 deletions flatfront-astro/src/lib/components/PlotSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ function PlotTypeSelect() {
const plot_type_options: { key: PlotType; label: string }[] = [
{ key: Plots.Histogram.key, label: Plots.Histogram.label },
{ key: Plots.Heatmap.key, label: Plots.Heatmap.label },
{ key: Plots.HeatmapObservable.key, label: Plots.HeatmapObservable.label },
{ key: Plots.BoxPlot.key, label: Plots.BoxPlot.label },
{ key: Plots.Scatterplot.key, label: Plots.Scatterplot.label },
{ key: Plots.Scatterplot3D.key, label: Plots.Scatterplot3D.label }
Expand Down Expand Up @@ -75,6 +76,8 @@ function PlotComponent() {
return <Plots.Histogram.Plot />;
case Plots.Heatmap.key:
return <Plots.Heatmap.Plot />;
case Plots.HeatmapObservable.key:
return <Plots.HeatmapObservable.Plot />;
case Plots.BoxPlot.key:
return <Plots.BoxPlot.Plot />;
case Plots.Scatterplot.key:
Expand All @@ -93,6 +96,8 @@ function PlotControls() {
return <Plots.Histogram.Controls />;
case Plots.Heatmap.key:
return <Plots.Heatmap.Controls />;
case Plots.HeatmapObservable.key:
return <Plots.HeatmapObservable.Controls />;
case Plots.BoxPlot.key:
return <Plots.BoxPlot.Controls />;
case Plots.Scatterplot.key:
Expand Down
117 changes: 117 additions & 0 deletions flatfront-astro/src/lib/components/Plots.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import {
useQueryClient,
type UseQueryOptions
} from "@tanstack/react-query";
import * as d3 from "d3";
import * as Plot from "@observablehq/plot";
import lodash_merge from "lodash.merge";
import { log, fetch_api_post } from "../shared";
import { useIsDarkMode } from "../dark-mode";
Expand All @@ -26,6 +28,7 @@ import {
LogModeCheckbox
} from "./PlotPrimitives";
import HighchartsPlot from "./HighchartsPlot";
import ObservablePlot from "./ObservablePlot";

export const Histogram: PlotWrapper = {
key: `histogram`,
Expand Down Expand Up @@ -220,6 +223,120 @@ export const Heatmap: PlotWrapper = {
}
};

export const HeatmapObservable: PlotWrapper = {
key: `heatmap_observable`,
label: `Heatmap v2`,
Plot() {
const catalog_id = useCatalogID();
const filters = useFilters();
const random_config = useRandomConfig();

const x_axis = useAxisConfig(`x_axis`);
const y_axis = useAxisConfig(`y_axis`);

const enable_request =
Boolean(catalog_id) &&
x_axis.ready_for_request &&
y_axis.ready_for_request;

const query = usePlotQuery<HistogramPostRequestBody, HistogramResponse>({
path: `/${catalog_id}/histogram`,
body: {
fields: [
{ field: x_axis.field_id, size: 20, log: x_axis.log_mode },
{ field: y_axis.field_id, size: 20, log: y_axis.log_mode }
] as any,
...filters,
...random_config
},
label: `Heatmap`,
enabled: enable_request
});

const sizes = query.data?.sizes ?? [0, 0];

const data_munged = (() => {
if (!query.data) return [];
return query.data.buckets.map(({ key: [x, y], count }) => {
const x1 = +x;
const y1 = +y;
const x2 = x_axis.log_mode ? x1 * sizes[0] : x1 + sizes[0];
const y2 = y_axis.log_mode ? y1 * sizes[1] : y1 + sizes[1];
return { x1, y1, x2, y2, count };
});
})();

log(`data_munged`, query.data?.sizes, data_munged);

const status = (() => {
if (x_axis.log_mode_error_message) {
return x_axis.log_mode_error_message;
} else if (y_axis.log_mode_error_message) {
return y_axis.log_mode_error_message;
} else if (query.isFetching) {
return <LoadingBox />;
} else if (!(data_munged.length > 0)) {
return `No data.`;
} else {
return null;
}
})();

const is_dark_mode = useIsDarkMode();

const plot = Plot.plot({
style: {
background: `transparent`,
width: `100%`
},
color: {
legend: true,
scheme: `Greys`,
reverse: is_dark_mode,
domain: [-2, d3.max(data_munged, (d) => d.count)]
},
x: {
label: x_axis.field_id,
type: x_axis.log_mode ? `log` : `linear`,
tickFormat: x_axis.log_mode ? `.3~f` : undefined,
grid: true
},
y: {
label: y_axis.field_id,
type: y_axis.log_mode ? `log` : `linear`,
tickFormat: y_axis.log_mode ? `.3~f` : undefined,
grid: true
},
marks: [
Plot.rect(data_munged, {
x1: `x1`,
x2: `x2`,
y1: `y1`,
y2: `y2`,
fill: `count`,
stroke: `currentColor`,
strokeOpacity: 0.2,
tip: true
})
]
});

return (
<StatusWrapper status={status}>
<ObservablePlot plot={plot} />
</StatusWrapper>
);
},
Controls() {
return (
<>
<XAxisControl />
<YAxisControl />
</>
);
}
};

export const BoxPlot: PlotWrapper = {
key: `boxplot`,
label: `Box Plot`,
Expand Down
1 change: 1 addition & 0 deletions flatfront-astro/src/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ export type PlotWrapper = {
export type PlotType =
| `histogram`
| `heatmap`
| `heatmap_observable`
| `boxplot`
| `scatterplot`
| `scatterplot_3d`;
Expand Down

0 comments on commit 127f192

Please sign in to comment.