fix(stats): stabilize stacked chart bands

This commit is contained in:
Adam
2026-05-29 14:20:23 -05:00
parent 494b55a2a7
commit 9854c5d910
+68 -15
View File
@@ -598,6 +598,7 @@ function TopModelsChart(props: {
}) { }) {
const [activeIndex, setActiveIndex] = createSignal<number>() const [activeIndex, setActiveIndex] = createSignal<number>()
const maxTotal = createMemo(() => getTopModelsMaxTotal(props.data)) const maxTotal = createMemo(() => getTopModelsMaxTotal(props.data))
const segmentOrder = createMemo(() => getTopModelsSegmentOrder(props.data))
const activePoint = createMemo(() => props.data[activeIndex() ?? -1]) const activePoint = createMemo(() => props.data[activeIndex() ?? -1])
return ( return (
@@ -671,8 +672,11 @@ function TopModelsChart(props: {
props.onActiveModelChange(undefined) props.onActiveModelChange(undefined)
}} }}
> >
<div data-slot="top-models-stack" style={{ "grid-template-rows": getTopModelsSegmentRows(day) }}> <div
<For each={stackedTopModelsSegments(day)}> data-slot="top-models-stack"
style={{ "grid-template-rows": getTopModelsSegmentRows(day, segmentOrder()) }}
>
<For each={stackedTopModelsSegments(day, segmentOrder())}>
{(item) => ( {(item) => (
<i <i
data-series={item.index} data-series={item.index}
@@ -682,6 +686,7 @@ function TopModelsChart(props: {
background: getTopModelsSegmentColor( background: getTopModelsSegmentColor(
item.segment.model, item.segment.model,
item.index, item.index,
segmentOrder(),
activeIndex() !== undefined && activeIndex() !== dayIndex(), activeIndex() !== undefined && activeIndex() !== dayIndex(),
props.activeModel, props.activeModel,
), ),
@@ -725,7 +730,10 @@ function TopModelsChart(props: {
} }
> >
<span data-slot="tooltip-label"> <span data-slot="tooltip-label">
<i style={{ background: usageColors[item.index] }} /> {item.segment.model} <i
style={{ background: getRankColor(item.segment.model, item.index, segmentOrder(), usageColors) }}
/>{" "}
{item.segment.model}
</span> </span>
<b>{formatTokens(item.segment.value)}</b> <b>{formatTokens(item.segment.value)}</b>
</p> </p>
@@ -754,10 +762,10 @@ function getTopModelsMaxTotal(data: UsagePoint[]) {
return max return max
} }
function getTopModelsSegmentRows(point: UsagePoint) { function getTopModelsSegmentRows(point: UsagePoint, order: Map<string, number>) {
const total = usageTotal(point) const total = usageTotal(point)
if (total <= 0) return "" if (total <= 0) return ""
return stackedTopModelsSegments(point) return stackedTopModelsSegments(point, order)
.map((item) => `${(item.segment.value / total) * 100}%`) .map((item) => `${(item.segment.value / total) * 100}%`)
.join(" ") .join(" ")
} }
@@ -766,17 +774,29 @@ function visibleTopModelsSegments(point: UsagePoint) {
return point.segments.map((segment, index) => ({ segment, index })).filter((item) => item.segment.value > 0) return point.segments.map((segment, index) => ({ segment, index })).filter((item) => item.segment.value > 0)
} }
function stackedTopModelsSegments(point: UsagePoint) { function stackedTopModelsSegments(point: UsagePoint, order: Map<string, number>) {
return visibleTopModelsSegments(point) return visibleTopModelsSegments(point)
.slice() .slice()
.sort((a, b) => a.segment.value - b.segment.value || a.index - b.index) .sort((a, b) => (order.get(b.segment.model) ?? b.index) - (order.get(a.segment.model) ?? a.index))
} }
function getTopModelsSegmentColor(model: string, index: number, muted: boolean, activeModel: string | undefined) { function getTopModelsSegmentOrder(data: UsagePoint[]) {
return getRankOrder(
data.flatMap((point) => point.segments.map((segment, index) => ({ key: segment.model, value: segment.value, index }))),
)
}
function getTopModelsSegmentColor(
model: string,
index: number,
order: Map<string, number>,
muted: boolean,
activeModel: string | undefined,
) {
if (activeModel !== undefined) if (activeModel !== undefined)
return activeModel === model ? (usageColors[index] ?? "var(--stats-text)") : "var(--stats-layer-2)" return activeModel === model ? getRankColor(model, index, order, usageColors) : "var(--stats-layer-2)"
if (muted) return "var(--stats-layer-2)" if (muted) return "var(--stats-layer-2)"
return usageColors[index] ?? "var(--stats-text)" return getRankColor(model, index, order, usageColors)
} }
function isTopModelsMobileAxisHidden(index: number, count: number) { function isTopModelsMobileAxisHidden(index: number, count: number) {
@@ -895,6 +915,7 @@ function MarketShareSection(props: { data: StatsHomeData["market"] }) {
const [activeAuthor, setActiveAuthor] = createSignal<string>() const [activeAuthor, setActiveAuthor] = createSignal<string>()
const [inspecting, setInspecting] = createSignal(false) const [inspecting, setInspecting] = createSignal(false)
const data = createMemo(() => props.data[range()]) const data = createMemo(() => props.data[range()])
const authorOrder = createMemo(() => getMarketAuthorOrder(data()))
const selectedIndex = createMemo(() => Math.min(activeIndex(), Math.max(data().length - 1, 0))) const selectedIndex = createMemo(() => Math.min(activeIndex(), Math.max(data().length - 1, 0)))
const activeDay = createMemo(() => data()[selectedIndex()]) const activeDay = createMemo(() => data()[selectedIndex()])
@@ -919,6 +940,7 @@ function MarketShareSection(props: { data: StatsHomeData["market"] }) {
<MarketShare <MarketShare
data={data()} data={data()}
range={range()} range={range()}
authorOrder={authorOrder()}
activeIndex={selectedIndex()} activeIndex={selectedIndex()}
activeAuthor={activeAuthor()} activeAuthor={activeAuthor()}
inspecting={inspecting()} inspecting={inspecting()}
@@ -933,6 +955,7 @@ function MarketShareSection(props: { data: StatsHomeData["market"] }) {
/> />
<MarketShareList <MarketShareList
data={day().authors} data={day().authors}
authorOrder={authorOrder()}
activeAuthor={activeAuthor()} activeAuthor={activeAuthor()}
onActiveAuthorChange={(author) => { onActiveAuthorChange={(author) => {
setActiveAuthor(author) setActiveAuthor(author)
@@ -966,6 +989,7 @@ function MarketShareSection(props: { data: StatsHomeData["market"] }) {
function MarketShare(props: { function MarketShare(props: {
data: MarketDay[] data: MarketDay[]
range: UsageRange range: UsageRange
authorOrder: Map<string, number>
activeIndex: number activeIndex: number
activeAuthor: string | undefined activeAuthor: string | undefined
inspecting: boolean inspecting: boolean
@@ -1013,9 +1037,10 @@ function MarketShare(props: {
onClick={() => props.onActiveIndexChange(index())} onClick={() => props.onActiveIndexChange(index())}
onPointerEnter={() => props.onActiveIndexChange(index())} onPointerEnter={() => props.onActiveIndexChange(index())}
> >
<For each={stackedMarketAuthors(day)}> <For each={stackedMarketAuthors(day, props.authorOrder)}>
{(item) => ( {(item) => (
<span <span
data-author={item.author.author}
data-active={props.activeAuthor === item.author.author ? "true" : undefined} data-active={props.activeAuthor === item.author.author ? "true" : undefined}
data-muted={ data-muted={
props.activeAuthor !== undefined && props.activeAuthor !== item.author.author ? "true" : undefined props.activeAuthor !== undefined && props.activeAuthor !== item.author.author ? "true" : undefined
@@ -1023,7 +1048,7 @@ function MarketShare(props: {
style={{ style={{
"background-color": getMarketSegmentColor( "background-color": getMarketSegmentColor(
item.author.author, item.author.author,
marketColors[item.index] ?? "var(--stats-text)", getRankColor(item.author.author, item.index, props.authorOrder, marketColors),
props.activeAuthor, props.activeAuthor,
), ),
"flex-grow": item.author.share, "flex-grow": item.author.share,
@@ -1056,6 +1081,7 @@ function MarketShare(props: {
function MarketShareList(props: { function MarketShareList(props: {
data: MarketDay["authors"] data: MarketDay["authors"]
authorOrder: Map<string, number>
activeAuthor: string | undefined activeAuthor: string | undefined
onActiveAuthorChange: (author: string) => void onActiveAuthorChange: (author: string) => void
}) { }) {
@@ -1077,7 +1103,7 @@ function MarketShareList(props: {
}} }}
> >
<span>{String(index() + 1).padStart(2, "0")}</span> <span>{String(index() + 1).padStart(2, "0")}</span>
<i style={{ background: marketColors[index()] }} /> <i style={{ background: getRankColor(item.author, index(), props.authorOrder, marketColors) }} />
<strong>{item.author}</strong> <strong>{item.author}</strong>
<em>{formatTrillions(item.tokens)}</em> <em>{formatTrillions(item.tokens)}</em>
<b>{item.share.toFixed(1)}%</b> <b>{item.share.toFixed(1)}%</b>
@@ -1094,11 +1120,38 @@ function getMarketSegmentColor(author: string, color: string, activeAuthor: stri
return "var(--stats-bar-idle)" return "var(--stats-bar-idle)"
} }
function stackedMarketAuthors(day: MarketDay) { function stackedMarketAuthors(day: MarketDay, order: Map<string, number>) {
return day.authors return day.authors
.map((author, index) => ({ author, index })) .map((author, index) => ({ author, index }))
.slice() .slice()
.sort((a, b) => a.author.share - b.author.share || a.index - b.index) .sort((a, b) => (order.get(b.author.author) ?? b.index) - (order.get(a.author.author) ?? a.index))
}
function getMarketAuthorOrder(data: MarketDay[]) {
return getRankOrder(
data.flatMap((day) => day.authors.map((author, index) => ({ key: author.author, value: author.tokens, index }))),
)
}
function getRankOrder(items: { key: string; value: number; index: number }[]) {
return new Map<string, number>(
Object.values(
items.reduce<Record<string, { key: string; value: number; index: number }>>((result, item) => {
result[item.key] = {
key: item.key,
value: (result[item.key]?.value ?? 0) + item.value,
index: Math.min(result[item.key]?.index ?? item.index, item.index),
}
return result
}, {}),
)
.toSorted((a, b) => b.value - a.value || a.index - b.index || a.key.localeCompare(b.key))
.map((item, index) => [item.key, index] as const),
)
}
function getRankColor(key: string, fallbackIndex: number, order: Map<string, number>, colors: readonly string[]) {
return colors[order.get(key) ?? fallbackIndex] ?? "var(--stats-text)"
} }
function isMarketMobileLabelHidden(index: number, count: number) { function isMarketMobileLabelHidden(index: number, count: number) {