Ticket #2100: trac_2100-aspect-ratio-rebase.patch
File trac_2100-aspect-ratio-rebase.patch, 35.8 KB (added by , 10 years ago) |
---|
-
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 397 397 398 398 A pretty circle of arrows:: 399 399 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]]) 401 401 402 402 If we want to draw the arrow between objects, for example, the 403 403 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 119 119 subplot.bar(ind, datalist, color=color, width=width, label=options['legend_label']) 120 120 121 121 @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') 123 123 def bar_chart(datalist, **options): 124 124 """ 125 125 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 283 283 284 284 And a circle with a legend:: 285 285 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) 287 287 288 288 Extra options will get passed on to show(), as long as they are valid:: 289 289 -
sage/plot/contour_plot.py
diff -r 5eb5ed73e74d -r 72fb76799653 sage/plot/contour_plot.py
a b 345 345 346 346 :: 347 347 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) 349 349 350 350 :: 351 351 … … 441 441 This should plot concentric circles centered at the origin:: 442 442 443 443 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)) 445 445 446 446 Extra options will get passed on to show(), as long as they are valid:: 447 447 … … 526 526 527 527 sage: var("x y") 528 528 (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)) 530 530 531 531 I can do the same thing, but using a callable function so I don't need 532 532 to explicitly define the variables in the ranges, and filling the inside:: 533 533 534 534 sage: x,y = var('x,y') 535 535 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) 537 537 538 538 The same circle but with a different line width:: 539 539 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) 541 541 542 542 And again the same circle but this time with a dashdot border:: 543 543 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') 545 545 546 546 You can also plot an equation:: 547 547 548 548 sage: var("x y") 549 549 (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)) 551 551 552 552 You can even change the color of the plot:: 553 553 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") 555 555 556 556 Here is a beautiful (and long) example which also tests that all 557 557 colors work with this:: … … 561 561 sage: for col in colors.keys(): # long time 562 562 ... G += implicit_plot(x^2+y^2==1+counter*.1, (x,-4,4),(y,-4,4),color=col) 563 563 ... counter += 1 564 sage: G.show( aspect_ratio=1,frame=False)564 sage: G.show(frame=False) 565 565 566 566 We can define a level-`n` approximation of the boundary of the 567 567 Mandelbrot set:: … … 578 578 579 579 The first-level approximation is just a circle:: 580 580 581 sage: implicit_plot(mandel(1), (-3, 3), (-3, 3)) .show(aspect_ratio=1)581 sage: implicit_plot(mandel(1), (-3, 3), (-3, 3)) 582 582 583 583 A third-level approximation starts to get interesting:: 584 584 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)) 586 586 587 587 The seventh-level approximation is a degree 64 polynomial, and 588 588 ``implicit_plot`` does a pretty good job on this part of the curve. … … 590 590 591 591 :: 592 592 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) 594 594 """ 595 595 from sage.symbolic.expression import is_SymbolicEquation 596 596 if is_SymbolicEquation(f): … … 663 663 664 664 A disk centered at the origin:: 665 665 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)) 667 667 668 668 A plot with more than one condition (all conditions must be true for the statement to be true):: 669 669 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)) 671 671 672 672 Since it doesn't look very good, let's increase plot_points:: 673 673 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) 675 675 676 676 To get plots where only one condition needs to be true, use a function:: 677 677 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)) 679 679 680 680 The first quadrant of the unit circle:: 681 681 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) 683 683 684 684 Here is another plot, with a huge border:: 685 685 … … 691 691 692 692 Here we have a cut circle:: 693 693 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) 695 695 696 696 The first variable range corresponds to the horizontal axis and 697 697 the second variable range corresponds to the vertical axis:: -
sage/plot/disk.py
diff -r 5eb5ed73e74d -r 72fb76799653 sage/plot/disk.py
a b 239 239 sage: tl = disk((0.0,0.0), 1, (pi/2, pi), color='black') 240 240 sage: br = disk((0.0,0.0), 1, (3*pi/2, 2*pi), color='black') 241 241 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) 243 243 244 To correct the aspect ratio of certain graphics, it is necessary 245 to show with a ``aspect_ratio`` of one:: 244 :: 246 245 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') 249 247 250 You can also achieve the same aspect ratio by specifying a ``figsize`` 251 with square dimensions:: 248 :: 252 249 253 250 sage: bl = disk((0.0,0.0), 1, (pi, 3*pi/2), rgbcolor=(1,1,0)) 254 251 sage: bl.show(figsize=[5,5]) -
sage/plot/plot.py
diff -r 5eb5ed73e74d -r 72fb76799653 sage/plot/plot.py
a b 75 75 76 76 Type ``?`` after each primitive in Sage for help and examples. 77 77 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 78 EXAMPLES: 83 79 84 80 We draw a circle and a curve:: 85 81 … … 92 88 93 89 sage: show(circle((1,1), 1) + plot(x^2, (x,0,5)), aspect_ratio=1) 94 90 95 With an aspect ratio of 2 the circle is squashed half way down (it 96 looks twice as wide as it does tall):: 91 The 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:: 97 92 98 93 sage: show(circle((1,1), 1) + plot(x^2, (x,0,5)), aspect_ratio=2) 99 94 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]) 95 The ``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 99 You 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]) 105 102 106 103 Note that the axes will not cross if the data is not on both sides of 107 104 both axes, even if it is quite close:: … … 112 109 large, scientific notation (the `e` notation for powers of ten) is used:: 113 110 114 111 sage: plot(x^2,(x,480,500)) # no scientific notation 112 113 :: 114 115 115 sage: plot(x^2,(x,300,500)) # scientific notation on y-axis 116 116 117 But you can fix your own labels, if you know what to expect and117 But you can fix your own tick labels, if you know what to expect and 118 118 have a preference:: 119 119 120 120 sage: plot(x^2,(x,300,500),ticks=[None,50000]) 121 121 122 We 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 122 128 Next we construct the reflection of the above polygon about the 123 129 `y`-axis by iterating over the list of first-coordinates of 124 130 the first graphic element of `P` (which is the actual … … 298 304 - Jason Grout (2009-09-05): shifted axes and grid functionality over 299 305 to matplotlib; fixed a number of smaller issues. 300 306 307 - Jason Grout (2010-10): rewrote aspect ratio portions of the code 308 301 309 """ 302 310 303 311 ############################################################################ … … 316 324 ## going to be used. 317 325 318 326 ALLOWED_EXTENSIONS = ['.eps', '.pdf', '.png', '.ps', '.sobj', '.svg'] 319 DEFAULT_FIGSIZE=(6, 3.70820393249937)327 #DEFAULT_FIGSIZE=(6, 3.70820393249937) 320 328 DEFAULT_DPI = 100 321 329 EMBEDDED_MODE = False 322 330 DOCTEST_MODE = False … … 415 423 416 424 sage: G = Graphics(); print G 417 425 Graphics object consisting of 0 graphics primitives 418 sage: c = circle((1,1), 1 ,aspect_ratio=1)426 sage: c = circle((1,1), 1) 419 427 sage: G+=c; print G 420 428 Graphics object consisting of 1 graphics primitive 421 429 … … 446 454 447 455 sage: G = Graphics() 448 456 """ 449 self.__aspect_ratio = None457 self.__aspect_ratio = 1.0 450 458 self.__fontsize = 10 451 459 self.__show_axes = True 452 460 self.__show_legend = False … … 460 468 461 469 def set_aspect_ratio(self, ratio): 462 470 """ 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). 464 474 465 475 INPUT: 466 476 467 477 468 - ``ratio`` - a positive real number 478 - ``ratio`` - a positive real number or 'auto' 469 479 470 480 471 481 EXAMPLES: We create a plot of a circle, and it doesn't look quite … … 485 495 sage: P + circle((0,0), 0.5) # still square 486 496 487 497 In the following example, both plots produce a circle that looks 488 twice as wide as tall::498 twice as tall as wide:: 489 499 490 500 sage: Q = circle((0,0), 0.5); Q.set_aspect_ratio(2) 491 501 sage: P + Q 492 502 sage: Q + P 493 503 """ 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'" 497 508 self.__aspect_ratio = ratio 498 509 499 510 def aspect_ratio(self): 500 511 """ 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). 505 517 506 518 EXAMPLES:: 507 519 508 520 sage: P = circle((1,1), 1) 509 sage: P.aspect_ratio() is None510 True521 sage: P.aspect_ratio() 522 1.0 511 523 sage: P.set_aspect_ratio(2) 512 524 sage: P.aspect_ratio() 513 525 2.0 526 sage: P.set_aspect_ratio('auto') 527 sage: P.aspect_ratio() 528 'auto' 514 529 """ 515 530 return self.__aspect_ratio 516 531 … … 1236 1251 The xmin, xmax, ymin, and ymax properties of the graphics objects 1237 1252 are expanded to include all objects in both scenes. If the aspect 1238 1253 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. 1240 1256 1241 1257 If one of the graphics object is set to show a legend, then the 1242 1258 resulting object will also be set to show a legend. None of the … … 1248 1264 sage: g2 = plot(-abs(sqrt(x^3-1)), (x,1,5), color='red') 1249 1265 sage: g1 + g2 # displays the plot 1250 1266 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 1255 1273 """ 1256 1274 if isinstance(other, int) and other == 0: 1257 1275 return self … … 1262 1280 raise TypeError, "other (=%s) must be a Graphics objects"%other 1263 1281 g = Graphics() 1264 1282 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) 1266 1289 g.__show_legend = self.__show_legend or other.__show_legend 1267 1290 g._extra_kwds.update(self._extra_kwds) 1268 1291 g._extra_kwds.update(other._extra_kwds) … … 1358 1381 # this dictionary to contain the default value for that parameter. 1359 1382 1360 1383 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, 1362 1386 dpi=DEFAULT_DPI, axes=None, axes_labels=None,frame=False, 1363 fontsize=None, aspect_ratio=None, 1387 fontsize=None, 1388 aspect_ratio=None, 1364 1389 gridlines=None, gridlinesstyle=None, 1365 1390 vgridlinesstyle=None, hgridlinesstyle=None,transparent=False, 1366 1391 show_legend=None, legend_options={}, … … 1384 1409 1385 1410 - ``figsize`` - [width, height] 1386 1411 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. 1393 1425 1394 1426 - ``axes`` - (default: True) 1395 1427 … … 1511 1543 sage: c = circle((1,1), 1, color='red') 1512 1544 sage: c.show(xmin=-1, xmax=3, ymin=-1, ymax=3) 1513 1545 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) 1527 1549 1528 1550 You can turn off the drawing of the axes:: 1529 1551 … … 1856 1878 xmin=None, xmax=None, ymin=None, ymax=None, 1857 1879 figsize=None, figure=None, sub=None, 1858 1880 axes=None, axes_labels=None, fontsize=None, 1859 frame=False, verify=True, aspect_ratio = None, 1881 frame=False, verify=True, 1882 aspect_ratio = None, 1860 1883 gridlines=None, gridlinesstyle=None, 1861 1884 vgridlinesstyle=None, hgridlinesstyle=None, 1862 1885 show_legend=None, legend_options={}, … … 1869 1892 1870 1893 sage: c = circle((1,1),1) 1871 1894 sage: print c.matplotlib() 1872 Figure( 480x296.656)1895 Figure(640x480) 1873 1896 1874 1897 To obtain the first matplotlib axes object inside of the 1875 1898 figure, you can do something like the following. … … 1927 1950 if axes is None: 1928 1951 axes = self.__show_axes 1929 1952 1930 from matplotlib.figure import Figure, figaspect 1953 from matplotlib.figure import Figure 1954 from matplotlib import rcParams 1931 1955 self.fontsize(fontsize) 1932 1956 self.axes_labels(l=axes_labels) 1933 1957 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) 1946 1961 1947 1962 if figure is None: 1948 figure=Figure(figsize )1963 figure=Figure(figsize=figsize) 1949 1964 1950 1965 #the incoming subplot instance 1951 1966 subplot = sub 1952 1967 if not subplot: 1953 1968 subplot = figure.add_subplot(111) 1954 if aspect_ratio is notNone: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') 1957 1972 #add all the primitives to the subplot 1958 1973 for g in self.__objects: 1959 1974 g._render_on_subplot(subplot) … … 2283 2298 if vgridlines not in (None, False): 2284 2299 subplot.xaxis.grid(True, **vgridstyle) 2285 2300 2286 if aspect_ratio is not None:2287 subplot.set_aspect(aspect_ratio)2288 2301 2289 2302 2290 2303 if self.__axes_labels is not None: … … 2338 2351 labeltrans=offset_copy(trans, figure, x=0, y=yaxis_labeloffset, units='points') 2339 2352 subplot.yaxis.set_label_coords(x=yaxis_labelx,y=yaxis_labely,transform=labeltrans) 2340 2353 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 2341 2357 #subplot.autoscale_view(tight=True) 2342 2358 return figure 2343 2359 … … 2385 2401 sage: filename = os.path.join(SAGE_TMP, 'test.png') 2386 2402 sage: c.save(filename, xmin=-1, xmax=3, ymin=-1, ymax=3) 2387 2403 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) 2399 2407 2400 2408 By default, the figure grows to include all of the graphics and text, 2401 2409 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) 2402 2415 2403 2416 You can also pass extra options to the plot command instead of this 2404 2417 method, e.g. :: … … 2428 2441 options.update(kwds) 2429 2442 dpi = options.pop('dpi') 2430 2443 transparent = options.pop('transparent') 2444 fig_tight = options.pop('fig_tight') 2431 2445 2432 2446 if filename is None: 2433 2447 filename = options.pop('filename') … … 2449 2463 # if the file extension is not '.png', then matplotlib will handle it. 2450 2464 from matplotlib.backends.backend_agg import FigureCanvasAgg 2451 2465 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', 2453 2470 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 2455 2540 2456 2541 _SelectiveFormatterClass = None 2457 2542 … … 2584 2669 @rename_keyword(color='rgbcolor') 2585 2670 @options(alpha=1, thickness=1, fill=False, fillcolor='automatic', fillalpha=0.5, rgbcolor=(0,0,1), plot_points=200, 2586 2671 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') 2588 2673 def plot(funcs, *args, **kwds): 2589 2674 r""" 2590 2675 Use plot by writing … … 3249 3334 3250 3335 ########## misc functions ################### 3251 3336 3252 @options(aspect_ratio=1 )3337 @options(aspect_ratio=1.0) 3253 3338 def parametric_plot(funcs, *args, **kwargs): 3254 3339 r""" 3255 3340 Plot a parametric curve or surface in 2d or 3d. … … 3360 3445 else: 3361 3446 raise ValueError, "the number of functions and the number of variable ranges is not a supported combination for a 2d or 3d parametric plots" 3362 3447 3363 @options(aspect_ratio=1 )3448 @options(aspect_ratio=1.0) 3364 3449 def polar_plot(funcs, *args, **kwds): 3365 3450 r""" 3366 3451 ``polar_plot`` takes a single function or a list or … … 3400 3485 3401 3486 Fill the area between two functions:: 3402 3487 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') 3404 3489 3405 3490 Fill the area between several spirals:: 3406 3491 … … 3408 3493 3409 3494 Exclude points at discontinuities:: 3410 3495 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]) 3412 3497 3413 3498 """ 3414 3499 kwds['polar']=True 3415 3500 return plot(funcs, *args, **kwds) 3416 3501 3502 @options(aspect_ratio='auto') 3417 3503 def list_plot(data, plotjoined=False, **kwargs): 3418 3504 r""" 3419 3505 ``list_plot`` takes either a single list of data, a list of tuples, … … 3534 3620 if not isinstance(g, Graphics): 3535 3621 raise TypeError, "every element of array must be a Graphics object" 3536 3622 self._glist.append(g) 3537 self._figsize = DEFAULT_FIGSIZE3623 self._figsize = None 3538 3624 3539 3625 def _repr_(self): 3540 3626 if SHOW_DEFAULT: … … 3571 3657 def append(self, g): 3572 3658 self._glist.append(g) 3573 3659 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): 3575 3661 r""" 3576 3662 ``render`` loops over all graphics objects in the array 3577 3663 and adds them to the subplot. … … 3593 3679 g.save(filename, dpi=dpi, figure=figure, sub=subplot, 3594 3680 verify=do_verify, axes = axes, **args) 3595 3681 3596 def save(self, filename=None, dpi=DEFAULT_DPI, figsize= DEFAULT_FIGSIZE,3682 def save(self, filename=None, dpi=DEFAULT_DPI, figsize=None, 3597 3683 axes = None, **args): 3598 3684 """ 3599 3685 save the ``graphics_array`` to (for now) a png called 3600 3686 'filename'. 3601 3687 """ 3602 if (figsize != DEFAULT_FIGSIZE): self.__set_figsize__(figsize)3688 if (figsize is not None): self.__set_figsize__(figsize) 3603 3689 self._render(filename, dpi=dpi, figsize=self._figsize, axes = axes, **args) 3604 3690 3605 def show(self, filename=None, dpi=DEFAULT_DPI, figsize= DEFAULT_FIGSIZE,3691 def show(self, filename=None, dpi=DEFAULT_DPI, figsize=None, 3606 3692 axes = None, **args): 3607 3693 r""" 3608 3694 Show this graphics array using the default viewer. … … 3614 3700 3615 3701 - ``dpi`` - dots per inch 3616 3702 3617 - ``figsize`` - [width, height] (same for square 3618 aspect) 3703 - ``figsize`` - width or [width, height] 3619 3704 3620 3705 - ``axes`` - (default: True) 3621 3706 … … 3633 3718 sage: G = graphics_array([[plot(sin), plot(cos)], [plot(tan), plot(sec)]]) 3634 3719 sage: G.show(axes=False) 3635 3720 """ 3636 if (figsize != DEFAULT_FIGSIZE): self.__set_figsize__(figsize)3721 if (figsize is not None): self.__set_figsize__(figsize) 3637 3722 if DOCTEST_MODE: 3638 3723 self.save(DOCTEST_MODE_FILE, 3639 3724 dpi=dpi, figsize=self._figsize, axes = axes, **args) … … 3782 3867 return var, values 3783 3868 3784 3869 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 aspect3788 ratio.3789 3790 INPUTS: figsize - a sequence of two positive real numbers3791 aspect_ratio - a positive real number xmin, xmax, ymin, ymax -3792 real numbers3793 3794 EXAMPLES: This function is used mainly internally by plotting code3795 so we explicitly import it::3796 3797 sage: from sage.plot.plot import adjust_figsize_for_aspect_ratio3798 3799 This returns (5,5), since the requested aspect ratio is 1 and the x3800 and y ranges are the same, so that's the right size rendered image3801 to produce a 1:1 ratio internally. 5 is used instead of 3 since the3802 image size is always adjusted to the larger of the figsize3803 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 to3811 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 are3826 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 where3832 circles look twice as wide as they are tall, we have to shrink the3833 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_ratio3842 if aspect_ratio is None:3843 return figsize3844 # 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]*s3850 3851 3852 3870 3853 3871 def setup_for_eval_on_grid(v, xrange, yrange, plot_points): 3854 3872 """ -
sage/plot/plot_field.py
diff -r 5eb5ed73e74d -r 72fb76799653 sage/plot/plot_field.py
a b 159 159 sage: x,y = var('x,y') 160 160 sage: a=plot_vector_field((x,y), (x,-3,3),(y,-3,3),color='blue') 161 161 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) 163 163 164 164 We ignore function values that are infinite or NaN:: 165 165 … … 213 213 sage: x,y = var('x y') 214 214 sage: capacity = 3 # thousand 215 215 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)) 217 217 218 218 Plot a slope field involving sin and cos:: 219 219 220 220 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)) 222 222 """ 223 223 slope_options = {'headaxislength': 0, 'headlength': 0, 'pivot': 'middle'} 224 224 slope_options.update(kwds) -
sage/plot/scatter_plot.py
diff -r 5eb5ed73e74d -r 72fb76799653 sage/plot/scatter_plot.py
a b 128 128 options = self.options() 129 129 subplot.scatter(self.xdata, self.ydata, alpha=options['alpha'], zorder=options['zorder'], marker=options['marker'],s=options['markersize'],facecolors=options['facecolor'], edgecolors=options['edgecolor']) 130 130 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') 132 132 def scatter_plot(datalist, **options): 133 133 """ 134 134 Returns a Graphics object of a scatter plot containing all points in