Spaces:
Sleeping
Sleeping
File size: 4,203 Bytes
78c571c 3ab07bd 78c571c 3ab07bd 78c571c 3ab07bd 78c571c 3ab07bd 78c571c 3ab07bd 78c571c | 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 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | """Plotly figures used by the Gradio Space.
`build_umap_figure` adapts `optcg_cards.visualize.render_html`
(visualize.py:109-128) - returns a Figure rather than writing HTML, and
overlays a second trace for search hits.
`build_cost_curve_figure` plots a synergy recommendation set's
cost-distribution as a bar chart for the Synergy Inspector tab.
"""
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from optcg_cards.visualize import _first_color_hex, _hover_label
if TYPE_CHECKING:
from spaceutil.synergy import SynergyHit
def build_umap_figure(
cards: list[dict[str, Any]],
highlight_indices: list[int] | None = None,
title: str = "OPTCG Card Embedding Map",
):
import plotly.graph_objects as go
if not cards:
raise ValueError("No cards to render")
if "umap_x" not in cards[0] or "umap_y" not in cards[0]:
raise ValueError("Cards must have umap_x/umap_y; cannot plot")
xs = [c["umap_x"] for c in cards]
ys = [c["umap_y"] for c in cards]
colors = [_first_color_hex(c.get("colors", [])) for c in cards]
hover = [_hover_label(c) for c in cards]
base_customdata = [[i] for i in range(len(cards))]
fig = go.Figure()
fig.add_trace(
go.Scatter(
x=xs,
y=ys,
mode="markers",
marker=dict(size=5, color=colors, opacity=0.4),
text=hover,
hoverinfo="text",
customdata=base_customdata,
name="all cards",
)
)
if highlight_indices:
hi_x = [cards[i]["umap_x"] for i in highlight_indices]
hi_y = [cards[i]["umap_y"] for i in highlight_indices]
hi_colors = [_first_color_hex(cards[i].get("colors", [])) for i in highlight_indices]
hi_hover = [
f"<b>Rank {rank + 1}</b><br>{_hover_label(cards[i])}"
for rank, i in enumerate(highlight_indices)
]
hi_customdata = [[idx, rank + 1] for rank, idx in enumerate(highlight_indices)]
fig.add_trace(
go.Scatter(
x=hi_x,
y=hi_y,
mode="markers",
marker=dict(
size=14,
color=hi_colors,
opacity=1.0,
line=dict(width=2, color="black"),
),
text=hi_hover,
hoverinfo="text",
customdata=hi_customdata,
name="search hits",
)
)
fig.update_layout(
title=title,
xaxis=dict(title="UMAP-1", showgrid=False, zeroline=False),
yaxis=dict(title="UMAP-2", showgrid=False, zeroline=False),
plot_bgcolor="white",
showlegend=False,
margin=dict(l=40, r=40, t=60, b=40),
)
return fig
def build_cost_curve_figure(
hits: list[SynergyHit],
title: str = "Cost curve of recommendations",
):
"""Bar chart of synergy recommendations grouped by cost.
Costs above 10 are clamped into a single "10+" bucket so a stray
high-cost finisher doesn't stretch the X axis."""
import plotly.graph_objects as go
from spaceutil.synergy import cost_curve
counts = cost_curve(hits, max_cost=10)
if not counts:
fig = go.Figure()
fig.add_annotation(
text="No cost data yet - pick a leader to see recommendations.",
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=60, b=40),
height=260,
)
return fig
costs = sorted(counts.keys())
labels = [("10+" if c == 10 else str(c)) for c in costs]
values = [counts[c] for c in costs]
fig = go.Figure(data=[go.Bar(x=labels, y=values, marker_color="#dc3545")])
fig.update_layout(
title=title,
xaxis=dict(title="Cost"),
yaxis=dict(title="Count of recommendations"),
plot_bgcolor="white",
margin=dict(l=40, r=40, t=60, b=40),
height=260,
)
return fig
|