Ejemplo n.º 1
0
def add_china_map_2basemap(ax,name ="province", facecolor='none',
                           edgecolor='c', lw=2, encoding='utf-8', **kwargs):
    """
    Add china province boundary to basemap instance.
    :param mp: basemap instance.
    :param ax: matplotlib axes instance.
    :param name: map name.
    :param facecolor: fill color, default is none.
    :param edgecolor: edge color.
    :param lw: line width.
    :param kwargs: keywords passing to Polygon.
    :return: None.
    """

    # map name
    names = {'nation': "bou1_4p", 'province': "bou2_4p",
             'county': "BOUNT_poly", 'river': "hyd1_4p",
             'river_high': "hyd2_4p"}
        # get shape file and information
    shpfile = pkg_resources.resource_filename(
        'meteva', "resources/maps/" + names[name])
    shp1 = readshapefile(shpfile, default_encoding=encoding)
    lines = LineCollection(shp1,antialiaseds=(1,))
    lines.set_color(edgecolor)
    lines.set_linewidth(lw)
    lines.set_label('_nolabel_')
    ax.add_collection(lines)
Ejemplo n.º 2
0
def plot_multicolor_line(splot,
                         x,
                         y,
                         z,
                         cmap=None,
                         vmin=None,
                         vmax=None,
                         lw=None,
                         label=None,
                         off_x=0,
                         off_y=0):
    """
    Adds a line to a plot that changes color based on the z-value and a cmap (default=viridis)
    """
    # Based on the matplotlib example: https://matplotlib.org/gallery/lines_bars_and_markers/multicolored_line.html
    points = np.array([x, y]).T.reshape(-1, 1, 2)
    segments = np.concatenate([points[:-1], points[1:]], axis=1)
    xo = np.ones(len(segments)) * off_x
    yo = np.ones(len(segments)) * off_y
    # xyo = list(zip(xo, yo))
    xyo = np.array([xo, yo]).T
    lc = LineCollection(segments,
                        cmap=cmap,
                        offsets=xyo,
                        transOffset=matplotlib.transforms.IdentityTransform())
    lc.set_array(z)
    lc.set_clim(vmin=vmin, vmax=vmax)
    if lw is not None:
        lc.set_linewidth(lw)
    if label is not None:
        lc.set_label(label)
    return splot.add_collection(lc)
Ejemplo n.º 3
0
    def loadlines(self,
                  name,
                  curdir='beijingJson',
                  zorder=None,
                  linewidth=0.5,
                  color='k',
                  antialiased=1,
                  ax=None,
                  default_encoding='utf-8',
                  linestyle='-',
                  linesalpha=1):
        # get current axes instance (if none specified).
        filename = curdir + '/' + name + '.json'
        coords = json.load(codecs.open(filename, 'r', 'utf-8'))
        coords = self.projectcoords(coords)

        ax = ax or self._check_ax()
        # make LineCollections for each polygon.
        lines = LineCollection(coords, antialiaseds=(1, ))
        lines.set_color(color)
        lines.set_linewidth(linewidth)
        lines.set_linestyle(linestyle)
        lines.set_alpha(linesalpha)
        lines.set_label('_nolabel_')
        if zorder is not None:
            lines.set_zorder(zorder)
        ax.add_collection(lines)
        # set axes limits to fit map region.
        self.set_axes_limits(ax=ax)
        # clip boundaries to map limbs
        lines, c = self._cliplimb(ax, lines)
        self.__dict__[name] = coords
        return lines
Ejemplo n.º 4
0
def draw_swap_gate(axes, gate_pos, wire_pos1, wire_pos2, plot_params):
    """
    Draws the symbol for a SWAP gate.

    Args:
        axes (matplotlib.axes.Axes): axes object
        x (float): x coordinate [data units]
        y1 (float): y coordinate of the 1st qubit wire
        y2 (float): y coordinate of the 2nd qubit wire
        plot_params (dict): plot parameters
    """
    delta = plot_params['swap_delta']

    lines = []
    for wire_pos in (wire_pos1, wire_pos2):
        lines.append([(gate_pos - delta, wire_pos - delta),
                      (gate_pos + delta, wire_pos + delta)])
        lines.append([(gate_pos - delta, wire_pos + delta),
                      (gate_pos + delta, wire_pos - delta)])
    lines.append([(gate_pos, wire_pos1), (gate_pos, wire_pos2)])

    gate = LineCollection(lines,
                          colors='k',
                          linewidths=plot_params['linewidth'])
    gate.set_label('SWAP')
    axes.add_collection(gate)
Ejemplo n.º 5
0
def add_trajectory(fig_lung, name, color_map, line_label, show_predicted, data):
    plt.figure(fig_lung.number) # set fig as current figure    
    if show_predicted:
        T = len(data.dx_predicted)
        for i in range(T):
            if i % 50 == 0:
                plt.plot(data.dx_predicted[i][:, 1], 
                         data.dx_predicted[i][:, 0],
                         '.-', color = purple, alpha = 0.1,
                         label = 'predicted trajectory')
    
    y = data.x_sensed[:,1] - data.x_sensed[0,1]
    x = data.x_sensed[:,0] - data.x_sensed[0,0]
    t = np.linspace(2, 10, len(y))
    points = np.array([y, x]).T.reshape(-1, 1, 2)
    segments = np.concatenate([points[:-1], points[1:]], axis=1)

    lc = LineCollection(segments, cmap=color_map,
                        norm=plt.Normalize(0, 10))
    lc.set_array(t)
    lc.set_linewidth(3)
    lc.set_label(line_label)
    plt.gca().add_collection(lc)
    
    plt.plot(data.x_desired[:,1] - data.x_sensed[0,1], 
             data.x_desired[:,0] - data.x_sensed[0,0], 
             'g.', label = 'desired')
    point_count = 0
    last_xd = np.array([])
    offset_y = 0.75
    offset_x = 1
    for i, xd in enumerate(data.x_desired):
        if not np.array_equal(xd, last_xd):
            plt.text(xd[1] + offset_y, xd[0] + offset_x, 
                     str(point_count), color = green)
            last_xd = xd.copy()
            point_count += 1
            
    ax = plt.gca()
    handles, labels = ax.get_legend_handles_labels()
    newLabels, newHandles = [], []
    for handle, label in zip(handles, labels):
        if label not in newLabels:
            newLabels.append(label)
            newHandles.append(handle)
    plt.legend(newHandles, newLabels, loc = 'upper left', bbox_to_anchor = [1,1])
    legend = ax.get_legend()
    
    for i, name in enumerate(newLabels):
        if name.lower() == 'ukf + mpc':
            legend.legendHandles[i].set_color(blue)
        elif name.lower() == 'mlc':
            legend.legendHandles[i].set_color(red)
        elif name.lower() == 'tip trajectory':
            legend.legendHandles[i].set_color(purple)
Ejemplo n.º 6
0
    def plot_magnetic_trace(self, fig, x, y):
        plt.figure(fig.number)

        t = np.linspace(2, 10, len(x))
        points = np.array([x,y]).T.reshape(-1, 1, 2)
        segments = np.concatenate([points[:-1], points[1:]], axis=1)

        lc = LineCollection(segments, cmap=blues_cmap,
                            norm=plt.Normalize(0, 10))
        lc.set_array(t)
        lc.set_linewidth(3)
        lc.set_label('sensed position')
        plt.gca().add_collection(lc)
        return fig
Ejemplo n.º 7
0
 def plot(self, plot, col):
   # Set the scale of the plot
   if self.log_x:
     plot.xscale('log')
   if self.log_y:
     plot.yscale('log')
   # Process the values
   values = []
   for x in self.get_x_data_gen().get_values():
     for y in self.get_y_data_gen().get_values():
       values.append(zip(x,y))
   lines = LineCollection(values)
   lines.set_color(col)
   lines.set_label(str(self.get_name()))
   # Plot the values
   plot.add_collection(lines)
Ejemplo n.º 8
0
def draw_wires(axes, n_labels, gate_grid, wire_grid, plot_params):
    """
    Draws all the circuit qubit wires.

    Args:
        axes (matplotlib.axes.Axes): axes object
        n_labels (int): number of qubit
        gate_grid (ndarray): array with the ref. x positions of the gates
        wire_grid (ndarray): array with the ref. y positions of the qubit
                             wires
        plot_params (dict): plot parameters
    """
    # pylint: disable=invalid-name

    lines = []
    for i in range(n_labels):
        lines.append(((gate_grid[0] - plot_params['column_spacing'],
                       wire_grid[i]), (gate_grid[-1], wire_grid[i])))
    all_lines = LineCollection(lines,
                               linewidths=plot_params['linewidth'],
                               edgecolor='k')
    all_lines.set_label('qubit_wires')
    axes.add_collection(all_lines)
Ejemplo n.º 9
0
class DecayLine(object):
    def __init__(self, n_points, tail_length, rgb_color, zorder=2, label=None):
        self.n_points = int(n_points)
        self.tail_length = int(tail_length)
        self.rgb_color = rgb_color
        self._zorder = zorder
        self.lc = None
        self._label = label
        self.dbg = True

    def __str__(self):
        if not hasattr(self, 'points') or not hasattr(self, 'segments'):
            return ""
        res = "DecayLine:" + "\n\t{}".format(self.segments)
        return res

    def set_data(self, x=None, y=None):
        if x is None or y is None:
            self.lc = LineCollection([], linewidths=1.0, zorder=self._zorder)
        else:
            # ensure we don't start with more points than we want
            x = x[-self.n_points:]
            y = y[-self.n_points:]
            # create a list of points with shape (len(x), 1, 2)
            # array([[[  x0  ,  y0  ]],
            #        [[  x1  ,  y1  ]],
            #        ...,
            #        [[  xn  ,  yn  ]]])
            #self.points = np.array([x, y]).T.reshape(-1, 1, 2)
            if not hasattr(self, 'points'):
                self.points = deque([[x[i], y[i]] for i in range(len(x))])
            else:
                for i in range(len(x)):
                    self.points.append([x[i], y[i]])
            # group each point with the one following it (shape (len(x)-1, 2, 2)):
            # array([[[  x0  ,   y0  ],
            #         [  x1  ,   y1  ]],
            #        [[  x1  ,   y1  ],
            #         [  x2  ,   y2  ]],
            #         ...
            # self.segments = np.concatenate([self.points[:-1], self.points[1:]],  axis=1)
            if len(self.points) > 1:
                pts = np.array(self.points).reshape(-1, 1, 2)
                self.segments = np.concatenate([pts[:-1], pts[1:]], axis=1)
                if hasattr(self, 'alphas'):
                    del self.alphas
                if hasattr(self, 'rgba_colors'):
                    del self.rgba_colors

                if self.lc is None:
                    self.lc = LineCollection(
                        self.segments,
                        colors=self.get_colors(),
                        linewidths=1.0,
                        zorder=self._zorder,
                        label="" if self._label is None else self._label)
                self.lc.set_segments(self.segments)
                colours = self.get_colors()
                if self.dbg:
                    print(colours)
                    self.dbg = False
                self.lc.set_color(colours)
                self.lc.set_edgecolors(colours)
                # self.lc.set_facecolors(colours)
            else:
                if self.lc is None:
                    self.lc = LineCollection(
                        [],
                        linewidths=1.0,
                        colors=(self.rgb_color[0], self.rgb_color[1],
                                self.rgb_color[2], 1.0),
                        zorder=self._zorder,
                        label="" if self._label is None else self._label)

    def get_LineCollection(self):
        if not hasattr(self, 'lc'):
            self.set_data()
        return self.lc

    def get_label(self):
        """Return the label used for this artist in the legend."""
        if self.lc is None:
            return "" if self._label is None else self._label
        return self.lc.get_label()

    def set_label(self, s):
        self._label = s
        if self.lc is not None:
            self.lc.set_label(self._label)

    def add_point(self, x, y):
        if not hasattr(self, 'points') or not hasattr(self, 'segments'):
            self.set_data([x], [y])
        else:
            # TODO: could use a circular buffer to reduce memory operations...
            # self.segments = np.concatenate((self.segments,[[self.points[-1][0],[x,y]]]))
            # self.points = np.concatenate((self.points, [[[x,y]]]))
            self.points.append([x, y])
            # remove points if necessary:
            while len(self.points) > self.n_points:
                self.points.popleft()
            pts = np.array(self.points).reshape(-1, 1, 2)
            self.segments = np.concatenate([pts[:-1], pts[1:]], axis=1)
            self.lc.set_segments(self.segments)
            colours = self.get_colors()
            self.lc.set_color(colours)
            self.lc.set_edgecolors(colours)
            # self.lc.set_facecolors(colours)

    @property
    def npoints(self):
        if not hasattr(self, 'points'):
            return 0
        else:
            #return self.points.shape[0]
            return len(self.points)

    def get_alphas(self):
        n_segments = self.n_points - 1
        n = len(self.segments)
        # n = self.points.shape[0]
        if n < n_segments:
            rest_length = n_segments - self.tail_length
            if n <= rest_length:
                return np.ones(n)
            else:
                tail_length = n - rest_length
                tail = np.linspace(1. / tail_length, 1., tail_length)
                rest = np.ones(rest_length)
                return np.concatenate((tail, rest), axis=None)
        else:  # n == n_segments
            if not hasattr(self, 'alphas'):
                tail = np.linspace(1. / self.tail_length, 1., self.tail_length)
                rest = np.ones(n_segments - self.tail_length)
                self.alphas = np.concatenate((tail, rest), axis=None)
            return self.alphas

    def get_colors(self):
        n_segments = self.n_points - 1
        n = len(self.segments)
        if n < 2:
            # return [self.rgb_color+[1.] for i in range(n)]
            colour = None
            if isinstance(self.rgb_color, np.ndarray):
                colour = np.concatenate([self.rgb_color, [
                    1.0,
                ]])
            elif type(self.rgb_color) in [list, tuple]:
                colour = self.rgb_color + [1.]
            return [colour for i in range(n)]
        if n < n_segments:
            alphas = self.get_alphas()
            rgba_colors = np.zeros((n, 4), dtype=np.float32)
            # first place the rgb color in the first three columns
            rgba_colors[:, 0:3] = self.rgb_color[:]
            # and the fourth column needs to be your alphas
            rgba_colors[:, 3] = alphas
            # self.rgba_colors = rgba_colors
            # return self.rgba_colors
            return rgba_colors
        else:
            if hasattr(self, 'rgba_colors'):
                pass
            else:
                alphas = self.get_alphas()
                rgba_colors = np.zeros((n, 4), dtype=np.float32)
                # first place the rgb color in the first three columns
                rgba_colors[:, 0:3] = self.rgb_color[:]
                # and the fourth column needs to be your alphas
                rgba_colors[:, 3] = alphas
                self.rgba_colors = rgba_colors
            return self.rgba_colors

    get_color = get_colors  # for compatibility with old versions
Ejemplo n.º 10
0
    G = nx.read_gpickle(args['graph'])
    graph_data = nx.get_node_attributes(G, 'pos')
    data = np.array(tuple(graph_data.values()))
    try:
        labels = nx.get_node_attributes(G, 'label')
        labels = np.array(list(labels.values()))
    except:
        labels = np.zeros(len(data))
    instances = np.zeros(len(data))
    edgelist = list(G.edges())
    edge_pos = np.asarray([(graph_data[e[0]], graph_data[e[1]])
                           for e in edgelist])
    edge_collection = LineCollection(edge_pos)
    edge_collection.set_zorder(1)  # edges go behind nodes
    edge_collection.set_label(None)

    fig, ax = plt.subplots()

    pts = ax.scatter(data[:, 0], data[:, 1], s=80, c=labels)
    ax.add_collection(edge_collection)
    selector = SelectFromCollection(ax, pts)
    fc = pts.get_facecolors()
    mode = 'SELECT'
    instance = 1

    fig.suptitle("Mode: " + mode + " | Instance: " + str(instance),
                 x=0.5,
                 y=0.05)
    ann_list = []
