Example #1
0
    def plot_field(self, field):
        """ Map the given field.

        Parameters:
        -----------
        field : 1D array TOCHECK
            Field to plot.

        """

        if self.mask is not None:
            field = np.ma.masked_where(field <= self.mask, field)

        # Update array values if the plot has already been initialised
        if self.tripcolor_plot:
            field = field[self.masked_tris].mean(axis=1)
            self.tripcolor_plot.set_array(field)
            return

        # Create tripcolor plot
        x, y = self.m(self.lon, self.lat)
        self.tri = Triangulation(x, y, self.triangles)
        self.masked_tris = self.tri.get_masked_triangles()
        field = field[self.masked_tris].mean(axis=1)
        self.tripcolor_plot = self.axes.tripcolor(self.tri,
                                                  field,
                                                  vmin=self.vmin,
                                                  vmax=self.vmax,
                                                  cmap=self.cmap,
                                                  edgecolors=self.edgecolors,
                                                  zorder=1,
                                                  norm=self.norm)

        # Overlay the grid
        # self.axes.triplot(self.tri, zorder=2)

        # Overlay stations in the first instance
        if self.stations is not None:
            mx, my = self.m(self.stations[0, :], self.stations[1, :])
            self.axes.scatter(mx,
                              my,
                              marker='*',
                              c='k',
                              s=self.s_stations,
                              edgecolors='none',
                              zorder=4)

        # Add colorbar scaled to axis width
        divider = make_axes_locatable(self.axes)
        cax = divider.append_axes("right", size="5%", pad=0.05)
        self.cbar = self.figure.colorbar(self.tripcolor_plot,
                                         cax=cax,
                                         extend=self.extend)
        self.cbar.ax.tick_params(labelsize=self.fs)
        if self.cb_label:
            self.cbar.set_label(self.cb_label)

        return
Example #2
0
    def _contour_args(self, args, kwargs):
        if self.filled:
            fn = 'contourf'
        else:
            fn = 'contour'
        tri, args, kwargs = Triangulation.get_from_args_and_kwargs(
            *args, **kwargs)
        z = np.asarray(args[0])

        #identified potential area of code to fix add type check of nans and raise warning here maybe to fix
        if z.shape != tri.x.shape:
            raise ValueError('z array must have same length as triangulation x'
                             ' and y arrays')

        #attempt solution 1 presented by ianthomas23 in issue
        if len(z[np.isnan(z[:, :])]) != 0:
            raise ValueError('z array must have contain no nan values')

        if len(z[np.isinf(z[:, :])]) != 0:
            raise ValueError('z array must have contain no inf values')

        self.zmax = z.max()
        self.zmin = z.min()
        if self.logscale and self.zmin <= 0:
            raise ValueError('Cannot %s log of negative values.' % fn)
        self._contour_level_args(z, args[1:])
        return (tri, z)
Example #3
0
    def _contour_args(self, args, kwargs):
        if self.filled:
            fn = 'contourf'
        else:
            fn = 'contour'
        tri, args, kwargs = Triangulation.get_from_args_and_kwargs(
            *args, **kwargs)
        z = np.ma.asarray(args[0])
        if z.shape != tri.x.shape:
            raise ValueError('z array must have same length as triangulation x'
                             ' and y arrays')

        # z values must be finite, only need to check points that are included
        # in the triangulation.
        z_check = z[np.unique(tri.get_masked_triangles())]
        if np.ma.is_masked(z_check):
            raise ValueError('z must not contain masked points within the '
                             'triangulation')
        if not np.isfinite(z_check).all():
            raise ValueError('z array must not contain non-finite values '
                             'within the triangulation')

        z = np.ma.masked_invalid(z, copy=False)
        self.zmax = float(z_check.max())
        self.zmin = float(z_check.min())
        if self.logscale and self.zmin <= 0:
            raise ValueError('Cannot %s log of negative values.' % fn)
        self._contour_level_args(z, args[1:])
        return (tri, z)
Example #4
0
    def plot_trisurf(self, *args, **kwargs):
        '''
        plot_trisurf(x, y, z,  **wrargs)
        plot_trisurf(x, y, z,  triangles = triangle,,,)
        plot_trisurf(tri, z,  **kwargs, cz = cz, cdata = cdata)


        '''
        from art3d_gl import poly_collection_3d_to_gl
        from matplotlib.tri.triangulation import Triangulation

        cz = kwargs.pop('cz', False)
        cdata = kwargs.pop('cdata', None)
        expanddata = kwargs.pop('expanddata', False)
        
        tri, args, kwargs = Triangulation.get_from_args_and_kwargs(*args, **kwargs)
        if 'Z' in kwargs:
            z = np.asarray(kwargs.pop('Z'))
        else:
            z = np.asarray(args[0])
            # We do this so Z doesn't get passed as an arg to PolyCollection
            args = args[1:]

        triangles = tri.get_masked_triangles()
        X3D = tri.x
        Y3D = tri.y
        Z3D = z
        idxset = tri.get_masked_triangles()

        if expanddata:
            verts = np.dstack((X3D[idxset], 
                           Y3D[idxset],
                           Z3D[idxset]))
            if cz:
                if cdata is not None:
                    cdata = cdata[idxset]
                else:
                    cdata = Z3D[idxset]
                shade = kwargs.pop('shade', 'linear')
                if shade != 'linear':
                    cdata = np.mean(cdata, -1)
                kwargs['facecolordata'] = np.real(cdata)
                kwargs.pop('facecolor', None) # get rid of this keyword
            kwargs['cz'] = cz
            o =  self.plot_solid(verts, **kwargs)
            o._idxset = (None, None, idxset)   # this is used for phasor
        else:
            verts = np.vstack((X3D, Y3D, Z3D)).transpose()
            if cz:
                if cdata is not None:
                    cdata = cdata
                else:
                    cdata = Z3D
                kwargs['facecolordata'] = np.real(cdata)
                kwargs.pop('facecolor', None) # get rid of this keyword
            kwargs['cz'] = cz
            o =  self.plot_solid(verts, idxset, **kwargs)
            o._idxset = (None, None, None)   # this is used for phasor            
        return o
Example #5
0
    def plot_trisurf(self, *args, **kwargs):
        '''
        plot_trisurf(x, y, z,  **wrargs)
        plot_trisurf(x, y, z,  triangles = triangle,,,)
        plot_trisurf(tri, z,  **kwargs, cz = cz, cdata = cdata)


        '''
        from art3d_gl import poly_collection_3d_to_gl
        from matplotlib.tri.triangulation import Triangulation

        cz = kwargs.pop('cz', False)
        cdata = kwargs.pop('cdata', None)
        expanddata = kwargs.pop('expanddata', False)

        tri, args, kwargs = Triangulation.get_from_args_and_kwargs(
            *args, **kwargs)
        if 'Z' in kwargs:
            z = np.asarray(kwargs.pop('Z'))
        else:
            z = np.asarray(args[0])
            # We do this so Z doesn't get passed as an arg to PolyCollection
            args = args[1:]

        triangles = tri.get_masked_triangles()
        X3D = tri.x
        Y3D = tri.y
        Z3D = z
        idxset = tri.get_masked_triangles()

        if expanddata:
            verts = np.dstack((X3D[idxset], Y3D[idxset], Z3D[idxset]))
            if cz:
                if cdata is not None:
                    cdata = cdata[idxset]
                else:
                    cdata = Z3D[idxset]
                shade = kwargs.pop('shade', 'linear')
                if shade != 'linear':
                    cdata = np.mean(cdata, -1)
                kwargs['facecolordata'] = np.real(cdata)
                kwargs.pop('facecolor', None)  # get rid of this keyword
            kwargs['cz'] = cz
            o = self.plot_solid(verts, **kwargs)
            o._idxset = (None, None, idxset)  # this is used for phasor
        else:
            verts = np.vstack((X3D, Y3D, Z3D)).transpose()
            if cz:
                if cdata is not None:
                    cdata = cdata
                else:
                    cdata = Z3D
                kwargs['facecolordata'] = np.real(cdata)
                kwargs.pop('facecolor', None)  # get rid of this keyword
            kwargs['cz'] = cz
            o = self.plot_solid(verts, idxset, **kwargs)
            o._idxset = (None, None, None)  # this is used for phasor
        return o
Example #6
0
def generate_mesh(nodes):
    from  matplotlib.tri.triangulation import Triangulation
    from numpy import array
    x = []; y = []
    for nid in sorted(nodes.keys()):
        x_, y_ = nodes[nid]
        x.append(x_)
        y.append(y_)
    t = Triangulation(x, y)
    return array(x), array(y), t.triangles
Example #7
0
def meshDelaunay(settings, heights):
    '''
    Convert coordinates to mesh using Delaunay triangulation. Also returns
    colormap for writing the mesh in IDTF format, surface triangles from
    triangulation (as opposed to tetrahedra), and the top surface area of
    the mesh.
    '''
    # Get coordinates of all height points (omitting zeros)
    coordinates = np.where(heights != 0)
    x_3D = coordinates[0]
    y_3D = coordinates[1]

    # Generate 3D mesh from heights using meshgrid and griddata
    dx = (max(x_3D) - min(x_3D)) / settings['grid_size']
    dy = (max(y_3D) - min(y_3D)) / settings['grid_size']

    x_grid = np.linspace(min(x_3D), max(x_3D), max(dx, dy))
    y_grid = np.linspace(min(y_3D), max(y_3D), max(dx, dy))

    X, Y = np.meshgrid(x_grid, y_grid)
    z = np.array(
        [heights[x_3D[i], y_3D[i]] for i in range(len(coordinates[0]))])
    Z = griddata((x_3D, y_3D), z, (X, Y))

    # Convert NaNs to zeros and find non-zero coordinates
    Z[np.isnan(Z)] = 0
    nonZero = np.where(Z > 0)  # Indices of non-zero points
    # Subset X,Y, and Z to contain only non-zero points
    Z_nz = Z[nonZero[0], nonZero[1]]
    X_nz = np.array([X[0][xi] for xi in nonZero[0]])
    Y_nz = np.array([Y[:, 0][yi] for yi in nonZero[1]])

    xyz_points = np.column_stack((X_nz, Y_nz, Z_nz))
    triangulation = Delaunay(xyz_points)

    # Get surface triangles
    triang, args, kwargs = Triangulation.get_from_args_and_kwargs(
        X_nz, Y_nz, Z_nz, triangles=triangulation.simplices)
    triangles = triang.get_masked_triangles(
    )  # From matplotlib.tri.triangulation

    # Get color values for mesh triangle faces
    fig = plt.figure()
    ax = fig.add_subplot(111, projection='3d')
    surf = ax.plot_trisurf(X_nz,
                           Y_nz,
                           Z_nz,
                           triangles=triangles,
                           cmap=plt.cm.viridis)
    m = plt.cm.ScalarMappable(cmap=surf.cmap, norm=surf.norm)
    colors = m.to_rgba(Z_nz)

    return z, triangulation, triangles, colors
Example #8
0
 def _contour_args(self, args, kwargs):
     if self.filled: fn = 'contourf'
     else: fn = 'contour'
     tri, args, kwargs = \
         Triangulation.get_from_args_and_kwargs(*args, **kwargs)
     z = np.asarray(args[0])
     if z.shape != tri.x.shape:
         raise ValueError('z array must have same length as triangulation x'
                          'and y arrays')
     self.zmax = z.max()
     self.zmin = z.min()
     if self.logscale and self.zmin <= 0:
         raise ValueError('Cannot %s log of negative values.' % fn)
     self._contour_level_args(z, args[1:])
     return (tri, z)
Example #9
0
 def _contour_args(self, args, kwargs):
     if self.filled: fn = 'contourf'
     else:           fn = 'contour'
     tri, args, kwargs = \
         Triangulation.get_from_args_and_kwargs(*args, **kwargs)
     z = np.asarray(args[0])
     if z.shape != tri.x.shape:
         raise ValueError('z array must have same length as triangulation x'
                          'and y arrays')
     self.zmax = z.max()
     self.zmin = z.min()
     if self.logscale and self.zmin <= 0:
         raise ValueError('Cannot %s log of negative values.' % fn)
     self._contour_level_args(z, args[1:])
     return (tri, z)
