Adds a unstructured, structured, or surface mesh to the
        plotting object.

        Also accepts a 3D numpy.ndarray

        Parameters
        ----------
        mesh : vtk unstructured, structured, polymesh, or 3D numpy.ndarray
            A vtk unstructured, structured, or polymesh to plot.

        color : string or 3 item list, optional, defaults to white
            Either a string, rgb list, or hex color string.  For example:
                color='white'
                color='w'
                color=[1, 1, 1]
                color='#FFFFFF'

            Color will be overridden when scalars are input.

        style : string, optional
            Visualization style of the vtk mesh.  One for the following:
                style='surface'
                style='wireframe'
                style='points'

            Defaults to 'surface'

        scalars : numpy array, optional
            Scalars used to "color" the mesh.  Accepts an array equal
            to the number of cells or the number of points in the
            mesh.  Array should be sized as a single vector. If both
            color and scalars are None, then the active scalars are
            used

        rng : 2 item list, optional
            Range of mapper for scalars.  Defaults to minimum and
            maximum of scalars array.  Example: ``[-1, 2]``. ``clim``
            is also an accepted alias for this.

        stitle : string, optional
            Scalar title.  By default there is no scalar legend bar.
            Setting this creates the legend bar and adds a title to
            it.  To create a bar with no title, use an empty string
            (i.e. '').

        show_edges : bool, optional
            Shows the edges of a mesh.  Does not apply to a wireframe
            representation.

        point_size : float, optional
            Point size.  Applicable when style='points'.  Default 5.0

        opacity : float, optional
            Opacity of mesh.  Should be between 0 and 1.  Default 1.0.
            A string option can also be specified to map the scalar range
            to the opacity. Options are: linear, linear_r, geom, geom_r

        line_width : float, optional
            Thickness of lines.  Only valid for wireframe and surface
            representations.  Default None.

        flip_scalars : bool, optional
            Flip direction of cmap.

        lighting : bool, optional
            Enable or disable view direction lighting.  Default False.

        n_colors : int, optional
            Number of colors to use when displaying scalars.  Default
            256.

        interpolate_before_map : bool, optional
            Enabling makes for a smoother scalar display.  Default
            False

        cmap : str, optional
           cmap string.  See available matplotlib cmaps.  Only
           applicable for when displaying scalars.  Defaults None
           (rainbow).  Requires matplotlib.

        multi_colors : bool, optional
            If a ``MultiBlock`` dataset is given this will color each
            block by a solid color using matplotlib's color cycler.

        name : str, optional
            The name for the added mesh/actor so that it can be easily
            updated.  If an actor of this name already exists in the
            rendering window, it will be replaced by the new actor.

        texture : vtk.vtkTexture or np.ndarray or boolean, optional
            A texture to apply if the input mesh has texture
            coordinates.  This will not work with MultiBlock
            datasets. If set to ``True``, the first avaialble texture
            on the object will be used. If a string name is given, it
            will pull a texture with that name associated to the input
            mesh.

        ambient : float, optional
            When lighting is enabled, this is the amount of light from
            0 to 1 that reaches the actor when not directed at the
            light source emitted from the viewer.  Default 0.2.

        nan_color : string or 3 item list, optional, defaults to gray
            The color to use for all NaN values in the plotted scalar
            array.

        nan_opacity : float, optional
            Opacity of NaN values.  Should be between 0 and 1.
            Default 1.0

        backface_culling : bool optional
            Does not render faces that should not be visible to the
            plotter.  This can be helpful for dense surface meshes,
            especially when edges are visible, but can cause flat
            meshes to be partially displayed.  Default False.

        rgb : bool, optional
            If an 2 dimensional array is passed as the scalars, plot those
            values as RGB+A colors! ``rgba`` is also accepted alias for this.

        categories : bool, optional
            If fetching a colormap from matplotlib, this is the number of
            categories to use in that colormap. If set to ``True``, then
            the number of unique values in the scalar array will be used.

        Returns
        -------
        actor: vtk.vtkActor
            VTK actor of the mesh.