Ejemplo n.º 11
0
def draw_networkx_edges(
    G,
    pos,
    edgelist=None,
    width=1.0,
    edge_color="k",
    style="solid",
    alpha=None,
    arrowstyle="-|>",
    arrowsize=10,
    edge_cmap=None,
    edge_vmin=None,
    edge_vmax=None,
    ax=None,
    arrows=True,
    label=None,
    node_size=300,
    nodelist=None,
    node_shape="o",
    connectionstyle=None,
    min_source_margin=0,
    min_target_margin=0,
):
    """Draw the edges of the graph G.

    This draws only the edges of the graph G.

    Parameters
    ----------
    G : graph
       A networkx graph

    pos : dictionary
       A dictionary with nodes as keys and positions as values.
       Positions should be sequences of length 2.

    edgelist : collection of edge tuples
       Draw only specified edges(default=G.edges())

    width : float, or array of floats
       Line width of edges (default=1.0)

    edge_color : color or array of colors (default='k')
       Edge color. Can be a single color or a sequence of colors with the same
       length as edgelist. Color can be string, or rgb (or rgba) tuple of
       floats from 0-1. If numeric values are specified they will be
       mapped to colors using the edge_cmap and edge_vmin,edge_vmax parameters.

    style : string
       Edge line style (default='solid') (solid|dashed|dotted,dashdot)

    alpha : float
       The edge transparency (default=None)

    edge_ cmap : Matplotlib colormap
       Colormap for mapping intensities of edges (default=None)

    edge_vmin,edge_vmax : floats
       Minimum and maximum for edge colormap scaling (default=None)

    ax : Matplotlib Axes object, optional
       Draw the graph in the specified Matplotlib axes.

    arrows : bool, optional (default=True)
       For directed graphs, if True draw arrowheads.
       Note: Arrows will be the same color as edges.

    arrowstyle : str, optional (default='-|>')
       For directed graphs, choose the style of the arrow heads.
       See :py:class: `matplotlib.patches.ArrowStyle` for more
       options.

    arrowsize : int, optional (default=10)
       For directed graphs, choose the size of the arrow head head's length and
       width. See :py:class: `matplotlib.patches.FancyArrowPatch` for attribute
       `mutation_scale` for more info.

    connectionstyle : str, optional (default=None)
       Pass the connectionstyle parameter to create curved arc of rounding
       radius rad. For example, connectionstyle='arc3,rad=0.2'.
       See :py:class: `matplotlib.patches.ConnectionStyle` and
       :py:class: `matplotlib.patches.FancyArrowPatch` for more info.

    label : [None| string]
       Label for legend

    min_source_margin : int, optional (default=0)
       The minimum margin (gap) at the begining of the edge at the source.

    min_target_margin : int, optional (default=0)
       The minimum margin (gap) at the end of the edge at the target.

    Returns
    -------
    matplotlib.collection.LineCollection
        `LineCollection` of the edges

    list of matplotlib.patches.FancyArrowPatch
        `FancyArrowPatch` instances of the directed edges

    Depending whether the drawing includes arrows or not.

    Notes
    -----
    For directed graphs, arrows are drawn at the head end.  Arrows can be
    turned off with keyword arrows=False. Be sure to include `node_size` as a
    keyword argument; arrows are drawn considering the size of nodes.

    Examples
    --------
    >>> G = nx.dodecahedral_graph()
    >>> edges = nx.draw_networkx_edges(G, pos=nx.spring_layout(G))

    >>> G = nx.DiGraph()
    >>> G.add_edges_from([(1, 2), (1, 3), (2, 3)])
    >>> arcs = nx.draw_networkx_edges(G, pos=nx.spring_layout(G))
    >>> alphas = [0.3, 0.4, 0.5]
    >>> for i, arc in enumerate(arcs):  # change alpha values of arcs
    ...     arc.set_alpha(alphas[i])

    Also see the NetworkX drawing examples at
    https://networkx.github.io/documentation/latest/auto_examples/index.html

    See Also
    --------
    draw()
    draw_networkx()
    draw_networkx_nodes()
    draw_networkx_labels()
    draw_networkx_edge_labels()
    """
    try:
        import matplotlib.pyplot as plt
        from matplotlib.colors import colorConverter, Colormap, Normalize
        from matplotlib.collections import LineCollection
        from matplotlib.patches import FancyArrowPatch
        import numpy as np
    except ImportError as e:
        raise ImportError("Matplotlib required for draw()") from e
    except RuntimeError:
        print("Matplotlib unable to open display")
        raise

    if ax is None:
        ax = plt.gca()

    if edgelist is None:
        edgelist = list(G.edges())

    if len(edgelist) == 0:  # no edges!
        if not G.is_directed() or not arrows:
            return LineCollection(None)
        else:
            return []

    if nodelist is None:
        nodelist = list(G.nodes())

    # FancyArrowPatch handles color=None different from LineCollection
    if edge_color is None:
        edge_color = "k"

    # set edge positions
    edge_pos = np.asarray([(pos[e[0]], pos[e[1]]) for e in edgelist])

    # Check if edge_color is an array of floats and map to edge_cmap.
    # This is the only case handled differently from matplotlib
    if (np.iterable(edge_color) and (len(edge_color) == len(edge_pos))
            and np.alltrue([isinstance(c, Number) for c in edge_color])):
        if edge_cmap is not None:
            assert isinstance(edge_cmap, Colormap)
        else:
            edge_cmap = plt.get_cmap()
        if edge_vmin is None:
            edge_vmin = min(edge_color)
        if edge_vmax is None:
            edge_vmax = max(edge_color)
        color_normal = Normalize(vmin=edge_vmin, vmax=edge_vmax)
        edge_color = [edge_cmap(color_normal(e)) for e in edge_color]

    if not G.is_directed() or not arrows:
        edge_collection = LineCollection(
            edge_pos,
            colors=edge_color,
            linewidths=width,
            antialiaseds=(1, ),
            linestyle=style,
            transOffset=ax.transData,
            alpha=alpha,
        )

        edge_collection.set_cmap(edge_cmap)
        edge_collection.set_clim(edge_vmin, edge_vmax)

        edge_collection.set_zorder(1)  # edges go behind nodes
        edge_collection.set_label(label)
        ax.add_collection(edge_collection)

        return edge_collection

    arrow_collection = None

    if G.is_directed() and arrows:
        # Note: Waiting for someone to implement arrow to intersection with
        # marker.  Meanwhile, this works well for polygons with more than 4
        # sides and circle.

        def to_marker_edge(marker_size, marker):
            if marker in "s^>v<d":  # `large` markers need extra space
                return np.sqrt(2 * marker_size) / 2
            else:
                return np.sqrt(marker_size) / 2

        # Draw arrows with `matplotlib.patches.FancyarrowPatch`
        arrow_collection = []
        mutation_scale = arrowsize  # scale factor of arrow head

        # FancyArrowPatch doesn't handle color strings
        arrow_colors = colorConverter.to_rgba_array(edge_color, alpha)
        for i, (src, dst) in enumerate(edge_pos):
            x1, y1 = src
            x2, y2 = dst
            shrink_source = 0  # space from source to tail
            shrink_target = 0  # space from  head to target
            if np.iterable(node_size):  # many node sizes
                source, target = edgelist[i][:2]
                source_node_size = node_size[nodelist.index(source)]
                target_node_size = node_size[nodelist.index(target)]
                shrink_source = to_marker_edge(source_node_size, node_shape)
                shrink_target = to_marker_edge(target_node_size, node_shape)
            else:
                shrink_source = shrink_target = to_marker_edge(
                    node_size, node_shape)

            if shrink_source < min_source_margin:
                shrink_source = min_source_margin

            if shrink_target < min_target_margin:
                shrink_target = min_target_margin

            if len(arrow_colors) == len(edge_pos):
                arrow_color = arrow_colors[i]
            elif len(arrow_colors) == 1:
                arrow_color = arrow_colors[0]
            else:  # Cycle through colors
                arrow_color = arrow_colors[i % len(arrow_colors)]

            if np.iterable(width):
                if len(width) == len(edge_pos):
                    line_width = width[i]
                else:
                    line_width = width[i % len(width)]
            else:
                line_width = width

            arrow = FancyArrowPatch(
                (x1, y1),
                (x2, y2),
                arrowstyle=arrowstyle,
                shrinkA=shrink_source,
                shrinkB=shrink_target,
                mutation_scale=mutation_scale,
                color=arrow_color,
                linewidth=line_width,
                connectionstyle=connectionstyle,
                linestyle=style,
                zorder=1,
            )  # arrows go behind nodes

            # There seems to be a bug in matplotlib to make collections of
            # FancyArrowPatch instances. Until fixed, the patches are added
            # individually to the axes instance.
            arrow_collection.append(arrow)
            ax.add_patch(arrow)

    # update view
    minx = np.amin(np.ravel(edge_pos[:, :, 0]))
    maxx = np.amax(np.ravel(edge_pos[:, :, 0]))
    miny = np.amin(np.ravel(edge_pos[:, :, 1]))
    maxy = np.amax(np.ravel(edge_pos[:, :, 1]))

    w = maxx - minx
    h = maxy - miny
    padx, pady = 0.05 * w, 0.05 * h
    corners = (minx - padx, miny - pady), (maxx + padx, maxy + pady)
    ax.update_datalim(corners)
    ax.autoscale_view()

    ax.tick_params(
        axis="both",
        which="both",
        bottom=False,
        left=False,
        labelbottom=False,
        labelleft=False,
    )

    return arrow_collection
Ejemplo n.º 12
0
def draw_edges(G,
               pos,
               ax,
               edgelist=None,
               width=1.0,
               width_adjuster=50,
               edge_color='k',
               style='solid',
               alpha=None,
               edge_cmap=None,
               edge_vmin=None,
               edge_vmax=None,
               traversal_weight=1.0,
               edge_delengthify=0.15,
               arrows=True,
               label=None,
               zorder=1,
               **kwds):
    """
    Code cleaned-up version of networkx.draw_networkx_edges

    New args:

    width_adjuster - the line width is generated from the weight if present, use this adjuster to thicken the lines (multiply)
    """
    if edgelist is None:
        edgelist = G.edges()

    if not edgelist or len(edgelist) == 0:  # no edges!
        return None

    # set edge positions
    edge_pos = [(pos[e[0]], pos[e[1]]) for e in edgelist]
    new_ep = []
    for e in edge_pos:
        x, y = e[0]
        dx, dy = e[1]

        # Get edge length
        elx = (dx - x) * edge_delengthify
        ely = (dy - y) * edge_delengthify

        x += elx
        y += ely
        dx -= elx
        dy -= ely

        new_ep.append(((x, y), (dx, dy)))
    edge_pos = numpy.asarray(new_ep)

    if not cb.iterable(width):
        #print [G.get_edge_data(n[0], n[1])['weight'] for n in edgelist]
        # see if I can find an edge attribute:
        if 'weight' in G.get_edge_data(edgelist[0][0],
                                       edgelist[0][1]):  # Test an edge
            lw = [
                0.5 +
                ((G.get_edge_data(n[0], n[1])['weight'] - traversal_weight) *
                 width_adjuster) for n in edgelist
            ]
        else:
            lw = (width, )
    else:
        lw = width

    if not is_string_like(edge_color) and cb.iterable(edge_color) and len(
            edge_color) == len(edge_pos):
        if numpy.alltrue([cb.is_string_like(c) for c in edge_color]):
            # (should check ALL elements)
            # list of color letters such as ['k','r','k',...]
            edge_colors = tuple(
                [colorConverter.to_rgba(c, alpha) for c in edge_color])
        elif numpy.alltrue([not cb.is_string_like(c) for c in edge_color]):
            # If color specs are given as (rgb) or (rgba) tuples, we're OK
            if numpy.alltrue(
                [cb.iterable(c) and len(c) in (3, 4) for c in edge_color]):
                edge_colors = tuple(edge_color)
            else:
                # numbers (which are going to be mapped with a colormap)
                edge_colors = None
        else:
            raise ValueError(
                'edge_color must consist of either color names or numbers')
    else:
        if is_string_like(edge_color) or len(edge_color) == 1:
            edge_colors = (colorConverter.to_rgba(edge_color, alpha), )
        else:
            raise ValueError(
                'edge_color must be a single color or list of exactly m colors where m is the number or edges'
            )

    edge_collection = LineCollection(edge_pos,
                                     colors=edge_colors,
                                     linewidths=lw,
                                     antialiaseds=(1, ),
                                     linestyle=style,
                                     transOffset=ax.transData,
                                     zorder=zorder)

    edge_collection.set_label(label)
    ax.add_collection(edge_collection)

    if cb.is_numlike(alpha):
        edge_collection.set_alpha(alpha)

    if edge_colors is None:
        if edge_cmap is not None:
            assert (isinstance(edge_cmap, Colormap))
        edge_collection.set_array(numpy.asarray(edge_color))
        edge_collection.set_cmap(edge_cmap)
        if edge_vmin is not None or edge_vmax is not None:
            edge_collection.set_clim(edge_vmin, edge_vmax)
        else:
            edge_collection.autoscale()

    # update view
    '''
    minx = numpy.amin(numpy.ravel(edge_pos[:,:,0]))
    maxx = numpy.amax(numpy.ravel(edge_pos[:,:,0]))
    miny = numpy.amin(numpy.ravel(edge_pos[:,:,1]))
    maxy = numpy.amax(numpy.ravel(edge_pos[:,:,1]))

    w = maxx-minx
    h = maxy-miny
    padx,  pady = 0.05*w, 0.05*h
    corners = (minx-padx, miny-pady), (maxx+padx, maxy+pady)
    ax.update_datalim(corners)
    ax.autoscale_view()
    '''
    return (edge_collection)
def animate_convolution(x, h, y, t, tau, td, taud, interval=75):
    """Plot animation of graphical representation of linear convolution.

    Parameters
    ----------
    x : sympy function
        First function to be convolved.
    h: sympy function
        Second function to be convolved.
    t: sympy variable
        Independent variable for functions (e.g. time).
    tau: sympy variable
        Integration variable for convolution.
    td: array like
        Discrete values of independent variable evaluated for plot.
    taud:
        Discrete values of integration variable evaluated for animation.
    interval:
        Interval in ms between frames of animation.
    Returns
    -------
    matplotlib.animation.FuncAnimation object.

    """
    def animate(ti):
        p = sym.plot(x.subs(t, tau), (tau, taud[0], taud[-1]), show=False)
        line_x.set_segments(p[0].get_segments())

        p = sym.plot(h.subs(t, t - tau).subs(t, ti), (tau, taud[0], taud[-1]),
                     show=False)
        line_h.set_segments(p[0].get_segments())

        p = sym.plot(y, (t, taud[0], taud[-1]), show=False)
        line_y.set_segments(p[0].get_segments())

        p = sym.plot(x.subs(t, tau) * h.subs(t, ti - tau), (tau, -5, 5),
                     show=False)
        points = p[0].get_points()
        verts = [[(xi[0], xi[1]) for xi in np.transpose(np.array(points))]]
        fill.set_verts(verts)

        dot.set_data(ti, y.subs(t, ti))

    # define line/fill collections and setup plot
    default_figsize = plt.rcParams.get('figure.figsize')
    fig, ax = plt.subplots(2,
                           1,
                           figsize=(default_figsize[0],
                                    1.5 * default_figsize[1]))
    fig.subplots_adjust(hspace=0.2)
    plt.close()  # suppresses empty plot in notebook

    fill = PolyCollection([], facecolors='r')
    fill.set_alpha(0.3)
    ax[0].add_collection(fill)

    line_x = LineCollection([], colors='C0')
    line_x.set_label(r'$x(\tau)$')
    ax[0].add_collection(line_x)

    line_h = LineCollection([], colors='C1')
    line_h.set_label(r'$h(t - \tau)$')
    ax[0].add_collection(line_h)

    line_y = LineCollection([], colors='C2')
    line_y.set_label(r'$y(t)$')
    ax[1].add_collection(line_y)

    dot, = ax[1].plot([], 'ro')

    for axi in ax:
        axi.spines['left'].set_position('zero')
        axi.spines['bottom'].set_position('zero')
        axi.spines['right'].set_color('none')
        axi.spines['top'].set_color('none')
        axi.xaxis.set_ticks_position('bottom')
        axi.yaxis.set_ticks_position('left')
        axi.set_xlim((-3, 4))
        axi.set_ylim((-.1, 1.2))

    ax[0].set_xlabel(r'$\tau$', horizontalalignment='right', x=1.0)
    ax[0].legend(loc='upper right')
    ax[1].set_xlabel(r'$t$', horizontalalignment='right', x=1.0)
    ax[1].legend(loc='upper right')

    return FuncAnimation(fig, animate, td, interval=interval)
Ejemplo n.º 14
0
def draw_networkx_edges(G,
                        pos,
                        edgelist=None,
                        width=1.0,
                        edge_color='k',
                        style='solid',
                        alpha=1.0,
                        edge_cmap=None,
                        edge_vmin=None,
                        edge_vmax=None,
                        ax=None,
                        arrows=True,
                        arrowstyle='thick',
                        label=None,
                        **kwds):
    try:
        import matplotlib
        import matplotlib.pyplot as plt
        import matplotlib.cbook as cb
        import matplotlib.patches as patches
        from matplotlib.colors import colorConverter, Colormap
        from matplotlib.collections import LineCollection
        from matplotlib.path import Path
        import numpy
    except ImportError:
        raise ImportError("Matplotlib required for draw()")
    except RuntimeError:
        print("Matplotlib unable to open display")
        raise
    # print "drawing_edges"

    if ax is None:
        ax = plt.gca()

    if edgelist is None:
        edgelist = G.edges()

    if not edgelist or len(edgelist) == 0:  # no edges!
        return None

    # set edge positions
    edge_pos = numpy.asarray([(pos[e[0]], pos[e[1]]) for e in edgelist])
    # for e in edge_pos:
    #   print e
    if not cb.iterable(width):
        lw = (width, )
    else:
        lw = width

    if not cb.is_string_like(edge_color) \
           and cb.iterable(edge_color) \
           and len(edge_color) == len(edge_pos):
        if numpy.alltrue([cb.is_string_like(c) for c in edge_color]):
            # (should check ALL elements)
            # list of color letters such as ['k','r','k',...]
            edge_colors = tuple(
                [colorConverter.to_rgba(c, alpha) for c in edge_color])
        elif numpy.alltrue([not cb.is_string_like(c) for c in edge_color]):
            # If color specs are given as (rgb) or (rgba) tuples, we're OK
            if numpy.alltrue(
                [cb.iterable(c) and len(c) in (3, 4) for c in edge_color]):
                edge_colors = tuple(edge_color)
            else:
                # numbers (which are going to be mapped with a colormap)
                edge_colors = None
        else:
            raise ValueError(
                'edge_color must consist of either color names or numbers')
    else:
        if cb.is_string_like(edge_color) or len(edge_color) == 1:
            edge_colors = (colorConverter.to_rgba(edge_color, alpha), )
        else:
            raise ValueError(
                'edge_color must be a single color or list of exactly m colors where m is the number or edges'
            )

    edge_collection = LineCollection(
        edge_pos,
        colors=edge_colors,
        linewidths=lw,
        antialiaseds=(1, ),
        linestyle=style,
        transOffset=ax.transData,
    )

    # print type(edge_collection)

    edge_collection.set_zorder(1)  # edges go behind nodes
    edge_collection.set_label(label)
    ax.add_collection(edge_collection)

    # Note: there was a bug in mpl regarding the handling of alpha values for
    # each line in a LineCollection.  It was fixed in matplotlib in r7184 and
    # r7189 (June 6 2009).  We should then not set the alpha value globally,
    # since the user can instead provide per-edge alphas now.  Only set it
    # globally if provided as a scalar.
    if cb.is_numlike(alpha):
        edge_collection.set_alpha(alpha)

    if edge_colors is None:
        if edge_cmap is not None:
            assert (isinstance(edge_cmap, Colormap))
        edge_collection.set_array(numpy.asarray(edge_color))
        edge_collection.set_cmap(edge_cmap)
        if edge_vmin is not None or edge_vmax is not None:
            edge_collection.set_clim(edge_vmin, edge_vmax)
        else:
            edge_collection.autoscale()

    arrow_collection = None

    if G.is_directed() and arrows:

        # a directed graph hack-fix
        # draws arrows at each
        # waiting for someone else to implement arrows that will work
        arrow_colors = edge_colors
        a_pos = []
        p = .1  # make arrows 10% of total length
        angle = 2.7  #angle for arrows
        for src, dst in edge_pos:
            x1, y1 = src
            x2, y2 = dst
            dx = x2 - x1  # x offset
            dy = y2 - y1  # y offset
            d = numpy.sqrt(float(dx**2 + dy**2))  # length of edge
            theta = numpy.arctan2(dy, dx)
            if d == 0:  # source and target at same position
                continue
            if dx == 0:  # vertical edge
                xa = x2
                ya = dy + y1
            if dy == 0:  # horizontal edge
                ya = y2
                xa = dx + x1
            else:
                # xa = p*d*numpy.cos(theta)+x1
                # ya = p*d*numpy.sin(theta)+y1
                #corrects the endpoints to better draw
                x2 -= .04 * numpy.cos(theta)
                y2 -= .04 * numpy.sin(theta)
                lx1 = p * d * numpy.cos(theta + angle) + (x2)
                lx2 = p * d * numpy.cos(theta - angle) + (x2)
                ly1 = p * d * numpy.sin(theta + angle) + (y2)
                ly2 = p * d * numpy.sin(theta - angle) + (y2)

            a_pos.append(((lx1, ly1), (x2, y2)))
            a_pos.append(((lx2, ly2), (x2, y2)))

        arrow_collection = LineCollection(
            a_pos,
            colors=arrow_colors,
            linewidths=[1 * ww for ww in lw],
            antialiaseds=(1, ),
            transOffset=ax.transData,
        )

        arrow_collection.set_zorder(1)  # edges go behind nodes
        arrow_collection.set_label(label)
        # print type(ax)
        ax.add_collection(arrow_collection)

    #drawing self loops

    d = 1
    c = 0.0707
    selfedges = []
    verts = [
        (0.1 * d - 0.1 * d, 0.0),  # P0
        (c * d - 0.1 * d, c * d),  # P0
        (0.0 - 0.1 * d, 0.1 * d),  # P0
        (-c * d - 0.1 * d, c * d),  # P0
        (-0.1 * d - 0.1 * d, 0.0),  # P0
        (-c * d - 0.1 * d, -c * d),  # P0
        (0.0 - 0.1 * d, -0.1 * d),  # P0
        (c * d - 0.1 * d, -c * d),  # P0
        (0.1 * d - 0.1 * d, 0.0)
    ]
    # print verts

    codes = [
        Path.MOVETO,
        Path.LINETO,
        Path.LINETO,
        Path.LINETO,
        Path.LINETO,
        Path.LINETO,
        Path.LINETO,
        Path.LINETO,
        Path.LINETO,
    ]

    for e in edge_pos:
        if (numpy.array_equal(e[0], e[1])):
            nodes = verts[:]
            for i in range(len(nodes)):
                nodes[i] += e[0]
            # print nodes
            path = Path(nodes, codes)
            patch = patches.PathPatch(path,
                                      color=None,
                                      facecolor=None,
                                      edgecolor=edge_colors[0],
                                      fill=False,
                                      lw=4)
            ax.add_patch(patch)

    # update view
    minx = numpy.amin(numpy.ravel(edge_pos[:, :, 0]))
    maxx = numpy.amax(numpy.ravel(edge_pos[:, :, 0]))
    miny = numpy.amin(numpy.ravel(edge_pos[:, :, 1]))
    maxy = numpy.amax(numpy.ravel(edge_pos[:, :, 1]))

    w = maxx - minx
    h = maxy - miny
    padx, pady = 0.05 * w, 0.05 * h
    corners = (minx - padx, miny - pady), (maxx + padx, maxy + pady)
    # print ax
    ax.update_datalim(corners)
    ax.autoscale_view()

    #    if arrow_collection:

    return edge_collection
