# 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 = """ Grainy Grassy Fragrant Fruity Peaty Woody Winey Off-Notes """ ################################################################################### 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)