Example #10
0
def meshDelaunay(settings,heights):
    '''
    Convert coordinates to mesh using Delaunay triangulation. Also returns
    colormap for writing the mesh in IDTF format, surface triangles from
    triangulation (as opposed to tetrahedra), and the top surface area of
    the mesh.
    '''
    # Get coordinates of all height points (omitting zeros)
    coordinates = np.where(heights != 0)
    x_3D = coordinates[0]
    y_3D = coordinates[1]

    # Generate 3D mesh from heights using meshgrid and griddata
    dx = (max(x_3D) - min(x_3D)) / settings['grid_size']
    dy = (max(y_3D) - min(y_3D)) / settings['grid_size']

    x_grid = np.linspace(min(x_3D),max(x_3D),max(dx,dy))
    y_grid = np.linspace(min(y_3D),max(y_3D),max(dx,dy))

    X,Y = np.meshgrid(x_grid,y_grid)
    z = np.array([heights[x_3D[i],y_3D[i]] for i in range(len(coordinates[0]))])
    Z = griddata((x_3D,y_3D),z,(X,Y))

    # Convert NaNs to zeros and find non-zero coordinates
    Z[np.isnan(Z)] = 0
    nonZero = np.where(Z > 0) # Indices of non-zero points
    # Subset X,Y, and Z to contain only non-zero points
    Z_nz = Z[nonZero[0],nonZero[1]]
    X_nz= np.array([X[0][xi] for xi in nonZero[0]])
    Y_nz = np.array([Y[:,0][yi] for yi in nonZero[1]])

    xyz_points = np.column_stack((X_nz,Y_nz,Z_nz))
    triangulation = Delaunay(xyz_points)

    # Get surface triangles
    triang,args,kwargs = Triangulation.get_from_args_and_kwargs(X_nz,Y_nz,Z_nz,triangles=triangulation.simplices)
    triangles = triang.get_masked_triangles() # From matplotlib.tri.triangulation

    # Get color values for mesh triangle faces
    fig = plt.figure()
    ax = fig.add_subplot(111, projection='3d')
    surf = ax.plot_trisurf(X_nz,Y_nz,Z_nz,triangles=triangles,cmap=plt.cm.viridis)
    m = plt.cm.ScalarMappable(cmap=surf.cmap,norm=surf.norm)
    colors = m.to_rgba(Z_nz)

    return z,triangulation,triangles,colors
Example #11
0
def triplot(ax, *args, **kwargs):
    """
    Draw a unstructured triangular grid as lines and/or markers to
    the :class:`~matplotlib.axes.Axes`.
    The triangulation to plot can be specified in one of two ways;
    either::
      triplot(triangulation, ...)
    where triangulation is a :class:`~matplotlib.tri.Triangulation`
    object, or
    ::
      triplot(x, y, ...)
      triplot(x, y, triangles, ...)
      triplot(x, y, triangles=triangles, ...)
      triplot(x, y, mask, ...)
      triplot(x, y, mask=mask, ...)
      triplot(x, y, triangles, mask, ...)
      triplot(x, y, triangles, mask=mask, ...)
    in which case a Triangulation object will be created.  See
    :class:`~matplotlib.tri.Triangulation` for a explanation of these
    possibilities.
    The remaining args and kwargs are the same as for
    :meth:`~matplotlib.axes.Axes.plot`.
    **Example:**
        .. plot:: mpl_examples/pylab_examples/triplot_demo.py
    """
    tri, args, kwargs = Triangulation.get_from_args_and_kwargs(*args, **kwargs)
    x = tri.x
    y = tri.y
    edges = tri.edges
    marker = kwargs.pop('marker', None)
    kwargs['marker'] = ''
    ax.plot(x[edges].T, y[edges].T, *args, **kwargs)
    if marker is None:
        kwargs.pop('marker')
    else:
        kwargs['marker'] = marker
    kwargs['linestyle'] = ''
    ax.plot(x, y, *args, **kwargs)
Example #12
0
def tripcolor(ax, *args, **kwargs):
    """
    Create a pseudocolor plot of an unstructured triangular grid to
    the :class:`~matplotlib.axes.Axes`.

    The triangulation can be specified in one of two ways; either::

      tripcolor(triangulation, ...)

    where triangulation is a :class:`~matplotlib.tri.Triangulation`
    object, or

    ::

      tripcolor(x, y, ...)
      tripcolor(x, y, triangles, ...)
      tripcolor(x, y, triangles=triangles, ...)
      tripcolor(x, y, mask, ...)
      tripcolor(x, y, mask=mask, ...)
      tripcolor(x, y, triangles, mask, ...)
      tripcolor(x, y, triangles, mask=mask, ...)

    in which case a Triangulation object will be created.  See
    :class:`~matplotlib.tri.Triangulation` for a explanation of these
    possibilities.

    The next argument must be *C*, the array of color values, one per
    point in the triangulation.  The colors used for each triangle
    are from the mean C of the triangle's three points.

    The remaining kwargs are the same as for
    :meth:`~matplotlib.axes.Axes.pcolor`.

    **Example:**

        .. plot:: mpl_examples/pylab_examples/tripcolor_demo.py
    """
    if not ax._hold: ax.cla()

    alpha = kwargs.pop('alpha', 1.0)
    norm = kwargs.pop('norm', None)
    cmap = kwargs.pop('cmap', None)
    vmin = kwargs.pop('vmin', None)
    vmax = kwargs.pop('vmax', None)
    shading = kwargs.pop('shading', 'flat')

    tri, args, kwargs = Triangulation.get_from_args_and_kwargs(*args, **kwargs)
    x = tri.x
    y = tri.y
    triangles = tri.get_masked_triangles()

    # Vertices of triangles.
    verts = np.concatenate(
        (x[triangles][..., np.newaxis], y[triangles][..., np.newaxis]), axis=2)

    C = np.asarray(args[0])
    if C.shape != x.shape:
        raise ValueError('C array must have same length as triangulation x and'
                         ' y arrays')

    # Color values, one per triangle, mean of the 3 vertex color values.
    C = C[triangles].mean(axis=1)

    if shading == 'faceted':
        edgecolors = (0, 0, 0, 1),
        linewidths = (0.25, )
    else:
        edgecolors = 'face'
        linewidths = (1.0, )
    kwargs.setdefault('edgecolors', edgecolors)
    kwargs.setdefault('antialiaseds', (0, ))
    kwargs.setdefault('linewidths', linewidths)

    collection = PolyCollection(verts, **kwargs)

    collection.set_alpha(alpha)
    collection.set_array(C)
    if norm is not None: assert (isinstance(norm, Normalize))
    collection.set_cmap(cmap)
    collection.set_norm(norm)
    if vmin is not None or vmax is not None:
        collection.set_clim(vmin, vmax)
    else:
        collection.autoscale_None()
    ax.grid(False)

    minx = tri.x.min()
    maxx = tri.x.max()
    miny = tri.y.min()
    maxy = tri.y.max()
    corners = (minx, miny), (maxx, maxy)
    ax.update_datalim(corners)
    ax.autoscale_view()
    ax.add_collection(collection)
    return collection
Example #13
0
def triplot(ax, *args, **kwargs):
    """
    Draw a unstructured triangular grid as lines and/or markers to
    the :class:`~matplotlib.axes.Axes`.

    The triangulation to plot can be specified in one of two ways;
    either::

      triplot(triangulation, ...)

    where triangulation is a :class:`~matplotlib.tri.Triangulation`
    object, or

    ::

      triplot(x, y, ...)
      triplot(x, y, triangles, ...)
      triplot(x, y, triangles=triangles, ...)
      triplot(x, y, mask=mask, ...)
      triplot(x, y, triangles, mask=mask, ...)

    in which case a Triangulation object will be created.  See
    :class:`~matplotlib.tri.Triangulation` for a explanation of these
    possibilities.

    The remaining args and kwargs are the same as for
    :meth:`~matplotlib.axes.Axes.plot`.

    **Example:**

        .. plot:: mpl_examples/pylab_examples/triplot_demo.py
    """
    import matplotlib.axes
    tri, args, kwargs = Triangulation.get_from_args_and_kwargs(*args, **kwargs)

    x = tri.x
    y = tri.y
    edges = tri.edges

    # If draw both lines and markers at the same time, e.g.
    #     ax.plot(x[edges].T, y[edges].T, *args, **kwargs)
    # then the markers are drawn more than once which is incorrect if alpha<1.
    # Hence draw lines and markers separately.

    # Decode plot format string, e.g. 'ro-'
    fmt = ''
    if len(args) > 0:
        fmt = args[0]

#   _process_plot_format moves around so I made copy here.
#   not a best solution...;D
#    linestyle, marker, color = matplotlib.axes._process_plot_format(fmt)
    linestyle, marker, color = _process_plot_format(fmt)

    # Draw lines without markers, if lines are required.
    a = []
    if linestyle is not None and linestyle is not 'None':
        kw = kwargs.copy()
        kw.pop('marker', None)     # Ignore marker if set.
        kw['linestyle'] = ls_mapper[linestyle]
        kw['edgecolor'] = color
        kw['facecolor'] = None

        vertices = np.column_stack((x[edges].flatten(), y[edges].flatten()))
        codes = ([Path.MOVETO] + [Path.LINETO])*len(edges)

        path = Path(vertices, codes)
        pathpatch = PathPatch(path, **kw)

        ax.add_patch(pathpatch)
        a.append(pathpatch)

    # Draw markers without lines.
    # Should avoid drawing markers for points that are not in any triangle?
    kwargs['linestyle'] = ''

    # without hiding points explicitly, marker would expose hidden points. 
    idx = np.unique(edges.flatten())
    l = ax.plot(x[idx], y[idx], *args, **kwargs)
    a = l+a
    return a
def tripcolor_costum(
    ax,
    *args,
    alpha=1.0,
    override_cmap_alpha=True,
    norm=None,
    cmap=None,
    vmin=None,
    vmax=None,
    shading="flat",
    facecolors=None,
    **kwargs,
):
    """
    Create a pseudocolor plot of an unstructured triangular grid.

    The triangulation can be specified in one of two ways; either::

      tripcolor(triangulation, ...)

    where triangulation is a :class:`matplotlib.tri.Triangulation`
    object, or

    ::

      tripcolor(x, y, ...)
      tripcolor(x, y, triangles, ...)
      tripcolor(x, y, triangles=triangles, ...)
      tripcolor(x, y, mask=mask, ...)
      tripcolor(x, y, triangles, mask=mask, ...)

    in which case a Triangulation object will be created.  See
    :class:`~matplotlib.tri.Triangulation` for a explanation of these
    possibilities.

    The next argument must be *C*, the array of color values, either
    one per point in the triangulation if color values are defined at
    points, or one per triangle in the triangulation if color values
    are defined at triangles. If there are the same number of points
    and triangles in the triangulation it is assumed that color
    values are defined at points; to force the use of color values at
    triangles use the kwarg ``facecolors=C`` instead of just ``C``.

    *shading* may be 'flat' (the default) or 'gouraud'. If *shading*
    is 'flat' and C values are defined at points, the color values
    used for each triangle are from the mean C of the triangle's
    three points. If *shading* is 'gouraud' then color values must be
    defined at points.

    The remaining kwargs are the same as for
    :meth:`~matplotlib.axes.Axes.pcolor`.
    """
    cbook._check_in_list(["flat", "gouraud"], shading=shading)

    tri, args, kwargs = Triangulation.get_from_args_and_kwargs(*args, **kwargs)

    # C is the colors array defined at either points or faces (i.e. triangles).
    # If facecolors is None, C are defined at points.
    # If facecolors is not None, C are defined at faces.
    if facecolors is not None:
        C = facecolors
    else:
        C = np.asarray(args[0])

    # If there are a different number of points and triangles in the
    # triangulation, can omit facecolors kwarg as it is obvious from
    # length of C whether it refers to points or faces.
    # Do not do this for gouraud shading.
    if (facecolors is None and len(C) == len(tri.triangles)
            and len(C) != len(tri.x) and shading != "gouraud"):
        facecolors = C

    # Check length of C is OK.
    if (facecolors is None
            and len(C) != len(tri.x)) or (facecolors is not None
                                          and len(C) != len(tri.triangles)):
        raise ValueError("Length of color values array must be the same "
                         "as either the number of triangulation points "
                         "or triangles")

    # Handling of linewidths, shading, edgecolors and antialiased as
    # in Axes.pcolor
    linewidths = (0.25, )
    if "linewidth" in kwargs:
        kwargs["linewidths"] = kwargs.pop("linewidth")
    kwargs.setdefault("linewidths", linewidths)

    edgecolors = "none"
    if "edgecolor" in kwargs:
        kwargs["edgecolors"] = kwargs.pop("edgecolor")
    ec = kwargs.setdefault("edgecolors", edgecolors)

    if "antialiased" in kwargs:
        kwargs["antialiaseds"] = kwargs.pop("antialiased")
    if "antialiaseds" not in kwargs and ec.lower() == "none":
        kwargs["antialiaseds"] = False

    if shading == "gouraud":
        if facecolors is not None:
            raise ValueError("Gouraud shading does not support the use "
                             "of facecolors kwarg")
        if len(C) != len(tri.x):
            raise ValueError("For gouraud shading, the length of color "
                             "values array must be the same as the "
                             "number of triangulation points")
        collection = CustomTriMesh(tri, **kwargs)
    else:
        # Vertices of triangles.
        maskedTris = tri.get_masked_triangles()
        verts = np.stack((tri.x[maskedTris], tri.y[maskedTris]), axis=-1)

        # Color values.
        if facecolors is None:
            # One color per triangle, the mean of the 3 vertex color values.
            C = C[maskedTris].mean(axis=1)
        elif tri.mask is not None:
            # Remove color values of masked triangles.
            C = C[~tri.mask]
        collection = CustomPolyCollection(verts, **kwargs)

    collection.set_alpha(alpha)
    collection.set_override_cmap_alpha(override_cmap_alpha)
    collection.set_array(C)
    if norm is not None and not isinstance(norm, Normalize):
        raise ValueError("'norm' must be an instance of 'Normalize'")
    collection.set_cmap(cmap)
    collection.set_norm(norm)
    if vmin is not None or vmax is not None:
        collection.set_clim(vmin, vmax)
    else:
        collection.autoscale_None()
    ax.grid(False)

    minx = tri.x.min()
    maxx = tri.x.max()
    miny = tri.y.min()
    maxy = tri.y.max()
    corners = (minx, miny), (maxx, maxy)
    ax.update_datalim(corners)
    ax.autoscale_view()
    ax.add_collection(collection)
    return ax, collection