def add_mesh(self, mesh, color=None, style=None, scalars=None,
                 rng=None, stitle=None, show_edges=None,
                 point_size=5.0, opacity=1.0, line_width=None,
                 flip_scalars=False, lighting=None, n_colors=256,
                 interpolate_before_map=False, cmap=None, label=None,
                 reset_camera=None, scalar_bar_args=None,
                 multi_colors=False, name=None, texture=None,
                 render_points_as_spheres=None,
                 render_lines_as_tubes=False, edge_color='black',
                 ambient=0.0, show_scalar_bar=None, nan_color=None,
                 nan_opacity=1.0, loc=None, backface_culling=False,
                 rgb=False, categories=False, **kwargs):
        """
        Adds a unstructured, structured, or surface mesh to the
        plotting object.

        Also accepts a 3D numpy.ndarray

        Parameters
        ----------
        mesh : vtk unstructured, structured, polymesh, or 3D numpy.ndarray
            A vtk unstructured, structured, or polymesh to plot.

        color : string or 3 item list, optional, defaults to white
            Either a string, rgb list, or hex color string.  For example:
                color='white'
                color='w'
                color=[1, 1, 1]
                color='#FFFFFF'

            Color will be overridden when scalars are input.

        style : string, optional
            Visualization style of the vtk mesh.  One for the following:
                style='surface'
                style='wireframe'
                style='points'

            Defaults to 'surface'

        scalars : numpy array, optional
            Scalars used to "color" the mesh.  Accepts an array equal
            to the number of cells or the number of points in the
            mesh.  Array should be sized as a single vector. If both
            color and scalars are None, then the active scalars are
            used

        rng : 2 item list, optional
            Range of mapper for scalars.  Defaults to minimum and
            maximum of scalars array.  Example: ``[-1, 2]``. ``clim``
            is also an accepted alias for this.

        stitle : string, optional
            Scalar title.  By default there is no scalar legend bar.
            Setting this creates the legend bar and adds a title to
            it.  To create a bar with no title, use an empty string
            (i.e. '').

        show_edges : bool, optional
            Shows the edges of a mesh.  Does not apply to a wireframe
            representation.

        point_size : float, optional
            Point size.  Applicable when style='points'.  Default 5.0

        opacity : float, optional
            Opacity of mesh.  Should be between 0 and 1.  Default 1.0.
            A string option can also be specified to map the scalar range
            to the opacity. Options are: linear, linear_r, geom, geom_r

        line_width : float, optional
            Thickness of lines.  Only valid for wireframe and surface
            representations.  Default None.

        flip_scalars : bool, optional
            Flip direction of cmap.

        lighting : bool, optional
            Enable or disable view direction lighting.  Default False.

        n_colors : int, optional
            Number of colors to use when displaying scalars.  Default
            256.

        interpolate_before_map : bool, optional
            Enabling makes for a smoother scalar display.  Default
            False

        cmap : str, optional
           cmap string.  See available matplotlib cmaps.  Only
           applicable for when displaying scalars.  Defaults None
           (rainbow).  Requires matplotlib.

        multi_colors : bool, optional
            If a ``MultiBlock`` dataset is given this will color each
            block by a solid color using matplotlib's color cycler.

        name : str, optional
            The name for the added mesh/actor so that it can be easily
            updated.  If an actor of this name already exists in the
            rendering window, it will be replaced by the new actor.

        texture : vtk.vtkTexture or np.ndarray or boolean, optional
            A texture to apply if the input mesh has texture
            coordinates.  This will not work with MultiBlock
            datasets. If set to ``True``, the first avaialble texture
            on the object will be used. If a string name is given, it
            will pull a texture with that name associated to the input
            mesh.

        ambient : float, optional
            When lighting is enabled, this is the amount of light from
            0 to 1 that reaches the actor when not directed at the
            light source emitted from the viewer.  Default 0.2.

        nan_color : string or 3 item list, optional, defaults to gray
            The color to use for all NaN values in the plotted scalar
            array.

        nan_opacity : float, optional
            Opacity of NaN values.  Should be between 0 and 1.
            Default 1.0

        backface_culling : bool optional
            Does not render faces that should not be visible to the
            plotter.  This can be helpful for dense surface meshes,
            especially when edges are visible, but can cause flat
            meshes to be partially displayed.  Default False.

        rgb : bool, optional
            If an 2 dimensional array is passed as the scalars, plot those
            values as RGB+A colors! ``rgba`` is also accepted alias for this.

        categories : bool, optional
            If fetching a colormap from matplotlib, this is the number of
            categories to use in that colormap. If set to ``True``, then
            the number of unique values in the scalar array will be used.

        Returns
        -------
        actor: vtk.vtkActor
            VTK actor of the mesh.
        """
        # fixes lighting issue when using precalculated normals
        if isinstance(mesh, vtk.vtkPolyData):
            if mesh.GetPointData().HasArray('Normals'):
                mesh.point_arrays['Normals'] = mesh.point_arrays.pop('Normals')

        if scalar_bar_args is None:
            scalar_bar_args = {}

        if isinstance(mesh, np.ndarray):
            mesh = vtki.PolyData(mesh)
            style = 'points'

        # Convert the VTK data object to a vtki wrapped object if neccessary
        if not is_vtki_obj(mesh):
            mesh = wrap(mesh)

        if show_edges is None:
            show_edges = rcParams['show_edges']

        if show_scalar_bar is None:
            show_scalar_bar = rcParams['show_scalar_bar']

        if lighting is None:
            lighting = rcParams['lighting']

        if rng is None:
            rng = kwargs.get('clim', None)

        if render_points_as_spheres is None:
            render_points_as_spheres = rcParams['render_points_as_spheres']

        if name is None:
            name = '{}({})'.format(type(mesh).__name__, str(hex(id(mesh))))

        if isinstance(mesh, vtki.MultiBlock):
            self.remove_actor(name, reset_camera=reset_camera)
            # frist check the scalars
            if rng is None and scalars is not None:
                # Get the data range across the array for all blocks
                # if scalar specified
                if isinstance(scalars, str):
                    rng = mesh.get_data_range(scalars)
                else:
                    # TODO: an array was given... how do we deal with
                    #       that? Possibly a 2D arrays or list of
                    #       arrays where first index corresponds to
                    #       the block? This could get complicated real
                    #       quick.
                    raise RuntimeError('Scalar array must be given as a string name for multiblock datasets.')
            if multi_colors:
                # Compute unique colors for each index of the block
                try:
                    import matplotlib as mpl
                    from itertools import cycle
                    cycler = mpl.rcParams['axes.prop_cycle']
                    colors = cycle(cycler)
                except ImportError:
                    multi_colors = False
                    logging.warning('Please install matplotlib for color cycles')
            # Now iteratively plot each element of the multiblock dataset
            actors = []
            for idx in range(mesh.GetNumberOfBlocks()):
                if mesh[idx] is None:
                    continue
                # Get a good name to use
                next_name = '{}-{}'.format(name, idx)
                # Get the data object
                if not is_vtki_obj(mesh[idx]):
                    data = wrap(mesh.GetBlock(idx))
                    if not is_vtki_obj(mesh[idx]):
                        continue # move on if we can't plot it
                else:
                    data = mesh.GetBlock(idx)
                if data is None:
                    # Note that a block can exist but be None type
                    continue
                # Now check that scalars is available for this dataset
                if isinstance(data, vtk.vtkMultiBlockDataSet) or get_scalar(data, scalars) is None:
                    ts = None
                else:
                    ts = scalars
                if multi_colors:
                    color = next(colors)['color']
                a = self.add_mesh(data, color=color, style=style,
                                  scalars=ts, rng=rng, stitle=stitle,
                                  show_edges=show_edges,
                                  point_size=point_size, opacity=opacity,
                                  line_width=line_width,
                                  flip_scalars=flip_scalars,
                                  lighting=lighting, n_colors=n_colors,
                                  interpolate_before_map=interpolate_before_map,
                                  cmap=cmap, label=label,
                                  scalar_bar_args=scalar_bar_args,
                                  reset_camera=reset_camera, name=next_name,
                                  texture=None,
                                  render_points_as_spheres=render_points_as_spheres,
                                  render_lines_as_tubes=render_lines_as_tubes,
                                  edge_color=edge_color,
                                  show_scalar_bar=show_scalar_bar, nan_color=nan_color,
                                  nan_opacity=nan_opacity,
                                  loc=loc, rgb=rgb, **kwargs)
                actors.append(a)
                if (reset_camera is None and not self.camera_set) or reset_camera:
                    cpos = self.get_default_cam_pos()
                    self.camera_position = cpos
                    self.camera_set = False
                    self.reset_camera()
            return actors

        if nan_color is None:
            nan_color = rcParams['nan_color']
        nanr, nanb, nang = parse_color(nan_color)
        nan_color = nanr, nanb, nang, nan_opacity
        if color is True:
            color = rcParams['color']

        if mesh.n_points < 1:
            raise RuntimeError('Empty meshes cannot be plotted. Input mesh has zero points.')

        # set main values
        self.mesh = mesh
        self.mapper = vtk.vtkDataSetMapper()
        self.mapper.SetInputData(self.mesh)
        if isinstance(scalars, str):
            self.mapper.SetArrayName(scalars)

        actor, prop = self.add_actor(self.mapper,
                                     reset_camera=reset_camera,
                                     name=name, loc=loc, culling=backface_culling)

        # Try to plot something if no preference given
        if scalars is None and color is None and texture is None:
            # Prefer texture first
            if len(list(mesh.textures.keys())) > 0:
                texture = True
            # If no texture, plot any active scalar
            else:
                # Make sure scalar components are not vectors/tuples
                scalars = mesh.active_scalar
                if scalars is None:# or scalars.ndim != 1:
                    scalars = None
                else:
                    if stitle is None:
                        stitle = mesh.active_scalar_info[1]

        if texture == True or isinstance(texture, (str, int)):
            texture = mesh._activate_texture(texture)

        if texture:
            if isinstance(texture, np.ndarray):
                texture = numpy_to_texture(texture)
            if not isinstance(texture, (vtk.vtkTexture, vtk.vtkOpenGLTexture)):
                raise TypeError('Invalid texture type ({})'.format(type(texture)))
            if mesh.GetPointData().GetTCoords() is None:
                raise AssertionError('Input mesh does not have texture coordinates to support the texture.')
            actor.SetTexture(texture)
            # Set color to white by default when using a texture
            if color is None:
                color = 'white'
            if scalars is None:
                show_scalar_bar = False
            self.mapper.SetScalarModeToUsePointFieldData()

        # Scalar formatting ===================================================
        if cmap is None: # grab alias for cmaps: colormap
            cmap = kwargs.get('colormap', None)
        if cmap is None: # Set default map if matplotlib is avaialble
            try:
                import matplotlib
                cmap = rcParams['cmap']
            except ImportError:
                pass
        title = 'Data' if stitle is None else stitle
        if scalars is not None:
            # if scalars is a string, then get the first array found with that name
            append_scalars = True
            if isinstance(scalars, str):
                title = scalars
                scalars = get_scalar(mesh, scalars,
                        preference=kwargs.get('preference', 'cell'), err=True)
                if stitle is None:
                    stitle = title
                #append_scalars = False

            if not isinstance(scalars, np.ndarray):
                scalars = np.asarray(scalars)

            if rgb is False or rgb is None:
                rgb = kwargs.get('rgba', False)
            if rgb:
                if scalars.ndim != 2 or scalars.shape[1] < 3 or scalars.shape[1] > 4:
                    raise ValueError('RGB array must be n_points/n_cells by 3/4 in shape.')

            if scalars.ndim != 1:
                if rgb:
                    pass
                elif scalars.ndim == 2 and (scalars.shape[0] == mesh.n_points or scalars.shape[0] == mesh.n_cells):
                    scalars = np.linalg.norm(scalars.copy(), axis=1)
                    title = '{}-normed'.format(title)
                else:
                    scalars = scalars.ravel()

            if scalars.dtype == np.bool:
                scalars = scalars.astype(np.float)

            # Scalar interpolation approach
            if scalars.shape[0] == mesh.n_points:
                self.mesh._add_point_scalar(scalars, title, append_scalars)
                self.mapper.SetScalarModeToUsePointData()
                self.mapper.GetLookupTable().SetNumberOfTableValues(n_colors)
                if interpolate_before_map:
                    self.mapper.InterpolateScalarsBeforeMappingOn()
            elif scalars.shape[0] == mesh.n_cells:
                self.mesh._add_cell_scalar(scalars, title, append_scalars)
                self.mapper.SetScalarModeToUseCellData()
                self.mapper.GetLookupTable().SetNumberOfTableValues(n_colors)
                if interpolate_before_map:
                    self.mapper.InterpolateScalarsBeforeMappingOn()
            else:
                _raise_not_matching(scalars, mesh)

            # Set scalar range
            if rng is None:
                rng = [np.nanmin(scalars), np.nanmax(scalars)]
            elif isinstance(rng, float) or isinstance(rng, int):
                rng = [-rng, rng]

            if np.any(rng) and not rgb:
                self.mapper.SetScalarRange(rng[0], rng[1])

            # Flip if requested
            table = self.mapper.GetLookupTable()
            table.SetNanColor(nan_color)
            if cmap is not None:
                try:
                    from matplotlib.cm import get_cmap
                except ImportError:
                    cmap = None
                    logging.warning('Please install matplotlib for color maps.')
            if cmap is not None:
                try:
                    from matplotlib.cm import get_cmap
                except ImportError:
                    raise Exception('cmap requires matplotlib')
                if isinstance(cmap, str):
                    if categories:
                        if categories is True:
                            categories = len(np.unique(scalars))
                        cmap = get_cmap(cmap, categories)
                    else:
                        cmap = get_cmap(cmap)
                    # ELSE: assume cmap is callable
                ctable = cmap(np.linspace(0, 1, n_colors))*255
                ctable = ctable.astype(np.uint8)
                # Set opactities
                if isinstance(opacity, str):
                    ctable[:,-1] = opacity_transfer_function(opacity, n_colors)
                if flip_scalars:
                    ctable = np.ascontiguousarray(ctable[::-1])
                table.SetTable(VN.numpy_to_vtk(ctable))

            else:  # no cmap specified
                if flip_scalars:
                    table.SetHueRange(0.0, 0.66667)
                else:
                    table.SetHueRange(0.66667, 0.0)

        else:
            self.mapper.SetScalarModeToUseFieldData()

        # select view style
        if not style:
            style = 'surface'
        style = style.lower()
        if style == 'wireframe':
            prop.SetRepresentationToWireframe()
            if color is None:
                color = rcParams['outline_color']
        elif style == 'points':
            prop.SetRepresentationToPoints()
        elif style == 'surface':
            prop.SetRepresentationToSurface()
        else:
            raise Exception('Invalid style.  Must be one of the following:\n' +
                            '\t"surface"\n' +
                            '\t"wireframe"\n' +
                            '\t"points"\n')

        prop.SetPointSize(point_size)
        prop.SetAmbient(ambient)
        # edge display style
        if show_edges:
            prop.EdgeVisibilityOn()

        rgb_color = parse_color(color)
        prop.SetColor(rgb_color)
        if isinstance(opacity, (float, int)):
            prop.SetOpacity(opacity)
        prop.SetEdgeColor(parse_color(edge_color))

        if render_points_as_spheres:
            prop.SetRenderPointsAsSpheres(render_points_as_spheres)
        if render_lines_as_tubes:
            prop.SetRenderLinesAsTubes(render_lines_as_tubes)

        # legend label
        if label:
            if not isinstance(label, str):
                raise AssertionError('Label must be a string')
            geom = single_triangle()
            if scalars is not None:
                geom = vtki.Box()
                rgb_color = parse_color('black')
            self._labels.append([geom, label, rgb_color])

        # lighting display style
        if not lighting:
            prop.LightingOff()

        # set line thickness
        if line_width:
            prop.SetLineWidth(line_width)

        # Add scalar bar if available
        if stitle is not None and show_scalar_bar and not rgb:
            self.add_scalar_bar(stitle, **scalar_bar_args)

        return actor