Add more options for distribution charts
Changing title, color, tick format, and domain
This commit is contained in:
parent
934608d971
commit
0c66bb0579
|
@ -5,18 +5,15 @@ import {
|
|||
distributionError,
|
||||
distributionErrorToString,
|
||||
} from "@quri/squiggle-lang";
|
||||
import { Vega, VisualizationSpec } from "react-vega";
|
||||
import * as chartSpecification from "../vega-specs/spec-distributions.json";
|
||||
import { Vega } from "react-vega";
|
||||
import { ErrorAlert } from "./Alert";
|
||||
import { useSize } from "react-use";
|
||||
import clsx from "clsx";
|
||||
|
||||
import {
|
||||
linearXScale,
|
||||
logXScale,
|
||||
linearYScale,
|
||||
expYScale,
|
||||
} from "./DistributionVegaScales";
|
||||
buildVegaSpec,
|
||||
DistributionChartSpecOptions,
|
||||
} from "../lib/distributionSpecBuilder";
|
||||
import { NumberShower } from "./NumberShower";
|
||||
|
||||
export type DistributionPlottingSettings = {
|
||||
|
@ -24,27 +21,26 @@ export type DistributionPlottingSettings = {
|
|||
showSummary: boolean;
|
||||
/** Whether to show the user graph controls (scale etc) */
|
||||
showControls: boolean;
|
||||
/** Set the x scale to be logarithmic by deault */
|
||||
logX: boolean;
|
||||
/** Set the y scale to be exponential by deault */
|
||||
expY: boolean;
|
||||
};
|
||||
} & DistributionChartSpecOptions;
|
||||
|
||||
export type DistributionChartProps = {
|
||||
distribution: Distribution;
|
||||
width?: number;
|
||||
height: number;
|
||||
actions?: boolean;
|
||||
} & DistributionPlottingSettings;
|
||||
|
||||
export const DistributionChart: React.FC<DistributionChartProps> = ({
|
||||
distribution,
|
||||
height,
|
||||
showSummary,
|
||||
width,
|
||||
showControls,
|
||||
logX,
|
||||
expY,
|
||||
}) => {
|
||||
export const DistributionChart: React.FC<DistributionChartProps> = (props) => {
|
||||
const {
|
||||
distribution,
|
||||
height,
|
||||
showSummary,
|
||||
width,
|
||||
showControls,
|
||||
logX,
|
||||
expY,
|
||||
actions = false,
|
||||
} = props;
|
||||
const [isLogX, setLogX] = React.useState(logX);
|
||||
const [isExpY, setExpY] = React.useState(expY);
|
||||
|
||||
|
@ -64,7 +60,7 @@ export const DistributionChart: React.FC<DistributionChartProps> = ({
|
|||
const massBelow0 =
|
||||
shape.value.continuous.some((x) => x.x <= 0) ||
|
||||
shape.value.discrete.some((x) => x.x <= 0);
|
||||
const spec = buildVegaSpec(isLogX, isExpY);
|
||||
const spec = buildVegaSpec(props);
|
||||
|
||||
let widthProp = width ? width : size.width;
|
||||
if (widthProp < 20) {
|
||||
|
@ -82,7 +78,7 @@ export const DistributionChart: React.FC<DistributionChartProps> = ({
|
|||
data={{ con: shape.value.continuous, dis: shape.value.discrete }}
|
||||
width={widthProp - 10}
|
||||
height={height}
|
||||
actions={false}
|
||||
actions={actions}
|
||||
/>
|
||||
) : (
|
||||
<ErrorAlert heading="Log Domain Error">
|
||||
|
@ -116,16 +112,6 @@ export const DistributionChart: React.FC<DistributionChartProps> = ({
|
|||
return sized;
|
||||
};
|
||||
|
||||
function buildVegaSpec(isLogX: boolean, isExpY: boolean): VisualizationSpec {
|
||||
return {
|
||||
...chartSpecification,
|
||||
scales: [
|
||||
isLogX ? logXScale : linearXScale,
|
||||
isExpY ? expYScale : linearYScale,
|
||||
],
|
||||
} as VisualizationSpec;
|
||||
}
|
||||
|
||||
interface CheckBoxProps {
|
||||
label: string;
|
||||
onChange: (x: boolean) => void;
|
||||
|
|
|
@ -41,6 +41,18 @@ export interface SquiggleChartProps {
|
|||
logX?: boolean;
|
||||
/** Set the y scale to be exponential by deault */
|
||||
expY?: boolean;
|
||||
/** How to format numbers on the x axis */
|
||||
tickFormat?: string;
|
||||
/** Title of the graphed distribution */
|
||||
title?: string;
|
||||
/** Color of the graphed distribution */
|
||||
color?: string;
|
||||
/** Specify the lower bound of the x scale */
|
||||
minX?: number;
|
||||
/** Specify the upper bound of the x scale */
|
||||
maxX?: number;
|
||||
/** Whether to show vega actions to the user, so they can copy the chart spec */
|
||||
distributionChartActions?: boolean;
|
||||
}
|
||||
|
||||
const defaultOnChange = () => {};
|
||||
|
@ -60,6 +72,12 @@ export const SquiggleChart: React.FC<SquiggleChartProps> = ({
|
|||
logX = false,
|
||||
expY = false,
|
||||
chartSettings = defaultChartSettings,
|
||||
tickFormat,
|
||||
minX,
|
||||
maxX,
|
||||
color,
|
||||
title,
|
||||
distributionChartActions,
|
||||
}) => {
|
||||
const { result } = useSquiggle({
|
||||
code: squiggleString,
|
||||
|
@ -78,6 +96,12 @@ export const SquiggleChart: React.FC<SquiggleChartProps> = ({
|
|||
showSummary,
|
||||
logX,
|
||||
expY,
|
||||
format: tickFormat,
|
||||
minX,
|
||||
maxX,
|
||||
color,
|
||||
title,
|
||||
actions: distributionChartActions,
|
||||
};
|
||||
|
||||
return (
|
||||
|
|
256
packages/components/src/lib/distributionSpecBuilder.ts
Normal file
256
packages/components/src/lib/distributionSpecBuilder.ts
Normal file
|
@ -0,0 +1,256 @@
|
|||
import { VisualizationSpec } from "react-vega";
|
||||
import type { LogScale, LinearScale, PowScale } from "vega";
|
||||
|
||||
export type DistributionChartSpecOptions = {
|
||||
/** Set the x scale to be logarithmic by deault */
|
||||
logX: boolean;
|
||||
/** Set the y scale to be exponential by deault */
|
||||
expY: boolean;
|
||||
/** The minimum x coordinate shown on the chart */
|
||||
minX?: number;
|
||||
/** The maximum x coordinate shown on the chart */
|
||||
maxX?: number;
|
||||
/** The color of the chart */
|
||||
color?: string;
|
||||
/** The title of the chart */
|
||||
title?: string;
|
||||
/** The formatting of the ticks */
|
||||
format?: string;
|
||||
};
|
||||
|
||||
export let linearXScale: LinearScale = {
|
||||
name: "xscale",
|
||||
clamp: true,
|
||||
type: "linear",
|
||||
range: "width",
|
||||
zero: false,
|
||||
nice: false,
|
||||
domain: {
|
||||
fields: [
|
||||
{
|
||||
data: "con",
|
||||
field: "x",
|
||||
},
|
||||
{
|
||||
data: "dis",
|
||||
field: "x",
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
export let linearYScale: LinearScale = {
|
||||
name: "yscale",
|
||||
type: "linear",
|
||||
range: "height",
|
||||
zero: false,
|
||||
domain: {
|
||||
fields: [
|
||||
{
|
||||
data: "con",
|
||||
field: "y",
|
||||
},
|
||||
{
|
||||
data: "dis",
|
||||
field: "y",
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export let logXScale: LogScale = {
|
||||
name: "xscale",
|
||||
type: "log",
|
||||
range: "width",
|
||||
zero: false,
|
||||
base: 10,
|
||||
nice: false,
|
||||
clamp: true,
|
||||
domain: {
|
||||
fields: [
|
||||
{
|
||||
data: "con",
|
||||
field: "x",
|
||||
},
|
||||
{
|
||||
data: "dis",
|
||||
field: "x",
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export let expYScale: PowScale = {
|
||||
name: "yscale",
|
||||
type: "pow",
|
||||
exponent: 0.1,
|
||||
range: "height",
|
||||
zero: false,
|
||||
nice: false,
|
||||
domain: {
|
||||
fields: [
|
||||
{
|
||||
data: "con",
|
||||
field: "y",
|
||||
},
|
||||
{
|
||||
data: "dis",
|
||||
field: "y",
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export function buildVegaSpec(
|
||||
specOptions: DistributionChartSpecOptions
|
||||
): VisualizationSpec {
|
||||
let {
|
||||
format = ".9~s",
|
||||
color = "#739ECC",
|
||||
title,
|
||||
minX,
|
||||
maxX,
|
||||
logX,
|
||||
expY,
|
||||
} = specOptions;
|
||||
|
||||
let xScale = logX ? logXScale : linearXScale;
|
||||
if (minX !== undefined) {
|
||||
xScale = { ...xScale, domainMin: minX };
|
||||
}
|
||||
|
||||
if (maxX !== undefined) {
|
||||
xScale = { ...xScale, domainMax: maxX };
|
||||
}
|
||||
|
||||
let spec: VisualizationSpec = {
|
||||
$schema: "https://vega.github.io/schema/vega/v5.json",
|
||||
description: "A basic area chart example",
|
||||
width: 500,
|
||||
height: 100,
|
||||
padding: 5,
|
||||
data: [
|
||||
{
|
||||
name: "con",
|
||||
},
|
||||
{
|
||||
name: "dis",
|
||||
},
|
||||
],
|
||||
signals: [],
|
||||
scales: [xScale, expY ? expYScale : linearYScale],
|
||||
axes: [
|
||||
{
|
||||
orient: "bottom",
|
||||
scale: "xscale",
|
||||
labelColor: "#727d93",
|
||||
tickColor: "#fff",
|
||||
tickOpacity: 0.0,
|
||||
domainColor: "#fff",
|
||||
domainOpacity: 0.0,
|
||||
format: format,
|
||||
tickCount: 10,
|
||||
},
|
||||
],
|
||||
marks: [
|
||||
{
|
||||
type: "area",
|
||||
from: {
|
||||
data: "con",
|
||||
},
|
||||
encode: {
|
||||
update: {
|
||||
interpolate: { value: "linear" },
|
||||
x: {
|
||||
scale: "xscale",
|
||||
field: "x",
|
||||
},
|
||||
y: {
|
||||
scale: "yscale",
|
||||
field: "y",
|
||||
},
|
||||
y2: {
|
||||
scale: "yscale",
|
||||
value: 0,
|
||||
},
|
||||
fill: {
|
||||
value: color,
|
||||
},
|
||||
fillOpacity: {
|
||||
value: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "rect",
|
||||
from: {
|
||||
data: "dis",
|
||||
},
|
||||
encode: {
|
||||
enter: {
|
||||
width: {
|
||||
value: 1,
|
||||
},
|
||||
},
|
||||
update: {
|
||||
x: {
|
||||
scale: "xscale",
|
||||
field: "x",
|
||||
},
|
||||
y: {
|
||||
scale: "yscale",
|
||||
field: "y",
|
||||
},
|
||||
y2: {
|
||||
scale: "yscale",
|
||||
value: 0,
|
||||
},
|
||||
fill: {
|
||||
value: "#2f65a7",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "symbol",
|
||||
from: {
|
||||
data: "dis",
|
||||
},
|
||||
encode: {
|
||||
enter: {
|
||||
shape: {
|
||||
value: "circle",
|
||||
},
|
||||
size: [{ value: 100 }],
|
||||
tooltip: {
|
||||
signal: "datum.y",
|
||||
},
|
||||
},
|
||||
update: {
|
||||
x: {
|
||||
scale: "xscale",
|
||||
field: "x",
|
||||
},
|
||||
y: {
|
||||
scale: "yscale",
|
||||
field: "y",
|
||||
},
|
||||
fill: {
|
||||
value: "#1e4577",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
if (title) {
|
||||
spec = {
|
||||
...spec,
|
||||
title: {
|
||||
text: title,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return spec;
|
||||
}
|
Loading…
Reference in New Issue
Block a user