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