Ticket #2100: trac_2100-aspect-ratio-rebase.patch

File trac_2100-aspect-ratio-rebase.patch, 35.8 KB (added by kcrisman, 9 years ago)

Rebase to 4.6.1/4.6.2.alpha0

  • sage/plot/arrow.py

    # HG changeset patch
    # User Karl-Dieter Crisman <kcrisman@gmail.com>
    # Date 1295294743 18000
    # Node ID 72fb76799653d22f1e471d865fb58fed54d18e7f
    # Parent  5eb5ed73e74d11bc4a55416d0fb080319a421dff
    Trac #2100 - Revamp the aspect ratio parts of 2d plotting (rebase)
    
    This patch exposes the following behavior:
    
        * Figure aspect ratio -- controls the final image size, including any text labels, etc. This will be set using the following options:
              o figsize
                    + single number - use this as a base size for the width of the figure canvas
                    + two numbers - an actual figure size in inches
                    + None - use the default size in Matplotlib
              o fit_tight
                    + if True, clip or extend the resulting figure to the plot objects (so the resulting figure will probably not have figsize dimensions
                    + if False, the resulting figure has exactly figsize dimensions, but items in the plot may be clipped or there may be excessive padding around drawn objects
        * Pixel aspect ratio
              o aspect_ratio -- the ratio height/width for a unit square
                    + 'equal' or 1 -- a unit square appears to have equal height and width.  This will be the default for Graphics objects (so if a default is not explicitly set, the default is this.)
                    + 'auto' -- plot the given data limits in the given (or computed) figsize, filling the figure (default for plot and list_plot)
                    + number -- ratio of height to width.
    
    diff -r 5eb5ed73e74d -r 72fb76799653 sage/plot/arrow.py
    a b  
    397397
    398398    A pretty circle of arrows::
    399399
    400         sage: sum([arrow2d((0,0), (cos(x),sin(x)), hue=x/(2*pi)) for x in [0..2*pi,step=0.1]]).show(aspect_ratio=1)
     400        sage: sum([arrow2d((0,0), (cos(x),sin(x)), hue=x/(2*pi)) for x in [0..2*pi,step=0.1]])
    401401
    402402    If we want to draw the arrow between objects, for example, the
    403403    boundaries of two lines, we can use the arrowshorten option
  • sage/plot/bar_chart.py

    diff -r 5eb5ed73e74d -r 72fb76799653 sage/plot/bar_chart.py
    a b  
    119119        subplot.bar(ind, datalist, color=color, width=width, label=options['legend_label'])
    120120
    121121@rename_keyword(color='rgbcolor')
    122 @options(width=0.5, rgbcolor=(0,0,1), legend_label=None)
     122@options(width=0.5, rgbcolor=(0,0,1), legend_label=None, aspect_ratio='auto')
    123123def bar_chart(datalist, **options):
    124124    """
    125125    A bar chart of (currently) one list of numerical data.
  • sage/plot/circle.py

    diff -r 5eb5ed73e74d -r 72fb76799653 sage/plot/circle.py
    a b  
    283283
    284284    And a circle with a legend::
    285285
    286         sage: circle((4,5), 1, rgbcolor='yellow', fill=True, legend_label='the sun').show(xmin=0, ymin=0, aspect_ratio=1)
     286        sage: circle((4,5), 1, rgbcolor='yellow', fill=True, legend_label='the sun').show(xmin=0, ymin=0)
    287287
    288288    Extra options will get passed on to show(), as long as they are valid::
    289289
  • sage/plot/contour_plot.py

    diff -r 5eb5ed73e74d -r 72fb76799653 sage/plot/contour_plot.py
    a b  
    345345
    346346    ::
    347347
    348         sage: contour_plot(f, (-2, 2), (-2, 2), contours=(1.0,), fill=False, aspect_ratio=1)
     348        sage: contour_plot(f, (-2, 2), (-2, 2), contours=(1.0,), fill=False)
    349349
    350350    ::
    351351
     
    441441    This should plot concentric circles centered at the origin::
    442442
    443443        sage: x,y = var('x,y')
    444         sage: contour_plot(x^2+y^2-2,(x,-1,1), (y,-1,1)).show(aspect_ratio=1)
     444        sage: contour_plot(x^2+y^2-2,(x,-1,1), (y,-1,1))
    445445
    446446    Extra options will get passed on to show(), as long as they are valid::
    447447
     
    526526
    527527        sage: var("x y")
    528528        (x, y)
    529         sage: implicit_plot(x^2+y^2-2, (x,-3,3), (y,-3,3)).show(aspect_ratio=1)
     529        sage: implicit_plot(x^2+y^2-2, (x,-3,3), (y,-3,3))
    530530
    531531    I can do the same thing, but using a callable function so I don't need
    532532    to explicitly define the variables in the ranges, and filling the inside::
    533533
    534534        sage: x,y = var('x,y')
    535535        sage: f(x,y) = x^2 + y^2 - 2
    536         sage: implicit_plot(f, (-3, 3), (-3, 3),fill=True).show(aspect_ratio=1)
     536        sage: implicit_plot(f, (-3, 3), (-3, 3),fill=True)
    537537
    538538    The same circle but with a different line width::
    539539
    540         sage: implicit_plot(f, (-3,3), (-3,3), linewidth=6).show(aspect_ratio=1)
     540        sage: implicit_plot(f, (-3,3), (-3,3), linewidth=6)
    541541
    542542    And again the same circle but this time with a dashdot border::
    543543
    544         sage: implicit_plot(f, (-3,3), (-3,3), linestyle='dashdot').show(aspect_ratio=1)
     544        sage: implicit_plot(f, (-3,3), (-3,3), linestyle='dashdot')
    545545
    546546    You can also plot an equation::
    547547
    548548        sage: var("x y")
    549549        (x, y)
    550         sage: implicit_plot(x^2+y^2 == 2, (x,-3,3), (y,-3,3)).show(aspect_ratio=1)
     550        sage: implicit_plot(x^2+y^2 == 2, (x,-3,3), (y,-3,3))
    551551       
    552552    You can even change the color of the plot::
    553553   
    554         sage: implicit_plot(x^2+y^2 == 2, (x,-3,3), (y,-3,3), color="red").show(aspect_ratio=1)
     554        sage: implicit_plot(x^2+y^2 == 2, (x,-3,3), (y,-3,3), color="red")
    555555
    556556    Here is a beautiful (and long) example which also tests that all
    557557    colors work with this::
     
    561561        sage: for col in colors.keys(): # long time
    562562        ...       G += implicit_plot(x^2+y^2==1+counter*.1, (x,-4,4),(y,-4,4),color=col)
    563563        ...       counter += 1
    564         sage: G.show(aspect_ratio=1,frame=False)
     564        sage: G.show(frame=False)
    565565
    566566    We can define a level-`n` approximation of the boundary of the
    567567    Mandelbrot set::
     
    578578
    579579    The first-level approximation is just a circle::
    580580
    581         sage: implicit_plot(mandel(1), (-3, 3), (-3, 3)).show(aspect_ratio=1)
     581        sage: implicit_plot(mandel(1), (-3, 3), (-3, 3))
    582582       
    583583    A third-level approximation starts to get interesting::
    584584
    585         sage: implicit_plot(mandel(3), (-2, 1), (-1.5, 1.5)).show(aspect_ratio=1)
     585        sage: implicit_plot(mandel(3), (-2, 1), (-1.5, 1.5))
    586586
    587587    The seventh-level approximation is a degree 64 polynomial, and
    588588    ``implicit_plot`` does a pretty good job on this part of the curve.
     
    590590
    591591    ::
    592592
    593         sage: implicit_plot(mandel(7), (-0.3, 0.05), (-1.15, -0.9),plot_points=50).show(aspect_ratio=1)
     593        sage: implicit_plot(mandel(7), (-0.3, 0.05), (-1.15, -0.9),plot_points=50)
    594594    """
    595595    from sage.symbolic.expression import is_SymbolicEquation
    596596    if is_SymbolicEquation(f):
     
    663663
    664664    A disk centered at the origin::
    665665
    666         sage: region_plot(x^2+y^2<1, (x,-1,1), (y,-1,1), aspect_ratio=1)
     666        sage: region_plot(x^2+y^2<1, (x,-1,1), (y,-1,1))
    667667
    668668    A plot with more than one condition (all conditions must be true for the statement to be true)::
    669669
    670         sage: region_plot([x^2+y^2<1, x<y], (x,-2,2), (y,-2,2), aspect_ratio=1)
     670        sage: region_plot([x^2+y^2<1, x<y], (x,-2,2), (y,-2,2))
    671671
    672672    Since it doesn't look very good, let's increase plot_points::
    673673
    674         sage: region_plot([x^2+y^2<1, x<y], (x,-2,2), (y,-2,2), plot_points=400, aspect_ratio=1)
     674        sage: region_plot([x^2+y^2<1, x<y], (x,-2,2), (y,-2,2), plot_points=400)
    675675
    676676    To get plots where only one condition needs to be true, use a function::
    677677
    678         sage: region_plot(lambda x,y: x^2+y^2<1 or x<y, (x,-2,2), (y,-2,2), aspect_ratio=1)
     678        sage: region_plot(lambda x,y: x^2+y^2<1 or x<y, (x,-2,2), (y,-2,2))
    679679   
    680680    The first quadrant of the unit circle::
    681681
    682         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, aspect_ratio=1)
     682        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)
    683683
    684684    Here is another plot, with a huge border::
    685685
     
    691691
    692692    Here we have a cut circle::
    693693
    694         sage: region_plot([x^2+y^2<4, x>-1], (x, -2, 2), (y, -2, 2), incol='lightblue', bordercol='gray', plot_points=200, aspect_ratio=1)
     694        sage: region_plot([x^2+y^2<4, x>-1], (x, -2, 2), (y, -2, 2), incol='lightblue', bordercol='gray', plot_points=200)
    695695
    696696    The first variable range corresponds to the horizontal axis and
    697697    the second variable range corresponds to the vertical axis::
  • sage/plot/disk.py

    diff -r 5eb5ed73e74d -r 72fb76799653 sage/plot/disk.py
    a b  
    239239        sage: tl = disk((0.0,0.0), 1, (pi/2, pi), color='black')
    240240        sage: br = disk((0.0,0.0), 1, (3*pi/2, 2*pi), color='black')
    241241        sage: P  = tl+tr+bl+br
    242         sage: P.show(aspect_ratio=1,xmin=-2,xmax=2,ymin=-2,ymax=2)
     242        sage: P.show(xmin=-2,xmax=2,ymin=-2,ymax=2)
    243243
    244     To correct the aspect ratio of certain graphics, it is necessary
    245     to show with a ``aspect_ratio`` of one::
     244    ::
    246245
    247         sage: bl = disk((0.0,0.0), 1, (pi, 3*pi/2), color='yellow')
    248         sage: bl.show(aspect_ratio=1)
     246        sage: disk((0.0,0.0), 1, (pi, 3*pi/2), color='yellow')
    249247
    250     You can also achieve the same aspect ratio by specifying a ``figsize``
    251     with square dimensions::
     248    ::
    252249
    253250        sage: bl = disk((0.0,0.0), 1, (pi, 3*pi/2), rgbcolor=(1,1,0))
    254251        sage: bl.show(figsize=[5,5])
  • sage/plot/plot.py

    diff -r 5eb5ed73e74d -r 72fb76799653 sage/plot/plot.py
    a b  
    7575
    7676Type ``?`` after each primitive in Sage for help and examples.
    7777
    78 EXAMPLES: We construct a plot involving several graphics objects::
    79 
    80     sage: G = plot(cos, -5, 5, thickness=5, color='green')
    81     sage: P = polygon([[1,2], [5,6], [5,0]], color='red')
    82     sage: G + P  # show it
     78EXAMPLES:
    8379
    8480We draw a circle and a curve::
    8581
     
    9288
    9389    sage: show(circle((1,1), 1) + plot(x^2, (x,0,5)), aspect_ratio=1)
    9490
    95 With an aspect ratio of 2 the circle is squashed half way down (it
    96 looks twice as wide as it does tall)::
     91The aspect ratio describes the apparently height/width ratio of a unit square.  If you want the vertical units to be twice as big as the horizontal units, specify an aspect ratio of 2::
    9792
    9893    sage: show(circle((1,1), 1) + plot(x^2, (x,0,5)), aspect_ratio=2)
    9994
    100 Use figsize to set the actual aspect ratio of the rendered image
    101 (i.e., of the frame). For example, this image is twice as many
    102 pixels wide as it is tall::
    103 
    104     sage: show(circle((1,1), 1) + plot(x^2, (x,0,5)), figsize=[8,4])
     95The ``figsize`` option adjusts the figure size.  The default figsize is 4.  To make a figure that is roughly twice as big, use ``figsize=8``::
     96
     97    sage: show(circle((1,1), 1) + plot(x^2, (x,0,5)), figsize=8)
     98
     99You can also give separate horizontal and vertical dimensions::
     100
     101    sage: show(circle((1,1), 1) + plot(x^2, (x,0,5)), figsize=[4,8])
    105102
    106103Note that the axes will not cross if the data is not on both sides of
    107104both axes, even if it is quite close::
     
    112109large, scientific notation (the `e` notation for powers of ten) is used::
    113110
    114111    sage: plot(x^2,(x,480,500))  # no scientific notation
     112
     113::
     114
    115115    sage: plot(x^2,(x,300,500))  # scientific notation on y-axis
    116116
    117 But you can fix your own labels, if you know what to expect and
     117But you can fix your own tick labels, if you know what to expect and
    118118have a preference::
    119119
    120120    sage: plot(x^2,(x,300,500),ticks=[None,50000])
    121121
     122We construct a plot involving several graphics objects::
     123
     124    sage: G = plot(cos(x), (x, -5, 5), thickness=5, color='green')
     125    sage: P = polygon([[1,2], [5,6], [5,0]], color='red')
     126    sage: G + P
     127
    122128Next we construct the reflection of the above polygon about the
    123129`y`-axis by iterating over the list of first-coordinates of
    124130the first graphic element of `P` (which is the actual
     
    298304- Jason Grout (2009-09-05): shifted axes and grid functionality over
    299305  to matplotlib; fixed a number of smaller issues.
    300306
     307- Jason Grout (2010-10): rewrote aspect ratio portions of the code
     308
    301309"""
    302310
    303311############################################################################
     
    316324## going to be used.
    317325
    318326ALLOWED_EXTENSIONS = ['.eps', '.pdf', '.png', '.ps', '.sobj', '.svg']
    319 DEFAULT_FIGSIZE=(6, 3.70820393249937)
     327#DEFAULT_FIGSIZE=(6, 3.70820393249937)
    320328DEFAULT_DPI = 100
    321329EMBEDDED_MODE = False
    322330DOCTEST_MODE = False
     
    415423   
    416424        sage: G = Graphics(); print G
    417425        Graphics object consisting of 0 graphics primitives
    418         sage: c = circle((1,1), 1,aspect_ratio=1)
     426        sage: c = circle((1,1), 1)
    419427        sage: G+=c; print G
    420428        Graphics object consisting of 1 graphics primitive
    421429   
     
    446454       
    447455            sage: G = Graphics()
    448456        """
    449         self.__aspect_ratio = None
     457        self.__aspect_ratio = 1.0
    450458        self.__fontsize = 10
    451459        self.__show_axes = True
    452460        self.__show_legend = False
     
    460468
    461469    def set_aspect_ratio(self, ratio):
    462470        """
    463         Set the aspect ratio.
     471        Set the aspect ratio, which is the ratio of height and width
     472        of a unit square (i.e., height/width of a unit square), or
     473        'auto' (expand to fill the figure).
    464474       
    465475        INPUT:
    466476       
    467477       
    468         -  ``ratio`` - a positive real number
     478        -  ``ratio`` - a positive real number or 'auto'
    469479       
    470480       
    471481        EXAMPLES: We create a plot of a circle, and it doesn't look quite
     
    485495            sage: P + circle((0,0), 0.5)           # still square
    486496       
    487497        In the following example, both plots produce a circle that looks
    488         twice as wide as tall::
     498        twice as tall as wide::
    489499       
    490500            sage: Q = circle((0,0), 0.5); Q.set_aspect_ratio(2)
    491501            sage: P + Q
    492502            sage: Q + P
    493503        """
    494         ratio = float(ratio)
    495         if ratio <= 0:
    496             raise ValueError, "the aspect ratio must be positive"
     504        if ratio != 'auto':
     505            ratio = float(ratio)
     506            if ratio <= 0:
     507                raise ValueError, "the aspect ratio must be positive or 'auto'"
    497508        self.__aspect_ratio = ratio
    498509
    499510    def aspect_ratio(self):
    500511        """
    501         Get the current aspect ratio.
    502        
    503         OUTPUT: either None if the aspect ratio hasn't been set or a
    504         positive float
     512        Get the current aspect ratio, which is the ratio of height to
     513        width of a unit square, or 'auto'.
     514       
     515        OUTPUT: a positive float (height/width of a unit square), or 'auto'
     516        (expand to fill the figure).
    505517       
    506518        EXAMPLES::
    507519       
    508520            sage: P = circle((1,1), 1)
    509             sage: P.aspect_ratio() is None
    510             True
     521            sage: P.aspect_ratio()
     522            1.0
    511523            sage: P.set_aspect_ratio(2)
    512524            sage: P.aspect_ratio()
    513525            2.0
     526            sage: P.set_aspect_ratio('auto')
     527            sage: P.aspect_ratio()
     528            'auto'
    514529        """
    515530        return self.__aspect_ratio
    516531
     
    12361251        The xmin, xmax, ymin, and ymax properties of the graphics objects
    12371252        are expanded to include all objects in both scenes. If the aspect
    12381253        ratio property of either or both objects are set, then the larger
    1239         aspect ratio is chosen.
     1254        aspect ratio is chosen, with 'auto' being overridden by a
     1255        numeric aspect ratio.
    12401256
    12411257        If one of the graphics object is set to show a legend, then the
    12421258        resulting object will also be set to show a legend.  None of the
     
    12481264            sage: g2 = plot(-abs(sqrt(x^3-1)), (x,1,5), color='red')
    12491265            sage: g1 + g2  # displays the plot
    12501266
    1251         TESTS::
    1252 
    1253             sage: (g1 + g2)._extra_kwds # extra keywords to show are propagated
    1254             {'frame': True}
     1267        TESTS:
     1268
     1269        Extra keywords to show are propagated::
     1270
     1271            sage: (g1 + g2)._extra_kwds=={'aspect_ratio': 'auto', 'frame': True}
     1272            True
    12551273        """
    12561274        if isinstance(other, int) and other == 0:
    12571275            return self
     
    12621280            raise TypeError, "other (=%s) must be a Graphics objects"%other
    12631281        g = Graphics()
    12641282        g.__objects = self.__objects + other.__objects
    1265         g.__aspect_ratio = max(self.__aspect_ratio, other.__aspect_ratio)
     1283        if self.__aspect_ratio=='auto':
     1284            g.__aspect_ratio=other.__aspect_ratio
     1285        elif other.__aspect_ratio=='auto':
     1286            g.__aspect_ratio=self.__aspect_ratio
     1287        else:
     1288            g.__aspect_ratio = max(self.__aspect_ratio, other.__aspect_ratio)
    12661289        g.__show_legend = self.__show_legend or other.__show_legend
    12671290        g._extra_kwds.update(self._extra_kwds)
    12681291        g._extra_kwds.update(other._extra_kwds)
     
    13581381    # this dictionary to contain the default value for that parameter.
    13591382
    13601383    SHOW_OPTIONS = dict(xmin=None, xmax=None, ymin=None, ymax=None,
    1361                         figsize=DEFAULT_FIGSIZE, filename=None,
     1384                        figsize=None, fig_tight=True,
     1385                        filename=None,
    13621386                        dpi=DEFAULT_DPI, axes=None, axes_labels=None,frame=False,
    1363                         fontsize=None, aspect_ratio=None,
     1387                        fontsize=None,
     1388                        aspect_ratio=None,
    13641389                        gridlines=None, gridlinesstyle=None,
    13651390                        vgridlinesstyle=None, hgridlinesstyle=None,transparent=False,
    13661391                        show_legend=None, legend_options={},
     
    13841409
    13851410        - ``figsize`` - [width, height]
    13861411
    1387         - ``aspect_ratio`` - the perceived width divided by the
    1388           perceived height.  If the aspect ratio is set to 1, circles
    1389           will look round.  If it is set to 2 they will look twice as
    1390           wide as they are tall.  This is the aspect_ratio of the
    1391           image, not of the frame that contains it.  If you want to set
    1392           the aspect ratio of the frame, use figsize.
     1412        - ``fig_tight`` - (default: True) whether to clip the drawing
     1413          tightly around drawn objects.  If True, then the resulting
     1414          image will usually not have dimensions corresponding to
     1415          ``figsize``.  If False, the resulting image will have
     1416          dimensions corresponding to ``figsize``.
     1417
     1418        - ``aspect_ratio`` - the perceived height divided by the
     1419          perceived width. If the aspect ratio is set to ``1``, circles
     1420          will look round and a unit square will appear to have sides
     1421          of equal length. If the aspect ratio is set ``2``, vertical units will be
     1422          twice as long as horizontal units, so a unit square will be twice as
     1423          high as it is wide.  If set to ``'auto'``, the aspect ratio
     1424          is determined by ``figsize`` and the picture fills the figure.
    13931425
    13941426        - ``axes`` - (default: True)
    13951427       
     
    15111543            sage: c = circle((1,1), 1, color='red')
    15121544            sage: c.show(xmin=-1, xmax=3, ymin=-1, ymax=3)
    15131545       
    1514         To correct the aspect ratio of certain graphics, you can
    1515         set the ``aspect_ratio`` to 1
    1516        
    1517         ::
    1518        
    1519             sage: c.show(aspect_ratio=1, xmin=-1, xmax=3, ymin=-1, ymax=3)
    1520 
    1521         You could also just make the dimensions of the picture square
    1522         using ``figsize``
    1523 
    1524         ::
    1525 
    1526             sage: c.show(figsize=[5,5], xmin=-1, xmax=3, ymin=-1, ymax=3)       
     1546        You could also just make the picture larger by changing ``figsize``::
     1547
     1548            sage: c.show(figsize=8, xmin=-1, xmax=3, ymin=-1, ymax=3)       
    15271549       
    15281550        You can turn off the drawing of the axes::
    15291551       
     
    18561878                   xmin=None, xmax=None, ymin=None, ymax=None,
    18571879                   figsize=None, figure=None, sub=None,
    18581880                   axes=None, axes_labels=None, fontsize=None,
    1859                    frame=False, verify=True, aspect_ratio = None,
     1881                   frame=False, verify=True,
     1882                   aspect_ratio = None,
    18601883                   gridlines=None, gridlinesstyle=None,
    18611884                   vgridlinesstyle=None, hgridlinesstyle=None,
    18621885                   show_legend=None, legend_options={},
     
    18691892       
    18701893            sage: c = circle((1,1),1)
    18711894            sage: print c.matplotlib()
    1872             Figure(480x296.656)
     1895            Figure(640x480)
    18731896
    18741897        To obtain the first matplotlib axes object inside of the
    18751898        figure, you can do something like the following.
     
    19271950        if axes is None:
    19281951            axes = self.__show_axes
    19291952
    1930         from matplotlib.figure import Figure, figaspect
     1953        from matplotlib.figure import Figure
     1954        from matplotlib import rcParams
    19311955        self.fontsize(fontsize)
    19321956        self.axes_labels(l=axes_labels)
    19331957
    1934         # adjust the figsize in case the user also specifies an aspect ratio
    1935         if aspect_ratio is None:
    1936             aspect_ratio = self.aspect_ratio()
    1937 
    1938         # We try to accommodate both a demand for aspect ratio and
    1939         # for a figure size by adjusting the figure size to have
    1940         # the right aspect ratio.
    1941         if figsize is None:
    1942             figsize=DEFAULT_FIGSIZE
    1943         figsize=adjust_figsize_for_aspect_ratio(figsize, aspect_ratio,
    1944                                                 xmin=xmin, xmax=xmax,
    1945                                                 ymin=ymin, ymax=ymax)
     1958        if figsize is not None and not isinstance(figsize, (list, tuple)):
     1959            default_width, default_height=rcParams['figure.figsize']
     1960            figsize=(figsize, default_height*figsize/default_width)
    19461961
    19471962        if figure is None:
    1948             figure=Figure(figsize)
     1963            figure=Figure(figsize=figsize)
    19491964       
    19501965        #the incoming subplot instance
    19511966        subplot = sub
    19521967        if not subplot:
    19531968            subplot = figure.add_subplot(111)
    1954             if aspect_ratio is not None:
    1955                 subplot.set_aspect('auto')
    1956 
     1969        if aspect_ratio is None:
     1970            aspect_ratio=self.aspect_ratio()
     1971        subplot.set_aspect(aspect_ratio, adjustable='box')
    19571972        #add all the primitives to the subplot
    19581973        for g in self.__objects:
    19591974            g._render_on_subplot(subplot)
     
    22832298                if vgridlines not in (None, False):
    22842299                    subplot.xaxis.grid(True, **vgridstyle)
    22852300
    2286         if aspect_ratio is not None:
    2287             subplot.set_aspect(aspect_ratio)
    22882301
    22892302
    22902303        if self.__axes_labels is not None:
     
    23382351                labeltrans=offset_copy(trans, figure, x=0, y=yaxis_labeloffset, units='points')
    23392352                subplot.yaxis.set_label_coords(x=yaxis_labelx,y=yaxis_labely,transform=labeltrans)
    23402353
     2354        # This option makes the xlim and ylim limits not take effect
     2355        # todo: figure out which limits were specified, and let the
     2356        # free limits autoscale
    23412357        #subplot.autoscale_view(tight=True)
    23422358        return figure
    23432359       
     
    23852401            sage: filename = os.path.join(SAGE_TMP, 'test.png')
    23862402            sage: c.save(filename, xmin=-1, xmax=3, ymin=-1, ymax=3)
    23872403
    2388         To correct the aspect ratio of certain graphics, you can set the
    2389         ``aspect_ratio`` to 1::
    2390        
    2391             sage: c.save(filename, aspect_ratio=1,
    2392             ...          xmin=-1, xmax=3, ymin=-1, ymax=3)
    2393 
    2394         You could also just make the dimensions of the picture square using
    2395         ``figsize``::
    2396 
    2397             sage: c.save(filename, figsize=[5, 5],
    2398             ...          xmin=-1, xmax=3, ymin=-1, ymax=3)       
     2404        To make a figure bigger or smaller, use ``figsize``::
     2405
     2406            sage: c.save(filename, figsize=5, xmin=-1, xmax=3, ymin=-1, ymax=3)       
    23992407
    24002408        By default, the figure grows to include all of the graphics and text,
    24012409        so the final image may not be exactly the figure size you specified.
     2410        If you want a figure to be exactly a certain size, specify the keyword
     2411        ``fig_tight=False``::
     2412
     2413            sage: c.save(filename, figsize=[8,4], fig_tight=False,
     2414            ...       xmin=-1, xmax=3, ymin=-1, ymax=3)       
    24022415       
    24032416        You can also pass extra options to the plot command instead of this
    24042417        method, e.g. ::
     
    24282441        options.update(kwds)
    24292442        dpi = options.pop('dpi')
    24302443        transparent = options.pop('transparent')
     2444        fig_tight = options.pop('fig_tight')
    24312445       
    24322446        if filename is None:
    24332447            filename = options.pop('filename')
     
    24492463            # if the file extension is not '.png', then matplotlib will handle it.
    24502464            from matplotlib.backends.backend_agg import FigureCanvasAgg
    24512465            figure.set_canvas(FigureCanvasAgg(figure))
    2452             figure.savefig(filename, dpi=dpi, bbox_inches='tight',
     2466            # this messes up the aspect ratio!
     2467            #figure.canvas.mpl_connect('draw_event', pad_for_tick_labels)
     2468            if fig_tight is True:
     2469                figure.savefig(filename, dpi=dpi, bbox_inches='tight',
    24532470                           transparent=transparent)
    2454 
     2471            else:
     2472                figure.savefig(filename, dpi=dpi,
     2473                           transparent=transparent)
     2474
     2475#Currently not used - see comment immediately above about
     2476#figure.canvas.mpl_connect('draw_event', pad_for_tick_labels)
     2477# TODO - figure out how to use this, add documentation
     2478#def pad_for_tick_labels(event):
     2479#    import matplotlib.transforms as mtransforms
     2480#    figure=event.canvas.figure
     2481#    bboxes = []
     2482#    for ax in figure.axes:
     2483#        bbox = ax.xaxis.get_label().get_window_extent()
     2484#        # the figure transform goes from relative coords->pixels and we
     2485#        # want the inverse of that
     2486#        bboxi = bbox.inverse_transformed(figure.transFigure)
     2487#        bboxes.append(bboxi)
     2488#
     2489#        bbox = ax.yaxis.get_label().get_window_extent()
     2490#        bboxi = bbox.inverse_transformed(figure.transFigure)
     2491#        bboxes.append(bboxi)
     2492#        for label in (ax.get_xticklabels()+ax.get_yticklabels() \
     2493#                          + ax.get_xticklabels(minor=True) \
     2494#                          +ax.get_yticklabels(minor=True)):
     2495#            bbox = label.get_window_extent()
     2496#            bboxi = bbox.inverse_transformed(figure.transFigure)
     2497#            bboxes.append(bboxi)
     2498#   
     2499#    # this is the bbox that bounds all the bboxes, again in relative
     2500#    # figure coords
     2501#    bbox = mtransforms.Bbox.union(bboxes)
     2502#    adjusted=adjust_figure_to_contain_bbox(figure,bbox)
     2503#   
     2504#    if adjusted:
     2505#        figure.canvas.draw()
     2506#    return False
     2507#
     2508#Currently not used - see comment above about
     2509#figure.canvas.mpl_connect('draw_event', pad_for_tick_labels)
     2510# TODO - figure out how to use this, add documentation
     2511#def adjust_figure_to_contain_bbox(fig, bbox,pad=1.1):
     2512#    """
     2513#    For each amount we are over (in axes coordinates), we adjust by over*pad
     2514#    to give ourselves a bit of padding.
     2515#    """
     2516#    left=fig.subplotpars.left
     2517#    bottom=fig.subplotpars.bottom
     2518#    right=fig.subplotpars.right
     2519#    top=fig.subplotpars.top
     2520#
     2521#    adjusted=False
     2522#    if bbox.xmin<0:
     2523#        left-=bbox.xmin*pad
     2524#        adjusted=True
     2525#    if bbox.ymin<0:
     2526#        bottom-=bbox.ymin*pad
     2527#        adjusted=True
     2528#    if bbox.xmax>1:
     2529#        right-=(bbox.xmax-1)*pad
     2530#        adjusted=True
     2531#    if bbox.ymax>1:
     2532#        top-=(bbox.ymax-1)*pad
     2533#        adjusted=True
     2534#
     2535#    if left<right and bottom<top:   
     2536#        fig.subplots_adjust(left=left, bottom=bottom, right=right, top=top)
     2537#        return adjusted
     2538#    else:
     2539#        return False
    24552540
    24562541_SelectiveFormatterClass = None
    24572542
     
    25842669@rename_keyword(color='rgbcolor')
    25852670@options(alpha=1, thickness=1, fill=False, fillcolor='automatic', fillalpha=0.5, rgbcolor=(0,0,1), plot_points=200,
    25862671         adaptive_tolerance=0.01, adaptive_recursion=5, detect_poles = False, exclude = None, legend_label=None,
    2587          __original_opts=True)
     2672         __original_opts=True, aspect_ratio='auto')
    25882673def plot(funcs, *args, **kwds):
    25892674    r"""
    25902675    Use plot by writing
     
    32493334
    32503335########## misc functions ###################
    32513336
    3252 @options(aspect_ratio=1)
     3337@options(aspect_ratio=1.0)
    32533338def parametric_plot(funcs, *args, **kwargs):
    32543339    r"""
    32553340    Plot a parametric curve or surface in 2d or 3d.
     
    33603445    else:
    33613446        raise ValueError, "the number of functions and the number of variable ranges is not a supported combination for a 2d or 3d parametric plots"
    33623447
    3363 @options(aspect_ratio=1)
     3448@options(aspect_ratio=1.0)
    33643449def polar_plot(funcs, *args, **kwds):
    33653450    r"""
    33663451    ``polar_plot`` takes a single function or a list or
     
    34003485
    34013486    Fill the area between two functions::
    34023487   
    3403         sage: polar_plot(cos(4*x) + 1.5, 0, 2*pi, fill=0.5 * cos(4*x) + 2.5, fillcolor='orange').show(aspect_ratio=1)
     3488        sage: polar_plot(cos(4*x) + 1.5, 0, 2*pi, fill=0.5 * cos(4*x) + 2.5, fillcolor='orange')
    34043489
    34053490    Fill the area between several spirals::
    34063491   
     
    34083493
    34093494    Exclude points at discontinuities::
    34103495
    3411         sage: polar_plot(log(floor(x)), (x, 1, 4*pi), aspect_ratio = 1, exclude = [1..12])
     3496        sage: polar_plot(log(floor(x)), (x, 1, 4*pi), exclude = [1..12])
    34123497
    34133498    """
    34143499    kwds['polar']=True
    34153500    return plot(funcs, *args, **kwds)
    34163501
     3502@options(aspect_ratio='auto')
    34173503def list_plot(data, plotjoined=False, **kwargs):
    34183504    r"""
    34193505    ``list_plot`` takes either a single list of data, a list of tuples,
     
    35343620                if not isinstance(g, Graphics):
    35353621                    raise TypeError, "every element of array must be a Graphics object"
    35363622                self._glist.append(g)
    3537         self._figsize = DEFAULT_FIGSIZE
     3623        self._figsize = None
    35383624
    35393625    def _repr_(self):
    35403626        if SHOW_DEFAULT:
     
    35713657    def append(self, g):
    35723658        self._glist.append(g)
    35733659
    3574     def _render(self, filename, dpi=None, figsize=DEFAULT_FIGSIZE, axes=None, **args):
     3660    def _render(self, filename, dpi=None, figsize=None, axes=None, **args):
    35753661        r"""
    35763662        ``render`` loops over all graphics objects in the array
    35773663        and adds them to the subplot.
     
    35933679        g.save(filename, dpi=dpi, figure=figure, sub=subplot,
    35943680               verify=do_verify, axes = axes, **args)
    35953681
    3596     def save(self, filename=None, dpi=DEFAULT_DPI, figsize=DEFAULT_FIGSIZE,
     3682    def save(self, filename=None, dpi=DEFAULT_DPI, figsize=None,
    35973683             axes = None, **args):
    35983684        """
    35993685        save the ``graphics_array`` to (for now) a png called
    36003686        'filename'.
    36013687        """
    3602         if (figsize != DEFAULT_FIGSIZE): self.__set_figsize__(figsize)
     3688        if (figsize is not None): self.__set_figsize__(figsize)
    36033689        self._render(filename, dpi=dpi, figsize=self._figsize, axes = axes, **args)
    36043690
    3605     def show(self, filename=None, dpi=DEFAULT_DPI, figsize=DEFAULT_FIGSIZE,
     3691    def show(self, filename=None, dpi=DEFAULT_DPI, figsize=None,
    36063692             axes = None, **args):
    36073693        r"""
    36083694        Show this graphics array using the default viewer.
     
    36143700       
    36153701        -  ``dpi`` - dots per inch
    36163702       
    3617         -  ``figsize`` - [width, height] (same for square
    3618            aspect)
     3703        -  ``figsize`` - width or [width, height]
    36193704       
    36203705        -  ``axes`` - (default: True)
    36213706       
     
    36333718            sage: G = graphics_array([[plot(sin), plot(cos)], [plot(tan), plot(sec)]])
    36343719            sage: G.show(axes=False)
    36353720        """
    3636         if (figsize != DEFAULT_FIGSIZE): self.__set_figsize__(figsize)
     3721        if (figsize is not None): self.__set_figsize__(figsize)
    36373722        if DOCTEST_MODE:
    36383723            self.save(DOCTEST_MODE_FILE,
    36393724                      dpi=dpi, figsize=self._figsize, axes = axes, **args)
     
    37823867        return var, values
    37833868
    37843869
    3785 def adjust_figsize_for_aspect_ratio(figsize, aspect_ratio, xmin, xmax, ymin, ymax):
    3786     """
    3787     Adjust the figsize in case the user also specifies an aspect
    3788     ratio.
    3789    
    3790     INPUTS: figsize - a sequence of two positive real numbers
    3791     aspect_ratio - a positive real number xmin, xmax, ymin, ymax -
    3792     real numbers
    3793    
    3794     EXAMPLES: This function is used mainly internally by plotting code
    3795     so we explicitly import it::
    3796    
    3797         sage: from sage.plot.plot import adjust_figsize_for_aspect_ratio
    3798    
    3799     This returns (5,5), since the requested aspect ratio is 1 and the x
    3800     and y ranges are the same, so that's the right size rendered image
    3801     to produce a 1:1 ratio internally. 5 is used instead of 3 since the
    3802     image size is always adjusted to the larger of the figsize
    3803     dimensions.
    3804    
    3805     ::
    3806    
    3807         sage: adjust_figsize_for_aspect_ratio([3,5], 1, 0, 2, 0, 2)
    3808         (5, 5)
    3809    
    3810     Here we give a scalar figsize, which is automatically converted to
    3811     the figsize ``(figsize, figsize/golden_ratio)``.
    3812    
    3813     ::
    3814    
    3815         sage: adjust_figsize_for_aspect_ratio(3, 1, 0, 2, 0, 2)
    3816         (3, 3)
    3817    
    3818     Here we omit the aspect ratio so the figsize is just returned.
    3819    
    3820     ::
    3821    
    3822         sage: adjust_figsize_for_aspect_ratio([5,6], None, 0, 2, 0, 2)
    3823         [5, 6]
    3824    
    3825     Here we have an aspect ratio of 2, and since the x and y ranges are
    3826     the same the returned figsize is twice as wide as tall::
    3827    
    3828         sage: adjust_figsize_for_aspect_ratio([3,5], 2, 0, 2, 0, 2)
    3829         (5, 5/2)
    3830    
    3831     Here the x range is rather large, so to get an aspect ratio where
    3832     circles look twice as wide as they are tall, we have to shrink the
    3833     y size of the image.
    3834    
    3835     ::
    3836    
    3837         sage: adjust_figsize_for_aspect_ratio([3,5], 2, 0, 10, 0, 2)
    3838         (5, 1/2)
    3839     """
    3840     if not isinstance(figsize, (list, tuple)):
    3841         figsize = [figsize, figsize * 0.618033988749895]   # 1/golden_ratio
    3842     if aspect_ratio is None:
    3843         return figsize
    3844     # We find a number r such that (ymax-ymin)*r / (xmax-xmin) = aspect_ratio:
    3845     r = max(aspect_ratio * (xmax - xmin)/(ymax-ymin), 0.001)
    3846     mx = max(figsize)
    3847     f = (figsize[0]*r, figsize[0])
    3848     s = min((mx/f[0], mx/f[1]))
    3849     return f[0]*s, f[1]*s
    3850 
    3851 
    38523870
    38533871def setup_for_eval_on_grid(v, xrange, yrange, plot_points):
    38543872    """
  • sage/plot/plot_field.py

    diff -r 5eb5ed73e74d -r 72fb76799653 sage/plot/plot_field.py
    a b  
    159159        sage: x,y = var('x,y')
    160160        sage: a=plot_vector_field((x,y), (x,-3,3),(y,-3,3),color='blue')
    161161        sage: b=plot_vector_field((y,-x),(x,-3,3),(y,-3,3),color='red')
    162         sage: show(a+b,aspect_ratio=1)
     162        sage: show(a+b)
    163163
    164164    We ignore function values that are infinite or NaN::
    165165
     
    213213        sage: x,y = var('x y')
    214214        sage: capacity = 3 # thousand
    215215        sage: growth_rate = 0.7 # population increases by 70% per unit of time
    216         sage: plot_slope_field(growth_rate*(1-y/capacity)*y, (x,0,5), (y,0,capacity*2)).show(aspect_ratio=1)
     216        sage: plot_slope_field(growth_rate*(1-y/capacity)*y, (x,0,5), (y,0,capacity*2))
    217217
    218218    Plot a slope field involving sin and cos::
    219219
    220220        sage: x,y = var('x y')
    221         sage: plot_slope_field(sin(x+y)+cos(x+y), (x,-3,3), (y,-3,3)).show(aspect_ratio=1)
     221        sage: plot_slope_field(sin(x+y)+cos(x+y), (x,-3,3), (y,-3,3))
    222222    """
    223223    slope_options = {'headaxislength': 0, 'headlength': 0, 'pivot': 'middle'}
    224224    slope_options.update(kwds)
  • sage/plot/scatter_plot.py

    diff -r 5eb5ed73e74d -r 72fb76799653 sage/plot/scatter_plot.py
    a b  
    128128        options = self.options()
    129129        subplot.scatter(self.xdata, self.ydata, alpha=options['alpha'], zorder=options['zorder'], marker=options['marker'],s=options['markersize'],facecolors=options['facecolor'], edgecolors=options['edgecolor'])
    130130
    131 @options(alpha=1, markersize=50, marker='o', zorder=5, facecolor='#fec7b8', edgecolor='black')
     131@options(alpha=1, markersize=50, marker='o', zorder=5, facecolor='#fec7b8', edgecolor='black', aspect_ratio='auto')
    132132def scatter_plot(datalist, **options):
    133133    """
    134134    Returns a Graphics object of a scatter plot containing all points in