From c7221d10264cb0cef2234b3d6f6316d7e02d5a3f Mon Sep 17 00:00:00 2001 From: Marshall Polaris Date: Wed, 28 Sep 2022 19:19:17 -0700 Subject: [PATCH] Use objects instead of tuples for chart data --- web/components/charts/contract/binary.tsx | 13 +++--- web/components/charts/contract/choice.tsx | 20 ++++----- web/components/charts/contract/numeric.tsx | 17 ++++--- .../charts/contract/pseudo-numeric.tsx | 13 +++--- web/components/charts/generic-charts.tsx | 44 +++++++++---------- 5 files changed, 54 insertions(+), 53 deletions(-) diff --git a/web/components/charts/contract/binary.tsx b/web/components/charts/contract/binary.tsx index aa79c354..d640dacb 100644 --- a/web/components/charts/contract/binary.tsx +++ b/web/components/charts/contract/binary.tsx @@ -17,9 +17,10 @@ import { SingleValueHistoryChart } from '../generic-charts' import { useElementWidth } from 'web/hooks/use-element-width' const getBetPoints = (bets: Bet[]) => { - return sortBy(bets, (b) => b.createdTime).map( - (b) => [new Date(b.createdTime), b.probAfter] as const - ) + return sortBy(bets, (b) => b.createdTime).map((b) => ({ + x: new Date(b.createdTime), + y: b.probAfter, + })) } export const BinaryContractChart = (props: { @@ -34,16 +35,16 @@ export const BinaryContractChart = (props: { const betPoints = useMemo(() => getBetPoints(bets), [bets]) const data = useMemo( () => [ - [startDate, startP] as const, + { x: startDate, y: startP }, ...betPoints, - [endDate ?? MAX_DATE, endP] as const, + { x: endDate ?? MAX_DATE, y: endP }, ], [startDate, startP, endDate, endP, betPoints] ) const rightmostDate = getRightmostVisibleDate( endDate, - last(betPoints)?.[0], + last(betPoints)?.x, new Date(Date.now()) ) const visibleRange = [startDate, rightmostDate] diff --git a/web/components/charts/contract/choice.tsx b/web/components/charts/contract/choice.tsx index 56ab018e..ffe6d979 100644 --- a/web/components/charts/contract/choice.tsx +++ b/web/components/charts/contract/choice.tsx @@ -93,7 +93,7 @@ const getTrackedAnswers = ( } const getStartPoint = (answers: Answer[], start: Date) => { - return [start, answers.map((_) => 0)] as const + return { x: start, y: answers.map((_) => 0) } } const getEndPoint = ( @@ -101,10 +101,10 @@ const getEndPoint = ( contract: FreeResponseContract | MultipleChoiceContract, end: Date ) => { - return [ - end, - answers.map((a) => getOutcomeProbability(contract, a.id)), - ] as const + return { + x: end, + y: answers.map((a) => getOutcomeProbability(contract, a.id)), + } } const getBetPoints = (answers: Answer[], bets: Bet[]) => { @@ -121,10 +121,10 @@ const getBetPoints = (answers: Answer[], bets: Bet[]) => { const sharesSquared = sum( Object.values(sharesByOutcome).map((shares) => shares ** 2) ) - points.push([ - new Date(bet.createdTime), - answers.map((answer) => sharesByOutcome[answer.id] ** 2 / sharesSquared), - ]) + points.push({ + x: new Date(bet.createdTime), + y: answers.map((a) => sharesByOutcome[a.id] ** 2 / sharesSquared), + }) } return points } @@ -151,7 +151,7 @@ export const ChoiceContractChart = (props: { ) const rightmostDate = getRightmostVisibleDate( contractEnd, - last(betPoints)?.[0], + last(betPoints)?.x, new Date(Date.now()) ) const visibleRange = [contractStart, rightmostDate] diff --git a/web/components/charts/contract/numeric.tsx b/web/components/charts/contract/numeric.tsx index d19147f6..bcd15afa 100644 --- a/web/components/charts/contract/numeric.tsx +++ b/web/components/charts/contract/numeric.tsx @@ -1,5 +1,5 @@ import { useMemo, useRef } from 'react' -import { max, range } from 'lodash' +import { range } from 'lodash' import { scaleLinear } from 'd3-scale' import { getDpmOutcomeProbabilities } from 'common/calculate-dpm' @@ -14,9 +14,10 @@ const getNumericChartData = (contract: NumericContract) => { const { totalShares, bucketCount, min, max } = contract const step = (max - min) / bucketCount const bucketProbs = getDpmOutcomeProbabilities(totalShares) - return range(bucketCount).map( - (i) => [min + step * (i + 0.5), bucketProbs[`${i}`]] as const - ) + return range(bucketCount).map((i) => ({ + x: min + step * (i + 0.5), + y: bucketProbs[`${i}`], + })) } export const NumericContractChart = (props: { @@ -24,16 +25,14 @@ export const NumericContractChart = (props: { height?: number }) => { const { contract } = props + const { min, max } = contract const data = useMemo(() => getNumericChartData(contract), [contract]) const isMobile = useIsMobile(800) const containerRef = useRef(null) const width = useElementWidth(containerRef) ?? 0 const height = props.height ?? (isMobile ? 150 : 250) - const maxY = max(data.map((d) => d[1])) as number - const xScale = scaleLinear( - [contract.min, contract.max], - [0, width - MARGIN_X] - ) + const maxY = Math.max(...data.map((d) => d.y)) + const xScale = scaleLinear([min, max], [0, width - MARGIN_X]) const yScale = scaleLinear([0, maxY], [height - MARGIN_Y, 0]) return (
diff --git a/web/components/charts/contract/pseudo-numeric.tsx b/web/components/charts/contract/pseudo-numeric.tsx index 2b23eb4d..43fa8d15 100644 --- a/web/components/charts/contract/pseudo-numeric.tsx +++ b/web/components/charts/contract/pseudo-numeric.tsx @@ -29,9 +29,10 @@ const getScaleP = (min: number, max: number, isLogScale: boolean) => { } const getBetPoints = (bets: Bet[], scaleP: (p: number) => number) => { - return sortBy(bets, (b) => b.createdTime).map( - (b) => [new Date(b.createdTime), scaleP(b.probAfter)] as const - ) + return sortBy(bets, (b) => b.createdTime).map((b) => ({ + x: new Date(b.createdTime), + y: scaleP(b.probAfter), + })) } export const PseudoNumericContractChart = (props: { @@ -51,15 +52,15 @@ export const PseudoNumericContractChart = (props: { const betPoints = useMemo(() => getBetPoints(bets, scaleP), [bets, scaleP]) const data = useMemo( () => [ - [startDate, startP] as const, + { x: startDate, y: startP }, ...betPoints, - [endDate ?? MAX_DATE, endP] as const, + { x: endDate ?? MAX_DATE, y: endP }, ], [betPoints, startDate, startP, endDate, endP] ) const rightmostDate = getRightmostVisibleDate( endDate, - last(betPoints)?.[0], + last(betPoints)?.x, new Date(Date.now()) ) const visibleRange = [startDate, rightmostDate] diff --git a/web/components/charts/generic-charts.tsx b/web/components/charts/generic-charts.tsx index 0d262e17..fc540226 100644 --- a/web/components/charts/generic-charts.tsx +++ b/web/components/charts/generic-charts.tsx @@ -25,9 +25,9 @@ import { formatLargeNumber } from 'common/util/format' import { useEvent } from 'web/hooks/use-event' import { Row } from 'web/components/layout/row' -export type MultiPoint = readonly [Date, number[]] // [time, [ordered outcome probs]] -export type HistoryPoint = readonly [Date, number] // [time, number or percentage] -export type DistributionPoint = readonly [number, number] // [outcome amount, prob] +export type MultiPoint = { x: Date; y: number[] } +export type HistoryPoint = { x: Date; y: number } +export type DistributionPoint = { x: number; y: number } export type PositionValue

= TooltipPosition & { p: P } const formatPct = (n: number, digits?: number) => { @@ -118,10 +118,10 @@ export const SingleValueDistributionChart = (props: { useState>() const xScale = viewXScale ?? props.xScale - const px = useCallback((p: DistributionPoint) => xScale(p[0]), [xScale]) + const px = useCallback((p: DistributionPoint) => xScale(p.x), [xScale]) const py0 = yScale(yScale.domain()[0]) - const py1 = useCallback((p: DistributionPoint) => yScale(p[1]), [yScale]) - const xBisector = bisector((p: DistributionPoint) => p[0]) + const py1 = useCallback((p: DistributionPoint) => yScale(p.y), [yScale]) + const xBisector = bisector((p: DistributionPoint) => p.x) const { fmtX, fmtY, xAxis, yAxis } = useMemo(() => { const fmtX = (n: number) => formatLargeNumber(n) @@ -154,8 +154,8 @@ export const SingleValueDistributionChart = (props: { // so your queryX is out of bounds return } - const [_x, y] = item - setMouseState({ top: mouseY - 10, left: mouseX + 60, p: [queryX, y] }) + const p = { x: queryX, y: item.y } + setMouseState({ top: mouseY - 10, left: mouseX + 60, p }) } }) @@ -167,7 +167,7 @@ export const SingleValueDistributionChart = (props: {

{mouseState && ( - {fmtY(mouseState.p[1])} {fmtX(mouseState.p[0])} + {fmtY(mouseState.p.y)} {fmtX(mouseState.p.x)} )} - const px = useCallback((p: SP) => xScale(p.data[0]), [xScale]) + const px = useCallback((p: SP) => xScale(p.data.x), [xScale]) const py0 = useCallback((p: SP) => yScale(p[0]), [yScale]) const py1 = useCallback((p: SP) => yScale(p[1]), [yScale]) - const xBisector = bisector((p: MultiPoint) => p[0]) + const xBisector = bisector((p: MultiPoint) => p.x) const { fmtX, fmtY, xAxis, yAxis } = useMemo(() => { const [start, end] = xScale.domain() @@ -232,7 +232,7 @@ export const MultiValueHistoryChart = (props: { const series = useMemo(() => { const d3Stack = stack() .keys(range(0, labels.length)) - .value(([_date, probs], o) => probs[o]) + .value(({ y }, o) => y[o]) .order(stackOrderReverse) return d3Stack(data) }, [data, labels.length]) @@ -260,8 +260,8 @@ export const MultiValueHistoryChart = (props: { // so your queryX is out of bounds return } - const [_x, ys] = item - setMouseState({ top: mouseY - 10, left: mouseX + 60, p: [queryX, ys] }) + const p = { x: queryX, y: item.y } + setMouseState({ top: mouseY - 10, left: mouseX + 60, p }) } }) @@ -269,7 +269,7 @@ export const MultiValueHistoryChart = (props: { setMouseState(undefined) }) - const mouseProbs = mouseState?.p[1] ?? [] + const mouseProbs = mouseState?.p.y ?? [] const legendItems = sortBy( mouseProbs.map((p, i) => ({ color: colors[i], @@ -284,7 +284,7 @@ export const MultiValueHistoryChart = (props: {
{mouseState && ( - {fmtX(mouseState.p[0])} + {fmtX(mouseState.p.x)} )} @@ -328,10 +328,10 @@ export const SingleValueHistoryChart = (props: { const [mouseState, setMouseState] = useState>() const xScale = viewXScale ?? props.xScale - const px = useCallback((p: HistoryPoint) => xScale(p[0]), [xScale]) + const px = useCallback((p: HistoryPoint) => xScale(p.x), [xScale]) const py0 = yScale(yScale.domain()[0]) - const py1 = useCallback((p: HistoryPoint) => yScale(p[1]), [yScale]) - const xBisector = bisector((p: HistoryPoint) => p[0]) + const py1 = useCallback((p: HistoryPoint) => yScale(p.y), [yScale]) + const xBisector = bisector((p: HistoryPoint) => p.x) const { fmtX, fmtY, xAxis, yAxis } = useMemo(() => { const [start, end] = xScale.domain() @@ -370,8 +370,8 @@ export const SingleValueHistoryChart = (props: { // so your queryX is out of bounds return } - const [_x, y] = item - setMouseState({ top: mouseY - 10, left: mouseX + 60, p: [queryX, y] }) + const p = { x: queryX, y: item.y } + setMouseState({ top: mouseY - 10, left: mouseX + 60, p }) } }) @@ -383,7 +383,7 @@ export const SingleValueHistoryChart = (props: {
{mouseState && ( - {fmtY(mouseState.p[1])} {fmtX(mouseState.p[0])} + {fmtY(mouseState.p.y)} {fmtX(mouseState.p.x)} )}