def _render_on_subplot(self, subplot): """ Render this arrow in a subplot. This is the key function that defines how this arrow graphics primitive is rendered in matplotlib's library. EXAMPLES: This function implicitly ends up rendering this arrow on a matplotlib subplot:: sage: arrow((0,1), (2,-1)) """ options = self.options() head = options.pop('head') if head == 0: style = '<|-' elif head == 1: style = '-|>' elif head == 2: style = '<|-|>' else: raise KeyError('head parameter must be one of 0 (start), 1 (end) or 2 (both).') width = float(options['width']) arrowshorten_end = float(options.get('arrowshorten',0))/2.0+width*2 arrowsize = float(options.get('arrowsize',5)) head_width=arrowsize head_length=arrowsize*2.0 color = to_mpl_color(options['rgbcolor']) from matplotlib.patches import FancyArrowPatch p = FancyArrowPatch((self.xtail, self.ytail), (self.xhead, self.yhead), lw=width, arrowstyle='%s,head_width=%s,head_length=%s'%(style,head_width, head_length), shrinkA=arrowshorten_end, shrinkB=arrowshorten_end, fc=color, ec=color, linestyle=options['linestyle']) p.set_zorder(options['zorder']) p.set_label(options['legend_label']) subplot.add_patch(p) return p
def _render_on_subplot(self, subplot): """ Render this arrow in a subplot. This is the key function that defines how this arrow graphics primitive is rendered in matplotlib's library. EXAMPLES: This function implicitly ends up rendering this arrow on a matplotlib subplot:: sage: arrow((0,1), (2,-1)) TESTS: The length of the ends (shrinkA and shrinkB) should not depend on the width of the arrow, because Matplotlib already takes this into account. See :trac:`12836`:: sage: fig = Graphics().matplotlib() sage: sp = fig.add_subplot(1,1,1) sage: a = arrow((0,0), (1,1)) sage: b = arrow((0,0), (1,1), width=20) sage: p1 = a[0]._render_on_subplot(sp) sage: p2 = b[0]._render_on_subplot(sp) sage: p1.shrinkA == p2.shrinkA True sage: p1.shrinkB == p2.shrinkB True """ options = self.options() head = options.pop('head') if head == 0: style = '<|-' elif head == 1: style = '-|>' elif head == 2: style = '<|-|>' else: raise KeyError('head parameter must be one of 0 (start), 1 (end) or 2 (both).') width = float(options['width']) arrowshorten_end = float(options.get('arrowshorten',0))/2.0 arrowsize = float(options.get('arrowsize',5)) head_width=arrowsize head_length=arrowsize*2.0 color = to_mpl_color(options['rgbcolor']) from matplotlib.patches import FancyArrowPatch p = FancyArrowPatch((self.xtail, self.ytail), (self.xhead, self.yhead), lw=width, arrowstyle='%s,head_width=%s,head_length=%s'%(style,head_width, head_length), shrinkA=arrowshorten_end, shrinkB=arrowshorten_end, fc=color, ec=color, linestyle=options['linestyle']) p.set_zorder(options['zorder']) p.set_label(options['legend_label']) subplot.add_patch(p) return p
def _render_on_subplot(self, subplot): """ Render this arrow in a subplot. This is the key function that defines how this arrow graphics primitive is rendered in matplotlib's library. EXAMPLES:: This function implicitly ends up rendering this arrow on a matplotlib subplot: sage: arrow(path=[[(0,1), (2,-1), (4,5)]]) """ from sage.plot.misc import get_matplotlib_linestyle options = self.options() width = float(options['width']) head = options.pop('head') if head == 0: style = '<|-' elif head == 1: style = '-|>' elif head == 2: style = '<|-|>' else: raise KeyError('head parameter must be one of 0 (start), 1 (end) or 2 (both).') arrowsize = float(options.get('arrowsize',5)) head_width=arrowsize head_length=arrowsize*2.0 color = to_mpl_color(options['rgbcolor']) from matplotlib.patches import FancyArrowPatch from matplotlib.path import Path bpath = Path(self.vertices, self.codes) p = FancyArrowPatch(path=bpath, lw=width, arrowstyle='%s,head_width=%s,head_length=%s'%(style,head_width, head_length), fc=color, ec=color) p.set_linestyle(get_matplotlib_linestyle(options['linestyle'],return_type='long')) p.set_zorder(options['zorder']) p.set_label(options['legend_label']) subplot.add_patch(p) return p
def _render_on_subplot(self, subplot): """ Render this arrow in a subplot. This is the key function that defines how this arrow graphics primitive is rendered in matplotlib's library. EXAMPLES:: This function implicitly ends up rendering this arrow on a matplotlib subplot: sage: arrow(path=[[(0,1), (2,-1), (4,5)]]) Graphics object consisting of 1 graphics primitive """ from sage.plot.misc import get_matplotlib_linestyle options = self.options() width = float(options["width"]) head = options.pop("head") if head == 0: style = "<|-" elif head == 1: style = "-|>" elif head == 2: style = "<|-|>" else: raise KeyError("head parameter must be one of 0 (start), 1 (end) or 2 (both).") arrowsize = float(options.get("arrowsize", 5)) head_width = arrowsize head_length = arrowsize * 2.0 color = to_mpl_color(options["rgbcolor"]) from matplotlib.patches import FancyArrowPatch from matplotlib.path import Path bpath = Path(self.vertices, self.codes) p = FancyArrowPatch( path=bpath, lw=width, arrowstyle="%s,head_width=%s,head_length=%s" % (style, head_width, head_length), fc=color, ec=color, ) p.set_linestyle(get_matplotlib_linestyle(options["linestyle"], return_type="long")) p.set_zorder(options["zorder"]) p.set_label(options["legend_label"]) subplot.add_patch(p) return p
def _render_on_subplot(self, subplot): r""" Render this arrow in a subplot. This is the key function that defines how this arrow graphics primitive is rendered in matplotlib's library. EXAMPLES: This function implicitly ends up rendering this arrow on a matplotlib subplot:: sage: arrow((0,1), (2,-1)) TESTS: The length of the ends (shrinkA and shrinkB) should not depend on the width of the arrow, because Matplotlib already takes this into account. See :trac:`12836`:: sage: fig = Graphics().matplotlib() sage: sp = fig.add_subplot(1,1,1) sage: a = arrow((0,0), (1,1)) sage: b = arrow((0,0), (1,1), width=20) sage: p1 = a[0]._render_on_subplot(sp) sage: p2 = b[0]._render_on_subplot(sp) sage: p1.shrinkA == p2.shrinkA True sage: p1.shrinkB == p2.shrinkB True Dashed arrows should have solid arrowheads, :trac:`12852`. This test saves the plot of a dashed arrow to an EPS file. Within the EPS file, ``stroke`` will be called twice: once to draw the line, and again to draw the arrowhead. We check that both calls do not occur while the dashed line style is enabled:: sage: a = arrow((0,0), (1,1), linestyle='dashed') sage: filename = tmp_filename(ext='.eps') sage: a.save(filename=filename) sage: with open(filename, 'r') as f: ....: contents = f.read().replace('\n', ' ') sage: two_stroke_pattern = r'setdash.*stroke.*stroke.*setdash' sage: import re sage: two_stroke_re = re.compile(two_stroke_pattern) sage: two_stroke_re.search(contents) is None True """ options = self.options() head = options.pop('head') if head == 0: style = '<|-' elif head == 1: style = '-|>' elif head == 2: style = '<|-|>' else: raise KeyError('head parameter must be one of 0 (start), 1 (end) or 2 (both).') width = float(options['width']) arrowshorten_end = float(options.get('arrowshorten',0))/2.0 arrowsize = float(options.get('arrowsize',5)) head_width=arrowsize head_length=arrowsize*2.0 color = to_mpl_color(options['rgbcolor']) from matplotlib.patches import FancyArrowPatch p = FancyArrowPatch((self.xtail, self.ytail), (self.xhead, self.yhead), lw=width, arrowstyle='%s,head_width=%s,head_length=%s'%(style,head_width, head_length), shrinkA=arrowshorten_end, shrinkB=arrowshorten_end, fc=color, ec=color, linestyle=options['linestyle']) p.set_zorder(options['zorder']) p.set_label(options['legend_label']) if options['linestyle']!='solid': # The next few lines work around a design issue in matplotlib. Currently, the specified # linestyle is used to draw both the path and the arrowhead. If linestyle is 'dashed', this # looks really odd. This code is from Jae-Joon Lee in response to a post to the matplotlib mailing # list. See http://sourceforge.net/mailarchive/forum.php?thread_name=CAG%3DuJ%2Bnw2dE05P9TOXTz_zp-mGP3cY801vMH7yt6vgP9_WzU8w%40mail.gmail.com&forum_name=matplotlib-users import matplotlib.patheffects as pe class CheckNthSubPath(object): def __init__(self, patch, n): """ creates an callable object that returns True if the provided path is the n-th path from the patch. """ self._patch = patch self._n = n def get_paths(self, renderer): self._patch.set_dpi_cor(renderer.points_to_pixels(1.)) paths, fillables = self._patch.get_path_in_displaycoord() return paths def __call__(self, renderer, gc, tpath, affine, rgbFace): path = self.get_paths(renderer)[self._n] vert1, code1 = path.vertices, path.codes import numpy as np if np.all(vert1 == tpath.vertices) and np.all(code1 == tpath.codes): return True else: return False class ConditionalStroke(pe._Base): def __init__(self, condition_func, pe_list): """ path effect that is only applied when the condition_func returns True. """ super(ConditionalStroke, self).__init__() self._pe_list = pe_list self._condition_func = condition_func def draw_path(self, renderer, gc, tpath, affine, rgbFace): if self._condition_func(renderer, gc, tpath, affine, rgbFace): for pe1 in self._pe_list: pe1.draw_path(renderer, gc, tpath, affine, rgbFace) pe1 = ConditionalStroke(CheckNthSubPath(p, 0),[pe.Stroke()]) pe2 = ConditionalStroke(CheckNthSubPath(p, 1),[pe.Stroke(linestyle="solid")]) p.set_path_effects([pe1, pe2]) subplot.add_patch(p) return p
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 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 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 # 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) 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 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 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 _render_on_subplot(self, subplot): """ TESTS:: sage: matrix_plot(random_matrix(RDF, 50), cmap='jet') Graphics object consisting of 1 graphics primitive """ options = self.options() cmap = get_cmap(options.pop('cmap',None)) origin=options['origin'] norm=options['norm'] if norm=='value': import matplotlib norm=matplotlib.colors.NoNorm() if options['subdivisions']: subdiv_options=options['subdivision_options'] if isinstance(subdiv_options['boundaries'], (list, tuple)): rowsub,colsub=subdiv_options['boundaries'] else: rowsub=subdiv_options['boundaries'] colsub=subdiv_options['boundaries'] if isinstance(subdiv_options['style'], (list, tuple)): rowstyle,colstyle=subdiv_options['style'] else: rowstyle=subdiv_options['style'] colstyle=subdiv_options['style'] if rowstyle is None: rowstyle=dict() if colstyle is None: colstyle=dict() # Make line objects for subdivisions from line import line2d lim=self.get_minmax_data() # First draw horizontal lines representing row subdivisions for y in rowsub: l=line2d([(lim['xmin'],y-0.5), (lim['xmax'],y-0.5)], **rowstyle)[0] l._render_on_subplot(subplot) for x in colsub: l=line2d([(x-0.5, lim['ymin']), (x-0.5, lim['ymax'])], **colstyle)[0] l._render_on_subplot(subplot) if hasattr(self.xy_data_array, 'tocoo'): # Sparse matrix -- use spy opts=options.copy() for opt in ['vmin', 'vmax', 'norm', 'origin','subdivisions','subdivision_options', 'colorbar','colorbar_options']: del opts[opt] if origin=='lower': subplot.spy(self.xy_data_array.tocsr()[::-1], **opts) else: subplot.spy(self.xy_data_array, **opts) else: opts = dict(cmap=cmap, interpolation='nearest', aspect='equal', norm=norm, vmin=options['vmin'], vmax=options['vmax'], origin=origin,zorder=options.get('zorder',None)) image=subplot.imshow(self.xy_data_array, **opts) if options.get('colorbar', False): colorbar_options = options['colorbar_options'] from matplotlib import colorbar cax,kwds=colorbar.make_axes_gridspec(subplot,**colorbar_options) cb=colorbar.Colorbar(cax,image, **kwds) if origin=='upper': subplot.xaxis.tick_top() elif origin=='lower': subplot.xaxis.tick_bottom() subplot.xaxis.set_ticks_position('both') #only tick marks, not tick labels
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: 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) 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 _render_on_subplot(self, subplot): """ TESTS:: sage: matrix_plot(random_matrix(RDF, 50), cmap='jet') Graphics object consisting of 1 graphics primitive """ options = self.options() cmap = get_cmap(options.pop('cmap', None)) origin = options['origin'] norm = options['norm'] if norm == 'value': import matplotlib norm = matplotlib.colors.NoNorm() if options['subdivisions']: subdiv_options = options['subdivision_options'] if isinstance(subdiv_options['boundaries'], (list, tuple)): rowsub, colsub = subdiv_options['boundaries'] else: rowsub = subdiv_options['boundaries'] colsub = subdiv_options['boundaries'] if isinstance(subdiv_options['style'], (list, tuple)): rowstyle, colstyle = subdiv_options['style'] else: rowstyle = subdiv_options['style'] colstyle = subdiv_options['style'] if rowstyle is None: rowstyle = dict() if colstyle is None: colstyle = dict() # Make line objects for subdivisions from .line import line2d lim = self.get_minmax_data() # First draw horizontal lines representing row subdivisions for y in rowsub: l = line2d([(lim['xmin'], y - 0.5), (lim['xmax'], y - 0.5)], **rowstyle)[0] l._render_on_subplot(subplot) for x in colsub: l = line2d([(x - 0.5, lim['ymin']), (x - 0.5, lim['ymax'])], **colstyle)[0] l._render_on_subplot(subplot) if hasattr(self.xy_data_array, 'tocoo'): # Sparse matrix -- use spy opts = options.copy() for opt in [ 'vmin', 'vmax', 'norm', 'origin', 'subdivisions', 'subdivision_options', 'colorbar', 'colorbar_options' ]: del opts[opt] if origin == 'lower': subplot.spy(self.xy_data_array.tocsr()[::-1], **opts) else: subplot.spy(self.xy_data_array, **opts) else: opts = dict(cmap=cmap, interpolation='nearest', aspect='equal', norm=norm, vmin=options['vmin'], vmax=options['vmax'], origin=origin, zorder=options.get('zorder', None)) image = subplot.imshow(self.xy_data_array, **opts) if options.get('colorbar', False): colorbar_options = options['colorbar_options'] from matplotlib import colorbar cax, kwds = colorbar.make_axes_gridspec( subplot, **colorbar_options) cb = colorbar.Colorbar(cax, image, **kwds) if origin == 'upper': subplot.xaxis.tick_top() elif origin == 'lower': subplot.xaxis.tick_bottom() subplot.xaxis.set_ticks_position( 'both') #only tick marks, not tick labels
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) Graphics object consisting of 1 graphics primitive More complicated examples with tilted axes and drawing options:: sage: ellipse((0,0),3,1,pi/6,fill=True,alpha=0.3,linestyle="dashed") Graphics object consisting of 1 graphics primitive sage: ellipse((0,0),3,1,pi/6,fill=True,alpha=0.3,linestyle="--") Graphics object consisting of 1 graphics primitive :: sage: ellipse((0,0),3,1,pi/6,fill=True,edgecolor='black',facecolor='red') Graphics object consisting of 1 graphics primitive 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') Graphics object consisting of 1 graphics primitive 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') Graphics object consisting of 1 graphics primitive """ 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 _render_on_subplot(self, subplot): """ TESTS: A somewhat random plot, but fun to look at:: sage: x,y = var('x,y') sage: contour_plot(x^2-y^3+10*sin(x*y), (x, -4, 4), (y, -4, 4),plot_points=121,cmap='hsv') """ from sage.rings.integer import Integer options = self.options() fill = options['fill'] contours = options['contours'] if options.has_key('cmap'): cmap = get_cmap(options['cmap']) elif fill or contours is None: cmap = get_cmap('gray') else: if isinstance(contours, (int, Integer)): cmap = get_cmap([(i,i,i) for i in xsrange(0,1,1/contours)]) else: l = Integer(len(contours)) cmap = get_cmap([(i,i,i) for i in xsrange(0,1,1/l)]) x0,x1 = float(self.xrange[0]), float(self.xrange[1]) y0,y1 = float(self.yrange[0]), float(self.yrange[1]) if isinstance(contours, (int, Integer)): contours = int(contours) CSF=None if fill: if contours is None: CSF=subplot.contourf(self.xy_data_array, cmap=cmap, extent=(x0,x1,y0,y1), label=options['legend_label']) else: CSF=subplot.contourf(self.xy_data_array, contours, cmap=cmap, extent=(x0,x1,y0,y1),extend='both', label=options['legend_label']) linewidths = options.get('linewidths',None) if isinstance(linewidths, (int, Integer)): linewidths = int(linewidths) elif isinstance(linewidths, (list, tuple)): linewidths = tuple(int(x) for x in linewidths) linestyles = options.get('linestyles',None) if contours is None: CS = subplot.contour(self.xy_data_array, cmap=cmap, extent=(x0,x1,y0,y1), linewidths=linewidths, linestyles=linestyles, label=options['legend_label']) else: CS = subplot.contour(self.xy_data_array, contours, cmap=cmap, extent=(x0,x1,y0,y1), linewidths=linewidths, linestyles=linestyles, label=options['legend_label']) if options.get('labels', False): label_options = options['label_options'] label_options['fontsize'] = int(label_options['fontsize']) if fill and label_options is None: label_options['inline']=False subplot.clabel(CS, **label_options) if options.get('colorbar', False): colorbar_options = options['colorbar_options'] from matplotlib import colorbar cax,kwds=colorbar.make_axes_gridspec(subplot,**colorbar_options) if CSF is None: cb=colorbar.Colorbar(cax,CS, **kwds) else: cb=colorbar.Colorbar(cax,CSF, **kwds) cb.add_lines(CS)
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 :trac:`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 _render_on_subplot(self, subplot): """ TESTS: A somewhat random plot, but fun to look at:: sage: x,y = var('x,y') sage: contour_plot(x^2-y^3+10*sin(x*y), (x, -4, 4), (y, -4, 4),plot_points=121,cmap='hsv') Graphics object consisting of 1 graphics primitive """ from sage.rings.integer import Integer options = self.options() fill = options['fill'] contours = options['contours'] if 'cmap' in options: cmap = get_cmap(options['cmap']) elif fill or contours is None: cmap = get_cmap('gray') else: if isinstance(contours, (int, Integer)): cmap = get_cmap([(i, i, i) for i in xsrange(0, 1, 1 / contours)]) else: l = Integer(len(contours)) cmap = get_cmap([(i, i, i) for i in xsrange(0, 1, 1 / l)]) x0, x1 = float(self.xrange[0]), float(self.xrange[1]) y0, y1 = float(self.yrange[0]), float(self.yrange[1]) if isinstance(contours, (int, Integer)): contours = int(contours) CSF = None if fill: if contours is None: CSF = subplot.contourf(self.xy_data_array, cmap=cmap, extent=(x0, x1, y0, y1), label=options['legend_label']) else: CSF = subplot.contourf(self.xy_data_array, contours, cmap=cmap, extent=(x0, x1, y0, y1), extend='both', label=options['legend_label']) linewidths = options.get('linewidths', None) if isinstance(linewidths, (int, Integer)): linewidths = int(linewidths) elif isinstance(linewidths, (list, tuple)): linewidths = tuple(int(x) for x in linewidths) from sage.plot.misc import get_matplotlib_linestyle linestyles = options.get('linestyles', None) if isinstance(linestyles, (list, tuple)): linestyles = [ get_matplotlib_linestyle(l, 'long') for l in linestyles ] else: linestyles = get_matplotlib_linestyle(linestyles, 'long') if contours is None: CS = subplot.contour(self.xy_data_array, cmap=cmap, extent=(x0, x1, y0, y1), linewidths=linewidths, linestyles=linestyles, label=options['legend_label']) else: CS = subplot.contour(self.xy_data_array, contours, cmap=cmap, extent=(x0, x1, y0, y1), linewidths=linewidths, linestyles=linestyles, label=options['legend_label']) if options.get('labels', False): label_options = options['label_options'] label_options['fontsize'] = int(label_options['fontsize']) if fill and label_options is None: label_options['inline'] = False subplot.clabel(CS, **label_options) if options.get('colorbar', False): colorbar_options = options['colorbar_options'] from matplotlib import colorbar cax, kwds = colorbar.make_axes_gridspec(subplot, **colorbar_options) if CSF is None: cb = colorbar.Colorbar(cax, CS, **kwds) else: cb = colorbar.Colorbar(cax, CSF, **kwds) cb.add_lines(CS)
def _render_on_subplot(self, subplot): r""" Render this arrow in a subplot. This is the key function that defines how this arrow graphics primitive is rendered in matplotlib's library. EXAMPLES: This function implicitly ends up rendering this arrow on a matplotlib subplot:: sage: arrow((0,1), (2,-1)) Graphics object consisting of 1 graphics primitive TESTS: The length of the ends (shrinkA and shrinkB) should not depend on the width of the arrow, because Matplotlib already takes this into account. See :trac:`12836`:: sage: fig = Graphics().matplotlib() sage: sp = fig.add_subplot(1,1,1, label='axis1') sage: a = arrow((0,0), (1,1)) sage: b = arrow((0,0), (1,1), width=20) sage: p1 = a[0]._render_on_subplot(sp) sage: p2 = b[0]._render_on_subplot(sp) sage: p1.shrinkA == p2.shrinkA True sage: p1.shrinkB == p2.shrinkB True Dashed arrows should have solid arrowheads, :trac:`12852`. This test saves the plot of a dashed arrow to an EPS file. Within the EPS file, ``stroke`` will be called twice: once to draw the line, and again to draw the arrowhead. We check that both calls do not occur while the dashed line style is enabled:: sage: a = arrow((0,0), (1,1), linestyle='dashed') sage: filename = tmp_filename(ext='.eps') sage: a.save(filename=filename) sage: with open(filename, 'r') as f: ....: contents = f.read().replace('\n', ' ') sage: two_stroke_pattern = r'setdash.*stroke.*stroke.*setdash.*setdash' sage: import re sage: two_stroke_re = re.compile(two_stroke_pattern) sage: two_stroke_re.search(contents) is None True """ from sage.plot.misc import get_matplotlib_linestyle options = self.options() head = options.pop('head') if head == 0: style = '<|-' elif head == 1: style = '-|>' elif head == 2: style = '<|-|>' else: raise KeyError( 'head parameter must be one of 0 (start), 1 (end) or 2 (both).' ) width = float(options['width']) arrowshorten_end = float(options.get('arrowshorten', 0)) / 2.0 arrowsize = float(options.get('arrowsize', 5)) head_width = arrowsize head_length = arrowsize * 2.0 color = to_mpl_color(options['rgbcolor']) from matplotlib.patches import FancyArrowPatch p = FancyArrowPatch( (self.xtail, self.ytail), (self.xhead, self.yhead), lw=width, arrowstyle='%s,head_width=%s,head_length=%s' % (style, head_width, head_length), shrinkA=arrowshorten_end, shrinkB=arrowshorten_end, fc=color, ec=color, linestyle=get_matplotlib_linestyle(options['linestyle'], return_type='long')) p.set_zorder(options['zorder']) p.set_label(options['legend_label']) if options['linestyle'] != 'solid': # The next few lines work around a design issue in matplotlib. # Currently, the specified linestyle is used to draw both the path # and the arrowhead. If linestyle is 'dashed', this looks really # odd. This code is from Jae-Joon Lee in response to a post to the # matplotlib mailing list. # See http://sourceforge.net/mailarchive/forum.php?thread_name=CAG%3DuJ%2Bnw2dE05P9TOXTz_zp-mGP3cY801vMH7yt6vgP9_WzU8w%40mail.gmail.com&forum_name=matplotlib-users import matplotlib.patheffects as pe class CheckNthSubPath(object): def __init__(self, patch, n): """ creates an callable object that returns True if the provided path is the n-th path from the patch. """ self._patch = patch self._n = n def get_paths(self, renderer): self._patch.set_dpi_cor(renderer.points_to_pixels(1.)) paths, fillables = self._patch.get_path_in_displaycoord() return paths def __call__(self, renderer, gc, tpath, affine, rgbFace): path = self.get_paths(renderer)[self._n] vert1, code1 = path.vertices, path.codes import numpy as np return np.array_equal(vert1, tpath.vertices) and np.array_equal( code1, tpath.codes) class ConditionalStroke(pe.RendererBase): def __init__(self, condition_func, pe_list): """ path effect that is only applied when the condition_func returns True. """ super(ConditionalStroke, self).__init__() self._pe_list = pe_list self._condition_func = condition_func def draw_path(self, renderer, gc, tpath, affine, rgbFace): if self._condition_func(renderer, gc, tpath, affine, rgbFace): for pe1 in self._pe_list: pe1.draw_path(renderer, gc, tpath, affine, rgbFace) pe1 = ConditionalStroke(CheckNthSubPath(p, 0), [pe.Stroke()]) pe2 = ConditionalStroke( CheckNthSubPath(p, 1), [pe.Stroke(dashes={ 'dash_offset': 0, 'dash_list': None })]) p.set_path_effects([pe1, pe2]) subplot.add_patch(p) return p
def get_minmax_data(self): """ Get minimum and maximum horizontal and vertical ranges for the Histogram object. EXAMPLES:: sage: H = histogram([10,3,5], density=True); h = H[0] sage: h.get_minmax_data() # rel tol 1e-15 {'xmax': 10.0, 'xmin': 3.0, 'ymax': 0.4761904761904765, 'ymin': 0} sage: G = histogram([random() for _ in range(500)]); g = G[0] sage: g.get_minmax_data() # random output {'xmax': 0.99729312925213209, 'xmin': 0.00013024562219410285, 'ymax': 61, 'ymin': 0} sage: Y = histogram([random()*10 for _ in range(500)], range=[2,8]); y = Y[0] sage: ymm = y.get_minmax_data(); ymm['xmax'], ymm['xmin'] (8.0, 2.0) sage: Z = histogram([[1,3,2,0], [4,4,3,3]]); z = Z[0] sage: z.get_minmax_data() {'xmax': 4.0, 'xmin': 0, 'ymax': 2, 'ymin': 0} TESTS:: sage: h = histogram([10,3,5], normed=True)[0] doctest:warning...: DeprecationWarning: the 'normed' option is deprecated. Use 'density' instead. See https://trac.sagemath.org/25260 for details. sage: h.get_minmax_data() doctest:warning ... ...VisibleDeprecationWarning: Passing `normed=True` on non-uniform bins has always been broken, and computes neither the probability density function nor the probability mass function. The result is only correct if the bins are uniform, when density=True will produce the same result anyway. The argument will be removed in a future version of numpy. {'xmax': 10.0, 'xmin': 3.0, 'ymax': 0.476190476190..., 'ymin': 0} """ import numpy # Extract these options (if they are not None) and pass them to # histogram() options = self.options() opt = {} for key in ('range', 'bins', 'normed', 'density', 'weights'): try: value = options[key] except KeyError: pass else: if value is not None: opt[key] = value #check to see if a list of datasets if not hasattr(self.datalist[0], '__contains__'): ydata, xdata = numpy.histogram(self.datalist, **opt) return minmax_data(xdata,[0]+list(ydata), dict=True) else: m = { 'xmax': 0, 'xmin':0, 'ymax':0, 'ymin':0} if not options.get('stacked'): for d in self.datalist: ydata, xdata = numpy.histogram(d, **opt) m['xmax'] = max([m['xmax']] + list(xdata)) m['xmin'] = min([m['xmin']] + list(xdata)) m['ymax'] = max([m['ymax']] + list(ydata)) return m else: for d in self.datalist: ydata, xdata = numpy.histogram(d, **opt) m['xmax'] = max([m['xmax']] + list(xdata)) m['xmin'] = min([m['xmin']] + list(xdata)) m['ymax'] = m['ymax'] + max(list(ydata)) return m
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 _render_on_subplot(self, subplot): """ TESTS:: sage: matrix_plot(random_matrix(RDF, 50), cmap='jet') """ options = self.options() cmap = get_cmap(options.pop("cmap", None)) origin = options["origin"] norm = options["norm"] if norm == "value": import matplotlib norm = matplotlib.colors.NoNorm() if options["subdivisions"]: subdiv_options = options["subdivision_options"] if isinstance(subdiv_options["boundaries"], (list, tuple)): rowsub, colsub = subdiv_options["boundaries"] else: rowsub = subdiv_options["boundaries"] colsub = subdiv_options["boundaries"] if isinstance(subdiv_options["style"], (list, tuple)): rowstyle, colstyle = subdiv_options["style"] else: rowstyle = subdiv_options["style"] colstyle = subdiv_options["style"] if rowstyle is None: rowstyle = dict() if colstyle is None: colstyle = dict() # Make line objects for subdivisions from line import line2d lim = self.get_minmax_data() # First draw horizontal lines representing row subdivisions for y in rowsub: l = line2d([(lim["xmin"], y - 0.5), (lim["xmax"], y - 0.5)], **rowstyle)[0] l._render_on_subplot(subplot) for x in colsub: l = line2d([(x - 0.5, lim["ymin"]), (x - 0.5, lim["ymax"])], **colstyle)[0] l._render_on_subplot(subplot) if hasattr(self.xy_data_array, "tocoo"): # Sparse matrix -- use spy opts = options.copy() for opt in [ "vmin", "vmax", "norm", "origin", "subdivisions", "subdivision_options", "colorbar", "colorbar_options", ]: del opts[opt] if origin == "lower": subplot.spy(self.xy_data_array.tocsr()[::-1], **opts) else: subplot.spy(self.xy_data_array, **opts) else: opts = dict( cmap=cmap, interpolation="nearest", aspect="equal", norm=norm, vmin=options["vmin"], vmax=options["vmax"], origin=origin, zorder=options.get("zorder", None), ) image = subplot.imshow(self.xy_data_array, **opts) if options.get("colorbar", False): colorbar_options = options["colorbar_options"] from matplotlib import colorbar cax, kwds = colorbar.make_axes_gridspec(subplot, **colorbar_options) cb = colorbar.Colorbar(cax, image, **kwds) if origin == "upper": subplot.xaxis.tick_top() elif origin == "lower": subplot.xaxis.tick_bottom() subplot.xaxis.set_ticks_position("both") # only tick marks, not tick labels
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 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