Example #1
0
def draw_circle(ax, x, y, color, scale=0.1, line_weight=1.0, zorder=2):
    path = Path(Path.unit_circle().vertices * scale, Path.unit_circle().codes)
    trans = matplotlib.transforms.Affine2D().translate(x, y)
    t_path = path.transformed(trans)
    patch = patches.PathPatch(
        t_path, facecolor=color.value, lw=line_weight, zorder=zorder)
    ax.add_patch(patch)
    return
def draw_star(ax, x, y, color, scale=0.1):
    path = Path(unit_star.vertices * scale, unit_star.codes)
    trans = matplotlib.transforms.Affine2D().translate(x, y)
    t_path = path.transformed(trans)
    patch = patches.PathPatch(t_path, facecolor=color.value, lw=line_weight, zorder=2)
    a = ax.add_patch(patch)
    ma = MonosaccharidePatch(saccharide_shape=(a,))
    return ma
def draw_generic(ax, x, y, name, n_points=6, scale=0.1):
    unit_polygon = Path.unit_regular_polygon(n_points)
    path = Path(unit_polygon.vertices * scale, unit_polygon.codes)
    trans = matplotlib.transforms.Affine2D().translate(x, y)
    t_path = path.transformed(trans)
    name = TextPath((x - (0.35 * scale), y), s=name, size=2 * scale * .25)
    patch = patches.PathPatch(t_path, facecolor="white", lw=line_weight, zorder=2)
    a = ax.add_patch(patch)
    patch = patches.PathPatch(name, lw=line_weight, zorder=2)
    s = ax.add_patch(patch)
    ma = MonosaccharidePatch(saccharide_shape=(a,), saccharide_label=(s,))
    return ma
Example #4
0
def make_custom_marker(text, flip_y=False):
    from matplotlib.path import Path
    from matplotlib.textpath import TextPath
    from matplotlib.font_manager import FontProperties

    textPath = TextPath((0, 4), text, size=3)
    textPath = textPath.transformed(mpl.transforms.Affine2D().translate(
        -1 * len(text), 0))
    circle = Path.unit_circle()
    triangle = Path([[0, 0], [1, 0], [0.5, 0.5], [0, 0]],
                    [Path.MOVETO, Path.LINETO, Path.LINETO, Path.CLOSEPOLY])
    triangle = triangle.transformed(mpl.transforms.Affine2D().translate(
        -0.5, 0).scale(3, -4).translate(0, 3))

    verts = np.concatenate(
        [circle.vertices, textPath.vertices, triangle.vertices])
    codes = np.concatenate([circle.codes, textPath.codes, triangle.codes])
    combined_marker = Path(verts, codes)

    combined_marker = combined_marker.transformed(
        mpl.transforms.Affine2D().scale(1000, -1000 if flip_y else 1000))

    return combined_marker
Example #5
0
    def _render_patches(self, axes, aa_pixel_size=0, **kwargs):
        result = []

        vertices = self.vertices
        scale_factors = np.linalg.norm(self.orientations, axis=-1)**2

        if self.outline > 0:
            outer_vertices = vertices
            vertices = geometry.insetPolygon(vertices, self.outline)

            commands = [
                Path.MOVETO
            ] + (vertices.shape[0] - 1) * [Path.LINETO] + [Path.CLOSEPOLY]
            commands = 2 * commands

            # reverse the inner vertices order to make an open
            # polygon. Duplicate the first vertex of each polygon to
            # close the shapes.
            outline_vertices = np.concatenate([
                outer_vertices, outer_vertices[:1], vertices[::-1],
                vertices[:1]
            ],
                                              axis=0)

            outline_path = Path(outline_vertices, commands)

            patches = []
            for (position, angle, scale) in zip(self.positions, self.angles,
                                                scale_factors):
                tf = Affine2D().scale(scale).rotate(angle).translate(*position)
                patches.append(PathPatch(outline_path.transformed(tf)))

            outline_colors = np.zeros_like(self.colors)
            outline_colors[:, 3] = self.colors[:, 3]
            result.append((patches, outline_colors))

            vertices += np.sign(vertices) * aa_pixel_size

        patches = []
        for (position, angle, scale) in zip(self.positions, self.angles,
                                            scale_factors):
            tf = Affine2D().scale(scale).rotate(angle).translate(*position)
            patches.append(Polygon(vertices, closed=True, transform=tf))
        result.append((patches, self.colors))

        return result
Example #6
0
    def __init__(self, id, position, direction, colour, t, y):
        super().__init__(id, position)
        self._direction = direction
        self._colour = colour

        # Scale y values so absolute maximum becomes 1
        maxabs = y[np.argmax(abs(y))]
        if maxabs != 0.0: y /= maxabs

        xy = np.empty((len(t), 2), dtype=np.float_)
        xy[:, 0] = t
        xy[:, 1] = y

        # Create a simplified path, scaled to ensure it will have a resonable number of points
        scale = 1000.0/abs(t[1] - t[0])
        xfm = Affine2D().scale(scale, scale)
        simplified = Path(xy).cleaned(transform=xfm, simplify=True)

        # Generate the SVG path, transforming back to the original data values
        self._path = _path.convert_to_string(simplified.transformed(xfm.inverted()), None, None, False, None, 6, [b'M', b'L', b'Q', b'C', b'z'], False).decode('ascii')