Example #15
0
# Read in the grid's dimensions
n_nodes = mediator.get_dimension_variable('node')
n_elems = mediator.get_dimension_variable('element')

# Grid connectivity/adjacency
nv = mediator.get_grid_variable('nv', (3, n_elems), int)

# Cartesian coordinates
x_nodes = mediator.get_grid_variable('x', (n_nodes), float)
y_nodes = mediator.get_grid_variable('y', (n_nodes), float)
x_centroids = mediator.get_grid_variable('xc', (n_elems), float)
y_centroids = mediator.get_grid_variable('yc', (n_elems), float)

triangles = nv.transpose()
tri = Triangulation(x_nodes, y_nodes, triangles)

# Plot
fig = plt.figure()
ax = fig.add_subplot(111)
ax.triplot(tri)

for idx, (xc, yc) in enumerate(zip(x_centroids, y_centroids)):
    ax.scatter(xc, yc)
    ax.annotate('xc_{}'.format(idx), xy=(xc, yc), xytext=(xc, yc))

# Plot
for idx, (x, y) in enumerate(zip(x_nodes, y_nodes)):
    ax.scatter(x, y)
    ax.annotate('xn_{}'.format(idx), xy=(x, y), xytext=(x, y))
    def show_img(self,
                 start_frame,
                 period=None,
                 output=None,
                 cell_rep=1,
                 vmax=None,
                 scalebar=False,
                 boundary=None,
                 offset=5,
                 boundary_offset=5,
                 img_offset=10,
                 cmap="gray",
                 mode='tri',
                 bin_step=1,
                 r=5,
                 bin_rep=7,
                 tri_method='linear',
                 roll_correction=True):

        if start_frame < 0:
            start_frame = len(self.Z_history) - 1

        if period is None:
            period = 100000000

        for num in range(start_frame, len(self.Z_history), period):
            img_name = "rip.{}.png".format(str(int(num / period)).zfill(5))

            print("DISPL NUM::{}".format(num))
            X_, Y_, Z_ = self.leveled_xyz(self.Z_history[num],
                                          cell_rep,
                                          correction=roll_correction)
            flat = [None, None, None]
            flat[0] = X_.flatten()
            flat[1] = Y_.flatten()
            flat[2] = Z_.flatten()
            flat = np.asarray(flat)

            if boundary is None:
                boundary = self.get_img_boundary(X_, Y_, Z_)
                boundary[0][0] += offset
                boundary[1][0] += offset
                boundary[0][1] -= offset
                boundary[1][1] -= offset

            print(boundary)

            if mode == 'scatter3d' or mode == 'scatter':
                #x_flag = np.logical_and(flat_[0] > boundary[0][0], flat_[0] < boundary[0][1])
                #y_flag = np.logical_and(flat_[1] > boundary[1][0], flat_[1] < boundary[1][1])
                #flat = np.array(flat_)
                #flat = flat[:, np.logical_and(x_flag, y_flag)]

                if mode == 'scatter3d':
                    fig = plt.figure()
                    ax = fig.add_subplot(111, projection='3d')

                    ax.scatter(flat[0], flat[1], flat[2])
                    ax.set_xlabel("X axis")
                    ax.set_ylabel("Y axis")
                    plt.show()

                else:
                    plt.scatter(flat[0], flat[1])
                    plt.show()

            elif mode == 'surf':
                r2 = np.power(r, 2)
                bin_centers = [
                    np.arange(boundary[0, 0], boundary[0, 1] + 0.001,
                              bin_step),
                    np.arange(boundary[1, 0], boundary[1, 1] + 0.001, bin_step)
                ]

                bin_edges = np.array([
                    bin_centers[0][:-1] + 0.5 * bin_step,
                    bin_centers[1][:-1] + 0.5 * bin_step
                ])

                indexes = [None, None]
                indexes[0] = np.digitize(flat_[0], bin_edges[0])  # x bins
                indexes[1] = np.digitize(flat_[1], bin_edges[1])  # y bins

                safe_offset = -1000000
                Z_holder = np.ones(
                    (bin_centers[1].shape[0], bin_centers[0].shape[0], 3, 3),
                    dtype=float) * safe_offset

                for i in range(len(flat_[0])):
                    ix = indexes[0][i]
                    iy = indexes[1][i]
                    cr_z = flat_[2][i]
                    if (Z_holder[iy, ix, 0, 2] < cr_z):
                        Z_holder[iy, ix, 2] = Z_holder[iy, ix, 1]
                        Z_holder[iy, ix, 1] = Z_holder[iy, ix, 0]
                        Z_holder[iy, ix, 0] = [flat_[0][i], flat_[1][i], cr_z]

                    elif (Z_holder[iy, ix, 1, 2] < cr_z):
                        Z_holder[iy, ix, 2] = Z_holder[iy, ix, 1]
                        Z_holder[iy, ix, 1] = [flat_[0][i], flat_[1][i], cr_z]

                    elif (Z_holder[iy, ix, 2, 2] < cr_z):
                        Z_holder[iy, ix, 2] = [flat_[0][i], flat_[1][i], cr_z]

                # discard edges
                Z_holder = Z_holder[1:-1, 1:-1, :, :]
                probe_bins = (bin_rep * 2 + 1) * (bin_rep * 2 + 1)
                probe_bins_total = probe_bins * 3
                Z_full_holder = np.empty((Z_holder.shape[0], Z_holder.shape[1],
                                          probe_bins_total, 3))

                bin_rep_arr = list(range(-bin_rep, bin_rep + 1))
                for n_, roll_ in zip(
                        range(probe_bins),
                        itertools.product(bin_rep_arr, bin_rep_arr)):
                    #print(roll_, n_*3, (n_+1)*3)
                    Z_full_holder[:, :, n_ * 3:(n_ + 1) * 3] = np.roll(
                        Z_holder, (roll_[0], roll_[1]), axis=(0, 1))
                Z_full_holder = Z_full_holder[1:-1, 1:-1, :, :]

                bin_centers[0] = bin_centers[0][2:-2]
                bin_centers[1] = bin_centers[1][2:-2]

                probe = np.stack(np.meshgrid(bin_centers[0], bin_centers[1]),
                                 -1)
                probe = np.append(probe,
                                  np.zeros(
                                      (probe.shape[0], probe.shape[1], 1)),
                                  axis=2)
                probe = np.tile(probe, probe_bins_total).reshape(
                    probe.shape[0], probe.shape[1], probe_bins_total, 3)

                probe_diff = Z_full_holder - probe
                probe_height = np.sqrt(r2 -
                                       (np.power(probe_diff[:, :, :, 0], 2) +
                                        np.power(probe_diff[:, :, :, 1], 2)))
                probe_z = Z_full_holder[:, :, :, 2] + probe_height

                probe_z[np.isnan(probe_z)] = safe_offset
                probe_z = np.amax(probe_z, -1)

                probe_z[probe_z <= safe_offset + 1] = 0.0
                probe_z -= np.min(probe_z)
                print("Probe {}".format(np.max(probe_z)))

                if vmax is None:
                    vmax = np.max(probe_z)

                if vmax == "get":
                    return np.max(probe_z)

                # normalize
                probe_z = probe_z / vmax
                probe_z = (0.5 - np.mean(probe_z)) + probe_z

                if output:
                    plt.imsave("{}/{}".format(output, img_name),
                               probe_z,
                               cmap=cmap)
                else:
                    plt.imshow(probe_z, cmap=cmap, vmin=0.0, vmax=1.0)
                    plt.show()

            elif mode == 'tri' or mode == 'tri_scatter':
                tri = Triangulation(flat[0], flat[1])
                if tri_method == 'cube':
                    interpol = CubicTriInterpolator(tri, flat[2])
                else:
                    interpol = LinearTriInterpolator(tri, flat[2])

                x_new = np.arange(boundary[0][0], boundary[0][1], self.img_dx)
                y_new = np.arange(boundary[1][0], boundary[1][1], self.img_dx)
                X_new, Y_new = np.meshgrid(x_new, y_new)

                Z_new = interpol(X_new, Y_new)

                print("Orginal range: {}   {}".format(np.min(Z_new),
                                                      np.max(Z_new)))

                Z_new = Z_new - np.min(Z_new)

                if vmax == "get":
                    return np.max(Z_new)
                if vmax is None:
                    vmax = np.max(Z_new)

                Z_new = Z_new / vmax
                Z_new += (1 - np.max(Z_new)) * 0.5

                if scalebar:
                    plt.gca().add_artist(ScaleBar(1.0 / self.img_dx, 'nm'))

                if output:
                    if mode == 'tri':
                        plt.imsave("{}/{}".format(output, img_name),
                                   Z_new,
                                   vmin=0,
                                   vmax=1,
                                   cmap=cmap)
                    else:
                        inside_box = np.logical_and(
                            np.logical_and(flat[0] > boundary[0][0],
                                           flat[0] < boundary[0][1]),
                            np.logical_and(flat[1] > boundary[1][0],
                                           flat[1] < boundary[1][1]))
                        scatter_x = flat[0, inside_box]
                        scatter_y = flat[1, inside_box]

                        plt.imshow(Z_new, vmin=0, vmax=1, cmap=cmap)
                        plt.scatter(scatter_x - boundary[0][0],
                                    scatter_y - boundary[1][0],
                                    marker=',',
                                    s=1,
                                    lw=0,
                                    color='red')
                        plt.savefig("{}/{}".format(output, img_name))
                        plt.cla()

                else:
                    plt.imshow(Z_new, vmin=0, vmax=1, cmap=cmap)
                    if mode == 'tri_scatter':
                        inside_box = np.logical_and(
                            np.logical_and(flat[0] > boundary[0][0],
                                           flat[0] < boundary[0][1]),
                            np.logical_and(flat[1] > boundary[1][0],
                                           flat[1] < boundary[1][1]))
                        scatter_x = flat[0, inside_box]
                        scatter_y = flat[1, inside_box]

                        plt.scatter(scatter_x - boundary[0][0],
                                    scatter_y - boundary[1][0],
                                    marker=',',
                                    s=1,
                                    lw=0,
                                    color='red')
                    plt.show()
