def _path_to_parent(self, node): c = self.n2c[node]; theta1 = c.angle; r = c.depth M = Path.MOVETO; L = Path.LINETO pc = self.n2c[node.parent]; theta2 = pc.angle px1 = math.cos(math.radians(c.angle))*pc.depth py1 = math.sin(math.radians(c.angle))*pc.depth verts = [(c.x,c.y),(px1,py1)]; codes = [M,L] t1, t2 = tuple(sorted((theta1,theta2))) diam = pc.depth*2 arc = Arc((0,0), diam, diam, theta1=t1, theta2=t2) arcpath = arc.get_path() av = arcpath.vertices * pc.depth ac = arcpath.codes verts.extend(av.tolist()) codes.extend(ac.tolist()) return verts, codes
def transform_path_non_affine(self, path): vertices = path.vertices codes = path.codes steps = path._interpolation_steps x, y = np.array(list(zip(*vertices))) if len(vertices) > 1 and not isinstance(steps, int): if steps == 'inf_circle': z = x + y * 1j new_vertices = [] new_codes = [] for i in range(len(z) - 1): az = self._axes._moebius_z(0.5 * (z[i] + z[i+1])) zz = self._axes._moebius_z(z[i:i+2]) ax, ay = az.real, az.imag bz, cz = zz bx, cx = zz.real - ax by, cy = zz.imag - ay k = 2 * (bx * cy - by * cx) xm = (cy * (bx ** 2 + by ** 2) - by * (cx ** 2 + cy ** 2)) / k + ax ym = (bx * (cx ** 2 + cy ** 2) - cx * (bx ** 2 + by ** 2)) / k + ay zm = xm + ym * 1j d = 2 * abs(zm - az) ang0 = np.angle(bz - zm, deg=True) % 360 ang1 = np.angle(cz - zm, deg=True) % 360 reverse = ang0 > ang1 if reverse: ang0, ang1 = ang1, ang0 arc = Arc([xm, ym], d, d, theta1=ang0, theta2=ang1, transform=self._axes.transMoebius) arc_path = arc.get_patch_transform().transform_path(arc.get_path()) if reverse: new_vertices.append(arc_path.vertices[::-1]) else: new_vertices.append(arc_path.vertices) new_codes.append(arc_path.codes) new_vertices = np.concatenate(new_vertices) new_codes = np.concatenate(new_codes) elif steps == 'center_circle': points = self._axes._get_key("path.default_interpolation") z = self._axes._moebius_z(x + y * 1j) ang0, ang1 = np.angle(z[0:2]) % TWO_PI ccw = (ang1 - ang0) % TWO_PI < np.pi ix, iy = [np.real(z[0])], [np.imag(z[0])] new_codes = [Path.MOVETO] for i in range(len(z) - 1): zz = z[i:i + 2] r0, r1 = np.abs(zz) ang0, ang1 = np.angle(zz) % TWO_PI if ccw: if ang0 > ang1: ang1 += TWO_PI else: if ang1 > ang0: ang0 += TWO_PI r = np.linspace(r0, r1, points)[1:] ang = np.linspace(ang0, ang1, points)[1:] ix += list(np.cos(ang) * r) iy += list(np.sin(ang) * r) new_codes += (points - 1) * [Path.LINETO] new_vertices = list(zip(ix, iy)) else: raise ValueError("Interpolation must be either an integer, 'inf_circle' or 'center_circle'") else: if steps == 0: steps = self._axes._get_key("path.default_interpolation") ix, iy = ([x[0:1]], [y[0:1]]) for i in range(len(x) - 1): x0, x1 = x[i:i + 2] y0, y1 = y[i:i + 2] tx = self._axes.real_interp1d([x0, x1], steps)[1:] if abs(x0 - x1) > EPSILON: ty = y0 + (tx - x0) * (y1 - y0) / (x1 - x0) else: ty = self._axes.imag_interp1d([y0, y1], steps)[1:] ix.append(tx) iy.append(ty) if codes is not None: new_codes = Path.LINETO * np.ones((len(codes) - 1) * steps + 1) new_codes[0::steps] = codes else: new_codes = None new_vertices = self.transform_non_affine(list(zip(np.concatenate(ix), np.concatenate(iy)))) new_codes = codes return Path(new_vertices, new_codes, 1)