def my_hyperbolic_triangle(a, b, c, **options): """ Return a hyperbolic triangle in the complex hyperbolic plane with points (a, b, c). Type ``?hyperbolic_triangle`` to see all options. INPUT: - ``a, b, c`` - complex numbers in the upper half complex plane OPTIONS: - ``alpha`` - default: 1 - ``fill`` - default: False - ``thickness`` - default: 1 - ``rgbcolor`` - default: 'blue' - ``linestyle`` - default: 'solid' EXAMPLES: Show a hyperbolic triangle with coordinates 0, `1/2+i\sqrt{3}/2` and `-1/2+i\sqrt{3}/2`:: sage: hyperbolic_triangle(0, -1/2+I*sqrt(3)/2, 1/2+I*sqrt(3)/2) A hyperbolic triangle with coordinates 0, 1 and 2+i:: sage: hyperbolic_triangle(0, 1, 2+i, fill=true, rgbcolor='red') """ from sage.plot.all import Graphics g = Graphics() g._set_extra_kwds(g._extract_kwds_for_show(options)) model = options['model'] npts = options.get('npts',10) sides = options.pop('sides',[1,2,3]) ## Which of the sides we will draw. verbose = options.get('verbose',0) options.pop('model',None); options.pop('method',None) if model=="D": #g.add_primitive(HyperbolicTriangleDisc(a, b, c, **options)) #print "options=",options options['sides']=sides H = HyperbolicTriangleDisc(a, b, c, **options) g += H() else: options.pop('npts',None) if sides == [1,2,3]: if verbose>0: print "adding HyperbolicTriangle({0}, {1}, {2},options={3})".format(a,b,c,options) options.pop('verbose',0) g.add_primitive(HyperbolicTriangle(a, b, c, options)) else: options['sides']=sides if verbose>0: print "adding MyHyperbolicTriangle({0}, {1}, {2},options={3})".format(a,b,c,options) g.add_primitive(MyHyperbolicTriangle(a, b, c, options)) g.set_aspect_ratio(1) return g
def hyperbolic_polygon(pts, **options): r""" Return a hyperbolic polygon in the hyperbolic plane with vertices ``pts``. Type ``?hyperbolic_polygon`` to see all options. INPUT: - ``pts`` -- a list or tuple of complex numbers OPTIONS: - ``alpha`` -- default: 1 - ``fill`` -- default: ``False`` - ``thickness`` -- default: 1 - ``rgbcolor`` -- default: ``'blue'`` - ``linestyle`` -- (default: ``'solid'``) The style of the line, which is one of ``'dashed'``, ``'dotted'``, ``'solid'``, ``'dashdot'``, or ``'--'``, ``':'``, ``'-'``, ``'-.'``, respectively. EXAMPLES: Show a hyperbolic polygon with coordinates `-1`, `3i`, `2+2i`, `1+i`:: sage: hyperbolic_polygon([-1,3*I,2+2*I,1+I]) Graphics object consisting of 1 graphics primitive .. PLOT:: P = hyperbolic_polygon([-1,3*I,2+2*I,1+I]) sphinx_plot(P) With more options:: sage: hyperbolic_polygon([-1,3*I,2+2*I,1+I], fill=True, color='red') Graphics object consisting of 1 graphics primitive .. PLOT:: P = hyperbolic_polygon([-1,3*I,2+2*I,1+I], fill=True, color='red') sphinx_plot(P) """ from sage.plot.all import Graphics g = Graphics() g._set_extra_kwds(g._extract_kwds_for_show(options)) g.add_primitive(HyperbolicPolygon(pts, options)) g.set_aspect_ratio(1) return g
def scatter_plot(datalist, **options): """ Returns a Graphics object of a scatter plot containing all points in the datalist. Type ``scatter_plot.options`` to see all available plotting options. INPUT: - ``datalist`` -- a list of tuples ``(x,y)`` - ``alpha`` -- default: 1 - ``markersize`` -- default: 50 - ``marker`` - The style of the markers (default ``"o"``), which is one of - ``"None"`` or ``" "`` or ``""`` (nothing) - ``","`` (pixel), ``"."`` (point) - ``"_"`` (horizontal line), ``"|"`` (vertical line) - ``"o"`` (circle), ``"p"`` (pentagon), ``"s"`` (square), ``"x"`` (x), ``"+"`` (plus), ``"*"`` (star) - ``"D"`` (diamond), ``"d"`` (thin diamond) - ``"H"`` (hexagon), ``"h"`` (alternative hexagon) - ``"<"`` (triangle left), ``">"`` (triangle right), ``"^"`` (triangle up), ``"v"`` (triangle down) - ``"1"`` (tri down), ``"2"`` (tri up), ``"3"`` (tri left), ``"4"`` (tri right) - ``0`` (tick left), ``1`` (tick right), ``2`` (tick up), ``3`` (tick down) - ``4`` (caret left), ``5`` (caret right), ``6`` (caret up), ``7`` (caret down) - ``"$...$"`` (math TeX string) - ``facecolor`` -- default: ``'#fec7b8'`` - ``edgecolor`` -- default: ``'black'`` - ``zorder`` -- default: 5 EXAMPLES:: sage: scatter_plot([[0,1],[2,2],[4.3,1.1]], marker='s') Extra options will get passed on to :meth:`~Graphics.show`, as long as they are valid:: sage: scatter_plot([(0, 0), (1, 1)], markersize=100, facecolor='green', ymax=100) sage: scatter_plot([(0, 0), (1, 1)], markersize=100, facecolor='green').show(ymax=100) # These are equivalent """ import numpy from sage.plot.all import Graphics g = Graphics() g._set_extra_kwds(Graphics._extract_kwds_for_show(options)) data = numpy.array(datalist, dtype='float') if len(data) != 0: xdata = data[:, 0] ydata = data[:, 1] g.add_primitive(ScatterPlot(xdata, ydata, options=options)) return g
def scatter_plot(datalist, **options): """ Returns a Graphics object of a scatter plot containing all points in the datalist. Type ``scatter_plot.options`` to see all available plotting options. INPUT: - ``datalist`` -- a list of tuples ``(x,y)`` - ``alpha`` -- default: 1 - ``markersize`` -- default: 50 - ``marker`` - The style of the markers (default ``"o"``), which is one of - ``"None"`` or ``" "`` or ``""`` (nothing) - ``","`` (pixel), ``"."`` (point) - ``"_"`` (horizontal line), ``"|"`` (vertical line) - ``"o"`` (circle), ``"p"`` (pentagon), ``"s"`` (square), ``"x"`` (x), ``"+"`` (plus), ``"*"`` (star) - ``"D"`` (diamond), ``"d"`` (thin diamond) - ``"H"`` (hexagon), ``"h"`` (alternative hexagon) - ``"<"`` (triangle left), ``">"`` (triangle right), ``"^"`` (triangle up), ``"v"`` (triangle down) - ``"1"`` (tri down), ``"2"`` (tri up), ``"3"`` (tri left), ``"4"`` (tri right) - ``0`` (tick left), ``1`` (tick right), ``2`` (tick up), ``3`` (tick down) - ``4`` (caret left), ``5`` (caret right), ``6`` (caret up), ``7`` (caret down) - ``"$...$"`` (math TeX string) - ``facecolor`` -- default: ``'#fec7b8'`` - ``edgecolor`` -- default: ``'black'`` - ``zorder`` -- default: 5 EXAMPLES:: sage: scatter_plot([[0,1],[2,2],[4.3,1.1]], marker='s') Extra options will get passed on to :meth:`~Graphics.show`, as long as they are valid:: sage: scatter_plot([(0, 0), (1, 1)], markersize=100, facecolor='green', ymax=100) sage: scatter_plot([(0, 0), (1, 1)], markersize=100, facecolor='green').show(ymax=100) # These are equivalent """ import numpy from sage.plot.all import Graphics g = Graphics() g._set_extra_kwds(Graphics._extract_kwds_for_show(options)) data = numpy.array(datalist, dtype='float') if len(data) != 0: xdata = data[:,0] ydata = data[:,1] g.add_primitive(ScatterPlot(xdata, ydata, options=options)) return g
def hyperbolic_arc(a, b, **options): """ Plot an arc from a to b in hyperbolic geometry in the complex upper half plane. INPUT: - ``a, b`` - complex numbers in the upper half complex plane connected bye the arc OPTIONS: - ``alpha`` - default: 1 - ``thickness`` - default: 1 - ``rgbcolor`` - default: 'blue' - ``linestyle`` - (default: ``'solid'``) The style of the line, which is one of ``'dashed'``, ``'dotted'``, ``'solid'``, ``'dashdot'``, or ``'--'``, ``':'``, ``'-'``, ``'-.'``, respectively. Examples: Show a hyperbolic arc from 0 to 1:: sage: hyperbolic_arc(0, 1) Graphics object consisting of 1 graphics primitive Show a hyperbolic arc from 1/2 to `i` with a red thick line:: sage: hyperbolic_arc(1/2, I, color='red', thickness=2) Graphics object consisting of 1 graphics primitive Show a hyperbolic arc form `i` to `2 i` with dashed line:: sage: hyperbolic_arc(I, 2*I, linestyle='dashed') Graphics object consisting of 1 graphics primitive sage: hyperbolic_arc(I, 2*I, linestyle='--') Graphics object consisting of 1 graphics primitive """ from sage.plot.all import Graphics g = Graphics() g._set_extra_kwds(g._extract_kwds_for_show(options)) g.add_primitive(HyperbolicArc(a, b, options)) g.set_aspect_ratio(1) return g
def my_hyperbolic_triangle(a, b, c, **options): """ Return a hyperbolic triangle in the complex hyperbolic plane with points (a, b, c). Type ``?hyperbolic_triangle`` to see all options. INPUT: - ``a, b, c`` - complex numbers in the upper half complex plane OPTIONS: - ``alpha`` - default: 1 - ``fill`` - default: False - ``thickness`` - default: 1 - ``rgbcolor`` - default: 'blue' - ``linestyle`` - default: 'solid' EXAMPLES: Show a hyperbolic triangle with coordinates 0, `1/2+i\sqrt{3}/2` and `-1/2+i\sqrt{3}/2`:: sage: hyperbolic_triangle(0, -1/2+I*sqrt(3)/2, 1/2+I*sqrt(3)/2) A hyperbolic triangle with coordinates 0, 1 and 2+i:: sage: hyperbolic_triangle(0, 1, 2+i, fill=true, rgbcolor='red') """ from sage.plot.all import Graphics g = Graphics() g._set_extra_kwds(g._extract_kwds_for_show(options)) model = options['model'] options.pop('model',None); options.pop('method',None) if model=="D": #g.add_primitive(HyperbolicTriangleDisc(a, b, c, **options)) H = HyperbolicTriangleDisc(a, b, c, **options) g += H() else: g.add_primitive(HyperbolicTriangle(a, b, c, options)) g.set_aspect_ratio(1) return g
def scatter_plot(datalist, **options): """ Returns a Graphics object of a scatter plot containing all points in the datalist. Type ``scatter_plot.options`` to see all available plotting options. INPUT: - ``datalist`` -- a list of tuples ``(x,y)`` - ``alpha`` -- default: 1 - ``markersize`` -- default: 50 - ``marker`` - The style of the markers (default ``"o"``). See the documentation of :func:`plot` for the full list of markers. - ``facecolor`` -- default: ``'#fec7b8'`` - ``edgecolor`` -- default: ``'black'`` - ``zorder`` -- default: 5 EXAMPLES:: sage: scatter_plot([[0,1],[2,2],[4.3,1.1]], marker='s') Graphics object consisting of 1 graphics primitive Extra options will get passed on to :meth:`~Graphics.show`, as long as they are valid:: sage: scatter_plot([(0, 0), (1, 1)], markersize=100, facecolor='green', ymax=100) Graphics object consisting of 1 graphics primitive sage: scatter_plot([(0, 0), (1, 1)], markersize=100, facecolor='green').show(ymax=100) # These are equivalent """ import numpy from sage.plot.all import Graphics g = Graphics() g._set_extra_kwds(Graphics._extract_kwds_for_show(options)) data = numpy.array(datalist, dtype='float') if len(data) != 0: xdata = data[:,0] ydata = data[:,1] g.add_primitive(ScatterPlot(xdata, ydata, options=options)) return g
def limit_arrow(tailpoint=None, headpoint=None, path=None, **options): from sage.plot.all import Graphics g = Graphics() g._set_extra_kwds(Graphics._extract_kwds_for_show(options)) if headpoint is not None and tailpoint is not None: xtail, ytail = tailpoint xhead, yhead = headpoint g.add_primitive(LimitArrow(xtail, ytail, xhead, yhead, options=options)) elif path is not None: g.add_primitive(CurveArrow(path, options=options)) elif tailpoint is None and headpoint is None: return g else: raise TypeError('Arrow requires either both headpoint and tailpoint or a path parameter.') if options['legend_label']: g.legend(True) g._legend_colors = [options['legend_color']] return g
def hyperbolic_triangle(a, b, c, **options): """ Return a hyperbolic triangle in the complex hyperbolic plane with points (a, b, c). Type ``?hyperbolic_triangle`` to see all options. INPUT: - ``a, b, c`` - complex numbers in the upper half complex plane OPTIONS: - ``alpha`` - default: 1 - ``fill`` - default: False - ``thickness`` - default: 1 - ``rgbcolor`` - default: 'blue' - ``linestyle`` - (default: ``'solid'``) The style of the line, which is one of ``'dashed'``, ``'dotted'``, ``'solid'``, ``'dashdot'``, or ``'--'``, ``':'``, ``'-'``, ``'-.'``, respectively. EXAMPLES: Show a hyperbolic triangle with coordinates 0, `1/2+i\sqrt{3}/2` and `-1/2+i\sqrt{3}/2`:: sage: hyperbolic_triangle(0, -1/2+I*sqrt(3)/2, 1/2+I*sqrt(3)/2) Graphics object consisting of 1 graphics primitive A hyperbolic triangle with coordinates 0, 1 and 2+i and a dashed line:: sage: hyperbolic_triangle(0, 1, 2+i, fill=true, rgbcolor='red', linestyle='--') Graphics object consisting of 1 graphics primitive """ from sage.plot.all import Graphics g = Graphics() g._set_extra_kwds(g._extract_kwds_for_show(options)) g.add_primitive(HyperbolicTriangle(a, b, c, options)) g.set_aspect_ratio(1) return g
def hyperbolic_arc(a, b, **options): """ Plot an arc from a to b in hyperbolic geometry in the complex upper half plane. INPUT: - ``a, b`` - complex numbers in the upper half complex plane connected bye the arc OPTIONS: - ``alpha`` - default: 1 - ``thickness`` - default: 1 - ``rgbcolor`` - default: 'blue' - ``linestyle`` - default: 'solid' Examples: Show a hyperbolic arc from 0 to 1:: sage: hyperbolic_arc(0, 1) Show a hyperbolic arc from 1/2 to `i` with a red thick line:: sage: hyperbolic_arc(1/2, I, color='red', thickness=2) Show a hyperbolic arc form `i` to `2 i` with dashed line:: sage: hyperbolic_arc(I, 2*I, linestyle='dashed') """ from sage.plot.all import Graphics g = Graphics() g._set_extra_kwds(g._extract_kwds_for_show(options)) g.add_primitive(HyperbolicArc(a, b, options)) g.set_aspect_ratio(1) return g
def hyperbolic_triangle(a, b, c, **options): """ Return a hyperbolic triangle in the complex hyperbolic plane with points (a, b, c). Type ``?hyperbolic_triangle`` to see all options. INPUT: - ``a, b, c`` - complex numbers in the upper half complex plane OPTIONS: - ``alpha`` - default: 1 - ``fill`` - default: False - ``thickness`` - default: 1 - ``rgbcolor`` - default: 'blue' - ``linestyle`` - (default: ``'solid'``) The style of the line, which is one of ``'dashed'``, ``'dotted'``, ``'solid'``, ``'dashdot'``, or ``'--'``, ``':'``, ``'-'``, ``'-.'``, respectively. EXAMPLES: Show a hyperbolic triangle with coordinates 0, `1/2+i\sqrt{3}/2` and `-1/2+i\sqrt{3}/2`:: sage: hyperbolic_triangle(0, -1/2+I*sqrt(3)/2, 1/2+I*sqrt(3)/2) A hyperbolic triangle with coordinates 0, 1 and 2+i and a dashed line:: sage: hyperbolic_triangle(0, 1, 2+i, fill=true, rgbcolor='red', linestyle='--') """ from sage.plot.all import Graphics g = Graphics() g._set_extra_kwds(g._extract_kwds_for_show(options)) g.add_primitive(HyperbolicTriangle(a, b, c, options)) g.set_aspect_ratio(1) return g
def hyperbolic_triangle(a, b, c, **options): """ Return a hyperbolic triangle in the complex hyperbolic plane with points (a, b, c). Type ``?hyperbolic_triangle`` to see all options. INPUT: - ``a, b, c`` - complex numbers in the upper half complex plane OPTIONS: - ``alpha`` - default: 1 - ``fill`` - default: False - ``thickness`` - default: 1 - ``rgbcolor`` - default: 'blue' - ``linestyle`` - default: 'solid' EXAMPLES: Show a hyperbolic triangle with coordinates 0, `1/2+i\sqrt{3}/2` and `-1/2+i\sqrt{3}/2`:: sage: hyperbolic_triangle(0, -1/2+I*sqrt(3)/2, 1/2+I*sqrt(3)/2) A hyperbolic triangle with coordinates 0, 1 and 2+i:: sage: hyperbolic_triangle(0, 1, 2+i, fill=true, rgbcolor='red') """ from sage.plot.all import Graphics g = Graphics() g._set_extra_kwds(g._extract_kwds_for_show(options)) g.add_primitive(HyperbolicTriangle(a, b, c, options)) g.set_aspect_ratio(1) return g
def polygon2d(points, **options): r""" Returns a 2-dimensional polygon defined by ``points``. Type ``polygon2d.options`` for a dictionary of the default options for polygons. You can change this to change the defaults for all future polygons. Use ``polygon2d.reset()`` to reset to the default options. EXAMPLES: We create a purple-ish polygon:: sage: polygon2d([[1,2], [5,6], [5,0]], rgbcolor=(1,0,1)) Graphics object consisting of 1 graphics primitive .. PLOT:: sphinx_plot(polygon2d([[1,2], [5,6], [5,0]], rgbcolor=(1,0,1))) By default, polygons are filled in, but we can make them without a fill as well:: sage: polygon2d([[1,2], [5,6], [5,0]], fill=False) Graphics object consisting of 1 graphics primitive .. PLOT:: sphinx_plot(polygon2d([[1,2], [5,6], [5,0]], fill=False)) In either case, the thickness of the border can be controlled:: sage: polygon2d([[1,2], [5,6], [5,0]], fill=False, thickness=4, color='orange') Graphics object consisting of 1 graphics primitive .. PLOT:: P = polygon2d([[1,2], [5,6], [5,0]], fill=False, thickness=4, color='orange') sphinx_plot(P) For filled polygons, one can use different colors for the border and the interior as follows:: sage: L = [[0,0]]+[[i/100, 1.1+cos(i/20)] for i in range(100)]+[[1,0]] sage: polygon2d(L, color="limegreen", edgecolor="black", axes=False) Graphics object consisting of 1 graphics primitive .. PLOT:: L = [[0,0]]+[[i*0.01, 1.1+cos(i*0.05)] for i in range(100)]+[[1,0]] P = polygon2d(L, color="limegreen", edgecolor="black", axes=False) sphinx_plot(P) Some modern art -- a random polygon, with legend:: sage: v = [(randrange(-5,5), randrange(-5,5)) for _ in range(10)] sage: polygon2d(v, legend_label='some form') Graphics object consisting of 1 graphics primitive .. PLOT:: v = [(randrange(-5,5), randrange(-5,5)) for _ in range(10)] P = polygon2d(v, legend_label='some form') sphinx_plot(P) A purple hexagon:: sage: L = [[cos(pi*i/3),sin(pi*i/3)] for i in range(6)] sage: polygon2d(L, rgbcolor=(1,0,1)) Graphics object consisting of 1 graphics primitive .. PLOT:: L = [[cos(pi*i/3.0),sin(pi*i/3.0)] for i in range(6)] P = polygon2d(L, rgbcolor=(1,0,1)) sphinx_plot(P) A green deltoid:: sage: L = [[-1+cos(pi*i/100)*(1+cos(pi*i/100)),2*sin(pi*i/100)*(1-cos(pi*i/100))] for i in range(200)] sage: polygon2d(L, rgbcolor=(1/8,3/4,1/2)) Graphics object consisting of 1 graphics primitive .. PLOT:: L = [[-1+cos(pi*i*0.01)*(1+cos(pi*i*0.01)),2*sin(pi*i*0.01)*(1-cos(pi*i*0.01))] for i in range(200)] P = polygon2d(L, rgbcolor=(0.125,0.75,0.5)) sphinx_plot(P) A blue hypotrochoid:: sage: L = [[6*cos(pi*i/100)+5*cos((6/2)*pi*i/100),6*sin(pi*i/100)-5*sin((6/2)*pi*i/100)] for i in range(200)] sage: polygon2d(L, rgbcolor=(1/8,1/4,1/2)) Graphics object consisting of 1 graphics primitive .. PLOT:: L = [[6*cos(pi*i*0.01)+5*cos(3*pi*i*0.01),6*sin(pi*i*0.01)-5*sin(3*pi*i*0.01)] for i in range(200)] P = polygon2d(L, rgbcolor=(0.125,0.25,0.5)) sphinx_plot(P) Another one:: sage: n = 4; h = 5; b = 2 sage: L = [[n*cos(pi*i/100)+h*cos((n/b)*pi*i/100),n*sin(pi*i/100)-h*sin((n/b)*pi*i/100)] for i in range(200)] sage: polygon2d(L, rgbcolor=(1/8,1/4,3/4)) Graphics object consisting of 1 graphics primitive .. PLOT:: n = 4.0; h = 5.0; b = 2.0 L = [[n*cos(pi*i*0.01)+h*cos((n/b)*pi*i*0.01),n*sin(pi*i*0.01)-h*sin((n/b)*pi*i*0.01)] for i in range(200)] P = polygon2d(L, rgbcolor=(0.125,0.25,0.75)) sphinx_plot(P) A purple epicycloid:: sage: m = 9; b = 1 sage: L = [[m*cos(pi*i/100)+b*cos((m/b)*pi*i/100),m*sin(pi*i/100)-b*sin((m/b)*pi*i/100)] for i in range(200)] sage: polygon2d(L, rgbcolor=(7/8,1/4,3/4)) Graphics object consisting of 1 graphics primitive .. PLOT:: m = 9.0; b = 1 L = [[m*cos(pi*i*0.01)+b*cos((m/b)*pi*i*0.01),m*sin(pi*i*0.01)-b*sin((m/b)*pi*i*0.01)] for i in range(200)] P = polygon2d(L, rgbcolor=(0.875,0.25,0.75)) sphinx_plot(P) A brown astroid:: sage: L = [[cos(pi*i/100)^3,sin(pi*i/100)^3] for i in range(200)] sage: polygon2d(L, rgbcolor=(3/4,1/4,1/4)) Graphics object consisting of 1 graphics primitive .. PLOT:: L = [[cos(pi*i*0.01)**3,sin(pi*i*0.01)**3] for i in range(200)] P = polygon2d(L, rgbcolor=(0.75,0.25,0.25)) sphinx_plot(P) And, my favorite, a greenish blob:: sage: L = [[cos(pi*i/100)*(1+cos(pi*i/50)), sin(pi*i/100)*(1+sin(pi*i/50))] for i in range(200)] sage: polygon2d(L, rgbcolor=(1/8,3/4,1/2)) Graphics object consisting of 1 graphics primitive .. PLOT:: L = [[cos(pi*i*0.01)*(1+cos(pi*i*0.02)), sin(pi*i*0.01)*(1+sin(pi*i*0.02))] for i in range(200)] P = polygon2d(L, rgbcolor=(0.125,0.75,0.5)) sphinx_plot(P) This one is for my wife:: sage: L = [[sin(pi*i/100)+sin(pi*i/50),-(1+cos(pi*i/100)+cos(pi*i/50))] for i in range(-100,100)] sage: polygon2d(L, rgbcolor=(1,1/4,1/2)) Graphics object consisting of 1 graphics primitive .. PLOT:: L = [[sin(pi*i*0.01)+sin(pi*i*0.02),-(1+cos(pi*i*0.01)+cos(pi*i*0.02))] for i in range(-100,100)] P = polygon2d(L, rgbcolor=(1,0.25,0.5)) sphinx_plot(P) One can do the same one with a colored legend label:: sage: polygon2d(L, color='red', legend_label='For you!', legend_color='red') Graphics object consisting of 1 graphics primitive .. PLOT:: L = [[sin(pi*i*0.01)+sin(pi*i*0.02),-(1+cos(pi*i*0.01)+cos(pi*i*0.02))] for i in range(-100,100)] P = polygon2d(L, color='red', legend_label='For you!', legend_color='red') sphinx_plot(P) Polygons have a default aspect ratio of 1.0:: sage: polygon2d([[1,2], [5,6], [5,0]]).aspect_ratio() 1.0 AUTHORS: - David Joyner (2006-04-14): the long list of examples above. """ from sage.plot.plot import xydata_from_point_list from sage.plot.all import Graphics if options["thickness"] is None: # If the user did not specify thickness if options["fill"] and options["edgecolor"] is None: # If the user chose fill options["thickness"] = 0 else: options["thickness"] = 1 xdata, ydata = xydata_from_point_list(points) g = Graphics() # Reset aspect_ratio to 'automatic' in case scale is 'semilog[xy]'. # Otherwise matplotlib complains. scale = options.get('scale', None) if isinstance(scale, (list, tuple)): scale = scale[0] if scale == 'semilogy' or scale == 'semilogx': options['aspect_ratio'] = 'automatic' g._set_extra_kwds(Graphics._extract_kwds_for_show(options)) g.add_primitive(Polygon(xdata, ydata, options)) if options['legend_label']: g.legend(True) g._legend_colors = [options['legend_color']] return g
def disk(point, radius, angle, **options): r""" A disk (that is, a sector or wedge of a circle) with center at a point = `(x,y)` (or `(x,y,z)` and parallel to the `xy`-plane) with radius = `r` spanning (in radians) angle=`(rad1, rad2)`. Type ``disk.options`` to see all options. EXAMPLES: Make some dangerous disks:: sage: bl = disk((0.0,0.0), 1, (pi, 3*pi/2), color='yellow') sage: tr = disk((0.0,0.0), 1, (0, pi/2), color='yellow') sage: tl = disk((0.0,0.0), 1, (pi/2, pi), color='black') sage: br = disk((0.0,0.0), 1, (3*pi/2, 2*pi), color='black') sage: P = tl+tr+bl+br sage: P.show(xmin=-2,xmax=2,ymin=-2,ymax=2) The default aspect ratio is 1.0:: sage: disk((0.0,0.0), 1, (pi, 3*pi/2)).aspect_ratio() 1.0 Another example of a disk:: sage: bl = disk((0.0,0.0), 1, (pi, 3*pi/2), rgbcolor=(1,1,0)) sage: bl.show(figsize=[5,5]) Note that since ``thickness`` defaults to zero, it is best to change that option when using ``fill=False``:: sage: disk((2,3), 1, (pi/4,pi/3), hue=.8, alpha=.3, fill=False, thickness=2) The previous two examples also illustrate using ``hue`` and ``rgbcolor`` as ways of specifying the color of the graphic. We can also use this command to plot three-dimensional disks parallel to the `xy`-plane:: sage: d = disk((1,1,3), 1, (pi,3*pi/2), rgbcolor=(1,0,0)) sage: d sage: type(d) <type 'sage.plot.plot3d.index_face_set.IndexFaceSet'> Extra options will get passed on to ``show()``, as long as they are valid:: sage: disk((0, 0), 5, (0, pi/2), xmin=0, xmax=5, ymin=0, ymax=5, figsize=(2,2), rgbcolor=(1, 0, 1)) sage: disk((0, 0), 5, (0, pi/2), rgbcolor=(1, 0, 1)).show(xmin=0, xmax=5, ymin=0, ymax=5, figsize=(2,2)) # These are equivalent TESTS: Testing that legend labels work right:: sage: disk((2,4), 3, (pi/8, pi/4), hue=1, legend_label='disk', legend_color='blue') We cannot currently plot disks in more than three dimensions:: sage: d = disk((1,1,1,1), 1, (0,pi)) Traceback (most recent call last): ... ValueError: The center point of a plotted disk should have two or three coordinates. """ from sage.plot.all import Graphics g = Graphics() # Reset aspect_ratio to 'automatic' in case scale is 'semilog[xy]'. # Otherwise matplotlib complains. scale = options.get('scale', None) if isinstance(scale, (list, tuple)): scale = scale[0] if scale == 'semilogy' or scale == 'semilogx': options['aspect_ratio'] = 'automatic' g._set_extra_kwds(Graphics._extract_kwds_for_show(options)) g.add_primitive(Disk(point, radius, angle, options)) if options['legend_label']: g.legend(True) g._legend_colors = [options['legend_color']] if len(point)==2: return g elif len(point)==3: return g[0].plot3d(z=point[2]) else: raise ValueError, 'The center point of a plotted disk should have two or three coordinates.'
def bezier_path(path, **options): """ Returns a Graphics object of a Bezier path corresponding to the path parameter. The path is a list of curves, and each curve is a list of points. Each point is a tuple ``(x,y)``. The first curve contains the endpoints as the first and last point in the list. All other curves assume a starting point given by the last entry in the preceding list, and take the last point in the list as their opposite endpoint. A curve can have 0, 1 or 2 control points listed between the endpoints. In the input example for path below, the first and second curves have 2 control points, the third has one, and the fourth has no control points: path = [[p1, c1, c2, p2], [c3, c4, p3], [c5, p4], [p5], ...] In the case of no control points, a straight line will be drawn between the two endpoints. If one control point is supplied, then the curve at each of the endpoints will be tangent to the line from that endpoint to the control point. Similarly, in the case of two control points, at each endpoint the curve will be tangent to the line connecting that endpoint with the control point immediately after or immediately preceding it in the list. .. PLOT:: p1 = (0,0) c1 = (1,1) c2 = (1.5,0.5) p2 = (4,-1) c3 = (3.5,0) c4 = (2,1) p3 = (0,2) c5 = (0.5,3) p4 = (1.5,2) p5 = (0,4) path = [[p1, c1, c2, p2], [c3, c4, p3], [c5, p4], [p5]] P = bezier_path(path) P += line([p1,c1], color="red", linestyle="dashed") P += line([p2,c2], color="red", linestyle="dashed") P += line([p2,c3], color="red", linestyle="dashed") P += line([p3,c4], color="red", linestyle="dashed") P += line([p3,c5], color="red", linestyle="dashed") P += text("c1", c1, horizontal_alignment='left') P += text("c2", c2, horizontal_alignment='right') P += text("c3", c3, horizontal_alignment='left', vertical_alignment='bottom') P += text("c4", c4, horizontal_alignment='left') P += text("c5", c5, horizontal_alignment='left') P += text("p1", p1, horizontal_alignment='left', vertical_alignment='top') P += text("p2", p2, horizontal_alignment='left') P += text("p3", p3, horizontal_alignment='right', vertical_alignment='top') P += text("p4", p4, horizontal_alignment='left') P += text("p5", p5, horizontal_alignment='left', vertical_alignment='bottom') P += point([c1, c2, c3, c4, c5]) sphinx_plot(P) So in our example above, the curve between p1 and p2 is tangent to the line through p1 and c1 at p1, and tangent to the line through p2 and c2 at p2. Similarly, the curve between p2 and p3 is tangent to line(p2,c3) at p2 and tangent to line(p3,c4) at p3. Curve(p3,p4) is tangent to line(p3,c5) at p3 and tangent to line(p4,c5) at p4. Curve(p4,p5) is a straight line. INPUT: - ``path`` -- a list of lists of tuples (see above) - ``alpha`` -- default: 1 - ``fill`` -- default: False - ``thickness`` -- default: 1 - ``linestyle`` -- default: ``'solid'``, The style of the line, which is one of ``'dashed'``, ``'dotted'``, ``'solid'``, ``'dashdot'``, or ``'--'``, ``':'``, ``'-'``, ``'-.'``, respectively. - ``rbgcolor`` -- default: (0,0,0) - ``zorder`` -- the layer in which to draw EXAMPLES:: sage: path = [[(0,0),(.5,.1),(.75,3),(1,0)],[(.5,1),(.5,0)],[(.2,.5)]] sage: b = bezier_path(path, linestyle='dashed', rgbcolor='green') sage: b Graphics object consisting of 1 graphics primitive .. PLOT:: path = [[(0,0),(.5,.1),(.75,3),(1,0)],[(.5,1),(.5,0)],[(.2,.5)]] b = bezier_path(path, linestyle='dashed', rgbcolor='green') sphinx_plot(b) To construct a simple curve, create a list containing a single list:: sage: path = [[(0,0),(.5,1),(1,0)]] sage: curve = bezier_path(path, linestyle='dashed', rgbcolor='green') sage: curve Graphics object consisting of 1 graphics primitive .. PLOT:: path = [[(0,0),(.5,1),(1,0)]] curve = bezier_path(path, linestyle='dashed', rgbcolor='green') sphinx_plot(curve) Extra options will get passed on to :meth:`~Graphics.show`, as long as they are valid:: sage: bezier_path([[(0,1),(.5,0),(1,1)]], fontsize=50) Graphics object consisting of 1 graphics primitive sage: bezier_path([[(0,1),(.5,0),(1,1)]]).show(fontsize=50) # These are equivalent .. PLOT:: sphinx_plot(bezier_path([[(0,1),(.5,0),(1,1)]], fontsize=50)) TESTS: We shouldn't modify our argument, :trac:`13822`:: sage: bp = [[(1,1),(2,3),(3,3)], [(4,4),(5,5)]] sage: foo = bezier_path(bp) sage: bp [[(1, 1), (2, 3), (3, 3)], [(4, 4), (5, 5)]] """ from sage.plot.all import Graphics g = Graphics() g._set_extra_kwds(g._extract_kwds_for_show(options)) g.add_primitive(BezierPath(path, options)) return g
def circle(center, radius, **options): """ Return a circle at a point center = `(x,y)` (or `(x,y,z)` and parallel to the `xy`-plane) with radius = `r`. Type ``circle.options`` to see all options. OPTIONS: - ``alpha`` - default: 1 - ``fill`` - default: False - ``thickness`` - default: 1 - ``linestyle`` - default: ``'solid'`` (2D plotting only) The style of the line, which is one of ``'dashed'``, ``'dotted'``, ``'solid'``, ``'dashdot'``, or ``'--'``, ``':'``, ``'-'``, ``'-.'``, respectively. - ``edgecolor`` - default: 'blue' (2D plotting only) - ``facecolor`` - default: 'blue' (2D plotting only, useful only if ``fill=True``) - ``rgbcolor`` - 2D or 3D plotting. This option overrides ``edgecolor`` and ``facecolor`` for 2D plotting. - ``legend_label`` - the label for this item in the legend - ``legend_color`` - the color for the legend label EXAMPLES: The default color is blue, the default linestyle is solid, but this is easy to change:: sage: c = circle((1,1), 1) sage: c :: sage: c = circle((1,1), 1, rgbcolor=(1,0,0), linestyle='-.') sage: c We can also use this command to plot three-dimensional circles parallel to the `xy`-plane:: sage: c = circle((1,1,3), 1, rgbcolor=(1,0,0)) sage: c sage: type(c) <class 'sage.plot.plot3d.base.TransformGroup'> To correct the aspect ratio of certain graphics, it is necessary to show with a ``figsize`` of square dimensions:: sage: c.show(figsize=[5,5],xmin=-1,xmax=3,ymin=-1,ymax=3) Here we make a more complicated plot, with many circles of different colors:: sage: g = Graphics() sage: step=6; ocur=1/5; paths=16; sage: PI = math.pi # numerical for speed -- fine for graphics sage: for r in range(1,paths+1): ... for x,y in [((r+ocur)*math.cos(n), (r+ocur)*math.sin(n)) for n in srange(0, 2*PI+PI/step, PI/step)]: ... g += circle((x,y), ocur, rgbcolor=hue(r/paths)) ... rnext = (r+1)^2 ... ocur = (rnext-r)-ocur ... sage: g.show(xmin=-(paths+1)^2, xmax=(paths+1)^2, ymin=-(paths+1)^2, ymax=(paths+1)^2, figsize=[6,6]) Note that the ``rgbcolor`` option overrides the other coloring options. This produces red fill in a blue circle:: sage: circle((2,3), 1, fill=True, edgecolor='blue') This produces an all-green filled circle:: sage: circle((2,3), 1, fill=True, edgecolor='blue', rgbcolor='green') The option ``hue`` overrides *all* other options, so be careful with its use. This produces a purplish filled circle:: sage: circle((2,3), 1, fill=True, edgecolor='blue', rgbcolor='green', hue=.8) And circles with legends:: sage: circle((4,5), 1, rgbcolor='yellow', fill=True, legend_label='the sun').show(xmin=0, ymin=0) :: sage: circle((4,5), 1, legend_label='the sun', legend_color='yellow').show(xmin=0, ymin=0) Extra options will get passed on to show(), as long as they are valid:: sage: circle((0, 0), 2, figsize=[10,10]) # That circle is huge! :: sage: circle((0, 0), 2).show(figsize=[10,10]) # These are equivalent TESTS: We cannot currently plot circles in more than three dimensions:: sage: circle((1,1,1,1), 1, rgbcolor=(1,0,0)) Traceback (most recent call last): ... ValueError: The center of a plotted circle should have two or three coordinates. The default aspect ratio for a circle is 1.0:: sage: P = circle((1,1), 1) sage: P.aspect_ratio() 1.0 """ from sage.plot.all import Graphics # Reset aspect_ratio to 'automatic' in case scale is 'semilog[xy]'. # Otherwise matplotlib complains. scale = options.get('scale', None) if isinstance(scale, (list, tuple)): scale = scale[0] if scale == 'semilogy' or scale == 'semilogx': options['aspect_ratio'] = 'automatic' g = Graphics() g._set_extra_kwds(Graphics._extract_kwds_for_show(options)) g.add_primitive(Circle(center[0], center[1], radius, options)) if options['legend_label']: g.legend(True) g._legend_colors = [options['legend_color']] if len(center) == 2: return g elif len(center) == 3: return g[0].plot3d(z=center[2]) else: raise ValueError, 'The center of a plotted circle should have two or three coordinates.'
def plot_vector_field(f_g, xrange, yrange, **options): r""" ``plot_vector_field`` takes two functions of two variables xvar and yvar (for instance, if the variables are `x` and `y`, take `(f(x,y), g(x,y))`) and plots vector arrows of the function over the specified ranges, with xrange being of xvar between xmin and xmax, and yrange similarly (see below). ``plot_vector_field((f, g), (xvar, xmin, xmax), (yvar, ymin, ymax))`` EXAMPLES: Plot some vector fields involving sin and cos:: sage: x,y = var('x y') sage: plot_vector_field((sin(x), cos(y)), (x,-3,3), (y,-3,3)) Graphics object consisting of 1 graphics primitive :: sage: plot_vector_field(( y, (cos(x)-2)*sin(x)), (x,-pi,pi), (y,-pi,pi)) Graphics object consisting of 1 graphics primitive Plot a gradient field:: sage: u,v = var('u v') sage: f = exp(-(u^2+v^2)) sage: plot_vector_field(f.gradient(), (u,-2,2), (v,-2,2), color='blue') Graphics object consisting of 1 graphics primitive Plot two orthogonal vector fields:: sage: x,y = var('x,y') sage: a=plot_vector_field((x,y), (x,-3,3),(y,-3,3),color='blue') sage: b=plot_vector_field((y,-x),(x,-3,3),(y,-3,3),color='red') sage: show(a+b) We ignore function values that are infinite or NaN:: sage: x,y = var('x,y') sage: plot_vector_field( (-x/sqrt(x^2+y^2), -y/sqrt(x^2+y^2)), (x, -10, 10), (y, -10, 10)) Graphics object consisting of 1 graphics primitive :: sage: x,y = var('x,y') sage: plot_vector_field( (-x/sqrt(x+y), -y/sqrt(x+y)), (x, -10, 10), (y, -10, 10)) Graphics object consisting of 1 graphics primitive Extra options will get passed on to show(), as long as they are valid:: sage: plot_vector_field((x, y), (x, -2, 2), (y, -2, 2), xmax=10) Graphics object consisting of 1 graphics primitive sage: plot_vector_field((x, y), (x, -2, 2), (y, -2, 2)).show(xmax=10) # These are equivalent """ (f, g) = f_g from sage.plot.all import Graphics from sage.plot.misc import setup_for_eval_on_grid z, ranges = setup_for_eval_on_grid([f, g], [xrange, yrange], options['plot_points']) f, g = z xpos_array, ypos_array, xvec_array, yvec_array = [], [], [], [] for x in xsrange(*ranges[0], include_endpoint=True): for y in xsrange(*ranges[1], include_endpoint=True): xpos_array.append(x) ypos_array.append(y) xvec_array.append(f(x, y)) yvec_array.append(g(x, y)) import numpy xvec_array = numpy.ma.masked_invalid(numpy.array(xvec_array, dtype=float)) yvec_array = numpy.ma.masked_invalid(numpy.array(yvec_array, dtype=float)) g = Graphics() g._set_extra_kwds(Graphics._extract_kwds_for_show(options)) g.add_primitive( PlotField(xpos_array, ypos_array, xvec_array, yvec_array, options)) return g
def region_plot(f, xrange, yrange, plot_points, incol, outcol, bordercol, borderstyle, borderwidth,**options): r""" ``region_plot`` takes a boolean function of two variables, `f(x,y)` and plots the region where f is True over the specified ``xrange`` and ``yrange`` as demonstrated below. ``region_plot(f, (xmin, xmax), (ymin, ymax), ...)`` INPUT: - ``f`` -- a boolean function of two variables - ``(xmin, xmax)`` -- 2-tuple, the range of ``x`` values OR 3-tuple ``(x,xmin,xmax)`` - ``(ymin, ymax)`` -- 2-tuple, the range of ``y`` values OR 3-tuple ``(y,ymin,ymax)`` - ``plot_points`` -- integer (default: 100); number of points to plot in each direction of the grid - ``incol`` -- a color (default: ``'blue'``), the color inside the region - ``outcol`` -- a color (default: ``'white'``), the color of the outside of the region If any of these options are specified, the border will be shown as indicated, otherwise it is only implicit (with color ``incol``) as the border of the inside of the region. - ``bordercol`` -- a color (default: ``None``), the color of the border (``'black'`` if ``borderwidth`` or ``borderstyle`` is specified but not ``bordercol``) - ``borderstyle`` -- string (default: 'solid'), one of ``'solid'``, ``'dashed'``, ``'dotted'``, ``'dashdot'``, respectively ``'-'``, ``'--'``, ``':'``, ``'-.'``. - ``borderwidth`` -- integer (default: None), the width of the border in pixels - ``legend_label`` -- the label for this item in the legend - ``base`` - (default: 10) the base of the logarithm if a logarithmic scale is set. This must be greater than 1. The base can be also given as a list or tuple ``(basex, basey)``. ``basex`` sets the base of the logarithm along the horizontal axis and ``basey`` sets the base along the vertical axis. - ``scale`` -- (default: ``"linear"``) string. The scale of the axes. Possible values are ``"linear"``, ``"loglog"``, ``"semilogx"``, ``"semilogy"``. The scale can be also be given as single argument that is a list or tuple ``(scale, base)`` or ``(scale, basex, basey)``. The ``"loglog"`` scale sets both the horizontal and vertical axes to logarithmic scale. The ``"semilogx"`` scale sets the horizontal axis to logarithmic scale. The ``"semilogy"`` scale sets the vertical axis to logarithmic scale. The ``"linear"`` scale is the default value when :class:`~sage.plot.graphics.Graphics` is initialized. EXAMPLES: Here we plot a simple function of two variables:: sage: x,y = var('x,y') sage: region_plot(cos(x^2+y^2) <= 0, (x, -3, 3), (y, -3, 3)) Here we play with the colors:: sage: region_plot(x^2+y^3 < 2, (x, -2, 2), (y, -2, 2), incol='lightblue', bordercol='gray') An even more complicated plot, with dashed borders:: sage: region_plot(sin(x)*sin(y) >= 1/4, (x,-10,10), (y,-10,10), incol='yellow', bordercol='black', borderstyle='dashed', plot_points=250) A disk centered at the origin:: sage: region_plot(x^2+y^2<1, (x,-1,1), (y,-1,1)) A plot with more than one condition (all conditions must be true for the statement to be true):: sage: region_plot([x^2+y^2<1, x<y], (x,-2,2), (y,-2,2)) Since it doesn't look very good, let's increase ``plot_points``:: sage: region_plot([x^2+y^2<1, x<y], (x,-2,2), (y,-2,2), plot_points=400) To get plots where only one condition needs to be true, use a function. Using lambda functions, we definitely need the extra ``plot_points``:: sage: region_plot(lambda x,y: x^2+y^2<1 or x<y, (x,-2,2), (y,-2,2), plot_points=400) The first quadrant of the unit circle:: sage: region_plot([y>0, x>0, x^2+y^2<1], (x,-1.1, 1.1), (y,-1.1, 1.1), plot_points = 400) Here is another plot, with a huge border:: sage: region_plot(x*(x-1)*(x+1)+y^2<0, (x, -3, 2), (y, -3, 3), incol='lightblue', bordercol='gray', borderwidth=10, plot_points=50) If we want to keep only the region where x is positive:: sage: region_plot([x*(x-1)*(x+1)+y^2<0, x>-1], (x, -3, 2), (y, -3, 3), incol='lightblue', plot_points=50) Here we have a cut circle:: sage: region_plot([x^2+y^2<4, x>-1], (x, -2, 2), (y, -2, 2), incol='lightblue', bordercol='gray', plot_points=200) The first variable range corresponds to the horizontal axis and the second variable range corresponds to the vertical axis:: sage: s,t=var('s,t') sage: region_plot(s>0,(t,-2,2),(s,-2,2)) :: sage: region_plot(s>0,(s,-2,2),(t,-2,2)) An example of a region plot in 'loglog' scale:: sage: region_plot(x^2+y^2<100, (x,1,10), (y,1,10), scale='loglog') """ from sage.plot.all import Graphics from sage.plot.misc import setup_for_eval_on_grid import numpy if not isinstance(f, (list, tuple)): f = [f] f = [equify(g) for g in f] g, ranges = setup_for_eval_on_grid(f, [xrange, yrange], plot_points) xrange,yrange=[r[:2] for r in ranges] xy_data_arrays = numpy.asarray([[[func(x, y) for x in xsrange(*ranges[0], include_endpoint=True)] for y in xsrange(*ranges[1], include_endpoint=True)] for func in g],dtype=float) xy_data_array=numpy.abs(xy_data_arrays.prod(axis=0)) # Now we need to set entries to negative iff all # functions were negative at that point. neg_indices = (xy_data_arrays<0).all(axis=0) xy_data_array[neg_indices]=-xy_data_array[neg_indices] from matplotlib.colors import ListedColormap incol = rgbcolor(incol) outcol = rgbcolor(outcol) cmap = ListedColormap([incol, outcol]) cmap.set_over(outcol) cmap.set_under(incol) g = Graphics() # Reset aspect_ratio to 'automatic' in case scale is 'semilog[xy]'. # Otherwise matplotlib complains. scale = options.get('scale', None) if isinstance(scale, (list, tuple)): scale = scale[0] if scale == 'semilogy' or scale == 'semilogx': options['aspect_ratio'] = 'automatic' g._set_extra_kwds(Graphics._extract_kwds_for_show(options, ignore=['xmin', 'xmax'])) g.add_primitive(ContourPlot(xy_data_array, xrange,yrange, dict(contours=[-1e307, 0, 1e307], cmap=cmap, fill=True, **options))) if bordercol or borderstyle or borderwidth: cmap = [rgbcolor(bordercol)] if bordercol else ['black'] linestyles = [borderstyle] if borderstyle else None linewidths = [borderwidth] if borderwidth else None g.add_primitive(ContourPlot(xy_data_array, xrange, yrange, dict(linestyles=linestyles, linewidths=linewidths, contours=[0], cmap=[bordercol], fill=False, **options))) return g
def polygon2d(points, **options): r""" Returns a 2-dimensional polygon defined by ``points``. Type ``polygon2d.options`` for a dictionary of the default options for polygons. You can change this to change the defaults for all future polygons. Use ``polygon2d.reset()`` to reset to the default options. EXAMPLES: We create a purple-ish polygon:: sage: polygon2d([[1,2], [5,6], [5,0]], rgbcolor=(1,0,1)) By default, polygons are filled in, but we can make them without a fill as well:: sage: polygon2d([[1,2], [5,6], [5,0]], fill=False) In either case, the thickness of the border can be controlled:: sage: polygon2d([[1,2], [5,6], [5,0]], fill=False, thickness=4, color='orange') Some modern art -- a random polygon, with legend:: sage: v = [(randrange(-5,5), randrange(-5,5)) for _ in range(10)] sage: polygon2d(v, legend_label='some form') A purple hexagon:: sage: L = [[cos(pi*i/3),sin(pi*i/3)] for i in range(6)] sage: polygon2d(L, rgbcolor=(1,0,1)) A green deltoid:: sage: L = [[-1+cos(pi*i/100)*(1+cos(pi*i/100)),2*sin(pi*i/100)*(1-cos(pi*i/100))] for i in range(200)] sage: polygon2d(L, rgbcolor=(1/8,3/4,1/2)) A blue hypotrochoid:: sage: L = [[6*cos(pi*i/100)+5*cos((6/2)*pi*i/100),6*sin(pi*i/100)-5*sin((6/2)*pi*i/100)] for i in range(200)] sage: polygon2d(L, rgbcolor=(1/8,1/4,1/2)) Another one:: sage: n = 4; h = 5; b = 2 sage: L = [[n*cos(pi*i/100)+h*cos((n/b)*pi*i/100),n*sin(pi*i/100)-h*sin((n/b)*pi*i/100)] for i in range(200)] sage: polygon2d(L, rgbcolor=(1/8,1/4,3/4)) A purple epicycloid:: sage: m = 9; b = 1 sage: L = [[m*cos(pi*i/100)+b*cos((m/b)*pi*i/100),m*sin(pi*i/100)-b*sin((m/b)*pi*i/100)] for i in range(200)] sage: polygon2d(L, rgbcolor=(7/8,1/4,3/4)) A brown astroid:: sage: L = [[cos(pi*i/100)^3,sin(pi*i/100)^3] for i in range(200)] sage: polygon2d(L, rgbcolor=(3/4,1/4,1/4)) And, my favorite, a greenish blob:: sage: L = [[cos(pi*i/100)*(1+cos(pi*i/50)), sin(pi*i/100)*(1+sin(pi*i/50))] for i in range(200)] sage: polygon2d(L, rgbcolor=(1/8, 3/4, 1/2)) This one is for my wife:: sage: L = [[sin(pi*i/100)+sin(pi*i/50),-(1+cos(pi*i/100)+cos(pi*i/50))] for i in range(-100,100)] sage: polygon2d(L, rgbcolor=(1,1/4,1/2)) One can do the same one with a colored legend label:: sage: polygon2d(L, color='red', legend_label='For you!', legend_color='red') Polygons have a default aspect ratio of 1.0:: sage: polygon2d([[1,2], [5,6], [5,0]]).aspect_ratio() 1.0 AUTHORS: - David Joyner (2006-04-14): the long list of examples above. """ from sage.plot.plot import xydata_from_point_list from sage.plot.all import Graphics if options["thickness"] is None: # If the user did not specify thickness if options["fill"]: # If the user chose fill options["thickness"] = 0 else: options["thickness"] = 1 xdata, ydata = xydata_from_point_list(points) g = Graphics() # Reset aspect_ratio to 'automatic' in case scale is 'semilog[xy]'. # Otherwise matplotlib complains. scale = options.get('scale', None) if isinstance(scale, (list, tuple)): scale = scale[0] if scale == 'semilogy' or scale == 'semilogx': options['aspect_ratio'] = 'automatic' g._set_extra_kwds(Graphics._extract_kwds_for_show(options)) g.add_primitive(Polygon(xdata, ydata, options)) if options['legend_label']: g.legend(True) g._legend_colors = [options['legend_color']] return g
def plot_vector_field(f_g, xrange, yrange, **options): r""" ``plot_vector_field`` takes two functions of two variables xvar and yvar (for instance, if the variables are `x` and `y`, take `(f(x,y), g(x,y))`) and plots vector arrows of the function over the specified ranges, with xrange being of xvar between xmin and xmax, and yrange similarly (see below). ``plot_vector_field((f, g), (xvar, xmin, xmax), (yvar, ymin, ymax))`` EXAMPLES: Plot some vector fields involving sin and cos:: sage: x,y = var('x y') sage: plot_vector_field((sin(x), cos(y)), (x,-3,3), (y,-3,3)) Graphics object consisting of 1 graphics primitive :: sage: plot_vector_field(( y, (cos(x)-2)*sin(x)), (x,-pi,pi), (y,-pi,pi)) Graphics object consisting of 1 graphics primitive Plot a gradient field:: sage: u,v = var('u v') sage: f = exp(-(u^2+v^2)) sage: plot_vector_field(f.gradient(), (u,-2,2), (v,-2,2), color='blue') Graphics object consisting of 1 graphics primitive Plot two orthogonal vector fields:: sage: x,y = var('x,y') sage: a=plot_vector_field((x,y), (x,-3,3),(y,-3,3),color='blue') sage: b=plot_vector_field((y,-x),(x,-3,3),(y,-3,3),color='red') sage: show(a+b) We ignore function values that are infinite or NaN:: sage: x,y = var('x,y') sage: plot_vector_field( (-x/sqrt(x^2+y^2), -y/sqrt(x^2+y^2)), (x, -10, 10), (y, -10, 10)) Graphics object consisting of 1 graphics primitive :: sage: x,y = var('x,y') sage: plot_vector_field( (-x/sqrt(x+y), -y/sqrt(x+y)), (x, -10, 10), (y, -10, 10)) Graphics object consisting of 1 graphics primitive Extra options will get passed on to show(), as long as they are valid:: sage: plot_vector_field((x, y), (x, -2, 2), (y, -2, 2), xmax=10) Graphics object consisting of 1 graphics primitive sage: plot_vector_field((x, y), (x, -2, 2), (y, -2, 2)).show(xmax=10) # These are equivalent """ (f, g) = f_g from sage.plot.all import Graphics from sage.plot.misc import setup_for_eval_on_grid z, ranges = setup_for_eval_on_grid([f,g], [xrange, yrange], options['plot_points']) f,g = z xpos_array, ypos_array, xvec_array, yvec_array = [],[],[],[] for x in xsrange(*ranges[0], include_endpoint=True): for y in xsrange(*ranges[1], include_endpoint=True): xpos_array.append(x) ypos_array.append(y) xvec_array.append(f(x,y)) yvec_array.append(g(x,y)) import numpy xvec_array = numpy.ma.masked_invalid(numpy.array(xvec_array, dtype=float)) yvec_array = numpy.ma.masked_invalid(numpy.array(yvec_array, dtype=float)) g = Graphics() g._set_extra_kwds(Graphics._extract_kwds_for_show(options)) g.add_primitive(PlotField(xpos_array, ypos_array, xvec_array, yvec_array, options)) return g
def arc(center, r1, r2=None, angle=0.0, sector=(0.0,2*pi), **options): r""" An arc (that is a portion of a circle or an ellipse) Type ``arc.options`` to see all options. INPUT: - ``center`` - 2-tuple of real numbers - position of the center. - ``r1``, ``r2`` - positive real numbers - radii of the ellipse. If only ``r1`` is set, then the two radii are supposed to be equal and this function returns an arc of of circle. - ``angle`` - real number - angle between the horizontal and the axis that corresponds to ``r1``. - ``sector`` - 2-tuple (default: (0,2*pi))- angles sector in which the arc will be drawn. OPTIONS: - ``alpha`` - float (default: 1) - transparency - ``thickness`` - float (default: 1) - thickness of the arc - ``color``, ``rgbcolor`` - string or 2-tuple (default: 'blue') - the color of the arc - ``linestyle`` - string (default: ``'solid'``) - The style of the line, which is one of ``'dashed'``, ``'dotted'``, ``'solid'``, ``'dashdot'``, or ``'--'``, ``':'``, ``'-'``, ``'-.'``, respectively. EXAMPLES: Plot an arc of circle centered at (0,0) with radius 1 in the sector `(\pi/4,3*\pi/4)`:: sage: arc((0,0), 1, sector=(pi/4,3*pi/4)) Graphics object consisting of 1 graphics primitive Plot an arc of an ellipse between the angles 0 and `\pi/2`:: sage: arc((2,3), 2, 1, sector=(0,pi/2)) Graphics object consisting of 1 graphics primitive Plot an arc of a rotated ellipse between the angles 0 and `\pi/2`:: sage: arc((2,3), 2, 1, angle=pi/5, sector=(0,pi/2)) Graphics object consisting of 1 graphics primitive Plot an arc of an ellipse in red with a dashed linestyle:: sage: arc((0,0), 2, 1, 0, (0,pi/2), linestyle="dashed", color="red") Graphics object consisting of 1 graphics primitive sage: arc((0,0), 2, 1, 0, (0,pi/2), linestyle="--", color="red") Graphics object consisting of 1 graphics primitive The default aspect ratio for arcs is 1.0:: sage: arc((0,0), 1, sector=(pi/4,3*pi/4)).aspect_ratio() 1.0 It is not possible to draw arcs in 3D:: sage: A = arc((0,0,0), 1) Traceback (most recent call last): ... NotImplementedError """ from sage.plot.all import Graphics # Reset aspect_ratio to 'automatic' in case scale is 'semilog[xy]'. # Otherwise matplotlib complains. scale = options.get('scale', None) if isinstance(scale, (list, tuple)): scale = scale[0] if scale == 'semilogy' or scale == 'semilogx': options['aspect_ratio'] = 'automatic' if len(center)==2: if r2 is None: r2 = r1 g = Graphics() g._set_extra_kwds(Graphics._extract_kwds_for_show(options)) if len(sector) != 2: raise ValueError("the sector must consist of two angles") g.add_primitive(Arc( center[0],center[1], r1,r2, angle, sector[0],sector[1], options)) return g elif len(center)==3: raise NotImplementedError
def point2d(points, **options): r""" A point of size ``size`` defined by point = `(x,y)`. Point takes either a single tuple of coordinates or a list of tuples. Type ``point2d.options`` to see all options. EXAMPLES: A purple point from a single tuple or coordinates:: sage: point((0.5, 0.5), rgbcolor=hue(0.75)) Passing an empty list returns an empty plot:: sage: point([]) If you need a 2D point to live in 3-space later, this is possible:: sage: A=point((1,1)) sage: a=A[0];a Point set defined by 1 point(s) sage: b=a.plot3d(z=3) This is also true with multiple points:: sage: P=point([(0,0), (1,1)]) sage: p=P[0] sage: q=p.plot3d(z=[2,3]) Here are some random larger red points, given as a list of tuples:: sage: point(((0.5, 0.5), (1, 2), (0.5, 0.9), (-1, -1)), rgbcolor=hue(1), size=30) And an example with a legend:: sage: point((0,0), rgbcolor='black', pointsize=40, legend_label='origin') The legend can be colored:: sage: P = points([(0,0),(1,0)], pointsize=40, legend_label='origin', legend_color='red') sage: P + plot(x^2,(x,0,1), legend_label='plot', legend_color='green') Extra options will get passed on to show(), as long as they are valid:: sage: point([(cos(theta), sin(theta)) for theta in srange(0, 2*pi, pi/8)], frame=True) sage: point([(cos(theta), sin(theta)) for theta in srange(0, 2*pi, pi/8)]).show(frame=True) # These are equivalent For plotting data, we can use a logarithmic scale, as long as we are sure not to include any nonpositive points in the logarithmic direction:: sage: point([(1,2),(2,4),(3,4),(4,8),(4.5,32)],scale='semilogy',base=2) Since Sage Version 4.4 (ticket #8599), the size of a 2d point can be given by the argument ``size`` instead of ``pointsize``. The argument ``pointsize`` is still supported:: sage: point((3,4), size=100) :: sage: point((3,4), pointsize=100) """ from sage.plot.plot import xydata_from_point_list from sage.plot.all import Graphics if points == []: return Graphics() xdata, ydata = xydata_from_point_list(points) g = Graphics() g._set_extra_kwds(Graphics._extract_kwds_for_show(options)) g.add_primitive(Point(xdata, ydata, options)) if options['legend_label']: g.legend(True) g._legend_colors = [options['legend_color']] return g
def ellipse(center, r1, r2, angle=0, **options): """ Return an ellipse centered at a point center = ``(x,y)`` with radii = ``r1,r2`` and angle ``angle``. Type ``ellipse.options`` to see all options. INPUT: - ``center`` - 2-tuple of real numbers - coordinates of the center - ``r1``, ``r2`` - positive real numbers - the radii of the ellipse - ``angle`` - real number (default: 0) - the angle between the first axis and the horizontal OPTIONS: - ``alpha`` - default: 1 - transparency - ``fill`` - default: False - whether to fill the ellipse or not - ``thickness`` - default: 1 - thickness of the line - ``linestyle`` - default: ``'solid'`` - The style of the line, which is one of ``'dashed'``, ``'dotted'``, ``'solid'``, ``'dashdot'``, or ``'--'``, ``':'``, ``'-'``, ``'-.'``, respectively. - ``edgecolor`` - default: 'black' - color of the contour - ``facecolor`` - default: 'red' - color of the filling - ``rgbcolor`` - 2D or 3D plotting. This option overrides ``edgecolor`` and ``facecolor`` for 2D plotting. - ``legend_label`` - the label for this item in the legend - ``legend_color`` - the color for the legend label EXAMPLES: An ellipse centered at (0,0) with major and minor axes of lengths 2 and 1. Note that the default color is blue:: sage: ellipse((0,0),2,1) More complicated examples with tilted axes and drawing options:: sage: ellipse((0,0),3,1,pi/6,fill=True,alpha=0.3,linestyle="dashed") sage: ellipse((0,0),3,1,pi/6,fill=True,alpha=0.3,linestyle="--") :: sage: ellipse((0,0),3,1,pi/6,fill=True,edgecolor='black',facecolor='red') We see that ``rgbcolor`` overrides these other options, as this plot is green:: sage: ellipse((0,0),3,1,pi/6,fill=True,edgecolor='black',facecolor='red',rgbcolor='green') The default aspect ratio for ellipses is 1.0:: sage: ellipse((0,0),2,1).aspect_ratio() 1.0 One cannot yet plot ellipses in 3D:: sage: ellipse((0,0,0),2,1) Traceback (most recent call last): ... NotImplementedError: plotting ellipse in 3D is not implemented We can also give ellipses a legend:: sage: ellipse((0,0),2,1,legend_label="My ellipse", legend_color='green') """ from sage.plot.all import Graphics g = Graphics() # Reset aspect_ratio to 'automatic' in case scale is 'semilog[xy]'. # Otherwise matplotlib complains. scale = options.get('scale', None) if isinstance(scale, (list, tuple)): scale = scale[0] if scale == 'semilogy' or scale == 'semilogx': options['aspect_ratio'] = 'automatic' g._set_extra_kwds(Graphics._extract_kwds_for_show(options)) g.add_primitive(Ellipse(center[0],center[1],r1,r2,angle,options)) if options['legend_label']: g.legend(True) g._legend_colors = [options['legend_color']] if len(center)==2: return g elif len(center)==3: raise NotImplementedError("plotting ellipse in 3D is not implemented")
def text(string, xy, **options): r""" Returns a 2D text graphics object at the point `(x,y)`. Type ``text.options`` for a dictionary of options for 2D text. 2D OPTIONS: - ``fontsize`` - How big the text is - ``rgbcolor`` - The color as an RGB tuple - ``hue`` - The color given as a hue - ``rotation`` - How to rotate the text: angle in degrees, vertical, horizontal - ``vertical_alignment`` - How to align vertically: top, center, bottom - ``horizontal_alignment`` - How to align horizontally: left, center, right - ``axis_coords`` - (default: False) if True, use axis coordinates, so that (0,0) is the lower left and (1,1) upper right, regardless of the x and y range of plotted values. EXAMPLES:: sage: text("Sage is really neat!!",(2,12)) Graphics object consisting of 1 graphics primitive The same text in larger font and colored red:: sage: text("Sage is really neat!!",(2,12),fontsize=20,rgbcolor=(1,0,0)) Graphics object consisting of 1 graphics primitive Same text but guaranteed to be in the lower left no matter what:: sage: text("Sage is really neat!!",(0,0), axis_coords=True, horizontal_alignment='left') Graphics object consisting of 1 graphics primitive Same text rotated around the left, bottom corner of the text:: sage: text("Sage is really neat!!",(0,0), rotation=45.0, horizontal_alignment='left', vertical_alignment='bottom') Graphics object consisting of 1 graphics primitive Same text oriented vertically:: sage: text("Sage is really neat!!",(0,0), rotation="vertical") Graphics object consisting of 1 graphics primitive You can also align text differently:: sage: t1 = text("Hello",(1,1), vertical_alignment="top") sage: t2 = text("World", (1,0.5), horizontal_alignment="left") sage: t1 + t2 # render the sum Graphics object consisting of 2 graphics primitives You can save text as part of PDF output:: sage: text("sage", (0,0), rgbcolor=(0,0,0)).save(os.path.join(SAGE_TMP, 'a.pdf')) Text must be 2D (use the text3d command for 3D text):: sage: t = text("hi",(1,2,3)) Traceback (most recent call last): ... ValueError: use text3d instead for text in 3d sage: t = text3d("hi",(1,2,3)) Extra options will get passed on to show(), as long as they are valid:: sage: text("MATH IS AWESOME", (0, 0), fontsize=40, axes=False) Graphics object consisting of 1 graphics primitive sage: text("MATH IS AWESOME", (0, 0), fontsize=40).show(axes=False) # These are equivalent """ try: x, y = xy except ValueError: if isinstance(xy, (list, tuple)) and len(xy) == 3: raise ValueError("use text3d instead for text in 3d") raise from sage.plot.all import Graphics options['rgbcolor'] = to_mpl_color(options['rgbcolor']) point = (float(x), float(y)) g = Graphics() g._set_extra_kwds( Graphics._extract_kwds_for_show(options, ignore='fontsize')) g.add_primitive(Text(string, point, options)) return g
def point2d(points, **options): r""" A point of size ``size`` defined by point = `(x,y)`. INPUT: - ``points`` - either a single point (as a tuple), a list of points, a single complex number, or a list of complex numbers. - ``alpha`` -- How transparent the point is. - ``faceted`` -- If True color the edge of the point. (only for 2D plots) - ``hue`` -- The color given as a hue. - ``legend_color`` -- The color of the legend text - ``legend_label`` -- The label for this item in the legend. - ``marker`` -- the marker symbol for 2D plots only (see documentation of :func:`plot` for details) - ``markeredgecolor`` -- the color of the marker edge (only for 2D plots) - ``rgbcolor`` -- The color as an RGB tuple. - ``size`` -- How big the point is (i.e., area in points^2=(1/72 inch)^2). - ``zorder`` -- The layer level in which to draw EXAMPLES: A purple point from a single tuple or coordinates:: sage: point((0.5, 0.5), rgbcolor=hue(0.75)) Graphics object consisting of 1 graphics primitive Points with customized markers and edge colors:: sage: r = [(random(), random()) for _ in range(10)] sage: point(r, marker='d', markeredgecolor='red', size=20) Graphics object consisting of 1 graphics primitive Passing an empty list returns an empty plot:: sage: point([]) Graphics object consisting of 0 graphics primitives sage: import numpy; point(numpy.array([])) Graphics object consisting of 0 graphics primitives If you need a 2D point to live in 3-space later, this is possible:: sage: A=point((1,1)) sage: a=A[0];a Point set defined by 1 point(s) sage: b=a.plot3d(z=3) This is also true with multiple points:: sage: P=point([(0,0), (1,1)]) sage: p=P[0] sage: q=p.plot3d(z=[2,3]) Here are some random larger red points, given as a list of tuples:: sage: point(((0.5, 0.5), (1, 2), (0.5, 0.9), (-1, -1)), rgbcolor=hue(1), size=30) Graphics object consisting of 1 graphics primitive And an example with a legend:: sage: point((0,0), rgbcolor='black', pointsize=40, legend_label='origin') Graphics object consisting of 1 graphics primitive The legend can be colored:: sage: P = points([(0,0),(1,0)], pointsize=40, legend_label='origin', legend_color='red') sage: P + plot(x^2,(x,0,1), legend_label='plot', legend_color='green') Graphics object consisting of 2 graphics primitives Extra options will get passed on to show(), as long as they are valid:: sage: point([(cos(theta), sin(theta)) for theta in srange(0, 2*pi, pi/8)], frame=True) Graphics object consisting of 1 graphics primitive sage: point([(cos(theta), sin(theta)) for theta in srange(0, 2*pi, pi/8)]).show(frame=True) # These are equivalent For plotting data, we can use a logarithmic scale, as long as we are sure not to include any nonpositive points in the logarithmic direction:: sage: point([(1,2),(2,4),(3,4),(4,8),(4.5,32)],scale='semilogy',base=2) Graphics object consisting of 1 graphics primitive Since Sage Version 4.4 (:trac:`8599`), the size of a 2d point can be given by the argument ``size`` instead of ``pointsize``. The argument ``pointsize`` is still supported:: sage: point((3,4), size=100) Graphics object consisting of 1 graphics primitive :: sage: point((3,4), pointsize=100) Graphics object consisting of 1 graphics primitive We can plot a single complex number:: sage: point(CC(1+I), pointsize=100) Graphics object consisting of 1 graphics primitive We can also plot a list of complex numbers:: sage: point([CC(I), CC(I+1), CC(2+2*I)], pointsize=100) Graphics object consisting of 1 graphics primitive """ from sage.plot.plot import xydata_from_point_list from sage.plot.all import Graphics from sage.rings.all import CC, CDF if points in CC or points in CDF: pass else: try: if not points: return Graphics() except ValueError: # numpy raises a ValueError if not empty pass xdata, ydata = xydata_from_point_list(points) g = Graphics() g._set_extra_kwds(Graphics._extract_kwds_for_show(options)) g.add_primitive(Point(xdata, ydata, options)) if options['legend_label']: g.legend(True) g._legend_colors = [options['legend_color']] return g
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): ... TypeError: mat must be a Matrix or a two dimensional array 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.matrix 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 plot(self, **kwds): """ Returns a graphics object representing the (di)graph. INPUT: The options accepted by this method are to be found in the documentation of the :mod:`sage.graphs.graph_plot` module, and the :meth:`~sage.plot.graphics.Graphics.show` method. .. NOTE:: See :mod:`the module's documentation <sage.graphs.graph_plot>` for information on default values of this method. We can specify some pretty precise plotting of familiar graphs:: sage: from math import sin, cos, pi sage: P = graphs.PetersenGraph() sage: d = {'#FF0000':[0,5], '#FF9900':[1,6], '#FFFF00':[2,7], '#00FF00':[3,8], '#0000FF':[4,9]} sage: pos_dict = {} sage: for i in range(5): ... x = float(cos(pi/2 + ((2*pi)/5)*i)) ... y = float(sin(pi/2 + ((2*pi)/5)*i)) ... pos_dict[i] = [x,y] ... sage: for i in range(10)[5:]: ... x = float(0.5*cos(pi/2 + ((2*pi)/5)*i)) ... y = float(0.5*sin(pi/2 + ((2*pi)/5)*i)) ... pos_dict[i] = [x,y] ... sage: pl = P.graphplot(pos=pos_dict, vertex_colors=d) sage: pl.show() Here are some more common graphs with typical options:: sage: C = graphs.CubeGraph(8) sage: P = C.graphplot(vertex_labels=False, vertex_size=0, graph_border=True) sage: P.show() sage: G = graphs.HeawoodGraph().copy(sparse=True) sage: for u,v,l in G.edges(): ... G.set_edge_label(u,v,'(' + str(u) + ',' + str(v) + ')') sage: G.graphplot(edge_labels=True).show() The options for plotting also work with directed graphs:: sage: D = DiGraph( { 0: [1, 10, 19], 1: [8, 2], 2: [3, 6], 3: [19, 4], 4: [17, 5], 5: [6, 15], 6: [7], 7: [8, 14], 8: [9], 9: [10, 13], 10: [11], 11: [12, 18], 12: [16, 13], 13: [14], 14: [15], 15: [16], 16: [17], 17: [18], 18: [19], 19: []}) sage: for u,v,l in D.edges(): ... D.set_edge_label(u,v,'(' + str(u) + ',' + str(v) + ')') sage: D.graphplot(edge_labels=True, layout='circular').show() This example shows off the coloring of edges:: sage: from sage.plot.colors import rainbow sage: C = graphs.CubeGraph(5) sage: R = rainbow(5) sage: edge_colors = {} sage: for i in range(5): ... edge_colors[R[i]] = [] sage: for u,v,l in C.edges(): ... for i in range(5): ... if u[i] != v[i]: ... edge_colors[R[i]].append((u,v,l)) sage: C.graphplot(vertex_labels=False, vertex_size=0, edge_colors=edge_colors).show() With the ``partition`` option, we can separate out same-color groups of vertices:: sage: D = graphs.DodecahedralGraph() sage: Pi = [[6,5,15,14,7],[16,13,8,2,4],[12,17,9,3,1],[0,19,18,10,11]] sage: D.show(partition=Pi) Loops are also plotted correctly:: sage: G = graphs.PetersenGraph() sage: G.allow_loops(True) sage: G.add_edge(0,0) sage: G.show() :: sage: D = DiGraph({0:[0,1], 1:[2], 2:[3]}, loops=True) sage: D.show() sage: D.show(edge_colors={(0,1,0):[(0,1,None),(1,2,None)],(0,0,0):[(2,3,None)]}) More options:: sage: pos = {0:[0.0, 1.5], 1:[-0.8, 0.3], 2:[-0.6, -0.8], 3:[0.6, -0.8], 4:[0.8, 0.3]} sage: g = Graph({0:[1], 1:[2], 2:[3], 3:[4], 4:[0]}) sage: g.graphplot(pos=pos, layout='spring', iterations=0).plot() Graphics object consisting of 11 graphics primitives sage: G = Graph() sage: P = G.graphplot().plot() sage: P.axes() False sage: G = DiGraph() sage: P = G.graphplot().plot() sage: P.axes() False We can plot multiple graphs:: sage: T = list(graphs.trees(7)) sage: t = T[3] sage: t.graphplot(heights={0:[0], 1:[4,5,1], 2:[2], 3:[3,6]}).plot() Graphics object consisting of 14 graphics primitives :: sage: T = list(graphs.trees(7)) sage: t = T[3] sage: t.graphplot(heights={0:[0], 1:[4,5,1], 2:[2], 3:[3,6]}).plot() Graphics object consisting of 14 graphics primitives sage: t.set_edge_label(0,1,-7) sage: t.set_edge_label(0,5,3) sage: t.set_edge_label(0,5,99) sage: t.set_edge_label(1,2,1000) sage: t.set_edge_label(3,2,'spam') sage: t.set_edge_label(2,6,3/2) sage: t.set_edge_label(0,4,66) sage: t.graphplot(heights={0:[0], 1:[4,5,1], 2:[2], 3:[3,6]}, edge_labels=True).plot() Graphics object consisting of 20 graphics primitives :: sage: T = list(graphs.trees(7)) sage: t = T[3] sage: t.graphplot(layout='tree').show() The tree layout is also useful:: sage: t = DiGraph('JCC???@A??GO??CO??GO??') sage: t.graphplot(layout='tree', tree_root=0, tree_orientation="up").show() More examples:: sage: D = DiGraph({0:[1,2,3], 2:[1,4], 3:[0]}) sage: D.graphplot().show() sage: D = DiGraph(multiedges=True, sparse=True) sage: for i in range(5): ... D.add_edge((i,i+1,'a')) ... D.add_edge((i,i-1,'b')) sage: D.graphplot(edge_labels=True,edge_colors=D._color_by_label()).plot() Graphics object consisting of 34 graphics primitives sage: g = Graph({}, loops=True, multiedges=True, sparse=True) sage: g.add_edges([(0,0,'a'),(0,0,'b'),(0,1,'c'),(0,1,'d'), ... (0,1,'e'),(0,1,'f'),(0,1,'f'),(2,1,'g'),(2,2,'h')]) sage: g.graphplot(edge_labels=True, color_by_label=True, edge_style='dashed').plot() Graphics object consisting of 22 graphics primitives The ``edge_style`` option may be provided in the short format too:: sage: g.graphplot(edge_labels=True, color_by_label=True, edge_style='--').plot() Graphics object consisting of 22 graphics primitives TESTS: Make sure that show options work with plot also:: sage: g = Graph({}) sage: g.plot(title='empty graph', axes=True) Graphics object consisting of 0 graphics primitives Check for invalid inputs:: sage: p = graphs.PetersenGraph().plot(egabrag='garbage') Traceback (most recent call last): ... ValueError: Invalid input 'egabrag=garbage' Make sure that no graphics primitive is clipped:: sage: tadpole = Graph({0:[0,1]}).plot() sage: bbox = tadpole.get_minmax_data() sage: for part in tadpole: ....: part_bbox = part.get_minmax_data() ....: assert bbox['xmin'] <= part_bbox['xmin'] <= part_bbox['xmax'] <= bbox['xmax'] ....: assert bbox['ymin'] <= part_bbox['ymin'] <= part_bbox['ymax'] <= bbox['ymax'] """ G = Graphics() options = self._options.copy() options.update(kwds) G._set_extra_kwds(Graphics._extract_kwds_for_show(options)) # Check the arguments for o in options: if o not in graphplot_options and o not in G._extra_kwds: raise ValueError("Invalid input '{}={}'".format(o, options[o])) for comp in self._plot_components.values(): if not isinstance(comp, list): G += comp else: for item in comp: G += item if self._options['graph_border']: xmin = G.xmin() xmax = G.xmax() ymin = G.ymin() ymax = G.ymax() dx = (xmax-xmin)/10.0 dy = (ymax-ymin)/10.0 border = (line([( xmin - dx, ymin - dy), ( xmin - dx, ymax + dy ), ( xmax + dx, ymax + dy ), ( xmax + dx, ymin - dy ), ( xmin - dx, ymin - dy )], thickness=1.3)) border.axes_range(xmin = (xmin - dx), xmax = (xmax + dx), ymin = (ymin - dy), ymax = (ymax + dy)) G += border G.set_aspect_ratio(1) G.axes(False) return G
def density_plot(f, xrange, yrange, **options): r""" ``density_plot`` takes a function of two variables, `f(x,y)` and plots the height of the function over the specified ``xrange`` and ``yrange`` as demonstrated below. ``density_plot(f, (xmin,xmax), (ymin,ymax), ...)`` INPUT: - ``f`` -- a function of two variables - ``(xmin,xmax)`` -- 2-tuple, the range of ``x`` values OR 3-tuple ``(x,xmin,xmax)`` - ``(ymin,ymax)`` -- 2-tuple, the range of ``y`` values OR 3-tuple ``(y,ymin,ymax)`` The following inputs must all be passed in as named parameters: - ``plot_points`` -- integer (default: 25); number of points to plot in each direction of the grid - ``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. - ``interpolation`` -- string (default: ``'catrom'``), the interpolation method to use: ``'bilinear'``, ``'bicubic'``, ``'spline16'``, ``'spline36'``, ``'quadric'``, ``'gaussian'``, ``'sinc'``, ``'bessel'``, ``'mitchell'``, ``'lanczos'``, ``'catrom'``, ``'hermite'``, ``'hanning'``, ``'hamming'``, ``'kaiser'`` EXAMPLES: Here we plot a simple function of two variables. Note that since the input function is an expression, we need to explicitly declare the variables in 3-tuples for the range:: sage: x,y = var('x,y') sage: density_plot(sin(x) * sin(y), (x,-2,2), (y,-2,2)) Graphics object consisting of 1 graphics primitive .. PLOT:: x,y = var('x,y') g = density_plot(sin(x) * sin(y), (x,-2,2), (y,-2,2)) sphinx_plot(g) Here we change the ranges and add some options; note that here ``f`` is callable (has variables declared), so we can use 2-tuple ranges:: sage: x,y = var('x,y') sage: f(x,y) = x^2 * cos(x*y) sage: density_plot(f, (x,-10,5), (y,-5,5), interpolation='sinc', plot_points=100) Graphics object consisting of 1 graphics primitive .. PLOT:: x,y = var('x,y') def f(x,y): return x**2 * cos(x*y) g = density_plot(f, (x,-10,5), (y,-5,5), interpolation='sinc', plot_points=100) sphinx_plot(g) An even more complicated plot:: sage: x,y = var('x,y') sage: density_plot(sin(x^2+y^2) * cos(x) * sin(y), (x,-4,4), (y,-4,4), cmap='jet', plot_points=100) Graphics object consisting of 1 graphics primitive .. PLOT:: x,y = var('x,y') g = density_plot(sin(x**2 + y**2)*cos(x)*sin(y), (x,-4,4), (y,-4,4), cmap='jet', plot_points=100) sphinx_plot(g) This should show a "spotlight" right on the origin:: sage: x,y = var('x,y') sage: density_plot(1/(x^10 + y^10), (x,-10,10), (y,-10,10)) Graphics object consisting of 1 graphics primitive .. PLOT:: x,y = var('x,y') g = density_plot(1/(x**10 + y**10), (x,-10,10), (y,-10,10)) sphinx_plot(g) Some elliptic curves, but with symbolic endpoints. In the first example, the plot is rotated 90 degrees because we switch the variables `x`, `y`:: sage: density_plot(y^2 + 1 - x^3 - x, (y,-pi,pi), (x,-pi,pi)) Graphics object consisting of 1 graphics primitive .. PLOT:: x,y = var('x,y') g = density_plot(y**2 + 1 - x**3 - x, (y,-pi,pi), (x,-pi,pi)) sphinx_plot(g) :: sage: density_plot(y^2 + 1 - x^3 - x, (x,-pi,pi), (y,-pi,pi)) Graphics object consisting of 1 graphics primitive .. PLOT:: x,y = var('x,y') g = density_plot(y**2 + 1 - x**3 - x, (x,-pi,pi), (y,-pi,pi)) sphinx_plot(g) Extra options will get passed on to show(), as long as they are valid:: sage: density_plot(log(x) + log(y), (x,1,10), (y,1,10), dpi=20) Graphics object consisting of 1 graphics primitive .. PLOT:: x,y = var('x,y') g = density_plot(log(x) + log(y), (x,1,10), (y,1,10), dpi=20) sphinx_plot(g) :: sage: density_plot(log(x) + log(y), (x,1,10), (y,1,10)).show(dpi=20) # These are equivalent TESTS: Check that :trac:`15315` is fixed, i.e., density_plot respects the ``aspect_ratio`` parameter. Without the fix, it looks like a thin line of width a few mm. With the fix it should look like a nice fat layered image:: sage: density_plot((x*y)^(1/2), (x,0,3), (y,0,500), aspect_ratio=.01) Graphics object consisting of 1 graphics primitive Default ``aspect_ratio`` is ``"automatic"``, and that should work too:: sage: density_plot((x*y)^(1/2), (x,0,3), (y,0,500)) Graphics object consisting of 1 graphics primitive """ from sage.plot.all import Graphics from sage.plot.misc import setup_for_eval_on_grid g, ranges = setup_for_eval_on_grid([f], [xrange, yrange], options['plot_points']) g = g[0] xrange, yrange = [r[:2] for r in ranges] xy_data_array = [[g(x,y) for x in xsrange(*ranges[0], include_endpoint=True)] for y in xsrange(*ranges[1], include_endpoint=True)] g = Graphics() g._set_extra_kwds(Graphics._extract_kwds_for_show(options, ignore=['xmin','xmax'])) g.add_primitive(DensityPlot(xy_data_array, xrange, yrange, options)) return g
def contour_plot(f, xrange, yrange, **options): r""" ``contour_plot`` takes a function of two variables, `f(x,y)` and plots contour lines of the function over the specified ``xrange`` and ``yrange`` as demonstrated below. ``contour_plot(f, (xmin, xmax), (ymin, ymax), ...)`` INPUT: - ``f`` -- a function of two variables - ``(xmin, xmax)`` -- 2-tuple, the range of ``x`` values OR 3-tuple ``(x,xmin,xmax)`` - ``(ymin, ymax)`` -- 2-tuple, the range of ``y`` values OR 3-tuple ``(y,ymin,ymax)`` The following inputs must all be passed in as named parameters: - ``plot_points`` -- integer (default: 100); number of points to plot in each direction of the grid. For old computers, 25 is fine, but should not be used to verify specific intersection points. - ``fill`` -- bool (default: ``True``), whether to color in the area between contour lines - ``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. - ``contours`` -- integer or list of numbers (default: ``None``): If a list of numbers is given, then this specifies the contour levels to use. If an integer is given, then this many contour lines are used, but the exact levels are determined automatically. If ``None`` is passed (or the option is not given), then the number of contour lines is determined automatically, and is usually about 5. - ``linewidths`` -- integer or list of integer (default: None), if a single integer all levels will be of the width given, otherwise the levels will be plotted with the width in the order given. If the list is shorter than the number of contours, then the widths will be repeated cyclically. - ``linestyles`` -- string or list of strings (default: None), the style of the lines to be plotted, one of: ``"solid"``, ``"dashed"``, ``"dashdot"``, ``"dotted"``, respectively ``"-"``, ``"--"``, ``"-."``, ``":"``. If the list is shorter than the number of contours, then the styles will be repeated cyclically. - ``labels`` -- boolean (default: False) Show level labels or not. The following options are to adjust the style and placement of labels, they have no effect if no labels are shown. - ``label_fontsize`` -- integer (default: 9), the font size of the labels. - ``label_colors`` -- string or sequence of colors (default: None) If a string, gives the name of a single color with which to draw all labels. If a sequence, gives the colors of the labels. A color is a string giving the name of one or a 3-tuple of floats. - ``label_inline`` -- boolean (default: False if fill is True, otherwise True), controls whether the underlying contour is removed or not. - ``label_inline_spacing`` -- integer (default: 3), When inline, this is the amount of contour that is removed from each side, in pixels. - ``label_fmt`` -- a format string (default: "%1.2f"), this is used to get the label text from the level. This can also be a dictionary with the contour levels as keys and corresponding text string labels as values. It can also be any callable which returns a string when called with a numeric contour level. - ``colorbar`` -- boolean (default: False) Show a colorbar or not. The following options are 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_spacing`` -- string (default: 'proportional'). If 'proportional', make the contour divisions proportional to values. If 'uniform', space the colorbar divisions uniformly, without regard for numeric values. - ``legend_label`` -- the label for this item in the legend - ``region`` - (default: None) If region is given, it must be a function of two variables. Only segments of the surface where region(x,y) returns a number >0 will be included in the plot. EXAMPLES: Here we plot a simple function of two variables. Note that since the input function is an expression, we need to explicitly declare the variables in 3-tuples for the range:: sage: x,y = var('x,y') sage: contour_plot(cos(x^2+y^2), (x, -4, 4), (y, -4, 4)) Here we change the ranges and add some options:: sage: x,y = var('x,y') sage: contour_plot((x^2)*cos(x*y), (x, -10, 5), (y, -5, 5), fill=False, plot_points=150) An even more complicated plot:: sage: x,y = var('x,y') sage: contour_plot(sin(x^2 + y^2)*cos(x)*sin(y), (x, -4, 4), (y, -4, 4),plot_points=150) Some elliptic curves, but with symbolic endpoints. In the first example, the plot is rotated 90 degrees because we switch the variables `x`, `y`:: sage: x,y = var('x,y') sage: contour_plot(y^2 + 1 - x^3 - x, (y,-pi,pi), (x,-pi,pi)) :: sage: contour_plot(y^2 + 1 - x^3 - x, (x,-pi,pi), (y,-pi,pi)) We can play with the contour levels:: sage: x,y = var('x,y') sage: f(x,y) = x^2 + y^2 sage: contour_plot(f, (-2, 2), (-2, 2)) :: sage: contour_plot(f, (-2, 2), (-2, 2), contours=2, cmap=[(1,0,0), (0,1,0), (0,0,1)]) :: sage: contour_plot(f, (-2, 2), (-2, 2), contours=(0.1, 1.0, 1.2, 1.4), cmap='hsv') :: sage: contour_plot(f, (-2, 2), (-2, 2), contours=(1.0,), fill=False) :: sage: contour_plot(x-y^2,(x,-5,5),(y,-3,3),contours=[-4,0,1]) We can change the style of the lines:: sage: contour_plot(f, (-2,2), (-2,2), fill=False, linewidths=10) :: sage: contour_plot(f, (-2,2), (-2,2), fill=False, linestyles='dashdot') :: sage: P=contour_plot(x^2-y^2,(x,-3,3),(y,-3,3),contours=[0,1,2,3,4],\ ... linewidths=[1,5],linestyles=['solid','dashed'],fill=False) sage: P :: sage: P=contour_plot(x^2-y^2,(x,-3,3),(y,-3,3),contours=[0,1,2,3,4],\ ... linewidths=[1,5],linestyles=['solid','dashed']) sage: P sage: P=contour_plot(x^2-y^2,(x,-3,3),(y,-3,3),contours=[0,1,2,3,4],\ ... linewidths=[1,5],linestyles=['-',':']) sage: P We can add labels and play with them:: sage: contour_plot(y^2 + 1 - x^3 - x, (x,-pi,pi), (y,-pi,pi), fill=False, cmap='hsv', labels=True) :: sage: P=contour_plot(y^2 + 1 - x^3 - x, (x,-pi,pi), (y,-pi,pi), fill=False, cmap='hsv',\ ... labels=True, label_fmt="%1.0f", label_colors='black') sage: P :: sage: P=contour_plot(y^2 + 1 - x^3 - x, (x,-pi,pi), (y,-pi,pi), fill=False, cmap='hsv',labels=True,\ ... contours=[-4,0,4], label_fmt={-4:"low", 0:"medium", 4: "hi"}, label_colors='black') sage: P :: sage: P=contour_plot(y^2 + 1 - x^3 - x, (x,-pi,pi), (y,-pi,pi), fill=False, cmap='hsv',labels=True,\ ... contours=[-4,0,4], label_fmt=lambda x: "$z=%s$"%x, label_colors='black', label_inline=True, \ ... label_fontsize=12) sage: P :: sage: P=contour_plot(y^2 + 1 - x^3 - x, (x,-pi,pi), (y,-pi,pi), \ ... fill=False, cmap='hsv', labels=True, label_fontsize=18) sage: P :: sage: P=contour_plot(y^2 + 1 - x^3 - x, (x,-pi,pi), (y,-pi,pi), \ ... fill=False, cmap='hsv', labels=True, label_inline_spacing=1) sage: P :: sage: P= contour_plot(y^2 + 1 - x^3 - x, (x,-pi,pi), (y,-pi,pi), \ ... fill=False, cmap='hsv', labels=True, label_inline=False) sage: P We can change the color of the labels if so desired:: sage: contour_plot(f, (-2,2), (-2,2), labels=True, label_colors='red') We can add a colorbar as well:: sage: f(x,y)=x^2-y^2 sage: contour_plot(f, (x,-3,3), (y,-3,3), colorbar=True) :: sage: contour_plot(f, (x,-3,3), (y,-3,3), colorbar=True,colorbar_orientation='horizontal') :: sage: contour_plot(f, (x,-3,3), (y,-3,3), contours=[-2,-1,4],colorbar=True) :: sage: contour_plot(f, (x,-3,3), (y,-3,3), contours=[-2,-1,4],colorbar=True,colorbar_spacing='uniform') :: sage: contour_plot(f, (x,-3,3), (y,-3,3), contours=[0,2,3,6],colorbar=True,colorbar_format='%.3f') :: sage: contour_plot(f, (x,-3,3), (y,-3,3), labels=True,label_colors='red',contours=[0,2,3,6],colorbar=True) :: sage: contour_plot(f, (x,-3,3), (y,-3,3), cmap='winter', contours=20, fill=False, colorbar=True) This should plot concentric circles centered at the origin:: sage: x,y = var('x,y') sage: contour_plot(x^2+y^2-2,(x,-1,1), (y,-1,1)) Extra options will get passed on to show(), as long as they are valid:: sage: f(x, y) = cos(x) + sin(y) sage: contour_plot(f, (0, pi), (0, pi), axes=True) One can also plot over a reduced region:: sage: contour_plot(x**2-y**2, (x,-2, 2), (y,-2, 2),region=x-y,plot_points=300) :: sage: contour_plot(f, (0, pi), (0, pi)).show(axes=True) # These are equivalent Note that with ``fill=False`` and grayscale contours, there is the possibility of confusion between the contours and the axes, so use ``fill=False`` together with ``axes=True`` with caution:: sage: contour_plot(f, (-pi, pi), (-pi, pi), fill=False, axes=True) TESTS: To check that ticket 5221 is fixed, note that this has three curves, not two:: sage: x,y = var('x,y') sage: contour_plot(x-y^2,(x,-5,5),(y,-3,3),contours=[-4,-2,0], fill=False) """ from sage.plot.all import Graphics from sage.plot.misc import setup_for_eval_on_grid region = options.pop('region') ev = [f] if region is None else [f,region] F, ranges = setup_for_eval_on_grid(ev, [xrange, yrange], options['plot_points']) g = F[0] xrange,yrange=[r[:2] for r in ranges] xy_data_array = [[g(x, y) for x in xsrange(*ranges[0], include_endpoint=True)] for y in xsrange(*ranges[1], include_endpoint=True)] if region is not None: import numpy xy_data_array = numpy.ma.asarray(xy_data_array,dtype=float) m = F[1] mask = numpy.asarray([[m(x, y)<=0 for x in xsrange(*ranges[0], include_endpoint=True)] for y in xsrange(*ranges[1], include_endpoint=True)],dtype=bool) xy_data_array[mask] = numpy.ma.masked g = Graphics() # Reset aspect_ratio to 'automatic' in case scale is 'semilog[xy]'. # Otherwise matplotlib complains. scale = options.get('scale', None) if isinstance(scale, (list, tuple)): scale = scale[0] if scale == 'semilogy' or scale == 'semilogx': options['aspect_ratio'] = 'automatic' g._set_extra_kwds(Graphics._extract_kwds_for_show(options, ignore=['xmin', 'xmax'])) g.add_primitive(ContourPlot(xy_data_array, xrange, yrange, options)) return g
def point2d(points, **options): r""" A point of size ``size`` defined by point = `(x, y)`. INPUT: - ``points`` -- either a single point (as a tuple), a list of points, a single complex number, or a list of complex numbers - ``alpha`` -- how transparent the point is - ``faceted`` -- if ``True``, color the edge of the point (only for 2D plots) - ``hue`` -- the color given as a hue - ``legend_color`` -- the color of the legend text - ``legend_label`` -- the label for this item in the legend - ``marker`` -- the marker symbol for 2D plots only (see documentation of :func:`plot` for details) - ``markeredgecolor`` -- the color of the marker edge (only for 2D plots) - ``rgbcolor`` -- the color as an RGB tuple - ``size`` -- how big the point is (i.e., area in points^2=(1/72 inch)^2) - ``zorder`` -- the layer level in which to draw EXAMPLES: A purple point from a single tuple of coordinates:: sage: point((0.5, 0.5), rgbcolor=hue(0.75)) Graphics object consisting of 1 graphics primitive Points with customized markers and edge colors:: sage: r = [(random(), random()) for _ in range(10)] sage: point(r, marker='d', markeredgecolor='red', size=20) Graphics object consisting of 1 graphics primitive Passing an empty list returns an empty plot:: sage: point([]) Graphics object consisting of 0 graphics primitives sage: import numpy; point(numpy.array([])) Graphics object consisting of 0 graphics primitives If you need a 2D point to live in 3-space later, this is possible:: sage: A = point((1, 1)) sage: a = A[0]; a Point set defined by 1 point(s) sage: b = a.plot3d(z=3) This is also true with multiple points:: sage: P = point([(0, 0), (1, 1)]) sage: p = P[0] sage: q = p.plot3d(z=[2,3]) Here are some random larger red points, given as a list of tuples:: sage: point(((0.5, 0.5), (1, 2), (0.5, 0.9), (-1, -1)), rgbcolor=hue(1), size=30) Graphics object consisting of 1 graphics primitive And an example with a legend:: sage: point((0, 0), rgbcolor='black', pointsize=40, legend_label='origin') Graphics object consisting of 1 graphics primitive The legend can be colored:: sage: P = points([(0, 0), (1, 0)], pointsize=40, legend_label='origin', legend_color='red') sage: P + plot(x^2, (x, 0, 1), legend_label='plot', legend_color='green') Graphics object consisting of 2 graphics primitives Extra options will get passed on to show(), as long as they are valid:: sage: point([(cos(theta), sin(theta)) for theta in srange(0, 2*pi, pi/8)], frame=True) Graphics object consisting of 1 graphics primitive sage: point([(cos(theta), sin(theta)) for theta in srange(0, 2*pi, pi/8)]).show(frame=True) # These are equivalent For plotting data, we can use a logarithmic scale, as long as we are sure not to include any nonpositive points in the logarithmic direction:: sage: point([(1, 2),(2, 4),(3, 4),(4, 8),(4.5, 32)], scale='semilogy', base=2) Graphics object consisting of 1 graphics primitive Since Sage Version 4.4 (:trac:`8599`), the size of a 2d point can be given by the argument ``size`` instead of ``pointsize``. The argument ``pointsize`` is still supported:: sage: point((3, 4), size=100) Graphics object consisting of 1 graphics primitive :: sage: point((3, 4), pointsize=100) Graphics object consisting of 1 graphics primitive We can plot a single complex number:: sage: point(1 + I, pointsize=100) Graphics object consisting of 1 graphics primitive sage: point(sqrt(2) + I, pointsize=100) Graphics object consisting of 1 graphics primitive We can also plot a list of complex numbers:: sage: point([I, 1 + I, 2 + 2*I], pointsize=100) Graphics object consisting of 1 graphics primitive TESTS:: sage: point2d(iter([])) Graphics object consisting of 0 graphics primitives """ from sage.plot.plot import xydata_from_point_list from sage.plot.all import Graphics from sage.structure.element import Expression # points could be a single number if isinstance(points, numbers.Complex): points = [(points.real(), points.imag())] elif isinstance(points, numbers.Real): points = [points] elif isinstance(points, Expression): points = [points] elif not isinstance(points, (list, tuple)): # or an iterator points = list(points) l = len(points) if l == 0: return Graphics() elif l == 2: # special case for a single 2D point if all( isinstance(z, numbers.Real) or ( isinstance(z, Expression) and not complex(z).imag) for z in points): points = [points] elif l == 3: # special case for a single 3D point if all( isinstance(z, numbers.Real) or ( isinstance(z, Expression) and not complex(z).imag) for z in points): raise TypeError('not a 2D point') xdata, ydata = xydata_from_point_list(points) g = Graphics() g._set_extra_kwds(Graphics._extract_kwds_for_show(options)) g.add_primitive(Point(xdata, ydata, options)) if options['legend_label']: g.legend(True) g._legend_colors = [options['legend_color']] return g
def line2d(points, **options): r""" Create the line through the given list of points. INPUT: - ``points`` - either a single point (as a tuple), a list of points, a single complex number, or a list of complex numbers. Type ``line2d.options`` for a dictionary of the default options for lines. You can change this to change the defaults for all future lines. Use ``line2d.reset()`` to reset to the default options. INPUT: - ``alpha`` -- How transparent the line is - ``thickness`` -- How thick the line is - ``rgbcolor`` -- The color as an RGB tuple - ``hue`` -- The color given as a hue - ``legend_color`` -- The color of the text in the legend - ``legend_label`` -- the label for this item in the legend Any MATPLOTLIB line option may also be passed in. E.g., - ``linestyle`` - (default: "-") The style of the line, which is one of - ``"-"`` or ``"solid"`` - ``"--"`` or ``"dashed"`` - ``"-."`` or ``"dash dot"`` - ``":"`` or ``"dotted"`` - ``"None"`` or ``" "`` or ``""`` (nothing) The linestyle can also be prefixed with a drawing style (e.g., ``"steps--"``) - ``"default"`` (connect the points with straight lines) - ``"steps"`` or ``"steps-pre"`` (step function; horizontal line is to the left of point) - ``"steps-mid"`` (step function; points are in the middle of horizontal lines) - ``"steps-post"`` (step function; horizontal line is to the right of point) - ``marker`` - The style of the markers, which is one of - ``"None"`` or ``" "`` or ``""`` (nothing) -- default - ``","`` (pixel), ``"."`` (point) - ``"_"`` (horizontal line), ``"|"`` (vertical line) - ``"o"`` (circle), ``"p"`` (pentagon), ``"s"`` (square), ``"x"`` (x), ``"+"`` (plus), ``"*"`` (star) - ``"D"`` (diamond), ``"d"`` (thin diamond) - ``"H"`` (hexagon), ``"h"`` (alternative hexagon) - ``"<"`` (triangle left), ``">"`` (triangle right), ``"^"`` (triangle up), ``"v"`` (triangle down) - ``"1"`` (tri down), ``"2"`` (tri up), ``"3"`` (tri left), ``"4"`` (tri right) - ``0`` (tick left), ``1`` (tick right), ``2`` (tick up), ``3`` (tick down) - ``4`` (caret left), ``5`` (caret right), ``6`` (caret up), ``7`` (caret down) - ``"$...$"`` (math TeX string) - ``markersize`` -- the size of the marker in points - ``markeredgecolor`` -- the color of the marker edge - ``markerfacecolor`` -- the color of the marker face - ``markeredgewidth`` -- the size of the marker edge in points EXAMPLES: A line with no points or one point:: sage: line([]) #returns an empty plot Graphics object consisting of 0 graphics primitives sage: import numpy; line(numpy.array([])) Graphics object consisting of 0 graphics primitives sage: line([(1,1)]) Graphics object consisting of 1 graphics primitive A line with numpy arrays:: sage: line(numpy.array([[1,2], [3,4]])) Graphics object consisting of 1 graphics primitive A line with a legend:: sage: line([(0,0),(1,1)], legend_label='line') Graphics object consisting of 1 graphics primitive Lines with different colors in the legend text:: sage: p1 = line([(0,0),(1,1)], legend_label='line') sage: p2 = line([(1,1),(2,4)], legend_label='squared', legend_color='red') sage: p1 + p2 Graphics object consisting of 2 graphics primitives Extra options will get passed on to show(), as long as they are valid:: sage: line([(0,1), (3,4)], figsize=[10, 2]) Graphics object consisting of 1 graphics primitive sage: line([(0,1), (3,4)]).show(figsize=[10, 2]) # These are equivalent We can also use a logarithmic scale if the data will support it:: sage: line([(1,2),(2,4),(3,4),(4,8),(4.5,32)],scale='loglog',base=2) Graphics object consisting of 1 graphics primitive Many more examples below! A blue conchoid of Nicomedes:: sage: L = [[1+5*cos(pi/2+pi*i/100), tan(pi/2+pi*i/100)*(1+5*cos(pi/2+pi*i/100))] for i in range(1,100)] sage: line(L, rgbcolor=(1/4,1/8,3/4)) Graphics object consisting of 1 graphics primitive A line with 2 complex points:: sage: i = CC.0 sage: line([1+i, 2+3*i]) Graphics object consisting of 1 graphics primitive A blue hypotrochoid (3 leaves):: sage: n = 4; h = 3; b = 2 sage: L = [[n*cos(pi*i/100)+h*cos((n/b)*pi*i/100),n*sin(pi*i/100)-h*sin((n/b)*pi*i/100)] for i in range(200)] sage: line(L, rgbcolor=(1/4,1/4,3/4)) Graphics object consisting of 1 graphics primitive A blue hypotrochoid (4 leaves):: sage: n = 6; h = 5; b = 2 sage: L = [[n*cos(pi*i/100)+h*cos((n/b)*pi*i/100),n*sin(pi*i/100)-h*sin((n/b)*pi*i/100)] for i in range(200)] sage: line(L, rgbcolor=(1/4,1/4,3/4)) Graphics object consisting of 1 graphics primitive A red limacon of Pascal:: sage: L = [[sin(pi*i/100)+sin(pi*i/50),-(1+cos(pi*i/100)+cos(pi*i/50))] for i in range(-100,101)] sage: line(L, rgbcolor=(1,1/4,1/2)) Graphics object consisting of 1 graphics primitive A light green trisectrix of Maclaurin:: sage: L = [[2*(1-4*cos(-pi/2+pi*i/100)^2),10*tan(-pi/2+pi*i/100)*(1-4*cos(-pi/2+pi*i/100)^2)] for i in range(1,100)] sage: line(L, rgbcolor=(1/4,1,1/8)) Graphics object consisting of 1 graphics primitive A green lemniscate of Bernoulli:: sage: cosines = [cos(-pi/2+pi*i/100) for i in range(201)] sage: v = [(1/c, tan(-pi/2+pi*i/100)) for i,c in enumerate(cosines) if c != 0] sage: L = [(a/(a^2+b^2), b/(a^2+b^2)) for a,b in v] sage: line(L, rgbcolor=(1/4,3/4,1/8)) Graphics object consisting of 1 graphics primitive A red plot of the Jacobi elliptic function `\text{sn}(x,2)`, `-3 < x < 3`:: sage: L = [(i/100.0, real_part(jacobi('sn', i/100.0, 2.0))) for i in ....: range(-300, 300, 30)] sage: line(L, rgbcolor=(3/4, 1/4, 1/8)) Graphics object consisting of 1 graphics primitive A red plot of `J`-Bessel function `J_2(x)`, `0 < x < 10`:: sage: L = [(i/10.0, bessel_J(2,i/10.0)) for i in range(100)] sage: line(L, rgbcolor=(3/4,1/4,5/8)) Graphics object consisting of 1 graphics primitive A purple plot of the Riemann zeta function `\zeta(1/2 + it)`, `0 < t < 30`:: sage: i = CDF.gen() sage: v = [zeta(0.5 + n/10 * i) for n in range(300)] sage: L = [(z.real(), z.imag()) for z in v] sage: line(L, rgbcolor=(3/4,1/2,5/8)) Graphics object consisting of 1 graphics primitive A purple plot of the Hasse-Weil `L`-function `L(E, 1 + it)`, `-1 < t < 10`:: sage: E = EllipticCurve('37a') sage: vals = E.lseries().values_along_line(1-I, 1+10*I, 100) # critical line sage: L = [(z[1].real(), z[1].imag()) for z in vals] sage: line(L, rgbcolor=(3/4,1/2,5/8)) Graphics object consisting of 1 graphics primitive A red, blue, and green "cool cat":: sage: G = plot(-cos(x), -2, 2, thickness=5, rgbcolor=(0.5,1,0.5)) sage: P = polygon([[1,2], [5,6], [5,0]], rgbcolor=(1,0,0)) sage: Q = polygon([(-x,y) for x,y in P[0]], rgbcolor=(0,0,1)) sage: G + P + Q # show the plot Graphics object consisting of 3 graphics primitives TESTS: Check that :trac:`13690` is fixed. The legend label should have circles as markers.:: sage: line(enumerate(range(2)), marker='o', legend_label='circle') Graphics object consisting of 1 graphics primitive """ from sage.plot.all import Graphics from sage.plot.plot import xydata_from_point_list from sage.rings.all import CC, CDF if points in CC or points in CDF: pass else: try: if not points: return Graphics() except ValueError: # numpy raises a ValueError if not empty pass xdata, ydata = xydata_from_point_list(points) g = Graphics() g._set_extra_kwds(Graphics._extract_kwds_for_show(options)) g.add_primitive(Line(xdata, ydata, options)) if options['legend_label']: g.legend(True) g._legend_colors = [options['legend_color']] return g
def contour_plot(f, xrange, yrange, **options): r""" ``contour_plot`` takes a function of two variables, `f(x,y)` and plots contour lines of the function over the specified ``xrange`` and ``yrange`` as demonstrated below. ``contour_plot(f, (xmin, xmax), (ymin, ymax), ...)`` INPUT: - ``f`` -- a function of two variables - ``(xmin, xmax)`` -- 2-tuple, the range of ``x`` values OR 3-tuple ``(x,xmin,xmax)`` - ``(ymin, ymax)`` -- 2-tuple, the range of ``y`` values OR 3-tuple ``(y,ymin,ymax)`` The following inputs must all be passed in as named parameters: - ``plot_points`` -- integer (default: 100); number of points to plot in each direction of the grid. For old computers, 25 is fine, but should not be used to verify specific intersection points. - ``fill`` -- bool (default: ``True``), whether to color in the area between contour lines - ``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. - ``contours`` -- integer or list of numbers (default: ``None``): If a list of numbers is given, then this specifies the contour levels to use. If an integer is given, then this many contour lines are used, but the exact levels are determined automatically. If ``None`` is passed (or the option is not given), then the number of contour lines is determined automatically, and is usually about 5. - ``linewidths`` -- integer or list of integer (default: None), if a single integer all levels will be of the width given, otherwise the levels will be plotted with the width in the order given. If the list is shorter than the number of contours, then the widths will be repeated cyclically. - ``linestyles`` -- string or list of strings (default: None), the style of the lines to be plotted, one of: ``"solid"``, ``"dashed"``, ``"dashdot"``, ``"dotted"``, respectively ``"-"``, ``"--"``, ``"-."``, ``":"``. If the list is shorter than the number of contours, then the styles will be repeated cyclically. - ``labels`` -- boolean (default: False) Show level labels or not. The following options are to adjust the style and placement of labels, they have no effect if no labels are shown. - ``label_fontsize`` -- integer (default: 9), the font size of the labels. - ``label_colors`` -- string or sequence of colors (default: None) If a string, gives the name of a single color with which to draw all labels. If a sequence, gives the colors of the labels. A color is a string giving the name of one or a 3-tuple of floats. - ``label_inline`` -- boolean (default: False if fill is True, otherwise True), controls whether the underlying contour is removed or not. - ``label_inline_spacing`` -- integer (default: 3), When inline, this is the amount of contour that is removed from each side, in pixels. - ``label_fmt`` -- a format string (default: "%1.2f"), this is used to get the label text from the level. This can also be a dictionary with the contour levels as keys and corresponding text string labels as values. It can also be any callable which returns a string when called with a numeric contour level. - ``colorbar`` -- boolean (default: False) Show a colorbar or not. The following options are 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_spacing`` -- string (default: 'proportional'). If 'proportional', make the contour divisions proportional to values. If 'uniform', space the colorbar divisions uniformly, without regard for numeric values. - ``legend_label`` -- the label for this item in the legend - ``region`` - (default: None) If region is given, it must be a function of two variables. Only segments of the surface where region(x,y) returns a number >0 will be included in the plot. EXAMPLES: Here we plot a simple function of two variables. Note that since the input function is an expression, we need to explicitly declare the variables in 3-tuples for the range:: sage: x,y = var('x,y') sage: contour_plot(cos(x^2+y^2), (x, -4, 4), (y, -4, 4)) Graphics object consisting of 1 graphics primitive Here we change the ranges and add some options:: sage: x,y = var('x,y') sage: contour_plot((x^2)*cos(x*y), (x, -10, 5), (y, -5, 5), fill=False, plot_points=150) Graphics object consisting of 1 graphics primitive An even more complicated plot:: sage: x,y = var('x,y') sage: contour_plot(sin(x^2 + y^2)*cos(x)*sin(y), (x, -4, 4), (y, -4, 4),plot_points=150) Graphics object consisting of 1 graphics primitive Some elliptic curves, but with symbolic endpoints. In the first example, the plot is rotated 90 degrees because we switch the variables `x`, `y`:: sage: x,y = var('x,y') sage: contour_plot(y^2 + 1 - x^3 - x, (y,-pi,pi), (x,-pi,pi)) Graphics object consisting of 1 graphics primitive :: sage: contour_plot(y^2 + 1 - x^3 - x, (x,-pi,pi), (y,-pi,pi)) Graphics object consisting of 1 graphics primitive We can play with the contour levels:: sage: x,y = var('x,y') sage: f(x,y) = x^2 + y^2 sage: contour_plot(f, (-2, 2), (-2, 2)) Graphics object consisting of 1 graphics primitive :: sage: contour_plot(f, (-2, 2), (-2, 2), contours=2, cmap=[(1,0,0), (0,1,0), (0,0,1)]) Graphics object consisting of 1 graphics primitive :: sage: contour_plot(f, (-2, 2), (-2, 2), contours=(0.1, 1.0, 1.2, 1.4), cmap='hsv') Graphics object consisting of 1 graphics primitive :: sage: contour_plot(f, (-2, 2), (-2, 2), contours=(1.0,), fill=False) Graphics object consisting of 1 graphics primitive :: sage: contour_plot(x-y^2,(x,-5,5),(y,-3,3),contours=[-4,0,1]) Graphics object consisting of 1 graphics primitive We can change the style of the lines:: sage: contour_plot(f, (-2,2), (-2,2), fill=False, linewidths=10) Graphics object consisting of 1 graphics primitive :: sage: contour_plot(f, (-2,2), (-2,2), fill=False, linestyles='dashdot') Graphics object consisting of 1 graphics primitive :: sage: P=contour_plot(x^2-y^2,(x,-3,3),(y,-3,3),contours=[0,1,2,3,4],\ ... linewidths=[1,5],linestyles=['solid','dashed'],fill=False) sage: P Graphics object consisting of 1 graphics primitive :: sage: P=contour_plot(x^2-y^2,(x,-3,3),(y,-3,3),contours=[0,1,2,3,4],\ ... linewidths=[1,5],linestyles=['solid','dashed']) sage: P Graphics object consisting of 1 graphics primitive sage: P=contour_plot(x^2-y^2,(x,-3,3),(y,-3,3),contours=[0,1,2,3,4],\ ... linewidths=[1,5],linestyles=['-',':']) sage: P Graphics object consisting of 1 graphics primitive We can add labels and play with them:: sage: contour_plot(y^2 + 1 - x^3 - x, (x,-pi,pi), (y,-pi,pi), fill=False, cmap='hsv', labels=True) Graphics object consisting of 1 graphics primitive :: sage: P=contour_plot(y^2 + 1 - x^3 - x, (x,-pi,pi), (y,-pi,pi), fill=False, cmap='hsv',\ ... labels=True, label_fmt="%1.0f", label_colors='black') sage: P Graphics object consisting of 1 graphics primitive :: sage: P=contour_plot(y^2 + 1 - x^3 - x, (x,-pi,pi), (y,-pi,pi), fill=False, cmap='hsv',labels=True,\ ... contours=[-4,0,4], label_fmt={-4:"low", 0:"medium", 4: "hi"}, label_colors='black') sage: P Graphics object consisting of 1 graphics primitive :: sage: P=contour_plot(y^2 + 1 - x^3 - x, (x,-pi,pi), (y,-pi,pi), fill=False, cmap='hsv',labels=True,\ ... contours=[-4,0,4], label_fmt=lambda x: "$z=%s$"%x, label_colors='black', label_inline=True, \ ... label_fontsize=12) sage: P Graphics object consisting of 1 graphics primitive :: sage: P=contour_plot(y^2 + 1 - x^3 - x, (x,-pi,pi), (y,-pi,pi), \ ... fill=False, cmap='hsv', labels=True, label_fontsize=18) sage: P Graphics object consisting of 1 graphics primitive :: sage: P=contour_plot(y^2 + 1 - x^3 - x, (x,-pi,pi), (y,-pi,pi), \ ... fill=False, cmap='hsv', labels=True, label_inline_spacing=1) sage: P Graphics object consisting of 1 graphics primitive :: sage: P= contour_plot(y^2 + 1 - x^3 - x, (x,-pi,pi), (y,-pi,pi), \ ... fill=False, cmap='hsv', labels=True, label_inline=False) sage: P Graphics object consisting of 1 graphics primitive We can change the color of the labels if so desired:: sage: contour_plot(f, (-2,2), (-2,2), labels=True, label_colors='red') Graphics object consisting of 1 graphics primitive We can add a colorbar as well:: sage: f(x,y)=x^2-y^2 sage: contour_plot(f, (x,-3,3), (y,-3,3), colorbar=True) Graphics object consisting of 1 graphics primitive :: sage: contour_plot(f, (x,-3,3), (y,-3,3), colorbar=True,colorbar_orientation='horizontal') Graphics object consisting of 1 graphics primitive :: sage: contour_plot(f, (x,-3,3), (y,-3,3), contours=[-2,-1,4],colorbar=True) Graphics object consisting of 1 graphics primitive :: sage: contour_plot(f, (x,-3,3), (y,-3,3), contours=[-2,-1,4],colorbar=True,colorbar_spacing='uniform') Graphics object consisting of 1 graphics primitive :: sage: contour_plot(f, (x,-3,3), (y,-3,3), contours=[0,2,3,6],colorbar=True,colorbar_format='%.3f') Graphics object consisting of 1 graphics primitive :: sage: contour_plot(f, (x,-3,3), (y,-3,3), labels=True,label_colors='red',contours=[0,2,3,6],colorbar=True) Graphics object consisting of 1 graphics primitive :: sage: contour_plot(f, (x,-3,3), (y,-3,3), cmap='winter', contours=20, fill=False, colorbar=True) Graphics object consisting of 1 graphics primitive This should plot concentric circles centered at the origin:: sage: x,y = var('x,y') sage: contour_plot(x^2+y^2-2,(x,-1,1), (y,-1,1)) Graphics object consisting of 1 graphics primitive Extra options will get passed on to show(), as long as they are valid:: sage: f(x, y) = cos(x) + sin(y) sage: contour_plot(f, (0, pi), (0, pi), axes=True) Graphics object consisting of 1 graphics primitive One can also plot over a reduced region:: sage: contour_plot(x**2-y**2, (x,-2, 2), (y,-2, 2),region=x-y,plot_points=300) Graphics object consisting of 1 graphics primitive :: sage: contour_plot(f, (0, pi), (0, pi)).show(axes=True) # These are equivalent Note that with ``fill=False`` and grayscale contours, there is the possibility of confusion between the contours and the axes, so use ``fill=False`` together with ``axes=True`` with caution:: sage: contour_plot(f, (-pi, pi), (-pi, pi), fill=False, axes=True) Graphics object consisting of 1 graphics primitive TESTS: To check that ticket 5221 is fixed, note that this has three curves, not two:: sage: x,y = var('x,y') sage: contour_plot(x-y^2,(x,-5,5),(y,-3,3),contours=[-4,-2,0], fill=False) Graphics object consisting of 1 graphics primitive """ from sage.plot.all import Graphics from sage.plot.misc import setup_for_eval_on_grid region = options.pop('region') ev = [f] if region is None else [f, region] F, ranges = setup_for_eval_on_grid(ev, [xrange, yrange], options['plot_points']) g = F[0] xrange, yrange = [r[:2] for r in ranges] xy_data_array = [[ g(x, y) for x in xsrange(*ranges[0], include_endpoint=True) ] for y in xsrange(*ranges[1], include_endpoint=True)] if region is not None: import numpy xy_data_array = numpy.ma.asarray(xy_data_array, dtype=float) m = F[1] mask = numpy.asarray([[ m(x, y) <= 0 for x in xsrange(*ranges[0], include_endpoint=True) ] for y in xsrange(*ranges[1], include_endpoint=True)], dtype=bool) xy_data_array[mask] = numpy.ma.masked g = Graphics() # Reset aspect_ratio to 'automatic' in case scale is 'semilog[xy]'. # Otherwise matplotlib complains. scale = options.get('scale', None) if isinstance(scale, (list, tuple)): scale = scale[0] if scale == 'semilogy' or scale == 'semilogx': options['aspect_ratio'] = 'automatic' g._set_extra_kwds( Graphics._extract_kwds_for_show(options, ignore=['xmin', 'xmax'])) g.add_primitive(ContourPlot(xy_data_array, xrange, yrange, options)) return g
def ellipse(center, r1, r2, angle=0, **options): """ Return an ellipse centered at a point center = ``(x,y)`` with radii = ``r1,r2`` and angle ``angle``. Type ``ellipse.options`` to see all options. INPUT: - ``center`` - 2-tuple of real numbers - coordinates of the center - ``r1``, ``r2`` - positive real numbers - the radii of the ellipse - ``angle`` - real number (default: 0) - the angle between the first axis and the horizontal OPTIONS: - ``alpha`` - default: 1 - transparency - ``fill`` - default: False - whether to fill the ellipse or not - ``thickness`` - default: 1 - thickness of the line - ``linestyle`` - default: ``'solid'`` - The style of the line, which is one of ``'dashed'``, ``'dotted'``, ``'solid'``, ``'dashdot'``, or ``'--'``, ``':'``, ``'-'``, ``'-.'``, respectively. - ``edgecolor`` - default: 'black' - color of the contour - ``facecolor`` - default: 'red' - color of the filling - ``rgbcolor`` - 2D or 3D plotting. This option overrides ``edgecolor`` and ``facecolor`` for 2D plotting. EXAMPLES: An ellipse centered at (0,0) with major and minor axes of lengths 2 and 1. Note that the default color is blue:: sage: ellipse((0,0),2,1) More complicated examples with tilted axes and drawing options:: sage: ellipse((0,0),3,1,pi/6,fill=True,alpha=0.3,linestyle="dashed") sage: ellipse((0,0),3,1,pi/6,fill=True,alpha=0.3,linestyle="--") :: sage: ellipse((0,0),3,1,pi/6,fill=True,edgecolor='black',facecolor='red') We see that ``rgbcolor`` overrides these other options, as this plot is green:: sage: ellipse((0,0),3,1,pi/6,fill=True,edgecolor='black',facecolor='red',rgbcolor='green') The default aspect ratio for ellipses is 1.0:: sage: ellipse((0,0),2,1).aspect_ratio() 1.0 One cannot yet plot ellipses in 3D:: sage: ellipse((0,0,0),2,1) Traceback (most recent call last): ... NotImplementedError: plotting ellipse in 3D is not implemented """ from sage.plot.all import Graphics g = Graphics() # Reset aspect_ratio to 'automatic' in case scale is 'semilog[xy]'. # Otherwise matplotlib complains. scale = options.get('scale', None) if isinstance(scale, (list, tuple)): scale = scale[0] if scale == 'semilogy' or scale == 'semilogx': options['aspect_ratio'] = 'automatic' g._set_extra_kwds(Graphics._extract_kwds_for_show(options)) g.add_primitive(Ellipse(center[0], center[1], r1, r2, angle, options)) if options['legend_label']: g.legend(True) if len(center) == 2: return g elif len(center) == 3: raise NotImplementedError, "plotting ellipse in 3D is not implemented"
def density_plot(f, xrange, yrange, **options): r""" ``density_plot`` takes a function of two variables, `f(x,y)` and plots the height of of the function over the specified ``xrange`` and ``yrange`` as demonstrated below. ``density_plot(f, (xmin, xmax), (ymin, ymax), ...)`` INPUT: - ``f`` -- a function of two variables - ``(xmin, xmax)`` -- 2-tuple, the range of ``x`` values OR 3-tuple ``(x,xmin,xmax)`` - ``(ymin, ymax)`` -- 2-tuple, the range of ``y`` values OR 3-tuple ``(y,ymin,ymax)`` The following inputs must all be passed in as named parameters: - ``plot_points`` -- integer (default: 25); number of points to plot in each direction of the grid - ``cmap`` -- a colormap (type ``cmap_help()`` for more information). - ``interpolation`` -- string (default: ``'catrom'``), the interpolation method to use: ``'bilinear'``, ``'bicubic'``, ``'spline16'``, ``'spline36'``, ``'quadric'``, ``'gaussian'``, ``'sinc'``, ``'bessel'``, ``'mitchell'``, ``'lanczos'``, ``'catrom'``, ``'hermite'``, ``'hanning'``, ``'hamming'``, ``'kaiser'`` EXAMPLES: Here we plot a simple function of two variables. Note that since the input function is an expression, we need to explicitly declare the variables in 3-tuples for the range:: sage: x,y = var('x,y') sage: density_plot(sin(x)*sin(y), (x, -2, 2), (y, -2, 2)) Here we change the ranges and add some options; note that here ``f`` is callable (has variables declared), so we can use 2-tuple ranges:: sage: x,y = var('x,y') sage: f(x,y) = x^2*cos(x*y) sage: density_plot(f, (x,-10,5), (y, -5,5), interpolation='sinc', plot_points=100) An even more complicated plot:: sage: x,y = var('x,y') sage: density_plot(sin(x^2 + y^2)*cos(x)*sin(y), (x, -4, 4), (y, -4, 4), cmap='jet', plot_points=100) This should show a "spotlight" right on the origin:: sage: x,y = var('x,y') sage: density_plot(1/(x^10+y^10), (x, -10, 10), (y, -10, 10)) Some elliptic curves, but with symbolic endpoints. In the first example, the plot is rotated 90 degrees because we switch the variables `x`, `y`:: sage: density_plot(y^2 + 1 - x^3 - x, (y,-pi,pi), (x,-pi,pi)) :: sage: density_plot(y^2 + 1 - x^3 - x, (x,-pi,pi), (y,-pi,pi)) Extra options will get passed on to show(), as long as they are valid:: sage: density_plot(log(x) + log(y), (x, 1, 10), (y, 1, 10), dpi=20) :: sage: density_plot(log(x) + log(y), (x, 1, 10), (y, 1, 10)).show(dpi=20) # These are equivalent """ from sage.plot.all import Graphics from sage.plot.misc import setup_for_eval_on_grid g, ranges = setup_for_eval_on_grid([f], [xrange, yrange], options['plot_points']) g = g[0] xrange, yrange = [r[:2] for r in ranges] xy_data_array = [[ g(x, y) for x in xsrange(*ranges[0], include_endpoint=True) ] for y in xsrange(*ranges[1], include_endpoint=True)] g = Graphics() g._set_extra_kwds( Graphics._extract_kwds_for_show(options, ignore=['xmin', 'xmax'])) g.add_primitive(DensityPlot(xy_data_array, xrange, yrange, options)) return g
def arc(center, r1, r2=None, angle=0.0, sector=(0.0,2*pi), **options): r""" An arc (that is a portion of a circle or an ellipse) Type ``arc.options`` to see all options. INPUT: - ``center`` - 2-tuple of real numbers - position of the center. - ``r1``, ``r2`` - positive real numbers - radii of the ellipse. If only ``r1`` is set, then the two radii are supposed to be equal and this function returns an arc of of circle. - ``angle`` - real number - angle between the horizontal and the axis that corresponds to ``r1``. - ``sector`` - 2-tuple (default: (0,2*pi))- angles sector in which the arc will be drawn. OPTIONS: - ``alpha`` - float (default: 1) - transparency - ``thickness`` - float (default: 1) - thickness of the arc - ``color``, ``rgbcolor`` - string or 2-tuple (default: 'blue') - the color of the arc - ``linestyle`` - string (default: 'solid') - the style of the line EXAMPLES: Plot an arc of circle centered at (0,0) with radius 1 in the sector `(\pi/4,3*\pi/4)`:: sage: arc((0,0), 1, sector=(pi/4,3*pi/4)) Plot an arc of an ellipse between the angles 0 and `\pi/2`:: sage: arc((2,3), 2, 1, sector=(0,pi/2)) Plot an arc of a rotated ellipse between the angles 0 and `\pi/2`:: sage: arc((2,3), 2, 1, angle=pi/5, sector=(0,pi/2)) Plot an arc of an ellipse in red with a dashed linestyle:: sage: arc((0,0), 2, 1, 0, (0,pi/2), linestyle="dashed", color="red") The default aspect ratio for arcs is 1.0:: sage: arc((0,0), 1, sector=(pi/4,3*pi/4)).aspect_ratio() 1.0 It is not possible to draw arcs in 3D:: sage: A = arc((0,0,0), 1) Traceback (most recent call last): ... NotImplementedError """ from sage.plot.all import Graphics if len(center)==2: if r2 is None: r2 = r1 g = Graphics() g._set_extra_kwds(Graphics._extract_kwds_for_show(options)) if len(sector) != 2: raise ValueError, "the sector must consist of two angles" g.add_primitive(Arc( center[0],center[1], r1,r2, angle, sector[0],sector[1], options)) return g elif len(center)==3: raise NotImplementedError
def arrow2d(tailpoint=None, headpoint=None, path=None, **options): """ If ``tailpoint`` and ``headpoint`` are provided, returns an arrow from (xtail, ytail) to (xhead, yhead). If ``tailpoint`` or ``headpoint`` is None and ``path`` is not None, returns an arrow along the path. (See further info on paths in :class:`bezier_path`). INPUT: - ``tailpoint`` - the starting point of the arrow - ``headpoint`` - where the arrow is pointing to - ``path`` - the list of points and control points (see bezier_path for detail) that the arrow will follow from source to destination - ``head`` - 0, 1 or 2, whether to draw the head at the start (0), end (1) or both (2) of the path (using 0 will swap headpoint and tailpoint). This is ignored in 3D plotting. - ``linestyle`` - (default: ``'solid'``) The style of the line, which is one of ``'dashed'``, ``'dotted'``, ``'solid'``, ``'dashdot'``, or ``'--'``, ``':'``, ``'-'``, ``'-.'``, respectively. - ``width`` - (default: 2) the width of the arrow shaft, in points - ``color`` - (default: (0,0,1)) the color of the arrow (as an RGB tuple or a string) - ``hue`` - the color of the arrow (as a number) - ``arrowsize`` - the size of the arrowhead - ``arrowshorten`` - the length in points to shorten the arrow (ignored if using path parameter) - ``legend_label`` - the label for this item in the legend - ``legend_color`` - the color for the legend label - ``zorder`` - the layer level to draw the arrow-- note that this is ignored in 3D plotting. EXAMPLES: A straight, blue arrow:: sage: arrow2d((1,1), (3,3)) Graphics object consisting of 1 graphics primitive .. PLOT:: sphinx_plot(arrow2d((1,1), (3,3))) Make a red arrow:: sage: arrow2d((-1,-1), (2,3), color=(1,0,0)) Graphics object consisting of 1 graphics primitive .. PLOT:: sphinx_plot(arrow2d((-1,-1), (2,3), color=(1,0,0))) :: sage: arrow2d((-1,-1), (2,3), color='red') Graphics object consisting of 1 graphics primitive .. PLOT:: sphinx_plot(arrow2d((-1,-1), (2,3), color='red')) You can change the width of an arrow:: sage: arrow2d((1,1), (3,3), width=5, arrowsize=15) Graphics object consisting of 1 graphics primitive .. PLOT:: P = arrow2d((1,1), (3,3), width=5, arrowsize=15) sphinx_plot(P) Use a dashed line instead of a solid one for the arrow:: sage: arrow2d((1,1), (3,3), linestyle='dashed') Graphics object consisting of 1 graphics primitive sage: arrow2d((1,1), (3,3), linestyle='--') Graphics object consisting of 1 graphics primitive .. PLOT:: P = arrow2d((1,1), (3,3), linestyle='--') sphinx_plot(P) A pretty circle of arrows:: sage: sum([arrow2d((0,0), (cos(x),sin(x)), hue=x/(2*pi)) for x in [0..2*pi,step=0.1]]) Graphics object consisting of 63 graphics primitives .. PLOT:: P = sum([arrow2d((0,0), (cos(x*0.1),sin(x*0.1)), hue=x/(20*pi)) for x in range(floor(20*pi)+1)]) sphinx_plot(P) If we want to draw the arrow between objects, for example, the boundaries of two lines, we can use the ``arrowshorten`` option to make the arrow shorter by a certain number of points:: sage: L1 = line([(0,0), (1,0)], thickness=10) sage: L2 = line([(0,1), (1,1)], thickness=10) sage: A = arrow2d((0.5,0), (0.5,1), arrowshorten=10, rgbcolor=(1,0,0)) sage: L1 + L2 + A Graphics object consisting of 3 graphics primitives .. PLOT:: L1 = line([(0,0), (1,0)],thickness=10) L2 = line([(0,1), (1,1)], thickness=10) A = arrow2d((0.5,0), (0.5,1), arrowshorten=10, rgbcolor=(1,0,0)) sphinx_plot(L1 + L2 + A) If BOTH ``headpoint`` and ``tailpoint`` are None, then an empty plot is returned:: sage: arrow2d(headpoint=None, tailpoint=None) Graphics object consisting of 0 graphics primitives We can also draw an arrow with a legend:: sage: arrow((0,0), (0,2), legend_label='up', legend_color='purple') Graphics object consisting of 1 graphics primitive .. PLOT:: P = arrow((0,0), (0,2), legend_label='up', legend_color='purple') sphinx_plot(P) Extra options will get passed on to :meth:`Graphics.show()`, as long as they are valid:: sage: arrow2d((-2,2), (7,1), frame=True) Graphics object consisting of 1 graphics primitive .. PLOT:: sphinx_plot(arrow2d((-2,2), (7,1), frame=True)) :: sage: arrow2d((-2,2), (7,1)).show(frame=True) """ from sage.plot.all import Graphics g = Graphics() g._set_extra_kwds(Graphics._extract_kwds_for_show(options)) if headpoint is not None and tailpoint is not None: xtail, ytail = tailpoint xhead, yhead = headpoint g.add_primitive(Arrow(xtail, ytail, xhead, yhead, options=options)) elif path is not None: g.add_primitive(CurveArrow(path, options=options)) elif tailpoint is None and headpoint is None: return g else: raise TypeError( 'Arrow requires either both headpoint and tailpoint or a path parameter.' ) if options['legend_label']: g.legend(True) g._legend_colors = [options['legend_color']] return g
def point2d(points, **options): r""" A point of size ``size`` defined by point = `(x,y)`. INPUT: - ``points`` - either a single point (as a tuple), a list of points, a single complex number, or a list of complex numbers. Type ``point2d.options`` to see all options. EXAMPLES: A purple point from a single tuple or coordinates:: sage: point((0.5, 0.5), rgbcolor=hue(0.75)) Passing an empty list returns an empty plot:: sage: point([]) sage: import numpy; point(numpy.array([])) If you need a 2D point to live in 3-space later, this is possible:: sage: A=point((1,1)) sage: a=A[0];a Point set defined by 1 point(s) sage: b=a.plot3d(z=3) This is also true with multiple points:: sage: P=point([(0,0), (1,1)]) sage: p=P[0] sage: q=p.plot3d(z=[2,3]) Here are some random larger red points, given as a list of tuples:: sage: point(((0.5, 0.5), (1, 2), (0.5, 0.9), (-1, -1)), rgbcolor=hue(1), size=30) And an example with a legend:: sage: point((0,0), rgbcolor='black', pointsize=40, legend_label='origin') The legend can be colored:: sage: P = points([(0,0),(1,0)], pointsize=40, legend_label='origin', legend_color='red') sage: P + plot(x^2,(x,0,1), legend_label='plot', legend_color='green') Extra options will get passed on to show(), as long as they are valid:: sage: point([(cos(theta), sin(theta)) for theta in srange(0, 2*pi, pi/8)], frame=True) sage: point([(cos(theta), sin(theta)) for theta in srange(0, 2*pi, pi/8)]).show(frame=True) # These are equivalent For plotting data, we can use a logarithmic scale, as long as we are sure not to include any nonpositive points in the logarithmic direction:: sage: point([(1,2),(2,4),(3,4),(4,8),(4.5,32)],scale='semilogy',base=2) Since Sage Version 4.4 (ticket #8599), the size of a 2d point can be given by the argument ``size`` instead of ``pointsize``. The argument ``pointsize`` is still supported:: sage: point((3,4), size=100) :: sage: point((3,4), pointsize=100) We can plot a single complex number:: sage: point(CC(1+I), pointsize=100) We can also plot a list of complex numbers:: sage: point([CC(I), CC(I+1), CC(2+2*I)], pointsize=100) """ from sage.plot.plot import xydata_from_point_list from sage.plot.all import Graphics from sage.rings.all import CC, CDF if points in CC or points in CDF: pass else: try: if not points: return Graphics() except ValueError: # numpy raises a ValueError if not empty pass xdata, ydata = xydata_from_point_list(points) g = Graphics() g._set_extra_kwds(Graphics._extract_kwds_for_show(options)) g.add_primitive(Point(xdata, ydata, options)) if options['legend_label']: g.legend(True) g._legend_colors = [options['legend_color']] return g
def hyperbolic_regular_polygon(sides, i_angle, center=CC(0,1), **options): r""" Return a hyperbolic regular polygon in the upper half model of Hyperbolic plane given the number of sides, interior angle and possibly a center. Type ``?hyperbolic_regular_polygon`` to see all options. INPUT: - ``sides`` -- number of sides of the polygon - ``i_angle`` -- interior angle of the polygon - ``center`` -- (default: `i`) hyperbolic center point (complex number) of the polygon OPTIONS: - ``alpha`` -- default: 1 - ``fill`` -- default: ``False`` - ``thickness`` -- default: 1 - ``rgbcolor`` -- default: ``'blue'`` - ``linestyle`` -- (default: ``'solid'``) the style of the line, which can be one of the following: * ``'dashed'`` or ``'--'`` * ``'dotted'`` or ``':'`` * ``'solid'`` or ``'-'`` * ``'dashdot'`` or ``'-.'`` EXAMPLES: Show a hyperbolic regular polygon with 6 sides and square angles:: sage: g = hyperbolic_regular_polygon(6, pi/2) sage: g.plot() Graphics object consisting of 1 graphics primitive .. PLOT:: g = hyperbolic_regular_polygon(6, pi/2) sphinx_plot(g.plot()) With more options:: sage: g = hyperbolic_regular_polygon(6, pi/2, center=3+2*I, fill=True, color='red') sage: g.plot() Graphics object consisting of 1 graphics primitive .. PLOT:: g = hyperbolic_regular_polygon(6, pi/2, center=3+2*I, fill=True, color='red') sphinx_plot(g.plot()) The code verifies is there exists a hyperbolic regular polygon with the given data, checking .. MATH:: A(\mathcal{P}) = \pi(s-2) - s \cdot \alpha > 0, where `s` is ``sides`` and `\alpha` is ``i_angle`. This raises an error if the ``i_angle`` is less than the minimum to generate a compact polygon:: sage: hyperbolic_regular_polygon(4, pi/2) Traceback (most recent call last): ... ValueError: there exists no hyperbolic regular compact polygon, for sides=4 the interior angle must be less than 1/2*pi It is an error to give a center outside the upper half plane in this model:: sage: from sage.plot.hyperbolic_regular_polygon import hyperbolic_regular_polygon sage: hyperbolic_regular_polygon(4, pi/4, 1-I) Traceback (most recent call last): ... ValueError: center: 1.00000000000000 - 1.00000000000000*I is not a valid point in the upper half plane model of the hyperbolic plane """ g = Graphics() g._set_extra_kwds(g._extract_kwds_for_show(options)) g.add_primitive(HyperbolicRegularPolygon(sides, i_angle, center, options)) g.set_aspect_ratio(1) return g
def point2d(points, **options): r""" A point of size ``size`` defined by point = `(x,y)`. Point takes either a single tuple of coordinates or a list of tuples. Type ``point2d.options`` to see all options. EXAMPLES: A purple point from a single tuple or coordinates:: sage: point((0.5, 0.5), rgbcolor=hue(0.75)) Passing an empty list returns an empty plot:: sage: point([]) If you need a 2D point to live in 3-space later, this is possible:: sage: A=point((1,1)) sage: a=A[0];a Point set defined by 1 point(s) sage: b=a.plot3d(z=3) This is also true with multiple points:: sage: P=point([(0,0), (1,1)]) sage: p=P[0] sage: q=p.plot3d(z=[2,3]) Here are some random larger red points, given as a list of tuples:: sage: point(((0.5, 0.5), (1, 2), (0.5, 0.9), (-1, -1)), rgbcolor=hue(1), size=30) And an example with a legend:: sage: point((0,0), rgbcolor='black', pointsize=40, legend_label='origin') Extra options will get passed on to show(), as long as they are valid:: sage: point([(cos(theta), sin(theta)) for theta in srange(0, 2*pi, pi/8)], frame=True) sage: point([(cos(theta), sin(theta)) for theta in srange(0, 2*pi, pi/8)]).show(frame=True) # These are equivalent For plotting data, we can use a logarithmic scale, as long as we are sure not to include any nonpositive points in the logarithmic direction:: sage: point([(1,2),(2,4),(3,4),(4,8),(4.5,32)],scale='semilogy',base=2) Since Sage Version 4.4 (ticket #8599), the size of a 2d point can be given by the argument ``size`` instead of ``pointsize``. The argument ``pointsize`` is still supported:: sage: point((3,4), size=100) :: sage: point((3,4), pointsize=100) """ from sage.plot.plot import xydata_from_point_list from sage.plot.all import Graphics if points == []: return Graphics() xdata, ydata = xydata_from_point_list(points) g = Graphics() g._set_extra_kwds(Graphics._extract_kwds_for_show(options)) g.add_primitive(Point(xdata, ydata, options)) if options['legend_label']: g.legend(True) return g
def plot(self, **kwds): """ Returns a graphics object representing the (di)graph. INPUT: The options accepted by this method are to be found in the documentation of the :mod:`sage.graphs.graph_plot` module, and the :meth:`~sage.plot.graphics.Graphics.show` method. .. NOTE:: See :mod:`the module's documentation <sage.graphs.graph_plot>` for information on default values of this method. We can specify some pretty precise plotting of familiar graphs:: sage: from math import sin, cos, pi sage: P = graphs.PetersenGraph() sage: d = {'#FF0000':[0,5], '#FF9900':[1,6], '#FFFF00':[2,7], '#00FF00':[3,8], '#0000FF':[4,9]} sage: pos_dict = {} sage: for i in range(5): ... x = float(cos(pi/2 + ((2*pi)/5)*i)) ... y = float(sin(pi/2 + ((2*pi)/5)*i)) ... pos_dict[i] = [x,y] ... sage: for i in range(10)[5:]: ... x = float(0.5*cos(pi/2 + ((2*pi)/5)*i)) ... y = float(0.5*sin(pi/2 + ((2*pi)/5)*i)) ... pos_dict[i] = [x,y] ... sage: pl = P.graphplot(pos=pos_dict, vertex_colors=d) sage: pl.show() Here are some more common graphs with typical options:: sage: C = graphs.CubeGraph(8) sage: P = C.graphplot(vertex_labels=False, vertex_size=0, graph_border=True) sage: P.show() sage: G = graphs.HeawoodGraph().copy(sparse=True) sage: for u,v,l in G.edges(): ... G.set_edge_label(u,v,'(' + str(u) + ',' + str(v) + ')') sage: G.graphplot(edge_labels=True).show() The options for plotting also work with directed graphs:: sage: D = DiGraph( { 0: [1, 10, 19], 1: [8, 2], 2: [3, 6], 3: [19, 4], 4: [17, 5], 5: [6, 15], 6: [7], 7: [8, 14], 8: [9], 9: [10, 13], 10: [11], 11: [12, 18], 12: [16, 13], 13: [14], 14: [15], 15: [16], 16: [17], 17: [18], 18: [19], 19: []}) sage: for u,v,l in D.edges(): ... D.set_edge_label(u,v,'(' + str(u) + ',' + str(v) + ')') sage: D.graphplot(edge_labels=True, layout='circular').show() This example shows off the coloring of edges:: sage: from sage.plot.colors import rainbow sage: C = graphs.CubeGraph(5) sage: R = rainbow(5) sage: edge_colors = {} sage: for i in range(5): ... edge_colors[R[i]] = [] sage: for u,v,l in C.edges(): ... for i in range(5): ... if u[i] != v[i]: ... edge_colors[R[i]].append((u,v,l)) sage: C.graphplot(vertex_labels=False, vertex_size=0, edge_colors=edge_colors).show() With the ``partition`` option, we can separate out same-color groups of vertices:: sage: D = graphs.DodecahedralGraph() sage: Pi = [[6,5,15,14,7],[16,13,8,2,4],[12,17,9,3,1],[0,19,18,10,11]] sage: D.show(partition=Pi) Loops are also plotted correctly:: sage: G = graphs.PetersenGraph() sage: G.allow_loops(True) sage: G.add_edge(0,0) sage: G.show() :: sage: D = DiGraph({0:[0,1], 1:[2], 2:[3]}, loops=True) sage: D.show() sage: D.show(edge_colors={(0,1,0):[(0,1,None),(1,2,None)],(0,0,0):[(2,3,None)]}) More options:: sage: pos = {0:[0.0, 1.5], 1:[-0.8, 0.3], 2:[-0.6, -0.8], 3:[0.6, -0.8], 4:[0.8, 0.3]} sage: g = Graph({0:[1], 1:[2], 2:[3], 3:[4], 4:[0]}) sage: g.graphplot(pos=pos, layout='spring', iterations=0).plot() Graphics object consisting of 11 graphics primitives sage: G = Graph() sage: P = G.graphplot().plot() sage: P.axes() False sage: G = DiGraph() sage: P = G.graphplot().plot() sage: P.axes() False We can plot multiple graphs:: sage: T = list(graphs.trees(7)) sage: t = T[3] sage: t.graphplot(heights={0:[0], 1:[4,5,1], 2:[2], 3:[3,6]}).plot() Graphics object consisting of 14 graphics primitives :: sage: T = list(graphs.trees(7)) sage: t = T[3] sage: t.graphplot(heights={0:[0], 1:[4,5,1], 2:[2], 3:[3,6]}).plot() Graphics object consisting of 14 graphics primitives sage: t.set_edge_label(0,1,-7) sage: t.set_edge_label(0,5,3) sage: t.set_edge_label(0,5,99) sage: t.set_edge_label(1,2,1000) sage: t.set_edge_label(3,2,'spam') sage: t.set_edge_label(2,6,3/2) sage: t.set_edge_label(0,4,66) sage: t.graphplot(heights={0:[0], 1:[4,5,1], 2:[2], 3:[3,6]}, edge_labels=True).plot() Graphics object consisting of 20 graphics primitives :: sage: T = list(graphs.trees(7)) sage: t = T[3] sage: t.graphplot(layout='tree').show() The tree layout is also useful:: sage: t = DiGraph('JCC???@A??GO??CO??GO??') sage: t.graphplot(layout='tree', tree_root=0, tree_orientation="up").show() More examples:: sage: D = DiGraph({0:[1,2,3], 2:[1,4], 3:[0]}) sage: D.graphplot().show() sage: D = DiGraph(multiedges=True, sparse=True) sage: for i in range(5): ... D.add_edge((i,i+1,'a')) ... D.add_edge((i,i-1,'b')) sage: D.graphplot(edge_labels=True,edge_colors=D._color_by_label()).plot() Graphics object consisting of 34 graphics primitives sage: g = Graph({}, loops=True, multiedges=True, sparse=True) sage: g.add_edges([(0,0,'a'),(0,0,'b'),(0,1,'c'),(0,1,'d'), ... (0,1,'e'),(0,1,'f'),(0,1,'f'),(2,1,'g'),(2,2,'h')]) sage: g.graphplot(edge_labels=True, color_by_label=True, edge_style='dashed').plot() Graphics object consisting of 22 graphics primitives The ``edge_style`` option may be provided in the short format too:: sage: g.graphplot(edge_labels=True, color_by_label=True, edge_style='--').plot() Graphics object consisting of 22 graphics primitives TESTS: Make sure that show options work with plot also:: sage: g = Graph({}) sage: g.plot(title='empty graph', axes=True) Graphics object consisting of 0 graphics primitives Check for invalid inputs:: sage: p = graphs.PetersenGraph().plot(egabrag='garbage') Traceback (most recent call last): ... ValueError: Invalid input 'egabrag=garbage' Make sure that no graphics primitive is clipped:: sage: tadpole = Graph({0:[0,1]}).plot() sage: bbox = tadpole.get_minmax_data() sage: for part in tadpole: ....: part_bbox = part.get_minmax_data() ....: assert bbox['xmin'] <= part_bbox['xmin'] <= part_bbox['xmax'] <= bbox['xmax'] ....: assert bbox['ymin'] <= part_bbox['ymin'] <= part_bbox['ymax'] <= bbox['ymax'] """ G = Graphics() options = self._options.copy() options.update(kwds) G._set_extra_kwds(Graphics._extract_kwds_for_show(options)) # Check the arguments for o in options: if o not in graphplot_options and o not in G._extra_kwds: raise ValueError("Invalid input '{}={}'".format(o, options[o])) for comp in self._plot_components.values(): if not isinstance(comp, list): G += comp else: for item in comp: G += item if self._options['graph_border']: xmin = G.xmin() xmax = G.xmax() ymin = G.ymin() ymax = G.ymax() dx = (xmax - xmin) / 10.0 dy = (ymax - ymin) / 10.0 border = (line([(xmin - dx, ymin - dy), (xmin - dx, ymax + dy), (xmax + dx, ymax + dy), (xmax + dx, ymin - dy), (xmin - dx, ymin - dy)], thickness=1.3)) border.axes_range(xmin=(xmin - dx), xmax=(xmax + dx), ymin=(ymin - dy), ymax=(ymax + dy)) G += border G.set_aspect_ratio(1) G.axes(False) return G
def text(string, xy, **options): r""" Returns a 2D text graphics object at the point `(x,y)`. Type ``text.options`` for a dictionary of options for 2D text. 2D OPTIONS: - ``fontsize`` - How big the text is. Either an integer that specifies the size in points or a string which specifies a size (one of 'xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large') - ``fontstyle`` - A string either 'normal', 'italic' or 'oblique' - ``fontweight`` - A numeric value in the range 0-1000 or a string (one of 'ultralight', 'light', 'normal', 'regular', 'book',' 'medium', 'roman', 'semibold', 'demibold', 'demi', 'bold', 'heavy', 'extra bold', 'black') - ``rgbcolor`` - The color as an RGB tuple - ``hue`` - The color given as a hue - ``alpha`` - A float (0.0 transparent through 1.0 opaque) - ``background_color`` - The background color - ``rotation`` - How to rotate the text: angle in degrees, vertical, horizontal - ``vertical_alignment`` - How to align vertically: top, center, bottom - ``horizontal_alignment`` - How to align horizontally: left, center, right - ``zorder`` - The layer level in which to draw - ``clip`` - (default: False) Whether to clip or not - ``axis_coords`` - (default: False) If True, use axis coordinates, so that (0,0) is the lower left and (1,1) upper right, regardless of the x and y range of plotted values. - ``bounding_box`` - A dictionary specifying a bounding box. Currently the text location. EXAMPLES:: sage: text("Sage graphics are really neat because they use matplotlib!", (2,12)) Graphics object consisting of 1 graphics primitive .. PLOT:: t = "Sage graphics are really neat because they use matplotlib!" sphinx_plot(text(t,(2,12))) Larger font, bold, colored red and transparent text:: sage: text("I had a dream!", (2,12), alpha=0.3, fontsize='large', fontweight='bold', color='red') Graphics object consisting of 1 graphics primitive .. PLOT:: sphinx_plot(text("I had a dream!", (2,12), alpha=0.3, fontsize='large', fontweight='bold', color='red')) By setting ``horizontal_alignment`` to 'left' the text is guaranteed to be in the lower left no matter what:: sage: text("I got a horse and he lives in a tree", (0,0), axis_coords=True, horizontal_alignment='left') Graphics object consisting of 1 graphics primitive .. PLOT:: t = "I got a horse and he lives in a tree" sphinx_plot(text(t, (0,0), axis_coords=True, horizontal_alignment='left')) Various rotations:: sage: text("noitator", (0,0), rotation=45.0, horizontal_alignment='left', vertical_alignment='bottom') Graphics object consisting of 1 graphics primitive .. PLOT:: sphinx_plot(text("noitator", (0,0), rotation=45.0, horizontal_alignment='left', vertical_alignment='bottom')) :: sage: text("Sage is really neat!!",(0,0), rotation="vertical") Graphics object consisting of 1 graphics primitive .. PLOT:: sphinx_plot(text("Sage is really neat!!",(0,0), rotation="vertical")) You can also align text differently:: sage: t1 = text("Hello",(1,1), vertical_alignment="top") sage: t2 = text("World", (1,0.5), horizontal_alignment="left") sage: t1 + t2 # render the sum Graphics object consisting of 2 graphics primitives .. PLOT:: t1 = text("Hello",(1,1), vertical_alignment="top") t2 = text("World", (1,0.5), horizontal_alignment="left") sphinx_plot(t1 + t2) You can save text as part of PDF output:: sage: text("sage", (0,0), rgbcolor=(0,0,0)).save(os.path.join(SAGE_TMP, 'a.pdf')) Some examples of bounding box:: sage: bbox = {'boxstyle':"rarrow,pad=0.3", 'fc':"cyan", 'ec':"b", 'lw':2} sage: text("I feel good", (1,2), bounding_box=bbox) Graphics object consisting of 1 graphics primitive .. PLOT:: bbox = {'boxstyle':"rarrow,pad=0.3", 'fc':"cyan", 'ec':"b", 'lw':2} sphinx_plot(text("I feel good", (1,2), bounding_box=bbox)) :: sage: text("So good", (0,0), bounding_box={'boxstyle':'round', 'fc':'w'}) Graphics object consisting of 1 graphics primitive .. PLOT:: bbox = {'boxstyle':'round', 'fc':'w'} sphinx_plot(text("So good", (0,0), bounding_box=bbox)) The possible options of the bounding box are 'boxstyle' (one of 'larrow', 'rarrow', 'round', 'round4', 'roundtooth', 'sawtooth', 'square'), 'fc' or 'facecolor', 'ec' or 'edgecolor', 'ha' or 'horizontalalignment', 'va' or 'verticalalignment', 'lw' or 'linewidth'. A text with a background color:: sage: text("So good", (-2,2), background_color='red') Graphics object consisting of 1 graphics primitive .. PLOT:: sphinx_plot(text("So good", (-2,2), background_color='red')) Text must be 2D (use the text3d command for 3D text):: sage: t = text("hi",(1,2,3)) Traceback (most recent call last): ... ValueError: use text3d instead for text in 3d sage: t = text3d("hi",(1,2,3)) Extra options will get passed on to show(), as long as they are valid:: sage: text("MATH IS AWESOME", (0, 0), fontsize=40, axes=False) Graphics object consisting of 1 graphics primitive sage: text("MATH IS AWESOME", (0, 0), fontsize=40).show(axes=False) # These are equivalent """ try: x, y = xy except ValueError: if isinstance(xy, (list, tuple)) and len(xy) == 3: raise ValueError("use text3d instead for text in 3d") raise from sage.plot.all import Graphics options['rgbcolor'] = to_mpl_color(options['rgbcolor']) point = (float(x), float(y)) g = Graphics() g._set_extra_kwds(Graphics._extract_kwds_for_show(options, ignore='fontsize')) g.add_primitive(Text(string, point, options)) return g
def bezier_path(path, **options): """ Returns a Graphics object of a Bezier path corresponding to the path parameter. The path is a list of curves, and each curve is a list of points. Each point is a tuple ``(x,y)``. The first curve contains the endpoints as the first and last point in the list. All other curves assume a starting point given by the last entry in the preceding list, and take the last point in the list as their opposite endpoint. A curve can have 0, 1 or 2 control points listed between the endpoints. In the input example for path below, the first and second curves have 2 control points, the third has one, and the fourth has no control points: path = [[p1, c1, c2, p2], [c3, c4, p3], [c5, p4], [p5], ...] In the case of no control points, a straight line will be drawn between the two endpoints. If one control point is supplied, then the curve at each of the endpoints will be tangent to the line from that endpoint to the control point. Similarly, in the case of two control points, at each endpoint the curve will be tangent to the line connecting that endpoint with the control point immediately after or immediately preceding it in the list. So in our example above, the curve between p1 and p2 is tangent to the line through p1 and c1 at p1, and tangent to the line through p2 and c2 at p2. Similarly, the curve between p2 and p3 is tangent to line(p2,c3) at p2 and tangent to line(p3,c4) at p3. Curve(p3,p4) is tangent to line(p3,c5) at p3 and tangent to line(p4,c5) at p4. Curve(p4,p5) is a straight line. INPUT: - ``path`` -- a list of lists of tuples (see above) - ``alpha`` -- default: 1 - ``fill`` -- default: False - ``thickness`` -- default: 1 - ``linestyle`` -- default: 'solid' - ``rbgcolor`` -- default: (0,0,0) - ``zorder`` -- the layer in which to draw EXAMPLES:: sage: path = [[(0,0),(.5,.1),(.75,3),(1,0)],[(.5,1),(.5,0)],[(.2,.5)]] sage: b = bezier_path(path, linestyle='dashed', rgbcolor='green') sage: b To construct a simple curve, create a list containing a single list:: sage: path = [[(0,0),(.5,1),(1,0)]] sage: curve = bezier_path(path, linestyle='dashed', rgbcolor='green') sage: curve Extra options will get passed on to :meth:`~Graphics.show`, as long as they are valid:: sage: bezier_path([[(0,1),(.5,0),(1,1)]], fontsize=50) sage: bezier_path([[(0,1),(.5,0),(1,1)]]).show(fontsize=50) # These are equivalent """ from sage.plot.all import Graphics g = Graphics() g._set_extra_kwds(g._extract_kwds_for_show(options)) g.add_primitive(BezierPath(path, options)) return g
def circle(center, radius, **options): """ Return a circle at a point center = `(x,y)` (or `(x,y,z)` and parallel to the `xy`-plane) with radius = `r`. Type ``circle.options`` to see all options. OPTIONS: - ``alpha`` - default: 1 - ``fill`` - default: False - ``thickness`` - default: 1 - ``linestyle`` - default: ``'solid'`` (2D plotting only) The style of the line, which is one of ``'dashed'``, ``'dotted'``, ``'solid'``, ``'dashdot'``, or ``'--'``, ``':'``, ``'-'``, ``'-.'``, respectively. - ``edgecolor`` - default: 'blue' (2D plotting only) - ``facecolor`` - default: 'blue' (2D plotting only, useful only if ``fill=True``) - ``rgbcolor`` - 2D or 3D plotting. This option overrides ``edgecolor`` and ``facecolor`` for 2D plotting. - ``legend_label`` - the label for this item in the legend - ``legend_color`` - the color for the legend label EXAMPLES: The default color is blue, the default linestyle is solid, but this is easy to change:: sage: c = circle((1,1), 1) sage: c Graphics object consisting of 1 graphics primitive .. PLOT:: sphinx_plot(circle((1,1), 1)) :: sage: c = circle((1,1), 1, rgbcolor=(1,0,0), linestyle='-.') sage: c Graphics object consisting of 1 graphics primitive .. PLOT:: c = circle((1,1), 1, rgbcolor=(1,0,0), linestyle='-.') sphinx_plot(c) We can also use this command to plot three-dimensional circles parallel to the `xy`-plane:: sage: c = circle((1,1,3), 1, rgbcolor=(1,0,0)) sage: c Graphics3d Object sage: type(c) <class 'sage.plot.plot3d.base.TransformGroup'> .. PLOT:: c = circle((1,1,3), 1, rgbcolor=(1,0,0)) sphinx_plot(c) To correct the aspect ratio of certain graphics, it is necessary to show with a ``figsize`` of square dimensions:: sage: c.show(figsize=[5,5],xmin=-1,xmax=3,ymin=-1,ymax=3) Here we make a more complicated plot, with many circles of different colors:: sage: g = Graphics() sage: step=6; ocur=1/5; paths=16; sage: PI = math.pi # numerical for speed -- fine for graphics sage: for r in range(1,paths+1): ....: for x,y in [((r+ocur)*math.cos(n), (r+ocur)*math.sin(n)) for n in srange(0, 2*PI+PI/step, PI/step)]: ....: g += circle((x,y), ocur, rgbcolor=hue(r/paths)) ....: rnext = (r+1)^2 ....: ocur = (rnext-r)-ocur sage: g.show(xmin=-(paths+1)^2, xmax=(paths+1)^2, ymin=-(paths+1)^2, ymax=(paths+1)^2, figsize=[6,6]) .. PLOT:: g = Graphics() step=6; ocur=1/5; paths=16; PI = math.pi # numerical for speed -- fine for graphics for r in range(1,paths+1): for x,y in [((r+ocur)*math.cos(n), (r+ocur)*math.sin(n)) for n in srange(0, 2*PI+PI/step, PI/step)]: g += circle((x,y), ocur, rgbcolor=hue(r*1.0/paths)) rnext = (r+1)**2 ocur = (rnext-r)-ocur g.set_axes_range(-(paths+1)**2,(paths+1)**2,-(paths+1)**2,(paths+1)**2) sphinx_plot(g) Note that the ``rgbcolor`` option overrides the other coloring options. This produces red fill in a blue circle:: sage: circle((2,3), 1, fill=True, edgecolor='blue', facecolor='red') Graphics object consisting of 1 graphics primitive .. PLOT:: sphinx_plot(circle((2,3), 1, fill=True, edgecolor='blue', facecolor='red')) This produces an all-green filled circle:: sage: circle((2,3), 1, fill=True, edgecolor='blue', rgbcolor='green') Graphics object consisting of 1 graphics primitive .. PLOT:: sphinx_plot(circle((2,3), 1, fill=True, edgecolor='blue', rgbcolor='green')) The option ``hue`` overrides *all* other options, so be careful with its use. This produces a purplish filled circle:: sage: circle((2,3), 1, fill=True, edgecolor='blue', rgbcolor='green', hue=.8) Graphics object consisting of 1 graphics primitive .. PLOT:: C = circle((2,3), 1, fill=True, edgecolor='blue', rgbcolor='green', hue=.8) sphinx_plot(C) And circles with legends:: sage: circle((4,5), 1, rgbcolor='yellow', fill=True, legend_label='the sun').show(xmin=0, ymin=0) .. PLOT:: C = circle((4,5), 1, rgbcolor='yellow', fill=True, legend_label='the sun') C.set_axes_range(xmin=0, ymin=0) sphinx_plot(C) :: sage: circle((4,5), 1, legend_label='the sun', legend_color='yellow').show(xmin=0, ymin=0) .. PLOT:: C = circle((4,5), 1, legend_label='the sun', legend_color='yellow') C.set_axes_range(xmin=0, ymin=0) sphinx_plot(C) Extra options will get passed on to show(), as long as they are valid:: sage: circle((0, 0), 2, figsize=[10,10]) # That circle is huge! Graphics object consisting of 1 graphics primitive :: sage: circle((0, 0), 2).show(figsize=[10,10]) # These are equivalent TESTS: We cannot currently plot circles in more than three dimensions:: sage: circle((1,1,1,1), 1, rgbcolor=(1,0,0)) Traceback (most recent call last): ... ValueError: The center of a plotted circle should have two or three coordinates. The default aspect ratio for a circle is 1.0:: sage: P = circle((1,1), 1) sage: P.aspect_ratio() 1.0 """ from sage.plot.all import Graphics # Reset aspect_ratio to 'automatic' in case scale is 'semilog[xy]'. # Otherwise matplotlib complains. scale = options.get('scale', None) if isinstance(scale, (list, tuple)): scale = scale[0] if scale == 'semilogy' or scale == 'semilogx': options['aspect_ratio'] = 'automatic' g = Graphics() g._set_extra_kwds(Graphics._extract_kwds_for_show(options)) g.add_primitive(Circle(center[0], center[1], radius, options)) if options['legend_label']: g.legend(True) g._legend_colors = [options['legend_color']] if len(center) == 2: return g elif len(center) == 3: return g[0].plot3d(z=center[2]) else: raise ValueError('The center of a plotted circle should have two or three coordinates.')
def density_plot(f, xrange, yrange, **options): r""" ``density_plot`` takes a function of two variables, `f(x,y)` and plots the height of of the function over the specified ``xrange`` and ``yrange`` as demonstrated below. ``density_plot(f, (xmin, xmax), (ymin, ymax), ...)`` INPUT: - ``f`` -- a function of two variables - ``(xmin, xmax)`` -- 2-tuple, the range of ``x`` values OR 3-tuple ``(x,xmin,xmax)`` - ``(ymin, ymax)`` -- 2-tuple, the range of ``y`` values OR 3-tuple ``(y,ymin,ymax)`` The following inputs must all be passed in as named parameters: - ``plot_points`` -- integer (default: 25); number of points to plot in each direction of the grid - ``cmap`` -- a colormap (type ``cmap_help()`` for more information). - ``interpolation`` -- string (default: ``'catrom'``), the interpolation method to use: ``'bilinear'``, ``'bicubic'``, ``'spline16'``, ``'spline36'``, ``'quadric'``, ``'gaussian'``, ``'sinc'``, ``'bessel'``, ``'mitchell'``, ``'lanczos'``, ``'catrom'``, ``'hermite'``, ``'hanning'``, ``'hamming'``, ``'kaiser'`` EXAMPLES: Here we plot a simple function of two variables. Note that since the input function is an expression, we need to explicitly declare the variables in 3-tuples for the range:: sage: x,y = var('x,y') sage: density_plot(sin(x)*sin(y), (x, -2, 2), (y, -2, 2)) Graphics object consisting of 1 graphics primitive Here we change the ranges and add some options; note that here ``f`` is callable (has variables declared), so we can use 2-tuple ranges:: sage: x,y = var('x,y') sage: f(x,y) = x^2*cos(x*y) sage: density_plot(f, (x,-10,5), (y, -5,5), interpolation='sinc', plot_points=100) Graphics object consisting of 1 graphics primitive An even more complicated plot:: sage: x,y = var('x,y') sage: density_plot(sin(x^2 + y^2)*cos(x)*sin(y), (x, -4, 4), (y, -4, 4), cmap='jet', plot_points=100) Graphics object consisting of 1 graphics primitive This should show a "spotlight" right on the origin:: sage: x,y = var('x,y') sage: density_plot(1/(x^10+y^10), (x, -10, 10), (y, -10, 10)) Graphics object consisting of 1 graphics primitive Some elliptic curves, but with symbolic endpoints. In the first example, the plot is rotated 90 degrees because we switch the variables `x`, `y`:: sage: density_plot(y^2 + 1 - x^3 - x, (y,-pi,pi), (x,-pi,pi)) Graphics object consisting of 1 graphics primitive :: sage: density_plot(y^2 + 1 - x^3 - x, (x,-pi,pi), (y,-pi,pi)) Graphics object consisting of 1 graphics primitive Extra options will get passed on to show(), as long as they are valid:: sage: density_plot(log(x) + log(y), (x, 1, 10), (y, 1, 10), dpi=20) Graphics object consisting of 1 graphics primitive :: sage: density_plot(log(x) + log(y), (x, 1, 10), (y, 1, 10)).show(dpi=20) # These are equivalent TESTS: Check that :trac:`15315` is fixed, i.e., density_plot respects the ``aspect_ratio`` parameter. Without the fix, it looks like a thin line of width a few mm. With the fix it should look like a nice fat layered image:: sage: density_plot((x*y)^(1/2), (x,0,3), (y,0,500), aspect_ratio=.01) Graphics object consisting of 1 graphics primitive Default ``aspect_ratio`` is ``"automatic"``, and that should work too:: sage: density_plot((x*y)^(1/2), (x,0,3), (y,0,500)) Graphics object consisting of 1 graphics primitive """ from sage.plot.all import Graphics from sage.plot.misc import setup_for_eval_on_grid g, ranges = setup_for_eval_on_grid([f], [xrange, yrange], options['plot_points']) g = g[0] xrange,yrange=[r[:2] for r in ranges] xy_data_array = [[g(x, y) for x in xsrange(*ranges[0], include_endpoint=True)] for y in xsrange(*ranges[1], include_endpoint=True)] g = Graphics() g._set_extra_kwds(Graphics._extract_kwds_for_show(options, ignore=['xmin', 'xmax'])) g.add_primitive(DensityPlot(xy_data_array, xrange, yrange, options)) return g
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]])) Graphics object consisting of 1 graphics primitive 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') Graphics object consisting of 1 graphics primitive 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 Graphics object consisting of 1 graphics primitive Graphics object consisting of 1 graphics primitive 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 Graphics object consisting of 1 graphics primitive Graphics object consisting of 1 graphics primitive 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) Graphics object consisting of 1 graphics primitive 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)) Graphics object consisting of 1 graphics primitive 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)]) Graphics object consisting of 1 graphics primitive 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') Graphics object consisting of 1 graphics primitive Another random plot, but over `\GF{389}`:: sage: m = random_matrix(GF(389), 10) sage: matrix_plot(m, cmap='Oranges') Graphics object consisting of 1 graphics primitive It also works if you lift it to the polynomial ring:: sage: matrix_plot(m.change_ring(GF(389)['x']), cmap='Oranges') Graphics object consisting of 1 graphics primitive We have several options for colorbars:: sage: matrix_plot(random_matrix(RDF, 50), colorbar=True, colorbar_orientation='horizontal') Graphics object consisting of 1 graphics primitive :: sage: matrix_plot(random_matrix(RDF, 50), colorbar=True, colorbar_format='%.3f') Graphics object consisting of 1 graphics primitive 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}) Graphics object consisting of 1 graphics primitive 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) Graphics object consisting of 1 graphics primitive :: sage: A=random_matrix(ZZ,100000,density=.00001,sparse=True) sage: matrix_plot(A,marker=',') Graphics object consisting of 1 graphics primitive 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) Graphics object consisting of 1 graphics primitive 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)) Graphics object consisting of 1 graphics primitive Plotting lists of lists also works:: sage: matrix_plot([[1,3,5,1],[2,4,5,6],[1,3,5,7]]) Graphics object consisting of 1 graphics primitive As does plotting of NumPy arrays:: sage: import numpy sage: matrix_plot(numpy.random.rand(10, 10)) Graphics object consisting of 1 graphics primitive A plot title can be added to the matrix plot.:: sage: matrix_plot(identity_matrix(50), origin='lower', title='not identity') Graphics object consisting of 1 graphics primitive 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') Graphics object consisting of 1 graphics primitive 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): ... TypeError: mat must be a Matrix or a two dimensional array Test that sparse matrices also work with subdivisions:: sage: matrix_plot(sparse, subdivisions=True, subdivision_boundaries=[[2,4],[6,8]]) Graphics object consisting of 1 graphics primitive Test that matrix plots have aspect ratio one (see :trac:`15315`):: sage: P = matrix_plot(random_matrix(RDF, 5)) sage: P.aspect_ratio() 1 """ import numpy as np import scipy.sparse as scipysparse from sage.plot.all import Graphics from sage.matrix.matrix 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 Exception: 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 circle(center, radius, **options): """ Return a circle at a point center = `(x,y)` (or `(x,y,z)` and parallel to the `xy`-plane) with radius = `r`. Type ``circle.options`` to see all options. OPTIONS: - ``alpha`` - default: 1 - ``fill`` - default: False - ``thickness`` - default: 1 - ``linestyle`` - default: 'solid' (2D plotting only) - ``edgecolor`` - default: 'blue' (2D plotting only) - ``facecolor`` - default: 'blue' (2D plotting only, useful only if ``fill=True``) - ``rgbcolor`` - 2D or 3D plotting. This option overrides ``edgecolor`` and ``facecolor`` for 2D plotting. - ``legend_label`` - the label for this item in the legend EXAMPLES: The default color is blue, but this is easy to change:: sage: c = circle((1,1), 1) sage: c :: sage: c = circle((1,1), 1, rgbcolor=(1,0,0)) sage: c We can also use this command to plot three-dimensional circles parallel to the `xy`-plane:: sage: c = circle((1,1,3), 1, rgbcolor=(1,0,0)) sage: c sage: type(c) <class 'sage.plot.plot3d.base.TransformGroup'> To correct the aspect ratio of certain graphics, it is necessary to show with a ``figsize`` of square dimensions:: sage: c.show(figsize=[5,5],xmin=-1,xmax=3,ymin=-1,ymax=3) Here we make a more complicated plot, with many circles of different colors:: sage: g = Graphics() sage: step=6; ocur=1/5; paths=16; sage: PI = math.pi # numerical for speed -- fine for graphics sage: for r in range(1,paths+1): ... for x,y in [((r+ocur)*math.cos(n), (r+ocur)*math.sin(n)) for n in srange(0, 2*PI+PI/step, PI/step)]: ... g += circle((x,y), ocur, rgbcolor=hue(r/paths)) ... rnext = (r+1)^2 ... ocur = (rnext-r)-ocur ... sage: g.show(xmin=-(paths+1)^2, xmax=(paths+1)^2, ymin=-(paths+1)^2, ymax=(paths+1)^2, figsize=[6,6]) Note that the ``rgbcolor`` option overrides the other coloring options. This produces red fill in a blue circle:: sage: circle((2,3), 1, fill=True, edgecolor='blue') This produces an all-green filled circle:: sage: circle((2,3), 1, fill=True, edgecolor='blue', rgbcolor='green') The option ``hue`` overrides *all* other options, so be careful with its use. This produces a purplish filled circle:: sage: circle((2,3), 1, fill=True, edgecolor='blue', rgbcolor='green', hue=.8) And a circle with a legend:: sage: circle((4,5), 1, rgbcolor='yellow', fill=True, legend_label='the sun').show(xmin=0, ymin=0) Extra options will get passed on to show(), as long as they are valid:: sage: circle((0, 0), 2, figsize=[10,10]) # That circle is huge! :: sage: circle((0, 0), 2).show(figsize=[10,10]) # These are equivalent TESTS: We cannot currently plot circles in more than three dimensions:: sage: circle((1,1,1,1), 1, rgbcolor=(1,0,0)) Traceback (most recent call last): ... ValueError: The center of a plotted circle should have two or three coordinates. The default aspect ratio for a circle is 1.0:: sage: P = circle((1,1), 1) sage: P.aspect_ratio() 1.0 """ from sage.plot.all import Graphics g = Graphics() g._set_extra_kwds(Graphics._extract_kwds_for_show(options)) g.add_primitive(Circle(center[0], center[1], radius, options)) if options['legend_label']: g.legend(True) if len(center)==2: return g elif len(center)==3: return g[0].plot3d(z=center[2]) else: raise ValueError, 'The center of a plotted circle should have two or three coordinates.'
z, ranges = setup_for_eval_on_grid([f,g], [xrange, yrange], options['plot_points']) f,g = z xpos_array, ypos_array, xvec_array, yvec_array = [],[],[],[] for x in xsrange(*ranges[0], include_endpoint=True): for y in xsrange(*ranges[1], include_endpoint=True): xpos_array.append(x) ypos_array.append(y) xvec_array.append(f(x,y)) yvec_array.append(g(x,y)) import numpy xvec_array = numpy.ma.masked_invalid(numpy.array(xvec_array, dtype=float)) yvec_array = numpy.ma.masked_invalid(numpy.array(yvec_array, dtype=float)) g = Graphics() g._set_extra_kwds(Graphics._extract_kwds_for_show(options)) g.add_primitive(PlotField(xpos_array, ypos_array, xvec_array, yvec_array, options)) return g def plot_slope_field(f, xrange, yrange, **kwds): r""" ``plot_slope_field`` takes a function of two variables xvar and yvar (for instance, if the variables are `x` and `y`, take `f(x,y)`), and at representative points `(x_i,y_i)` between xmin, xmax, and ymin, ymax respectively, plots a line with slope `f(x_i,y_i)` (see below). ``plot_slope_field(f, (xvar, xmin, xmax), (yvar, ymin, ymax))`` EXAMPLES: A logistic function modeling population growth::
def region_plot(f, xrange, yrange, plot_points, incol, outcol, bordercol, borderstyle, borderwidth, **options): r""" ``region_plot`` takes a boolean function of two variables, `f(x,y)` and plots the region where f is True over the specified ``xrange`` and ``yrange`` as demonstrated below. ``region_plot(f, (xmin, xmax), (ymin, ymax), ...)`` INPUT: - ``f`` -- a boolean function of two variables - ``(xmin, xmax)`` -- 2-tuple, the range of ``x`` values OR 3-tuple ``(x,xmin,xmax)`` - ``(ymin, ymax)`` -- 2-tuple, the range of ``y`` values OR 3-tuple ``(y,ymin,ymax)`` - ``plot_points`` -- integer (default: 100); number of points to plot in each direction of the grid - ``incol`` -- a color (default: ``'blue'``), the color inside the region - ``outcol`` -- a color (default: ``'white'``), the color of the outside of the region If any of these options are specified, the border will be shown as indicated, otherwise it is only implicit (with color ``incol``) as the border of the inside of the region. - ``bordercol`` -- a color (default: ``None``), the color of the border (``'black'`` if ``borderwidth`` or ``borderstyle`` is specified but not ``bordercol``) - ``borderstyle`` -- string (default: 'solid'), one of ``'solid'``, ``'dashed'``, ``'dotted'``, ``'dashdot'``, respectively ``'-'``, ``'--'``, ``':'``, ``'-.'``. - ``borderwidth`` -- integer (default: None), the width of the border in pixels - ``legend_label`` -- the label for this item in the legend - ``base`` - (default: 10) the base of the logarithm if a logarithmic scale is set. This must be greater than 1. The base can be also given as a list or tuple ``(basex, basey)``. ``basex`` sets the base of the logarithm along the horizontal axis and ``basey`` sets the base along the vertical axis. - ``scale`` -- (default: ``"linear"``) string. The scale of the axes. Possible values are ``"linear"``, ``"loglog"``, ``"semilogx"``, ``"semilogy"``. The scale can be also be given as single argument that is a list or tuple ``(scale, base)`` or ``(scale, basex, basey)``. The ``"loglog"`` scale sets both the horizontal and vertical axes to logarithmic scale. The ``"semilogx"`` scale sets the horizontal axis to logarithmic scale. The ``"semilogy"`` scale sets the vertical axis to logarithmic scale. The ``"linear"`` scale is the default value when :class:`~sage.plot.graphics.Graphics` is initialized. EXAMPLES: Here we plot a simple function of two variables:: sage: x,y = var('x,y') sage: region_plot(cos(x^2+y^2) <= 0, (x, -3, 3), (y, -3, 3)) Graphics object consisting of 1 graphics primitive Here we play with the colors:: sage: region_plot(x^2+y^3 < 2, (x, -2, 2), (y, -2, 2), incol='lightblue', bordercol='gray') Graphics object consisting of 2 graphics primitives An even more complicated plot, with dashed borders:: sage: region_plot(sin(x)*sin(y) >= 1/4, (x,-10,10), (y,-10,10), incol='yellow', bordercol='black', borderstyle='dashed', plot_points=250) Graphics object consisting of 2 graphics primitives A disk centered at the origin:: sage: region_plot(x^2+y^2<1, (x,-1,1), (y,-1,1)) Graphics object consisting of 1 graphics primitive A plot with more than one condition (all conditions must be true for the statement to be true):: sage: region_plot([x^2+y^2<1, x<y], (x,-2,2), (y,-2,2)) Graphics object consisting of 1 graphics primitive Since it doesn't look very good, let's increase ``plot_points``:: sage: region_plot([x^2+y^2<1, x<y], (x,-2,2), (y,-2,2), plot_points=400) Graphics object consisting of 1 graphics primitive To get plots where only one condition needs to be true, use a function. Using lambda functions, we definitely need the extra ``plot_points``:: sage: region_plot(lambda x,y: x^2+y^2<1 or x<y, (x,-2,2), (y,-2,2), plot_points=400) Graphics object consisting of 1 graphics primitive The first quadrant of the unit circle:: sage: region_plot([y>0, x>0, x^2+y^2<1], (x,-1.1, 1.1), (y,-1.1, 1.1), plot_points = 400) Graphics object consisting of 1 graphics primitive Here is another plot, with a huge border:: sage: region_plot(x*(x-1)*(x+1)+y^2<0, (x, -3, 2), (y, -3, 3), incol='lightblue', bordercol='gray', borderwidth=10, plot_points=50) Graphics object consisting of 2 graphics primitives If we want to keep only the region where x is positive:: sage: region_plot([x*(x-1)*(x+1)+y^2<0, x>-1], (x, -3, 2), (y, -3, 3), incol='lightblue', plot_points=50) Graphics object consisting of 1 graphics primitive Here we have a cut circle:: sage: region_plot([x^2+y^2<4, x>-1], (x, -2, 2), (y, -2, 2), incol='lightblue', bordercol='gray', plot_points=200) Graphics object consisting of 2 graphics primitives The first variable range corresponds to the horizontal axis and the second variable range corresponds to the vertical axis:: sage: s,t=var('s,t') sage: region_plot(s>0,(t,-2,2),(s,-2,2)) Graphics object consisting of 1 graphics primitive :: sage: region_plot(s>0,(s,-2,2),(t,-2,2)) Graphics object consisting of 1 graphics primitive An example of a region plot in 'loglog' scale:: sage: region_plot(x^2+y^2<100, (x,1,10), (y,1,10), scale='loglog') Graphics object consisting of 1 graphics primitive """ from sage.plot.all import Graphics from sage.plot.misc import setup_for_eval_on_grid import numpy if not isinstance(f, (list, tuple)): f = [f] f = [equify(g) for g in f] g, ranges = setup_for_eval_on_grid(f, [xrange, yrange], plot_points) xrange, yrange = [r[:2] for r in ranges] xy_data_arrays = numpy.asarray( [[[func(x, y) for x in xsrange(*ranges[0], include_endpoint=True)] for y in xsrange(*ranges[1], include_endpoint=True)] for func in g], dtype=float) xy_data_array = numpy.abs(xy_data_arrays.prod(axis=0)) # Now we need to set entries to negative iff all # functions were negative at that point. neg_indices = (xy_data_arrays < 0).all(axis=0) xy_data_array[neg_indices] = -xy_data_array[neg_indices] from matplotlib.colors import ListedColormap incol = rgbcolor(incol) outcol = rgbcolor(outcol) cmap = ListedColormap([incol, outcol]) cmap.set_over(outcol) cmap.set_under(incol) g = Graphics() # Reset aspect_ratio to 'automatic' in case scale is 'semilog[xy]'. # Otherwise matplotlib complains. scale = options.get('scale', None) if isinstance(scale, (list, tuple)): scale = scale[0] if scale == 'semilogy' or scale == 'semilogx': options['aspect_ratio'] = 'automatic' g._set_extra_kwds( Graphics._extract_kwds_for_show(options, ignore=['xmin', 'xmax'])) g.add_primitive( ContourPlot( xy_data_array, xrange, yrange, dict(contours=[-1e307, 0, 1e307], cmap=cmap, fill=True, **options))) if bordercol or borderstyle or borderwidth: cmap = [rgbcolor(bordercol)] if bordercol else ['black'] linestyles = [borderstyle] if borderstyle else None linewidths = [borderwidth] if borderwidth else None g.add_primitive( ContourPlot( xy_data_array, xrange, yrange, dict(linestyles=linestyles, linewidths=linewidths, contours=[0], cmap=[bordercol], fill=False, **options))) return g
def disk(point, radius, angle, **options): r""" A disk (that is, a sector or wedge of a circle) with center at a point = `(x,y)` (or `(x,y,z)` and parallel to the `xy`-plane) with radius = `r` spanning (in radians) angle=`(rad1, rad2)`. Type ``disk.options`` to see all options. EXAMPLES: Make some dangerous disks:: sage: bl = disk((0.0,0.0), 1, (pi, 3*pi/2), color='yellow') sage: tr = disk((0.0,0.0), 1, (0, pi/2), color='yellow') sage: tl = disk((0.0,0.0), 1, (pi/2, pi), color='black') sage: br = disk((0.0,0.0), 1, (3*pi/2, 2*pi), color='black') sage: P = tl+tr+bl+br sage: P.show(xmin=-2,xmax=2,ymin=-2,ymax=2) The default aspect ratio is 1.0:: sage: disk((0.0,0.0), 1, (pi, 3*pi/2)).aspect_ratio() 1.0 Another example of a disk:: sage: bl = disk((0.0,0.0), 1, (pi, 3*pi/2), rgbcolor=(1,1,0)) sage: bl.show(figsize=[5,5]) Note that since ``thickness`` defaults to zero, it is best to change that option when using ``fill=False``:: sage: disk((2,3), 1, (pi/4,pi/3), hue=.8, alpha=.3, fill=False, thickness=2) Graphics object consisting of 1 graphics primitive The previous two examples also illustrate using ``hue`` and ``rgbcolor`` as ways of specifying the color of the graphic. We can also use this command to plot three-dimensional disks parallel to the `xy`-plane:: sage: d = disk((1,1,3), 1, (pi,3*pi/2), rgbcolor=(1,0,0)) sage: d Graphics3d Object sage: type(d) <type 'sage.plot.plot3d.index_face_set.IndexFaceSet'> Extra options will get passed on to ``show()``, as long as they are valid:: sage: disk((0, 0), 5, (0, pi/2), xmin=0, xmax=5, ymin=0, ymax=5, figsize=(2,2), rgbcolor=(1, 0, 1)) Graphics object consisting of 1 graphics primitive sage: disk((0, 0), 5, (0, pi/2), rgbcolor=(1, 0, 1)).show(xmin=0, xmax=5, ymin=0, ymax=5, figsize=(2,2)) # These are equivalent TESTS: Testing that legend labels work right:: sage: disk((2,4), 3, (pi/8, pi/4), hue=1, legend_label='disk', legend_color='blue') Graphics object consisting of 1 graphics primitive We cannot currently plot disks in more than three dimensions:: sage: d = disk((1,1,1,1), 1, (0,pi)) Traceback (most recent call last): ... ValueError: The center point of a plotted disk should have two or three coordinates. """ from sage.plot.all import Graphics g = Graphics() # Reset aspect_ratio to 'automatic' in case scale is 'semilog[xy]'. # Otherwise matplotlib complains. scale = options.get('scale', None) if isinstance(scale, (list, tuple)): scale = scale[0] if scale == 'semilogy' or scale == 'semilogx': options['aspect_ratio'] = 'automatic' g._set_extra_kwds(Graphics._extract_kwds_for_show(options)) g.add_primitive(Disk(point, radius, angle, options)) if options['legend_label']: g.legend(True) g._legend_colors = [options['legend_color']] if len(point)==2: return g elif len(point)==3: return g[0].plot3d(z=point[2]) else: raise ValueError('The center point of a plotted disk should have two or three coordinates.')
def ellipse(center, r1, r2, angle=0, **options): """ Return an ellipse centered at a point center = ``(x,y)`` with radii = ``r1,r2`` and angle ``angle``. Type ``ellipse.options`` to see all options. INPUT: - ``center`` - 2-tuple of real numbers - coordinates of the center - ``r1``, ``r2`` - positive real numbers - the radii of the ellipse - ``angle`` - real number (default: 0) - the angle between the first axis and the horizontal OPTIONS: - ``alpha`` - default: 1 - transparency - ``fill`` - default: False - whether to fill the ellipse or not - ``thickness`` - default: 1 - thickness of the line - ``rgbcolor`` - default: (0,0,0) - color of the ellipse (overwrites ``edgecolor`` and ``facecolor``) - ``linestyle`` - default: 'solid' - ``edgecolor`` - default: 'black' - color of the contour - ``facecolor`` - default: 'red' - color of the filling EXAMPLES: An ellipse centered at (0,0) with major and minor axes of lengths 2 and 1:: sage: ellipse((0,0),2,1) More complicated examples with tilted axes and drawing options:: sage: ellipse((0,0),3,1,pi/6,fill=True,alpha=0.3) :: sage: ellipse((0,0),3,1,pi/6,fill=True,edgecolor='blue',facecolor='red') The default aspect ratio for ellipses is 1.0:: sage: ellipse((0,0),2,1).aspect_ratio() 1.0 One cannot yet plot ellipses in 3D:: sage: ellipse((0,0,0),2,1) Traceback (most recent call last): ... NotImplementedError: plotting ellipse in 3D is not implemented """ from sage.plot.all import Graphics g = Graphics() g._set_extra_kwds(Graphics._extract_kwds_for_show(options)) g.add_primitive(Ellipse(center[0],center[1],r1,r2,angle,options)) if len(center)==2: return g elif len(center)==3: raise NotImplementedError, "plotting ellipse in 3D is not implemented"
def arrow2d(tailpoint=None, headpoint=None, path=None, **options): """ If tailpoint and headpoint are provided, returns an arrow from (xmin, ymin) to (xmax, ymax). If tailpoint or headpoint is None and path is not None, returns an arrow along the path. (See further info on paths in bezier_path). INPUT: - ``tailpoint`` - the starting point of the arrow - ``headpoint`` - where the arrow is pointing to - ``path`` - the list of points and control points (see bezier_path for detail) that the arrow will follow from source to destination - ``head`` - 0, 1 or 2, whether to draw the head at the start (0), end (1) or both (2) of the path (using 0 will swap headpoint and tailpoint). This is ignored in 3D plotting. - ``linestyle`` - The style of the line, which is one of 'dashed', 'dotted', 'solid', 'dashdot', or '--', ':', '-', '-.', respectively. - ``width`` - (default: 2) the width of the arrow shaft, in points - ``color`` - (default: (0,0,1)) the color of the arrow (as an RGB tuple or a string) - ``hue`` - the color of the arrow (as a number) - ``arrowsize`` - the size of the arrowhead - ``arrowshorten`` - the length in points to shorten the arrow (ignored if using path parameter) - ``legend_label`` - the label for this item in the legend - ``zorder`` - the layer level to draw the arrow-- note that this is ignored in 3D plotting. EXAMPLES: A straight, blue arrow:: sage: arrow2d((1, 1), (3, 3)) Make a red arrow:: sage: arrow2d((-1, -1), (2, 3), color=(1,0,0)) sage: arrow2d((-1, -1), (2, 3), color='red') You can change the width of an arrow:: sage: arrow2d((1, 1), (3, 3), width=5, arrowsize=15) Use a dashed line instead of a solid one for the arrow:: sage: arrow2d((1, 1), (3, 3), linestyle='dashed') sage: arrow2d((1, 1), (3, 3), linestyle='--') A pretty circle of arrows:: sage: sum([arrow2d((0,0), (cos(x),sin(x)), hue=x/(2*pi)) for x in [0..2*pi,step=0.1]]) If we want to draw the arrow between objects, for example, the boundaries of two lines, we can use the arrowshorten option to make the arrow shorter by a certain number of points:: sage: line([(0,0),(1,0)],thickness=10)+line([(0,1),(1,1)], thickness=10)+arrow2d((0.5,0),(0.5,1), arrowshorten=10,rgbcolor=(1,0,0)) If BOTH headpoint and tailpoint are None, then an empty plot is returned:: sage: arrow2d(headpoint=None, tailpoint=None) We can also draw an arrow with a legend:: sage: arrow((0,0), (0,2), legend_label='up') Extra options will get passed on to show(), as long as they are valid:: sage: arrow2d((-2, 2), (7,1), frame=True) sage: arrow2d((-2, 2), (7,1)).show(frame=True) """ # Allow the usual linestyles used in the plot() command dict_line = {':': 'dotted', '-': 'solid', '--': 'dashed', '-.': 'dashdot'} if options['linestyle'] in dict_line: options['linestyle'] = dict_line[options['linestyle']] from sage.plot.all import Graphics g = Graphics() g._set_extra_kwds(Graphics._extract_kwds_for_show(options)) if headpoint is not None and tailpoint is not None: xtail, ytail = tailpoint xhead, yhead = headpoint g.add_primitive(Arrow(xtail, ytail, xhead, yhead, options=options)) elif path is not None: g.add_primitive(CurveArrow(path, options=options)) elif tailpoint is None and headpoint is None: return g else: raise TypeError('Arrow requires either both headpoint and tailpoint or a path parameter.') if options['legend_label']: g.legend(True) return g
def my_hyperbolic_triangle(a, b, c, **options): """ Return a hyperbolic triangle in the complex hyperbolic plane with points (a, b, c). Type ``?hyperbolic_triangle`` to see all options. INPUT: - ``a, b, c`` - complex numbers in the upper half complex plane OPTIONS: - ``alpha`` - default: 1 - ``fill`` - default: False - ``thickness`` - default: 1 - ``rgbcolor`` - default: 'blue' - ``linestyle`` - default: 'solid' EXAMPLES: Show a hyperbolic triangle with coordinates 0, `1/2+i\sqrt{3}/2` and `-1/2+i\sqrt{3}/2`:: sage: hyperbolic_triangle(0, -1/2+I*sqrt(3)/2, 1/2+I*sqrt(3)/2) A hyperbolic triangle with coordinates 0, 1 and 2+i:: sage: hyperbolic_triangle(0, 1, 2+i, fill=true, rgbcolor='red') """ from sage.plot.all import Graphics g = Graphics() g._set_extra_kwds(g._extract_kwds_for_show(options)) model = options['model'] npts = options.get('npts', 10) sides = options.pop('sides', [1, 2, 3]) ## Which of the sides we will draw. verbose = options.get('verbose', 0) options.pop('model', None) options.pop('method', None) if model == "D": #g.add_primitive(HyperbolicTriangleDisc(a, b, c, **options)) #print "options=",options options['sides'] = sides H = HyperbolicTriangleDisc(a, b, c, **options) g += H() else: options.pop('npts', None) if sides == [1, 2, 3]: if verbose > 0: print "adding HyperbolicTriangle({0}, {1}, {2},options={3})".format( a, b, c, options) options.pop('verbose', 0) ## check if We need my class or the original class g.add_primitive(HyperbolicTriangle(a, b, c, options)) else: options['sides'] = sides if verbose > 0: print "adding HyperbolicTriangle({0}, {1}, {2},options={3})".format( a, b, c, options) g.add_primitive(HyperbolicTriangle(a, b, c, options)) g.set_aspect_ratio(1) return g