Ticket #2100: 2100-aspect_ratio.2.patch

File 2100-aspect_ratio.2.patch, 35.7 KB (added by jason, 9 years ago)

apply instead of previous patch

  • sage/plot/arrow.py

    # HG changeset patch
    # User Jason Grout <jason-sage@creativetrax.com>
    # Date 1286435222 18000
    # Node ID cf1b0507fcd00dc8792be29ee77f58552f785e90
    # Parent  da9376d80113ab1b14bfcc906ee901bb09eb0ef6
    2100: Revamp the aspect ratio parts of 2d plotting.
    
    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 da9376d80113 -r cf1b0507fcd0 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 da9376d80113 -r cf1b0507fcd0 sage/plot/bar_chart.py
    a b  
    107107        subplot.bar(ind, datalist, color=color, width=width, label=options['legend_label'])
    108108
    109109@rename_keyword(color='rgbcolor')
    110 @options(width=0.5, rgbcolor=(0,0,1), legend_label=None)
     110@options(width=0.5, rgbcolor=(0,0,1), legend_label=None, aspect_ratio='auto')
    111111def bar_chart(datalist, **options):
    112112    """
    113113    A bar chart of (currently) one list of numerical data.
  • sage/plot/circle.py

    diff -r da9376d80113 -r cf1b0507fcd0 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 da9376d80113 -r cf1b0507fcd0 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
     
    523523
    524524        sage: var("x y")
    525525        (x, y)
    526         sage: implicit_plot(x^2+y^2-2, (x,-3,3), (y,-3,3)).show(aspect_ratio=1)
     526        sage: implicit_plot(x^2+y^2-2, (x,-3,3), (y,-3,3))
    527527
    528528    I can do the same thing, but using a callable function so I don't need
    529529    to explicitly define the variables in the ranges, and filling the inside::
    530530
    531531        sage: x,y = var('x,y')
    532532        sage: f(x,y) = x^2 + y^2 - 2
    533         sage: implicit_plot(f, (-3, 3), (-3, 3),fill=True).show(aspect_ratio=1)
     533        sage: implicit_plot(f, (-3, 3), (-3, 3),fill=True)
    534534
    535535    The same circle but with a different line width::
    536536
    537         sage: implicit_plot(f, (-3,3), (-3,3), linewidth=6).show(aspect_ratio=1)
     537        sage: implicit_plot(f, (-3,3), (-3,3), linewidth=6)
    538538
    539539    And again the same circle but this time with a dashdot border::
    540540
    541         sage: implicit_plot(f, (-3,3), (-3,3), linestyle='dashdot').show(aspect_ratio=1)
     541        sage: implicit_plot(f, (-3,3), (-3,3), linestyle='dashdot')
    542542
    543543    You can also plot an equation::
    544544
    545545        sage: var("x y")
    546546        (x, y)
    547         sage: implicit_plot(x^2+y^2 == 2, (x,-3,3), (y,-3,3)).show(aspect_ratio=1)
     547        sage: implicit_plot(x^2+y^2 == 2, (x,-3,3), (y,-3,3))
    548548
    549549    We can define a level-`n` approximation of the boundary of the
    550550    Mandelbrot set::
     
    561561
    562562    The first-level approximation is just a circle::
    563563
    564         sage: implicit_plot(mandel(1), (-3, 3), (-3, 3)).show(aspect_ratio=1)
     564        sage: implicit_plot(mandel(1), (-3, 3), (-3, 3))
    565565       
    566566    A third-level approximation starts to get interesting::
    567567
    568         sage: implicit_plot(mandel(3), (-2, 1), (-1.5, 1.5)).show(aspect_ratio=1)
     568        sage: implicit_plot(mandel(3), (-2, 1), (-1.5, 1.5))
    569569
    570570    The seventh-level approximation is a degree 64 polynomial, and
    571571    ``implicit_plot`` does a pretty good job on this part of the curve.
     
    573573
    574574    ::
    575575
    576         sage: implicit_plot(mandel(7), (-0.3, 0.05), (-1.15, -0.9),plot_points=50).show(aspect_ratio=1)
     576        sage: implicit_plot(mandel(7), (-0.3, 0.05), (-1.15, -0.9),plot_points=50)
    577577    """
    578578    from sage.symbolic.expression import is_SymbolicEquation
    579579    if is_SymbolicEquation(f):
     
    642642
    643643    A disk centered at the origin::
    644644
    645         sage: region_plot(x^2+y^2<1, (x,-1,1), (y,-1,1), aspect_ratio=1)
     645        sage: region_plot(x^2+y^2<1, (x,-1,1), (y,-1,1))
    646646
    647647    A plot with more than one condition (all conditions must be true for the statement to be true)::
    648648
    649         sage: region_plot([x^2+y^2<1, x<y], (x,-2,2), (y,-2,2), aspect_ratio=1)
     649        sage: region_plot([x^2+y^2<1, x<y], (x,-2,2), (y,-2,2))
    650650
    651651    Since it doesn't look very good, let's increase plot_points::
    652652
    653         sage: region_plot([x^2+y^2<1, x<y], (x,-2,2), (y,-2,2), plot_points=400, aspect_ratio=1)
     653        sage: region_plot([x^2+y^2<1, x<y], (x,-2,2), (y,-2,2), plot_points=400)
    654654
    655655    To get plots where only one condition needs to be true, use a function::
    656656
    657         sage: region_plot(lambda x,y: x^2+y^2<1 or x<y, (x,-2,2), (y,-2,2), aspect_ratio=1)
     657        sage: region_plot(lambda x,y: x^2+y^2<1 or x<y, (x,-2,2), (y,-2,2))
    658658   
    659659    The first quadrant of the unit circle::
    660660
    661         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)
     661        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)
    662662
    663663    Here is another plot, with a huge border::
    664664
     
    670670
    671671    Here we have a cut circle::
    672672
    673         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)
     673        sage: region_plot([x^2+y^2<4, x>-1], (x, -2, 2), (y, -2, 2), incol='lightblue', bordercol='gray', plot_points=200)
    674674
    675675    The first variable range corresponds to the horizontal axis and
    676676    the second variable range corresponds to the vertical axis::
  • sage/plot/disk.py

    diff -r da9376d80113 -r cf1b0507fcd0 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 da9376d80113 -r cf1b0507fcd0 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############################################################################
     
    315323## imported in functions, so it only gets started if it is actually
    316324## going to be used.
    317325
    318 DEFAULT_FIGSIZE=(6, 3.70820393249937)
     326#DEFAULT_FIGSIZE=(6, 3.70820393249937)
    319327DEFAULT_DPI = 100
    320328EMBEDDED_MODE = False
    321329DOCTEST_MODE = False
     
    414422   
    415423        sage: G = Graphics(); print G
    416424        Graphics object consisting of 0 graphics primitives
    417         sage: c = circle((1,1), 1,aspect_ratio=1)
     425        sage: c = circle((1,1), 1)
    418426        sage: G+=c; print G
    419427        Graphics object consisting of 1 graphics primitive
    420428   
     
    445453       
    446454            sage: G = Graphics()
    447455        """
    448         self.__aspect_ratio = None
     456        self.__aspect_ratio = 1.0
    449457        self.__fontsize = 10
    450458        self.__show_axes = True
    451459        self.__show_legend = False
     
    459467
    460468    def set_aspect_ratio(self, ratio):
    461469        """
    462         Set the aspect ratio.
     470        Set the aspect ratio, which is the ratio of height and width
     471        of a unit square (i.e., height/width of a unit square), or
     472        'auto' (expand to fill the figure).
    463473       
    464474        INPUT:
    465475       
    466476       
    467         -  ``ratio`` - a positive real number
     477        -  ``ratio`` - a positive real number or 'auto'
    468478       
    469479       
    470480        EXAMPLES: We create a plot of a circle, and it doesn't look quite
     
    484494            sage: P + circle((0,0), 0.5)           # still square
    485495       
    486496        In the following example, both plots produce a circle that looks
    487         twice as wide as tall::
     497        twice as tall as wide::
    488498       
    489499            sage: Q = circle((0,0), 0.5); Q.set_aspect_ratio(2)
    490500            sage: P + Q
    491501            sage: Q + P
    492502        """
    493         ratio = float(ratio)
    494         if ratio <= 0:
    495             raise ValueError, "the aspect ratio must be positive"
     503        if ratio != 'auto':
     504            ratio = float(ratio)
     505            if ratio <= 0:
     506                raise ValueError, "the aspect ratio must be positive or 'auto'"
    496507        self.__aspect_ratio = ratio
    497508
    498509    def aspect_ratio(self):
    499510        """
    500         Get the current aspect ratio.
    501        
    502         OUTPUT: either None if the aspect ratio hasn't been set or a
    503         positive float
     511        Get the current aspect ratio, which is the ratio of height to
     512        width of a unit square, or 'auto'.
     513       
     514        OUTPUT: a positive float (height/width of a unit square), or 'auto'
     515        (expand to fill the figure).
    504516       
    505517        EXAMPLES::
    506518       
    507519            sage: P = circle((1,1), 1)
    508             sage: P.aspect_ratio() is None
    509             True
     520            sage: P.aspect_ratio()
     521            1.0
    510522            sage: P.set_aspect_ratio(2)
    511523            sage: P.aspect_ratio()
    512524            2.0
     525            sage: P.set_aspect_ratio('auto')
     526            sage: P.aspect_ratio()
     527            'auto'
    513528        """
    514529        return self.__aspect_ratio
    515530
     
    12351250        The xmin, xmax, ymin, and ymax properties of the graphics objects
    12361251        are expanded to include all objects in both scenes. If the aspect
    12371252        ratio property of either or both objects are set, then the larger
    1238         aspect ratio is chosen.
     1253        aspect ratio is chosen, with 'auto' being overridden by a
     1254        numeric aspect ratio.
    12391255
    12401256        If one of the graphics object is set to show a legend, then the
    12411257        resulting object will also be set to show a legend.  None of the
     
    12471263            sage: g2 = plot(-abs(sqrt(x^3-1)), (x,1,5), color='red')
    12481264            sage: g1 + g2  # displays the plot
    12491265
    1250         TESTS::
    1251 
    1252             sage: (g1 + g2)._extra_kwds # extra keywords to show are propagated
    1253             {'frame': True}
     1266        TESTS:
     1267
     1268        Extra keywords to show are propagated::
     1269
     1270            sage: (g1 + g2)._extra_kwds=={'aspect_ratio': 'auto', 'frame': True}
     1271            True
    12541272        """
    12551273        if isinstance(other, int) and other == 0:
    12561274            return self
     
    12611279            raise TypeError, "other (=%s) must be a Graphics objects"%other
    12621280        g = Graphics()
    12631281        g.__objects = self.__objects + other.__objects
    1264         g.__aspect_ratio = max(self.__aspect_ratio, other.__aspect_ratio)
     1282        if self.__aspect_ratio=='auto':
     1283            g.__aspect_ratio=other.__aspect_ratio
     1284        elif other.__aspect_ratio=='auto':
     1285            g.__aspect_ratio=self.__aspect_ratio
     1286        else:
     1287            g.__aspect_ratio = max(self.__aspect_ratio, other.__aspect_ratio)
    12651288        g.__show_legend = self.__show_legend or other.__show_legend
    12661289        g._extra_kwds.update(self._extra_kwds)
    12671290        g._extra_kwds.update(other._extra_kwds)
     
    13571380    # this dictionary to contain the default value for that parameter.
    13581381
    13591382    SHOW_OPTIONS = dict(xmin=None, xmax=None, ymin=None, ymax=None,
    1360                         figsize=DEFAULT_FIGSIZE, filename=None,
     1383                        figsize=None, fig_tight=True,
     1384                        filename=None,
    13611385                        dpi=DEFAULT_DPI, axes=None, axes_labels=None,frame=False,
    1362                         fontsize=None, aspect_ratio=None,
     1386                        fontsize=None,
     1387                        aspect_ratio=None,
    13631388                        gridlines=None, gridlinesstyle=None,
    13641389                        vgridlinesstyle=None, hgridlinesstyle=None,transparent=False,
    13651390                        show_legend=None, legend_options={},
     
    13831408
    13841409        - ``figsize`` - [width, height]
    13851410
    1386         - ``aspect_ratio`` - the perceived width divided by the
    1387           perceived height.  If the aspect ratio is set to 1, circles
    1388           will look round.  If it is set to 2 they will look twice as
    1389           wide as they are tall.  This is the aspect_ratio of the
    1390           image, not of the frame that contains it.  If you want to set
    1391           the aspect ratio of the frame, use figsize.
     1411        - ``fig_tight`` - (default: True) whether to clip the drawing
     1412          tightly around drawn objects.  If True, then the resulting
     1413          image will usually not have dimensions corresponding to
     1414          ``figsize``.  If False, the resulting image will have
     1415          dimensions corresponding to ``figsize``.
     1416
     1417        - ``aspect_ratio`` - the perceived height divided by the
     1418          perceived width. If the aspect ratio is set to ``1``, circles
     1419          will look round and a unit square will appear to have sides
     1420          of equal length. If the aspect ratio is set ``2``, vertical units will be
     1421          twice as long as horizontal units, so a unit square will be twice as
     1422          high as it is wide.  If set to ``'auto'``, the aspect ratio
     1423          is determined by ``figsize`` and the picture fills the figure.
    13921424
    13931425        - ``axes`` - (default: True)
    13941426       
     
    15101542            sage: c = circle((1,1), 1, color='red')
    15111543            sage: c.show(xmin=-1, xmax=3, ymin=-1, ymax=3)
    15121544       
    1513         To correct the aspect ratio of certain graphics, you can
    1514         set the ``aspect_ratio`` to 1
    1515        
    1516         ::
    1517        
    1518             sage: c.show(aspect_ratio=1, xmin=-1, xmax=3, ymin=-1, ymax=3)
    1519 
    1520         You could also just make the dimensions of the picture square
    1521         using ``figsize``
    1522 
    1523         ::
    1524 
    1525             sage: c.show(figsize=[5,5], xmin=-1, xmax=3, ymin=-1, ymax=3)       
     1545        You could also just make the picture larger by changing ``figsize``::
     1546
     1547            sage: c.show(figsize=8, xmin=-1, xmax=3, ymin=-1, ymax=3)       
    15261548       
    15271549        You can turn off the drawing of the axes::
    15281550       
     
    18601882       
    18611883    def matplotlib(self, filename=None,
    18621884                   xmin=None, xmax=None, ymin=None, ymax=None,
    1863                    figsize=None, figure=None, sub=None,
     1885                   figsize=None, fig_tight=None,
     1886                   figure=None, sub=None,
    18641887                   axes=None, axes_labels=None, fontsize=None,
    1865                    frame=False, verify=True, aspect_ratio = None,
     1888                   frame=False, verify=True,
     1889                   aspect_ratio = None,
    18661890                   gridlines=None, gridlinesstyle=None,
    18671891                   vgridlinesstyle=None, hgridlinesstyle=None,
    18681892                   show_legend=None, legend_options={},
     
    18751899       
    18761900            sage: c = circle((1,1),1)
    18771901            sage: print c.matplotlib()
    1878             Figure(480x296.656)
     1902            Figure(640x480)
    18791903
    18801904        To obtain the first matplotlib axes object inside of the
    18811905        figure, you can do something like the following.
     
    19241948        if axes is None:
    19251949            axes = self.__show_axes
    19261950
    1927         from matplotlib.figure import Figure, figaspect
     1951        from matplotlib.figure import Figure
     1952        from matplotlib import rcParams
    19281953        self.fontsize(fontsize)
    19291954        self.axes_labels(l=axes_labels)
    19301955
    1931         # adjust the figsize in case the user also specifies an aspect ratio
    1932         if aspect_ratio is None:
    1933             aspect_ratio = self.aspect_ratio()
    1934 
    1935         # We try to accommodate both a demand for aspect ratio and
    1936         # for a figure size by adjusting the figure size to have
    1937         # the right aspect ratio.
    1938         if figsize is None:
    1939             figsize=DEFAULT_FIGSIZE
    1940         figsize=adjust_figsize_for_aspect_ratio(figsize, aspect_ratio,
    1941                                                 xmin=xmin, xmax=xmax,
    1942                                                 ymin=ymin, ymax=ymax)
     1956        if figsize is not None and not isinstance(figsize, (list, tuple)):
     1957            default_width, default_height=rcParams['figure.figsize']
     1958            figsize=(figsize, default_height*figsize/default_width)
    19431959
    19441960        if figure is None:
    1945             figure=Figure(figsize)
     1961            figure=Figure(figsize=figsize)
    19461962       
    19471963        #the incoming subplot instance
    19481964        subplot = sub
    19491965        if not subplot:
    19501966            subplot = figure.add_subplot(111)
    1951             if aspect_ratio is not None:
    1952                 subplot.set_aspect('auto')
    1953 
     1967        if aspect_ratio is None:
     1968            aspect_ratio=self.aspect_ratio()
     1969        subplot.set_aspect(aspect_ratio, adjustable='box')
    19541970        #add all the primitives to the subplot
    19551971        for g in self.__objects:
    19561972            g._render_on_subplot(subplot)
     
    22802296                if vgridlines not in (None, False):
    22812297                    subplot.xaxis.grid(True, **vgridstyle)
    22822298
    2283         if aspect_ratio is not None:
    2284             subplot.set_aspect(aspect_ratio)
    22852299
    22862300
    22872301        if self.__axes_labels is not None:
     
    23352349                labeltrans=offset_copy(trans, figure, x=0, y=yaxis_labeloffset, units='points')
    23362350                subplot.yaxis.set_label_coords(x=yaxis_labelx,y=yaxis_labely,transform=labeltrans)
    23372351
    2338         #subplot.autoscale_view(tight=True)
     2352        # This option makes the xlim and ylim limits not take effect
     2353        # todo: figure out which limits were specified, and let the
     2354        # free limits autoscale
     2355        #subplot.autoscale_view(tight=True)
    23392356        return figure
    23402357
    23412358    def save(self, filename=None, dpi=DEFAULT_DPI, savenow=True, *args, **kwds):
    23422359        r"""
    23432360        Save the graphics to an image file of type: PNG, PS, EPS, SVG,
    23442361        SOBJ, depending on the file extension you give the filename.
    2345         Extension types can be: ``.png``, ``.ps``,
    2346         ``.eps``, ``.svg``, and
    2347         ``.sobj`` (for a Sage object you can load later).
     2362        Extension types include be ``.png``, ``.pdf``, ``.ps``,
     2363        ``.eps``, ``.svg``, and ``.sobj`` (for a Sage object you can load later).
    23482364       
    23492365
    23502366        EXAMPLES::
     
    23532369            sage: filename=os.path.join(SAGE_TMP, 'test.png')
    23542370            sage: c.save(filename, xmin=-1,xmax=3,ymin=-1,ymax=3)
    23552371
    2356         To correct the aspect ratio of certain graphics, you can
    2357         set the ``aspect_ratio`` to 1::
    2358        
    2359             sage: c.save(filename, aspect_ratio=1, xmin=-1, xmax=3, ymin=-1, ymax=3)
    2360 
    2361         You could also just make the dimensions of the picture square
    2362         using ``figsize``::
    2363 
    2364             sage: c.save(filename, figsize=[5,5], xmin=-1, xmax=3, ymin=-1, ymax=3)       
    2365 
    2366         ::
    2367        
    2368             sage: point((-1,1),pointsize=30, color='red')
     2372        To make a figure bigger or smaller, use ``figsize``::
     2373
     2374            sage: c.save(filename, figsize=5, xmin=-1, xmax=3, ymin=-1, ymax=3)       
    23692375
    23702376        By default, the figure grows to include all of the graphics
    23712377        and text, so the final image may not be exactly the figure
    2372         size you specified.
     2378        size you specified. If you want a figure to be exactly a
     2379        certain size, specify ``fig_tight=False``::
     2380
     2381            sage: c.save(filename, figsize=[8,4], fig_tight=False, xmin=-1, xmax=3, ymin=-1, ymax=3)       
     2382
    23732383        """
    23742384        if filename is None:
    23752385            filename = sage.misc.misc.graphics_filename()
    23762386        try:
    23772387            ext = os.path.splitext(filename)[1].lower()
    23782388        except IndexError:
    2379             raise ValueError, "file extension must be either 'png', 'eps', 'svg' or 'sobj'"
     2389            raise ValueError, "file extension must be specified (e.g., .png, .pdf, .eps, .ps, .svg, .sobj, etc.)"
    23802390       
    23812391        if ext == '' or ext == '.sobj':
    23822392            SageObject.save(self, filename)
     
    23932403            # if the file extension is not '.png', then matplotlib will handle it.
    23942404            from matplotlib.backends.backend_agg import FigureCanvasAgg
    23952405            figure.set_canvas(FigureCanvasAgg(figure))
     2406            # this messes up the aspect ratio!
     2407            #figure.canvas.mpl_connect('draw_event', pad_for_tick_labels)
    23962408
    23972409            if ext in ['.eps', '.ps', '.pdf']:
    23982410                if dpi is None:
     
    24052417                    dpi = 100
    24062418            else:
    24072419                raise ValueError, "file extension must be either 'png', 'ps, 'eps', 'pdf, 'svg' or 'sobj'"
    2408             figure.savefig(filename,dpi=dpi,bbox_inches='tight',**options)
     2420            if kwds.get('fig_tight', True):
     2421                options['bbox_inches']='tight'
     2422            figure.savefig(filename,dpi=dpi,**options)
     2423
     2424
     2425def pad_for_tick_labels(event):
     2426    import matplotlib.transforms as mtransforms
     2427    figure=event.canvas.figure
     2428    bboxes = []
     2429    for ax in figure.axes:
     2430        bbox = ax.xaxis.get_label().get_window_extent()
     2431        # the figure transform goes from relative coords->pixels and we
     2432        # want the inverse of that
     2433        bboxi = bbox.inverse_transformed(figure.transFigure)
     2434        bboxes.append(bboxi)
     2435
     2436        bbox = ax.yaxis.get_label().get_window_extent()
     2437        bboxi = bbox.inverse_transformed(figure.transFigure)
     2438        bboxes.append(bboxi)
     2439        for label in (ax.get_xticklabels()+ax.get_yticklabels() \
     2440                          + ax.get_xticklabels(minor=True) \
     2441                          +ax.get_yticklabels(minor=True)):
     2442            bbox = label.get_window_extent()
     2443            bboxi = bbox.inverse_transformed(figure.transFigure)
     2444            bboxes.append(bboxi)
     2445   
     2446    # this is the bbox that bounds all the bboxes, again in relative
     2447    # figure coords
     2448    bbox = mtransforms.Bbox.union(bboxes)
     2449    adjusted=adjust_figure_to_contain_bbox(figure,bbox)
     2450   
     2451    if adjusted:
     2452        figure.canvas.draw()
     2453    return False
     2454
     2455def adjust_figure_to_contain_bbox(fig, bbox,pad=1.1):
     2456    """
     2457    For each amount we are over (in axes coordinates), we adjust by over*pad
     2458    to give ourselves a bit of padding.
     2459    """
     2460    left=fig.subplotpars.left
     2461    bottom=fig.subplotpars.bottom
     2462    right=fig.subplotpars.right
     2463    top=fig.subplotpars.top
     2464
     2465    adjusted=False
     2466    if bbox.xmin<0:
     2467        left-=bbox.xmin*pad
     2468        adjusted=True
     2469    if bbox.ymin<0:
     2470        bottom-=bbox.ymin*pad
     2471        adjusted=True
     2472    if bbox.xmax>1:
     2473        right-=(bbox.xmax-1)*pad
     2474        adjusted=True
     2475    if bbox.ymax>1:
     2476        top-=(bbox.ymax-1)*pad
     2477        adjusted=True
     2478
     2479    if left<right and bottom<top:   
     2480        fig.subplots_adjust(left=left, bottom=bottom, right=right, top=top)
     2481        return adjusted
     2482    else:
     2483        return False
    24092484
    24102485
    24112486_SelectiveFormatterClass = None
     
    25392614@rename_keyword(color='rgbcolor')
    25402615@options(alpha=1, thickness=1, fill=False, fillcolor='automatic', fillalpha=0.5, rgbcolor=(0,0,1), plot_points=200,
    25412616         adaptive_tolerance=0.01, adaptive_recursion=5, detect_poles = False, exclude = None, legend_label=None,
    2542          __original_opts=True)
     2617         __original_opts=True, aspect_ratio='auto')
    25432618def plot(funcs, *args, **kwds):
    25442619    r"""
    25452620    Use plot by writing
     
    32043279
    32053280########## misc functions ###################
    32063281
    3207 @options(aspect_ratio=1)
     3282@options(aspect_ratio=1.0)
    32083283def parametric_plot(funcs, *args, **kwargs):
    32093284    r"""
    32103285    Plot a parametric curve or surface in 2d or 3d.
     
    33153390    else:
    33163391        raise ValueError, "the number of functions and the number of variable ranges is not a supported combination for a 2d or 3d parametric plots"
    33173392
    3318 @options(aspect_ratio=1)
     3393@options(aspect_ratio=1.0)
    33193394def polar_plot(funcs, *args, **kwds):
    33203395    r"""
    33213396    ``polar_plot`` takes a single function or a list or
     
    33553430
    33563431    Fill the area between two functions::
    33573432   
    3358         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)
     3433        sage: polar_plot(cos(4*x) + 1.5, 0, 2*pi, fill=0.5 * cos(4*x) + 2.5, fillcolor='orange')
    33593434
    33603435    Fill the area between several spirals::
    33613436   
     
    33633438
    33643439    Exclude points at discontinuities::
    33653440
    3366         sage: polar_plot(log(floor(x)), (x, 1, 4*pi), aspect_ratio = 1, exclude = [1..12])
     3441        sage: polar_plot(log(floor(x)), (x, 1, 4*pi), exclude = [1..12])
    33673442
    33683443    """
    33693444    kwds['polar']=True
    33703445    return plot(funcs, *args, **kwds)
    33713446
     3447@options(aspect_ratio='auto')
    33723448def list_plot(data, plotjoined=False, **kwargs):
    33733449    r"""
    33743450    ``list_plot`` takes either a single list of data, a list of tuples,
     
    34893565                if not isinstance(g, Graphics):
    34903566                    raise TypeError, "every element of array must be a Graphics object"
    34913567                self._glist.append(g)
    3492         self._figsize = DEFAULT_FIGSIZE
     3568        self._figsize = None
    34933569
    34943570    def _repr_(self):
    34953571        if SHOW_DEFAULT:
     
    35263602    def append(self, g):
    35273603        self._glist.append(g)
    35283604
    3529     def _render(self, filename, dpi=None, figsize=DEFAULT_FIGSIZE, axes=None, **args):
     3605    def _render(self, filename, dpi=None, figsize=None, axes=None, **args):
    35303606        r"""
    35313607        ``render`` loops over all graphics objects in the array
    35323608        and adds them to the subplot.
     
    35483624        g.save(filename, dpi=dpi, figure=figure, sub=subplot,
    35493625               verify=do_verify, axes = axes, **args)
    35503626
    3551     def save(self, filename=None, dpi=DEFAULT_DPI, figsize=DEFAULT_FIGSIZE,
     3627    def save(self, filename=None, dpi=DEFAULT_DPI, figsize=None,
    35523628             axes = None, **args):
    35533629        """
    35543630        save the ``graphics_array`` to (for now) a png called
    35553631        'filename'.
    35563632        """
    3557         if (figsize != DEFAULT_FIGSIZE): self.__set_figsize__(figsize)
     3633        if (figsize is not None): self.__set_figsize__(figsize)
    35583634        self._render(filename, dpi=dpi, figsize=self._figsize, axes = axes, **args)
    35593635
    3560     def show(self, filename=None, dpi=DEFAULT_DPI, figsize=DEFAULT_FIGSIZE,
     3636    def show(self, filename=None, dpi=DEFAULT_DPI, figsize=None,
    35613637             axes = None, **args):
    35623638        r"""
    35633639        Show this graphics array using the default viewer.
     
    35693645       
    35703646        -  ``dpi`` - dots per inch
    35713647       
    3572         -  ``figsize`` - [width, height] (same for square
    3573            aspect)
     3648        -  ``figsize`` - width or [width, height]
    35743649       
    35753650        -  ``axes`` - (default: True)
    35763651       
     
    35883663            sage: G = graphics_array([[plot(sin), plot(cos)], [plot(tan), plot(sec)]])
    35893664            sage: G.show(axes=False)
    35903665        """
    3591         if (figsize != DEFAULT_FIGSIZE): self.__set_figsize__(figsize)
     3666        if (figsize is not None): self.__set_figsize__(figsize)
    35923667        if DOCTEST_MODE:
    35933668            self.save(DOCTEST_MODE_FILE,
    35943669                      dpi=dpi, figsize=self._figsize, axes = axes, **args)
     
    37373812        return var, values
    37383813
    37393814
    3740 def adjust_figsize_for_aspect_ratio(figsize, aspect_ratio, xmin, xmax, ymin, ymax):
    3741     """
    3742     Adjust the figsize in case the user also specifies an aspect
    3743     ratio.
    3744    
    3745     INPUTS: figsize - a sequence of two positive real numbers
    3746     aspect_ratio - a positive real number xmin, xmax, ymin, ymax -
    3747     real numbers
    3748    
    3749     EXAMPLES: This function is used mainly internally by plotting code
    3750     so we explicitly import it::
    3751    
    3752         sage: from sage.plot.plot import adjust_figsize_for_aspect_ratio
    3753    
    3754     This returns (5,5), since the requested aspect ratio is 1 and the x
    3755     and y ranges are the same, so that's the right size rendered image
    3756     to produce a 1:1 ratio internally. 5 is used instead of 3 since the
    3757     image size is always adjusted to the larger of the figsize
    3758     dimensions.
    3759    
    3760     ::
    3761    
    3762         sage: adjust_figsize_for_aspect_ratio([3,5], 1, 0, 2, 0, 2)
    3763         (5, 5)
    3764    
    3765     Here we give a scalar figsize, which is automatically converted to
    3766     the figsize ``(figsize, figsize/golden_ratio)``.
    3767    
    3768     ::
    3769    
    3770         sage: adjust_figsize_for_aspect_ratio(3, 1, 0, 2, 0, 2)
    3771         (3, 3)
    3772    
    3773     Here we omit the aspect ratio so the figsize is just returned.
    3774    
    3775     ::
    3776    
    3777         sage: adjust_figsize_for_aspect_ratio([5,6], None, 0, 2, 0, 2)
    3778         [5, 6]
    3779    
    3780     Here we have an aspect ratio of 2, and since the x and y ranges are
    3781     the same the returned figsize is twice as wide as tall::
    3782    
    3783         sage: adjust_figsize_for_aspect_ratio([3,5], 2, 0, 2, 0, 2)
    3784         (5, 5/2)
    3785    
    3786     Here the x range is rather large, so to get an aspect ratio where
    3787     circles look twice as wide as they are tall, we have to shrink the
    3788     y size of the image.
    3789    
    3790     ::
    3791    
    3792         sage: adjust_figsize_for_aspect_ratio([3,5], 2, 0, 10, 0, 2)
    3793         (5, 1/2)
    3794     """
    3795     if not isinstance(figsize, (list, tuple)):
    3796         figsize = [figsize, figsize * 0.618033988749895]   # 1/golden_ratio
    3797     if aspect_ratio is None:
    3798         return figsize
    3799     # We find a number r such that (ymax-ymin)*r / (xmax-xmin) = aspect_ratio:
    3800     r = max(aspect_ratio * (xmax - xmin)/(ymax-ymin), 0.001)
    3801     mx = max(figsize)
    3802     f = (figsize[0]*r, figsize[0])
    3803     s = min((mx/f[0], mx/f[1]))
    3804     return f[0]*s, f[1]*s
    3805 
    3806 
    38073815
    38083816def setup_for_eval_on_grid(v, xrange, yrange, plot_points):
    38093817    """
  • sage/plot/plot_field.py

    diff -r da9376d80113 -r cf1b0507fcd0 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 da9376d80113 -r cf1b0507fcd0 sage/plot/scatter_plot.py
    a b  
    109109        options = self.options()
    110110        subplot.scatter(self.xdata, self.ydata, alpha=options['alpha'], zorder=options['zorder'], marker=options['marker'],s=options['markersize'],facecolors=options['facecolor'], edgecolors=options['edgecolor'])
    111111
    112 @options(alpha=1, markersize=50, marker='o', zorder=5, facecolor='#fec7b8', edgecolor='black')
     112@options(alpha=1, markersize=50, marker='o', zorder=5, facecolor='#fec7b8', edgecolor='black', aspect_ratio='auto')
    113113def scatter_plot(datalist, **options):
    114114    """
    115115    Returns a Graphics object of a scatter plot containing all points in