Пример #1
0
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
Пример #2
0
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)
Пример #3
0
 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)
Пример #4
0
 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)
Пример #5
0
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
Пример #6
0
 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)
Пример #7
0
 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)
Пример #8
0
 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))
Пример #9
0
 def setUp(self):
     self.paths = {
         "empty": Path(()),
         "triple": Path(("a", "b", "c")),
         "unicode": Path(("東京", )),
     }
Пример #10
0
 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")))