Spaces:
Running on Zero
Running on Zero
UX: CSV/SVG download links, schema preview on load, cleaner SVG theme
Browse files
src/visualization/svg_theme.py
CHANGED
|
@@ -43,6 +43,7 @@ def apply_theme(svg: str) -> str:
|
|
| 43 |
if not svg or "<svg" not in svg:
|
| 44 |
return svg
|
| 45 |
|
|
|
|
| 46 |
svg = _ensure_viewbox(svg)
|
| 47 |
svg = _ensure_responsive(svg)
|
| 48 |
svg = _normalize_fonts(svg)
|
|
@@ -51,6 +52,25 @@ def apply_theme(svg: str) -> str:
|
|
| 51 |
return svg
|
| 52 |
|
| 53 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 54 |
def _ensure_viewbox(svg: str) -> str:
|
| 55 |
"""If width/height are present but viewBox is missing, derive it."""
|
| 56 |
if re.search(r"viewBox\s*=", svg, re.IGNORECASE):
|
|
|
|
| 43 |
if not svg or "<svg" not in svg:
|
| 44 |
return svg
|
| 45 |
|
| 46 |
+
svg = _strip_plotly_chrome(svg)
|
| 47 |
svg = _ensure_viewbox(svg)
|
| 48 |
svg = _ensure_responsive(svg)
|
| 49 |
svg = _normalize_fonts(svg)
|
|
|
|
| 52 |
return svg
|
| 53 |
|
| 54 |
|
| 55 |
+
def _strip_plotly_chrome(svg: str) -> str:
|
| 56 |
+
"""Remove Plotly's modebar, watermark and toolbar artifacts."""
|
| 57 |
+
# Plotly draws a modebar group — strip it
|
| 58 |
+
svg = re.sub(
|
| 59 |
+
r'<g[^>]*class="[^"]*modebar[^"]*"[^>]*>.*?</g>',
|
| 60 |
+
"",
|
| 61 |
+
svg,
|
| 62 |
+
flags=re.DOTALL,
|
| 63 |
+
)
|
| 64 |
+
# Remove explicit white backgrounds that Plotly adds
|
| 65 |
+
svg = re.sub(
|
| 66 |
+
r'fill="(?:rgb\(255,\s*255,\s*255\)|#fff(?:fff)?|white)"',
|
| 67 |
+
'fill="transparent"',
|
| 68 |
+
svg,
|
| 69 |
+
flags=re.IGNORECASE,
|
| 70 |
+
)
|
| 71 |
+
return svg
|
| 72 |
+
|
| 73 |
+
|
| 74 |
def _ensure_viewbox(svg: str) -> str:
|
| 75 |
"""If width/height are present but viewBox is missing, derive it."""
|
| 76 |
if re.search(r"viewBox\s*=", svg, re.IGNORECASE):
|