Example #7
0
    def agent(self,
              step: Step = None,
              agent_name: str = None,
              location: Location = None,
              rotation: float = None,
              color=None,
              size: float = 40.0,
              show_trajectory: bool = True,
              marker: Path = None):
        if step:
            agent_name = step.agent_name
            location = step.location
            rotation = step.rotation

        # if show_trajectory:
        #     self.agents_trajectories.append(step)
        #     x = self.agents_trajectories.get_agent_trajectory(agent_name).get("location").get("x")
        #     y = self.agents_trajectories.get_agent_trajectory(agent_name).get("location").get("y")
        #     self.agents[agent_name], = self.ax.plot(x, y, c=color)

        if not marker:
            if agent_name in self.agents_markers:
                marker = self.agents_markers[agent_name]
            else:
                if agent_name == "predator":
                    marker = Agent_markers.robot()
                else:
                    marker = Agent_markers.mouse()

        if agent_name not in self.agents:
            self.agents[agent_name], = self.ax.plot(location.x,
                                                    location.y,
                                                    marker=marker,
                                                    c=color,
                                                    markersize=size)

        t = Affine2D().rotate_deg_around(0, 0, -rotation)
        self.agents[agent_name].set_marker(marker.transformed(t))
        self.agents[agent_name].set_xdata(location.x)
        self.agents[agent_name].set_ydata(location.y)
        self.agents[agent_name].set_color(color)
def draw_square(ax, x, y, color, scale=0.1):
    square_verts = np.array([
        (0.5, 0.5),
        (0.5, -0.5),
        (-0.5, -0.5),
        (-0.5, 0.5),
        (0.5, 0.5),
        (0., 0.),
    ]) * 2
    square_codes = [
        Path.MOVETO,
        Path.LINETO,
        Path.LINETO,
        Path.LINETO,
        Path.LINETO,
        Path.CLOSEPOLY,
    ]
    path = Path(square_verts * scale, square_codes)
    trans = matplotlib.transforms.Affine2D().translate(x, y)
    t_path = path.transformed(trans)
    patch = patches.PathPatch(t_path, facecolor=color.value, lw=line_weight, zorder=2)
    a = ax.add_patch(patch)
    ma = MonosaccharidePatch(saccharide_shape=(a,))
    return ma
Example #9
0
    def _render_patches(self, axes, aa_pixel_size=0, **kwargs):
        result = []

        vertices = self.vertices
        # distance vector from each vertex to the next vertex in a given shape
        delta_verts = np.roll(vertices, -1, axis=0) - vertices
        delta_verts /= np.linalg.norm(delta_verts, axis=-1, keepdims=True)
        # the normal vector of the edge originating at each vertex
        vert_normals = np.transpose([delta_verts[:, 1], -delta_verts[:, 0]])

        # start and end angles for the arc around each vertex, in degrees
        degree_ends = 180/np.pi*np.arctan2(vert_normals[..., 1], vert_normals[..., 0])
        degree_starts = np.roll(degree_ends, 1, axis=0)

        radius = self.radius
        outline = self.outline
        delta_outline = radius - outline

        if outline > 0:
            # sketch out the outline, using the full radius
            commands = [Path.MOVETO]
            positions = [vertices[-1] + vert_normals[-1]*radius]
            for (vert, norm, degrees_start, degrees_end) in zip(
                    vertices, np.roll(vert_normals, 1, axis=0),
                    degree_starts, degree_ends):
                commands.append(Path.LINETO)
                positions.append(vert + norm*radius)
                arc = Path.arc(degrees_start, degrees_end)
                for (pos, cmd) in arc.iter_segments():
                    if cmd in {Path.STOP, Path.MOVETO}:
                        continue
                    pos = pos.reshape((-1, 2))
                    commands.extend(pos.shape[0]*[cmd])
                    positions.extend(vert[np.newaxis] + pos*radius)

            # repeat the outline path creation but in reverse to make
            # the hole for the colored portion of the shape
            commands.append(Path.MOVETO)
            positions.append(vertices[0] + vert_normals[-1]*delta_outline)
            for (vert, norm, degrees_end, degrees_start) in zip(
                    vertices[::-1], vert_normals[::-1],
                    degree_ends[::-1], degree_starts[::-1]):
                commands.append(Path.LINETO)
                positions.append(vert + norm*delta_outline)
                arc = Path.arc(degrees_start, degrees_end)
                for (pos, cmd) in reversed(list(arc.iter_segments())):
                    if cmd in {Path.STOP, Path.MOVETO}:
                        continue
                    pos = pos.reshape((-1, 2))[::-1]
                    commands.extend(pos.shape[0]*[cmd])
                    positions.extend(vert[np.newaxis] + pos*delta_outline)
            path = Path(positions, commands)

            patches = []
            for (position, angle) in zip(self.positions, self.angles):
                tf = Affine2D().rotate(angle).translate(*position)
                patches.append(PathPatch(path.transformed(tf)))
            outline_colors = np.zeros_like(self.colors)
            outline_colors[:, 3] = self.colors[:, 3]

            result.append((patches, outline_colors))

            vertices += np.sign(vertices)*aa_pixel_size

        # create the path for the filled/colored portion of the shape
        commands = [Path.MOVETO]
        positions = [vertices[-1] + vert_normals[-1]*delta_outline]
        for (vert, norm, degrees_start, degrees_end) in zip(
                vertices, np.roll(vert_normals, 1, axis=0), degree_starts, degree_ends):
            commands.append(Path.LINETO)
            positions.append(vert + norm*delta_outline)
            arc = Path.arc(degrees_start, degrees_end)
            for (pos, cmd) in arc.iter_segments():
                if cmd in {Path.STOP, Path.MOVETO}:
                    continue
                pos = pos.reshape((-1, 2))*delta_outline
                commands.extend(pos.shape[0]*[cmd])
                positions.extend(vert[np.newaxis] + pos)
        path = Path(positions, commands)

        patches = []
        for (position, angle) in zip(self.positions, self.angles):
            tf = Affine2D().rotate(angle).translate(*position)
            patches.append(PathPatch(path.transformed(tf)))
        result.append((patches, self.colors))

        return result
