Update simulator to nivo chart. Remove chart.js

This commit is contained in:
jahooma 2021-12-12 19:50:17 -06:00
parent d32d929735
commit 54571b29de
3 changed files with 134 additions and 168 deletions

31
web/package-lock.json generated
View File

@ -8,15 +8,13 @@
"dependencies": {
"@headlessui/react": "1.4.2",
"@heroicons/react": "1.0.5",
"@nivo/core": "^0.74.0",
"@nivo/line": "^0.74.0",
"chart.js": "3.6.1",
"@nivo/core": "0.74.0",
"@nivo/line": "0.74.0",
"clsx": "1.1.1",
"daisyui": "1.16.4",
"firebase": "9.6.0",
"next": "12.0.4",
"react": "17.0.2",
"react-chartjs-2": "4.0.0",
"react-dom": "17.0.2"
},
"devDependencies": {
@ -3045,11 +3043,6 @@
"node": ">=4"
}
},
"node_modules/chart.js": {
"version": "3.6.1",
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.6.1.tgz",
"integrity": "sha512-AycnixR0I325Fp3bqQ7wRJbkIJPwz/9IZtUBvdBWMjK5+nKCy6FZ3VejkDTtB9udePEXNt1UYoGTsNL49JoIbg=="
},
"node_modules/chokidar": {
"version": "3.5.1",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz",
@ -6540,15 +6533,6 @@
"node": ">=0.10.0"
}
},
"node_modules/react-chartjs-2": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-4.0.0.tgz",
"integrity": "sha512-0kx41EVO6wIoeU6zvdwovX9kKcdrs7O62DGTSNmwAXZeLGJ3U+n4XijO1kxcMmAi4I6PQJWGD5oRwxVixHSp6g==",
"peerDependencies": {
"chart.js": "^3.5.0",
"react": "^16.8.0 || ^17.0.0"
}
},
"node_modules/react-dom": {
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz",
@ -10207,11 +10191,6 @@
"supports-color": "^5.3.0"
}
},
"chart.js": {
"version": "3.6.1",
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.6.1.tgz",
"integrity": "sha512-AycnixR0I325Fp3bqQ7wRJbkIJPwz/9IZtUBvdBWMjK5+nKCy6FZ3VejkDTtB9udePEXNt1UYoGTsNL49JoIbg=="
},
"chokidar": {
"version": "3.5.1",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz",
@ -12894,12 +12873,6 @@
"object-assign": "^4.1.1"
}
},
"react-chartjs-2": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-4.0.0.tgz",
"integrity": "sha512-0kx41EVO6wIoeU6zvdwovX9kKcdrs7O62DGTSNmwAXZeLGJ3U+n4XijO1kxcMmAi4I6PQJWGD5oRwxVixHSp6g==",
"requires": {}
},
"react-dom": {
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz",

View File

@ -11,15 +11,13 @@
"dependencies": {
"@headlessui/react": "1.4.2",
"@heroicons/react": "1.0.5",
"@nivo/core": "^0.74.0",
"@nivo/line": "^0.74.0",
"chart.js": "3.6.1",
"@nivo/core": "0.74.0",
"@nivo/line": "0.74.0",
"clsx": "1.1.1",
"daisyui": "1.16.4",
"firebase": "9.6.0",
"next": "12.0.4",
"react": "17.0.2",
"react-chartjs-2": "4.0.0",
"react-dom": "17.0.2"
},
"devDependencies": {

View File

@ -1,31 +1,10 @@
import React, { useEffect, useMemo, useState } from 'react'
import { Line } from 'react-chartjs-2'
import {
CategoryScale,
Chart,
LinearScale,
PointElement,
LineElement,
Title,
Tooltip,
Legend,
} from 'chart.js'
import React, { useMemo, useState } from 'react'
import { DatumValue } from '@nivo/core'
import { ResponsiveLine } from '@nivo/line'
import { Entry, makeEntries } from '../../lib/simulator/entries'
import { Header } from '../../components/header'
// Auto import doesn't work for some reason...
// So we manually register ChartJS components instead:
Chart.register(
CategoryScale,
LinearScale,
PointElement,
LineElement,
Title,
Tooltip,
Legend
)
function TableBody(props: { entries: Entry[] }) {
return (
<tbody>
@ -74,17 +53,19 @@ function TableRowStart(props: { entry: Entry }) {
}
}
function TableRowEnd(props: { entry: Entry | null, isNew?: boolean }) {
function TableRowEnd(props: { entry: Entry | null; isNew?: boolean }) {
const { entry } = props
if (!entry) {
return (
<>
<td>0</td>
<td>0</td>
{!props.isNew && <>
<td>N/A</td>
<td>N/A</td>
</>}
{!props.isNew && (
<>
<td>N/A</td>
<td>N/A</td>
</>
)}
</>
)
} else if (entry.yesBid && entry.noBid) {
@ -92,10 +73,12 @@ function TableRowEnd(props: { entry: Entry | null, isNew?: boolean }) {
<>
<td>{(entry.prob * 100).toFixed(1)}%</td>
<td>N/A</td>
{!props.isNew && <>
<td>N/A</td>
<td>N/A</td>
</>}
{!props.isNew && (
<>
<td>N/A</td>
<td>N/A</td>
</>
)}
</>
)
} else if (entry.yesBid) {
@ -103,10 +86,12 @@ function TableRowEnd(props: { entry: Entry | null, isNew?: boolean }) {
<>
<td>{(entry.prob * 100).toFixed(1)}%</td>
<td>${(entry.yesBid + entry.yesWeight).toFixed(0)}</td>
{!props.isNew && <>
<td>${entry.yesPayout.toFixed(0)}</td>
<td>{(entry.yesReturn * 100).toFixed(0)}%</td>
</>}
{!props.isNew && (
<>
<td>${entry.yesPayout.toFixed(0)}</td>
<td>{(entry.yesReturn * 100).toFixed(0)}%</td>
</>
)}
</>
)
} else {
@ -114,10 +99,12 @@ function TableRowEnd(props: { entry: Entry | null, isNew?: boolean }) {
<>
<td>{(entry.prob * 100).toFixed(1)}%</td>
<td>${(entry.noBid + entry.noWeight).toFixed(0)}</td>
{!props.isNew && <>
<td>${entry.noPayout.toFixed(0)}</td>
<td>{(entry.noReturn * 100).toFixed(0)}%</td>
</>}
{!props.isNew && (
<>
<td>${entry.noPayout.toFixed(0)}</td>
<td>{(entry.noReturn * 100).toFixed(0)}%</td>
</>
)}
</>
)
}
@ -150,8 +137,6 @@ function NewBidTable(props: {
setNewBid(0)
}
function toggleBidType() {
setNewBidType(newBidType === 'YES' ? 'NO' : 'YES')
}
@ -162,9 +147,7 @@ function NewBidTable(props: {
const nextEntry = entries[entries.length - 1]
function randomBid() {
const bidType = Math.random() < 0.5
? 'YES'
: 'NO'
const bidType = Math.random() < 0.5 ? 'YES' : 'NO'
const amount = Math.round(Math.random() * 500)
const bid = makeBid(bidType, amount)
@ -174,86 +157,81 @@ function NewBidTable(props: {
setNewBid(0)
}
return <>
<table className="table table-compact my-8 w-full text-center">
<thead>
<tr>
<th>Order #</th>
<th>Type</th>
<th>Bet</th>
<th>Prob</th>
<th>Est Payout</th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<th>{steps + 1}</th>
<td>
<div
className={
`badge hover:cursor-pointer ` +
(newBidType == 'YES' ? 'badge-success' : 'badge-ghost')
}
onClick={toggleBidType}
>
YES
</div>
<br />
<div
className={
`badge hover:cursor-pointer ` +
(newBidType == 'NO' ? 'badge-error' : 'badge-ghost')
}
onClick={toggleBidType}
>
NO
</div>
</td>
<td>
{/* Note: Would love to make this input smaller... */}
<input
type="number"
placeholder="0"
className="input input-bordered"
style={{ maxWidth: 100 }}
value={newBid.toString()}
onChange={(e) => setNewBid(parseInt(e.target.value) || 0)}
onKeyUp={(e) => {
if (e.key === 'Enter') {
submitBid()
return (
<>
<table className="table table-compact my-8 w-full text-center">
<thead>
<tr>
<th>Order #</th>
<th>Type</th>
<th>Bet</th>
<th>Prob</th>
<th>Est Payout</th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<th>{steps + 1}</th>
<td>
<div
className={
`badge hover:cursor-pointer ` +
(newBidType == 'YES' ? 'badge-success' : 'badge-ghost')
}
}}
onFocus={(e) => e.target.select()}
/>
</td>
onClick={toggleBidType}
>
YES
</div>
<br />
<div
className={
`badge hover:cursor-pointer ` +
(newBidType == 'NO' ? 'badge-error' : 'badge-ghost')
}
onClick={toggleBidType}
>
NO
</div>
</td>
<td>
{/* Note: Would love to make this input smaller... */}
<input
type="number"
placeholder="0"
className="input input-bordered"
style={{ maxWidth: 100 }}
value={newBid.toString()}
onChange={(e) => setNewBid(parseInt(e.target.value) || 0)}
onKeyUp={(e) => {
if (e.key === 'Enter') {
submitBid()
}
}}
onFocus={(e) => e.target.select()}
/>
</td>
<TableRowEnd
entry={nextEntry}
isNew
/>
<TableRowEnd entry={nextEntry} isNew />
<td>
<button
className="btn btn-primary"
onClick={() => submitBid()}
disabled={newBid <= 0}
>
Submit
</button>
<td>
<button
className="btn btn-primary"
onClick={() => submitBid()}
disabled={newBid <= 0}
>
Submit
</button>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<button
className="btn btn-secondary mb-4"
onClick={randomBid}
>
Random bet!
</button>
</>
<button className="btn btn-secondary mb-4" onClick={randomBid}>
Random bet!
</button>
</>
)
}
// Show a hello world React page
@ -269,17 +247,9 @@ export default function Simulator() {
const reversedEntries = [...entries].reverse()
const probs = entries.map((entry) => entry.prob)
const chartData = {
labels: Array.from({ length: steps }, (_, i) => 1 + i),
datasets: [
{
label: 'Implied probability',
data: probs,
borderColor: 'rgb(75, 192, 192)',
},
],
}
const points = probs.map((prob, i) => ({ x: i + 1, y: prob * 100 }))
const data = [{ id: 'Yes', data: points, color: '#11b981' }]
const tickValues = [0, 25, 50, 75, 100]
return (
<div>
@ -291,7 +261,6 @@ export default function Simulator() {
Dynamic Parimutuel Market Simulator
</h1>
<NewBidTable {...{ steps, bids, setSteps, setBids }} />
{/* History of bids */}
@ -320,7 +289,29 @@ export default function Simulator() {
Probability of
<div className="badge badge-success text-2xl h-8 w-18">YES</div>
</h1>
<Line data={chartData} height={200} />
<div className="w-full" style={{ height: 400 }}>
<ResponsiveLine
data={data}
yScale={{ min: 0, max: 100, type: 'linear' }}
yFormat={formatPercent}
gridYValues={tickValues}
axisLeft={{
tickValues,
format: formatPercent,
}}
axisBottom={{
tickValues: [],
}}
enableGridX={false}
colors={{ datum: 'color' }}
pointSize={12}
pointBorderWidth={2}
pointBorderColor="#fff"
enableSlices="x"
enableArea
margin={{ top: 20, right: 10, bottom: 20, left: 40 }}
/>
</div>
{/* Range slider that sets the current step */}
<label>Orders # 1 - {steps}</label>
<input
@ -336,3 +327,7 @@ export default function Simulator() {
</div>
)
}
function formatPercent(y: DatumValue) {
return `${Math.round(+y.toString())}%`
}