Example #17
0
class Plotter():
    """ Create plot objects based on output from the FVCOM.

    Class to assist in the creation of plots and animations based on output
    from the FVCOM.

    Provides
    --------
    plot_field
    plot_quiver
    plot_lines
    plot_scatter
    remove_line_plots (N.B., this is mostly specific to PyLag-tools)

    Author(s)
    ---------
    James Clark (Plymouth Marine Laboratory)
    Pierre Cazenave (Plymouth Marine Laboratory)

    """
    def __init__(self,
                 dataset,
                 figure=None,
                 axes=None,
                 stations=None,
                 extents=None,
                 vmin=None,
                 vmax=None,
                 mask=None,
                 res='c',
                 fs=10,
                 title=None,
                 cmap='viridis',
                 figsize=(10., 10.),
                 axis_position=None,
                 edgecolors='none',
                 s_stations=20,
                 s_particles=20,
                 linewidth=1.0,
                 tick_inc=None,
                 cb_label=None,
                 extend='neither',
                 norm=None,
                 m=None):
        """
        Parameters:
        -----------
        dataset : Dataset, PyFVCOM.read.FileReader
            netCDF4 Dataset or PyFVCOM.read.FileReader object.

        stations : 2D array, optional
            List of station coordinates to be plotted ([[lons], [lats]])

        extents : 1D array, optional
            Four element numpy array giving lon/lat limits (e.g. [-4.56, -3.76,
            49.96, 50.44])

        vmin : float, optional
            Lower bound to be used on colour bar (plot_field only).

        vmax : float, optional
            Upper bound to be used colour bar (plot_field only).

        mask : float, optional
            Mask out values < mask (plot_field only).

        res : string, optional
            Resolution to use when drawing Basemap object

        fs : int, optional
            Font size to use when rendering plot text

        title : str, optional
            Title to use when creating the plot

        cmap : string, optional
            Colormap to use when shading field data (plot_field only).

        figure : Figure, optional
            Matplotlib figure object. A figure object is created if not
            provided.

        figsize : tuple(float), optional
            Figure size in cm. This is only used if a new Figure object is
            created.

        axes : Axes, optional
            Matplotlib Axes object. An Axes object is created if not
            provided.

        axis_position : 1D array, optional
            Array giving axis dimensions

        s_stations : int, optional
            Symbol size used when producing scatter plot of station locations

        s_particles : int, optional
            Symbol size used when producing scatter plot of particle locations

        linewidth : float, optional
            Linewidth to be used when generating line plots

        tick_inc : list, optional
            Add coordinate axes (i.e. lat/long) at the intervals specified in
            the list ([lon_spacing, lat_spacing]).

        cb_label : str, optional
            Set the colour bar label.

        extend : str, optional
            Set the colour bar extension ('neither', 'both', 'min', 'max').
            Defaults to 'neither').

        norm : matplotlib.colors.Normalize, optional
            Normalise the luminance to 0,1. For example, use from
            matplotlib.colors.LogNorm to do log plots of fields.

        m : mpl_toolkits.basemap.Basemap, optional
            Pass a Basemap object rather than creating one on each invocation.

        Author(s):
        -------
        James Clark (PML)
        Pierre Cazenave (PML)

        """

        self.ds = dataset
        self.figure = figure
        self.axes = axes
        self.stations = stations
        self.extents = extents
        self.vmin = vmin
        self.vmax = vmax
        self.mask = mask
        self.res = res
        self.fs = fs
        self.title = title
        self.cmap = cmap
        self.figsize = figsize
        self.axis_position = axis_position
        self.edgecolors = edgecolors
        self.s_stations = s_stations
        self.s_particles = s_particles
        self.linewidth = linewidth
        self.tick_inc = tick_inc
        self.cb_label = cb_label
        self.extend = extend
        self.norm = norm
        self.m = m

        # Plot instances (initialise to None for truthiness test later)
        self.quiver_plot = None
        self.scat_plot = None
        self.tripcolor_plot = None
        self.tri = None
        self.masked_tris = None
        self.cbar = None
        self.line_plot = None

        # Are we working with a FileReader object or a bog-standard netCDF4 Dataset?
        self._FileReader = False
        if isinstance(dataset, FileReader):
            self._FileReader = True

        # Initialise the figure
        self._init_figure()

    def _init_figure(self):
        # Read in required grid variables
        if self._FileReader:
            self.n_nodes = getattr(self.ds.dims, 'node')
            self.n_elems = getattr(self.ds.dims, 'nele')
            self.lon = self.ds.grid.lon
            self.lat = self.ds.grid.lat
            self.lonc = self.ds.grid.lonc
            self.latc = self.ds.grid.latc
            self.nv = self.ds.grid.nv
        else:
            self.n_nodes = len(self.ds.dimensions['node'])
            self.n_elems = len(self.ds.dimensions['nele'])
            self.lon = self.ds.variables['lon'][:]
            self.lat = self.ds.variables['lat'][:]
            self.lonc = self.ds.variables['lonc'][:]
            self.latc = self.ds.variables['latc'][:]
            self.nv = self.ds.variables['nv'][:]

        if self.nv.min() != 1:
            self.nv -= self.nv.min()

        # Triangles
        self.triangles = self.nv.transpose() - 1

        # Initialise the figure
        if self.figure is None:
            figsize = (cm2inch(self.figsize[0]), cm2inch(self.figsize[1]))
            self.figure = plt.figure(figsize=figsize)
            self.figure.set_facecolor('white')

        # Create plot axes
        if not self.axes:
            self.axes = self.figure.add_subplot(1, 1, 1)
            if self.axis_position:
                self.axes.set_position(self.axis_position)

        # If plot extents were not given, use min/max lat/lon values
        if self.extents is None:
            self.extents = np.array([
                self.lon.min(),
                self.lon.max(),
                self.lat.min(),
                self.lat.max()
            ])

        # Create basemap object
        if not self.m:
            if have_basemap:
                self.m = Basemap(llcrnrlon=self.extents[:2].min(),
                                 llcrnrlat=self.extents[-2:].min(),
                                 urcrnrlon=self.extents[:2].max(),
                                 urcrnrlat=self.extents[-2:].max(),
                                 rsphere=(6378137.00, 6356752.3142),
                                 resolution=self.res,
                                 projection='merc',
                                 area_thresh=0.1,
                                 lat_0=self.extents[-2:].mean(),
                                 lon_0=self.extents[:2].mean(),
                                 lat_ts=self.extents[-2:].mean(),
                                 ax=self.axes)
            else:
                raise RuntimeError(
                    'mpl_toolkits is not available in this Python.')

        self.m.drawmapboundary()
        self.m.drawcoastlines(zorder=2)
        self.m.fillcontinents(color='0.6', zorder=2)

        if self.title:
            self.axes.set_title(self.title)

        # Add coordinate labels to the x and y axes.
        if self.tick_inc:
            meridians = np.arange(np.floor(np.min(self.extents[:2])),
                                  np.ceil(np.max(self.extents[:2])),
                                  self.tick_inc[0])
            parallels = np.arange(np.floor(np.min(self.extents[2:])),
                                  np.ceil(np.max(self.extents[2:])),
                                  self.tick_inc[1])
            self.m.drawparallels(parallels,
                                 labels=[1, 0, 0, 0],
                                 fontsize=self.fs,
                                 linewidth=0,
                                 ax=self.axes)
            self.m.drawmeridians(meridians,
                                 labels=[0, 0, 0, 1],
                                 fontsize=self.fs,
                                 linewidth=0,
                                 ax=self.axes)

    def replot(self):
        self.axes.cla()
        self._init_figure()

    def plot_field(self, field):
        """ Map the given field.

        Parameters:
        -----------
        field : 1D array TOCHECK
            Field to plot.

        """

        if self.mask is not None:
            field = np.ma.masked_where(field <= self.mask, field)

        # Update array values if the plot has already been initialised
        if self.tripcolor_plot:
            field = field[self.masked_tris].mean(axis=1)
            self.tripcolor_plot.set_array(field)
            return

        # Create tripcolor plot
        x, y = self.m(self.lon, self.lat)
        self.tri = Triangulation(x, y, self.triangles)
        self.masked_tris = self.tri.get_masked_triangles()
        field = field[self.masked_tris].mean(axis=1)
        self.tripcolor_plot = self.axes.tripcolor(self.tri,
                                                  field,
                                                  vmin=self.vmin,
                                                  vmax=self.vmax,
                                                  cmap=self.cmap,
                                                  edgecolors=self.edgecolors,
                                                  zorder=1,
                                                  norm=self.norm)

        # Overlay the grid
        # self.axes.triplot(self.tri, zorder=2)

        # Overlay stations in the first instance
        if self.stations is not None:
            mx, my = self.m(self.stations[0, :], self.stations[1, :])
            self.axes.scatter(mx,
                              my,
                              marker='*',
                              c='k',
                              s=self.s_stations,
                              edgecolors='none',
                              zorder=4)

        # Add colorbar scaled to axis width
        divider = make_axes_locatable(self.axes)
        cax = divider.append_axes("right", size="5%", pad=0.05)
        self.cbar = self.figure.colorbar(self.tripcolor_plot,
                                         cax=cax,
                                         extend=self.extend)
        self.cbar.ax.tick_params(labelsize=self.fs)
        if self.cb_label:
            self.cbar.set_label(self.cb_label)

        return

    def plot_quiver(self,
                    u,
                    v,
                    field=False,
                    add_key=True,
                    scale=1.0,
                    label=None):
        """ Produce quiver plot using u and v velocity components.

        Parameters:
        -----------
        u : 1D or 2D array
            u-component of the velocity field.

        v : 1D or 2D array
            v-component of the velocity field

        field : 1D or 2D array
            velocity magnitude field. Used to colour the vectors. Also adds a colour bar which uses the cb_label and
            cmap, if provided.

        add_key : bool, optional
            Add key for the quiver plot. Defaults to True.

        scale : float, optional
            Scaling to be provided to arrows with scale_units of inches. Defaults to 1.0.

        label : str, optional
            Give label to use for the quiver key (defaults to "`scale' ms^{-1}").

        """

        if self.quiver_plot:
            if np.any(field):
                self.quiver_plot.set_UVC(u, v, field)
            else:
                self.quiver_plot.set_UVC(u, v)
            return

        if not label:
            label = '{} '.format(scale) + r'$\mathrm{ms^{-1}}$'

        x, y = self.m(self.lonc, self.latc)

        if np.any(field):
            self.quiver_plot = self.axes.quiver(x,
                                                y,
                                                u,
                                                v,
                                                field,
                                                cmap=self.cmap,
                                                units='inches',
                                                scale_units='inches',
                                                scale=scale)
            divider = make_axes_locatable(self.axes)
            cax = divider.append_axes("right", size="5%", pad=0.05)
            self.cbar = self.figure.colorbar(self.quiver_plot, cax=cax)
            self.cbar.ax.tick_params(labelsize=self.fs)
            if self.cb_label:
                self.cbar.set_label(self.cb_label)
        else:
            self.quiver_plot = self.axes.quiver(x,
                                                y,
                                                u,
                                                v,
                                                units='inches',
                                                scale_units='inches',
                                                scale=scale)
        if add_key:
            self.quiver_key = plt.quiverkey(self.quiver_plot,
                                            0.9,
                                            0.9,
                                            scale,
                                            label,
                                            coordinates='axes')

        return

    def plot_lines(self,
                   x,
                   y,
                   group_name='Default',
                   colour='r',
                   zone_number='30N'):
        """ Plot path lines.

        Parameters:
        -----------
        x : 1D array TOCHECK
            Array of x coordinates to plot.

        y : 1D array TOCHECK
            Array of y coordinates to plot.

        group_name : str, optional
            Group name for this set of particles - a separate plot object is
            created for each group name passed in.

            Default `None'

        color : string, optional
            Colour to use when making the plot.

            Default `r'

        zone_number : string, optional
            See PyFVCOM documentation for a full list of supported codes.

        """

        if not self.line_plot:
            self.line_plot = dict()

        # Remove current line plots for this group, if they exist
        if group_name in self.line_plot:
            if self.line_plot[group_name]:
                self.remove_line_plots(group_name)

        lon, lat = lonlat_from_utm(x, y, zone_number)
        mx, my = self.m(lon, lat)
        self.line_plot[group_name] = self.axes.plot(mx,
                                                    my,
                                                    color=colour,
                                                    linewidth=self.linewidth,
                                                    alpha=0.25,
                                                    zorder=2)

    def remove_line_plots(self, group_name):
        """ Remove line plots for group `group_name'

        Parameters:
        -----------
        group_name : str
            Name of the group for which line plots should be deleted.

        """
        if self.line_plot:
            while self.line_plot[group_name]:
                self.line_plot[group_name].pop(0).remove()

    def plot_scatter(self,
                     x,
                     y,
                     group_name='Default',
                     colour='r',
                     zone_number='30N'):
        """ Plot scatter.

        Parameters:
        -----------
        x : 1D array TOCHECK
            Array of x coordinates to plot.

        y : 1D array TOCHECK
            Array of y coordinates to plot.

        group_name : str, optional
            Group name for this set of particles - a separate plot object is
            created for each group name passed in.

            Default `None'

        color : string, optional
            Colour to use when making the plot.

            Default `r'

        zone_number : string, optional
            See PyFVCOM documentation for a full list of supported codes.

            Default `30N'

        """
        if not self.scat_plot:
            self.scat_plot = dict()

        lon, lat = lonlat_from_utm(x, y, zone_number)
        mx, my = self.m(lon, lat)

        try:
            data = np.array([mx, my])
            self.scat_plot[group_name].set_offsets(data.transpose())
        except KeyError:
            self.scat_plot[group_name] = self.axes.scatter(mx,
                                                           my,
                                                           s=self.s_particles,
                                                           color=colour,
                                                           edgecolors='none',
                                                           zorder=3)

    def set_title(self, title):
        """ Set the title for the current axis. """
        self.axes.set_title(title, fontsize=self.fs)

    def close(self):
        """ Close the current figure. """
        plt.close(self.figure)
