Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tags for x scale #2828

Draft
wants to merge 10 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 34 additions & 90 deletions packages/components/src/components/PlaygroundSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ import React from "react";
import { z } from "zod";

import { SqScale } from "@quri/squiggle-lang";
import { CheckboxFormField, NumberFormField, RadioFormField } from "@quri/ui";
import { CheckboxFormField, NumberFormField } from "@quri/ui";

import { SAMPLE_COUNT_MAX, SAMPLE_COUNT_MIN } from "../lib/constants.js";
import { functionChartDefaults } from "../widgets/LambdaWidget/FunctionChart/utils.js";
import { FormComment } from "./ui/FormComment.js";
import { FormSection } from "./ui/FormSection.js";
import { SqDistributionValue } from "../../../squiggle-lang/src/public/SqValue/index.js";

export const environmentSchema = z.object({
sampleCount: z.number().int().gte(SAMPLE_COUNT_MIN).lte(SAMPLE_COUNT_MAX),
Expand All @@ -31,28 +32,9 @@ const scaleSchema = z.union([
z.literal("exp"),
]);

type ScaleType = z.infer<typeof scaleSchema>;

function scaleTypeToSqScale(
scaleType: ScaleType,
args: { min?: number; max?: number; tickFormat?: string } = {}
) {
switch (scaleType) {
case "linear":
case "log":
case "symlog":
return new SqScale({ method: { type: scaleType }, ...args });
case "exp":
return new SqScale({ method: { type: "power" }, ...args });
default:
// should never happen, just a precaution
throw new Error("Internal error");
}
}

export const distributionSettingsSchema = z.object({
xScale: scaleSchema,
yScale: scaleSchema,
xScale: scaleSchema.optional(),
yScale: scaleSchema.optional(),
minX: z.number().optional(),
maxX: z.number().optional(),
title: z.string().optional(),
Expand Down Expand Up @@ -82,8 +64,6 @@ export const defaultPlaygroundSettings: PlaygroundSettings = {
count: functionChartDefaults.points,
},
distributionChartSettings: {
xScale: "linear",
yScale: "linear",
showSummary: true,
},
editorSettings: {
Expand All @@ -101,18 +81,35 @@ export type PartialPlaygroundSettings = DeepPartial<PlaygroundSettings>;

// partial params for SqDistributionsPlot.create; TODO - infer explicit type?
export function generateDistributionPlotSettings(
settings: z.infer<typeof distributionSettingsSchema>,
xTickFormat?: string
dist: SqDistributionValue,
settings: z.infer<typeof distributionSettingsSchema>
) {
const xScale = scaleTypeToSqScale(settings.xScale, {
min: settings.minX,
max: settings.maxX,
tickFormat: xTickFormat,
});
const yScale = scaleTypeToSqScale(settings.yScale);
const defaultDist = dist.defaultPlot();
function convertScaleType(
scaleType: "linear" | "log" | "symlog" | "exp"
): "linear" | "log" | "symlog" | "power" {
return scaleType === "exp" ? "power" : scaleType;
}

const _xScale = defaultDist.xScale.merge(
new SqScale({
method: settings.xScale
? { type: convertScaleType(settings.xScale) }
: undefined,
min: settings.minX,
max: settings.maxX,
})
);
const _yScale = defaultDist.yScale.merge(
new SqScale({
method: settings.yScale
? { type: convertScaleType(settings.yScale) }
: undefined,
})
);
return {
xScale,
yScale,
xScale: _xScale,
yScale: _yScale,
showSummary: settings.showSummary,
title: settings.title,
};
Expand All @@ -138,62 +135,14 @@ export const EnvironmentForm: React.FC = () => (
</div>
);

export const DistributionSettingsForm: React.FC<{
metaSettings?: MetaSettings;
}> = ({ metaSettings }) => {
export const DistributionSettingsForm: React.FC = () => {
return (
<FormSection title="Distribution Display Settings">
<div className="space-y-4">
<CheckboxFormField<PlaygroundSettings>
name="distributionChartSettings.showSummary"
label="Show summary statistics"
/>
<RadioFormField<PlaygroundSettings>
name="distributionChartSettings.xScale"
label="X Scale"
options={[
{
id: "linear",
name: "Linear",
},
{
id: "log",
name: "Logarithmic",
...(metaSettings?.disableLogX
? {
disabled: true,
tooltip:
"Your distribution has mass lower than or equal to 0. Log only works on strictly positive values.",
}
: null),
},
{
id: "symlog",
name: "Symlog",
tooltip:
"Almost logarithmic scale that supports negative values.",
},
{
id: "exp",
name: "Exponential",
},
]}
/>
<RadioFormField<PlaygroundSettings>
name="distributionChartSettings.yScale"
label="Y Scale"
options={[
{
id: "linear",
name: "Linear",
},
// log Y is hidden because it almost always causes an empty chart
{
id: "exp",
name: "Exponential",
},
]}
/>
<NumberFormField<PlaygroundSettings>
name="distributionChartSettings.minX"
label="Min X Value"
Expand Down Expand Up @@ -250,12 +199,7 @@ export const EditorSettingsForm: React.FC = () => {
export const PlaygroundSettingsForm: React.FC<{
withFunctionSettings?: boolean;
withGlobalSettings?: boolean;
metaSettings?: MetaSettings;
}> = ({
withGlobalSettings = true,
withFunctionSettings = true,
metaSettings,
}) => {
}> = ({ withGlobalSettings = true, withFunctionSettings = true }) => {
return (
<div className="divide-y divide-gray-200 max-w-2xl">
{withGlobalSettings && (
Expand All @@ -278,7 +222,7 @@ export const PlaygroundSettingsForm: React.FC<{
)}

<div className="pt-6 mb-6">
<DistributionSettingsForm metaSettings={metaSettings} />
<DistributionSettingsForm />
</div>

{withFunctionSettings ? (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,7 @@ type Props = {
withFunctionSettings: boolean;
};

const ItemSettingsModal: FC<Props> = ({
value,
metaSettings,
withFunctionSettings,
}) => {
const ItemSettingsModal: FC<Props> = ({ value, withFunctionSettings }) => {
const close = useCloseDropdown();
const setLocalItemState = useSetLocalItemState();

Expand Down Expand Up @@ -94,7 +90,6 @@ const ItemSettingsModal: FC<Props> = ({
<PlaygroundSettingsForm
withGlobalSettings={false}
withFunctionSettings={withFunctionSettings}
metaSettings={metaSettings}
/>
</FormProvider>
</Modal.Body>
Expand Down
26 changes: 16 additions & 10 deletions packages/components/src/stories/SquigglePlayground.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -291,15 +291,21 @@ export const Tagged: Story = {
args: {
defaultCode: `z = 34 -> Tag.format(".1f")

@name("My favorite Dist")
@doc("This is a long description")
@format("$.2")
x = 5 to 10

@showAs(Plot.numericFn)
@name("My favorite Fn")
fn = {|e| e}

y = x -> Tag.all`,
@name("My favorite Dist")
@doc("This is a long description")
@format("$.2")
x = 5 to 10

@showAs(Plot.numericFn)
@name("My favorite Fn")
fn = {|e| e}

@format("$.2f")
withFormat = 4 to 100

@xScale(Scale.log())
withXScale = 4 to 100

y = x -> Tag.getAll`,
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -555,7 +555,7 @@ export const DistributionsChart: FC<DistributionsChartProps> = ({
return (
<DistProvider generateInitialValue={() => ({})}>
{plot.title && <PlotTitle title={plot.title} />}
{hasLogError && (
{hasLogError && nonTitleHeight > 30 && (
<ErrorAlert heading="Log Domain Error">
Cannot graph distribution with negative values on logarithmic scale.
</ErrorAlert>
Expand Down
20 changes: 7 additions & 13 deletions packages/components/src/widgets/DistWidget/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { SqDistributionsPlot, SqScale } from "@quri/squiggle-lang";
import { SqDistributionsPlot } from "@quri/squiggle-lang";

import { NumberShower } from "../../components/NumberShower.js";
import { generateDistributionPlotSettings } from "../../components/PlaygroundSettings.js";
Expand Down Expand Up @@ -31,13 +31,7 @@ widgetRegistry.register("Dist", {
const p95 = unwrapOrFailure(dist.inv(environment, 0.95));
const oneValue = p05 === p95;

const distPlot = value.showAsPlot();
const plot = SqDistributionsPlot.create({
distribution: value.value,
showSummary: false,
xScale: distPlot?.xScale ?? SqScale.linearDefault(),
yScale: distPlot?.yScale ?? SqScale.linearDefault(),
});
const plot = value.defaultPlot().setShowSummary(false);
return oneValue ? (
showNumber(p05)
) : (
Expand Down Expand Up @@ -71,13 +65,13 @@ widgetRegistry.register("Dist", {
);
},
Chart(value, settings) {
const numberFormat = value.tags.numberFormat();
const defaults = generateDistributionPlotSettings(
value,
settings.distributionChartSettings
);
const plot = SqDistributionsPlot.create({
distribution: value.value,
...generateDistributionPlotSettings(
settings.distributionChartSettings,
numberFormat
),
...defaults,
});

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,20 @@ import {
SqDomain,
SqError,
SqLambda,
SqLambdaValue,
SqNumericFnPlot,
SqNumericRangeDomain,
SqScale,
} from "@quri/squiggle-lang";

import { MessageAlert } from "../../../components/Alert.js";
import { ErrorBoundary } from "../../../components/ErrorBoundary.js";
import {
generateDistributionPlotSettings,
PlaygroundSettings,
} from "../../../components/PlaygroundSettings.js";
import { PlaygroundSettings } from "../../../components/PlaygroundSettings.js";
import { SquiggleErrorAlert } from "../../../components/SquiggleErrorAlert.js";
import { DistFunctionChart } from "./DistFunctionChart.js";
import { NumericFunctionChart } from "./NumericFunctionChart.js";

type AutomaticFunctionChartProps = {
fn: SqLambda;
fn: SqLambdaValue;
settings: PlaygroundSettings;
environment: Env;
height: number;
Expand Down Expand Up @@ -73,7 +70,7 @@ export const AutomaticFunctionChart: FC<AutomaticFunctionChartProps> = ({
environment,
height,
}) => {
const parameters = fn.parameterCounts();
const parameters = fn.value.parameterCounts();
if (!parameters.includes(1)) {
return (
<MessageAlert heading="Function Display Not Supported">
Expand All @@ -86,31 +83,33 @@ export const AutomaticFunctionChart: FC<AutomaticFunctionChartProps> = ({
const max: number = settings.functionChartSettings.stop;
const xCount: number = settings.functionChartSettings.count;

const includedDomain = fn.signatures().find((s) => s.length === 1)?.[0]
const includedDomain = fn.value.signatures().find((s) => s.length === 1)?.[0]
?.domain;

const xDomain = includedDomain
? includedDomain
: SqNumericRangeDomain.fromMinMax(min, max);

const inferredOutputType = getInferredFnOutputType(xDomain, fn, environment);
const inferredOutputType = getInferredFnOutputType(
xDomain,
fn.value,
environment
);

if (!inferredOutputType.ok) {
return <FunctionCallErrorAlert error={inferredOutputType.value} />;
}

const yScale = SqScale.linearDefault();
const xScale = xDomain.toDefaultScale();
const yScale = fn.defaultYScale();
const xScale = fn.defaultXScale();

switch (inferredOutputType.value) {
case "Dist": {
const plot = SqDistFnPlot.create({
fn,
fn: fn.value,
xScale,
yScale,
distXScale: generateDistributionPlotSettings(
settings.distributionChartSettings
).xScale,
distXScale: yScale,
});

return (
Expand All @@ -124,9 +123,9 @@ export const AutomaticFunctionChart: FC<AutomaticFunctionChartProps> = ({
}
case "Number": {
const plot = SqNumericFnPlot.create({
fn,
fn: fn.value,
xScale,
yScale: SqScale.linearDefault(),
yScale,
});

return (
Expand Down
2 changes: 1 addition & 1 deletion packages/components/src/widgets/LambdaWidget/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ widgetRegistry.register("Lambda", {
}
return (
<AutomaticFunctionChart
fn={value.value}
fn={value}
settings={settings}
height={settings.chartHeight}
environment={{
Expand Down
Loading
Loading