Ejemplo n.º 15
0
def plot2d(x: Union[core.NeuronObject, core.Volume, np.ndarray,
                    List[Union[core.NeuronObject, np.ndarray, core.Volume]]],
           method: Union[Literal['2d'], Literal['3d'],
                         Literal['3d_complex']] = '2d',
           **kwargs) -> Tuple[mpl.figure.Figure, mpl.axes.Axes]:
    """ Generate 2D plots of neurons and neuropils.

    The main advantage of this is that you can save plot as vector graphics.

    Important
    ---------
    This function uses matplotlib which "fakes" 3D as it has only very limited
    control over layers. Therefore neurites aren't necessarily plotted in the
    right Z order which becomes especially troublesome when plotting a complex
    scene with lots of neurons criss-crossing. See the ``method`` parameter
    for details. All methods use orthogonal projection.

    Parameters
    ----------
    x :               skeleton IDs | TreeNeuron | NeuronList | Volume | Dotprops | np.ndarray
                      Objects to plot::

                        - int is intepreted as skeleton ID(s)
                        - str is intepreted as volume name(s)
                        - multiple objects can be passed as list (see examples)
                        - numpy array of shape (n,3) is intepreted as scatter
    method :          '2d' | '3d' | '3d_complex'
                      Method used to generate plot. Comes in three flavours:
                        1. '2d' uses normal matplotlib. Neurons are plotted in
                           the order their are provided. Well behaved when
                           plotting neuropils and connectors. Always gives
                           frontal view.
                        2. '3d' uses matplotlib's 3D axis. Here, matplotlib
                           decide the order of plotting. Can chance perspective
                           either interacively or by code (see examples).
                        3. '3d_complex' same as 3d but each neuron segment is
                           added individually. This allows for more complex
                           crossing patterns to be rendered correctly. Slows
                           down rendering though.

    **kwargs
                      See Notes for permissible keyword arguments.

    Examples
    --------
    >>> import navis
    >>> import matplotlib.pyplot as plt

    Plot list of neurons as simple 2d
    >>> nl = navis.example_neurons()
    >>> fig, ax = navis.plot2d(nl)
    >>> plt.show()

    Add a volume
    >>> v = navis.example_volume('LH')
    >>> fig, ax = navis.plot2d([nl, vol])
    >>> plt.show()

    Change neuron colors
    >>> fig, ax = navis.plot2d(nl, color=['r', 'g', 'b', 'm', 'c', 'y'])
    >>> plt.show()

    Plot in "fake" 3D
    >>> fig, ax = navis.plot2d(nl, method='3d')
    >>> plt.show()
    >>> # Try dragging the window

    Plot in "fake" 3D and change perspective
    >>> fig, ax = navis.plot2d(nl, method='3d')
    >>> # Change view to lateral
    >>> ax.azim = 0
    >>> ax.elev = 0
    >>> # Change view to top
    >>> ax.azim = -90
    >>> ax.elev = 90
    >>> # Tilted top view
    >>> ax.azim = -135
    >>> ax.elev = 45
    >>> # Move camera closer (will make image bigger)
    >>> ax.dist = 5
    >>> plt.show()

    Plot using depth-coloring
    >>> fig, ax = navis.plot2d(nl, method='3d', depth_coloring=True)
    >>> plt.show()


    Returns
    --------
    fig, ax :      matplotlib figure and axis object

    Notes
    -----

    Optional keyword arguments:

    ``soma`` (bool, default = True)
       Plot soma if one exists.

    ``connectors`` (boolean, default = True)
       Plot connectors (synapses, gap junctions, abutting)

    ``connectors_only`` (boolean, default = False)
       Plot only connectors, not the neuron.

    ``cn_size`` (int | float, default = 1)
      Size of connectors.

    ``linewidth``/``lw`` (int | float, default = .5)
      Width of neurites.

    ``linestyle``/``ls`` (str, default = '-')
      Line style of neurites.

    ``autoscale`` (bool, default=True)
       If True, will scale the axes to fit the data.

    ``scalebar`` (int | float, default=False)
       Adds scale bar. Provide integer/float to set size of scalebar.
       For methods '3d' and '3d_complex', this will create an axis object.

    ``ax`` (matplotlib ax, default=None)
       Pass an ax object if you want to plot on an existing canvas.

    ``figsize`` (tuple, default = (8, 8))
      Size of figure.

    ``color`` (tuple | list | str | dict)
      Tuples/lists (r,g,b) and str (color name) are interpreted as a single
      colors that will be applied to all neurons. Dicts will be mapped onto
      neurons by skeleton ID.

    ``alpha`` (float [0-1], default = .9)
      Alpha value for neurons. Overriden if alpha is provided as fourth value
      in ``color``.

    ``use_neuron_color`` (bool, default = False)
      If True, will attempt to use ``.color`` attribute of neurons.

    ``depth_coloring`` (bool, default = False)
      If True, will color encode depth (Z). Overrides ``color``. Does not work
      with ``method = '3d_complex'``.

    ``depth_scale`` (bool, default = True)
      If True and ``depth_coloring=True`` will plot a scale.

    ``cn_mesh_colors`` (bool, default = False)
      If True, will use the neuron's color for its connectors too.

    ``group_neurons`` (bool, default = False)
      If True, neurons will be grouped. Works with SVG export (not PDF).
      Does NOT work with ``method='3d_complex'``.

    ``scatter_kws`` (dict, default = {})
      Parameters to be used when plotting points. Accepted keywords are:
      ``size`` and ``color``.

    ``view`` (tuple, default = ("x", "y"))
      Sets view for ``method='2d'``.


    See Also
    --------
    :func:`navis.plot3d`
            Use this if you want interactive, perspectively correct renders
            and if you don't need vector graphics as outputs.
    :func:`navis.plot1d`
            A nifty way to visualise neurons in a single dimension.

    """

    # Filter kwargs
    _ACCEPTED_KWARGS = [
        'soma', 'connectors', 'connectors_only', 'ax', 'color', 'colors', 'c',
        'view', 'scalebar', 'cn_mesh_colors', 'linewidth', 'cn_size',
        'group_neurons', 'scatter_kws', 'figsize', 'linestyle', 'alpha',
        'depth_coloring', 'autoscale', 'depth_scale', 'use_neuron_color', 'ls',
        'lw'
    ]
    wrong_kwargs = [a for a in kwargs if a not in _ACCEPTED_KWARGS]
    if wrong_kwargs:
        raise KeyError(f'Unknown kwarg(s): {",".join(wrong_kwargs)}. '
                       f'Currently accepted: {",".join(_ACCEPTED_KWARGS)}')

    _METHOD_OPTIONS = ['2d', '3d', '3d_complex']
    if method not in _METHOD_OPTIONS:
        raise ValueError(f'Unknown method "{method}". Please use either: '
                         f'{",".join(_METHOD_OPTIONS)}')

    # Set axis to plot for method '2d'
    axis1, axis2 = kwargs.get('view', ('x', 'y'))

    plot_soma = kwargs.get('soma', True)

    connectors = kwargs.get('connectors', False)
    connectors_only = kwargs.get('connectors_only', False)
    cn_mesh_colors = kwargs.get('cn_mesh_colors', False)
    use_neuron_color = kwargs.get('use_neuron_color', False)
    ax = kwargs.get('ax', None)
    color = kwargs.get('color', kwargs.get('c', kwargs.get('colors', None)))
    scalebar = kwargs.get('scalebar', None)
    group_neurons = kwargs.get('group_neurons', False)

    # This is overwritten if color specifies alphas
    alpha = kwargs.get('alpha', .9)

    # Depth coloring
    depth_coloring = kwargs.get('depth_coloring', False)
    depth_scale = kwargs.get('depth_scale', True)

    scatter_kws = kwargs.get('scatter_kws', {})

    linewidth = kwargs.get('linewidth', kwargs.get('lw', .5))
    cn_size = kwargs.get('cn_size', 1)
    linestyle = kwargs.get('linestyle', kwargs.get('ls', '-'))
    autoscale = kwargs.get('autoscale', True)

    # Keep track of limits if necessary
    lim = []

    # Parse objects
    skdata, dotprops, volumes, points, visuals = utils.parse_objects(x)

    # Generate the colormaps
    (neuron_cmap, dotprop_cmap,
     volumes_cmap) = prepare_colormap(color,
                                      skdata,
                                      dotprops,
                                      volumes,
                                      use_neuron_color=use_neuron_color,
                                      color_range=1)

    # Make sure axes are projected orthogonally
    if method in ['3d', '3d_complex']:
        proj3d.persp_transformation = _orthogonal_proj

    # Generate axes
    if not ax:
        if method == '2d':
            fig, ax = plt.subplots(figsize=kwargs.get('figsize', (8, 8)))
            ax.set_aspect('equal')
        elif method in ['3d', '3d_complex']:
            fig = plt.figure(figsize=kwargs.get('figsize',
                                                plt.figaspect(1) * 1.5))
            ax = fig.gca(projection='3d')

            # This sets front view
            ax.azim = -90
            ax.elev = 0
            ax.dist = 7
            # Disallowed for 3D in matplotlib 3.1.0
            # ax.set_aspect('equal')
    # Check if correct axis were provided
    else:
        if not isinstance(ax, mpl.axes.Axes):
            raise TypeError('Ax must be of type "mpl.axes.Axes", '
                            f'not "{type(ax)}"')
        fig = ax.get_figure()
        if method in ['3d', '3d_complex']:
            if ax.name != '3d':
                raise TypeError('Axis must be 3d.')

            # Add existing limits to ax
            lim += np.array((ax.get_xlim3d(), ax.get_zlim3d(),
                             ax.get_ylim3d())).T.tolist()
        elif method == '2d':
            if ax.name == '3d':
                raise TypeError('Axis must be 2d.')

    # Prepare some stuff for depth coloring
    if depth_coloring and method == '3d_complex':
        raise Exception(f'Depth coloring unavailable for method "{method}"')
    elif depth_coloring and method == '2d':
        all_co = skdata.nodes[['x', 'y', 'z']]
        norm = plt.Normalize(vmin=all_co.z.min(), vmax=all_co.z.max())

    # Plot volumes first
    if volumes:
        for i, v in enumerate(volumes):
            c = volumes_cmap[i]

            if method == '2d':
                vpatch = mpatches.Polygon(v.to_2d(view=f'{axis1}{axis2}',
                                                  invert_y=True),
                                          closed=True,
                                          lw=0,
                                          fill=True,
                                          fc=c,
                                          alpha=c[3] if len(c) == 4 else 1)
                ax.add_patch(vpatch)
            elif method in ['3d', '3d_complex']:
                verts = np.vstack(v.vertices)

                # Invert y-axis
                verts[:, 1] *= -1

                # Add alpha
                if len(c) == 3:
                    c = (c[0], c[1], c[2], .1)

                ts = ax.plot_trisurf(verts[:, 0],
                                     verts[:, 2],
                                     v.faces,
                                     verts[:, 1],
                                     label=v.name,
                                     color=c)
                ts.set_gid(v.name)

                # Keep track of limits
                lim.append(verts.max(axis=0))
                lim.append(verts.min(axis=0))

    # Create lines from segments
    line3D_collections = []
    surf3D_collections = []
    for i, neuron in enumerate(
            config.tqdm(skdata.itertuples(),
                        desc='Plot neurons',
                        total=skdata.shape[0],
                        leave=False,
                        disable=config.pbar_hide | len(dotprops) == 0)):
        this_color = neuron_cmap[i]

        if neuron.nodes.empty:
            logger.warning(f'Skipping neuron w/o nodes: {neuron.uuid}')
            continue

        if not connectors_only:
            # Now make traces (invert y axis)
            coords = segments_to_coords(neuron,
                                        neuron.segments,
                                        modifier=(1, -1, 1))

            if method == '2d':
                if not depth_coloring:
                    # We have to add (None, None, None) to the end of each
                    # slab to make that line discontinuous there
                    coords = np.vstack(
                        [np.append(t, [[None] * 3], axis=0) for t in coords])

                    this_line = mlines.Line2D(
                        coords[:, 0],
                        coords[:, 1],
                        lw=linewidth,
                        ls=linestyle,
                        alpha=alpha,
                        color=this_color,
                        label=
                        f'{getattr(neuron, "name", "NA")} - #{neuron.uuid}')
                    ax.add_line(this_line)
                else:
                    coords = tn_pairs_to_coords(neuron, modifier=(1, -1, 1))
                    lc = LineCollection(coords[:, :, [0, 1]],
                                        cmap='jet',
                                        norm=norm)
                    lc.set_array(neuron.nodes.loc[neuron.nodes.parent_id >= 0,
                                                  'z'].values)
                    lc.set_linewidth(linewidth)
                    lc.set_alpha(alpha)
                    lc.set_linestyle(linestyle)
                    lc.set_label(
                        f'{getattr(neuron, "name", "NA")} - #{neuron.uuid}')
                    line = ax.add_collection(lc)

                if plot_soma and not isinstance(neuron.soma, type(None)):
                    soma = utils.make_iterable(neuron.soma)
                    for s in soma:
                        n = neuron.nodes.set_index('node_id').loc[s]
                        r = getattr(n, neuron.soma_radius) if isinstance(
                            neuron.soma_radius, str) else neuron.soma_radius

                        if depth_coloring:
                            this_color = mpl.cm.jet(norm(n.z))

                        s = mpatches.Circle((int(n.x), int(-n.y)),
                                            radius=r,
                                            alpha=alpha,
                                            fill=True,
                                            fc=this_color,
                                            zorder=4,
                                            edgecolor='none')
                        ax.add_patch(s)

            elif method in ['3d', '3d_complex']:
                cmap = mpl.cm.jet if depth_coloring else None

                # For simple scenes, add whole neurons at a time -> will speed
                # up rendering
                if method == '3d':
                    if depth_coloring:
                        this_coords = tn_pairs_to_coords(
                            neuron, modifier=(1, -1, 1))[:, :, [0, 2, 1]]
                    else:
                        this_coords = [c[:, [0, 2, 1]] for c in coords]

                    lc = Line3DCollection(this_coords,
                                          color=this_color,
                                          label=neuron.uuid,
                                          alpha=alpha,
                                          cmap=cmap,
                                          lw=linewidth,
                                          linestyle=linestyle)
                    if group_neurons:
                        lc.set_gid(neuron.uuid)
                    ax.add_collection3d(lc)
                    line3D_collections.append(lc)

                # For complex scenes, add each segment as a single collection
                # -> help preventing Z-order errors
                elif method == '3d_complex':
                    for c in coords:
                        lc = Line3DCollection([c[:, [0, 2, 1]]],
                                              color=this_color,
                                              lw=linewidth,
                                              alpha=alpha,
                                              linestyle=linestyle)
                        if group_neurons:
                            lc.set_gid(neuron.uuid)
                        ax.add_collection3d(lc)

                coords = np.vstack(coords)
                lim.append(coords.max(axis=0))
                lim.append(coords.min(axis=0))

                surf3D_collections.append([])

                if plot_soma and not isinstance(neuron.soma, type(None)):
                    soma = utils.make_iterable(neuron.soma)
                    for s in soma:
                        n = neuron.nodes.set_index('node_id').loc[s]
                        r = getattr(n, neuron.soma_radius) if isinstance(
                            neuron.soma_radius, str) else neuron.soma_radius

                        resolution = 20
                        u = np.linspace(0, 2 * np.pi, resolution)
                        v = np.linspace(0, np.pi, resolution)
                        x = r * np.outer(np.cos(u), np.sin(v)) + n.x
                        y = r * np.outer(np.sin(u), np.sin(v)) - n.y
                        z = r * np.outer(np.ones(np.size(u)), np.cos(v)) + n.z
                        surf = ax.plot_surface(x,
                                               z,
                                               y,
                                               color=this_color,
                                               shade=False,
                                               alpha=alpha)
                        if group_neurons:
                            surf.set_gid(neuron.uuid)

                        surf3D_collections[-1].append(surf)

        if (connectors or connectors_only) and neuron.has_connectors:
            if not cn_mesh_colors:
                cn_types = {0: 'red', 1: 'blue', 2: 'green', 3: 'magenta'}
            else:
                cn_types = {
                    0: this_color,
                    1: this_color,
                    2: this_color,
                    3: this_color
                }
            if method == '2d':
                for c in cn_types:
                    this_cn = neuron.connectors[neuron.connectors.relation ==
                                                c]
                    ax.scatter(this_cn.x.values, (-this_cn.y).values,
                               c=cn_types[c],
                               alpha=alpha,
                               zorder=4,
                               edgecolor='none',
                               s=cn_size)
                    ax.get_children()[-1].set_gid(f'CN_{neuron.uuid}')
            elif method in ['3d', '3d_complex']:
                all_cn = neuron.connectors
                c = [cn_types[i] for i in all_cn.relation.values]
                ax.scatter(all_cn.x.values,
                           all_cn.z.values,
                           -all_cn.y.values,
                           c=c,
                           s=cn_size,
                           depthshade=False,
                           edgecolor='none',
                           alpha=alpha)
                ax.get_children()[-1].set_gid(f'CN_{neuron.uuid}')

            coords = neuron.connectors[['x', 'y', 'z']].values
            coords[:, 1] *= -1
            lim.append(coords.max(axis=0))
            lim.append(coords.min(axis=0))

    for i, neuron in enumerate(
            config.tqdm(dotprops.itertuples(),
                        desc='Plt dotprops',
                        total=dotprops.shape[0],
                        leave=False,
                        disable=config.pbar_hide | len(dotprops) == 0)):
        # Prepare lines - this is based on nat:::plot3d.dotprops
        halfvect = neuron.points[['x_vec', 'y_vec', 'z_vec']] / 2

        starts = neuron.points[['x', 'y', 'z']].values - halfvect.values
        ends = neuron.points[['x', 'y', 'z']].values + halfvect.values

        try:
            this_color = dotprop_cmap[i]
        except BaseException:
            this_color = (.1, .1, .1)

        if method == '2d':
            # Add None between segments
            x_coords = [
                n for sublist in zip(starts[:, 0], ends[:, 0], [None] *
                                     starts.shape[0]) for n in sublist
            ]
            y_coords = [
                n for sublist in zip(starts[:, 1] * -1, ends[:, 1] *
                                     -1, [None] * starts.shape[0])
                for n in sublist
            ]

            this_line = mlines.Line2D(x_coords,
                                      y_coords,
                                      lw=linewidth,
                                      ls=linestyle,
                                      alpha=alpha,
                                      color=this_color,
                                      label='%s' % (neuron.gene_name))

            ax.add_line(this_line)

            # Add soma
            if plot_soma:
                s = mpatches.Circle((neuron.X, -neuron.Y),
                                    radius=2,
                                    alpha=alpha,
                                    fill=True,
                                    fc=this_color,
                                    zorder=4,
                                    edgecolor='none')
                ax.add_patch(s)
        elif method in ['3d', '3d_complex']:
            # Combine coords by weaving starts and ends together
            coords = np.empty((starts.shape[0] * 2, 3), dtype=starts.dtype)
            coords[0::2] = starts
            coords[1::2] = ends

            # Invert y-axis
            coords[:, 1] *= -1

            # For simple scenes, add whole neurons at a time
            # -> will speed up rendering
            if method == '3d':
                lc = Line3DCollection(np.split(coords[:, [0, 2, 1]],
                                               starts.shape[0]),
                                      color=this_color,
                                      label=neuron.gene_name,
                                      lw=linewidth,
                                      alpha=alpha,
                                      linestyle=linestyle)
                if group_neurons:
                    lc.set_gid(neuron.gene_name)
                ax.add_collection3d(lc)

            # For complex scenes, add each segment as a single collection
            # -> help preventing Z-order errors
            elif method == '3d_complex':
                for c in np.split(coords[:, [0, 2, 1]], starts.shape[0]):
                    lc = Line3DCollection([c],
                                          color=this_color,
                                          lw=linewidth,
                                          alpha=alpha,
                                          linestyle=linestyle)
                    if group_neurons:
                        lc.set_gid(neuron.gene_name)
                    ax.add_collection3d(lc)

            lim.append(coords.max(axis=0))
            lim.append(coords.min(axis=0))

            resolution = 20
            u = np.linspace(0, 2 * np.pi, resolution)
            v = np.linspace(0, np.pi, resolution)
            x = 2 * np.outer(np.cos(u), np.sin(v)) + neuron.X
            y = 2 * np.outer(np.sin(u), np.sin(v)) - neuron.Y
            z = 2 * np.outer(np.ones(np.size(u)), np.cos(v)) + neuron.Z
            surf = ax.plot_surface(x,
                                   z,
                                   y,
                                   color=this_color,
                                   shade=False,
                                   alpha=alpha)
            if group_neurons:
                surf.set_gid(neuron.gene_name)

    if points:
        for p in points:
            if method == '2d':
                default_settings = dict(c='black',
                                        zorder=4,
                                        edgecolor='none',
                                        s=1)
                default_settings.update(scatter_kws)
                default_settings = _fix_default_dict(default_settings)

                ax.scatter(p[:, 0], p[:, 1] * -1, **default_settings)
            elif method in ['3d', '3d_complex']:
                default_settings = dict(c='black',
                                        s=1,
                                        depthshade=False,
                                        edgecolor='none')
                default_settings.update(scatter_kws)
                default_settings = _fix_default_dict(default_settings)

                ax.scatter(p[:, 0], p[:, 2], p[:, 1] * -1, **default_settings)

            coords = p
            coords[:, 1] *= -1
            lim.append(coords.max(axis=0))
            lim.append(coords.min(axis=0))

    if autoscale:
        if method == '2d':
            ax.autoscale()
        elif method in ['3d', '3d_complex']:
            lim = np.vstack(lim)
            lim_min = lim.min(axis=0)
            lim_max = lim.max(axis=0)

            center = lim_min + (lim_max - lim_min) / 2
            max_dim = (lim_max - lim_min).max()

            new_min = center - max_dim / 2
            new_max = center + max_dim / 2

            ax.set_xlim(new_min[0], new_max[0])
            ax.set_ylim(new_min[2], new_max[2])
            ax.set_zlim(new_min[1], new_max[1])

    if scalebar is not None:
        # Convert sc size to nm
        sc_size = scalebar * 1000

        # Hard-coded offset from figure boundaries
        ax_offset = 1000

        if method == '2d':
            xlim = ax.get_xlim()
            ylim = ax.get_ylim()

            coords = np.array(
                [[xlim[0] + ax_offset, ylim[0] + ax_offset],
                 [xlim[0] + ax_offset + sc_size, ylim[0] + ax_offset]])

            sbar = mlines.Line2D(coords[:, 0],
                                 coords[:, 1],
                                 lw=3,
                                 alpha=.9,
                                 color='black')
            sbar.set_gid(f'{scalebar}_um')

            ax.add_line(sbar)
        elif method in ['3d', '3d_complex']:
            left = lim_min[0] + ax_offset
            bottom = lim_min[1] + ax_offset
            front = lim_min[2] + ax_offset

            sbar = [
                np.array([[left, front, bottom], [left, front, bottom]]),
                np.array([[left, front, bottom], [left, front, bottom]]),
                np.array([[left, front, bottom], [left, front, bottom]])
            ]
            sbar[0][1][0] += sc_size
            sbar[1][1][1] += sc_size
            sbar[2][1][2] += sc_size

            lc = Line3DCollection(sbar, color='black', lw=1)
            lc.set_gid(f'{scalebar}_um')
            ax.add_collection3d(lc)

    def set_depth():
        """Sets depth information for neurons according to camera position."""

        # Modifier for soma coordinates
        modifier = np.array([1, 1, -1])

        # Get all coordinates
        all_co = np.concatenate(
            [lc._segments3d[:, 0, :] for lc in line3D_collections], axis=0)

        # Get projected coordinates
        proj_co = mpl_toolkits.mplot3d.proj3d.proj_points(
            all_co, ax.get_proj())

        # Get min and max of z coordinates
        z_min, z_max = min(proj_co[:, 2]), max(proj_co[:, 2])

        # Generate a new normaliser
        norm = plt.Normalize(vmin=z_min, vmax=z_max)

        # Go over all neurons and update Z information
        for neuron, lc, surf in zip(skdata, line3D_collections,
                                    surf3D_collections):
            # Get this neurons coordinates
            this_co = lc._segments3d[:, 0, :]

            # Get projected coordinates
            this_proj = mpl_toolkits.mplot3d.proj3d.proj_points(
                this_co, ax.get_proj())

            # Normalise z coordinates
            ns = norm(this_proj[:, 2]).data

            # Set array
            lc.set_array(ns)

            # No need for normaliser - already happened
            lc.set_norm(None)

            if not isinstance(neuron.soma, type(None)):
                # Get depth of soma(s)
                soma = utils.make_iterable(neuron.soma)
                soma_co = neuron.nodes.set_index('node_id').loc[soma][[
                    'x', 'z', 'y'
                ]].values
                soma_proj = mpl_toolkits.mplot3d.proj3d.proj_points(
                    soma_co * modifier, ax.get_proj())
                soma_cs = norm(soma_proj[:, 2]).data

                # Set soma color
                for cs, s in zip(soma_cs, surf):
                    s.set_color(cmap(cs))

    def Update(event):
        set_depth()

    if depth_coloring:
        if method == '2d' and depth_scale:
            fig.colorbar(line, ax=ax, fraction=.075, shrink=.5, label='Depth')
        elif method == '3d':
            fig.canvas.mpl_connect('draw_event', Update)
            set_depth()

    plt.axis('off')

    logger.debug('Done. Use matplotlib.pyplot.show() to show plot.')

    return fig, ax