Example #18
0
def tripcolor(ax, *args, **kwargs):
    """
    Create a pseudocolor plot of an unstructured triangular grid to
    the :class:`~matplotlib.axes.Axes`.

    The triangulation can be specified in one of two ways; either::

      tripcolor(triangulation, ...)

    where triangulation is a :class:`~matplotlib.tri.Triangulation`
    object, or

    ::

      tripcolor(x, y, ...)
      tripcolor(x, y, triangles, ...)
      tripcolor(x, y, triangles=triangles, ...)
      tripcolor(x, y, mask=mask, ...)
      tripcolor(x, y, triangles, mask=mask, ...)

    in which case a Triangulation object will be created.  See
    :class:`~matplotlib.tri.Triangulation` for a explanation of these
    possibilities.

    The next argument must be *C*, the array of color values, one per
    point in the triangulation.

    *shading* may be 'flat', 'faceted' or 'gouraud'. If *shading* is
    'flat' or 'faceted', the colors used for each triangle are from
    the mean C of the triangle's three points.

    The remaining kwargs are the same as for
    :meth:`~matplotlib.axes.Axes.pcolor`.

    **Example:**

        .. plot:: mpl_examples/pylab_examples/tripcolor_demo.py
    """
    if not ax._hold: ax.cla()

    alpha = kwargs.pop('alpha', 1.0)
    norm = kwargs.pop('norm', None)
    cmap = kwargs.pop('cmap', None)
    vmin = kwargs.pop('vmin', None)
    vmax = kwargs.pop('vmax', None)
    shading = kwargs.pop('shading', 'flat')

    tri, args, kwargs = Triangulation.get_from_args_and_kwargs(*args, **kwargs)
    x = tri.x
    y = tri.y
    triangles = tri.get_masked_triangles()

    C = np.asarray(args[0])
    if C.shape != x.shape:
        raise ValueError('C array must have same length as triangulation x and'
                         ' y arrays')

    if shading == 'gouraud':
        collection = TriMesh(tri, **kwargs)
    else:
        if shading == 'faceted':
            edgecolors = (0,0,0,1),
            linewidths = (0.25,)
        else:
            edgecolors = 'face'
            linewidths = (1.0,)
        kwargs.setdefault('edgecolors', edgecolors)
        kwargs.setdefault('antialiaseds', (0,))
        kwargs.setdefault('linewidths', linewidths)

        # Vertices of triangles.
        verts = np.concatenate((x[triangles][...,np.newaxis],
                                y[triangles][...,np.newaxis]), axis=2)
        # Color values, one per triangle, mean of the 3 vertex color values.
        C = C[triangles].mean(axis=1)
        collection = PolyCollection(verts, **kwargs)

    collection.set_alpha(alpha)
    collection.set_array(C)
    if norm is not None: assert(isinstance(norm, Normalize))
    collection.set_cmap(cmap)
    collection.set_norm(norm)
    if vmin is not None or vmax is not None:
        collection.set_clim(vmin, vmax)
    else:
        collection.autoscale_None()
    ax.grid(False)

    minx = tri.x.min()
    maxx = tri.x.max()
    miny = tri.y.min()
    maxy = tri.y.max()
    corners = (minx, miny), (maxx, maxy)
    ax.update_datalim( corners)
    ax.autoscale_view()
    ax.add_collection(collection)
    return collection
Example #19
0
def tripcolor(ax, *args, **kwargs):
    """
    Create a pseudocolor plot of an unstructured triangular grid.

    The triangulation can be specified in one of two ways; either::

      tripcolor(triangulation, ...)

    where triangulation is a :class:`matplotlib.tri.Triangulation`
    object, or

    ::

      tripcolor(x, y, ...)
      tripcolor(x, y, triangles, ...)
      tripcolor(x, y, triangles=triangles, ...)
      tripcolor(x, y, mask=mask, ...)
      tripcolor(x, y, triangles, mask=mask, ...)

    in which case a Triangulation object will be created.  See
    :class:`~matplotlib.tri.Triangulation` for a explanation of these
    possibilities.

    The next argument must be *C*, the array of color values, either
    one per point in the triangulation if color values are defined at
    points, or one per triangle in the triangulation if color values
    are defined at triangles. If there are the same number of points
    and triangles in the triangulation it is assumed that color
    values are defined at points; to force the use of color values at
    triangles use the kwarg *facecolors*=C instead of just *C*.

    *shading* may be 'flat' (the default) or 'gouraud'. If *shading*
    is 'flat' and C values are defined at points, the color values
    used for each triangle are from the mean C of the triangle's
    three points. If *shading* is 'gouraud' then color values must be
    defined at points.

    The remaining kwargs are the same as for
    :meth:`~matplotlib.axes.Axes.pcolor`.

    **Example:**

        .. plot:: mpl_examples/pylab_examples/tripcolor_demo.py
    """
    if not ax._hold:
        ax.cla()

    alpha = kwargs.pop('alpha', 1.0)
    norm = kwargs.pop('norm', None)
    cmap = kwargs.pop('cmap', None)
    vmin = kwargs.pop('vmin', None)
    vmax = kwargs.pop('vmax', None)
    shading = kwargs.pop('shading', 'flat')
    facecolors = kwargs.pop('facecolors', None)

    if shading not in ['flat', 'gouraud']:
        raise ValueError("shading must be one of ['flat', 'gouraud'] "
                         "not {0}".format(shading))

    tri, args, kwargs = Triangulation.get_from_args_and_kwargs(*args, **kwargs)

    # C is the colors array defined at either points or faces (i.e. triangles).
    # If facecolors is None, C are defined at points.
    # If facecolors is not None, C are defined at faces.
    if facecolors is not None:
        C = facecolors
    else:
        C = np.asarray(args[0])

    # If there are a different number of points and triangles in the
    # triangulation, can omit facecolors kwarg as it is obvious from
    # length of C whether it refers to points or faces.
    # Do not do this for gouraud shading.
    if (facecolors is None and len(C) == len(tri.triangles) and
            len(C) != len(tri.x) and shading != 'gouraud'):
        facecolors = C

    # Check length of C is OK.
    if ((facecolors is None and len(C) != len(tri.x)) or
            (facecolors is not None and len(C) != len(tri.triangles))):
        raise ValueError('Length of color values array must be the same '
                         'as either the number of triangulation points '
                         'or triangles')

    # Handling of linewidths, shading, edgecolors and antialiased as
    # in Axes.pcolor
    linewidths = (0.25,)
    if 'linewidth' in kwargs:
        kwargs['linewidths'] = kwargs.pop('linewidth')
    kwargs.setdefault('linewidths', linewidths)

    edgecolors = 'none'
    if 'edgecolor' in kwargs:
        kwargs['edgecolors'] = kwargs.pop('edgecolor')
    ec = kwargs.setdefault('edgecolors', edgecolors)

    if 'antialiased' in kwargs:
        kwargs['antialiaseds'] = kwargs.pop('antialiased')
    if 'antialiaseds' not in kwargs and ec.lower() == "none":
        kwargs['antialiaseds'] = False

    if shading == 'gouraud':
        if facecolors is not None:
            raise ValueError('Gouraud shading does not support the use '
                             'of facecolors kwarg')
        if len(C) != len(tri.x):
            raise ValueError('For gouraud shading, the length of color '
                             'values array must be the same as the '
                             'number of triangulation points')
        collection = TriMesh(tri, **kwargs)
    else:
        # Vertices of triangles.
        maskedTris = tri.get_masked_triangles()
        verts = np.concatenate((tri.x[maskedTris][..., np.newaxis],
                                tri.y[maskedTris][..., np.newaxis]), axis=2)

        # Color values.
        if facecolors is None:
            # One color per triangle, the mean of the 3 vertex color values.
            C = C[maskedTris].mean(axis=1)
        elif tri.mask is not None:
            # Remove color values of masked triangles.
            C = C.compress(1-tri.mask)

        collection = PolyCollection(verts, **kwargs)

    collection.set_alpha(alpha)
    collection.set_array(C)
    if norm is not None:
        if not isinstance(norm, Normalize):
            msg = "'norm' must be an instance of 'Normalize'"
            raise ValueError(msg)
    collection.set_cmap(cmap)
    collection.set_norm(norm)
    if vmin is not None or vmax is not None:
        collection.set_clim(vmin, vmax)
    else:
        collection.autoscale_None()
    ax.grid(False)

    minx = tri.x.min()
    maxx = tri.x.max()
    miny = tri.y.min()
    maxy = tri.y.max()
    corners = (minx, miny), (maxx, maxy)
    ax.update_datalim(corners)
    ax.autoscale_view()
    ax.add_collection(collection)
    return collection
def triplot(ax, *args, **kwargs):
    """
    Draw a unstructured triangular grid as lines and/or markers.

    The triangulation to plot can be specified in one of two ways;
    either::

      triplot(triangulation, ...)

    where triangulation is a :class:`~matplotlib.tri.Triangulation`
    object, or

    ::

      triplot(x, y, ...)
      triplot(x, y, triangles, ...)
      triplot(x, y, triangles=triangles, ...)
      triplot(x, y, mask=mask, ...)
      triplot(x, y, triangles, mask=mask, ...)

    in which case a Triangulation object will be created.  See
    :class:`~matplotlib.tri.Triangulation` for a explanation of these
    possibilities.

    The remaining args and kwargs are the same as for
    :meth:`~matplotlib.axes.Axes.plot`.

    **Example:**

        .. plot:: mpl_examples/pylab_examples/triplot_demo.py
    """
    import matplotlib.axes

    tri, args, kwargs = Triangulation.get_from_args_and_kwargs(*args, **kwargs)

    x = tri.x
    y = tri.y
    edges = tri.edges

    # If draw both lines and markers at the same time, e.g.
    #     ax.plot(x[edges].T, y[edges].T, *args, **kwargs)
    # then the markers are drawn more than once which is incorrect if alpha<1.
    # Hence draw lines and markers separately.

    # Decode plot format string, e.g. 'ro-'
    fmt = ''
    if len(args) > 0:
        fmt = args[0]
    linestyle, marker, color = matplotlib.axes._process_plot_format(fmt)

    # Draw lines without markers, if lines are required.
    if linestyle is not None and linestyle is not 'None':
        kw = kwargs.copy()
        kw.pop('marker', None)  # Ignore marker if set.
        kw['linestyle'] = ls_mapper[linestyle]
        kw['edgecolor'] = color
        kw['facecolor'] = None

        vertices = np.column_stack((x[edges].flatten(), y[edges].flatten()))
        codes = ([Path.MOVETO] + [Path.LINETO]) * len(edges)

        path = Path(vertices, codes)
        pathpatch = PathPatch(path, **kw)

        ax.add_patch(pathpatch)

    # Draw markers without lines.
    # Should avoid drawing markers for points that are not in any triangle?
    kwargs['linestyle'] = ''
    ax.plot(x, y, *args, **kwargs)
Example #21
0
def triplot(ax, *args, **kwargs):
    """
    Draw a unstructured triangular grid as lines and/or markers.

    The triangulation to plot can be specified in one of two ways;
    either::

      triplot(triangulation, ...)

    where triangulation is a :class:`matplotlib.tri.Triangulation`
    object, or

    ::

      triplot(x, y, ...)
      triplot(x, y, triangles, ...)
      triplot(x, y, triangles=triangles, ...)
      triplot(x, y, mask=mask, ...)
      triplot(x, y, triangles, mask=mask, ...)

    in which case a Triangulation object will be created.  See
    :class:`~matplotlib.tri.Triangulation` for a explanation of these
    possibilities.

    The remaining args and kwargs are the same as for
    :meth:`~matplotlib.axes.Axes.plot`.

    Return a list of 2 :class:`~matplotlib.lines.Line2D` containing
    respectively:

        - the lines plotted for triangles edges
        - the markers plotted for triangles nodes
    """
    import matplotlib.axes

    tri, args, kwargs = Triangulation.get_from_args_and_kwargs(*args, **kwargs)
    x, y, edges = (tri.x, tri.y, tri.edges)

    # Decode plot format string, e.g., 'ro-'
    fmt = ""
    if len(args) > 0:
        fmt = args[0]
    linestyle, marker, color = matplotlib.axes._base._process_plot_format(fmt)

    # Insert plot format string into a copy of kwargs (kwargs values prevail).
    kw = kwargs.copy()
    for key, val in zip(('linestyle', 'marker', 'color'),
                        (linestyle, marker, color)):
        if val is not None:
            kw[key] = kwargs.get(key, val)

    # Draw lines without markers.
    # Note 1: If we drew markers here, most markers would be drawn more than
    #         once as they belong to several edges.
    # Note 2: We insert nan values in the flattened edges arrays rather than
    #         plotting directly (triang.x[edges].T, triang.y[edges].T)
    #         as it considerably speeds-up code execution.
    linestyle = kw['linestyle']
    kw_lines = kw.copy()
    kw_lines['marker'] = 'None'  # No marker to draw.
    kw_lines['zorder'] = kw.get('zorder', 1)  # Path default zorder is used.
    if (linestyle is not None) and (linestyle not in ['None', '', ' ']):
        tri_lines_x = np.insert(x[edges], 2, np.nan, axis=1)
        tri_lines_y = np.insert(y[edges], 2, np.nan, axis=1)
        tri_lines = ax.plot(tri_lines_x.ravel(), tri_lines_y.ravel(),
                            **kw_lines)
    else:
        tri_lines = ax.plot([], [], **kw_lines)

    # Draw markers separately.
    marker = kw['marker']
    kw_markers = kw.copy()
    kw_markers['linestyle'] = 'None'  # No line to draw.
    if (marker is not None) and (marker not in ['None', '', ' ']):
        tri_markers = ax.plot(x, y, **kw_markers)
    else:
        tri_markers = ax.plot([], [], **kw_markers)

    return tri_lines + tri_markers
