Skip to content

Commit

Permalink
fixes #40
Browse files Browse the repository at this point in the history
  • Loading branch information
WolfgangFahl committed Feb 28, 2024
1 parent 7f0a1af commit bd21e28
Show file tree
Hide file tree
Showing 7 changed files with 376 additions and 176 deletions.
132 changes: 44 additions & 88 deletions dcm/dcm_chart.py
Original file line number Diff line number Diff line change
Expand Up @@ -317,86 +317,6 @@ def generate_pie_elements_for_segments(
self.generate_donut_segment_for_element(
svg, element, learner, segment=segment, ringspec=ringspec
)

def generate_pie_elements(
self,
level: int,
svg: SVG,
ct: CompetenceTree,
parent_element: CompetenceElement,
learner: Learner,
segment: DonutSegment,
):
"""
generate the pie elements (donut segments) for the subelements
of the given parent_element at the given level
e.g. aspects, areas or facets - taking the learner
achievements into account if a corresponding achievement
is found. The segment limits the area in
which the generation may operate
the symmetry level denotes at which level the rings should be symmetric
"""
sub_element_name = ct.level_attr_names[level]
# get the elements to be displayed
elements = getattr(parent_element, sub_element_name)
total = len(elements)
total_sub_elements = self.dcm.competence_tree.total_elements[sub_element_name]
hierarchy_level = sub_element_name[:-1]
# calculate inner and outer radius
ringspec = self.dcm.competence_tree.ring_specs[hierarchy_level]
text_mode = ringspec.text_mode
# Calculate the actual inner and outer radii
inner_radius = self.svg.config.width / 2 * ringspec.inner_ratio
outer_radius = self.svg.config.width / 2 * ringspec.outer_ratio
# are there any elements to be shown?
if total == 0:
# there are no subelements we might need a single
# empty donut segment
# but only if there are any other available subelements
# on this level
if total_sub_elements == 0:
return

sub_segment = DonutSegment(
cx=self.cx,
cy=self.cy,
inner_radius=inner_radius,
outer_radius=outer_radius,
start_angle=segment.start_angle,
end_angle=segment.end_angle,
text_mode=text_mode,
)
self.generate_donut_segment_for_element(
svg, element=None, learner=None, segment=sub_segment, ringspec=ringspec
)
else:
angle_per_element = (segment.end_angle - segment.start_angle) / total
start_angle = segment.start_angle
for element in elements:
end_angle = start_angle + angle_per_element
sub_segment = DonutSegment(
cx=self.cx,
cy=self.cy,
inner_radius=inner_radius,
outer_radius=outer_radius,
start_angle=start_angle,
end_angle=end_angle,
text_mode=text_mode,
)
self.generate_donut_segment_for_element(
svg, element, learner, segment=sub_segment, ringspec=ringspec
)
start_angle = end_angle
if level + 1 < ct.total_levels:
self.generate_pie_elements(
level=level + 1,
svg=svg,
ct=ct,
parent_element=element,
learner=learner,
segment=sub_segment,
)

def create_donut_segment(self,
parent_segment: DonutSegment,
Expand Down Expand Up @@ -457,24 +377,60 @@ def calculate_sub_segments(
"""
ringspec: RingSpec = ct.ring_specs[level_name]
sub_segments: Dict[str, DonutSegment] = {}

total_elements: int = len(elements)
if total_elements == 0:
attr_names={
"time": "time",
"score":"max_score"
}
if len(elements) == 0:
return sub_segments
num_zero_none_values = 0

if symmetry_mode=="count":
total = len(elements)
else:
attr_name=attr_names[symmetry_mode]
total=0
min_value = float('inf') # Initialize to infinity for proper minimum comparison

# Initial loop to calculate total and count 0/None values
for element in elements:
value = getattr(element, attr_name)
if value in (0, None):
num_zero_none_values += 1
else:
total += value
if value < min_value:
min_value = value

if total == 0 and num_zero_none_values == len(elements):
raise ValueError("All element values are 0 or None, cannot divide segment.")

angle_per_element: float = (parent_segment.end_angle - parent_segment.start_angle) / total_elements
start_angle: float = parent_segment.start_angle
# Correct handling when all values are not 0/None
# and therefore min_value was not updated
if num_zero_none_values>0:
# Adjust total value for 0/None values
# we use the min_value as a default
total += min_value * num_zero_none_values

start_angle = parent_segment.start_angle

for element in elements:
end_angle = start_angle + angle_per_element
segment: DonutSegment = self.create_donut_segment(
if symmetry_mode=="count":
value=1
else:
value = getattr(element, attr_name) or min_value
proportion = value / total
angle_span = (parent_segment.end_angle - parent_segment.start_angle) * proportion
end_angle = start_angle + angle_span

segment = self.create_donut_segment(
parent_segment, start_angle, end_angle, ringspec
)
# Add the segment with the element's path as the key
sub_segments[element.path] = segment
start_angle = end_angle

return sub_segments


def calculate_parent_segments(
self,
Expand Down
14 changes: 8 additions & 6 deletions dcm/dcm_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class RingSpec:
text_mode (Optional[str]): The mode of text display on the ring. Default is None.
inner_ratio (Optional[float]): The inner radius of the ring, relative to the chart size.
outer_ratio (Optional[float]): The outer radius of the ring, relative to the chart size.
symmetry_mode (Optional[str]): Specifies the symmetry mode for the ring. Supports "count", "time", or "score" to determine how the ring segments are balanced. Default is None.
symmetry_mode (Optional[str]): Specifies the symmetry mode for the ring. Supports "count", "time", "score" to determine how the ring segments are balanced. Default is None.
"""
text_mode: Optional[str] = "empty"
inner_ratio: Optional[float] = None
Expand Down Expand Up @@ -70,6 +70,12 @@ class CompetenceElement:
description: Optional[str] = None
color_code: Optional[str] = None
border_color: Optional[str] = None

time: Optional[float] = None
time_unit: Optional[str] = None # h/CP
max_score: Optional[float] = None # 100
score_unit: Optional[str] = None # %


def __post_init__(self):
# Set the id to the the slug of the name if id is None
Expand Down Expand Up @@ -127,11 +133,7 @@ class CompetenceFacet(CompetenceElement):
This class can include additional properties or methods specific to a competence facet.
"""

time: Optional[float] = None
time_unit: Optional[str] = "h"
max_score: Optional[float] = 100.0
score_unit: Optional[str] = "%"



@dataclass_json
Expand Down
30 changes: 29 additions & 1 deletion dcm_examples/architecture.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# see https://github.com/WolfgangFahl/dcm/issues/10
# see e.g. https://www.architektur.tu-darmstadt.de/studieren/studieninteressierte/studienangebot/bsc_architektur/kurzinformation_bsc_arch/index.en.jsp
# One CP corresponds to 30 hours of work
# created 2023-12-18 by WF
name: architecture
id: architecture
Expand All @@ -24,6 +26,8 @@ aspects:
url: https://en.wikipedia.org/wiki/Architectural_design
description: The art and science of designing buildings and structures.
color_code: '#719bc0'
time: 21.6
time_unit: CP
- name: Urban Planning
short_name: |
Urban
Expand All @@ -33,6 +37,8 @@ aspects:
description: The technical and political process concerned with the development
and design of land use.
color_code: '#6b96bf'
time: 16.2
time_unit: CP
- name: Building Codes and Regulations
short_name: |
Building
Expand All @@ -42,6 +48,8 @@ aspects:
description: The set of standards for the construction of buildings to ensure
safety and health for the occupants.
color_code: '#6590bd'
time: 8.1
time_unit: CP
- name: Sustainable Design
short_name: |
Sust
Expand All @@ -51,6 +59,8 @@ aspects:
description: Design that seeks to reduce negative impacts on the environment,
and the health and comfort of building occupants.
color_code: '#5f8bbc'
time: 8.1
time_unit: CP
- name: Technical Competence
short_name: |
Technical
Expand All @@ -69,6 +79,8 @@ aspects:
description: Engineering discipline concerned with the structural integrity
and strength of buildings or structures.
color_code: '#a48b70'
time: 18.0
time_unit: CP
- name: Building Technology
short_name: |
Building
Expand All @@ -78,6 +90,8 @@ aspects:
description: The application of technology to the design and construction of
buildings.
color_code: '#9e856b'
time: 13.5
time_unit: CP
- name: Material Science
short_name: |
Material
Expand All @@ -87,6 +101,8 @@ aspects:
description: The study of the properties and applications of materials of construction
or manufacture.
color_code: '#987f65'
time: 13.5
time_unit: CP
- name: Project Management and Administration
id: PMandA
short_name: |
Expand All @@ -106,6 +122,8 @@ aspects:
description: The process of leading the work of a team to achieve all project
goals within the given constraints.
color_code: '#b9aa8d'
time: 16.2
time_unit: CP
- name: Cost Estimation
short_name: |
Cost
Expand All @@ -115,6 +133,8 @@ aspects:
description: The approximate prediction of the cost of a program, project, or
operation.
color_code: '#b4a588'
time: 12.15
time_unit: CP
- name: Risk Management
short_name: |
Risk
Expand All @@ -125,6 +145,8 @@ aspects:
by coordinated and economical application of resources to minimize, monitor,
and control the probability or impact of unfortunate events.
color_code: '#afa083'
time: 12.15
time_unit: CP
- name: Professional Communication and Collaboration
id: PCandC
short_name: |
Expand All @@ -143,6 +165,8 @@ aspects:
url: https://en.wikipedia.org/wiki/Soft_skills#Interpersonal_skills
description: The skills used by a person to interact with others properly.
color_code: '#d4be9d'
time: 13.4
time_unit: CP
- name: Team Collaboration
short_name: |
Team
Expand All @@ -151,11 +175,15 @@ aspects:
url: https://en.wikipedia.org/wiki/Collaboration
description: Working jointly with others, especially in an intellectual endeavor.
color_code: '#cfb998'
time: 13.4
time_unit: CP
- name: Leadership
id: Leadership
url: https://en.wikipedia.org/wiki/Leadership
description: The action of leading a group of people or an organization.
color_code: '#cab493'
time: 13.7
time_unit: CP
levels:
- name: Novice
id: Level1
Expand Down Expand Up @@ -195,11 +223,11 @@ ring_specs:
text_mode: horizontal
inner_ratio: 0.167
outer_ratio: 0.5
symmetry_mode: count
area:
text_mode: angled
inner_ratio: 0.5
outer_ratio: 1.0
symmetry_mode: time
facet:
text_mode: empty
inner_ratio: 0.0
Expand Down
Loading

0 comments on commit bd21e28

Please sign in to comment.