Ejemplo n.º 16
0
def draw_networkx_edges(G, pos,
                        edgelist=None,
                        width=1.0,
                        edge_color='k',
                        style='solid',
                        alpha=1.0,
                        edge_cmap=None,
                        edge_vmin=None,
                        edge_vmax=None,
                        ax=None,
                        arrows=True,
                        label=None,
                        **kwds):
    """Draw the edges of the graph G.

    This draws only the edges of the graph G.

    Parameters
    ----------
    G : graph
       A networkx graph

    pos : dictionary
       A dictionary with nodes as keys and positions as values.
       Positions should be sequences of length 2.

    edgelist : collection of edge tuples
       Draw only specified edges(default=G.edges())

    width : float, or array of floats
       Line width of edges (default=1.0)

    edge_color : color string, or array of floats
       Edge color. Can be a single color format string (default='r'),
       or a sequence of colors with the same length as edgelist.
       If numeric values are specified they will be mapped to
       colors using the edge_cmap and edge_vmin,edge_vmax parameters.

    style : string
       Edge line style (default='solid') (solid|dashed|dotted,dashdot)

    alpha : float
       The edge transparency (default=1.0)

    edge_ cmap : Matplotlib colormap
       Colormap for mapping intensities of edges (default=None)

    edge_vmin,edge_vmax : floats
       Minimum and maximum for edge colormap scaling (default=None)

    ax : Matplotlib Axes object, optional
       Draw the graph in the specified Matplotlib axes.

    arrows : bool, optional (default=True)
       For directed graphs, if True draw arrowheads.

    label : [None| string]
       Label for legend

    Returns
    -------
    matplotlib.collection.LineCollection
        `LineCollection` of the edges

    Notes
    -----
    For directed graphs, "arrows" (actually just thicker stubs) are drawn
    at the head end.  Arrows can be turned off with keyword arrows=False.
    Yes, it is ugly but drawing proper arrows with Matplotlib this
    way is tricky.

    Examples
    --------
    >>> G=nx.dodecahedral_graph()
    >>> edges=nx.draw_networkx_edges(G,pos=nx.spring_layout(G))

    Also see the NetworkX drawing examples at
    http://networkx.github.io/documentation/latest/gallery.html

    See Also
    --------
    draw()
    draw_networkx()
    draw_networkx_nodes()
    draw_networkx_labels()
    draw_networkx_edge_labels()
    """
    try:
        import matplotlib
        import matplotlib.pyplot as plt
        import matplotlib.cbook as cb
        from matplotlib.colors import colorConverter, Colormap
        from matplotlib.collections import LineCollection
        import numpy
    except ImportError:
        raise ImportError("Matplotlib required for draw()")
    except RuntimeError:
        print("Matplotlib unable to open display")
        raise

    if ax is None:
        ax = plt.gca()

    if edgelist is None:
        edgelist = list(G.edges())

    if not edgelist or len(edgelist) == 0:  # no edges!
        return None

    # set edge positions
    edge_pos = numpy.asarray([(pos[e[0]], pos[e[1]]) for e in edgelist])

    if not cb.iterable(width):
        lw = (width,)
    else:
        lw = width

    if not cb.is_string_like(edge_color) \
           and cb.iterable(edge_color) \
           and len(edge_color) == len(edge_pos):
        if numpy.alltrue([cb.is_string_like(c)
                         for c in edge_color]):
            # (should check ALL elements)
            # list of color letters such as ['k','r','k',...]
            edge_colors = tuple([colorConverter.to_rgba(c, alpha)
                                 for c in edge_color])
        elif numpy.alltrue([not cb.is_string_like(c)
                           for c in edge_color]):
            # If color specs are given as (rgb) or (rgba) tuples, we're OK
            if numpy.alltrue([cb.iterable(c) and len(c) in (3, 4)
                             for c in edge_color]):
                edge_colors = tuple(edge_color)
            else:
                # numbers (which are going to be mapped with a colormap)
                edge_colors = None
        else:
            raise ValueError('edge_color must consist of either color names or numbers')
    else:
        if cb.is_string_like(edge_color) or len(edge_color) == 1:
            edge_colors = (colorConverter.to_rgba(edge_color, alpha), )
        else:
            raise ValueError('edge_color must be a single color or list of exactly m colors where m is the number or edges')

    edge_collection = LineCollection(edge_pos,
                                     colors=edge_colors,
                                     linewidths=lw,
                                     antialiaseds=(1,),
                                     linestyle=style,
                                     transOffset = ax.transData,
                                     )

    edge_collection.set_zorder(1)  # edges go behind nodes
    edge_collection.set_label(label)
    ax.add_collection(edge_collection)

    # Note: there was a bug in mpl regarding the handling of alpha values for
    # each line in a LineCollection.  It was fixed in matplotlib in r7184 and
    # r7189 (June 6 2009).  We should then not set the alpha value globally,
    # since the user can instead provide per-edge alphas now.  Only set it
    # globally if provided as a scalar.
    if cb.is_numlike(alpha):
        edge_collection.set_alpha(alpha)

    if edge_colors is None:
        if edge_cmap is not None:
            assert(isinstance(edge_cmap, Colormap))
        edge_collection.set_array(numpy.asarray(edge_color))
        edge_collection.set_cmap(edge_cmap)
        if edge_vmin is not None or edge_vmax is not None:
            edge_collection.set_clim(edge_vmin, edge_vmax)
        else:
            edge_collection.autoscale()

    arrow_collection = None

    if G.is_directed() and arrows:

        # a directed graph hack
        # draw thick line segments at head end of edge
        # waiting for someone else to implement arrows that will work
        arrow_colors = edge_colors
        a_pos = []
        p = 1.0-0.25  # make head segment 25 percent of edge length
        for src, dst in edge_pos:
            x1, y1 = src
            x2, y2 = dst
            dx = x2-x1   # x offset
            dy = y2-y1   # y offset
            d = numpy.sqrt(float(dx**2 + dy**2))  # length of edge
            if d == 0:   # source and target at same position
                continue
            if dx == 0:  # vertical edge
                xa = x2
                ya = dy*p+y1
            if dy == 0:  # horizontal edge
                ya = y2
                xa = dx*p+x1
            else:
                theta = numpy.arctan2(dy, dx)
                xa = p*d*numpy.cos(theta)+x1
                ya = p*d*numpy.sin(theta)+y1

            a_pos.append(((xa, ya), (x2, y2)))

        arrow_collection = LineCollection(a_pos,
                                colors=arrow_colors,
                                linewidths=[4*ww for ww in lw],
                                antialiaseds=(1,),
                                transOffset = ax.transData,
                                )

        arrow_collection.set_zorder(1)  # edges go behind nodes
        arrow_collection.set_label(label)
        ax.add_collection(arrow_collection)

    # update view
    minx = numpy.amin(numpy.ravel(edge_pos[:, :, 0]))
    maxx = numpy.amax(numpy.ravel(edge_pos[:, :, 0]))
    miny = numpy.amin(numpy.ravel(edge_pos[:, :, 1]))
    maxy = numpy.amax(numpy.ravel(edge_pos[:, :, 1]))

    w = maxx-minx
    h = maxy-miny
    padx,  pady = 0.05*w, 0.05*h
    corners = (minx-padx, miny-pady), (maxx+padx, maxy+pady)
    ax.update_datalim(corners)
    ax.autoscale_view()

#    if arrow_collection:

    return edge_collection
Ejemplo n.º 17
0
def draw_networkx_edges(
    G,
    pos,
    edgelist=None,
    width=1.0,
    edge_color="k",
    style="solid",
    alpha=None,
    arrowstyle="-|>",
    arrowsize=3,
    edge_cmap=None,
    edge_vmin=None,
    edge_vmax=None,
    ax=None,
    arrows=True,
    label=None,
    node_size=300,
    nodelist=None,
    node_shape="o",
    connectionstyle=None,
    min_source_margin=0,
    min_target_margin=0,
):
    """Draw the edges of the graph G. Adjusted from networkx."""
    try:
        import matplotlib.pyplot as plt
        from matplotlib.colors import colorConverter, Colormap, Normalize
        from matplotlib.collections import LineCollection
        from matplotlib.patches import FancyArrowPatch
        from numbers import Number
    except ImportError:
        raise ImportError("Matplotlib required for draw()")
    except RuntimeError:
        print("Matplotlib unable to open display")
        raise

    if ax is None:
        ax = plt.gca()

    if edgelist is None:
        edgelist = list(G.edges())

    if not edgelist or len(edgelist) == 0:  # no edges!
        return None

    if nodelist is None:
        nodelist = list(G.nodes())

    # FancyArrowPatch handles color=None different from LineCollection
    if edge_color is None:
        edge_color = "k"

    # set edge positions
    edge_pos = np.asarray([(pos[e[0]], pos[e[1]]) for e in edgelist])

    # Check if edge_color is an array of floats and map to edge_cmap.
    # This is the only case handled differently from matplotlib
    if (
        np.iterable(edge_color)
        and (len(edge_color) == len(edge_pos))
        and np.alltrue([isinstance(c, Number) for c in edge_color])
    ):
        if edge_cmap is not None:
            assert isinstance(edge_cmap, Colormap)
        else:
            edge_cmap = plt.get_cmap()
        if edge_vmin is None:
            edge_vmin = min(edge_color)
        if edge_vmax is None:
            edge_vmax = max(edge_color)
        color_normal = Normalize(vmin=edge_vmin, vmax=edge_vmax)
        edge_color = [edge_cmap(color_normal(e)) for e in edge_color]

    if not G.is_directed() or not arrows:
        edge_collection = LineCollection(
            edge_pos,
            colors=edge_color,
            linewidths=width,
            antialiaseds=(1,),
            linestyle=style,
            transOffset=ax.transData,
            alpha=alpha,
        )

        edge_collection.set_cmap(edge_cmap)
        edge_collection.set_clim(edge_vmin, edge_vmax)

        edge_collection.set_zorder(1)  # edges go behind nodes
        edge_collection.set_label(label)
        ax.add_collection(edge_collection)

        return edge_collection

    arrow_collection = None

    if G.is_directed() and arrows:
        # Note: Waiting for someone to implement arrow to intersection with
        # marker.  Meanwhile, this works well for polygons with more than 4
        # sides and circle.

        def to_marker_edge(marker_size, marker):
            if marker in "s^>v<d":  # `large` markers need extra space
                return np.sqrt(2 * marker_size) / 2
            else:
                return np.sqrt(marker_size) / 2

        # Draw arrows with `matplotlib.patches.FancyarrowPatch`
        arrow_collection = []
        mutation_scale = arrowsize  # scale factor of arrow head

        # FancyArrowPatch doesn't handle color strings
        arrow_colors = colorConverter.to_rgba_array(edge_color, alpha)
        for i, (src, dst) in enumerate(edge_pos):
            x1, y1 = src
            x2, y2 = dst
            shrink_source = 0  # space from source to tail
            shrink_target = 0  # space from  head to target
            if np.iterable(node_size):  # many node sizes
                source, target = edgelist[i][:2]
                source_node_size = node_size[nodelist.index(source)]
                target_node_size = node_size[nodelist.index(target)]
                shrink_source = to_marker_edge(source_node_size, node_shape)
                shrink_target = to_marker_edge(target_node_size, node_shape)
            else:
                shrink_source = shrink_target = to_marker_edge(node_size, node_shape)

            if shrink_source < min_source_margin:
                shrink_source = min_source_margin

            if shrink_target < min_target_margin:
                shrink_target = min_target_margin

            if len(arrow_colors) == len(edge_pos):
                arrow_color = arrow_colors[i]
            elif len(arrow_colors) == 1:
                arrow_color = arrow_colors[0]
            else:  # Cycle through colors
                arrow_color = arrow_colors[i % len(arrow_colors)]

            if np.iterable(width):
                if len(width) == len(edge_pos):
                    line_width = width[i]
                else:
                    line_width = width[i % len(width)]
            else:
                line_width = width

            arrow = FancyArrowPatch(
                (x1, y1),
                (x2, y2),
                arrowstyle=arrowstyle,
                shrinkA=shrink_source,
                shrinkB=shrink_target,
                mutation_scale=mutation_scale,
                color=arrow_color,
                linewidth=line_width,
                connectionstyle=connectionstyle,
                linestyle=style,
                zorder=1,
            )  # arrows go behind nodes

            # There seems to be a bug in matplotlib to make collections of
            # FancyArrowPatch instances. Until fixed, the patches are added
            # individually to the axes instance.
            arrow_collection.append(arrow)
            ax.add_patch(arrow)

    # update view
    minx = np.amin(np.ravel(edge_pos[:, :, 0]))
    maxx = np.amax(np.ravel(edge_pos[:, :, 0]))
    miny = np.amin(np.ravel(edge_pos[:, :, 1]))
    maxy = np.amax(np.ravel(edge_pos[:, :, 1]))

    w = maxx - minx
    h = maxy - miny
    padx, pady = 0.05 * w, 0.05 * h
    corners = (minx - padx, miny - pady), (maxx + padx, maxy + pady)
    ax.update_datalim(corners)
    ax.autoscale_view()

    ax.tick_params(
        axis="both",
        which="both",
        bottom=False,
        left=False,
        labelbottom=False,
        labelleft=False,
    )

    return arrow_collection
