Spaces:
Sleeping
Sleeping
File size: 3,652 Bytes
16eaadc | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | """Plotly figures for the deck-builder Space.
Three breakdown charts displayed alongside a generated deck:
- cost curve (bar): quantities by cost bucket vs. the target curve
- type breakdown (bar): Character/Event/Stage counts
- color breakdown (bar): cards per color
Color hex map mirrors the upstream `optcg_cards.visualize._first_color_hex`
so palettes stay consistent across all OPTCG-related Spaces.
"""
from __future__ import annotations
from typing import TYPE_CHECKING
from optcg_cards.visualize import _first_color_hex
if TYPE_CHECKING:
from spaceutil.deck import Deck
def _empty_fig(message: str, height: int = 240):
import plotly.graph_objects as go
fig = go.Figure()
fig.add_annotation(
text=message,
xref="paper", yref="paper", x=0.5, y=0.5,
showarrow=False, font=dict(color="gray"),
)
fig.update_layout(
xaxis=dict(visible=False),
yaxis=dict(visible=False),
plot_bgcolor="white",
margin=dict(l=40, r=40, t=40, b=40),
height=height,
)
return fig
def build_cost_curve_figure(deck: Deck | None, height: int = 280):
"""Bar chart comparing the deck's actual cost curve vs. the style target."""
import plotly.graph_objects as go
if deck is None or deck.total_quantity == 0:
return _empty_fig("Build a deck to see its cost curve.", height=height)
actual = deck.cost_distribution
target = deck.target_curve or {}
buckets = sorted(set(actual) | set(target))
labels = [("8+" if b == 8 else str(b)) for b in buckets]
actual_y = [actual.get(b, 0) for b in buckets]
target_y = [target.get(b, 0) for b in buckets]
fig = go.Figure(data=[
go.Bar(name="Actual", x=labels, y=actual_y, marker_color="#dc3545"),
go.Bar(name="Target", x=labels, y=target_y, marker_color="#1f77b4", opacity=0.5),
])
fig.update_layout(
title="Cost curve: actual vs. target",
xaxis=dict(title="Cost"),
yaxis=dict(title="Cards"),
barmode="group",
plot_bgcolor="white",
margin=dict(l=40, r=40, t=60, b=40),
height=height,
legend=dict(orientation="h", y=1.0, yanchor="bottom"),
)
return fig
def build_type_breakdown_figure(deck: Deck | None, height: int = 240):
import plotly.graph_objects as go
if deck is None or deck.total_quantity == 0:
return _empty_fig("Build a deck to see its type mix.", height=height)
dist = deck.type_distribution
types = sorted(dist.keys())
counts = [dist[t] for t in types]
fig = go.Figure(data=[go.Bar(x=types, y=counts, marker_color="#6c757d")])
fig.update_layout(
title="Card type mix",
xaxis=dict(title=""),
yaxis=dict(title="Cards"),
plot_bgcolor="white",
margin=dict(l=40, r=40, t=60, b=40),
height=height,
)
return fig
def build_color_breakdown_figure(deck: Deck | None, height: int = 240):
import plotly.graph_objects as go
if deck is None or deck.total_quantity == 0:
return _empty_fig("Build a deck to see its color mix.", height=height)
dist = deck.color_distribution
colors = sorted(dist.keys())
counts = [dist[c] for c in colors]
bar_colors = [_first_color_hex([c]) for c in colors]
fig = go.Figure(data=[go.Bar(x=colors, y=counts, marker_color=bar_colors)])
fig.update_layout(
title="Color mix (per copy)",
xaxis=dict(title=""),
yaxis=dict(title="Cards (counted per color of multicolor cards)"),
plot_bgcolor="white",
margin=dict(l=40, r=40, t=60, b=40),
height=height,
)
return fig
|