Might as well show all the FR outcomes now

This commit is contained in:
Marshall Polaris 2022-09-26 23:51:24 -07:00
parent 3e6191af82
commit 875fa24359
2 changed files with 81 additions and 20 deletions

View File

@ -1,6 +1,6 @@
import { useMemo, useRef } from 'react' import { useMemo, useRef } from 'react'
import { sum, sortBy, groupBy } from 'lodash' import { sum, sortBy, groupBy } from 'lodash'
import { scaleTime, scaleLinear, schemeCategory10 } from 'd3' import { scaleTime, scaleLinear } from 'd3'
import { Bet } from 'common/bet' import { Bet } from 'common/bet'
import { FreeResponseContract, MultipleChoiceContract } from 'common/contract' import { FreeResponseContract, MultipleChoiceContract } from 'common/contract'
@ -10,6 +10,64 @@ import { MARGIN_X, MARGIN_Y, getDateRange } from '../helpers'
import { MultiPoint, MultiValueHistoryChart } from '../generic-charts' import { MultiPoint, MultiValueHistoryChart } from '../generic-charts'
import { useElementWidth } from 'web/hooks/use-element-width' import { useElementWidth } from 'web/hooks/use-element-width'
// thanks to https://observablehq.com/@jonhelfman/optimal-orders-for-choosing-categorical-colors
const CATEGORY_COLORS = [
'#00b8dd',
'#eecafe',
'#874c62',
'#6457ca',
'#f773ba',
'#9c6bbc',
'#a87744',
'#af8a04',
'#bff9aa',
'#f3d89d',
'#c9a0f5',
'#ff00e5',
'#9dc6f7',
'#824475',
'#d973cc',
'#bc6808',
'#056e70',
'#677932',
'#00b287',
'#c8ab6c',
'#a2fb7a',
'#f8db68',
'#14675a',
'#8288f4',
'#fe1ca0',
'#ad6aff',
'#786306',
'#9bfbaf',
'#b00cf7',
'#2f7ec5',
'#4b998b',
'#42fa0e',
'#5b80a1',
'#962d9d',
'#3385ff',
'#48c5ab',
'#b2c873',
'#4cf9a4',
'#00ffff',
'#3cca73',
'#99ae17',
'#7af5cf',
'#52af45',
'#fbb80f',
'#29971b',
'#187c9a',
'#00d539',
'#bbfa1a',
'#61f55c',
'#cabc03',
'#ff9000',
'#779100',
'#bcfd6f',
'#70a560',
]
const getMultiChartData = ( const getMultiChartData = (
contract: FreeResponseContract | MultipleChoiceContract, contract: FreeResponseContract | MultipleChoiceContract,
bets: Bet[], bets: Bet[],
@ -22,12 +80,8 @@ const getMultiChartData = (
const sortedBets = sortBy(bets, (b) => b.createdTime) const sortedBets = sortBy(bets, (b) => b.createdTime)
const betsByOutcome = groupBy(sortedBets, (bet) => bet.outcome) const betsByOutcome = groupBy(sortedBets, (bet) => bet.outcome)
const validAnswers = answers.filter((answer) => { const validAnswers = answers.filter((answer) => {
const maxProb = Math.max(
...betsByOutcome[answer.id].map((bet) => bet.probAfter)
)
return ( return (
(answer.id !== '0' || outcomeType === 'MULTIPLE_CHOICE') && (answer.id !== '0' || outcomeType === 'MULTIPLE_CHOICE') &&
maxProb > 0.02 &&
totalBets[answer.id] > 0.000000001 totalBets[answer.id] > 0.000000001
) )
}) })
@ -82,7 +136,7 @@ export const ChoiceContractChart = (props: {
const { contract, bets } = props const { contract, bets } = props
const [start, end] = useMemo(() => getDateRange(contract), [contract]) const [start, end] = useMemo(() => getDateRange(contract), [contract])
const data = useMemo( const data = useMemo(
() => getMultiChartData(contract, bets, start, end, 6), () => getMultiChartData(contract, bets, start, end, CATEGORY_COLORS.length),
[contract, bets, start, end] [contract, bets, start, end]
) )
const isMobile = useIsMobile(800) const isMobile = useIsMobile(800)
@ -100,7 +154,7 @@ export const ChoiceContractChart = (props: {
xScale={xScale} xScale={xScale}
yScale={yScale} yScale={yScale}
data={data.points} data={data.points}
colors={schemeCategory10} colors={CATEGORY_COLORS}
labels={data.labels} labels={data.labels}
pct pct
/> />

View File

@ -13,7 +13,7 @@ import {
ScaleContinuousNumeric, ScaleContinuousNumeric,
SeriesPoint, SeriesPoint,
} from 'd3' } from 'd3'
import { range } from 'lodash' import { range, sortBy } from 'lodash'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { import {
@ -203,7 +203,7 @@ export const MultiValueHistoryChart = (props: {
const py1 = useCallback((p: SP) => yScale(p[1]), [yScale]) const py1 = useCallback((p: SP) => yScale(p[1]), [yScale])
const xBisector = bisector((p: MultiPoint) => p[0]) const xBisector = bisector((p: MultiPoint) => p[0])
const { fmtX, fmtY, xAxis, yAxis, series } = useMemo(() => { const { fmtX, fmtY, xAxis, yAxis } = useMemo(() => {
const [start, end] = xScale.domain() const [start, end] = xScale.domain()
const fmtX = getFormatterForDateRange(start, end) const fmtX = getFormatterForDateRange(start, end)
const fmtY = (n: number) => (pct ? formatPct(n, 0) : formatLargeNumber(n)) const fmtY = (n: number) => (pct ? formatPct(n, 0) : formatLargeNumber(n))
@ -215,13 +215,16 @@ export const MultiValueHistoryChart = (props: {
.tickValues(tickValues) .tickValues(tickValues)
.tickFormat(fmtY) .tickFormat(fmtY)
return { fmtX, fmtY, xAxis, yAxis }
}, [h, pct, xScale, yScale])
const series = useMemo(() => {
const d3Stack = stack<MultiPoint, number>() const d3Stack = stack<MultiPoint, number>()
.keys(range(0, labels.length)) .keys(range(0, labels.length))
.value(([_date, probs], o) => probs[o]) .value(([_date, probs], o) => probs[o])
.order(stackOrderReverse) .order(stackOrderReverse)
const series = d3Stack(data) return d3Stack(data)
return { fmtX, fmtY, xAxis, yAxis, series } }, [data, labels.length])
}, [h, pct, xScale, yScale, data, labels.length])
const onSelect = useEvent((ev: D3BrushEvent<MultiPoint>) => { const onSelect = useEvent((ev: D3BrushEvent<MultiPoint>) => {
if (ev.selection) { if (ev.selection) {
@ -247,19 +250,23 @@ export const MultiValueHistoryChart = (props: {
setMouseState(undefined) setMouseState(undefined)
}) })
const mouseProbs = mouseState?.p[1] ?? []
const legendItems = sortBy(
mouseProbs.map((p, i) => ({
color: colors[i],
label: labels[i],
value: fmtY(p),
p,
})),
(item) => -item.p
).slice(0, 10)
return ( return (
<div className="relative"> <div className="relative">
{mouseState && ( {mouseState && (
<ChartTooltip {...mouseState}> <ChartTooltip {...mouseState}>
{fmtX(mouseState.p[0])} {fmtX(mouseState.p[0])}
<Legend <Legend className="text-sm" items={legendItems} />
className="text-sm"
items={mouseState.p[1].map((p, i) => ({
color: colors[i],
label: labels[i],
value: fmtY(p),
}))}
/>
</ChartTooltip> </ChartTooltip>
)} )}
<SVGChart <SVGChart