Пример #1
0
def plot_cell_mayavi(lines,
                     boundary=None,
                     clf=True,
                     smooth=True,
                     min_seg_length=5,
                     **kwargs):
    import mayavi.mlab as may
    may.clf()

    hues = n.linspace(0, 1, len(lines) + 1)[:-1]
    colours = [hsv_to_rgb(hue, 1, 1) for hue in hues]
    random.shuffle(colours)
    i = 0
    for (line, colour) in zip(lines, colours):
        vprint('Plotting line {} / {}\r'.format(i, len(lines) - 1), False)
        i += 1
        for segment in line:
            if len(segment) < min_seg_length:
                continue
            plot_line(segment,
                      mode='mayavi',
                      clf=False,
                      color=colour,
                      **kwargs)

    if boundary is not None:
        draw_bounding_box_mayavi(boundary, **kwargs)
Пример #2
0
    def octree_simplify(self,
                        runs=1,
                        plot=False,
                        rotate=True,
                        obey_knotting=False,
                        **kwargs):
        '''
        Simplifies the curves via the octree reduction of
        :module:`pyknotid.simplify.octree`.

        Parameters
        ----------
        runs : int
            The number of times to run the octree simplification.
            Defaults to 1.
        plot : bool
            Whether to plot the curve after each run. Defaults to False.
        rotate : bool
            Whether to rotate the space curve before each run. Defaults
            to True as this can make things much faster.
        obey_knotting : bool
            Whether to not let the line pass through itself. Defaults to
            False - knotting of individual components will be ignored!
            This is *much* faster than the alternative.

        kwargs are passed to the :class:`pyknotid.simplify.octree.OctreeCell`
        constructor.
        '''
        from ..simplify.octree import OctreeCell, remove_nearby_points
        for line in self.lines:
            line.points = remove_nearby_points(line.points)
        for i in range(runs):
            if n.sum([len(knot.points) for knot in self.lines]) > 30:
                vprint(
                    '\rRun {} of {}, {} points remain'.format(
                        i, runs, len(self)), False, self.verbose)

            if rotate:
                rot_mat = get_rotation_matrix(n.random.random(3))
                for line in self.lines:
                    line._apply_matrix(rot_mat)

            oc = OctreeCell.from_lines([line.points for line in self.lines],
                                       **kwargs)
            oc.simplify(obey_knotting)
            self._recent_octree = oc
            self.lines = [Knot(line) for line in oc.get_lines()]
            for line in self.lines:
                line.points = remove_nearby_points(line.points)

            if rotate:
                for line in self.lines:
                    line._apply_matrix(rot_mat.T)

            if plot:
                self.plot()

        vprint('\nReduced to {} points'.format(len(self)))
Пример #3
0
def plot_cell_vispy(lines,
                    boundary=None,
                    clf=True,
                    colours=None,
                    randomise_colours=True,
                    tube_radius=1.,
                    **kwargs):
    if clf:
        clear_vispy_canvas()

    if colours is None:
        hues = n.linspace(0, 1, len(lines) + 1)[:-1]
        colours = [hsv_to_rgb(hue, 1, 1) for hue in hues]
        if randomise_colours:
            random.shuffle(colours)
    elif not isinstance(colours, (list, tuple)):
        colours = [colours for _ in lines]
    i = 0
    segments = []
    segment_colours = []
    segment_radii = []
    if not isinstance(tube_radius, list):
        tube_radius = [tube_radius for _ in range(len(lines))]
    for (line, colour, radius) in zip(lines, colours, tube_radius):
        vprint('Plotting line {} / {}\r'.format(i, len(lines) - 1), False)
        i += 1
        if len(colour) == 4 and colour[-1] == 0:
            continue
        for segment in line:
            if len(segment) < 4:
                continue
            segments.append(segment)
            segment_colours.append(colour)
            segment_radii.append(radius)
            # plot_line_vispy(segment,
            #                 clf=False, colour=colour, **kwargs)
    plot_lines_vispy(segments,
                     colours=segment_colours,
                     tube_radius=segment_radii,
                     clf=clf,
                     **kwargs)

    if boundary is not None:
        draw_bounding_box_vispy(boundary, tube_radius=tube_radius[0])