Ejemplo n.º 18
0
def QuickPlot(conf=None,
              bodies=None,
              xaxis=None,
              yaxis=None,
              aaxis=None,
              interactive=True,
              nolog=False):
    '''

    '''

    # Assign defaults
    if conf is None:
        conf = GetConf()
    if bodies is None:
        bodies = conf.bodies
    if xaxis is None:
        xaxis = conf.xaxis
    if yaxis is None:
        yaxis = conf.yaxis
    if aaxis is None:
        aaxis = conf.aaxis
    if nolog:
        conf.xlog = False
        conf.ylog = False

    # Output object
    output = GetArrays(bodies=bodies)

    # Names of all available params
    param_names = list(
        set([param.name for body in output.bodies for param in body.params]))

    if len(param_names) == 0:
        raise Exception("There don't seem to be any parameters to be plotted.")

    # The x-axis parameter
    x = param_names[np.argmax(
        np.array(
            [name.lower().startswith(xaxis.lower()) for name in param_names]))]
    if not x.lower().startswith(xaxis.lower()):
        raise Exception('Parameter not understood: %s.' % xaxis)

    # The array of y-axis parameters
    # Ensure it's a list
    if type(yaxis) is str:
        yaxis = [yaxis]

    if len(yaxis) == 0:
        # User didn't specify any; let's plot all of them
        yarr = list(sorted(set(param_names) - set([x])))
    else:
        yarr = []
        for yn in yaxis:
            y = param_names[np.argmax(
                np.array([
                    name.lower().startswith(yn.lower()) for name in param_names
                ]))]
            if not y.lower().startswith(yn.lower()):
                raise Exception('Parameter not found: %s.' % yn)
            yarr.append(y)

    # The alpha parameter
    if aaxis is not None and aaxis != 'None':
        a = param_names[np.argmax(
            np.array([
                name.lower().startswith(aaxis.lower()) for name in param_names
            ]))]
        if not a.lower().startswith(aaxis.lower()):
            raise Exception('Parameter not found: %s.' % aaxis)

    # We will only plot up to a maximum of ``conf.maxrows`` if columns are off
    if (not conf.columns) and len(yarr) > conf.maxrows:
        yarr = yarr[:conf.maxrows]
        rows = conf.maxrows
    elif conf.columns and len(yarr) > conf.maxrows:
        columns = int(np.ceil(float(len(yarr)) / conf.maxrows))
        rows = conf.maxrows
    else:
        columns = 1
        rows = len(yarr)

    # Correct for border cases
    if len(yarr) <= (columns * (rows - 1)):
        rows -= 1
    elif len(yarr) <= ((columns - 1) * rows):
        columns -= 1

    # Set up the plot
    # See http://stackoverflow.com/a/19627237
    mpl.rcParams['figure.autolayout'] = False
    fig = pl.figure(1, figsize=(conf.figwidth, conf.figheight))
    gs = gridspec.GridSpec(rows, columns)
    for i, ss in enumerate(gs):
        if i == 0:
            ax = [fig.add_subplot(gs[0])]
        else:
            ax.append(fig.add_subplot(ss, sharex=ax[0]))

    # Hide empty subplots
    empty = range(len(yarr), rows * columns)
    for i in empty:
        ax[i].set_visible(False)

    # Loop over all parameters (one subplot per each)
    for i, y in enumerate(yarr):

        # Axes limits
        ymin = np.inf
        ymax = -np.inf
        xmin = np.inf
        xmax = -np.inf

        # Loop over all bodies
        for b, body in enumerate(output.bodies):

            # Get indices of the parameters
            if len(body.params):
                xi = np.where(
                    np.array([param.name for param in body.params]) == x)[0]
                yi = np.where(
                    np.array([param.name for param in body.params]) == y)[0]
            else:
                xi = np.array([], dtype=int)
                yi = np.array([], dtype=int)

            if aaxis is not None and aaxis != 'None':
                ai = np.where(
                    a == np.array([param.name for param in body.params]))[0]
            else:
                ai = []

            # Are both x and y arrays preset for this body?
            if len(xi) and len(yi):
                xi = xi[0]
                yi = yi[0]
            else:
                continue

            if len(ai):
                ai = ai[0]
            else:
                ai = None

            # Get the arrays
            xpts = body.params[xi].array
            ypts = body.params[yi].array

            # Decide whether to plot individual legends
            if conf.legend_all:
                label = body.name
            else:
                label = None

            # Should we plot the first point if x = 0?
            if xpts[0] == 0. and conf.xlog and conf.skip_xzero_log:
                xpts = xpts[1:]
                ypts = ypts[1:]

            # Plot the curve
            if ai is None:

                # A simple solid color line
                ax[i].plot(xpts,
                           ypts,
                           conf.line_styles[b],
                           label=label,
                           lw=conf.linewidth)
            else:

                # Let's get fancy: make the curve opacity proportional
                # to the `aaxis` parameter
                apts = body.params[ai].array

                # Make logarithmic if necessary
                if conf.alog:
                    if apts[0] == 0.:
                        apts = apts[1:]
                    apts = np.log10(apts)

                points = np.array([xpts, ypts]).T.reshape(-1, 1, 2)
                segments = np.concatenate([points[:-1], points[1:]], axis=1)
                lc = LineCollection(
                    segments,
                    cmap=AlphaMap(
                        *ColorConverter().to_rgb(conf.line_styles[b][0])),
                    norm=pl.Normalize(np.nanmin(apts), np.nanmax(apts)))
                lc.set_array(apts)
                lc.set_linestyle(conf.line_styles[b][1:])
                lc.set_linewidth(conf.linewidth)
                lc.set_label(label)
                ax[i].add_collection(lc)

            # Limits
            if np.nanmin(xpts) < xmin:
                xmin = np.nanmin(xpts)
            if np.nanmin(ypts) < ymin:
                ymin = np.nanmin(ypts)
            if np.nanmax(xpts) > xmax:
                xmax = np.nanmax(xpts)
            if np.nanmax(ypts) > ymax:
                ymax = np.nanmax(ypts)

            # Labels
            ax[i].set_xlabel(body.params[xi].label(conf.short_labels),
                             fontsize=conf.xlabel_fontsize)
            ax[i].set_ylabel(body.params[yi].label(conf.short_labels,
                                                   conf.maxylabelsize),
                             fontsize=conf.ylabel_fontsize)

            # Tick sizes
            for tick in ax[i].xaxis.get_major_ticks():
                tick.label.set_fontsize(conf.xticklabel_fontsize)
            for tick in ax[i].yaxis.get_major_ticks():
                tick.label.set_fontsize(conf.yticklabel_fontsize)

        # Log scale?
        if conf.xlog:
            if np.log(xmax) - np.log(xmin) > conf.xlog:
                if xmin > 0:
                    ax[i].set_xscale('log')
        if conf.ylog:
            if np.log(ymax) - np.log(ymin) > conf.ylog:
                if ymin > 0:
                    ax[i].set_yscale('log')

        # Tighten things up a bit
        if i < len(yarr) - columns:
            if conf.tight_layout:
                ax[i].set_xticklabels([])
            ax[i].set_xlabel('')

        # Add y-axis margins (doesn't work well with log)
        ax[i].margins(0., conf.ymargin)

        # Add a legend
        if conf.legend_all:
            ax[i].legend(loc=conf.legend_loc, fontsize=conf.legend_fontsize)
        elif i == 0:
            xlim = ax[i].get_xlim()
            ylim = ax[i].get_ylim()
            for b, body in enumerate(output.bodies):
                # HACK: Plot a line of length zero in the center
                # of the plot so that it will show up on the legend
                foo = ax[i].plot([(xlim[0] + xlim[1]) / 2.],
                                 [(ylim[0] + ylim[1]) / 2.],
                                 conf.line_styles[b],
                                 label=body.name)
            ax[i].legend(loc=conf.legend_loc, fontsize=conf.legend_fontsize)

    # Add title
    if conf.title:
        if len(yarr) == 1:
            pl.title('VPLANET: %s' % output.sysname, fontsize=24)
        else:
            pl.suptitle('VPLANET: %s' % output.sysname, fontsize=24)

    try:
        gs.tight_layout(fig, rect=[0, 0.03, 1, 0.95])
    except:
        # No biggie
        pass

    # Show or save?
    if interactive and conf.interactive:
        pl.show()
    else:
        fig.savefig(conf.figname, bbox_inches='tight')

    return fig, ax
Ejemplo n.º 19
0
def _plot_skeleton(neuron, color, method, ax, **kwargs):
    """Plot skeleton."""
    depth_coloring = kwargs.get('depth_coloring', False)
    linewidth = kwargs.get('linewidth', kwargs.get('lw', .5))
    linestyle = kwargs.get('linestyle', kwargs.get('ls', '-'))
    alpha = kwargs.get('alpha', .9)
    norm = kwargs.get('norm')
    plot_soma = kwargs.get('soma', True)
    group_neurons = kwargs.get('group_neurons', False)

    # Generate by-segment coordinates
    coords = segments_to_coords(neuron,
                                neuron.segments,
                                modifier=(1, 1, 1))

    if method == '2d':
        if not depth_coloring:
            # We have to add (None, None, None) to the end of each
            # slab to make that line discontinuous there
            coords = np.vstack(
                [np.append(t, [[None] * 3], axis=0) for t in coords])

            this_line = mlines.Line2D(coords[:, 0], coords[:, 1],
                                      lw=linewidth, ls=linestyle,
                                      alpha=alpha, color=color,
                                      label=f'{getattr(neuron, "name", "NA")} - #{neuron.id}')
            ax.add_line(this_line)
        else:
            coords = tn_pairs_to_coords(neuron, modifier=(1, 1, 1))
            lc = LineCollection(coords[:, :, [0, 1]],
                                cmap='jet',
                                norm=norm)
            lc.set_array(neuron.nodes.loc[neuron.nodes.parent_id >= 0, 'z'].values)
            lc.set_linewidth(linewidth)
            lc.set_alpha(alpha)
            lc.set_linestyle(linestyle)
            lc.set_label(f'{getattr(neuron, "name", "NA")} - #{neuron.id}')
            ax.add_collection(lc)

        if plot_soma and not isinstance(neuron.soma, type(None)):
            soma = utils.make_iterable(neuron.soma)
            # If soma detection is messed up we might end up producing
            # dozens of soma which will freeze the kernel
            if len(soma) >= 10:
                logger.warning(f'{neuron.id} - {len(soma)} somas found.')
            for s in soma:
                n = neuron.nodes.set_index('node_id').loc[s]
                r = getattr(n, neuron.soma_radius) if isinstance(neuron.soma_radius, str) else neuron.soma_radius

                if depth_coloring:
                    color = mpl.cm.jet(norm(n.z))

                s = mpatches.Circle((int(n.x), int(n.y)), radius=r,
                                    alpha=alpha, fill=True, fc=color,
                                    zorder=4, edgecolor='none')
                ax.add_patch(s)
        return None, None

    elif method in ['3d', '3d_complex']:
        # For simple scenes, add whole neurons at a time -> will speed
        # up rendering
        if method == '3d':
            if depth_coloring:
                this_coords = tn_pairs_to_coords(neuron,
                                                 modifier=(1, 1, 1))[:, :, [0, 1, 2]]
            else:
                this_coords = [c[:, [0, 1, 2]] for c in coords]

            lc = Line3DCollection(this_coords,
                                  color=color,
                                  label=neuron.id,
                                  alpha=alpha,
                                  cmap=mpl.cm.jet if depth_coloring else None,
                                  lw=linewidth,
                                  linestyle=linestyle)
            if group_neurons:
                lc.set_gid(neuron.id)
            # Need to get this before adding data
            line3D_collection = ax.add_collection3d(lc)

        # For complex scenes, add each segment as a single collection
        # -> helps preventing Z-order errors
        elif method == '3d_complex':
            for c in coords:
                lc = Line3DCollection([c],
                                      color=color,
                                      lw=linewidth,
                                      alpha=alpha,
                                      linestyle=linestyle)
                if group_neurons:
                    lc.set_gid(neuron.id)
                ax.add_collection3d(lc)
            line3D_collection = None

        surf3D_collections = []
        if plot_soma and not isinstance(neuron.soma, type(None)):
            soma = utils.make_iterable(neuron.soma)
            # If soma detection is messed up we might end up producing
            # dozens of soma which will freeze the kernel
            if len(soma) >= 5:
                logger.warning(f'Neuron {neuron.id} appears to have {len(soma)}'
                               ' somas. Skipping plotting its somas.')
            else:
                for s in soma:
                    n = neuron.nodes.set_index('node_id').loc[s]
                    r = getattr(n, neuron.soma_radius) if isinstance(neuron.soma_radius, str) else neuron.soma_radius

                    resolution = 20
                    u = np.linspace(0, 2 * np.pi, resolution)
                    v = np.linspace(0, np.pi, resolution)
                    x = r * np.outer(np.cos(u), np.sin(v)) + n.x
                    y = r * np.outer(np.sin(u), np.sin(v)) + n.y
                    z = r * np.outer(np.ones(np.size(u)), np.cos(v)) + n.z
                    surf = ax.plot_surface(x, y, z,
                                           color=color,
                                           shade=False,
                                           alpha=alpha)
                    if group_neurons:
                        surf.set_gid(neuron.id)

                    surf3D_collections.append(surf)

        return line3D_collection, surf3D_collections
Ejemplo n.º 20
0
    def readshapefileext(self,
                         shapefile,
                         name,
                         drawbounds=True,
                         zorder=None,
                         linewidth=0.5,
                         color='k',
                         antialiased=1,
                         ax=None,
                         default_encoding='utf-8',
                         linestyle='-'):
        """
        Read in shape file, optionally draw boundaries on map.

        .. note::
          - Assumes shapes are 2D
          - only works for Point, MultiPoint, Polyline and Polygon shapes.
          - vertices/points must be in geographic (lat/lon) coordinates.

        Mandatory Arguments:

        .. tabularcolumns:: |l|L|

        ==============   ====================================================
        Argument         Description
        ==============   ====================================================
        shapefile        path to shapefile components.  Example:
                         shapefile='/home/jeff/esri/world_borders' assumes
                         that world_borders.shp, world_borders.shx and
                         world_borders.dbf live in /home/jeff/esri.
        name             name for Basemap attribute to hold the shapefile
                         vertices or points in map projection
                         coordinates. Class attribute name+'_info' is a list
                         of dictionaries, one for each shape, containing
                         attributes of each shape from dbf file, For
                         example, if name='counties', self.counties
                         will be a list of x,y vertices for each shape in
                         map projection  coordinates and self.counties_info
                         will be a list of dictionaries with shape
                         attributes.  Rings in individual Polygon
                         shapes are split out into separate polygons, and
                         additional keys 'RINGNUM' and 'SHAPENUM' are added
                         to the shape attribute dictionary.
        ==============   ====================================================

        The following optional keyword arguments are only relevant for Polyline
        and Polygon shape types, for Point and MultiPoint shapes they are
        ignored.

        .. tabularcolumns:: |l|L|

        ==============   ====================================================
        Keyword          Description
        ==============   ====================================================
        drawbounds       draw boundaries of shapes (default True).
        zorder           shape boundary zorder (if not specified,
                         default for mathplotlib.lines.LineCollection
                         is used).
        linewidth        shape boundary line width (default 0.5)
        color            shape boundary line color (default black)
        antialiased      antialiasing switch for shape boundaries
                         (default True).
        ax               axes instance (overrides default axes instance)
        ==============   ====================================================

        A tuple (num_shapes, type, min, max) containing shape file info
        is returned.
        num_shapes is the number of shapes, type is the type code (one of
        the SHPT* constants defined in the shapelib module, see
        http://shapelib.maptools.org/shp_api.html) and min and
        max are 4-element lists with the minimum and maximum values of the
        vertices. If ``drawbounds=True`` a
        matplotlib.patches.LineCollection object is appended to the tuple.
        """
        import shapefile as shp
        from shapefile import Reader
        shp.default_encoding = default_encoding
        if not os.path.exists('%s.shp' % shapefile):
            raise IOError('cannot locate %s.shp' % shapefile)
        if not os.path.exists('%s.shx' % shapefile):
            raise IOError('cannot locate %s.shx' % shapefile)
        if not os.path.exists('%s.dbf' % shapefile):
            raise IOError('cannot locate %s.dbf' % shapefile)
        # open shapefile, read vertices for each object, convert
        # to map projection coordinates (only works for 2D shape types).
        try:
            shf = Reader(shapefile)
        except:
            raise IOError('error reading shapefile %s.shp' % shapefile)
        fields = shf.fields
        coords = []
        attributes = []
        msg = dedent("""
        shapefile must have lat/lon vertices  - it looks like this one has vertices
        in map projection coordinates. You can convert the shapefile to geographic
        coordinates using the shpproj utility from the shapelib tools
        (http://shapelib.maptools.org/shapelib-tools.html)""")
        shptype = shf.shapes()[0].shapeType
        bbox = shf.bbox.tolist()
        info = (shf.numRecords, shptype, bbox[0:2] + [0., 0.],
                bbox[2:] + [0., 0.])
        npoly = 0
        for shprec in shf.shapeRecords():
            shp = shprec.shape
            rec = shprec.record
            npoly = npoly + 1
            if shptype != shp.shapeType:
                raise ValueError(
                    'readshapefile can only handle a single shape type per file'
                )
            if shptype not in [1, 3, 5, 8]:
                raise ValueError(
                    'readshapefile can only handle 2D shape types')
            verts = shp.points
            if shptype in [1, 8]:  # a Point or MultiPoint shape.
                lons, lats = list(zip(*verts))
                if max(lons) > 721. or min(lons) < -721. or max(
                        lats) > 90.01 or min(lats) < -90.01:
                    raise ValueError(msg)
                # if latitude is slightly greater than 90, truncate to 90
                lats = [max(min(lat, 90.0), -90.0) for lat in lats]
                if len(verts) > 1:  # MultiPoint
                    x, y = self(lons, lats)
                    coords.append(list(zip(x, y)))
                else:  # single Point
                    x, y = self(lons[0], lats[0])
                    coords.append((x, y))
                attdict = {}
                for r, key in zip(rec, fields[1:]):
                    attdict[key[0]] = r
                attributes.append(attdict)
            else:  # a Polyline or Polygon shape.
                parts = shp.parts.tolist()
                ringnum = 0
                for indx1, indx2 in zip(parts, parts[1:] + [len(verts)]):
                    ringnum = ringnum + 1
                    lons, lats = list(zip(*verts[indx1:indx2]))
                    if max(lons) > 721. or min(lons) < -721. or max(
                            lats) > 90.01 or min(lats) < -90.01:
                        raise ValueError(msg)
                    # if latitude is slightly greater than 90, truncate to 90
                    lats = [max(min(lat, 90.0), -90.0) for lat in lats]
                    x, y = self(lons, lats)
                    coords.append(list(zip(x, y)))
                    attdict = {}
                    for r, key in zip(rec, fields[1:]):
                        attdict[key[0]] = r
                    # add information about ring number to dictionary.
                    attdict['RINGNUM'] = ringnum
                    attdict['SHAPENUM'] = npoly
                    attributes.append(attdict)
        # draw shape boundaries for polylines, polygons  using LineCollection.
        if shptype not in [1, 8] and drawbounds:
            # get current axes instance (if none specified).
            ax = ax or self._check_ax()
            # make LineCollections for each polygon.
            lines = LineCollection(coords, antialiaseds=(1, ))
            lines.set_color(color)
            lines.set_linewidth(linewidth)
            lines.set_linestyle(linestyle)
            lines.set_label('_nolabel_')
            if zorder is not None:
                lines.set_zorder(zorder)
            ax.add_collection(lines)
            # set axes limits to fit map region.
            self.set_axes_limits(ax=ax)
            # clip boundaries to map limbs
            lines, c = self._cliplimb(ax, lines)
            info = info + (lines, )
        self.__dict__[name] = coords
        self.__dict__[name + '_info'] = attributes
        return info
