Skip to content

Commit

Permalink
refactors radar_chart to separate module
Browse files Browse the repository at this point in the history
  • Loading branch information
WolfgangFahl committed Feb 5, 2024
1 parent 70d59df commit f55a9e6
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 61 deletions.
2 changes: 1 addition & 1 deletion dcm/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.1.15"
__version__ = "0.1.16"
23 changes: 0 additions & 23 deletions dcm/dcm_chart.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
@author: wf
"""
import copy
import math
from typing import List, Optional, Tuple

from dcm.dcm_core import (
Expand All @@ -17,7 +16,6 @@
)
from dcm.svg import SVG, DonutSegment, SVGConfig, SVGNodeConfig


class DcmChart:
"""
a Dynamic competence map chart
Expand Down Expand Up @@ -126,27 +124,6 @@ def get_element_config(self, element: CompetenceElement) -> SVGNodeConfig:
)
return element_config

def calculate_radar_chart_points(
self,
scores: List[float],
max_score: float,
center: Tuple[float, float],
radius: float,
) -> List[Tuple[float, float]]:
num_axes = len(scores)
angle_per_axis = 2 * math.pi / num_axes # Angle between each axis in radians

points = []
for i, score in enumerate(scores):
angle = angle_per_axis * i # Angle for this axis
# Calculate the distance from the center for this point
distance = (score / max_score) * radius
x = center[0] + distance * math.cos(angle)
y = center[1] + distance * math.sin(angle)
points.append((x, y))

return points

def get_stacked_segment(
self,
level: int,
Expand Down
102 changes: 102 additions & 0 deletions dcm/radar_chart.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
'''
Created on 2024-02-05
@author: wf
'''
import math
from typing import List, Optional, Tuple
from dcm.svg import SVG, SVGNodeConfig, Polygon


class RadarChart:
"""
a radar chart
"""

def __init__(self,svg:SVG,max_score:float=100.0):
self.svg=svg
self.radius = self.svg.config.width / 2
self.center_x = self.radius
self.center_y = self.radius
self.max_score=max_score

def add_scale_circles(self,
num_circles: int = 10,
stroke_width: float = 1.0,
stroke_color: str = "black"):
"""
Add concentric circles to the SVG based on the SVG's configuration.
Args:
num_circles (int): The number of concentric circles to draw.
stroke_width (float): The stroke width of the circle lines.
stroke_color (str): The color of the circle lines.
"""
for i in range(1, num_circles + 1):
circle_radius = (self.radius * i) / num_circles
self.svg.add_circle(
SVGNodeConfig(
x=self.center_x,
y=self.center_y,
width=circle_radius,
stroke_width=stroke_width,
color=stroke_color,
fill="none" # Ensure circles are not filled
)
)

def calculate_radar_chart_points(self,
scores: List[float]) -> List[Tuple[float, float]]:
"""
Calculate the points for the radar chart based on the given scores.
Args:
scores (List[float]): The scores to be represented on the radar chart.
Returns:
List[Tuple[float, float]]: The list of points for the radar chart.
"""
num_axes = len(scores)
angle_per_axis = 2 * math.pi / num_axes # Angle between each axis in radians

points = []
for i, score in enumerate(scores):
angle = angle_per_axis * i # Angle for this axis
# Calculate the distance from the center for this point
distance = (score / self.max_score) * self.radius
x = self.center_x + distance * math.cos(angle)
y = self.center_y + distance * math.sin(angle)
points.append((x, y))

return points

def add_scores(self,
scores: List[float],
config: Optional[SVGNodeConfig] = None) -> None:
"""
Add the scores to the radar chart as a polygon.
Args:
scores (List[float]): The scores to be represented on the radar chart.
config (SVGNodeConfig, optional): The configuration for the polygon representing the scores.
""" # Use the function to calculate points for the scores
radar_points = self.calculate_radar_chart_points(
scores
)
if config is None:
config=SVGNodeConfig(
color="blue",
fill="none",
stroke_width=2.0,
opacity=0.5
)

# Create a Polygon for the radar chart
radar_chart_polygon = Polygon(
points=radar_points,
fill=config.fill,
stroke_width=config.stroke_width,
color=config.color,
opacity=config.opacity,
)
self.svg.add_polygon(radar_chart_polygon)
44 changes: 7 additions & 37 deletions tests/test_dcm_chart.py → tests/test_radar_chart.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from ngwidgets.basetest import Basetest

from dcm.dcm_chart import DcmChart
from dcm.radar_chart import RadarChart
from dcm.svg import SVG, Polygon, SVGConfig, SVGNodeConfig


Expand Down Expand Up @@ -60,43 +60,13 @@ def test_radar_chart(self):
"""
test radar chart creation
"""
dcm_chart = DcmChart(None)
# Define the center and radius for the radar chart
center = (300, 300) # Adjust as needed
radius = 200 # Adjust as needed

# Use the function to calculate points for the scores
radar_points = dcm_chart.calculate_radar_chart_points(
self.scores, max_score=100.0, center=center, radius=radius
)

# Create a Polygon for the radar chart
radar_chart_polygon = Polygon(
points=radar_points,
fill="none",
stroke_width=2.0,
color="blue",
opacity=0.5,
)

# Create an SVG instance and add the radar chart Polygon
# Create an SVG instance
svg = SVG(SVGConfig(width=600, height=600))

# Add concentric circles at every 10% interval
for i in range(1, 11):
circle_radius = (radius * i) / 10
svg.add_circle(
SVGNodeConfig(
x=center[0],
y=center[1],
width=circle_radius,
fill="none",
stroke_width=1.0,
color="black",
)
)
svg.add_polygon(radar_chart_polygon)

radar_chart = RadarChart(svg,max_score=100.0)
radar_chart.add_scale_circles()
radar_chart.add_scores(self.scores)

# Save the SVG to a file or inspect the SVG markup
svg_file_name = "radar_chart.svg"
self.save(svg, svg_file_name)
Expand All @@ -106,4 +76,4 @@ def test_radar_chart(self):
svg_markup = svg.get_svg_markup()
print(svg_markup)

self.assertTrue("""<polygon points="500.0""" in svg_markup)
self.assertTrue("""<polygon points="600.0""" in svg_markup)

0 comments on commit f55a9e6

Please sign in to comment.