Example #22
0
def _get_interp_tri(x_in, y_in, gr_x, gr_y, method=None):
    """
    For each value (x_in, y_in) returns _indexes of the closets 3 values (Delaunay) in the (gr_x, gr_y) table, 
    and the corresponding coefficients.
    @method: tri_surf', 'plan_interp'
    """
    methods = ['tri_surf', 'plan_interp']

    calling = 'interp_3D'
    pc.log_.message('Entering interp 3D', calling=calling)
    if not pc.config.INSTALLED['Triangulation']:
        pc.log_.error('Triangulation package not available from matplotlib.',
                      calling=calling)
        return None
    if method is None:
        method = methods[0]
    if method not in methods:
        pc.log_.error('{0} is not a valid method'.format(method),
                      calling=calling)
        return None

    n_points = np.size(x_in)
    indexes = np.zeros((n_points, 3), dtype=int) - 1
    coeffs = np.zeros((n_points, 3))
    if method == 'tri_surf':

        def get_coeff(x, y, P1, P2, P3):
            v1x = P1[0] - x
            v1y = P1[1] - y
            v2x = P2[0] - x
            v2y = P2[1] - y
            v3x = P3[0] - x
            v3y = P3[1] - y
            d1 = abs(v2x * v3y - v2y * v3x)
            d2 = abs(v1x * v3y - v1y * v3x)
            d3 = abs(v1x * v2y - v1y * v2x)
            dsum = d1 + d2 + d3
            return np.squeeze(np.transpose([d1 / dsum, d2 / dsum, d3 / dsum]))
    elif method == 'plan_interp':

        def get_coeff(x, y, P1, P2, P3):
            XY = np.asarray((x, y))
            d1 = misc.dist_point_line(XY, P2, P3) / dpl1
            d2 = misc.dist_point_line(XY, P1, P3) / dpl2
            d3 = misc.dist_point_line(XY, P1, P2) / dpl3
            dsum = d1 + d2 + d3
            return np.squeeze(np.transpose([d1 / dsum, d2 / dsum, d3 / dsum]))

    tri = Triangulation(gr_x, gr_y)
    pc.log_.message('Triangulation done', calling=calling)
    n_triangles = tri.triangle_nodes.shape[0]
    for i, triangle in enumerate(tri.triangle_nodes):
        T1 = np.asarray((gr_x[triangle[0]], gr_y[triangle[0]]))
        T2 = np.asarray((gr_x[triangle[1]], gr_y[triangle[1]]))
        T3 = np.asarray((gr_x[triangle[2]], gr_y[triangle[2]]))
        points_inside = misc.points_inside_triangle(x_in, y_in, T1, T2, T3)
        pc.log_.message('{0} points inside triangle {1} over {2}'.format(
            points_inside.sum(), i, n_triangles),
                        calling=calling)
        if method == 'plan_interp':
            dpl1 = misc.dist_point_line(T1, T2, T3)
            dpl2 = misc.dist_point_line(T2, T3, T1)
            dpl3 = misc.dist_point_line(T3, T1, T2)
        if points_inside.sum() != 0:
            indexes[points_inside] = triangle
            coeffs[points_inside] = get_coeff(x_in[points_inside],
                                              y_in[points_inside], T1, T2, T3)
    return indexes, coeffs
Example #23
0
def triplot(ax, *args, **kwargs):
    """
    Draw a unstructured triangular grid as lines and/or markers.

    The triangulation to plot can be specified in one of two ways; either::

      triplot(triangulation, ...)

    where triangulation is a `.Triangulation` object, or

    ::

      triplot(x, y, ...)
      triplot(x, y, triangles, ...)
      triplot(x, y, triangles=triangles, ...)
      triplot(x, y, mask=mask, ...)
      triplot(x, y, triangles, mask=mask, ...)

    in which case a Triangulation object will be created.  See `.Triangulation`
    for a explanation of these possibilities.

    The remaining args and kwargs are the same as for `~.Axes.plot`.

    Returns
    -------
    lines : `~matplotlib.lines.Line2D`
        The drawn triangles edges.
    markers : `~matplotlib.lines.Line2D`
        The drawn marker nodes.
    """
    import matplotlib.axes

    tri, args, kwargs = Triangulation.get_from_args_and_kwargs(*args, **kwargs)
    x, y, edges = (tri.x, tri.y, tri.edges)

    # Decode plot format string, e.g., 'ro-'
    fmt = args[0] if args else ""
    linestyle, marker, color = matplotlib.axes._base._process_plot_format(fmt)

    # Insert plot format string into a copy of kwargs (kwargs values prevail).
    kw = cbook.normalize_kwargs(kwargs, mlines.Line2D)
    for key, val in zip(('linestyle', 'marker', 'color'),
                        (linestyle, marker, color)):
        if val is not None:
            kw.setdefault(key, val)

    # Draw lines without markers.
    # Note 1: If we drew markers here, most markers would be drawn more than
    #         once as they belong to several edges.
    # Note 2: We insert nan values in the flattened edges arrays rather than
    #         plotting directly (triang.x[edges].T, triang.y[edges].T)
    #         as it considerably speeds-up code execution.
    linestyle = kw['linestyle']
    kw_lines = {
        **kw,
        'marker': 'None',  # No marker to draw.
        'zorder': kw.get('zorder', 1),  # Path default zorder is used.
    }
    if linestyle not in [None, 'None', '', ' ']:
        tri_lines_x = np.insert(x[edges], 2, np.nan, axis=1)
        tri_lines_y = np.insert(y[edges], 2, np.nan, axis=1)
        tri_lines = ax.plot(tri_lines_x.ravel(), tri_lines_y.ravel(),
                            **kw_lines)
    else:
        tri_lines = ax.plot([], [], **kw_lines)

    # Draw markers separately.
    marker = kw['marker']
    kw_markers = {
        **kw,
        'linestyle': 'None',  # No line to draw.
    }
    if marker not in [None, 'None', '', ' ']:
        tri_markers = ax.plot(x, y, **kw_markers)
    else:
        tri_markers = ax.plot([], [], **kw_markers)

    return tri_lines + tri_markers
Example #24
0
    def _refine_triangulation_once(triangulation, ancestors=None):
        """
        This function refines a matplotlib.tri *triangulation* by splitting
        each triangle into 4 child-masked_triangles built on the edges midside
        nodes.
        The masked triangles, if present, are also splitted but their children
        returned masked.

        If *ancestors* is not provided, returns only a new triangulation:
        child_triangulation.

        If the array-like key table *ancestor* is given, it shall be of shape
        (ntri,) where ntri is the number of *triangulation* masked_triangles.
        In this case, the function returns
        (child_triangulation, child_ancestors)
        child_ancestors is defined so that the 4 child masked_triangles share
        the same index as their father: child_ancestors.shape = (4 * ntri,).

        """
        x = triangulation.x
        y = triangulation.y

        #    According to tri.triangulation doc:
        #         neighbors[i,j] is the triangle that is the neighbor
        #         to the edge from point index masked_triangles[i,j] to point
        #         index masked_triangles[i,(j+1)%3].
        neighbors = triangulation.neighbors
        triangles = triangulation.triangles
        npts = np.shape(x)[0]
        ntri = np.shape(triangles)[0]
        if ancestors is not None:
            ancestors = np.asarray(ancestors)
            if np.shape(ancestors) != (ntri,):
                raise ValueError(
                    "Incompatible shapes provide for triangulation"
                    ".masked_triangles and ancestors: {0} and {1}".format(
                        np.shape(triangles), np.shape(ancestors)))

        # Initiating tables refi_x and refi_y of the refined triangulation
        # points
        # hint: each apex is shared by 2 masked_triangles except the borders.
        borders = np.sum(neighbors == -1)
        added_pts = (3*ntri + borders) / 2
        refi_npts = npts + added_pts
        refi_x = np.zeros(refi_npts)
        refi_y = np.zeros(refi_npts)

        # First part of refi_x, refi_y is just the initial points
        refi_x[:npts] = x
        refi_y[:npts] = y

        # Second part contains the edge midside nodes.
        # Each edge belongs to 1 triangle (if border edge) or is shared by 2
        # masked_triangles (interior edge).
        # We first build 2 * ntri arrays of edge starting nodes (edge_elems,
        # edge_apexes) ; we then extract only the masters to avoid overlaps.
        # The so-called 'master' is the triangle with biggest index
        # The 'slave' is the triangle with lower index
        # (can be -1 if border edge)
        # For slave and master we will identify the apex pointing to the edge
        # start
        edge_elems = np.ravel(np.vstack([np.arange(ntri, dtype=np.int32),
                                         np.arange(ntri, dtype=np.int32),
                                         np.arange(ntri, dtype=np.int32)]))
        edge_apexes = np.ravel(np.vstack([np.zeros(ntri, dtype=np.int32),
                                          np.ones(ntri, dtype=np.int32),
                                          np.ones(ntri, dtype=np.int32)*2]))
        edge_neighbors = neighbors[edge_elems, edge_apexes]
        mask_masters = (edge_elems > edge_neighbors)

        # Identifying the "masters" and adding to refi_x, refi_y vec
        masters = edge_elems[mask_masters]
        apex_masters = edge_apexes[mask_masters]
        x_add = (x[triangles[masters, apex_masters]] +
                 x[triangles[masters, (apex_masters+1) % 3]]) * 0.5
        y_add = (y[triangles[masters, apex_masters]] +
                 y[triangles[masters, (apex_masters+1) % 3]]) * 0.5
        refi_x[npts:] = x_add
        refi_y[npts:] = y_add

        # Building the new masked_triangles ; each old masked_triangles hosts
        # 4 new masked_triangles
        # there are 6 pts to identify per 'old' triangle, 3 new_pt_corner and
        # 3 new_pt_midside
        new_pt_corner = triangles

        # What is the index in refi_x, refi_y of point at middle of apex iapex
        #  of elem ielem ?
        # If ielem is the apex master: simple count, given the way refi_x was
        #  built.
        # If ielem is the apex slave: yet we do not know ; but we will soon
        # using the neighbors table.
        new_pt_midside = np.empty([ntri, 3], dtype=np.int32)
        cum_sum = npts
        for imid in range(3):
            mask_st_loc = (imid == apex_masters)
            n_masters_loc = np.sum(mask_st_loc)
            elem_masters_loc = masters[mask_st_loc]
            new_pt_midside[:, imid][elem_masters_loc] = np.arange(
                n_masters_loc, dtype=np.int32) + cum_sum
            cum_sum += n_masters_loc

        # Now dealing with slave elems.
        # for each slave element we identify the master and then the inode
        # onces slave_masters is indentified, slave_masters_apex is such that:
        # neighbors[slaves_masters, slave_masters_apex] == slaves
        mask_slaves = np.logical_not(mask_masters)
        slaves = edge_elems[mask_slaves]
        slaves_masters = edge_neighbors[mask_slaves]
        diff_table = np.abs(neighbors[slaves_masters, :] -
                            np.outer(slaves, np.ones(3, dtype=np.int32)))
        slave_masters_apex = np.argmin(diff_table, axis=1)
        slaves_apex = edge_apexes[mask_slaves]
        new_pt_midside[slaves, slaves_apex] = new_pt_midside[
            slaves_masters, slave_masters_apex]

        # Builds the 4 child masked_triangles
        child_triangles = np.empty([ntri*4, 3], dtype=np.int32)
        child_triangles[0::4, :] = np.vstack([
            new_pt_corner[:, 0], new_pt_midside[:, 0],
            new_pt_midside[:, 2]]).T
        child_triangles[1::4, :] = np.vstack([
            new_pt_corner[:, 1], new_pt_midside[:, 1],
            new_pt_midside[:, 0]]).T
        child_triangles[2::4, :] = np.vstack([
            new_pt_corner[:, 2], new_pt_midside[:, 2],
            new_pt_midside[:, 1]]).T
        child_triangles[3::4, :] = np.vstack([
            new_pt_midside[:, 0], new_pt_midside[:, 1],
            new_pt_midside[:, 2]]).T
        child_triangulation = Triangulation(refi_x, refi_y, child_triangles)

        # Builds the child mask
        if triangulation.mask is not None:
            child_triangulation.set_mask(np.repeat(triangulation.mask, 4))

        if ancestors is None:
            return child_triangulation
        else:
            return child_triangulation, np.repeat(ancestors, 4)