Ejemplo n.º 21
0
def _plot_skeleton(neuron, color, method, ax, **kwargs):
    """Plot skeleton."""
    depth_coloring = kwargs.get('depth_coloring', False)
    linewidth = kwargs.get('linewidth', kwargs.get('lw', .5))
    linestyle = kwargs.get('linestyle', kwargs.get('ls', '-'))
    alpha = kwargs.get('alpha', .9)
    norm = kwargs.get('norm')
    plot_soma = kwargs.get('soma', True)
    group_neurons = kwargs.get('group_neurons', False)
    view = kwargs.get('view', ('x', 'y'))

    if method == '2d':
        if not depth_coloring and not (isinstance(color, np.ndarray)
                                       and color.ndim == 2):
            # Generate by-segment coordinates
            coords = segments_to_coords(neuron,
                                        neuron.segments,
                                        modifier=(1, 1, 1))

            # We have to add (None, None, None) to the end of each
            # slab to make that line discontinuous there
            coords = np.vstack(
                [np.append(t, [[None] * 3], axis=0) for t in coords])

            x, y = _parse_view2d(coords, view)
            this_line = mlines.Line2D(
                x,
                y,
                lw=linewidth,
                ls=linestyle,
                alpha=alpha,
                color=color,
                label=f'{getattr(neuron, "name", "NA")} - #{neuron.id}')
            ax.add_line(this_line)
        else:
            coords = tn_pairs_to_coords(neuron, modifier=(1, 1, 1))

            xy = _parse_view2d(coords, view)
            lc = LineCollection(xy,
                                cmap='jet' if depth_coloring else None,
                                norm=norm if depth_coloring else None,
                                joinstyle='round')

            lc.set_linewidth(linewidth)
            lc.set_linestyle(linestyle)
            lc.set_label(f'{getattr(neuron, "name", "NA")} - #{neuron.id}')

            if depth_coloring:
                lc.set_alpha(alpha)
                lc.set_array(neuron.nodes.loc[neuron.nodes.parent_id >= 0,
                                              'z'].values)
            elif (isinstance(color, np.ndarray) and color.ndim == 2):
                # If we have a color for each node, we need to drop the roots
                if color.shape[1] != coords.shape[0]:
                    lc.set_color(color[neuron.nodes.parent_id.values >= 0])
                else:
                    lc.set_color(color)

            ax.add_collection(lc)

        if plot_soma and np.any(neuron.soma):
            soma = utils.make_iterable(neuron.soma)
            # If soma detection is messed up we might end up producing
            # dozens of soma which will freeze the kernel
            if len(soma) >= 10:
                logger.warning(f'{neuron.id} - {len(soma)} somas found.')
            for s in soma:
                if isinstance(color, np.ndarray) and color.ndim > 1:
                    s_ix = np.where(neuron.nodes.node_id == s)[0][0]
                    soma_color = color[s_ix]
                else:
                    soma_color = color

                n = neuron.nodes.set_index('node_id').loc[s]
                r = getattr(n, neuron.soma_radius) if isinstance(
                    neuron.soma_radius, str) else neuron.soma_radius

                if depth_coloring:
                    d = [n.x, n.y, n.z][_get_depth_axis(view)]
                    soma_color = mpl.cm.jet(norm(d))

                sx, sy = _parse_view2d(np.array([[n.x, n.y, n.z]]), view)
                c = mpatches.Circle((sx[0], sy[0]),
                                    radius=r,
                                    alpha=alpha,
                                    fill=True,
                                    fc=soma_color,
                                    zorder=4,
                                    edgecolor='none')
                ax.add_patch(c)
        return None, None

    elif method in ['3d', '3d_complex']:
        # For simple scenes, add whole neurons at a time to speed up rendering
        if method == '3d':
            if (isinstance(color, np.ndarray)
                    and color.ndim == 2) or depth_coloring:
                coords = tn_pairs_to_coords(neuron, modifier=(1, 1, 1))
                # If we have a color for each node, we need to drop the roots
                if isinstance(
                        color,
                        np.ndarray) and color.shape[1] != coords.shape[0]:
                    line_color = color[neuron.nodes.parent_id.values >= 0]
                else:
                    line_color = color
            else:
                # Generate by-segment coordinates
                coords = segments_to_coords(neuron,
                                            neuron.segments,
                                            modifier=(1, 1, 1))
                line_color = color

            lc = Line3DCollection(
                coords,
                color=line_color,
                label=neuron.id,
                alpha=alpha if not kwargs.get('shade_by', False) else None,
                cmap=mpl.cm.jet if depth_coloring else None,
                lw=linewidth,
                joinstyle='round',
                linestyle=linestyle)
            if group_neurons:
                lc.set_gid(neuron.id)
            # Need to get this before adding data
            line3D_collection = lc
            ax.add_collection3d(lc)

        # For complex scenes, add each segment as a single collection
        # -> helps reducing Z-order errors
        elif method == '3d_complex':
            # Generate by-segment coordinates
            coords = segments_to_coords(neuron,
                                        neuron.segments,
                                        modifier=(1, 1, 1))
            for c in coords:
                lc = Line3DCollection([c],
                                      color=color,
                                      lw=linewidth,
                                      alpha=alpha,
                                      linestyle=linestyle)
                if group_neurons:
                    lc.set_gid(neuron.id)
                ax.add_collection3d(lc)
            line3D_collection = None

        surf3D_collections = []
        if plot_soma and not isinstance(getattr(neuron, 'soma', None),
                                        type(None)):
            soma = utils.make_iterable(neuron.soma)
            # If soma detection is messed up we might end up producing
            # dozens of soma which will freeze the kernel
            if len(soma) >= 5:
                logger.warning(
                    f'Neuron {neuron.id} appears to have {len(soma)}'
                    ' somas. Skipping plotting its somas.')
            else:
                for s in soma:
                    if isinstance(color, np.ndarray) and color.ndim > 1:
                        s_ix = np.where(neuron.nodes.node_id == s)[0][0]
                        soma_color = color[s_ix]
                    else:
                        soma_color = color

                    n = neuron.nodes.set_index('node_id').loc[s]
                    r = getattr(n, neuron.soma_radius) if isinstance(
                        neuron.soma_radius, str) else neuron.soma_radius

                    resolution = 20
                    u = np.linspace(0, 2 * np.pi, resolution)
                    v = np.linspace(0, np.pi, resolution)
                    x = r * np.outer(np.cos(u), np.sin(v)) + n.x
                    y = r * np.outer(np.sin(u), np.sin(v)) + n.y
                    z = r * np.outer(np.ones(np.size(u)), np.cos(v)) + n.z
                    surf = ax.plot_surface(x,
                                           y,
                                           z,
                                           color=soma_color,
                                           shade=False,
                                           alpha=alpha)
                    if group_neurons:
                        surf.set_gid(neuron.id)

                    surf3D_collections.append(surf)

        return line3D_collection, surf3D_collections
def drawMap(filename,names,totalCount):
  countries = json.loads(open(filename).read())["features"]

  for country in countries:
    name = country["properties"]["name"]
    polygonList = country["geometry"]["coordinates"]
    polygonType = country["geometry"]["type"]
    shpsegs = []

    print "Processing %s [%d/%s] ..." % (unicode(name).encode("utf-8"), len(polygonList), polygonType)
    maxverts = 0
    maxindex = 0
    counter = 0
    for polygon in polygonList:
      if polygonType == "MultiPolygon":
        for p in polygon:
          if len(p) == 1:
            p = p[0]
          if p[0] != p[-1]:
            p.append(p[0])

          lons, lats = zip(*p)
          x, y = m(lons, lats)
          shpsegs.append(zip(x,y))
          if len(x) > maxverts:
            maxverts = len(x)
            maxindex = counter
          counter+=1
      else:
        if len(polygon) == 1:
          polygon = polygon[0]
        if polygon[0] != polygon[-1]:
          polygon.append(polygon[0])

        lons, lats = zip(*polygon)
        x, y = m(lons, lats)
        shpsegs.append(zip(x,y))
        if len(x) > maxverts:
          maxverts = len(x)
          maxindex = counter
        counter+=1

    # Compute centroid
    centroid = Polygon(shpsegs[maxindex]).centroid

    # Create country shape
    lines = LineCollection(shpsegs,antialiaseds=(1,))
    lines.set_edgecolors('k')
    lines.set_linewidth(0.5)

    #import brewer2mpl
    #colormap = brewer2mpl.get_map('Paired', 'qualitative', 12).mpl_colors
    colormap = [(0.6509803921568628, 0.807843137254902, 0.8901960784313725), (0.12156862745098039, 0.47058823529411764, 0.7058823529411765), (0.6980392156862745, 0.8745098039215686, 0.5411764705882353), (0.2, 0.6274509803921569, 0.17254901960784313), (0.984313725490196, 0.6039215686274509, 0.6), (0.8901960784313725, 0.10196078431372549, 0.10980392156862745), (0.9921568627450981, 0.7490196078431373, 0.43529411764705883), (1.0, 0.4980392156862745, 0.0), (0.792156862745098, 0.6980392156862745, 0.8392156862745098), (0.41568627450980394, 0.23921568627450981, 0.6039215686274509), (1.0, 1.0, 0.6), (0.6941176470588235, 0.34901960784313724, 0.1568627450980392)]

    # Add color and label if covered by Safecast
    if name in names.keys():
      color = colormap[(int((float(names[name][0])/totalCount)*12)+1)]
      lines.set_label("%s - %0.1fK (%d)" % (name, names[name][0]/1000.0, names[name][1]) )
      #lines.set_label(name)
      lines.set_edgecolors(color)
      lines.set_facecolors(color)
      label = plt.text(centroid.x, centroid.y, "%d" % names[name][1], fontsize=5, ha='center', va='center', color='k', fontweight='bold')
      plt.setp(label, path_effects=[PathEffects.withStroke(linewidth=2, foreground="w")])
    ax.add_collection(lines)
Ejemplo n.º 23
0
def draw_networkx_edges(G, pos,
                        edgelist=None,
                        width=1.0,
                        edge_color='k',
                        style='solid',
                        alpha=1.0,
                        arrowstyle='-|>',
                        arrowsize=10,
                        edge_cmap=None,
                        edge_vmin=None,
                        edge_vmax=None,
                        ax=None,
                        arrows=True,
                        label=None,
                        node_size=300,
                        nodelist=None,
                        node_shape="o",
                        **kwds):
    """Draw the edges of the graph G.

    This draws only the edges of the graph G.

    Parameters
    ----------
    G : graph
       A networkx graph

    pos : dictionary
       A dictionary with nodes as keys and positions as values.
       Positions should be sequences of length 2.

    edgelist : collection of edge tuples
       Draw only specified edges(default=G.edges())

    width : float, or array of floats
       Line width of edges (default=1.0)

    edge_color : color string, or array of floats
       Edge color. Can be a single color format string (default='r'),
       or a sequence of colors with the same length as edgelist.
       If numeric values are specified they will be mapped to
       colors using the edge_cmap and edge_vmin,edge_vmax parameters.

    style : string
       Edge line style (default='solid') (solid|dashed|dotted,dashdot)

    alpha : float
       The edge transparency (default=1.0)

    edge_ cmap : Matplotlib colormap
       Colormap for mapping intensities of edges (default=None)

    edge_vmin,edge_vmax : floats
       Minimum and maximum for edge colormap scaling (default=None)

    ax : Matplotlib Axes object, optional
       Draw the graph in the specified Matplotlib axes.

    arrows : bool, optional (default=True)
       For directed graphs, if True draw arrowheads.
       Note: Arrows will be the same color as edges.

    arrowstyle : str, optional (default='-|>')
       For directed graphs, choose the style of the arrow heads.
       See :py:class: `matplotlib.patches.ArrowStyle` for more
       options.

    arrowsize : int, optional (default=10)
       For directed graphs, choose the size of the arrow head head's length and
       width. See :py:class: `matplotlib.patches.FancyArrowPatch` for attribute
       `mutation_scale` for more info.

    label : [None| string]
       Label for legend

    Returns
    -------
    matplotlib.collection.LineCollection
        `LineCollection` of the edges

    list of matplotlib.patches.FancyArrowPatch
        `FancyArrowPatch` instances of the directed edges

    Depending whether the drawing includes arrows or not.

    Notes
    -----
    For directed graphs, arrows are drawn at the head end.  Arrows can be
    turned off with keyword arrows=False. Be sure to include `node_size' as a
    keyword argument; arrows are drawn considering the size of nodes.

    Examples
    --------
    >>> G = nx.dodecahedral_graph()
    >>> edges = nx.draw_networkx_edges(G, pos=nx.spring_layout(G))

    >>> G = nx.DiGraph()
    >>> G.add_edges_from([(1, 2), (1, 3), (2, 3)])
    >>> arcs = nx.draw_networkx_edges(G, pos=nx.spring_layout(G))
    >>> alphas = [0.3, 0.4, 0.5]
    >>> for i, arc in enumerate(arcs):  # change alpha values of arcs
    ...     arc.set_alpha(alphas[i])

    Also see the NetworkX drawing examples at
    https://networkx.github.io/documentation/latest/auto_examples/index.html

    See Also
    --------
    draw()
    draw_networkx()
    draw_networkx_nodes()
    draw_networkx_labels()
    draw_networkx_edge_labels()
    """
    try:
        import matplotlib
        import matplotlib.pyplot as plt
        import matplotlib.cbook as cb
        from matplotlib.colors import colorConverter, Colormap, Normalize
        from matplotlib.collections import LineCollection
        from matplotlib.patches import FancyArrowPatch
        import numpy as np
    except ImportError:
        raise ImportError("Matplotlib required for draw()")
    except RuntimeError:
        print("Matplotlib unable to open display")
        raise

    if ax is None:
        ax = plt.gca()

    if edgelist is None:
        edgelist = list(G.edges())

    if not edgelist or len(edgelist) == 0:  # no edges!
        return None

    if nodelist is None:
        nodelist = list(G.nodes())

    # set edge positions
    edge_pos = np.asarray([(pos[e[0]], pos[e[1]]) for e in edgelist])

    if not cb.iterable(width):
        lw = (width,)
    else:
        lw = width

    if not is_string_like(edge_color) \
            and cb.iterable(edge_color) \
            and len(edge_color) == len(edge_pos):
        if np.alltrue([is_string_like(c) for c in edge_color]):
            # (should check ALL elements)
            # list of color letters such as ['k','r','k',...]
            edge_colors = tuple([colorConverter.to_rgba(c, alpha)
                                 for c in edge_color])
        elif np.alltrue([not is_string_like(c) for c in edge_color]):
            # If color specs are given as (rgb) or (rgba) tuples, we're OK
            if np.alltrue([cb.iterable(c) and len(c) in (3, 4)
                          for c in edge_color]):
                edge_colors = tuple(edge_color)
            else:
                # numbers (which are going to be mapped with a colormap)
                edge_colors = None
        else:
            raise ValueError('edge_color must contain color names or numbers')
    else:
        if is_string_like(edge_color) or len(edge_color) == 1:
            edge_colors = (colorConverter.to_rgba(edge_color, alpha), )
        else:
            msg = 'edge_color must be a color or list of one color per edge'
            raise ValueError(msg)

    if (not G.is_directed() or not arrows):
        edge_collection = LineCollection(edge_pos,
                                         colors=edge_colors,
                                         linewidths=lw,
                                         antialiaseds=(1,),
                                         linestyle=style,
                                         transOffset=ax.transData,
                                         )

        edge_collection.set_zorder(1)  # edges go behind nodes
        edge_collection.set_label(label)
        ax.add_collection(edge_collection)

        # Note: there was a bug in mpl regarding the handling of alpha values
        # for each line in a LineCollection. It was fixed in matplotlib by
        # r7184 and r7189 (June 6 2009). We should then not set the alpha
        # value globally, since the user can instead provide per-edge alphas
        # now.  Only set it globally if provided as a scalar.
        if cb.is_numlike(alpha):
            edge_collection.set_alpha(alpha)

        if edge_colors is None:
            if edge_cmap is not None:
                assert(isinstance(edge_cmap, Colormap))
            edge_collection.set_array(np.asarray(edge_color))
            edge_collection.set_cmap(edge_cmap)
            if edge_vmin is not None or edge_vmax is not None:
                edge_collection.set_clim(edge_vmin, edge_vmax)
            else:
                edge_collection.autoscale()
        return edge_collection

    arrow_collection = None

    if G.is_directed() and arrows:
        # Note: Waiting for someone to implement arrow to intersection with
        # marker.  Meanwhile, this works well for polygons with more than 4
        # sides and circle.

        def to_marker_edge(marker_size, marker):
            if marker in "s^>v<d":  # `large` markers need extra space
                return np.sqrt(2 * marker_size) / 2
            else:
                return np.sqrt(marker_size) / 2

        # Draw arrows with `matplotlib.patches.FancyarrowPatch`
        arrow_collection = []
        mutation_scale = arrowsize  # scale factor of arrow head
        arrow_colors = edge_colors
        if arrow_colors is None:
            if edge_cmap is not None:
                assert(isinstance(edge_cmap, Colormap))
            else:
                edge_cmap = plt.get_cmap()  # default matplotlib colormap
            if edge_vmin is None:
                edge_vmin = min(edge_color)
            if edge_vmax is None:
                edge_vmax = max(edge_color)
            color_normal = Normalize(vmin=edge_vmin, vmax=edge_vmax)

        for i, (src, dst) in enumerate(edge_pos):
            x1, y1 = src
            x2, y2 = dst
            arrow_color = None
            line_width = None
            shrink_source = 0  # space from source to tail
            shrink_target = 0  # space from  head to target
            if cb.iterable(node_size):  # many node sizes
                src_node, dst_node = edgelist[i]
                index_node = nodelist.index(dst_node)
                marker_size = node_size[index_node]
                shrink_target = to_marker_edge(marker_size, node_shape)
            else:
                shrink_target = to_marker_edge(node_size, node_shape)
            if arrow_colors is None:
                arrow_color = edge_cmap(color_normal(edge_color[i]))
            elif len(arrow_colors) > 1:
                arrow_color = arrow_colors[i]
            else:
                arrow_color = arrow_colors[0]
            if len(lw) > 1:
                line_width = lw[i]
            else:
                line_width = lw[0]
            arrow = FancyArrowPatch((x1, y1), (x2, y2),
                                    arrowstyle=arrowstyle,
                                    shrinkA=shrink_source,
                                    shrinkB=shrink_target,
                                    mutation_scale=mutation_scale,
                                    color=arrow_color,
                                    linewidth=line_width,
                                    zorder=1)  # arrows go behind nodes

            # There seems to be a bug in matplotlib to make collections of
            # FancyArrowPatch instances. Until fixed, the patches are added
            # individually to the axes instance.
            arrow_collection.append(arrow)
            ax.add_patch(arrow)

    # update view
    minx = np.amin(np.ravel(edge_pos[:, :, 0]))
    maxx = np.amax(np.ravel(edge_pos[:, :, 0]))
    miny = np.amin(np.ravel(edge_pos[:, :, 1]))
    maxy = np.amax(np.ravel(edge_pos[:, :, 1]))

    w = maxx - minx
    h = maxy - miny
    padx,  pady = 0.05 * w, 0.05 * h
    corners = (minx - padx, miny - pady), (maxx + padx, maxy + pady)
    ax.update_datalim(corners)
    ax.autoscale_view()

    return arrow_collection
