Spaces:
Running on CPU Upgrade

whisky-wheel / lib /wheel.py
ziem-io's picture
Docs: Comments
d39782f
raw
history blame
5.6 kB
# 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)