Пример #4
0
def writhing_numbers(gc, diagrams, based=False):
    '''Returns the signed sum of representations of the given Arrow
    diagrams in the given representation.

    Parameters
    ----------

    gc : A :class:`~pyknotid.representations.gausscode.GaussCode` or
         equivalent representation.
        The knot for which to find the writhes. 
    diagrams : str or list or tuple
        A list of strings, or single string, representing Arrow
        diagrams, e.g. '1-2+1+2-' for Vassiliev 2.
    based : bool
        Whether the diagrams have basepoints (if True, assumed to be
        just before the first entry).
    '''

    if not isinstance(diagrams, (list, tuple)):
        diagrams = [diagrams]

    multipliers = defaultdict(lambda: {})
    use_multipliers = False
    if any(['d' in diagram for diagram in diagrams]):
        use_multipliers = True
    if use_multipliers:
        for di, diagram in enumerate(diagrams):
            terms = diagram.split(',')
            for term in terms:
                if term[-1] == 'd':
                    multiplier = 2
                else:
                    multiplier = 1
                term = int(term[:-2]) if 'd' in term else int(term[:-1])
                multipliers[diagram.replace('d', '')][term] = multiplier
            diagrams[di] = diagram.replace('d', '')

    for d in diagrams:
        validate_diagram(d)

    level = 0

    code = gc._gauss_code
    code = code[0]
    gc_len = len(gc)
    code_len = len(code)
    from pyknotid.invariants import _crossing_arrows_and_signs
    arrows, signs = _crossing_arrows_and_signs(code, gc.crossing_numbers)

    crossing_numbers = list(gc.crossing_numbers)

    # degrees = [len(diagram.split(',')) for diagram in diagrams]

    degrees = defaultdict(lambda: [])
    for diagram in diagrams:
        degrees[len(diagram.split(',')) // 2].append(diagram)

    relations = {diagram: [] for diagram in diagrams}
    for diagram in diagrams:
        degree = len(diagram.split(',')) // 2
        num_relations = factorial(degree - 1) * 4

        terms = diagram.split(',')
        numbers = [term[:-1] for term in terms]

        number_strs = list(sorted(set(numbers), key=lambda j: int(j)))
        for i, number in enumerate(number_strs):
            for oi, other_number in enumerate(number_strs[i + 1:]):
                oi += i + 1
                if i != 0:
                    if terms.index(number + '-') < terms.index(other_number +
                                                               '-'):
                        relations[diagram].append(
                            lambda l, i=i, oi=oi: l[i][0] < l[oi][0])
                    else:
                        relations[diagram].append(
                            lambda l, i=i, oi=oi: l[i][0] > l[oi][0])

                if terms.index(number + '-') < terms.index(other_number + '+'):
                    relations[diagram].append(
                        lambda l, i=i, oi=oi: l[i][0] < l[oi][1])
                else:
                    relations[diagram].append(
                        lambda l, i=i, oi=oi: l[i][0] > l[oi][1])

                if terms.index(number + '+') < terms.index(other_number + '-'):
                    relations[diagram].append(
                        lambda l, i=i, oi=oi: l[i][1] < l[oi][0])
                else:
                    relations[diagram].append(
                        lambda l, i=i, oi=oi: l[i][1] > l[oi][0])

                # This one seems to not be necessary for diagrams where all arrows cross?
                if terms.index(number + '+') < terms.index(other_number + '+'):
                    relations[diagram].append(
                        lambda l, i=i, oi=oi: l[i][1] < l[oi][1])
                else:
                    relations[diagram].append(
                        lambda l, i=i, oi=oi: l[i][1] > l[oi][1])

            if i == 0:
                continue
            if terms.index(number + '+') < terms.index(number + '-'):
                relations[diagram].append(
                    lambda l, i=i, oi=oi: l[i][1] < l[i][0])
            else:
                relations[diagram].append(
                    lambda l, i=i, oi=oi: l[i][1] > l[i][0])

    max_degree = max(degrees.keys())

    representations_sums = {d: 0 for d in diagrams}
    used_sets = {d: set() for d in diagrams}

    combs = combinations(crossing_numbers, max_degree)
    try:
        num_combs = (factorial(len(crossing_numbers)) //
                     factorial(max_degree) //
                     factorial(len(crossing_numbers) - max_degree))
    except ValueError:
        num_combs = 0
    strs = [None for _ in range(max_degree)] * 2
    order = [None for _ in range(max_degree)] * 2
    for ci, comb in enumerate(combs):
        if ci % 10000 == 0:
            vprint('\rCombination {} of {}    '.format(ci + 1, num_combs),
                   newline=False,
                   condition=(ci % 10000) == 0)

        if based:
            perms = [comb]
        else:
            perms = permutations(comb)

        ordered_indices = tuple(sorted(comb))
        for diagram in diagrams:
            if ordered_indices not in used_sets[diagram]:
                break
        else:
            continue

        for perm in perms:
            cur_arrows = [list(arrows[i]) for i in perm]

            a1s = cur_arrows[0][0]
            if based:
                a1s = 0

            for i, arrow in enumerate(cur_arrows):
                arrow[0] = (arrow[0] - a1s) % code_len
                arrow[1] = (arrow[1] - a1s) % code_len

            for diagram in diagrams:
                if ordered_indices in used_sets[diagram]:
                    continue
                for relation in relations[diagram]:
                    if not relation(cur_arrows):
                        break
                else:
                    if use_multipliers:
                        representations_sums[diagram] += (reduce(
                            lambda x, y: x * y, [
                                signs[arrow_i]**multipliers[diagram][num + 1]
                                for num, arrow_i in enumerate(perm)
                            ]))
                    else:
                        representations_sums[diagram] += (reduce(
                            lambda x, y: x * y,
                            [signs[arrow_i] for arrow_i in perm]))
                    used_sets[diagram].add(ordered_indices)

    vprint()

    return representations_sums
Пример #5
0
 def _vprint(self, s, newline=True):
     '''Prints s, with optional newline. Intended for internal use
     in displaying progress.'''
     if self.verbose:
         vprint(s, newline)
Пример #6
0
def plot_sphere_mollweide_vispy(func,
                                circle_points=50,
                                depth=2,
                                edge_color=None,
                                cmap='hsv',
                                smooth=0,
                                mesh='circles',
                                **kwargs):
    '''func must be a function of sphere angles theta, phi'''

    # from vispy.scene import Sphere, ArcballCamera
    from vispy.scene import TurntableCamera, Mesh

    if mesh == 'circles':
        vertices, indices = circles_ellipse_mesh(circle_points, depth)
    else:
        vertices, indices = recursive_ellipse_mesh(circle_points, depth)
    vertices[:, 0] *= 2 * n.sqrt(2)
    vertices[:, 1] *= n.sqrt(2)
    mesh = Mesh(vertices, indices)

    md = mesh._meshdata
    vertices = md.get_vertices()

    values = n.zeros(len(vertices))

    print('pre')
    thetas = []
    phis = []
    for i, vertex in enumerate(vertices):
        if i % 10 == 0:
            vprint('\ri = {} / {}'.format(i, len(vertices)), newline=False)

        intermediate = n.arcsin(vertex[1] / n.sqrt(2))
        theta = n.arcsin((2 * intermediate + n.sin(2 * intermediate)) / n.pi)
        phi = n.pi * vertex[0] / (2 * n.sqrt(2) * n.cos(intermediate))

        # theta = n.arccos(vertex[2])
        # phi = n.arctan2(vertex[1], vertex[0])

        if n.isnan(theta):
            theta = 0.0
            print('theta', vertex)
        if n.isnan(phi):
            phi = 0.0
            print('phi', vertex)

        thetas.append(theta)
        phis.append(phi)
        values[i] = func(theta + n.pi / 2, phi + n.pi)
    vprint()

    print('thetas', n.min(thetas), n.max(thetas))
    print('phis', n.min(phis), n.max(phis))

    colours = n.zeros((len(values), 4))
    max_val = n.max(values)
    min_val = n.min(values)
    unique_values = n.unique(colours)
    max_val += (1. + 1. / len(unique_values)) * (max_val - min_val)
    diff = (max_val - min_val)

    import matplotlib.pyplot as plt
    cm = plt.get_cmap(cmap)
    for i in range(len(colours)):
        colours[i] = cm(((values[i] - min_val) / diff))

    colours[:, -1] = 1.

    faces = md.get_faces()
    for si in range(smooth):
        new_colours = [[n.array(row) for _ in range(3)] for row in colours]
        for i, face in enumerate(faces):
            new_colours[face[0]].append(colours[face[1]])
            new_colours[face[0]].append(colours[face[2]])
            new_colours[face[1]].append(colours[face[0]])
            new_colours[face[1]].append(colours[face[2]])
            new_colours[face[2]].append(colours[face[0]])
            new_colours[face[2]].append(colours[face[1]])

        new_colours = n.array([n.average(cs, axis=0) for cs in new_colours])

        colours = new_colours

    md.set_vertex_colors(colours)

    ensure_vispy_canvas()
    clear_vispy_canvas()
    vispy_canvas.view.camera = TurntableCamera(fov=0, elevation=90.)
    vispy_canvas.view.add(mesh)
    vispy_canvas.show()
Пример #7
0
def plot_sphere_shell_vispy(func,
                            rows=100,
                            cols=100,
                            radius=1.,
                            opacity=1.,
                            translation=(0., 0., 0.),
                            method='latitude',
                            edge_color=None,
                            cmap='hsv',
                            smooth=0,
                            cutoff=0.4,
                            cutoff_max=0.8,
                            transparent_side=True,
                            **kwargs):
    '''func must be a function of sphere angles theta, phi'''

    from vispy.scene import Sphere, ArcballCamera

    s = Sphere(rows=rows,
               cols=cols,
               method=method,
               edge_color=edge_color,
               radius=radius)
    mesh = s.mesh
    md = mesh._meshdata
    vertices = md.get_vertices()
    md.set_vertices(vertices + n.array(translation))

    values = n.zeros(len(vertices))
    opacities = n.ones(len(vertices))

    print('pre')
    for i, vertex in enumerate(vertices):
        if i % 10 == 0:
            vprint('\ri = {} / {}'.format(i, len(vertices)), newline=False)
        vertex = vertex / n.sqrt(n.sum(vertex * vertex))
        theta = n.arccos(vertex[2])
        phi = n.arctan2(vertex[1], vertex[0])

        if n.isnan(theta):
            theta = 0.0
        values[i] = func(theta, phi)
        distance = vertex[1] - cutoff
        distance_frac = distance / (cutoff_max - cutoff)
        opacity = max(0, 1. - distance_frac)
        opacities[i] = 1. if vertex[1] < cutoff else opacity
    vprint()

    colours = n.zeros((len(values), 4))
    max_val = n.max(values)
    min_val = n.min(values)
    unique_values = n.unique(colours)
    # max_val += (1. + 1./len(unique_values))*(max_val - min_val)
    diff = (max_val - min_val)

    import matplotlib.pyplot as plt
    cm = plt.get_cmap(cmap)
    for i in range(len(colours)):
        colours[i] = cm(((values[i] - min_val) / diff))

    colours[:, -1] = opacity

    faces = md.get_faces()
    for si in range(smooth):
        new_colours = [[n.array(row) for _ in range(3)] for row in colours]
        for i, face in enumerate(faces):
            new_colours[face[0]].append(colours[face[1]])
            new_colours[face[0]].append(colours[face[2]])
            new_colours[face[1]].append(colours[face[0]])
            new_colours[face[1]].append(colours[face[2]])
            new_colours[face[2]].append(colours[face[0]])
            new_colours[face[2]].append(colours[face[1]])

        new_colours = n.array([n.average(cs, axis=0) for cs in new_colours])

        colours = new_colours

    colours = [(c[0], c[1], c[2], o) for c, o in zip(colours, opacities)]

    md.set_vertex_colors(colours)

    ensure_vispy_canvas()
    vispy_canvas.view.camera = ArcballCamera(fov=30)
    vispy_canvas.view.add(s)
    vispy_canvas.show()

    return colours
Пример #8
0
def plot_sphere_lambert_sharp_vispy(func,
                                    circle_points=50,
                                    depth=2,
                                    output_size=500,
                                    edge_color=None,
                                    cmap='brg',
                                    smooth=0,
                                    mesh='circles',
                                    **kwargs):
    '''func must be a function of sphere angles theta, phi'''

    from vispy.scene import TurntableCamera, Mesh

    if mesh == 'circles':
        vertices, indices = circles_ellipse_mesh(circle_points, depth)
    else:
        vertices, indices = recursive_ellipse_mesh(circle_points, depth)
    vertices[:, 0] *= 2
    vertices[:, 1] *= 2
    mesh = Mesh(vertices, indices)

    md = mesh._meshdata
    vertices = md.get_vertices()

    values = n.zeros(len(vertices))

    print('pre')
    thetas = []
    phis = []
    for i, vertex in enumerate(vertices):
        if i % 10 == 0:
            vprint('\ri = {} / {}'.format(i, len(vertices)), newline=False)

        theta = 2 * np.arccos(np.sqrt(vertex[0]**2 + vertex[1]**2) / 2.)
        phi = np.arctan2(vertex[1], vertex[0])

        if n.isnan(theta):
            theta = 0.0
            print('theta', vertex)
        if n.isnan(phi):
            phi = 0.0
            print('phi', vertex)

        thetas.append(theta)
        phis.append(phi)
        values[i] = func(theta + n.pi / 2, phi + n.pi)
    vprint()

    return thetas, phis, values

    import svgwrite as svg
    d = svg.Drawing()

    import matplotlib.pyplot as plt
    cmap = plt.get_cmap(cmap)

    max_value = n.max(values)
    min_value = n.min(values)

    def normalise(v):
        return (v - min_value) / (max_value - min_value)

    for tri_i, triangle in enumerate(indices):
        v1 = vertices[triangle[0]]
        v2 = vertices[triangle[1]]
        v3 = vertices[triangle[2]]

        c1 = values[triangle[0]]
        c2 = values[triangle[1]]
        c3 = values[triangle[2]]

        offset_x = 2.001412
        offset_y = 2.0214
        v1_x = (v1[0] + offset_x) / 4. * output_size
        v1_y = (v1[1] + offset_y) / 4. * output_size

        v2_x = (v2[0] + offset_x) / 4. * output_size
        v2_y = (v2[1] + offset_y) / 4. * output_size

        v3_x = (v3[0] + offset_x) / 4. * output_size
        v3_y = (v3[1] + offset_y) / 4. * output_size

        c_x = n.average([v1_x, v2_x, v3_x])
        c_y = n.average([v1_y, v2_y, v3_y])

        v12_x = (v1_x + v2_x) / 2.
        v12_y = (v1_y + v2_y) / 2.
        v13_x = (v1_x + v3_x) / 2.
        v13_y = (v1_y + v3_y) / 2.
        v23_x = (v2_x + v3_x) / 2.
        v23_y = (v2_y + v3_y) / 2.

        cmap_1 = cmap(normalise(c1))
        rgb_cmap1 = [int(c * 255) for c in cmap_1[:3]]
        d.add(
            d.polygon(
                [[v1_x, v1_y], [v12_x, v12_y], [c_x, c_y], [v13_x, v13_y]],
                fill='rgb({},{},{})'.format(*rgb_cmap1),
                stroke='rgb({},{},{})'.format(*rgb_cmap1),
                stroke_width='0.5'))

        cmap_2 = cmap(normalise(c2))
        rgb_cmap2 = [int(c * 255) for c in cmap_2[:3]]
        d.add(
            d.polygon(
                [[v2_x, v2_y], [v12_x, v12_y], [c_x, c_y], [v23_x, v23_y]],
                fill='rgb({},{},{})'.format(*rgb_cmap2),
                stroke='rgb({},{},{})'.format(*rgb_cmap2),
                stroke_width='0.5'))

        cmap_3 = cmap(normalise(c3))
        rgb_cmap3 = [int(c * 255) for c in cmap_3[:3]]
        d.add(
            d.polygon(
                [[v3_x, v3_y], [v13_x, v13_y], [c_x, c_y], [v23_x, v23_y]],
                fill='rgb({},{},{})'.format(*rgb_cmap3),
                stroke='rgb({},{},{})'.format(*rgb_cmap3),
                stroke_width='0.5'))

        # print('cols', c1, cmap_1, c2, cmap_2, c3, cmap_3)

    return d