Ejemplo n.º 24
0
    def draw_animation_edges(G,
                             pos,
                             edgelist=None,
                             width=1.0,
                             edge_color='k',
                             style='solid',
                             alpha=1.0,
                             edge_cmap=None,
                             edge_vmin=None,
                             edge_vmax=None,
                             ax=None,
                             arrows=True,
                             label=None,
                             **kwds):
        try:
            import matplotlib
            import matplotlib.pyplot as plt
            import matplotlib.cbook as cb
            from matplotlib.colors import colorConverter, Colormap
            from matplotlib.collections import LineCollection
            import numpy
        except ImportError:
            raise ImportError("Matplotlib required for draw()")
        except RuntimeError:
            print("Matplotlib unable to open display")
            raise

        if ax is None:
            ax = plt.gca()

        if edgelist is None:
            edgelist = list(G.edges())

        if not edgelist or len(edgelist) == 0:  # no edges!
            return None

        # set edge positions

        box_pos = numpy.asarray([(pos[e[0]], pos[e[1]]) for e in edgelist])
        p = 0.25
        edge_pos = []
        for edge in edgelist:
            src, dst = np.array(pos[edge[0]]), np.array(pos[edge[1]])
            s = dst - src
            # src = src + p * s  # Box at beginning
            # dst = src + (1-p) * s   # Box at the end
            dst = src  # No edge at all
            edge_pos.append((src, dst))
        edge_pos = numpy.asarray(edge_pos)

        if not cb.iterable(width):
            lw = (width, )
        else:
            lw = width

        if not cb.is_scalar_or_string(edge_color) \
                and cb.iterable(edge_color) \
                and len(edge_color) == len(edge_pos):
            if numpy.alltrue([cb.is_scalar_or_string(c) for c in edge_color]):
                # (should check ALL elements)
                # list of color letters such as ['k','r','k',...]
                edge_colors = tuple(
                    [colorConverter.to_rgba(c, alpha) for c in edge_color])
            elif numpy.alltrue(
                [not cb.is_scalar_or_string(c) for c in edge_color]):
                # If color specs are given as (rgb) or (rgba) tuples, we're OK
                if numpy.alltrue(
                    [cb.iterable(c) and len(c) in (3, 4) for c in edge_color]):
                    edge_colors = tuple(edge_color)
                else:
                    # numbers (which are going to be mapped with a colormap)
                    edge_colors = None
            else:
                raise ValueError(
                    'edge_color must consist of either color names or numbers')
        else:
            if cb.is_scalar_or_string(edge_color) or len(edge_color) == 1:
                edge_colors = (colorConverter.to_rgba(edge_color, alpha), )
            else:
                raise ValueError(
                    'edge_color must be a single color or list of exactly m colors where m is the number or edges'
                )
        '''
        modEdgeColors = list(edge_colors)
        modEdgeColors = tuple(modEdgeColors + [colorConverter.to_rgba('w', alpha)
                                     for c in edge_color])
        #print(modEdgeColors)
        edge_collection = LineCollection(np.asarray(list(edge_pos)*2),
                                         colors=modEdgeColors,
                                         linewidths=[6]*len(list(edge_colors))+[4]*len(list(edge_colors)),
                                         antialiaseds=(1,),
                                         linestyle=style,
                                         transOffset=ax.transData,
                                         )
        '''
        edge_collection = LineCollection(
            edge_pos,
            colors=edge_colors,
            linewidths=6,
            antialiaseds=(1, ),
            linestyle=style,
            transOffset=ax.transData,
        )

        edge_collection.set_zorder(1)  # edges go behind nodes
        edge_collection.set_label(label)
        ax.add_collection(edge_collection)

        tube_collection = LineCollection(
            edge_pos,
            colors=tuple([
                colorConverter.to_rgba('lightgrey', alpha) for c in edge_color
            ]),
            linewidths=4,
            antialiaseds=(1, ),
            linestyle=style,
            transOffset=ax.transData,
        )

        tube_collection.set_zorder(1)  # edges go behind nodes
        tube_collection.set_label(label)
        ax.add_collection(tube_collection)
        # Note: there was a bug in mpl regarding the handling of alpha values for
        # each line in a LineCollection.  It was fixed in matplotlib in r7184 and
        # r7189 (June 6 2009).  We should then not set the alpha value globally,
        # since the user can instead provide per-edge alphas now.  Only set it
        # globally if provided as a scalar.
        if cb.is_numlike(alpha):
            edge_collection.set_alpha(alpha)

        if edge_colors is None:
            if edge_cmap is not None:
                assert (isinstance(edge_cmap, Colormap))
            edge_collection.set_array(numpy.asarray(edge_color))
            edge_collection.set_cmap(edge_cmap)
            if edge_vmin is not None or edge_vmax is not None:
                edge_collection.set_clim(edge_vmin, edge_vmax)
            else:
                edge_collection.autoscale()

        box_collection = Utilities.get_boxes(edge_colors=edge_colors,
                                             edge_pos=box_pos)
        box_collection.set_zorder(1)  # edges go behind nodes
        box_collection.set_label(label)
        ax.add_collection(box_collection)

        arrow_collection = Utilities.get_arrows_on_edges(
            edge_colors=edge_colors, edge_pos=box_pos)
        arrow_collection.set_zorder(0)

        if arrows:
            # Visualize them only if wanted
            ax.add_collection(arrow_collection)

        return edge_collection, box_collection, tube_collection, arrow_collection
Ejemplo n.º 25
0
def draw_networkx_edges(G, pos,
                        edgelist=None,
                        width=1.0,
                        edge_color='k',
                        style='solid',
                        alpha=1.0,
                        edge_cmap=None,
                        edge_vmin=None,
                        edge_vmax=None,
                        ax=None,
                        arrows=True,
                        label=None,
                        **kwds):
    """Draw the edges of the graph G.

    This draws only the edges of the graph G.

    Parameters
    ----------
    G : graph
       A networkx graph

    pos : dictionary
       A dictionary with nodes as keys and positions as values.
       Positions should be sequences of length 2.

    edgelist : collection of edge tuples
       Draw only specified edges(default=G.edges())

    width : float, or array of floats
       Line width of edges (default=1.0)

    edge_color : color string, or array of floats
       Edge color. Can be a single color format string (default='r'),
       or a sequence of colors with the same length as edgelist.
       If numeric values are specified they will be mapped to
       colors using the edge_cmap and edge_vmin,edge_vmax parameters.

    style : string
       Edge line style (default='solid') (solid|dashed|dotted,dashdot)

    alpha : float
       The edge transparency (default=1.0)

    edge_ cmap : Matplotlib colormap
       Colormap for mapping intensities of edges (default=None)

    edge_vmin,edge_vmax : floats
       Minimum and maximum for edge colormap scaling (default=None)

    ax : Matplotlib Axes object, optional
       Draw the graph in the specified Matplotlib axes.

    arrows : bool, optional (default=True)
       For directed graphs, if True draw arrowheads.

    label : [None| string]
       Label for legend

    Returns
    -------
    matplotlib.collection.LineCollection
        `LineCollection` of the edges

    Notes
    -----
    For directed graphs, "arrows" (actually just thicker stubs) are drawn
    at the head end.  Arrows can be turned off with keyword arrows=False.
    Yes, it is ugly but drawing proper arrows with Matplotlib this
    way is tricky.

    Examples
    --------
    >>> G = nx.dodecahedral_graph()
    >>> edges = nx.draw_networkx_edges(G, pos=nx.spring_layout(G))

    Also see the NetworkX drawing examples at
    https://networkx.github.io/documentation/latest/auto_examples/index.html

    See Also
    --------
    draw()
    draw_networkx()
    draw_networkx_nodes()
    draw_networkx_labels()
    draw_networkx_edge_labels()
    """
    try:
        import matplotlib
        import matplotlib.pyplot as plt
        import matplotlib.cbook as cb
        from matplotlib.colors import colorConverter, Colormap
        from matplotlib.collections import LineCollection
        import numpy as np
    except ImportError:
        raise ImportError("Matplotlib required for draw()")
    except RuntimeError:
        print("Matplotlib unable to open display")
        raise

    if ax is None:
        ax = plt.gca()

    if edgelist is None:
        edgelist = list(G.edges())

    if not edgelist or len(edgelist) == 0:  # no edges!
        return None

    # set edge positions
    edge_pos = np.asarray([(pos[e[0]], pos[e[1]]) for e in edgelist])

    if not cb.iterable(width):
        lw = (width,)
    else:
        lw = width

    if not cb.is_string_like(edge_color) \
            and cb.iterable(edge_color) \
            and len(edge_color) == len(edge_pos):
        if np.alltrue([cb.is_string_like(c)
                      for c in edge_color]):
            # (should check ALL elements)
            # list of color letters such as ['k','r','k',...]
            edge_colors = tuple([colorConverter.to_rgba(c, alpha)
                                 for c in edge_color])
        elif np.alltrue([not cb.is_string_like(c)
                        for c in edge_color]):
            # If color specs are given as (rgb) or (rgba) tuples, we're OK
            if np.alltrue([cb.iterable(c) and len(c) in (3, 4)
                          for c in edge_color]):
                edge_colors = tuple(edge_color)
            else:
                # numbers (which are going to be mapped with a colormap)
                edge_colors = None
        else:
            raise ValueError('edge_color must consist of either color names or numbers')
    else:
        if cb.is_string_like(edge_color) or len(edge_color) == 1:
            edge_colors = (colorConverter.to_rgba(edge_color, alpha), )
        else:
            raise ValueError(
                'edge_color must be a single color or list of exactly m colors where m is the number or edges')

    edge_collection = LineCollection(edge_pos,
                                     colors=edge_colors,
                                     linewidths=lw,
                                     antialiaseds=(1,),
                                     linestyle=style,
                                     transOffset=ax.transData,
                                     )

    edge_collection.set_zorder(1)  # edges go behind nodes
    edge_collection.set_label(label)
    ax.add_collection(edge_collection)

    # Note: there was a bug in mpl regarding the handling of alpha values for
    # each line in a LineCollection.  It was fixed in matplotlib in r7184 and
    # r7189 (June 6 2009).  We should then not set the alpha value globally,
    # since the user can instead provide per-edge alphas now.  Only set it
    # globally if provided as a scalar.
    if cb.is_numlike(alpha):
        edge_collection.set_alpha(alpha)

    if edge_colors is None:
        if edge_cmap is not None:
            assert(isinstance(edge_cmap, Colormap))
        edge_collection.set_array(np.asarray(edge_color))
        edge_collection.set_cmap(edge_cmap)
        if edge_vmin is not None or edge_vmax is not None:
            edge_collection.set_clim(edge_vmin, edge_vmax)
        else:
            edge_collection.autoscale()

    arrow_collection = None

    if G.is_directed() and arrows:

        # a directed graph hack
        # draw thick line segments at head end of edge
        # waiting for someone else to implement arrows that will work
        arrow_colors = edge_colors
        a_pos = []
        p = 1.0 - 0.25  # make head segment 25 percent of edge length
        for src, dst in edge_pos:
            x1, y1 = src
            x2, y2 = dst
            dx = x2 - x1   # x offset
            dy = y2 - y1   # y offset
            d = np.sqrt(float(dx**2 + dy**2))  # length of edge
            if d == 0:   # source and target at same position
                continue
            if dx == 0:  # vertical edge
                xa = x2
                ya = dy * p + y1
            if dy == 0:  # horizontal edge
                ya = y2
                xa = dx * p + x1
            else:
                theta = np.arctan2(dy, dx)
                xa = p * d * np.cos(theta) + x1
                ya = p * d * np.sin(theta) + y1

            a_pos.append(((xa, ya), (x2, y2)))

        arrow_collection = LineCollection(a_pos,
                                          colors=arrow_colors,
                                          linewidths=[4 * ww for ww in lw],
                                          antialiaseds=(1,),
                                          transOffset=ax.transData,
                                          )

        arrow_collection.set_zorder(1)  # edges go behind nodes
        arrow_collection.set_label(label)
        ax.add_collection(arrow_collection)

    # update view
    minx = np.amin(np.ravel(edge_pos[:, :, 0]))
    maxx = np.amax(np.ravel(edge_pos[:, :, 0]))
    miny = np.amin(np.ravel(edge_pos[:, :, 1]))
    maxy = np.amax(np.ravel(edge_pos[:, :, 1]))

    w = maxx - minx
    h = maxy - miny
    padx,  pady = 0.05 * w, 0.05 * h
    corners = (minx - padx, miny - pady), (maxx + padx, maxy + pady)
    ax.update_datalim(corners)
    ax.autoscale_view()

#    if arrow_collection:

    return edge_collection
Ejemplo n.º 26
0
def plot_tree(tree, figure_name, color_by_trait, initial_branch_width,
              tip_size, start_date, end_date, include_color_bar):
    """Plot a BioPython Phylo tree in the BALTIC-style.
    """
    # Plot H3N2 tree in BALTIC style from Bio.Phylo tree.
    mpl.rcParams['savefig.dpi'] = 120
    mpl.rcParams['figure.dpi'] = 100

    mpl.rcParams['font.weight'] = 300
    mpl.rcParams['axes.labelweight'] = 300
    mpl.rcParams['font.size'] = 14

    yvalues = [node.yvalue for node in tree.find_clades()]
    y_span = max(yvalues)
    y_unit = y_span / float(len(yvalues))

    # Setup colors.
    trait_name = color_by_trait
    traits = [k.attr[trait_name] for k in tree.find_clades()]
    norm = mpl.colors.Normalize(min(traits), max(traits))
    cmap = mpl.cm.viridis

    #
    # Setup the figure grid.
    #

    if include_color_bar:
        fig = plt.figure(figsize=(8, 6), facecolor='w')
        gs = gridspec.GridSpec(2,
                               1,
                               height_ratios=[14, 1],
                               width_ratios=[1],
                               hspace=0.1,
                               wspace=0.1)
        ax = fig.add_subplot(gs[0])
        colorbar_ax = fig.add_subplot(gs[1])
    else:
        fig = plt.figure(figsize=(8, 4), facecolor='w')
        gs = gridspec.GridSpec(1, 1)
        ax = fig.add_subplot(gs[0])

    L = len([k for k in tree.find_clades() if k.is_terminal()])

    # Setup arrays for tip and internal node coordinates.
    tip_circles_x = []
    tip_circles_y = []
    tip_circles_color = []
    tip_circle_sizes = []
    node_circles_x = []
    node_circles_y = []
    node_circles_color = []
    node_line_widths = []
    node_line_segments = []
    node_line_colors = []
    branch_line_segments = []
    branch_line_widths = []
    branch_line_colors = []
    branch_line_labels = []

    for k in tree.find_clades():  ## iterate over objects in tree
        x = k.attr["num_date"]  ## or from x position determined earlier
        y = k.yvalue  ## get y position from .drawTree that was run earlier, but could be anything else

        if k.parent is None:
            xp = None
        else:
            xp = k.parent.attr[
                "num_date"]  ## get x position of current object's parent

        if x == None:  ## matplotlib won't plot Nones, like root
            x = 0.0
        if xp == None:
            xp = x

        c = 'k'
        if trait_name in k.attr:
            c = cmap(norm(k.attr[trait_name]))

        branchWidth = 2
        if k.is_terminal():  ## if leaf...
            s = tip_size  ## tip size can be fixed

            tip_circle_sizes.append(s)
            tip_circles_x.append(x)
            tip_circles_y.append(y)
            tip_circles_color.append(c)
        else:  ## if node...
            k_leaves = [
                child for child in k.find_clades() if child.is_terminal()
            ]

            # Scale branch widths by the number of tips.
            branchWidth += initial_branch_width * len(k_leaves) / float(L)

            if len(k.clades) == 1:
                node_circles_x.append(x)
                node_circles_y.append(y)
                node_circles_color.append(c)

            ax.plot([x, x], [k.clades[-1].yvalue, k.clades[0].yvalue],
                    lw=branchWidth,
                    color=c,
                    ls='-',
                    zorder=9,
                    solid_capstyle='round')

        branch_line_segments.append([(xp, y), (x, y)])
        branch_line_widths.append(branchWidth)
        branch_line_colors.append(c)

    branch_lc = LineCollection(branch_line_segments, zorder=9)
    branch_lc.set_color(branch_line_colors)
    branch_lc.set_linewidth(branch_line_widths)
    branch_lc.set_label(branch_line_labels)
    branch_lc.set_linestyle("-")
    ax.add_collection(branch_lc)

    # Add circles for tips and internal nodes.
    tip_circle_sizes = np.array(tip_circle_sizes)
    ax.scatter(tip_circles_x,
               tip_circles_y,
               s=tip_circle_sizes,
               facecolor=tip_circles_color,
               edgecolor='none',
               zorder=11)  ## plot circle for every tip
    ax.scatter(tip_circles_x,
               tip_circles_y,
               s=tip_circle_sizes * 2,
               facecolor='k',
               edgecolor='none',
               zorder=10)  ## plot black circle underneath
    ax.scatter(
        node_circles_x,
        node_circles_y,
        facecolor=node_circles_color,
        s=50,
        edgecolor='none',
        zorder=10,
        lw=2,
        marker='|'
    )  ## mark every node in the tree to highlight that it's a multitype tree

    #ax.set_ylim(-10, y_span - 300)

    ax.spines['top'].set_visible(False)  ## no axes
    ax.spines['right'].set_visible(False)
    ax.spines['left'].set_visible(False)

    ax.grid(axis='x', ls='-', color='grey')
    ax.tick_params(axis='y', size=0)
    ax.set_yticklabels([])

    if start_date:
        # Always add a buffer to the left edge of the plot so data up to the
        # given end date can be clearly seen.
        ax.set_xlim(left=timestamp_to_float(pd.to_datetime(start_date)) - 2.0)

    if end_date:
        # Always add a buffer of 3 months to the right edge of the plot so data
        # up to the given end date can be clearly seen.
        ax.set_xlim(right=timestamp_to_float(pd.to_datetime(end_date)) + 0.25)

    if include_color_bar:
        cb1 = mpl.colorbar.ColorbarBase(colorbar_ax,
                                        cmap=cmap,
                                        norm=norm,
                                        orientation='horizontal')
        cb1.set_label(color_by_trait)

    gs.tight_layout(fig)
    plt.savefig(figure_name)
