Skip to content

Commit

Permalink
fixes #25
Browse files Browse the repository at this point in the history
  • Loading branch information
WolfgangFahl committed Jan 24, 2024
1 parent 25e37af commit d1e261a
Show file tree
Hide file tree
Showing 11 changed files with 1,901 additions and 65 deletions.
28 changes: 15 additions & 13 deletions dcm/dcm_chart.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ def prepare_and_add_inner_circle(
self.radius_steps = competence_tree.total_levels
self.tree_radius = config.width / 2 / self.radius_steps / 2
if "tree" in competence_tree.relative_radius:
_inner,outer=competence_tree.relative_radius.get("tree")
self.tree_radius=outer *config.width/2
_inner, outer = competence_tree.relative_radius.get("tree")
self.tree_radius = outer * config.width / 2

self.circle_config = competence_tree.to_svg_node_config(
x=self.cx, y=self.cy, width=self.tree_radius
)
Expand All @@ -60,7 +60,7 @@ def prepare_and_add_inner_circle(
self.cx,
self.cy,
competence_tree.short_name,
text_anchor = "middle",
text_anchor="middle",
center_v=True,
fill="white",
)
Expand Down Expand Up @@ -230,8 +230,8 @@ def generate_donut_segment_for_element(
generate a donut segment for a given element of
the CompetenceTree
"""
if segment.outer_radius==0.0:
result=segment
if segment.outer_radius == 0.0:
result = segment
else:
# Simply create the donut segment without considering the achievement
result = self.add_donut_segment(svg=svg, element=element, segment=segment)
Expand Down Expand Up @@ -265,16 +265,18 @@ def generate_pie_elements(
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]
hierarchy_level = sub_element_name[:-1]
if hierarchy_level in self.dcm.competence_tree.relative_radius:
# calculate inner and outer radius
inner_ratio, outer_ratio = self.dcm.competence_tree.relative_radius[hierarchy_level]
inner_ratio, outer_ratio = self.dcm.competence_tree.relative_radius[
hierarchy_level
]
# Calculate the actual inner and outer radii
inner_radius = self.svg.config.width/2 * inner_ratio
outer_radius = self.svg.config.width/2 * outer_ratio
inner_radius = self.svg.config.width / 2 * inner_ratio
outer_radius = self.svg.config.width / 2 * outer_ratio
else:
inner_radius=segment.outer_radius
outer_radius=segment.outer_radius + self.tree_radius * 2
inner_radius = segment.outer_radius
outer_radius = segment.outer_radius + self.tree_radius * 2
# are there any elements to be shown?
if total == 0:
# there are no subelements we might need a single
Expand All @@ -283,7 +285,7 @@ def generate_pie_elements(
# on this level
if total_sub_elements == 0:
return

sub_segment = DonutSegment(
cx=self.cx,
cy=self.cy,
Expand Down
9 changes: 7 additions & 2 deletions dcm/svg.py
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,12 @@ def add_legend_column(
self.add_text(x, y - height, title, font_weight="bold")
for index, (color, label) in enumerate(items):
self.add_rectangle(x, y + index * (height + 5), width, height, color)
self.add_text(x + width + 10, y + index * (height + 5) + height / 2, label,center_v=True)
self.add_text(
x + width + 10,
y + index * (height + 5) + height / 2,
label,
center_v=True,
)

def add_text(
self,
Expand Down Expand Up @@ -616,7 +621,7 @@ def add_text_to_donut_segment(
font_weight="normal",
indent_level=indent_level,
transform=transform,
text_anchor = "middle",
text_anchor="middle",
center_v=True,
)

Expand Down
79 changes: 79 additions & 0 deletions dcm/xapi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
"""
Created on 2024-01-24
Experience API xAPI support module
@author: wf
"""
import json
import sys

from dcm.dcm_core import Achievement, CompetenceTree, Learner


class XAPI:
"""
Experience API xAPI support class
"""

def __init__(self):
self.xapi_dict = {}

def warn(self, msg):
print(msg, file=sys.stderr)
pass

def to_learner(self, competence_tree: CompetenceTree) -> Learner:
"""
Convert xapi_dict to a Learner with Achievements.
Args:
competence_tree (CompetenceTree): The competence tree to align the achievements with.
Returns:
Learner: A learner object with achievements mapped from xapi_dict.
"""
# Assuming each entry in xapi_dict is an xAPI statement relevant to a learning activity
achievements = []
actor_id = None
learner = None
for entry in self.xapi_dict:
stmt=entry.get("statement")
if stmt:
actor=stmt.get("actor")
if actor:
# Extract necessary information from the xAPI statement
new_actor_id = actor["account"]["name"]
if actor_id is None:
actor_id = new_actor_id
else:
if new_actor_id != actor_id:
self.warn(f"invalid actor_id {new_actor_id} != {actor_id}")
competence_path = stmt["context"]["extensions"][
"learningObjectMetadata"
]["competencePath"]
score_scaled = stmt["result"]["score"]["scaled"]
timestamp = stmt["timestamp"]

# Create an Achievement instance
achievement = Achievement(
path=competence_path,
level=int(
score_scaled * competence_tree.total_valid_levels
), # Convert scaled score to level
score=stmt["result"]["score"]["raw"],
date_assessed_iso=timestamp,
)
achievements.append(achievement)

if actor_id:
# Create a Learner instance with these achievements
learner = Learner(learner_id=actor_id, achievements=achievements)
else:
self.warn("no learner / actor defined")
return learner

@classmethod
def from_json(cls, json_file_path: str):
xapi = cls()
# Open and read the JSON file
with open(json_file_path, "r") as json_file:
xapi.xapi_dict = json.load(json_file)
return xapi
2 changes: 1 addition & 1 deletion dcm_examples/greta.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: GRETA
short_name: GRETA
id: GRETA
id: greta_v2_0
url: https://www.greta-die.de/webpages/greta-interaktiv
description: GRETA-Kompetenzmodell 2.0
total_levels: 4
Expand Down
109 changes: 109 additions & 0 deletions dcm_examples/greta_learner_xapi_example1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
{
"learner_id": "1116e424-b4f9-45a2-acc1-c5d54350daea",
"achievements": [
{
"path": "greta_v2_0/BerufspraktischesWissenUndKoennen/BeratungIndividualisierteLernunterstuetzung/Teilnehmendenorientierung",
"level": 3,
"score": 3,
"score_unit": "%",
"evidence": null,
"date_assessed_iso": "2023-09-17T11:03:33.863Z"
},
{
"path": "greta_v2_0/BerufspraktischesWissenUndKoennen/BeratungIndividualisierteLernunterstuetzung/Teilnehmendenorientierung",
"level": 3,
"score": 3,
"score_unit": "%",
"evidence": null,
"date_assessed_iso": "2023-09-23T11:03:33.863Z"
},
{
"path": "greta_v2_0/BerufspraktischesWissenUndKoennen/BeratungIndividualisierteLernunterstuetzung/Teilnehmendenorientierung",
"level": 3,
"score": 3,
"score_unit": "%",
"evidence": null,
"date_assessed_iso": "2023-09-18T11:03:33.863Z"
},
{
"path": "greta_v2_0/ProfessionelleSelbststeuerung/MotivationaleOrientierungen/Selbstwirksamkeitsueberzeugungen",
"level": 3,
"score": 3,
"score_unit": "%",
"evidence": null,
"date_assessed_iso": "2023-09-25T11:03:33.863Z"
},
{
"path": "greta_v2_0/ProfessionelleSelbststeuerung/MotivationaleOrientierungen/Selbstwirksamkeitsueberzeugungen",
"level": 3,
"score": 3,
"score_unit": "%",
"evidence": null,
"date_assessed_iso": "2023-09-23T11:03:33.863Z"
},
{
"path": "greta_v2_0/BerufspraktischesWissenUndKoennen/DidaktikUndMethodik/RahmenbedingungenUndLernumgebungen",
"level": 3,
"score": 3,
"score_unit": "%",
"evidence": null,
"date_assessed_iso": "2023-09-19T11:03:33.863Z"
},
{
"path": "greta_v2_0/BerufspraktischesWissenUndKoennen/DidaktikUndMethodik/RahmenbedingungenUndLernumgebungen",
"level": 3,
"score": 3,
"score_unit": "%",
"evidence": null,
"date_assessed_iso": "2023-09-17T11:03:33.863Z"
},
{
"path": "greta_v2_0/BerufspraktischesWissenUndKoennen/DidaktikUndMethodik/Outcomeorientierung",
"level": 3,
"score": 3,
"score_unit": "%",
"evidence": null,
"date_assessed_iso": "2023-09-22T11:03:33.863Z"
},
{
"path": "greta_v2_0/BerufspraktischesWissenUndKoennen/DidaktikUndMethodik/Outcomeorientierung",
"level": 3,
"score": 3,
"score_unit": "%",
"evidence": null,
"date_assessed_iso": "2023-09-17T11:03:33.863Z"
},
{
"path": "greta_v2_0/BerufspraktischesWissenUndKoennen/DidaktikUndMethodik/LerninhalteUndZiele",
"level": 3,
"score": 3,
"score_unit": "%",
"evidence": null,
"date_assessed_iso": "2023-09-17T11:03:33.863Z"
},
{
"path": "greta_v2_0/BerufspraktischesWissenUndKoennen/DidaktikUndMethodik/LerninhalteUndZiele",
"level": 3,
"score": 3,
"score_unit": "%",
"evidence": null,
"date_assessed_iso": "2023-09-18T11:03:33.863Z"
},
{
"path": "greta_v2_0/ProfessionelleSelbststeuerung/MotivationaleOrientierungen/Enthusiasmus",
"level": 3,
"score": 3,
"score_unit": "%",
"evidence": null,
"date_assessed_iso": "2023-09-26T11:03:33.863Z"
},
{
"path": "greta_v2_0/ProfessionelleSelbststeuerung/MotivationaleOrientierungen/Enthusiasmus",
"level": 3,
"score": 3,
"score_unit": "%",
"evidence": null,
"date_assessed_iso": "2023-09-25T11:03:33.863Z"
}
]
}
Loading

0 comments on commit d1e261a

Please sign in to comment.