Example #25
0
def tripcolor(ax, *args, **kwargs):
    """
    Create a pseudocolor plot of an unstructured triangular grid.

    The triangulation can be specified in one of two ways; either::

      tripcolor(triangulation, ...)

    where triangulation is a :class:`matplotlib.tri.Triangulation`
    object, or

    ::

      tripcolor(x, y, ...)
      tripcolor(x, y, triangles, ...)
      tripcolor(x, y, triangles=triangles, ...)
      tripcolor(x, y, mask=mask, ...)
      tripcolor(x, y, triangles, mask=mask, ...)

    in which case a Triangulation object will be created.  See
    :class:`~matplotlib.tri.Triangulation` for a explanation of these
    possibilities.

    The next argument must be *C*, the array of color values, either
    one per point in the triangulation if color values are defined at
    points, or one per triangle in the triangulation if color values
    are defined at triangles. If there are the same number of points
    and triangles in the triangulation it is assumed that color
    values are defined at points; to force the use of color values at
    triangles use the kwarg *facecolors*=C instead of just *C*.

    *shading* may be 'flat' (the default) or 'gouraud'. If *shading*
    is 'flat' and C values are defined at points, the color values
    used for each triangle are from the mean C of the triangle's
    three points. If *shading* is 'gouraud' then color values must be
    defined at points.

    The remaining kwargs are the same as for
    :meth:`~matplotlib.axes.Axes.pcolor`.

    **Example:**

        .. plot:: mpl_examples/pylab_examples/tripcolor_demo.py
    """
    if not ax._hold:
        ax.cla()

    alpha = kwargs.pop('alpha', 1.0)
    norm = kwargs.pop('norm', None)
    cmap = kwargs.pop('cmap', None)
    vmin = kwargs.pop('vmin', None)
    vmax = kwargs.pop('vmax', None)
    shading = kwargs.pop('shading', 'flat')
    facecolors = kwargs.pop('facecolors', None)

    if shading not in ['flat', 'gouraud']:
        raise ValueError("shading must be one of ['flat', 'gouraud'] "
                         "not {0}".format(shading))

    tri, args, kwargs = Triangulation.get_from_args_and_kwargs(*args, **kwargs)

    # C is the colors array defined at either points or faces (i.e. triangles).
    # If facecolors is None, C are defined at points.
    # If facecolors is not None, C are defined at faces.
    if facecolors is not None:
        C = facecolors
    else:
        C = np.asarray(args[0])

    # If there are a different number of points and triangles in the
    # triangulation, can omit facecolors kwarg as it is obvious from
    # length of C whether it refers to points or faces.
    # Do not do this for gouraud shading.
    if (facecolors is None and len(C) == len(tri.triangles) and
            len(C) != len(tri.x) and shading != 'gouraud'):
        facecolors = C

    # Check length of C is OK.
    if ((facecolors is None and len(C) != len(tri.x)) or
            (facecolors is not None and len(C) != len(tri.triangles))):
        raise ValueError('Length of color values array must be the same '
                         'as either the number of triangulation points '
                         'or triangles')

    # Handling of linewidths, shading, edgecolors and antialiased as
    # in Axes.pcolor
    linewidths = (0.25,)
    if 'linewidth' in kwargs:
        kwargs['linewidths'] = kwargs.pop('linewidth')
    kwargs.setdefault('linewidths', linewidths)

    edgecolors = 'none'
    if 'edgecolor' in kwargs:
        kwargs['edgecolors'] = kwargs.pop('edgecolor')
    ec = kwargs.setdefault('edgecolors', edgecolors)

    if 'antialiased' in kwargs:
        kwargs['antialiaseds'] = kwargs.pop('antialiased')
    if 'antialiaseds' not in kwargs and ec.lower() == "none":
        kwargs['antialiaseds'] = False

    if shading == 'gouraud':
        if facecolors is not None:
            raise ValueError('Gouraud shading does not support the use '
                             'of facecolors kwarg')
        if len(C) != len(tri.x):
            raise ValueError('For gouraud shading, the length of color '
                             'values array must be the same as the '
                             'number of triangulation points')
        collection = TriMesh(tri, **kwargs)
    else:
        # Vertices of triangles.
        maskedTris = tri.get_masked_triangles()
        verts = np.concatenate((tri.x[maskedTris][..., np.newaxis],
                                tri.y[maskedTris][..., np.newaxis]), axis=2)

        # Color values.
        if facecolors is None:
            # One color per triangle, the mean of the 3 vertex color values.
            C = C[maskedTris].mean(axis=1)
        elif tri.mask is not None:
            # Remove color values of masked triangles.
            C = C.compress(1-tri.mask)

        collection = PolyCollection(verts, **kwargs)

    collection.set_alpha(alpha)
    collection.set_array(C)
    if norm is not None:
        if not isinstance(norm, Normalize):
            msg = "'norm' must be an instance of 'Normalize'"
            raise ValueError(msg)
    collection.set_cmap(cmap)
    collection.set_norm(norm)
    if vmin is not None or vmax is not None:
        collection.set_clim(vmin, vmax)
    else:
        collection.autoscale_None()
    ax.grid(False)

    minx = tri.x.min()
    maxx = tri.x.max()
    miny = tri.y.min()
    maxy = tri.y.max()
    corners = (minx, miny), (maxx, maxy)
    ax.update_datalim(corners)
    ax.autoscale_view()
    ax.add_collection(collection)
    return collection
Example #26
0
def tripcolor(ax,
              *args,
              alpha=1.0,
              norm=None,
              cmap=None,
              vmin=None,
              vmax=None,
              shading='flat',
              facecolors=None,
              **kwargs):
    """
    Create a pseudocolor plot of an unstructured triangular grid.

    Call signatures::

      tripcolor(triangulation, C, *, ...)
      tripcolor(x, y, C, *, [triangles=triangles], [mask=mask], ...)

    The triangular grid can be specified either by passing a `.Triangulation`
    object as the first parameter, or by passing the points *x*, *y* and
    optionally the *triangles* and a *mask*. See `.Triangulation` for an
    explanation of these parameters.

    If neither of *triangulation* or *triangles* are given, the triangulation
    is calculated on the fly. In this case, it does not make sense to provide
    colors at the triangle faces via *C* or *facecolors* because there are
    multiple possible triangulations for a group of points and you don't know
    which triangles will be constructed.

    Parameters
    ----------
    triangulation : `.Triangulation`
        An already created triangular grid.
    x, y, triangles, mask
        Parameters defining the triangular grid. See `.Triangulation`.
        This is mutually exclusive with specifying *triangulation*.
    C : array-like
        The color values, either for the points or for the triangles. Which one
        is automatically inferred from the length of *C*, i.e. does it match
        the number of points or the number of triangles. If there are the same
        number of points and triangles in the triangulation it is assumed that
        color values are defined at points; to force the use of color values at
        triangles use the keyword argument ``facecolors=C`` instead of just
        ``C``.
        This parameter is position-only.
    facecolors : array-like, optional
        Can be used alternatively to *C* to specify colors at the triangle
        faces. This parameter takes precedence over *C*.
    shading : {'flat', 'gouraud'}, default: 'flat'
        If  'flat' and the color values *C* are defined at points, the color
        values used for each triangle are from the mean C of the triangle's
        three points. If *shading* is 'gouraud' then color values must be
        defined at points.
    other_parameters
        All other parameters are the same as for `~.Axes.pcolor`.

    Notes
    -----
    It is possible to pass the triangles positionally, i.e.
    ``tripcolor(x, y, triangles, C, ...)``. However, this is discouraged.
    For more clarity, pass *triangles* via keyword argument.
    """
    _api.check_in_list(['flat', 'gouraud'], shading=shading)

    tri, args, kwargs = Triangulation.get_from_args_and_kwargs(*args, **kwargs)

    # Parse the color to be in one of (the other variable will be None):
    # - facecolors: if specified at the triangle faces
    # - point_colors: if specified at the points
    if facecolors is not None:
        if args:
            _api.warn_external(
                "Positional parameter C has no effect when the keyword "
                "facecolors is given")
        point_colors = None
        if len(facecolors) != len(tri.triangles):
            raise ValueError("The length of facecolors must match the number "
                             "of triangles")
    else:
        # Color from positional parameter C
        if not args:
            raise ValueError(
                "Missing color parameter. Please pass C positionally or "
                "facecolors via keyword")
        elif len(args) > 1:
            _api.warn_external(
                "Additional positional parameters {args[1:]!r} are ignored")
        C = np.asarray(args[0])
        if len(C) == len(tri.x):
            # having this before the len(tri.triangles) comparison gives
            # precedence to nodes if there are as many nodes as triangles
            point_colors = C
            facecolors = None
        elif len(C) == len(tri.triangles):
            point_colors = None
            facecolors = C
        else:
            raise ValueError('The length of C must match either the number '
                             'of points or the number of triangles')

    # Handling of linewidths, shading, edgecolors and antialiased as
    # in Axes.pcolor
    linewidths = (0.25, )
    if 'linewidth' in kwargs:
        kwargs['linewidths'] = kwargs.pop('linewidth')
    kwargs.setdefault('linewidths', linewidths)

    edgecolors = 'none'
    if 'edgecolor' in kwargs:
        kwargs['edgecolors'] = kwargs.pop('edgecolor')
    ec = kwargs.setdefault('edgecolors', edgecolors)

    if 'antialiased' in kwargs:
        kwargs['antialiaseds'] = kwargs.pop('antialiased')
    if 'antialiaseds' not in kwargs and ec.lower() == "none":
        kwargs['antialiaseds'] = False

    _api.check_isinstance((Normalize, None), norm=norm)
    if shading == 'gouraud':
        if facecolors is not None:
            raise ValueError(
                "shading='gouraud' can only be used when the colors "
                "are specified at the points, not at the faces.")
        collection = TriMesh(tri,
                             alpha=alpha,
                             array=point_colors,
                             cmap=cmap,
                             norm=norm,
                             **kwargs)
    else:
        # Vertices of triangles.
        maskedTris = tri.get_masked_triangles()
        verts = np.stack((tri.x[maskedTris], tri.y[maskedTris]), axis=-1)

        # Color values.
        if facecolors is None:
            # One color per triangle, the mean of the 3 vertex color values.
            colors = point_colors[maskedTris].mean(axis=1)
        elif tri.mask is not None:
            # Remove color values of masked triangles.
            colors = facecolors[~tri.mask]
        else:
            colors = facecolors
        collection = PolyCollection(verts,
                                    alpha=alpha,
                                    array=colors,
                                    cmap=cmap,
                                    norm=norm,
                                    **kwargs)

    collection._scale_norm(norm, vmin, vmax)
    ax.grid(False)

    minx = tri.x.min()
    maxx = tri.x.max()
    miny = tri.y.min()
    maxy = tri.y.max()
    corners = (minx, miny), (maxx, maxy)
    ax.update_datalim(corners)
    ax.autoscale_view()
    ax.add_collection(collection)
    return collection
Example #27
0
    def show_scalar_in_matplotlib_3d(self, field, **kwargs):
        import matplotlib.pyplot as plt

        # This import also registers the 3D projection.
        import mpl_toolkits.mplot3d.art3d as art3d

        do_show = kwargs.pop("do_show", True)
        vmin = kwargs.pop("vmin", None)
        vmax = kwargs.pop("vmax", None)
        norm = kwargs.pop("norm", None)

        nodes = self._vis_nodes_numpy()
        field = resample_to_numpy(self.connection, field)

        assert nodes.shape[0] == self.vis_discr.ambient_dim

        vis_connectivity, = self._vtk_connectivity.groups

        fig = plt.gcf()
        ax = fig.gca(projection="3d")

        had_data = ax.has_data()

        if self.vis_discr.dim == 2:
            nodes = list(nodes)
            # pad to 3D with zeros
            while len(nodes) < 3:
                nodes.append(0*nodes[0])

            from matplotlib.tri.triangulation import Triangulation
            tri, _, kwargs = \
                Triangulation.get_from_args_and_kwargs(
                        *nodes,
                        triangles=vis_connectivity.vis_connectivity.reshape(-1, 3))

            triangles = tri.get_masked_triangles()
            xt = nodes[0][triangles]
            yt = nodes[1][triangles]
            zt = nodes[2][triangles]
            verts = np.stack((xt, yt, zt), axis=-1)

            fieldt = field[triangles]

            polyc = art3d.Poly3DCollection(verts, **kwargs)

            # average over the three points of each triangle
            avg_field = fieldt.mean(axis=1)
            polyc.set_array(avg_field)

            if vmin is not None or vmax is not None:
                polyc.set_clim(vmin, vmax)
            if norm is not None:
                polyc.set_norm(norm)

            ax.add_collection(polyc)
            ax.auto_scale_xyz(xt, yt, zt, had_data)

        else:
            raise RuntimeError("meshes of bulk dimension %d are currently "
                    "unsupported" % self.vis_discr.dim)

        if do_show:
            plt.show()