Ejemplo n.º 27
0
def draw_networkx_edges(G, pos,
                        edgelist=None,
                        width=1.0,
                        edge_color='k',
                        style='solid',
                        alpha=1.0,
                        arrowstyle='-|>',
                        arrowsize=10,
                        edge_cmap=None,
                        edge_vmin=None,
                        edge_vmax=None,
                        ax=None,
                        arrows=True,
                        label=None,
                        node_size=300,
                        nodelist=None,
                        node_shape="o",
                        connectionstyle=None,
                        **kwds):
    """Draw the edges of the graph G.

    This draws only the edges of the graph G.

    Parameters
    ----------
    G : graph
       A networkx graph

    pos : dictionary
       A dictionary with nodes as keys and positions as values.
       Positions should be sequences of length 2.

    edgelist : collection of edge tuples
       Draw only specified edges(default=G.edges())

    width : float, or array of floats
       Line width of edges (default=1.0)

    edge_color : color string, or array of floats
       Edge color. Can be a single color format string (default='r'),
       or a sequence of colors with the same length as edgelist.
       If numeric values are specified they will be mapped to
       colors using the edge_cmap and edge_vmin,edge_vmax parameters.

    style : string
       Edge line style (default='solid') (solid|dashed|dotted,dashdot)

    alpha : float
       The edge transparency (default=1.0)

    edge_ cmap : Matplotlib colormap
       Colormap for mapping intensities of edges (default=None)

    edge_vmin,edge_vmax : floats
       Minimum and maximum for edge colormap scaling (default=None)

    ax : Matplotlib Axes object, optional
       Draw the graph in the specified Matplotlib axes.

    arrows : bool, optional (default=True)
       For directed graphs, if True draw arrowheads.
       Note: Arrows will be the same color as edges.

    arrowstyle : str, optional (default='-|>')
       For directed graphs, choose the style of the arrow heads.
       See :py:class: `matplotlib.patches.ArrowStyle` for more
       options.

    arrowsize : int, optional (default=10)
       For directed graphs, choose the size of the arrow head head's length and
       width. See :py:class: `matplotlib.patches.FancyArrowPatch` for attribute
       `mutation_scale` for more info.

    connectionstyle : str, optional (default=None)
       Pass the connectionstyle parameter to create curved arc of rounding
       radius rad. For example, connectionstyle='arc3,rad=0.2'.
       See :py:class: `matplotlib.patches.ConnectionStyle` and
       :py:class: `matplotlib.patches.FancyArrowPatch` for more info.

    label : [None| string]
       Label for legend

    Returns
    -------
    matplotlib.collection.LineCollection
        `LineCollection` of the edges

    list of matplotlib.patches.FancyArrowPatch
        `FancyArrowPatch` instances of the directed edges

    Depending whether the drawing includes arrows or not.

    Notes
    -----
    For directed graphs, arrows are drawn at the head end.  Arrows can be
    turned off with keyword arrows=False. Be sure to include `node_size` as a
    keyword argument; arrows are drawn considering the size of nodes.

    Examples
    --------
    >>> G = nx.dodecahedral_graph()
    >>> edges = nx.draw_networkx_edges(G, pos=nx.spring_layout(G))

    >>> G = nx.DiGraph()
    >>> G.add_edges_from([(1, 2), (1, 3), (2, 3)])
    >>> arcs = nx.draw_networkx_edges(G, pos=nx.spring_layout(G))
    >>> alphas = [0.3, 0.4, 0.5]
    >>> for i, arc in enumerate(arcs):  # change alpha values of arcs
    ...     arc.set_alpha(alphas[i])

    Also see the NetworkX drawing examples at
    https://networkx.github.io/documentation/latest/auto_examples/index.html

    See Also
    --------
    draw()
    draw_networkx()
    draw_networkx_nodes()
    draw_networkx_labels()
    draw_networkx_edge_labels()
    """
    try:
        import matplotlib
        import matplotlib.pyplot as plt
        import matplotlib.cbook as cb
        from matplotlib.colors import colorConverter, Colormap, Normalize
        from matplotlib.collections import LineCollection
        from matplotlib.patches import FancyArrowPatch
        import numpy as np
    except ImportError:
        raise ImportError("Matplotlib required for draw()")
    except RuntimeError:
        print("Matplotlib unable to open display")
        raise

    if ax is None:
        ax = plt.gca()

    if edgelist is None:
        edgelist = list(G.edges())

    if not edgelist or len(edgelist) == 0:  # no edges!
        return None

    if nodelist is None:
        nodelist = list(G.nodes())

    # set edge positions
    edge_pos = np.asarray([(pos[e[0]], pos[e[1]]) for e in edgelist])

    if not cb.iterable(width):
        lw = (width,)
    else:
        lw = width

    if not is_string_like(edge_color) \
            and cb.iterable(edge_color) \
            and len(edge_color) == len(edge_pos):
        if np.alltrue([is_string_like(c) for c in edge_color]):
            # (should check ALL elements)
            # list of color letters such as ['k','r','k',...]
            edge_colors = tuple([colorConverter.to_rgba(c, alpha)
                                 for c in edge_color])
        elif np.alltrue([not is_string_like(c) for c in edge_color]):
            # If color specs are given as (rgb) or (rgba) tuples, we're OK
            if np.alltrue([cb.iterable(c) and len(c) in (3, 4)
                           for c in edge_color]):
                edge_colors = tuple(edge_color)
            else:
                # numbers (which are going to be mapped with a colormap)
                edge_colors = None
        else:
            raise ValueError('edge_color must contain color names or numbers')
    else:
        if is_string_like(edge_color) or len(edge_color) == 1:
            edge_colors = (colorConverter.to_rgba(edge_color, alpha), )
        else:
            msg = 'edge_color must be a color or list of one color per edge'
            raise ValueError(msg)

    if (not G.is_directed() or not arrows):
        edge_collection = LineCollection(edge_pos,
                                         colors=edge_colors,
                                         linewidths=lw,
                                         antialiaseds=(1,),
                                         linestyle=style,
                                         transOffset=ax.transData,
                                         )

        edge_collection.set_zorder(1)  # edges go behind nodes
        edge_collection.set_label(label)
        ax.add_collection(edge_collection)

        # Note: there was a bug in mpl regarding the handling of alpha values
        # for each line in a LineCollection. It was fixed in matplotlib by
        # r7184 and r7189 (June 6 2009). We should then not set the alpha
        # value globally, since the user can instead provide per-edge alphas
        # now.  Only set it globally if provided as a scalar.
        if isinstance(alpha, Number):
            edge_collection.set_alpha(alpha)

        if edge_colors is None:
            if edge_cmap is not None:
                assert(isinstance(edge_cmap, Colormap))
            edge_collection.set_array(np.asarray(edge_color))
            edge_collection.set_cmap(edge_cmap)
            if edge_vmin is not None or edge_vmax is not None:
                edge_collection.set_clim(edge_vmin, edge_vmax)
            else:
                edge_collection.autoscale()
        return edge_collection

    arrow_collection = None

    if G.is_directed() and arrows:
        # Note: Waiting for someone to implement arrow to intersection with
        # marker.  Meanwhile, this works well for polygons with more than 4
        # sides and circle.

        def to_marker_edge(marker_size, marker):
            if marker in "s^>v<d":  # `large` markers need extra space
                return np.sqrt(2 * marker_size) / 2
            else:
                return np.sqrt(marker_size) / 2

        # Draw arrows with `matplotlib.patches.FancyarrowPatch`
        arrow_collection = []
        mutation_scale = arrowsize  # scale factor of arrow head
        arrow_colors = edge_colors
        if arrow_colors is None:
            if edge_cmap is not None:
                assert(isinstance(edge_cmap, Colormap))
            else:
                edge_cmap = plt.get_cmap()  # default matplotlib colormap
            if edge_vmin is None:
                edge_vmin = min(edge_color)
            if edge_vmax is None:
                edge_vmax = max(edge_color)
            color_normal = Normalize(vmin=edge_vmin, vmax=edge_vmax)

        for i, (src, dst) in enumerate(edge_pos):
            x1, y1 = src
            x2, y2 = dst
            arrow_color = None
            line_width = None
            shrink_source = 0  # space from source to tail
            shrink_target = 0  # space from  head to target
            if cb.iterable(node_size):  # many node sizes
                src_node, dst_node = edgelist[i][:2]
                index_node = nodelist.index(dst_node)
                marker_size = node_size[index_node]
                shrink_target = to_marker_edge(marker_size, node_shape)
            else:
                shrink_target = to_marker_edge(node_size, node_shape)
            if arrow_colors is None:
                arrow_color = edge_cmap(color_normal(edge_color[i]))
            elif len(arrow_colors) > 1:
                arrow_color = arrow_colors[i]
            else:
                arrow_color = arrow_colors[0]
            if len(lw) > 1:
                line_width = lw[i]
            else:
                line_width = lw[0]
            arrow = FancyArrowPatch((x1, y1), (x2, y2),
                                    arrowstyle=arrowstyle,
                                    shrinkA=shrink_source,
                                    shrinkB=shrink_target,
                                    mutation_scale=mutation_scale,
                                    color=arrow_color,
                                    linewidth=line_width,
                                    connectionstyle=connectionstyle,
                                    zorder=1)  # arrows go behind nodes

            # There seems to be a bug in matplotlib to make collections of
            # FancyArrowPatch instances. Until fixed, the patches are added
            # individually to the axes instance.
            arrow_collection.append(arrow)
            ax.add_patch(arrow)

    # update view
    minx = np.amin(np.ravel(edge_pos[:, :, 0]))
    maxx = np.amax(np.ravel(edge_pos[:, :, 0]))
    miny = np.amin(np.ravel(edge_pos[:, :, 1]))
    maxy = np.amax(np.ravel(edge_pos[:, :, 1]))

    w = maxx - minx
    h = maxy - miny
    padx,  pady = 0.05 * w, 0.05 * h
    corners = (minx - padx, miny - pady), (maxx + padx, maxy + pady)
    ax.update_datalim(corners)
    ax.autoscale_view()

    plt.tick_params(
        axis='both',
        which='both',
        bottom=False,
        left=False,
        labelbottom=False,
        labelleft=False)

    return arrow_collection
Ejemplo n.º 28
0
def draw_networkx_edges(G, pos,
                        edgelist=None,
                        width=1.0,
                        edge_color='k',
                        style='solid',
                        alpha=None,
                        arrowstyle='-|>',
                        arrowsize=10,
                        edge_cmap=None,
                        edge_vmin=None,
                        edge_vmax=None,
                        ax=None,
                        arrows=True,
                        label=None,
                        node_size=300,
                        nodelist=None,
                        node_shape="o",
                        connectionstyle=None,
                        **kwds):
    """Draw the edges of the graph G.

    This draws only the edges of the graph G.

    Parameters
    ----------
    G : graph
       A networkx graph

    pos : dictionary
       A dictionary with nodes as keys and positions as values.
       Positions should be sequences of length 2.

    edgelist : collection of edge tuples
       Draw only specified edges(default=G.edges())

    width : float, or array of floats
       Line width of edges (default=1.0)

    edge_color : color or array of colors (default='k')
       Edge color. Can be a single color or a sequence of colors with the same
       length as edgelist. Color can be string, or rgb (or rgba) tuple of
       floats from 0-1. If numeric values are specified they will be
       mapped to colors using the edge_cmap and edge_vmin,edge_vmax parameters.

    style : string
       Edge line style (default='solid') (solid|dashed|dotted,dashdot)

    alpha : float
       The edge transparency (default=None)

    edge_ cmap : Matplotlib colormap
       Colormap for mapping intensities of edges (default=None)

    edge_vmin,edge_vmax : floats
       Minimum and maximum for edge colormap scaling (default=None)

    ax : Matplotlib Axes object, optional
       Draw the graph in the specified Matplotlib axes.

    arrows : bool, optional (default=True)
       For directed graphs, if True draw arrowheads.
       Note: Arrows will be the same color as edges.

    arrowstyle : str, optional (default='-|>')
       For directed graphs, choose the style of the arrow heads.
       See :py:class: `matplotlib.patches.ArrowStyle` for more
       options.

    arrowsize : int, optional (default=10)
       For directed graphs, choose the size of the arrow head head's length and
       width. See :py:class: `matplotlib.patches.FancyArrowPatch` for attribute
       `mutation_scale` for more info.

    connectionstyle : str, optional (default=None)
       Pass the connectionstyle parameter to create curved arc of rounding
       radius rad. For example, connectionstyle='arc3,rad=0.2'.
       See :py:class: `matplotlib.patches.ConnectionStyle` and
       :py:class: `matplotlib.patches.FancyArrowPatch` for more info.

    label : [None| string]
       Label for legend

    Returns
    -------
    matplotlib.collection.LineCollection
        `LineCollection` of the edges

    list of matplotlib.patches.FancyArrowPatch
        `FancyArrowPatch` instances of the directed edges

    Depending whether the drawing includes arrows or not.

    Notes
    -----
    For directed graphs, arrows are drawn at the head end.  Arrows can be
    turned off with keyword arrows=False. Be sure to include `node_size` as a
    keyword argument; arrows are drawn considering the size of nodes.

    Examples
    --------
    >>> G = nx.dodecahedral_graph()
    >>> edges = nx.draw_networkx_edges(G, pos=nx.spring_layout(G))

    >>> G = nx.DiGraph()
    >>> G.add_edges_from([(1, 2), (1, 3), (2, 3)])
    >>> arcs = nx.draw_networkx_edges(G, pos=nx.spring_layout(G))
    >>> alphas = [0.3, 0.4, 0.5]
    >>> for i, arc in enumerate(arcs):  # change alpha values of arcs
    ...     arc.set_alpha(alphas[i])

    Also see the NetworkX drawing examples at
    https://networkx.github.io/documentation/latest/auto_examples/index.html

    See Also
    --------
    draw()
    draw_networkx()
    draw_networkx_nodes()
    draw_networkx_labels()
    draw_networkx_edge_labels()
    """
    try:
        import matplotlib
        import matplotlib.pyplot as plt
        import matplotlib.cbook as cb
        from matplotlib.colors import colorConverter, Colormap, Normalize
        from matplotlib.collections import LineCollection
        from matplotlib.patches import FancyArrowPatch
        import numpy as np
    except ImportError:
        raise ImportError("Matplotlib required for draw()")
    except RuntimeError:
        print("Matplotlib unable to open display")
        raise

    if ax is None:
        ax = plt.gca()

    if edgelist is None:
        edgelist = list(G.edges())

    if not edgelist or len(edgelist) == 0:  # no edges!
        return None

    if nodelist is None:
        nodelist = list(G.nodes())

    # FancyArrowPatch handles color=None different from LineCollection
    if edge_color is None:
        edge_color = 'k'

    # set edge positions
    edge_pos = np.asarray([(pos[e[0]], pos[e[1]]) for e in edgelist])

    # Check if edge_color is an array of floats and map to edge_cmap.
    # This is the only case handled differently from matplotlib
    if cb.iterable(edge_color) and (len(edge_color) == len(edge_pos)) \
        and np.alltrue([isinstance(c,Number) for c in edge_color]):
            if edge_cmap is not None:
                assert(isinstance(edge_cmap, Colormap))
            else:
                edge_cmap = plt.get_cmap()
            if edge_vmin is None:
                edge_vmin = min(edge_color)
            if edge_vmax is None:
                edge_vmax = max(edge_color)
            color_normal = Normalize(vmin=edge_vmin, vmax=edge_vmax)
            edge_color = [edge_cmap(color_normal(e)) for e in edge_color]

    if (not G.is_directed() or not arrows):
        edge_collection = LineCollection(edge_pos,
                                         colors=edge_color,
                                         linewidths=width,
                                         antialiaseds=(1,),
                                         linestyle=style,
                                         transOffset=ax.transData,
                                         alpha=alpha
                                         )

        edge_collection.set_zorder(1)  # edges go behind nodes
        edge_collection.set_label(label)
        ax.add_collection(edge_collection)

        return edge_collection

    arrow_collection = None

    if G.is_directed() and arrows:
        # Note: Waiting for someone to implement arrow to intersection with
        # marker.  Meanwhile, this works well for polygons with more than 4
        # sides and circle.

        def to_marker_edge(marker_size, marker):
            if marker in "s^>v<d":  # `large` markers need extra space
                return np.sqrt(2 * marker_size) / 2
            else:
                return np.sqrt(marker_size) / 2

        # Draw arrows with `matplotlib.patches.FancyarrowPatch`
        arrow_collection = []
        mutation_scale = arrowsize  # scale factor of arrow head

        # FancyArrowPatch doesn't handle color strings
        arrow_colors = colorConverter.to_rgba_array(edge_color,alpha)
        for i, (src, dst) in enumerate(edge_pos):
            x1, y1 = src
            x2, y2 = dst
            shrink_source = 0  # space from source to tail
            shrink_target = 0  # space from  head to target
            if cb.iterable(node_size):  # many node sizes
                src_node, dst_node = edgelist[i][:2]
                index_node = nodelist.index(dst_node)
                marker_size = node_size[index_node]
                shrink_target = to_marker_edge(marker_size, node_shape)
            else:
                shrink_target = to_marker_edge(node_size, node_shape)

            if cb.iterable(arrow_colors):
                if len(arrow_colors) == len(edge_pos):
                    arrow_color = arrow_colors[i]
                elif len(arrow_colors)==1:
                    arrow_color = arrow_colors[0]
                else: # Cycle through colors
                    arrow_color =  arrow_colors[i%len(arrow_colors)]
            else:
                arrow_color = edge_color

            if cb.iterable(width):
                if len(width) == len(edge_pos):
                    line_width = width[i]
                else:
                    line_width = width[i%len(width)]
            else:
                line_width = width

            arrow = FancyArrowPatch((x1, y1), (x2, y2),
                                    arrowstyle=arrowstyle,
                                    shrinkA=shrink_source,
                                    shrinkB=shrink_target,
                                    mutation_scale=mutation_scale,
                                    color=arrow_color,
                                    linewidth=line_width,
                                    connectionstyle=connectionstyle,
                                    zorder=1)  # arrows go behind nodes

            # There seems to be a bug in matplotlib to make collections of
            # FancyArrowPatch instances. Until fixed, the patches are added
            # individually to the axes instance.
            arrow_collection.append(arrow)
            ax.add_patch(arrow)

    # update view
    minx = np.amin(np.ravel(edge_pos[:, :, 0]))
    maxx = np.amax(np.ravel(edge_pos[:, :, 0]))
    miny = np.amin(np.ravel(edge_pos[:, :, 1]))
    maxy = np.amax(np.ravel(edge_pos[:, :, 1]))

    w = maxx - minx
    h = maxy - miny
    padx,  pady = 0.05 * w, 0.05 * h
    corners = (minx - padx, miny - pady), (maxx + padx, maxy + pady)
    ax.update_datalim(corners)
    ax.autoscale_view()

    plt.tick_params(
        axis='both',
        which='both',
        bottom=False,
        left=False,
        labelbottom=False,
        labelleft=False)

    return arrow_collection