Spaces:
Running on CPU Upgrade
Running on CPU Upgrade
Add a new color logic for plotly (Needs some more adjustments later)
Browse files
utils.py
CHANGED
|
@@ -40,50 +40,75 @@ TRANSPARENT_BG = dict(
|
|
| 40 |
# ---------------------------------------------------------------------------
|
| 41 |
|
| 42 |
# ---------------------------------------------------------------------------
|
| 43 |
-
#
|
| 44 |
-
#
|
| 45 |
-
#
|
| 46 |
-
#
|
| 47 |
-
#
|
| 48 |
-
#
|
| 49 |
-
#
|
| 50 |
-
#
|
| 51 |
-
# 4 β pale tint (100, 240)
|
| 52 |
-
# The palette is interleaved hue-first so index 0=red-vivid, 1=yellow-vivid,
|
| 53 |
-
# 2=green-vivid ... 6=red-medium, 7=yellow-medium, etc.
|
| 54 |
# ---------------------------------------------------------------------------
|
| 55 |
-
def _build_palette():
|
| 56 |
-
# OpenCV HSV hue is 0-179 (half-degrees)
|
| 57 |
-
hues_deg = [0, 30, 60, 90, 120, 150] # red, yellow, green, cyan, blue, magenta
|
| 58 |
-
tiers = [(255, 200), (180, 230), (255, 140), (100, 240)]
|
| 59 |
-
palette = []
|
| 60 |
-
for sat, val in tiers:
|
| 61 |
-
for h_deg in hues_deg:
|
| 62 |
-
h_cv = h_deg # already 0-179 range
|
| 63 |
-
hsv = np.uint8([[[h_cv, sat, val]]])
|
| 64 |
-
bgr = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)
|
| 65 |
-
b = f'{bgr[0][0][0].item():02x}'
|
| 66 |
-
g = f'{bgr[0][0][1].item():02x}'
|
| 67 |
-
r = f'{bgr[0][0][2].item():02x}'
|
| 68 |
-
palette.append('#' + b + g + r)
|
| 69 |
-
return palette # 24 colors
|
| 70 |
-
|
| 71 |
-
_PALETTE = _build_palette() + ["#999DA0"] # index 24: grey for No Voice
|
| 72 |
|
|
|
|
|
|
|
| 73 |
|
| 74 |
-
|
| 75 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 76 |
|
| 77 |
-
Colors are taken in palette order (redβyellowβgreenβcyanβblueβmagenta,
|
| 78 |
-
then repeating across brightness tiers) so adjacent speakers always have
|
| 79 |
-
maximally different hues. Cycles if n > 24.
|
| 80 |
|
| 81 |
-
|
| 82 |
-
|
|
|
|
|
|
|
|
|
|
| 83 |
"""
|
| 84 |
if n == 0:
|
| 85 |
return []
|
| 86 |
-
|
|
|
|
| 87 |
|
| 88 |
|
| 89 |
def extract_clip_bytes(waveform, sample_rate, seg_start, seg_end):
|
|
@@ -324,7 +349,7 @@ def build_fig_pie2(df4, speakerNames, speakerColors, catColors, get_display_name
|
|
| 324 |
fig = go.Figure()
|
| 325 |
fig.update_layout(
|
| 326 |
title_text="Percentage of Speakers per Role",
|
| 327 |
-
colorway=
|
| 328 |
**TRANSPARENT_BG,
|
| 329 |
)
|
| 330 |
fig.add_trace(go.Pie(values=df4["values"], labels=df4["names"], sort=False))
|
|
@@ -334,26 +359,20 @@ def build_fig_pie2(df4, speakerNames, speakerColors, catColors, get_display_name
|
|
| 334 |
def _voice_color_map(df5_labels, speakerColors):
|
| 335 |
"""Build the label->color map for sunburst/treemap charts.
|
| 336 |
|
| 337 |
-
Single Voice
|
| 338 |
-
Multi Voice
|
| 339 |
-
No Voice
|
| 340 |
-
Speakers
|
| 341 |
-
blend into their parent category layer.
|
| 342 |
"""
|
| 343 |
-
reserved = {0, 4}
|
| 344 |
-
speaker_indices = [i for i in range(24) if i not in reserved] # exclude grey index
|
| 345 |
-
|
| 346 |
top_labels = ["No Voice", "Single Voice", "Multi Voice"]
|
| 347 |
color_map = {
|
| 348 |
-
"Single Voice": _PALETTE[0],
|
| 349 |
-
"Multi Voice": _PALETTE[
|
| 350 |
-
"No Voice": _PALETTE[
|
| 351 |
}
|
| 352 |
speaker_labels = [l for l in df5_labels if l not in top_labels]
|
| 353 |
for i, lbl in enumerate(speaker_labels):
|
| 354 |
-
color_map[lbl] =
|
| 355 |
-
# speaker_indices contains palette indices; convert to hex
|
| 356 |
-
color_map[lbl] = _PALETTE[speaker_indices[i % len(speaker_indices)]]
|
| 357 |
return color_map
|
| 358 |
|
| 359 |
|
|
@@ -436,7 +455,7 @@ def build_fig_timeline(speakers_dataFrame, currTotalTime, speakerColors, get_dis
|
|
| 436 |
fig = px.timeline(
|
| 437 |
df, x_start="Start", x_end="Finish", y="Resource", color="Resource",
|
| 438 |
title="Timeline of Audio with Speakers",
|
| 439 |
-
color_discrete_sequence=
|
| 440 |
)
|
| 441 |
fig.update_yaxes(autorange="reversed")
|
| 442 |
|
|
@@ -486,7 +505,7 @@ def build_fig_bar(df2, speakerNames, catColors, speakerColors, get_display_name_
|
|
| 486 |
df2, x="values", y="names", color="names", orientation="h",
|
| 487 |
custom_data=["names", "time_label"],
|
| 488 |
title="Time Spoken by each Speaker",
|
| 489 |
-
color_discrete_sequence=
|
| 490 |
)
|
| 491 |
# Hide x-axis tick labels β values are crowded with many speakers.
|
| 492 |
# The exact time is still visible on hover via the hovertemplate.
|
|
|
|
| 40 |
# ---------------------------------------------------------------------------
|
| 41 |
|
| 42 |
# ---------------------------------------------------------------------------
|
| 43 |
+
# Color palette β loaded from plotly_colorwheel.txt at import time.
|
| 44 |
+
# Edit that file to change colors; no code changes needed.
|
| 45 |
+
# Structure: 8 colors Γ 3 shades (indices 0-23) + 1 grey (index 24).
|
| 46 |
+
# Reserved indices:
|
| 47 |
+
# 0 = Single Voice (red shade 0)
|
| 48 |
+
# 3 = Multi Voice (green shade 0)
|
| 49 |
+
# 24 = No Voice (grey)
|
| 50 |
+
# Speakers cycle through all other indices in order.
|
|
|
|
|
|
|
|
|
|
| 51 |
# ---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 52 |
|
| 53 |
+
def _load_palette(path="plotly_colorwheel.txt"):
|
| 54 |
+
"""Parse plotly_colorwheel.txt (id, color, shade, hex table) into a list.
|
| 55 |
|
| 56 |
+
Returns a list indexed by id so _PALETTE[id] gives the hex color directly.
|
| 57 |
+
Falls back to hardcoded defaults if file is missing.
|
| 58 |
+
"""
|
| 59 |
+
FALLBACK = [
|
| 60 |
+
"#de2d26","#fc9272","#fee0d2", # red 0-2
|
| 61 |
+
"#e6550d","#fdae6b","#feedde", # orange 3-5
|
| 62 |
+
"#d9b300","#fdd44d","#fff7bc", # yellow 6-8
|
| 63 |
+
"#31a354","#a1d99b","#e5f5e0", # green 9-11
|
| 64 |
+
"#1a9e9e","#66c2c2","#ccecec", # teal 12-14
|
| 65 |
+
"#3182bd","#9ecae1","#deebf7", # blue 15-17
|
| 66 |
+
"#756bb1","#bcbddc","#efedf5", # purple 18-20
|
| 67 |
+
"#d4679a","#f1b6d1","#fce4f0", # pink 21-23
|
| 68 |
+
"#999DA0", # grey 24
|
| 69 |
+
]
|
| 70 |
+
try:
|
| 71 |
+
entries = {}
|
| 72 |
+
with open(path, "r") as f:
|
| 73 |
+
for line in f:
|
| 74 |
+
line = line.strip()
|
| 75 |
+
if not line or line.startswith("#"):
|
| 76 |
+
continue
|
| 77 |
+
parts = [p.strip() for p in line.split(",")]
|
| 78 |
+
if len(parts) < 4:
|
| 79 |
+
continue
|
| 80 |
+
try:
|
| 81 |
+
idx = int(parts[0])
|
| 82 |
+
hex_color = parts[3]
|
| 83 |
+
if hex_color.startswith("#"):
|
| 84 |
+
entries[idx] = hex_color
|
| 85 |
+
except ValueError:
|
| 86 |
+
continue
|
| 87 |
+
if not entries:
|
| 88 |
+
return FALLBACK
|
| 89 |
+
max_idx = max(entries.keys())
|
| 90 |
+
palette = [entries.get(i, "#cccccc") for i in range(max_idx + 1)]
|
| 91 |
+
return palette
|
| 92 |
+
except FileNotFoundError:
|
| 93 |
+
return FALLBACK
|
| 94 |
+
|
| 95 |
+
_PALETTE = _load_palette()
|
| 96 |
+
# Reserved: 0 = Single Voice (red shade 0), 9 = Multi Voice (green shade 0),
|
| 97 |
+
# 24 = No Voice (grey). Speakers use all other indices.
|
| 98 |
+
_RESERVED = {0, 9, len(_PALETTE) - 1}
|
| 99 |
+
_SPEAKER_PALETTE = [c for i, c in enumerate(_PALETTE) if i not in _RESERVED]
|
| 100 |
|
|
|
|
|
|
|
|
|
|
| 101 |
|
| 102 |
+
def colorsCSS(n, startingHue=None, pool=None):
|
| 103 |
+
"""Return n CSS hex colors from the speaker palette.
|
| 104 |
+
|
| 105 |
+
Cycles if n > len(_SPEAKER_PALETTE).
|
| 106 |
+
startingHue and pool accepted for backwards compatibility but ignored.
|
| 107 |
"""
|
| 108 |
if n == 0:
|
| 109 |
return []
|
| 110 |
+
pal = _SPEAKER_PALETTE if _SPEAKER_PALETTE else _PALETTE
|
| 111 |
+
return [pal[i % len(pal)] for i in range(n)]
|
| 112 |
|
| 113 |
|
| 114 |
def extract_clip_bytes(waveform, sample_rate, seg_start, seg_end):
|
|
|
|
| 349 |
fig = go.Figure()
|
| 350 |
fig.update_layout(
|
| 351 |
title_text="Percentage of Speakers per Role",
|
| 352 |
+
colorway=_SPEAKER_PALETTE,
|
| 353 |
**TRANSPARENT_BG,
|
| 354 |
)
|
| 355 |
fig.add_trace(go.Pie(values=df4["values"], labels=df4["names"], sort=False))
|
|
|
|
| 359 |
def _voice_color_map(df5_labels, speakerColors):
|
| 360 |
"""Build the label->color map for sunburst/treemap charts.
|
| 361 |
|
| 362 |
+
Single Voice β _PALETTE[0] (red shade 0, reserved)
|
| 363 |
+
Multi Voice β _PALETTE[3] (green shade 0, reserved)
|
| 364 |
+
No Voice β _PALETTE[-1] (grey, reserved)
|
| 365 |
+
Speakers β _SPEAKER_PALETTE in order (never collides with reserved)
|
|
|
|
| 366 |
"""
|
|
|
|
|
|
|
|
|
|
| 367 |
top_labels = ["No Voice", "Single Voice", "Multi Voice"]
|
| 368 |
color_map = {
|
| 369 |
+
"Single Voice": _PALETTE[0], # red shade 0
|
| 370 |
+
"Multi Voice": _PALETTE[9], # green shade 0
|
| 371 |
+
"No Voice": _PALETTE[-1], # grey
|
| 372 |
}
|
| 373 |
speaker_labels = [l for l in df5_labels if l not in top_labels]
|
| 374 |
for i, lbl in enumerate(speaker_labels):
|
| 375 |
+
color_map[lbl] = _SPEAKER_PALETTE[i % len(_SPEAKER_PALETTE)]
|
|
|
|
|
|
|
| 376 |
return color_map
|
| 377 |
|
| 378 |
|
|
|
|
| 455 |
fig = px.timeline(
|
| 456 |
df, x_start="Start", x_end="Finish", y="Resource", color="Resource",
|
| 457 |
title="Timeline of Audio with Speakers",
|
| 458 |
+
color_discrete_sequence=_SPEAKER_PALETTE,
|
| 459 |
)
|
| 460 |
fig.update_yaxes(autorange="reversed")
|
| 461 |
|
|
|
|
| 505 |
df2, x="values", y="names", color="names", orientation="h",
|
| 506 |
custom_data=["names", "time_label"],
|
| 507 |
title="Time Spoken by each Speaker",
|
| 508 |
+
color_discrete_sequence=_SPEAKER_PALETTE,
|
| 509 |
)
|
| 510 |
# Hide x-axis tick labels β values are crowded with many speakers.
|
| 511 |
# The exact time is still visible on hover via the hovertemplate.
|