Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
File size: 5,603 Bytes
d39782f 8be8777 d39782f 8be8777 d39782f 8be8777 d39782f 8be8777 d39782f 8be8777 d39782f 8be8777 d39782f 8be8777 4acb8ae d39782f |
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 134 135 136 |
# Utilities for constructing the whisky flavor wheel SVG.
from typing import List, Tuple
import math
###################################################################################
# Base SVG template with placeholder for the dynamic graph coordinates.
SVG_BASE = """
<svg id="wheel"
viewBox="0 0 500 500"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<path id="textPathU-68cfdea07e622" d="M 250, 250 m 0, 220 a -220,-220 0 1,1 0,-440 a -220,-220 0 1,1 0,440" style="stroke: red; fill: none;" />
<path id="textPathL-68cfdea07e622" d="M 250, 250 m 0, -220 a 220,220 0 1,0 0,440 a 220,220 0 1,0 0,-440" style="stroke: red; fill: none;" />
</defs>
<!-- Ringe -->
<circle class="circle" r="40" cx="250" cy="250" style="stroke:rgb(180, 180, 180); fill:none" />
<circle class="circle" r="80" cx="250" cy="250" style="stroke:rgb(180, 180, 180); fill:none" />
<circle class="circle" r="120" cx="250" cy="250" style="stroke:rgb(180, 180, 180); fill:none" />
<circle class="circle" r="160" cx="250" cy="250" style="stroke:rgb(180, 180, 180); fill:none" />
<circle class="circle" r="200" cx="250" cy="250" style="stroke:rgb(180, 180, 180); fill:none" />
<!-- Achsen -->
<line class="line" x1="250" y1="210" x2="250" y2="50" style="stroke:rgb(180, 180, 180)" />
<line class="line" x1="278.28427124746" y1="221.71572875254" x2="391.42135623731" y2="108.57864376269" style="stroke:rgb(180, 180, 180)" />
<line class="line" x1="290" y1="250" x2="450" y2="250" style="stroke:rgb(180, 180, 180)" />
<line class="line" x1="278.28427124746" y1="278.28427124746" x2="391.42135623731" y2="391.42135623731" style="stroke:rgb(180, 180, 180)" />
<line class="line" x1="250" y1="290" x2="250" y2="450" style="stroke:rgb(180, 180, 180)" />
<line class="line" x1="221.71572875254" y1="278.28427124746" x2="108.57864376269" y2="391.42135623731" style="stroke:rgb(180, 180, 180)" />
<line class="line" x1="210" y1="250" x2="50" y2="250" style="stroke:rgb(180, 180, 180)" />
<line class="line" x1="221.71572875254" y1="221.71572875254" x2="108.57864376269" y2="108.57864376269" style="stroke:rgb(180, 180, 180)" />
<!-- Beschriftung -->
<text text-anchor="middle" dy="0">
<textPath xlink:href="#textPathU-68cfdea07e622" startOffset="50%">
Grainy
</textPath>
</text>
<text text-anchor="middle" dy="0">
<textPath xlink:href="#textPathU-68cfdea07e622" startOffset="62.5%">
Grassy
</textPath>
</text>
<text text-anchor="middle" dy="0">
<textPath xlink:href="#textPathU-68cfdea07e622" startOffset="75%">
Fragrant
</textPath>
</text>
<text text-anchor="middle" dy="9px">
<textPath xlink:href="#textPathL-68cfdea07e622" startOffset="62.5%">
Fruity
</textPath>
</text>
<text text-anchor="middle" dy="9px">
<textPath xlink:href="#textPathL-68cfdea07e622" startOffset="50%">
Peaty
</textPath>
</text>
<text text-anchor="middle" dy="9px">
<textPath xlink:href="#textPathL-68cfdea07e622" startOffset="37.5%">
Woody
</textPath>
</text>
<text text-anchor="middle" dy="0">
<textPath xlink:href="#textPathU-68cfdea07e622" startOffset="25%">
Winey
</textPath>
</text>
<text text-anchor="middle" dy="0">
<textPath xlink:href="#textPathU-68cfdea07e622" startOffset="37.5%">
Off-Notes
</textPath>
</text>
<!-- Fläche -->
<polyline class="graph" points="{POINTS}" style="fill:rgb(250,208,72); fill-opacity:0.9" />
</svg>
"""
###################################################################################
def compute_wheel_points(
vals: List[float],
segments: int = 8,
offset_angle_deg: float = 0.0,
inner_radius: float = 40.0,
center: float = 250.0,
input_ratio: float = 40.0,
) -> List[Tuple[float, float]]:
# Repliziert die JS-Logik:
# angle = (360/segments*i + offsetAngle - 90) * (π*2/360)
# r = vals[i] * inputRatio + innerRadius
# x = cos(angle) * r + center
# y = sin(angle) * r + center
pts = []
for i, v in enumerate(vals):
# Align each segment by converting the polar angle to radians and shifting upwards.
angle_deg = (360.0 / segments) * i + offset_angle_deg - 90.0
angle = angle_deg * (math.pi * 2.0 / 360.0)
# Map the normalized input value onto the wheel radius and translate back to SVG center.
r = v * input_ratio + inner_radius
x = math.cos(angle) * r + center
y = math.sin(angle) * r + center
pts.append((x, y))
return pts
###################################################################################
def build_svg_with_values(
vals: List[float],
segments: int = 8,
offset_angle_deg: float = 0.0,
inner_radius: float = 40.0,
center: float = 250.0,
input_ratio: float = 40.0,
) -> str:
# Populate the SVG template with cartesian points generated from the input values.
pts = compute_wheel_points(
vals,
segments=segments,
offset_angle_deg=offset_angle_deg,
inner_radius=inner_radius,
center=center,
input_ratio=input_ratio,
)
# Build the `points` attribute string in the format expected by the SVG polyline element.
points_attr = " ".join(f"{x:.2f},{y:.2f}" for x, y in pts)
return SVG_BASE.format(POINTS=points_attr)
|