Example #28
0
def triplot(ax, *args, **kwargs):
    """
    Draw a unstructured triangular grid as lines and/or markers.

    The triangulation to plot can be specified in one of two ways;
    either::

      triplot(triangulation, ...)

    where triangulation is a :class:`matplotlib.tri.Triangulation`
    object, or

    ::

      triplot(x, y, ...)
      triplot(x, y, triangles, ...)
      triplot(x, y, triangles=triangles, ...)
      triplot(x, y, mask=mask, ...)
      triplot(x, y, triangles, mask=mask, ...)

    in which case a Triangulation object will be created.  See
    :class:`~matplotlib.tri.Triangulation` for a explanation of these
    possibilities.

    The remaining args and kwargs are the same as for
    :meth:`~matplotlib.axes.Axes.plot`.

    Return a list of 2 :class:`~matplotlib.lines.Line2D` containing
    respectively:

        - the lines plotted for triangles edges
        - the markers plotted for triangles nodes

    **Example:**

        .. plot:: mpl_examples/pylab_examples/triplot_demo.py
    """
    import matplotlib.axes

    tri, args, kwargs = Triangulation.get_from_args_and_kwargs(*args, **kwargs)
    x, y, edges = (tri.x, tri.y, tri.edges)

    # Decode plot format string, e.g., 'ro-'
    fmt = ""
    if len(args) > 0:
        fmt = args[0]
    linestyle, marker, color = matplotlib.axes._base._process_plot_format(fmt)

    # Insert plot format string into a copy of kwargs (kwargs values prevail).
    kw = kwargs.copy()
    for key, val in zip(('linestyle', 'marker', 'color'),
                        (linestyle, marker, color)):
        if val is not None:
            kw[key] = kwargs.get(key, val)

    # Draw lines without markers.
    # Note 1: If we drew markers here, most markers would be drawn more than
    #         once as they belong to several edges.
    # Note 2: We insert nan values in the flattened edges arrays rather than
    #         plotting directly (triang.x[edges].T, triang.y[edges].T)
    #         as it considerably speeds-up code execution.
    linestyle = kw['linestyle']
    kw_lines = kw.copy()
    kw_lines['marker'] = 'None'  # No marker to draw.
    kw_lines['zorder'] = kw.get('zorder', 1)  # Path default zorder is used.
    if (linestyle is not None) and (linestyle not in ['None', '', ' ']):
        tri_lines_x = np.insert(x[edges], 2, np.nan, axis=1)
        tri_lines_y = np.insert(y[edges], 2, np.nan, axis=1)
        tri_lines = ax.plot(tri_lines_x.ravel(), tri_lines_y.ravel(),
                            **kw_lines)
    else:
        tri_lines = ax.plot([], [], **kw_lines)

    # Draw markers separately.
    marker = kw['marker']
    kw_markers = kw.copy()
    kw_markers['linestyle'] = 'None'  # No line to draw.
    if (marker is not None) and (marker not in ['None', '', ' ']):
        tri_markers = ax.plot(x, y, **kw_markers)
    else:
        tri_markers = ax.plot([], [], **kw_markers)

    return tri_lines + tri_markers
Example #29
0
def triplot(ax, *args, **kwargs):
    """
    Draw a unstructured triangular grid as lines and/or markers.

    The triangulation to plot can be specified in one of two ways;
    either::

      triplot(triangulation, ...)

    where triangulation is a :class:`matplotlib.tri.Triangulation`
    object, or

    ::

      triplot(x, y, ...)
      triplot(x, y, triangles, ...)
      triplot(x, y, triangles=triangles, ...)
      triplot(x, y, mask=mask, ...)
      triplot(x, y, triangles, mask=mask, ...)

    in which case a Triangulation object will be created.  See
    :class:`~matplotlib.tri.Triangulation` for a explanation of these
    possibilities.

    The remaining args and kwargs are the same as for
    :meth:`~matplotlib.axes.Axes.plot`.

    **Example:**

        .. plot:: mpl_examples/pylab_examples/triplot_demo.py
    """
    import matplotlib.axes

    tri, args, kwargs = Triangulation.get_from_args_and_kwargs(*args, **kwargs)

    x = tri.x
    y = tri.y
    edges = tri.edges

    # If draw both lines and markers at the same time, e.g.
    #     ax.plot(x[edges].T, y[edges].T, *args, **kwargs)
    # then the markers are drawn more than once which is incorrect if alpha<1.
    # Hence draw lines and markers separately.

    # Decode plot format string, e.g., 'ro-'
    fmt = ""
    if len(args) > 0:
        fmt = args[0]
    linestyle, marker, color = matplotlib.axes._process_plot_format(fmt)

    # Draw lines without markers, if lines are required.
    if linestyle is not None and linestyle is not "None":
        kw = kwargs.copy()
        kw.pop("marker", None)  # Ignore marker if set.
        kw["linestyle"] = ls_mapper[linestyle]
        kw["edgecolor"] = color
        kw["facecolor"] = None

        vertices = np.column_stack((x[edges].flatten(), y[edges].flatten()))
        codes = ([Path.MOVETO] + [Path.LINETO]) * len(edges)

        path = Path(vertices, codes)
        pathpatch = PathPatch(path, **kw)

        ax.add_patch(pathpatch)

    # Draw markers without lines.
    # Should avoid drawing markers for points that are not in any triangle?
    kwargs["linestyle"] = ""
    ax.plot(x, y, *args, **kwargs)
Example #30
0
def tripcolor(ax,
              *args,
              alpha=1.0,
              norm=None,
              cmap=None,
              vmin=None,
              vmax=None,
              shading='flat',
              facecolors=None,
              **kwargs):
    """
    Create a pseudocolor plot of an unstructured triangular grid.

    The triangulation can be specified in one of two ways; either::

      tripcolor(triangulation, ...)

    where triangulation is a `.Triangulation` object, or

    ::

      tripcolor(x, y, ...)
      tripcolor(x, y, triangles, ...)
      tripcolor(x, y, triangles=triangles, ...)
      tripcolor(x, y, mask=mask, ...)
      tripcolor(x, y, triangles, mask=mask, ...)

    in which case a Triangulation object will be created.  See `.Triangulation`
    for a explanation of these possibilities.

    The next argument must be *C*, the array of color values, either
    one per point in the triangulation if color values are defined at
    points, or one per triangle in the triangulation if color values
    are defined at triangles. If there are the same number of points
    and triangles in the triangulation it is assumed that color
    values are defined at points; to force the use of color values at
    triangles use the kwarg ``facecolors=C`` instead of just ``C``.

    *shading* may be 'flat' (the default) or 'gouraud'. If *shading*
    is 'flat' and C values are defined at points, the color values
    used for each triangle are from the mean C of the triangle's
    three points. If *shading* is 'gouraud' then color values must be
    defined at points.

    The remaining kwargs are the same as for `~.Axes.pcolor`.
    """
    _api.check_in_list(['flat', 'gouraud'], shading=shading)

    tri, args, kwargs = Triangulation.get_from_args_and_kwargs(*args, **kwargs)

    # C is the colors array defined at either points or faces (i.e. triangles).
    # If facecolors is None, C are defined at points.
    # If facecolors is not None, C are defined at faces.
    if facecolors is not None:
        C = facecolors
    else:
        C = np.asarray(args[0])

    # If there are a different number of points and triangles in the
    # triangulation, can omit facecolors kwarg as it is obvious from
    # length of C whether it refers to points or faces.
    # Do not do this for gouraud shading.
    if (facecolors is None and len(C) == len(tri.triangles)
            and len(C) != len(tri.x) and shading != 'gouraud'):
        facecolors = C

    # Check length of C is OK.
    if ((facecolors is None and len(C) != len(tri.x))
            or (facecolors is not None and len(C) != len(tri.triangles))):
        raise ValueError('Length of color values array must be the same '
                         'as either the number of triangulation points '
                         'or triangles')

    # Handling of linewidths, shading, edgecolors and antialiased as
    # in Axes.pcolor
    linewidths = (0.25, )
    if 'linewidth' in kwargs:
        kwargs['linewidths'] = kwargs.pop('linewidth')
    kwargs.setdefault('linewidths', linewidths)

    edgecolors = 'none'
    if 'edgecolor' in kwargs:
        kwargs['edgecolors'] = kwargs.pop('edgecolor')
    ec = kwargs.setdefault('edgecolors', edgecolors)

    if 'antialiased' in kwargs:
        kwargs['antialiaseds'] = kwargs.pop('antialiased')
    if 'antialiaseds' not in kwargs and ec.lower() == "none":
        kwargs['antialiaseds'] = False

    if shading == 'gouraud':
        if facecolors is not None:
            raise ValueError('Gouraud shading does not support the use '
                             'of facecolors kwarg')
        if len(C) != len(tri.x):
            raise ValueError('For gouraud shading, the length of color '
                             'values array must be the same as the '
                             'number of triangulation points')
        collection = TriMesh(tri, **kwargs)
    else:
        # Vertices of triangles.
        maskedTris = tri.get_masked_triangles()
        verts = np.stack((tri.x[maskedTris], tri.y[maskedTris]), axis=-1)

        # Color values.
        if facecolors is None:
            # One color per triangle, the mean of the 3 vertex color values.
            C = C[maskedTris].mean(axis=1)
        elif tri.mask is not None:
            # Remove color values of masked triangles.
            C = C[~tri.mask]

        collection = PolyCollection(verts, **kwargs)

    collection.set_alpha(alpha)
    collection.set_array(C)
    _api.check_isinstance((Normalize, None), norm=norm)
    collection.set_cmap(cmap)
    collection.set_norm(norm)
    collection._scale_norm(norm, vmin, vmax)
    ax.grid(False)

    minx = tri.x.min()
    maxx = tri.x.max()
    miny = tri.y.min()
    maxy = tri.y.max()
    corners = (minx, miny), (maxx, maxy)
    ax.update_datalim(corners)
    ax.autoscale_view()
    ax.add_collection(collection)
    return collection
Example #31
0
def triplot(ax, *args, **kwargs):
    """
    Draw an unstructured triangular grid as lines and/or markers.

    Call signatures::

      triplot(triangulation, ...)
      triplot(x, y, [triangles], *, [mask=mask], ...)

    The triangular grid can be specified either by passing a `.Triangulation`
    object as the first parameter, or by passing the points *x*, *y* and
    optionally the *triangles* and a *mask*. If neither of *triangulation* or
    *triangles* are given, the triangulation is calculated on the fly.

    Parameters
    ----------
    triangulation : `.Triangulation`
        An already created triangular grid.
    x, y, triangles, mask
        Parameters defining the triangular grid. See `.Triangulation`.
        This is mutually exclusive with specifying *triangulation*.
    other_parameters
        All other args and kwargs are forwarded to `~.Axes.plot`.

    Returns
    -------
    lines : `~matplotlib.lines.Line2D`
        The drawn triangles edges.
    markers : `~matplotlib.lines.Line2D`
        The drawn marker nodes.
    """
    import matplotlib.axes

    tri, args, kwargs = Triangulation.get_from_args_and_kwargs(*args, **kwargs)
    x, y, edges = (tri.x, tri.y, tri.edges)

    # Decode plot format string, e.g., 'ro-'
    fmt = args[0] if args else ""
    linestyle, marker, color = matplotlib.axes._base._process_plot_format(fmt)

    # Insert plot format string into a copy of kwargs (kwargs values prevail).
    kw = cbook.normalize_kwargs(kwargs, mlines.Line2D)
    for key, val in zip(('linestyle', 'marker', 'color'),
                        (linestyle, marker, color)):
        if val is not None:
            kw.setdefault(key, val)

    # Draw lines without markers.
    # Note 1: If we drew markers here, most markers would be drawn more than
    #         once as they belong to several edges.
    # Note 2: We insert nan values in the flattened edges arrays rather than
    #         plotting directly (triang.x[edges].T, triang.y[edges].T)
    #         as it considerably speeds-up code execution.
    linestyle = kw['linestyle']
    kw_lines = {
        **kw,
        'marker': 'None',  # No marker to draw.
        'zorder': kw.get('zorder', 1),  # Path default zorder is used.
    }
    if linestyle not in [None, 'None', '', ' ']:
        tri_lines_x = np.insert(x[edges], 2, np.nan, axis=1)
        tri_lines_y = np.insert(y[edges], 2, np.nan, axis=1)
        tri_lines = ax.plot(tri_lines_x.ravel(), tri_lines_y.ravel(),
                            **kw_lines)
    else:
        tri_lines = ax.plot([], [], **kw_lines)

    # Draw markers separately.
    marker = kw['marker']
    kw_markers = {
        **kw,
        'linestyle': 'None',  # No line to draw.
    }
    if marker not in [None, 'None', '', ' ']:
        tri_markers = ax.plot(x, y, **kw_markers)
    else:
        tri_markers = ax.plot([], [], **kw_markers)

    return tri_lines + tri_markers