Example #10
0
def plot_fish(ax,
              fish,
              pos=(0, 0),
              direction=(1, 0),
              size=20.0,
              bend=0,
              scaley=1,
              bodykwargs={},
              finkwargs={}):
    """ Plot body and fin of an electric fish.

    Parameters
    ----------
    ax: matplotlib axes
        Axes where to draw the fish.
    fish: string or tuple or dict
        Specifies a fish to show:
        - any of the strings defining a shape contained in the `fish_shapes` dictionary,
        - a tuple with the name of the fish as the first element and 'top' or 'side' as the second element,
        - a dictionary with at least a 'body' key holding pathes to be drawn.
    pos: tuple of floats
        Coordinates of the fish's position (its center).
    direction: tuple of floats
        Coordinates of a vector defining the orientation of the fish.
    size: float
        Size of the fish.
    bend: float
        Bending angle of the fish's tail in degree.
    scaley: float
        Scale factor applied in y direction after bending and rotation to
        compensate for differently scaled axes.
    bodykwargs: dict
        Key-word arguments for PathPatch used to draw the fish's body.
    finkwargs: dict
        Key-word arguments for PathPatch used to draw the fish's fins.

    Returns
    -------
    bpatch: matplotlib.patches.PathPatch
        The fish's body. Can be used for set_clip_path().

    Example
    -------

    ```
    fig, ax = plt.subplots()
    bodykwargs=dict(lw=1, edgecolor='k', facecolor='k')
    finkwargs=dict(lw=1, edgecolor='k', facecolor='grey')
    fish = (('Eigenmannia', 'side'), (0, 0), (1, 0), 20.0, -25)
    plot_fish(ax, *fish, bodykwargs=bodykwargs, finkwargs=finkwargs)
    ax.set_xlim(-15, 15)
    ax.set_ylim(-10, 10)
    plt.show()
    ```
    """
    # retrieve fish shape:
    if not isinstance(fish, dict):
        if isinstance(fish, (tuple, list)):
            if fish[1] == 'top':
                fish = fish_top_shapes[fish[0]]
            else:
                fish = fish_side_shapes[fish[0]]
        else:
            fish = fish_shapes[fish]
    bpatch = None
    size_fac = 1.1
    bbox = bbox_pathes(*fish.values())
    for part, verts in fish.items():
        verts = bend_path(verts, bend, size, size_fac)
        codes = np.zeros(len(verts))
        codes[:] = Path.LINETO
        codes[0] = Path.MOVETO
        codes[-1] = Path.CLOSEPOLY
        path = Path(verts, codes)
        #pixelx = np.abs(np.diff(ax.get_window_extent().get_points()[:,0]))[0]
        #pixely = np.abs(np.diff(ax.get_window_extent().get_points()[:,1]))[0]
        #xmin, xmax = ax.get_xlim()
        #ymin, ymax = ax.get_ylim()
        #dxu = np.abs(xmax - xmin)/pixelx
        #dyu = np.abs(ymax - ymin)/pixely
        trans = mpl.transforms.Affine2D()
        angle = np.arctan2(direction[1], direction[0])
        trans.rotate(angle)
        #trans.scale(dxu/dyu, dyu/dxu)   # what is the right scaling????
        trans.scale(1, scaley)
        trans.translate(*pos)
        path = path.transformed(trans)
        kwargs = bodykwargs if part == 'body' else finkwargs
        patch = PathPatch(path, **kwargs)
        if part == 'body':
            bpatch = patch
        ax.add_patch(patch)
    return bpatch