def calculate_angles( structured_paths: List[List[List[Path]]], path_values: Dict[Path, float], ) -> Dict[Path, Angles]: angles: Dict[Path, Angles] = {} # return value # the total sum of all elements (on one level) value_sum = path_values[Path(())] for level_no, groups in enumerate(structured_paths): for group in groups: theta2 = None # else pycharm complains about theta2 undefined for path_no, path in enumerate(group): # First we determine the starting angle (theta1) for the wedge # corresponding to the path. if level_no == 0: # This corresponds to the inner circle (because level 0 # only contains the empty path, the root of the whole tree) theta1 = 0 elif path_no == 0: # The first path of a group. Since the wedges must be # aligned with the parent, we have to get this value # from the parent. theta1 = angles[path.parent()].theta1 else: # we continue the wedge where the previous one had stopped theta1 = theta2 # type: ignore # Now we determine the ending angle based on the fraction of # the value. theta2 = theta1 + 360 * path_values[path] / value_sum angles[path] = Angles(theta1, theta2) return angles
def complete_pv(pathvalues: Dict[Path, float]) -> Dict[Path, float]: """Consider a pathvalue dictionary of the form Dict[Path, float] e.g. {1.1.1: 12.0} (here: only one entry). This function will disect each path and assign its value to the truncated path: e.g. here 1, 1.1 and 1.1.1. Thus we get {1: 12.0, 1.1: 12.0, 1.1.1: 12.0}. For more items the values will be summed accordingly. Furthermore the total sum of the items of the topmost level will be assigned to the empty path. For this to make sense we require that no empty path is in the data beforehand"" :param pathvalues: {path: value} dictionary :return: {path: value} dictionary """ if Path(()) in pathvalues: raise ValueError( "This function does not allow the empty path as item" "in the data list." ) completed: DefaultDict[Path, float] = collections.defaultdict(float) for path, value in pathvalues.items(): # len(path) +1 ensures that also the whole tag is considered # starting point 0: also add to empty path. for level in range(0, len(path) + 1): completed[path[:level]] += value return dict(completed)
def test_ancestors(self): for path in self.paths.values(): ancestors = path.ancestors() self.assertEqual(len(ancestors), len(path) + 1) self.assertIn(Path(()), ancestors) self.assertIn(path, ancestors) self.assertIn(path.parent(), ancestors)
def test_slice(self): for _, path in self.paths.items(): for i in range(len(path)): for j in range(len(path)): self.assertIsInstance(path[i:j], Path) if i > j: self.assertEqual(path[i:j], Path(())) if i == j - 1: self.assertEqual(path[i:j], path[i]) if i == 0 and j == len(path): self.assertEqual(path[i:j], path)
def complete_paths(paths: List[Path]) -> List[Path]: """Like complete_pv, only that it tries to preserve the order of paths.""" ret = [Path(())] for path in paths: for i in range(1, len(path)): # iterate over all "real" ancestors ancestor = path[:i] if ancestor not in paths and ancestor not in ret: # will not come up later: insert before path ret.append(ancestor) ret.append(path) return ret
def test_init(self): self.assertEqual(Path(""), self.paths["empty"]) self.assertEqual(Path("abc"), self.paths["triple"]) for i in range(10): with self.subTest(i=i): self.assertEqual(len(Path("a" * i)), i) self.assertEqual(len(Path(["a"] * i)), i) self.assertEqual(len(Path(("a", ) * i)), i) self.assertEqual(len(Path(("", )) * i), i)
def test_charvalues_to_pathvalues(self): charvalues = {"123": 1.0, "": 2.0, "1": 3.0} pathvalues = {Path("123"): 1.0, Path(()): 2.0, Path("1"): 3.0} self.assertEqual(charvalues_to_pv(charvalues), pathvalues)
def test_startswith(self): for path in self.paths.values(): self.assertTrue(path.startswith(Path(()))) for ancestor in path.ancestors(): self.assertTrue(path.startswith(ancestor))
def setUp(self): self.paths = { "empty": Path(()), "triple": Path(("a", "b", "c")), "unicode": Path(("東京", )), }
def test_parent(self): self.assertEqual(self.paths["empty"].parent(), Path(())) self.assertEqual(self.paths["unicode"].parent(), Path(())) self.assertEqual(self.paths["triple"].parent(), Path(("a", "b")))