def _acted_upon_(self, g, self_on_left): r""" Implements the left action of `SL_2(\ZZ)` on self. EXAMPLES:: sage: g = matrix(ZZ, 2, [1,1,0,1]); g [1 1] [0 1] sage: g * Cusp(2,5) 7/5 sage: Cusp(2,5) * g Traceback (most recent call last): ... TypeError: unsupported operand parent(s) for '*': 'Set P^1(QQ) of all cusps' and 'Full MatrixSpace of 2 by 2 dense matrices over Integer Ring' sage: h = matrix(ZZ, 2, [12,3,-100,7]) sage: h * Cusp(2,5) -13/55 sage: Cusp(2,5)._acted_upon_(h, False) -13/55 sage: (h*g) * Cusp(3,7) == h * (g * Cusp(3,7)) True sage: cm = sage.structure.element.get_coercion_model() sage: cm.explain(MatrixSpace(ZZ, 2), Cusps) Action discovered. Left action by Full MatrixSpace of 2 by 2 dense matrices over Integer Ring on Set P^1(QQ) of all cusps Result lives in Set P^1(QQ) of all cusps Set P^1(QQ) of all cusps """ if not self_on_left: if (is_Matrix(g) and g.base_ring() is ZZ and g.ncols() == 2 and g.nrows() == 2): a, b, c, d = g.list() return Cusp(a*self.__a + b*self.__b, c*self.__a + d*self.__b)
def __init__(self, parent, A): """ INPUT: - ``parent`` - a homspace - ``A`` - matrix EXAMPLES:: sage: from sage.modules.matrix_morphism import MatrixMorphism sage: T = End(ZZ^3) sage: M = MatrixSpace(ZZ,3) sage: I = M.identity_matrix() sage: A = MatrixMorphism(T, I) sage: loads(A.dumps()) == A True """ if not matrix.is_Matrix(A): A = matrix.MatrixSpace(parent.category().base_ring(), parent.domain().rank(), parent.codomain().rank())(A) R = A.base_ring() if A.nrows() != parent.domain().rank(): raise ArithmeticError, "number of rows of matrix (=%s) must equal rank of domain (=%s)"%(A.nrows(), parent.domain().rank()) if A.ncols() != parent.codomain().rank(): raise ArithmeticError, "number of columns of matrix (=%s) must equal rank of codomain (=%s)"%(A.ncols(), parent.codomain().rank()) self._matrix = A MatrixMorphism_abstract.__init__(self, parent)
def __init__(self, parent, A): """ INPUT: - ``parent`` - a homspace - ``A`` - matrix EXAMPLES:: sage: from sage.modules.matrix_morphism import MatrixMorphism sage: T = End(ZZ^3) sage: M = MatrixSpace(ZZ,3) sage: I = M.identity_matrix() sage: A = MatrixMorphism(T, I) sage: loads(A.dumps()) == A True """ if not matrix.is_Matrix(A): A = matrix.MatrixSpace(parent.category().base_ring(), parent.domain().rank(), parent.codomain().rank())(A) R = A.base_ring() if A.nrows() != parent.domain().rank(): raise ArithmeticError, "number of rows of matrix (=%s) must equal rank of domain (=%s)" % ( A.nrows(), parent.domain().rank()) if A.ncols() != parent.codomain().rank(): raise ArithmeticError, "number of columns of matrix (=%s) must equal rank of codomain (=%s)" % ( A.ncols(), parent.codomain().rank()) self._matrix = A MatrixMorphism_abstract.__init__(self, parent)
def normalize_square_matrices(matrices): """ Find a common space for all matrices. OUTPUT: A list of matrices, all elements of the same matrix space. EXAMPLES:: sage: from sage.groups.matrix_gps.finitely_generated import normalize_square_matrices sage: m1 = [[1,2],[3,4]] sage: m2 = [2, 3, 4, 5] sage: m3 = matrix(QQ, [[1/2,1/3],[1/4,1/5]]) sage: m4 = MatrixGroup(m3).gen(0) sage: normalize_square_matrices([m1, m2, m3, m4]) [ [1 2] [2 3] [1/2 1/3] [1/2 1/3] [3 4], [4 5], [1/4 1/5], [1/4 1/5] ] """ deg = [] gens = [] for m in matrices: if is_MatrixGroupElement(m): deg.append(m.parent().degree()) gens.append(m.matrix()) continue if is_Matrix(m): if not m.is_square(): raise TypeError('matrix must be square') deg.append(m.ncols()) gens.append(m) continue try: m = list(m) except TypeError: gens.append(m) continue if isinstance(m[0], (list, tuple)): m = map(list, m) degree = ZZ(len(m)) else: degree, rem = ZZ(len(m)).sqrtrem() if rem != 0: raise ValueError( 'list of plain numbers must have square integer length') deg.append(degree) gens.append(matrix(degree, degree, m)) deg = set(deg) if len(set(deg)) != 1: raise ValueError('not all matrices have the same size') gens = Sequence(gens, immutable=True) MS = gens.universe() if not is_MatrixSpace(MS): raise TypeError('all generators must be matrices') if MS.nrows() != MS.ncols(): raise ValueError('matrices must be square') return gens
def normalize_square_matrices(matrices): """ Find a common space for all matrices. OUTPUT: A list of matrices, all elements of the same matrix space. EXAMPLES:: sage: from sage.groups.matrix_gps.finitely_generated import normalize_square_matrices sage: m1 = [[1,2],[3,4]] sage: m2 = [2, 3, 4, 5] sage: m3 = matrix(QQ, [[1/2,1/3],[1/4,1/5]]) sage: m4 = MatrixGroup(m3).gen(0) sage: normalize_square_matrices([m1, m2, m3, m4]) [ [1 2] [2 3] [1/2 1/3] [1/2 1/3] [3 4], [4 5], [1/4 1/5], [1/4 1/5] ] """ deg = [] gens = [] for m in matrices: if is_MatrixGroupElement(m): deg.append(m.parent().degree()) gens.append(m.matrix()) continue if is_Matrix(m): if not m.is_square(): raise TypeError('matrix must be square') deg.append(m.ncols()) gens.append(m) continue try: m = list(m) except TypeError: gens.append(m) continue if isinstance(m[0], (list, tuple)): m = map(list, m) degree = ZZ(len(m)) else: degree, rem = ZZ(len(m)).sqrtrem() if rem!=0: raise ValueError('list of plain numbers must have square integer length') deg.append(degree) gens.append(matrix(degree, degree, m)) deg = set(deg) if len(set(deg)) != 1: raise ValueError('not all matrices have the same size') gens = Sequence(gens, immutable=True) MS = gens.universe() if not is_MatrixSpace(MS): raise TypeError('all generators must be matrices') if MS.nrows() != MS.ncols(): raise ValueError('matrices must be square') return gens
def jacobian(functions, variables): """ Return the Jacobian matrix, which is the matrix of partial derivatives in which the i,j entry of the Jacobian matrix is the partial derivative diff(functions[i], variables[j]). EXAMPLES:: sage: x,y = var('x,y') sage: g=x^2-2*x*y sage: jacobian(g, (x,y)) [2*x - 2*y -2*x] The Jacobian of the Jacobian should give us the "second derivative", which is the Hessian matrix:: sage: jacobian(jacobian(g, (x,y)), (x,y)) [ 2 -2] [-2 0] sage: g.hessian() [ 2 -2] [-2 0] sage: f=(x^3*sin(y), cos(x)*sin(y), exp(x)) sage: jacobian(f, (x,y)) [ 3*x^2*sin(y) x^3*cos(y)] [-sin(x)*sin(y) cos(x)*cos(y)] [ e^x 0] sage: jacobian(f, (y,x)) [ x^3*cos(y) 3*x^2*sin(y)] [ cos(x)*cos(y) -sin(x)*sin(y)] [ 0 e^x] """ if is_Matrix(functions) and (functions.nrows() == 1 or functions.ncols() == 1): functions = functions.list() elif not (isinstance(functions, (tuple, list)) or is_Vector(functions)): functions = [functions] if not isinstance(variables, (tuple, list)) and not is_Vector(variables): variables = [variables] return matrix([[diff(f, v) for v in variables] for f in functions])
def jacobian(functions, variables): """ Return the Jacobian matrix, which is the matrix of partial derivatives in which the i,j entry of the Jacobian matrix is the partial derivative diff(functions[i], variables[j]). EXAMPLES:: sage: x,y = var('x,y') sage: g=x^2-2*x*y sage: jacobian(g, (x,y)) [2*x - 2*y -2*x] The Jacobian of the Jacobian should give us the "second derivative", which is the Hessian matrix:: sage: jacobian(jacobian(g, (x,y)), (x,y)) [ 2 -2] [-2 0] sage: g.hessian() [ 2 -2] [-2 0] sage: f=(x^3*sin(y), cos(x)*sin(y), exp(x)) sage: jacobian(f, (x,y)) [ 3*x^2*sin(y) x^3*cos(y)] [-sin(x)*sin(y) cos(x)*cos(y)] [ e^x 0] sage: jacobian(f, (y,x)) [ x^3*cos(y) 3*x^2*sin(y)] [ cos(x)*cos(y) -sin(x)*sin(y)] [ 0 e^x] """ if is_Matrix(functions) and (functions.nrows()==1 or functions.ncols()==1): functions = functions.list() elif not (isinstance(functions, (tuple, list)) or is_Vector(functions)): functions = [functions] if not isinstance(variables, (tuple, list)) and not is_Vector(variables): variables = [variables] return matrix([[diff(f, v) for v in variables] for f in functions])
def matrix_plot(mat, **options): r""" A plot of a given matrix or 2D array. If the matrix is dense, each matrix element is given a different color value depending on its relative size compared to the other elements in the matrix. If the matrix is sparse, colors only indicate whether an element is nonzero or zero, so the plot represents the sparsity pattern of the matrix. The tick marks drawn on the frame axes denote the row numbers (vertical ticks) and the column numbers (horizontal ticks) of the matrix. INPUT: - ``mat`` - a 2D matrix or array The following input must all be passed in as named parameters, if default not used: - ``cmap`` - a colormap (default: 'gray'), the name of a predefined colormap, a list of colors, or an instance of a matplotlib Colormap. Type: ``import matplotlib.cm; matplotlib.cm.datad.keys()`` for available colormap names. - ``colorbar`` -- boolean (default: False) Show a colorbar or not (dense matrices only). The following options are used to adjust the style and placement of colorbars. They have no effect if a colorbar is not shown. - ``colorbar_orientation`` -- string (default: 'vertical'), controls placement of the colorbar, can be either 'vertical' or 'horizontal' - ``colorbar_format`` -- a format string, this is used to format the colorbar labels. - ``colorbar_options`` -- a dictionary of options for the matplotlib colorbar API. Documentation for the :mod:`matplotlib.colorbar` module has details. - ``norm`` - If None (default), the value range is scaled to the interval [0,1]. If 'value', then the actual value is used with no scaling. A :class:`matplotlib.colors.Normalize` instance may also passed. - ``vmin`` - The minimum value (values below this are set to this value) - ``vmax`` - The maximum value (values above this are set to this value) - ``origin`` - If 'upper' (default), the first row of the matrix is on the top of the graph. If 'lower', the first row is on the bottom of the graph. - ``subdivisions`` - If True, plot the subdivisions of the matrix as lines. - ``subdivision_boundaries`` - a list of lists in the form ``[row_subdivisions, column_subdivisions]``, which specifies the row and column subdivisions to use. If not specified, defaults to the matrix subdivisions - ``subdivision_style`` - a dictionary of properties passed on to the :func:`~sage.plot.line.line2d` command for plotting subdivisions. If this is a two-element list or tuple, then it specifies the styles of row and column divisions, respectively. EXAMPLES: A matrix over `\ZZ` colored with different grey levels:: sage: matrix_plot(matrix([[1,3,5,1],[2,4,5,6],[1,3,5,7]])) Here we make a random matrix over `\RR` and use ``cmap='hsv'`` to color the matrix elements different RGB colors:: sage: matrix_plot(random_matrix(RDF, 50), cmap='hsv') By default, entries are scaled to the interval [0,1] before determining colors from the color map. That means the two plots below are the same:: sage: P = matrix_plot(matrix(2,[1,1,3,3])) sage: Q = matrix_plot(matrix(2,[2,2,3,3])) sage: P; Q However, we can specify which values scale to 0 or 1 with the ``vmin`` and ``vmax`` parameters (values outside the range are clipped). The two plots below are now distinguished:: sage: P = matrix_plot(matrix(2,[1,1,3,3]), vmin=0, vmax=3, colorbar=True) sage: Q = matrix_plot(matrix(2,[2,2,3,3]), vmin=0, vmax=3, colorbar=True) sage: P; Q We can also specify a norm function of 'value', which means that there is no scaling performed:: sage: matrix_plot(random_matrix(ZZ,10)*.05, norm='value', colorbar=True) Matrix subdivisions can be plotted as well:: sage: m=random_matrix(RR,10) sage: m.subdivide([2,4],[6,8]) sage: matrix_plot(m, subdivisions=True, subdivision_style=dict(color='red',thickness=3)) You can also specify your own subdivisions and separate styles for row or column subdivisions:: sage: m=random_matrix(RR,10) sage: matrix_plot(m, subdivisions=True, subdivision_boundaries=[[2,4],[6,8]], subdivision_style=[dict(color='red',thickness=3),dict(linestyle='--',thickness=6)]) Generally matrices are plotted with the (0,0) entry in the upper left. However, sometimes if we are plotting an image, we'd like the (0,0) entry to be in the lower left. We can do that with the ``origin`` argument:: sage: matrix_plot(identity_matrix(100), origin='lower') Another random plot, but over `\GF{389}`:: sage: m = random_matrix(GF(389), 10) sage: matrix_plot(m, cmap='Oranges') It also works if you lift it to the polynomial ring:: sage: matrix_plot(m.change_ring(GF(389)['x']), cmap='Oranges') We have several options for colorbars:: sage: matrix_plot(random_matrix(RDF, 50), colorbar=True, colorbar_orientation='horizontal') :: sage: matrix_plot(random_matrix(RDF, 50), colorbar=True, colorbar_format='%.3f') The length of a color bar and the length of the adjacent matrix plot dimension may be quite different. This example shows how to adjust the length of the colorbar by passing a dictionary of options to the matplotlib colorbar routines. :: sage: m = random_matrix(ZZ, 40, 80, x=-10, y=10) sage: m.plot(colorbar=True, colorbar_orientation='vertical', ... colorbar_options={'shrink':0.50}) Here we plot a random sparse matrix:: sage: sparse = matrix(dict([((randint(0, 10), randint(0, 10)), 1) for i in xrange(100)])) sage: matrix_plot(sparse) :: sage: A=random_matrix(ZZ,100000,density=.00001,sparse=True) sage: matrix_plot(A,marker=',') As with dense matrices, sparse matrix entries are automatically converted to floating point numbers before plotting. Thus the following works:: sage: b=random_matrix(GF(2),200,sparse=True,density=0.01) sage: matrix_plot(b) While this returns an error:: sage: b=random_matrix(CDF,200,sparse=True,density=0.01) sage: matrix_plot(b) Traceback (most recent call last): ... ValueError: can not convert entries to floating point numbers To plot the absolute value of a complex matrix, use the ``apply_map`` method:: sage: b=random_matrix(CDF,200,sparse=True,density=0.01) sage: matrix_plot(b.apply_map(abs)) Plotting lists of lists also works:: sage: matrix_plot([[1,3,5,1],[2,4,5,6],[1,3,5,7]]) As does plotting of NumPy arrays:: sage: import numpy sage: matrix_plot(numpy.random.rand(10, 10)) TESTS:: sage: P.<t> = RR[] sage: matrix_plot(random_matrix(P, 3, 3)) Traceback (most recent call last): ... TypeError: cannot coerce nonconstant polynomial to float :: sage: matrix_plot([1,2,3]) Traceback (most recent call last): ... TypeError: mat must be a Matrix or a two dimensional array :: sage: matrix_plot([[sin(x), cos(x)], [1, 0]]) Traceback (most recent call last): ... ValueError: can not convert entries to floating point numbers Test that sparse matrices also work with subdivisions:: sage: matrix_plot(sparse, subdivisions=True, subdivision_boundaries=[[2,4],[6,8]]) """ import numpy as np import scipy.sparse as scipysparse from sage.plot.plot import Graphics from sage.matrix.all import is_Matrix from sage.rings.all import RDF orig_mat = mat if is_Matrix(mat): sparse = mat.is_sparse() if sparse: entries = list(mat._dict().items()) try: data = np.asarray([d for _, d in entries], dtype=float) except: raise ValueError, "can not convert entries to floating point numbers" positions = np.asarray([[row for (row, col), _ in entries], [col for (row, col), _ in entries]], dtype=int) mat = scipysparse.coo_matrix((data, positions), shape=(mat.nrows(), mat.ncols())) else: mat = mat.change_ring(RDF).numpy() elif hasattr(mat, 'tocoo'): sparse = True else: sparse = False try: if sparse: xy_data_array = mat else: xy_data_array = np.asarray(mat, dtype=float) except TypeError: raise TypeError, "mat must be a Matrix or a two dimensional array" except ValueError: raise ValueError, "can not convert entries to floating point numbers" if len(xy_data_array.shape) < 2: raise TypeError, "mat must be a Matrix or a two dimensional array" xrange = (0, xy_data_array.shape[1]) yrange = (0, xy_data_array.shape[0]) if options['subdivisions'] and options['subdivision_options'][ 'boundaries'] is None: options['subdivision_options'][ 'boundaries'] = orig_mat.get_subdivisions() g = Graphics() g._set_extra_kwds(Graphics._extract_kwds_for_show(options)) g.add_primitive(MatrixPlot(xy_data_array, xrange, yrange, options)) return g
def MatrixGroup(gens): r""" Return the matrix group with given generators. INPUT: - ``gens`` - list of matrices in a matrix space or matrix group EXAMPLES:: sage: F = GF(5) sage: gens = [matrix(F,2,[1,2, -1, 1]), matrix(F,2, [1,1, 0,1])] sage: G = MatrixGroup(gens); G Matrix group over Finite Field of size 5 with 2 generators: [[[1, 2], [4, 1]], [[1, 1], [0, 1]]] In the second example, the generators are a matrix over `\ZZ`, a matrix over a finite field, and the integer `2`. Sage determines that they both canonically map to matrices over the finite field, so creates that matrix group there. :: sage: gens = [matrix(2,[1,2, -1, 1]), matrix(GF(7), 2, [1,1, 0,1]), 2] sage: G = MatrixGroup(gens); G Matrix group over Finite Field of size 7 with 3 generators: [[[1, 2], [6, 1]], [[1, 1], [0, 1]], [[2, 0], [0, 2]]] Each generator must be invertible:: sage: G = MatrixGroup([matrix(ZZ,2,[1,2,3,4])]) Traceback (most recent call last): ... ValueError: each generator must be an invertible matrix but one is not: [1 2] [3 4] Some groups aren't supported:: sage: SL(2, CC).gens() Traceback (most recent call last): ... NotImplementedError: Matrix group over Complex Field with 53 bits of precision not implemented. sage: G = SL(0, QQ) Traceback (most recent call last): ... ValueError: The degree must be at least 1 """ if len(gens) == 0: raise ValueError, "gens must have positive length" try: R = gens[0].base_ring() except AttributeError: raise TypeError, "gens must be a list of matrices" for i in range(len(gens)): if not is_Matrix(gens[i]): try: gens[i] = gens[i].matrix() except AttributeError: pass if is_FiniteField(R): return MatrixGroup_gens_finite_field(gens) else: return MatrixGroup_gens(gens)
def list_plot3d(v, interpolation_type='default', texture="automatic", point_list=None, **kwds): r""" A 3-dimensional plot of a surface defined by the list `v` of points in 3-dimensional space. INPUT: - ``v`` - something that defines a set of points in 3 space, for example: - a matrix - a list of 3-tuples - a list of lists (all of the same length) - this is treated the same as a matrix. - ``texture`` - (default: "automatic", a solid light blue) OPTIONAL KEYWORDS: - ``interpolation_type`` - 'linear', 'nn' (nearest neighbor), 'spline' 'linear' will perform linear interpolation The option 'nn' will interpolate by averaging the value of the nearest neighbors, this produces an interpolating function that is smoother than a linear interpolation, it has one derivative everywhere except at the sample points. The option 'spline' interpolates using a bivariate B-spline. When v is a matrix the default is to use linear interpolation, when v is a list of points the default is nearest neighbor. - ``degree`` - an integer between 1 and 5, controls the degree of spline used for spline interpolation. For data that is highly oscillatory use higher values - ``point_list`` - If point_list=True is passed, then if the array is a list of lists of length three, it will be treated as an array of points rather than a 3xn array. - ``num_points`` - Number of points to sample interpolating function in each direction, when ``interpolation_type`` is not ``default``. By default for an `n\times n` array this is `n`. - ``**kwds`` - all other arguments are passed to the surface function OUTPUT: a 3d plot EXAMPLES: We plot a matrix that illustrates summation modulo `n`. :: sage: n = 5; list_plot3d(matrix(RDF,n,[(i+j)%n for i in [1..n] for j in [1..n]])) We plot a matrix of values of sin. :: sage: pi = float(pi) sage: m = matrix(RDF, 6, [sin(i^2 + j^2) for i in [0,pi/5,..,pi] for j in [0,pi/5,..,pi]]) sage: list_plot3d(m, texture='yellow', frame_aspect_ratio=[1,1,1/3]) Though it doesn't change the shape of the graph, increasing num_points can increase the clarity of the graph. :: sage: list_plot3d(m, texture='yellow', frame_aspect_ratio=[1,1,1/3],num_points=40) We can change the interpolation type. :: sage: list_plot3d(m, texture='yellow', interpolation_type='nn',frame_aspect_ratio=[1,1,1/3]) We can make this look better by increasing the number of samples. :: sage: list_plot3d(m, texture='yellow', interpolation_type='nn',frame_aspect_ratio=[1,1,1/3],num_points=40) Let's try a spline. :: sage: list_plot3d(m, texture='yellow', interpolation_type='spline',frame_aspect_ratio=[1,1,1/3]) That spline doesn't capture the oscillation very well; let's try a higher degree spline. :: sage: list_plot3d(m, texture='yellow', interpolation_type='spline', degree=5, frame_aspect_ratio=[1,1,1/3]) We plot a list of lists:: sage: show(list_plot3d([[1, 1, 1, 1], [1, 2, 1, 2], [1, 1, 3, 1], [1, 2, 1, 4]])) We plot a list of points. As a first example we can extract the (x,y,z) coordinates from the above example and make a list plot out of it. By default we do linear interpolation. :: sage: l=[] sage: for i in range(6): ... for j in range(6): ... l.append((float(i*pi/5),float(j*pi/5),m[i,j])) sage: list_plot3d(l,texture='yellow') Note that the points do not have to be regularly sampled. For example:: sage: l=[] sage: for i in range(-5,5): ... for j in range(-5,5): ... l.append((normalvariate(0,1),normalvariate(0,1),normalvariate(0,1))) sage: list_plot3d(l,interpolation_type='nn',texture='yellow',num_points=100) TESTS: We plot 0, 1, and 2 points:: sage: list_plot3d([]) :: sage: list_plot3d([(2,3,4)]) :: sage: list_plot3d([(0,0,1), (2,3,4)]) However, if two points are given with the same x,y coordinates but different z coordinates, an exception will be raised:: sage: pts =[(-4/5, -2/5, -2/5), (-4/5, -2/5, 2/5), (-4/5, 2/5, -2/5), (-4/5, 2/5, 2/5), (-2/5, -4/5, -2/5), (-2/5, -4/5, 2/5), (-2/5, -2/5, -4/5), (-2/5, -2/5, 4/5), (-2/5, 2/5, -4/5), (-2/5, 2/5, 4/5), (-2/5, 4/5, -2/5), (-2/5, 4/5, 2/5), (2/5, -4/5, -2/5), (2/5, -4/5, 2/5), (2/5, -2/5, -4/5), (2/5, -2/5, 4/5), (2/5, 2/5, -4/5), (2/5, 2/5, 4/5), (2/5, 4/5, -2/5), (2/5, 4/5, 2/5), (4/5, -2/5, -2/5), (4/5, -2/5, 2/5), (4/5, 2/5, -2/5), (4/5, 2/5, 2/5)] sage: show(list_plot3d(pts, interpolation_type='nn')) Traceback (most recent call last): ... ValueError: Two points with same x,y coordinates and different z coordinates were given. Interpolation cannot handle this. Additionally we need at least 3 points to do the interpolation:: sage: mat = matrix(RDF, 1, 2, [3.2, 1.550]) sage: show(list_plot3d(mat,interpolation_type='nn')) Traceback (most recent call last): ... ValueError: We need at least 3 points to perform the interpolation """ import numpy if texture == "automatic": texture = "lightblue" if is_Matrix(v): if interpolation_type == 'default' or interpolation_type == 'linear' and not kwds.has_key( 'num_points'): return list_plot3d_matrix(v, texture=texture, **kwds) else: l = [] for i in xrange(v.nrows()): for j in xrange(v.ncols()): l.append((i, j, v[i, j])) return list_plot3d_tuples(l, interpolation_type, texture, **kwds) if type(v) == numpy.ndarray: return list_plot3d(matrix(v), interpolation_type, texture, **kwds) if isinstance(v, list): if len(v) == 0: # return empty 3d graphic from base import Graphics3d return Graphics3d() elif len(v) == 1: # return a point from shapes2 import point3d return point3d(v[0], **kwds) elif len(v) == 2: # return a line from shapes2 import line3d return line3d(v, **kwds) elif isinstance(v[0], tuple) or point_list == True and len(v[0]) == 3: return list_plot3d_tuples(v, interpolation_type, texture=texture, **kwds) else: return list_plot3d_array_of_arrays(v, interpolation_type, texture, **kwds) raise TypeError, "v must be a matrix or list"
def __call__(self, A, check=True): r""" INPUT: - A -- either a matrix or a list/tuple of images of generators, or a function returning elements of the codomain for elements of the domain. - check -- bool (default: True) If A is a matrix, then it is the matrix of this linear transformation, with respect to the basis for the domain and codomain. Thus the identity matrix always defines the identity morphism. EXAMPLES:: sage: V = (ZZ^3).span_of_basis([[1,1,0],[1,0,2]]) sage: H = V.Hom(V); H Set of Morphisms from ... sage: H([V.0,V.1]) # indirect doctest Free module morphism defined by the matrix [1 0] [0 1]... sage: phi = H([V.1,V.0]); phi Free module morphism defined by the matrix [0 1] [1 0]... sage: phi(V.1) == V.0 True sage: phi(V.0) == V.1 True The following tests against a bug that was fixed in trac ticket #9944. The method ``zero()`` calls this hom space with a function, not with a matrix, and that case had previously not been taken care of:: sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ) sage: V.Hom(V).zero() # indirect doctest Free module morphism defined by the matrix [0 0 0] [0 0 0] [0 0 0] Domain: Free module of degree 3 and rank 3 over Integer Ring Echelon ... Codomain: Free module of degree 3 and rank 3 over Integer Ring Echelon ... """ if not matrix.is_Matrix(A): # Compute the matrix of the morphism that sends the # generators of the domain to the elements of A. C = self.codomain() if isfunction(A): try: v = [C(A(g)) for g in self.domain().gens()] A = matrix.matrix([C.coordinates(a) for a in v]) except TypeError, msg: # Let us hope that FreeModuleMorphism knows to handle that case pass else: try: v = [C(a) for a in A] A = matrix.matrix([C.coordinates(a) for a in v]) except TypeError, msg: # Let us hope that FreeModuleMorphism knows to handle that case pass
def __call__(self, A, check=True): r""" INPUT: - ``A`` - one of several possible inputs representing a morphism from this vector space homspace. - a vector space morphism in this homspace - a matrix representation relative to the bases of the vector spaces, which acts on a vector placed to the left of the matrix - a list or tuple containing images of the domain's basis vectors - a function from the domain to the codomain - ``check`` (default: True) - ``True`` or ``False``, required for compatibility with calls from :meth:`sage.structure.parent_gens.ParentWithGens.hom`. EXAMPLES:: sage: V = (QQ^3).span_of_basis([[1,1,0],[1,0,2]]) sage: H = V.Hom(V) sage: H Set of Morphisms (Linear Transformations) from Vector space of degree 3 and dimension 2 over Rational Field User basis matrix: [1 1 0] [1 0 2] to Vector space of degree 3 and dimension 2 over Rational Field User basis matrix: [1 1 0] [1 0 2] Coercing a matrix:: sage: A = matrix(QQ, [[0, 1], [1, 0]]) sage: rho = H(A) # indirect doctest sage: rho Vector space morphism represented by the matrix: [0 1] [1 0] Domain: Vector space of degree 3 and dimension 2 over Rational Field User basis matrix: [1 1 0] [1 0 2] Codomain: Vector space of degree 3 and dimension 2 over Rational Field User basis matrix: [1 1 0] [1 0 2] Coercing a list of images:: sage: phi = H([V.1, V.0]) sage: phi(V.1) == V.0 True sage: phi(V.0) == V.1 True sage: phi Vector space morphism represented by the matrix: [0 1] [1 0] Domain: Vector space of degree 3 and dimension 2 over Rational Field User basis matrix: [1 1 0] [1 0 2] Codomain: Vector space of degree 3 and dimension 2 over Rational Field User basis matrix: [1 1 0] [1 0 2] Coercing a lambda function:: sage: f = lambda x: vector(QQ, [x[0], (1/2)*x[2], 2*x[1]]) sage: zeta = H(f) sage: zeta Vector space morphism represented by the matrix: [0 1] [1 0] Domain: Vector space of degree 3 and dimension 2 over Rational Field User basis matrix: [1 1 0] [1 0 2] Codomain: Vector space of degree 3 and dimension 2 over Rational Field User basis matrix: [1 1 0] [1 0 2] Coercing a vector space morphism into the parent of a second vector space morphism will unify their parents. :: sage: U = QQ^3 sage: V = QQ^4 sage: W = QQ^3 sage: X = QQ^4 sage: H = Hom(U, V) sage: K = Hom(W, X) sage: A = matrix(QQ, 3, 4, [0]*12) sage: f = H(A) sage: B = matrix(QQ, 3, 4, range(12)) sage: g = K(B) sage: f.parent() is g.parent() False sage: h = H(g) sage: f.parent() is h.parent() True See other examples in the module-level documentation. TESTS:: sage: V = GF(3)^0 sage: W = GF(3)^1 sage: H = V.Hom(W) sage: H.zero_element().is_zero() True Previously the above code resulted in a TypeError because the dimensions of the matrix were incorrect. """ import vector_space_morphism D = self.domain() C = self.codomain() if matrix.is_Matrix(A): pass elif vector_space_morphism.is_VectorSpaceMorphism(A): A = A.matrix() elif inspect.isfunction(A): try: images = [A(g) for g in D.basis()] except (ValueError, TypeError, IndexError), e: msg = 'function cannot be applied properly to some basis element because\n' + e.args[ 0] raise ValueError(msg) try: A = matrix.matrix(D.dimension(), C.dimension(), [C.coordinates(C(a)) for a in images]) except (ArithmeticError, TypeError), e: msg = 'some image of the function is not in the codomain, because\n' + e.args[ 0] raise ArithmeticError(msg)
def matrix_plot(mat, **options): r""" A plot of a given matrix or 2D array. If the matrix is dense, each matrix element is given a different color value depending on its relative size compared to the other elements in the matrix. If the matrix is sparse, colors only indicate whether an element is nonzero or zero, so the plot represents the sparsity pattern of the matrix. The tick marks drawn on the frame axes denote the row numbers (vertical ticks) and the column numbers (horizontal ticks) of the matrix. INPUT: - ``mat`` - a 2D matrix or array The following input must all be passed in as named parameters, if default not used: - ``cmap`` - a colormap (default: 'gray'), the name of a predefined colormap, a list of colors, or an instance of a matplotlib Colormap. Type: ``import matplotlib.cm; matplotlib.cm.datad.keys()`` for available colormap names. - ``colorbar`` -- boolean (default: False) Show a colorbar or not (dense matrices only). The following options are used to adjust the style and placement of colorbars. They have no effect if a colorbar is not shown. - ``colorbar_orientation`` -- string (default: 'vertical'), controls placement of the colorbar, can be either 'vertical' or 'horizontal' - ``colorbar_format`` -- a format string, this is used to format the colorbar labels. - ``colorbar_options`` -- a dictionary of options for the matplotlib colorbar API. Documentation for the :mod:`matplotlib.colorbar` module has details. - ``norm`` - If None (default), the value range is scaled to the interval [0,1]. If 'value', then the actual value is used with no scaling. A :class:`matplotlib.colors.Normalize` instance may also passed. - ``vmin`` - The minimum value (values below this are set to this value) - ``vmax`` - The maximum value (values above this are set to this value) - ``origin`` - If 'upper' (default), the first row of the matrix is on the top of the graph. If 'lower', the first row is on the bottom of the graph. - ``subdivisions`` - If True, plot the subdivisions of the matrix as lines. - ``subdivision_boundaries`` - a list of lists in the form ``[row_subdivisions, column_subdivisions]``, which specifies the row and column subdivisions to use. If not specified, defaults to the matrix subdivisions - ``subdivision_style`` - a dictionary of properties passed on to the :func:`~sage.plot.line.line2d` command for plotting subdivisions. If this is a two-element list or tuple, then it specifies the styles of row and column divisions, respectively. EXAMPLES: A matrix over `\ZZ` colored with different grey levels:: sage: matrix_plot(matrix([[1,3,5,1],[2,4,5,6],[1,3,5,7]])) Here we make a random matrix over `\RR` and use ``cmap='hsv'`` to color the matrix elements different RGB colors:: sage: matrix_plot(random_matrix(RDF, 50), cmap='hsv') By default, entries are scaled to the interval [0,1] before determining colors from the color map. That means the two plots below are the same:: sage: P = matrix_plot(matrix(2,[1,1,3,3])) sage: Q = matrix_plot(matrix(2,[2,2,3,3])) sage: P; Q However, we can specify which values scale to 0 or 1 with the ``vmin`` and ``vmax`` parameters (values outside the range are clipped). The two plots below are now distinguished:: sage: P = matrix_plot(matrix(2,[1,1,3,3]), vmin=0, vmax=3, colorbar=True) sage: Q = matrix_plot(matrix(2,[2,2,3,3]), vmin=0, vmax=3, colorbar=True) sage: P; Q We can also specify a norm function of 'value', which means that there is no scaling performed:: sage: matrix_plot(random_matrix(ZZ,10)*.05, norm='value', colorbar=True) Matrix subdivisions can be plotted as well:: sage: m=random_matrix(RR,10) sage: m.subdivide([2,4],[6,8]) sage: matrix_plot(m, subdivisions=True, subdivision_style=dict(color='red',thickness=3)) You can also specify your own subdivisions and separate styles for row or column subdivisions:: sage: m=random_matrix(RR,10) sage: matrix_plot(m, subdivisions=True, subdivision_boundaries=[[2,4],[6,8]], subdivision_style=[dict(color='red',thickness=3),dict(linestyle='--',thickness=6)]) Generally matrices are plotted with the (0,0) entry in the upper left. However, sometimes if we are plotting an image, we'd like the (0,0) entry to be in the lower left. We can do that with the ``origin`` argument:: sage: matrix_plot(identity_matrix(100), origin='lower') Another random plot, but over `\GF{389}`:: sage: m = random_matrix(GF(389), 10) sage: matrix_plot(m, cmap='Oranges') It also works if you lift it to the polynomial ring:: sage: matrix_plot(m.change_ring(GF(389)['x']), cmap='Oranges') We have several options for colorbars:: sage: matrix_plot(random_matrix(RDF, 50), colorbar=True, colorbar_orientation='horizontal') :: sage: matrix_plot(random_matrix(RDF, 50), colorbar=True, colorbar_format='%.3f') The length of a color bar and the length of the adjacent matrix plot dimension may be quite different. This example shows how to adjust the length of the colorbar by passing a dictionary of options to the matplotlib colorbar routines. :: sage: m = random_matrix(ZZ, 40, 80, x=-10, y=10) sage: m.plot(colorbar=True, colorbar_orientation='vertical', ... colorbar_options={'shrink':0.50}) Here we plot a random sparse matrix:: sage: sparse = matrix(dict([((randint(0, 10), randint(0, 10)), 1) for i in xrange(100)])) sage: matrix_plot(sparse) :: sage: A=random_matrix(ZZ,100000,density=.00001,sparse=True) sage: matrix_plot(A,marker=',') As with dense matrices, sparse matrix entries are automatically converted to floating point numbers before plotting. Thus the following works:: sage: b=random_matrix(GF(2),200,sparse=True,density=0.01) sage: matrix_plot(b) While this returns an error:: sage: b=random_matrix(CDF,200,sparse=True,density=0.01) sage: matrix_plot(b) Traceback (most recent call last): ... ValueError: can not convert entries to floating point numbers To plot the absolute value of a complex matrix, use the ``apply_map`` method:: sage: b=random_matrix(CDF,200,sparse=True,density=0.01) sage: matrix_plot(b.apply_map(abs)) Plotting lists of lists also works:: sage: matrix_plot([[1,3,5,1],[2,4,5,6],[1,3,5,7]]) As does plotting of NumPy arrays:: sage: import numpy sage: matrix_plot(numpy.random.rand(10, 10)) A plot title can be added to the matrix plot.:: sage: matrix_plot(identity_matrix(50), origin='lower', title='not identity') The title position is adjusted upwards if the ``origin`` keyword is set to ``"upper"`` (this is the default).:: sage: matrix_plot(identity_matrix(50), title='identity') TESTS:: sage: P.<t> = RR[] sage: matrix_plot(random_matrix(P, 3, 3)) Traceback (most recent call last): ... TypeError: cannot coerce nonconstant polynomial to float :: sage: matrix_plot([1,2,3]) Traceback (most recent call last): ... TypeError: mat must be a Matrix or a two dimensional array :: sage: matrix_plot([[sin(x), cos(x)], [1, 0]]) Traceback (most recent call last): ... ValueError: can not convert entries to floating point numbers Test that sparse matrices also work with subdivisions:: sage: matrix_plot(sparse, subdivisions=True, subdivision_boundaries=[[2,4],[6,8]]) """ import numpy as np import scipy.sparse as scipysparse from sage.plot.all import Graphics from sage.matrix.all import is_Matrix from sage.rings.all import RDF orig_mat=mat if is_Matrix(mat): sparse = mat.is_sparse() if sparse: entries = list(mat._dict().items()) try: data = np.asarray([d for _,d in entries], dtype=float) except StandardError: raise ValueError, "can not convert entries to floating point numbers" positions = np.asarray([[row for (row,col),_ in entries], [col for (row,col),_ in entries]], dtype=int) mat = scipysparse.coo_matrix((data,positions), shape=(mat.nrows(), mat.ncols())) else: mat = mat.change_ring(RDF).numpy() elif hasattr(mat, 'tocoo'): sparse = True else: sparse = False try: if sparse: xy_data_array = mat else: xy_data_array = np.asarray(mat, dtype = float) except TypeError: raise TypeError, "mat must be a Matrix or a two dimensional array" except ValueError: raise ValueError, "can not convert entries to floating point numbers" if len(xy_data_array.shape) < 2: raise TypeError, "mat must be a Matrix or a two dimensional array" xrange = (0, xy_data_array.shape[1]) yrange = (0, xy_data_array.shape[0]) if options['subdivisions'] and options['subdivision_options']['boundaries'] is None: options['subdivision_options']['boundaries']=orig_mat.get_subdivisions() # Custom position the title. Otherwise it overlaps with tick labels if options['origin'] == 'upper' and 'title_pos' not in options: options['title_pos'] = (0.5, 1.05) g = Graphics() g._set_extra_kwds(Graphics._extract_kwds_for_show(options)) g.add_primitive(MatrixPlot(xy_data_array, xrange, yrange, options)) return g
def __call__(self, A, check=True): r""" INPUT: - ``A`` - one of several possible inputs representing a morphism from this vector space homspace. - a vector space morphism in this homspace - a matrix representation relative to the bases of the vector spaces, which acts on a vector placed to the left of the matrix - a list or tuple containing images of the domain's basis vectors - a function from the domain to the codomain - ``check`` (default: True) - ``True`` or ``False``, required for compatibility with calls from :meth:`sage.structure.parent_gens.ParentWithGens.hom`. EXAMPLES:: sage: V = (QQ^3).span_of_basis([[1,1,0],[1,0,2]]) sage: H = V.Hom(V) sage: H Set of Morphisms (Linear Transformations) from Vector space of degree 3 and dimension 2 over Rational Field User basis matrix: [1 1 0] [1 0 2] to Vector space of degree 3 and dimension 2 over Rational Field User basis matrix: [1 1 0] [1 0 2] Coercing a matrix:: sage: A = matrix(QQ, [[0, 1], [1, 0]]) sage: rho = H(A) # indirect doctest sage: rho Vector space morphism represented by the matrix: [0 1] [1 0] Domain: Vector space of degree 3 and dimension 2 over Rational Field User basis matrix: [1 1 0] [1 0 2] Codomain: Vector space of degree 3 and dimension 2 over Rational Field User basis matrix: [1 1 0] [1 0 2] Coercing a list of images:: sage: phi = H([V.1, V.0]) sage: phi(V.1) == V.0 True sage: phi(V.0) == V.1 True sage: phi Vector space morphism represented by the matrix: [0 1] [1 0] Domain: Vector space of degree 3 and dimension 2 over Rational Field User basis matrix: [1 1 0] [1 0 2] Codomain: Vector space of degree 3 and dimension 2 over Rational Field User basis matrix: [1 1 0] [1 0 2] Coercing a lambda function:: sage: f = lambda x: vector(QQ, [x[0], (1/2)*x[2], 2*x[1]]) sage: zeta = H(f) sage: zeta Vector space morphism represented by the matrix: [0 1] [1 0] Domain: Vector space of degree 3 and dimension 2 over Rational Field User basis matrix: [1 1 0] [1 0 2] Codomain: Vector space of degree 3 and dimension 2 over Rational Field User basis matrix: [1 1 0] [1 0 2] Coercing a vector space morphism into the parent of a second vector space morphism will unify their parents. :: sage: U = QQ^3 sage: V = QQ^4 sage: W = FreeModule(QQ,3,sparse=True) sage: X = QQ^4 sage: H = Hom(U, V) sage: K = Hom(W, X) sage: H is K False sage: A = matrix(QQ, 3, 4, [0]*12) sage: f = H(A) sage: B = matrix(QQ, 3, 4, range(12)) sage: g = K(B) sage: f.parent() is H and g.parent() is K True sage: h = H(g) sage: f.parent() is h.parent() True See other examples in the module-level documentation. TESTS:: sage: V = GF(3)^0 sage: W = GF(3)^1 sage: H = V.Hom(W) sage: H.zero_element().is_zero() True Previously the above code resulted in a TypeError because the dimensions of the matrix were incorrect. """ from vector_space_morphism import is_VectorSpaceMorphism, VectorSpaceMorphism D = self.domain() C = self.codomain() if matrix.is_Matrix(A): pass elif is_VectorSpaceMorphism(A): A = A.matrix() elif inspect.isfunction(A): try: images = [A(g) for g in D.basis()] except (ValueError, TypeError, IndexError), e: msg = 'function cannot be applied properly to some basis element because\n' + e.args[0] raise ValueError(msg) try: A = matrix.matrix(D.dimension(), C.dimension(), [C.coordinates(C(a)) for a in images]) except (ArithmeticError, TypeError), e: msg = 'some image of the function is not in the codomain, because\n' + e.args[0] raise ArithmeticError(msg)
def list_plot3d(v, interpolation_type='default', texture="automatic", point_list=None,**kwds): r""" A 3-dimensional plot of a surface defined by the list `v` of points in 3-dimensional space. INPUT: - ``v`` - something that defines a set of points in 3 space, for example: - a matrix - a list of 3-tuples - a list of lists (all of the same length) - this is treated the same as a matrix. - ``texture`` - (default: "automatic", a solid light blue) OPTIONAL KEYWORDS: - ``interpolation_type`` - 'linear', 'nn' (nearest neighbor), 'spline' 'linear' will perform linear interpolation The option 'nn' will interpolate by averaging the value of the nearest neighbors, this produces an interpolating function that is smoother than a linear interpolation, it has one derivative everywhere except at the sample points. The option 'spline' interpolates using a bivariate B-spline. When v is a matrix the default is to use linear interpolation, when v is a list of points the default is nearest neighbor. - ``degree`` - an integer between 1 and 5, controls the degree of spline used for spline interpolation. For data that is highly oscillatory use higher values - ``point_list`` - If point_list=True is passed, then if the array is a list of lists of length three, it will be treated as an array of points rather than a 3xn array. - ``num_points`` - Number of points to sample interpolating function in each direction, when ``interpolation_type`` is not ``default``. By default for an `n\times n` array this is `n`. - ``**kwds`` - all other arguments are passed to the surface function OUTPUT: a 3d plot EXAMPLES: We plot a matrix that illustrates summation modulo `n`. :: sage: n = 5; list_plot3d(matrix(RDF,n,[(i+j)%n for i in [1..n] for j in [1..n]])) We plot a matrix of values of sin. :: sage: pi = float(pi) sage: m = matrix(RDF, 6, [sin(i^2 + j^2) for i in [0,pi/5,..,pi] for j in [0,pi/5,..,pi]]) sage: list_plot3d(m, texture='yellow', frame_aspect_ratio=[1,1,1/3]) Though it doesn't change the shape of the graph, increasing num_points can increase the clarity of the graph. :: sage: list_plot3d(m, texture='yellow', frame_aspect_ratio=[1,1,1/3],num_points=40) We can change the interpolation type. :: sage: list_plot3d(m, texture='yellow', interpolation_type='nn',frame_aspect_ratio=[1,1,1/3]) We can make this look better by increasing the number of samples. :: sage: list_plot3d(m, texture='yellow', interpolation_type='nn',frame_aspect_ratio=[1,1,1/3],num_points=40) Let's try a spline. :: sage: list_plot3d(m, texture='yellow', interpolation_type='spline',frame_aspect_ratio=[1,1,1/3]) That spline doesn't capture the oscillation very well; let's try a higher degree spline. :: sage: list_plot3d(m, texture='yellow', interpolation_type='spline', degree=5, frame_aspect_ratio=[1,1,1/3]) We plot a list of lists:: sage: show(list_plot3d([[1, 1, 1, 1], [1, 2, 1, 2], [1, 1, 3, 1], [1, 2, 1, 4]])) We plot a list of points. As a first example we can extract the (x,y,z) coordinates from the above example and make a list plot out of it. By default we do linear interpolation. :: sage: l=[] sage: for i in range(6): ... for j in range(6): ... l.append((float(i*pi/5),float(j*pi/5),m[i,j])) sage: list_plot3d(l,texture='yellow') Note that the points do not have to be regularly sampled. For example:: sage: l=[] sage: for i in range(-5,5): ... for j in range(-5,5): ... l.append((normalvariate(0,1),normalvariate(0,1),normalvariate(0,1))) sage: list_plot3d(l,interpolation_type='nn',texture='yellow',num_points=100) TESTS: We plot 0, 1, and 2 points:: sage: list_plot3d([]) :: sage: list_plot3d([(2,3,4)]) :: sage: list_plot3d([(0,0,1), (2,3,4)]) However, if two points are given with the same x,y coordinates but different z coordinates, an exception will be raised:: sage: pts =[(-4/5, -2/5, -2/5), (-4/5, -2/5, 2/5), (-4/5, 2/5, -2/5), (-4/5, 2/5, 2/5), (-2/5, -4/5, -2/5), (-2/5, -4/5, 2/5), (-2/5, -2/5, -4/5), (-2/5, -2/5, 4/5), (-2/5, 2/5, -4/5), (-2/5, 2/5, 4/5), (-2/5, 4/5, -2/5), (-2/5, 4/5, 2/5), (2/5, -4/5, -2/5), (2/5, -4/5, 2/5), (2/5, -2/5, -4/5), (2/5, -2/5, 4/5), (2/5, 2/5, -4/5), (2/5, 2/5, 4/5), (2/5, 4/5, -2/5), (2/5, 4/5, 2/5), (4/5, -2/5, -2/5), (4/5, -2/5, 2/5), (4/5, 2/5, -2/5), (4/5, 2/5, 2/5)] sage: show(list_plot3d(pts, interpolation_type='nn')) Traceback (most recent call last): ... ValueError: Two points with same x,y coordinates and different z coordinates were given. Interpolation cannot handle this. Additionally we need at least 3 points to do the interpolation:: sage: mat = matrix(RDF, 1, 2, [3.2, 1.550]) sage: show(list_plot3d(mat,interpolation_type='nn')) Traceback (most recent call last): ... ValueError: We need at least 3 points to perform the interpolation """ import numpy if texture == "automatic": texture = "lightblue" if is_Matrix(v): if interpolation_type=='default' or interpolation_type=='linear' and not kwds.has_key('num_points'): return list_plot3d_matrix(v, texture=texture, **kwds) else: l=[] for i in xrange(v.nrows()): for j in xrange(v.ncols()): l.append((i,j,v[i,j])) return list_plot3d_tuples(l,interpolation_type,texture,**kwds) if type(v)==numpy.ndarray: return list_plot3d(matrix(v),interpolation_type,texture,**kwds) if isinstance(v, list): if len(v) == 0: # return empty 3d graphic from base import Graphics3d return Graphics3d() elif len(v) == 1: # return a point from shapes2 import point3d return point3d(v[0], **kwds) elif len(v) == 2: # return a line from shapes2 import line3d return line3d(v, **kwds) elif isinstance(v[0],tuple) or point_list==True and len(v[0]) == 3: return list_plot3d_tuples(v,interpolation_type,texture=texture, **kwds) else: return list_plot3d_array_of_arrays(v, interpolation_type,texture, **kwds) raise TypeError, "v must be a matrix or list"