Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/plot/plot.py
8815 views
1
r"""
2
2D Plotting
3
4
Sage provides extensive 2D plotting functionality. The underlying
5
rendering is done using the matplotlib Python library.
6
7
The following graphics primitives are supported:
8
9
10
- :func:`~sage.plot.arrow.arrow` - an arrow from a min point to a max point.
11
12
- :func:`~sage.plot.circle.circle` - a circle with given radius
13
14
- :func:`~sage.plot.ellipse.ellipse` - an ellipse with given radii
15
and angle
16
17
- :func:`~sage.plot.arc.arc` - an arc of a circle or an ellipse
18
19
- :func:`~sage.plot.disk.disk` - a filled disk (i.e. a sector or wedge of a circle)
20
21
- :func:`~sage.plot.line.line` - a line determined by a sequence of points (this need not
22
be straight!)
23
24
- :func:`~sage.plot.point.point` - a point
25
26
- :func:`~sage.plot.text.text` - some text
27
28
- :func:`~sage.plot.polygon.polygon` - a filled polygon
29
30
31
The following plotting functions are supported:
32
33
34
- :func:`plot` - plot of a function or other Sage object (e.g., elliptic
35
curve).
36
37
- :func:`parametric_plot`
38
39
- :func:`~sage.plot.contour_plot.implicit_plot`
40
41
- :func:`polar_plot`
42
43
- :func:`~sage.plot.contour_plot.region_plot`
44
45
- :func:`list_plot`
46
47
- :func:`~sage.plot.scatter_plot.scatter_plot`
48
49
- :func:`~sage.plot.bar_chart.bar_chart`
50
51
- :func:`~sage.plot.contour_plot.contour_plot`
52
53
- :func:`~sage.plot.density_plot.density_plot`
54
55
- :func:`~sage.plot.plot_field.plot_vector_field`
56
57
- :func:`~sage.plot.plot_field.plot_slope_field`
58
59
- :func:`~sage.plot.matrix_plot.matrix_plot`
60
61
- :func:`~sage.plot.complex_plot.complex_plot`
62
63
- :func:`graphics_array`
64
65
- The following log plotting functions:
66
67
- :func:`plot_loglog`
68
69
- :func:`plot_semilogx` and :func:`plot_semilogy`
70
71
- :func:`list_plot_loglog`
72
73
- :func:`list_plot_semilogx` and :func:`list_plot_semilogy`
74
75
76
The following miscellaneous Graphics functions are included:
77
78
79
- :func:`Graphics`
80
81
- :func:`is_Graphics`
82
83
- :func:`~sage.plot.colors.hue`
84
85
86
Type ``?`` after each primitive in Sage for help and examples.
87
88
EXAMPLES:
89
90
We draw a curve::
91
92
sage: plot(x^2, (x,0,5))
93
94
We draw a circle and a curve::
95
96
sage: circle((1,1), 1) + plot(x^2, (x,0,5))
97
98
Notice that the aspect ratio of the above plot makes the plot very tall because
99
the plot adopts the default aspect ratio of the circle (to make the circle appear
100
like a circle). We can change the aspect ratio to be what we normally expect for a plot
101
by explicitly asking for an 'automatic' aspect ratio::
102
103
sage: show(circle((1,1), 1) + plot(x^2, (x,0,5)), aspect_ratio='automatic')
104
105
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::
106
107
sage: show(circle((1,1), 1) + plot(x^2, (x,0,5)), aspect_ratio=2)
108
109
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``::
110
111
sage: show(circle((1,1), 1) + plot(x^2, (x,0,5)), figsize=8)
112
113
You can also give separate horizontal and vertical dimensions::
114
115
sage: show(circle((1,1), 1) + plot(x^2, (x,0,5)), figsize=[4,8])
116
117
Note that the axes will not cross if the data is not on both sides of
118
both axes, even if it is quite close::
119
120
sage: plot(x^3,(x,1,10))
121
122
When the labels have quite different orders of magnitude or are very
123
large, scientific notation (the `e` notation for powers of ten) is used::
124
125
sage: plot(x^2,(x,480,500)) # no scientific notation
126
127
::
128
129
sage: plot(x^2,(x,300,500)) # scientific notation on y-axis
130
131
But you can fix your own tick labels, if you know what to expect and
132
have a preference::
133
134
sage: plot(x^2,(x,300,500),ticks=[None,50000])
135
136
You can even have custom tick labels along with custom positioning. ::
137
138
sage: plot(x**2, (x,0,3), ticks=[[1,2.5],pi/2], tick_formatter=[["$x_1$","$x_2$"],pi])
139
140
We construct a plot involving several graphics objects::
141
142
sage: G = plot(cos(x), (x, -5, 5), thickness=5, color='green', title='A plot')
143
sage: P = polygon([[1,2], [5,6], [5,0]], color='red')
144
sage: G + P
145
146
Next we construct the reflection of the above polygon about the
147
`y`-axis by iterating over the list of first-coordinates of
148
the first graphic element of ``P`` (which is the actual
149
Polygon; note that ``P`` is a Graphics object, which consists
150
of a single polygon)::
151
152
sage: Q = polygon([(-x,y) for x,y in P[0]], color='blue')
153
sage: Q # show it
154
155
We combine together different graphics objects using "+"::
156
157
sage: H = G + P + Q
158
sage: print H
159
Graphics object consisting of 3 graphics primitives
160
sage: type(H)
161
<class 'sage.plot.graphics.Graphics'>
162
sage: H[1]
163
Polygon defined by 3 points
164
sage: list(H[1])
165
[(1.0, 2.0), (5.0, 6.0), (5.0, 0.0)]
166
sage: H # show it
167
168
We can put text in a graph::
169
170
sage: L = [[cos(pi*i/100)^3,sin(pi*i/100)] for i in range(200)]
171
sage: p = line(L, rgbcolor=(1/4,1/8,3/4))
172
sage: t = text('A Bulb', (1.5, 0.25))
173
sage: x = text('x axis', (1.5,-0.2))
174
sage: y = text('y axis', (0.4,0.9))
175
sage: g = p+t+x+y
176
sage: g.show(xmin=-1.5, xmax=2, ymin=-1, ymax=1)
177
178
We can add a title to a graph::
179
180
sage: x = var('x')
181
sage: plot(x^2, (x,-2,2), title='A plot of $x^2$')
182
183
We can set the position of the title::
184
185
sage: plot(x^2, (-2,2), title='Plot of $x^2$', title_pos=(0.5,-0.05))
186
187
We plot the Riemann zeta function along the critical line and see
188
the first few zeros::
189
190
sage: i = CDF.0 # define i this way for maximum speed.
191
sage: p1 = plot(lambda t: arg(zeta(0.5+t*i)), 1,27,rgbcolor=(0.8,0,0))
192
sage: p2 = plot(lambda t: abs(zeta(0.5+t*i)), 1,27,color=hue(0.7))
193
sage: print p1 + p2
194
Graphics object consisting of 2 graphics primitives
195
sage: p1 + p2 # display it
196
197
Many concentric circles shrinking toward the origin::
198
199
sage: show(sum(circle((i,0), i, hue=sin(i/10)) for i in [10,9.9,..,0]))
200
201
Here is a pretty graph::
202
203
sage: g = Graphics()
204
sage: for i in range(60):
205
... p = polygon([(i*cos(i),i*sin(i)), (0,i), (i,0)],\
206
... color=hue(i/40+0.4), alpha=0.2)
207
... g = g + p
208
...
209
sage: g.show(dpi=200, axes=False)
210
211
Another graph::
212
213
sage: x = var('x')
214
sage: P = plot(sin(x)/x, -4,4, color='blue') + \
215
... plot(x*cos(x), -4,4, color='red') + \
216
... plot(tan(x),-4,4, color='green')
217
...
218
sage: P.show(ymin=-pi,ymax=pi)
219
220
PYX EXAMPLES: These are some examples of plots similar to some of
221
the plots in the PyX (http://pyx.sourceforge.net) documentation:
222
223
Symbolline::
224
225
sage: y(x) = x*sin(x^2)
226
sage: v = [(x, y(x)) for x in [-3,-2.95,..,3]]
227
sage: show(points(v, rgbcolor=(0.2,0.6, 0.1), pointsize=30) + plot(spline(v), -3.1, 3))
228
229
Cycliclink::
230
231
sage: x = var('x')
232
sage: g1 = plot(cos(20*x)*exp(-2*x), 0, 1)
233
sage: g2 = plot(2*exp(-30*x) - exp(-3*x), 0, 1)
234
sage: show(graphics_array([g1, g2], 2, 1), xmin=0)
235
236
Pi Axis::
237
238
sage: g1 = plot(sin(x), 0, 2*pi)
239
sage: g2 = plot(cos(x), 0, 2*pi, linestyle = "--")
240
sage: (g1+g2).show(ticks=pi/6, tick_formatter=pi) # show their sum, nicely formatted
241
242
An illustration of integration::
243
244
sage: f(x) = (x-3)*(x-5)*(x-7)+40
245
sage: P = line([(2,0),(2,f(2))], color='black')
246
sage: P += line([(8,0),(8,f(8))], color='black')
247
sage: P += polygon([(2,0),(2,f(2))] + [(x, f(x)) for x in [2,2.1,..,8]] + [(8,0),(2,0)], rgbcolor=(0.8,0.8,0.8),aspect_ratio='automatic')
248
sage: P += text("$\\int_{a}^b f(x) dx$", (5, 20), fontsize=16, color='black')
249
sage: P += plot(f, (1, 8.5), thickness=3)
250
sage: P # show the result
251
252
253
254
NUMERICAL PLOTTING:
255
256
Sage includes Matplotlib, which provides 2D plotting with an interface
257
that is a likely very familiar to people doing numerical
258
computation. For example,
259
260
::
261
262
sage: from pylab import *
263
sage: t = arange(0.0, 2.0, 0.01)
264
sage: s = sin(2*pi*t)
265
sage: P = plot(t, s, linewidth=1.0)
266
sage: xl = xlabel('time (s)')
267
sage: yl = ylabel('voltage (mV)')
268
sage: t = title('About as simple as it gets, folks')
269
sage: grid(True)
270
sage: savefig(os.path.join(SAGE_TMP, 'sage.png'))
271
272
We test that ``imshow`` works as well, verifying that
273
:trac:`2900` is fixed (in Matplotlib).
274
275
::
276
277
sage: imshow([[(0,0,0)]])
278
<matplotlib.image.AxesImage object at ...>
279
sage: savefig(os.path.join(SAGE_TMP, 'foo.png'))
280
281
Since the above overwrites many Sage plotting functions, we reset
282
the state of Sage, so that the examples below work!
283
284
::
285
286
sage: reset()
287
288
See http://matplotlib.sourceforge.net for complete documentation
289
about how to use Matplotlib.
290
291
TESTS: We test dumping and loading a plot.
292
293
::
294
295
sage: p = plot(sin(x), (x, 0,2*pi))
296
sage: Q = loads(dumps(p))
297
298
Verify that a clean sage startup does *not* import matplotlib::
299
300
sage: os.system("sage -c \"if 'matplotlib' in sys.modules: sys.exit(1)\"")
301
0
302
303
AUTHORS:
304
305
- Alex Clemesha and William Stein (2006-04-10): initial version
306
307
- David Joyner: examples
308
309
- Alex Clemesha (2006-05-04) major update
310
311
- William Stein (2006-05-29): fine tuning, bug fixes, better server
312
integration
313
314
- William Stein (2006-07-01): misc polish
315
316
- Alex Clemesha (2006-09-29): added contour_plot, frame axes, misc
317
polishing
318
319
- Robert Miller (2006-10-30): tuning, NetworkX primitive
320
321
- Alex Clemesha (2006-11-25): added plot_vector_field, matrix_plot,
322
arrow, bar_chart, Axes class usage (see axes.py)
323
324
- Bobby Moretti and William Stein (2008-01): Change plot to specify
325
ranges using the (varname, min, max) notation.
326
327
- William Stein (2008-01-19): raised the documentation coverage from a
328
miserable 12 percent to a 'wopping' 35 percent, and fixed and
329
clarified numerous small issues.
330
331
- Jason Grout (2009-09-05): shifted axes and grid functionality over
332
to matplotlib; fixed a number of smaller issues.
333
334
- Jason Grout (2010-10): rewrote aspect ratio portions of the code
335
336
- Jeroen Demeyer (2012-04-19): move parts of this file to graphics.py (:trac:`12857`)
337
338
"""
339
#*****************************************************************************
340
# Copyright (C) 2006 Alex Clemesha <[email protected]>
341
# Copyright (C) 2006-2008 William Stein <[email protected]>
342
# Copyright (C) 2010 Jason Grout
343
#
344
# Distributed under the terms of the GNU General Public License (GPL)
345
# as published by the Free Software Foundation; either version 2 of
346
# the License, or (at your option) any later version.
347
# http://www.gnu.org/licenses/
348
#*****************************************************************************
349
350
351
import os
352
353
## IMPORTANT: Do *not* import matplotlib at module scope. It takes a
354
## surprisingly long time to initialize itself. It's better if it is
355
## imported in functions, so it only gets started if it is actually
356
## going to be used.
357
358
#DEFAULT_FIGSIZE=(6, 3.70820393249937)
359
EMBEDDED_MODE = False
360
import sage.misc.misc
361
from sage.misc.misc import srange
362
363
from sage.misc.randstate import current_randstate #for plot adaptive refinement
364
from math import sin, cos, pi #for polar_plot
365
366
from sage.ext.fast_eval import fast_float, fast_float_constant, is_fast_float
367
368
from sage.misc.decorators import options, rename_keyword
369
370
from graphics import Graphics, GraphicsArray
371
372
#Currently not used - see comment immediately above about
373
#figure.canvas.mpl_connect('draw_event', pad_for_tick_labels)
374
# TODO - figure out how to use this, add documentation
375
#def pad_for_tick_labels(event):
376
# import matplotlib.transforms as mtransforms
377
# figure=event.canvas.figure
378
# bboxes = []
379
# for ax in figure.axes:
380
# bbox = ax.xaxis.get_label().get_window_extent()
381
# # the figure transform goes from relative coords->pixels and we
382
# # want the inverse of that
383
# bboxi = bbox.inverse_transformed(figure.transFigure)
384
# bboxes.append(bboxi)
385
#
386
# bbox = ax.yaxis.get_label().get_window_extent()
387
# bboxi = bbox.inverse_transformed(figure.transFigure)
388
# bboxes.append(bboxi)
389
# for label in (ax.get_xticklabels()+ax.get_yticklabels() \
390
# + ax.get_xticklabels(minor=True) \
391
# +ax.get_yticklabels(minor=True)):
392
# bbox = label.get_window_extent()
393
# bboxi = bbox.inverse_transformed(figure.transFigure)
394
# bboxes.append(bboxi)
395
#
396
# # this is the bbox that bounds all the bboxes, again in relative
397
# # figure coords
398
# bbox = mtransforms.Bbox.union(bboxes)
399
# adjusted=adjust_figure_to_contain_bbox(figure,bbox)
400
#
401
# if adjusted:
402
# figure.canvas.draw()
403
# return False
404
#
405
#Currently not used - see comment above about
406
#figure.canvas.mpl_connect('draw_event', pad_for_tick_labels)
407
# TODO - figure out how to use this, add documentation
408
#def adjust_figure_to_contain_bbox(fig, bbox,pad=1.1):
409
# """
410
# For each amount we are over (in axes coordinates), we adjust by over*pad
411
# to give ourselves a bit of padding.
412
# """
413
# left=fig.subplotpars.left
414
# bottom=fig.subplotpars.bottom
415
# right=fig.subplotpars.right
416
# top=fig.subplotpars.top
417
#
418
# adjusted=False
419
# if bbox.xmin<0:
420
# left-=bbox.xmin*pad
421
# adjusted=True
422
# if bbox.ymin<0:
423
# bottom-=bbox.ymin*pad
424
# adjusted=True
425
# if bbox.xmax>1:
426
# right-=(bbox.xmax-1)*pad
427
# adjusted=True
428
# if bbox.ymax>1:
429
# top-=(bbox.ymax-1)*pad
430
# adjusted=True
431
#
432
# if left<right and bottom<top:
433
# fig.subplots_adjust(left=left, bottom=bottom, right=right, top=top)
434
# return adjusted
435
# else:
436
# return False
437
438
_SelectiveFormatterClass = None
439
440
def SelectiveFormatter(formatter, skip_values):
441
"""
442
This matplotlib formatter selectively omits some tick values and
443
passes the rest on to a specified formatter.
444
445
EXAMPLES:
446
447
This example is almost straight from a matplotlib example.
448
449
::
450
451
sage: from sage.plot.plot import SelectiveFormatter
452
sage: import matplotlib.pyplot as plt
453
sage: import numpy
454
sage: fig=plt.figure()
455
sage: ax=fig.add_subplot(111)
456
sage: t = numpy.arange(0.0, 2.0, 0.01)
457
sage: s = numpy.sin(2*numpy.pi*t)
458
sage: p = ax.plot(t, s)
459
sage: formatter=SelectiveFormatter(ax.xaxis.get_major_formatter(),skip_values=[0,1])
460
sage: ax.xaxis.set_major_formatter(formatter)
461
sage: fig.savefig(os.path.join(SAGE_TMP, 'test.png'))
462
"""
463
global _SelectiveFormatterClass
464
if _SelectiveFormatterClass is None:
465
466
from matplotlib.ticker import Formatter
467
468
class _SelectiveFormatterClass(Formatter):
469
def __init__(self, formatter,skip_values):
470
"""
471
Initialize a SelectiveFormatter object.
472
473
INPUT:
474
475
- formatter -- the formatter object to which we should pass labels
476
477
- skip_values -- a list of values that we should skip when
478
formatting the tick labels
479
480
EXAMPLES::
481
482
sage: from sage.plot.plot import SelectiveFormatter
483
sage: import matplotlib.pyplot as plt
484
sage: import numpy
485
sage: fig=plt.figure()
486
sage: ax=fig.add_subplot(111)
487
sage: t = numpy.arange(0.0, 2.0, 0.01)
488
sage: s = numpy.sin(2*numpy.pi*t)
489
sage: line=ax.plot(t, s)
490
sage: formatter=SelectiveFormatter(ax.xaxis.get_major_formatter(),skip_values=[0,1])
491
sage: ax.xaxis.set_major_formatter(formatter)
492
sage: fig.savefig(os.path.join(SAGE_TMP, 'test.png'))
493
"""
494
self.formatter=formatter
495
self.skip_values=skip_values
496
def set_locs(self, locs):
497
"""
498
Set the locations for the ticks that are not skipped.
499
500
EXAMPLES::
501
sage: from sage.plot.plot import SelectiveFormatter
502
sage: import matplotlib.ticker
503
sage: formatter=SelectiveFormatter(matplotlib.ticker.Formatter(),skip_values=[0,200])
504
sage: formatter.set_locs([i*100 for i in range(10)])
505
"""
506
self.formatter.set_locs([l for l in locs if l not in self.skip_values])
507
def __call__(self, x, *args, **kwds):
508
"""
509
Return the format for tick val *x* at position *pos*
510
511
EXAMPLES::
512
513
sage: from sage.plot.plot import SelectiveFormatter
514
sage: import matplotlib.ticker
515
sage: formatter=SelectiveFormatter(matplotlib.ticker.FixedFormatter(['a','b']),skip_values=[0,2])
516
sage: [formatter(i,1) for i in range(10)]
517
['', 'b', '', 'b', 'b', 'b', 'b', 'b', 'b', 'b']
518
"""
519
if x in self.skip_values:
520
return ''
521
else:
522
return self.formatter(x, *args, **kwds)
523
524
return _SelectiveFormatterClass(formatter, skip_values)
525
526
527
def xydata_from_point_list(points):
528
r"""
529
Returns two lists (xdata, ydata), each coerced to a list of floats,
530
which correspond to the x-coordinates and the y-coordinates of the
531
points.
532
533
The points parameter can be a list of 2-tuples or some object that
534
yields a list of one or two numbers.
535
536
This function can potentially be very slow for large point sets.
537
538
TESTS::
539
540
sage: from sage.plot.plot import xydata_from_point_list
541
sage: xydata_from_point_list([CC(0), CC(1)]) # ticket 8082
542
([0.0, 1.0], [0.0, 0.0])
543
544
This function should work for anything than can be turned into a
545
list, such as iterators and such (see ticket #10478)::
546
547
sage: xydata_from_point_list(iter([(0,0), (sqrt(3), 2)]))
548
([0.0, 1.7320508075688772], [0.0, 2.0])
549
sage: xydata_from_point_list((x, x^2) for x in range(5))
550
([0.0, 1.0, 2.0, 3.0, 4.0], [0.0, 1.0, 4.0, 9.0, 16.0])
551
sage: xydata_from_point_list(enumerate(prime_range(1, 15)))
552
([0.0, 1.0, 2.0, 3.0, 4.0, 5.0], [2.0, 3.0, 5.0, 7.0, 11.0, 13.0])
553
sage: from itertools import izip; xydata_from_point_list(izip([2,3,5,7], [11, 13, 17, 19]))
554
([2.0, 3.0, 5.0, 7.0], [11.0, 13.0, 17.0, 19.0])
555
"""
556
from sage.rings.complex_number import ComplexNumber
557
if not isinstance(points, (list,tuple)):
558
points = list(points)
559
try:
560
points = [[float(z) for z in points]]
561
except TypeError:
562
pass
563
elif len(points)==2 and not isinstance(points[0],(list,tuple,ComplexNumber)):
564
try:
565
points = [[float(z) for z in points]]
566
except TypeError:
567
pass
568
569
if len(points)>0 and len(list(points[0]))!=2:
570
raise ValueError, "points must have 2 coordinates in a 2d line"
571
572
573
xdata = [float(z[0]) for z in points]
574
ydata = [float(z[1]) for z in points]
575
576
return xdata, ydata
577
578
@rename_keyword(color='rgbcolor')
579
@options(alpha=1, thickness=1, fill=False, fillcolor='automatic', fillalpha=0.5, rgbcolor=(0,0,1), plot_points=200,
580
adaptive_tolerance=0.01, adaptive_recursion=5, detect_poles = False, exclude = None, legend_label=None,
581
__original_opts=True, aspect_ratio='automatic')
582
def plot(funcs, *args, **kwds):
583
r"""
584
Use plot by writing
585
586
``plot(X, ...)``
587
588
where `X` is a Sage object (or list of Sage objects) that
589
either is callable and returns numbers that can be coerced to
590
floats, or has a plot method that returns a
591
``GraphicPrimitive`` object.
592
593
There are many other specialized 2D plot commands available
594
in Sage, such as ``plot_slope_field``, as well as various
595
graphics primitives like :class:`~sage.plot.arrow.Arrow`;
596
type ``sage.plot.plot?`` for a current list.
597
598
Type ``plot.options`` for a dictionary of the default
599
options for plots. You can change this to change the defaults for
600
all future plots. Use ``plot.reset()`` to reset to the
601
default options.
602
603
PLOT OPTIONS:
604
605
- ``plot_points`` - (default: 200) the minimal number of plot points.
606
607
- ``adaptive_recursion`` - (default: 5) how many levels of recursion to go
608
before giving up when doing adaptive refinement. Setting this to 0
609
disables adaptive refinement.
610
611
- ``adaptive_tolerance`` - (default: 0.01) how large a difference should be
612
before the adaptive refinement code considers it significant. See the
613
documentation further below for more information, starting at "the
614
algorithm used to insert".
615
616
- ``base`` - (default: 10) the base of the logarithm if
617
a logarithmic scale is set. This must be greater than 1. The base
618
can be also given as a list or tuple ``(basex, basey)``.
619
``basex`` sets the base of the logarithm along the horizontal
620
axis and ``basey`` sets the base along the vertical axis.
621
622
- ``scale`` -- (default: ``"linear"``) string. The scale of the axes.
623
Possible values are ``"linear"``, ``"loglog"``, ``"semilogx"``,
624
``"semilogy"``.
625
626
The scale can be also be given as single argument that is a list
627
or tuple ``(scale, base)`` or ``(scale, basex, basey)``.
628
629
The ``"loglog"`` scale sets both the horizontal and vertical axes to
630
logarithmic scale. The ``"semilogx"`` scale sets the horizontal axis
631
to logarithmic scale. The ``"semilogy"`` scale sets the vertical axis
632
to logarithmic scale. The ``"linear"`` scale is the default value
633
when :class:`~sage.plot.graphics.Graphics` is initialized.
634
635
- ``xmin`` - starting x value
636
637
- ``xmax`` - ending x value
638
639
- ``ymin`` - starting y value in the rendered figure
640
641
- ``ymax`` - ending y value in the rendered figure
642
643
- ``color`` - an RGB tuple (r,g,b) with each of r,g,b between 0 and 1,
644
or a color name as a string (e.g., 'purple'), or an HTML color
645
such as '#aaff0b'.
646
647
- ``detect_poles`` - (Default: False) If set to True poles are detected.
648
If set to "show" vertical asymptotes are drawn.
649
650
- ``legend_color`` - the color of the text for this item in the legend
651
652
- ``legend_label`` - the label for this item in the legend
653
654
.. note::
655
656
- If the ``scale`` is ``"linear"``, then irrespective of what
657
``base`` is set to, it will default to 10 and will remain unused.
658
659
- If you want to limit the plot along the horizontal axis in the
660
final rendered figure, then pass the ``xmin`` and ``xmax``
661
keywords to the :meth:`~sage.plot.graphics.Graphics.show` method.
662
To limit the plot along the vertical axis, ``ymin`` and ``ymax``
663
keywords can be provided to either this ``plot`` command or to
664
the ``show`` command.
665
666
- For the other keyword options that the ``plot`` function can
667
take, refer to the method :meth:`~sage.plot.graphics.Graphics.show`.
668
669
APPEARANCE OPTIONS:
670
671
The following options affect the appearance of
672
the line through the points on the graph of `X` (these are
673
the same as for the line function):
674
675
INPUT:
676
677
- ``alpha`` - How transparent the line is
678
679
- ``thickness`` - How thick the line is
680
681
- ``rgbcolor`` - The color as an RGB tuple
682
683
- ``hue`` - The color given as a hue
684
685
Any MATPLOTLIB line option may also be passed in. E.g.,
686
687
- ``linestyle`` - (default: "-") The style of the line, which is one of
688
- ``"-"`` or ``"solid"``
689
- ``"--"`` or ``"dashed"``
690
- ``"-."`` or ``"dash dot"``
691
- ``":"`` or ``"dotted"``
692
- ``"None"`` or ``" "`` or ``""`` (nothing)
693
694
The linestyle can also be prefixed with a drawing style (e.g., ``"steps--"``)
695
696
- ``"default"`` (connect the points with straight lines)
697
- ``"steps"`` or ``"steps-pre"`` (step function; horizontal
698
line is to the left of point)
699
- ``"steps-mid"`` (step function; points are in the middle of
700
horizontal lines)
701
- ``"steps-post"`` (step function; horizontal line is to the
702
right of point)
703
704
- ``marker`` - The style of the markers, which is one of
705
- ``"None"`` or ``" "`` or ``""`` (nothing) -- default
706
- ``","`` (pixel), ``"."`` (point)
707
- ``"_"`` (horizontal line), ``"|"`` (vertical line)
708
- ``"o"`` (circle), ``"p"`` (pentagon), ``"s"`` (square), ``"x"`` (x), ``"+"`` (plus), ``"*"`` (star)
709
- ``"D"`` (diamond), ``"d"`` (thin diamond)
710
- ``"H"`` (hexagon), ``"h"`` (alternative hexagon)
711
- ``"<"`` (triangle left), ``">"`` (triangle right), ``"^"`` (triangle up), ``"v"`` (triangle down)
712
- ``"1"`` (tri down), ``"2"`` (tri up), ``"3"`` (tri left), ``"4"`` (tri right)
713
- ``0`` (tick left), ``1`` (tick right), ``2`` (tick up), ``3`` (tick down)
714
- ``4`` (caret left), ``5`` (caret right), ``6`` (caret up), ``7`` (caret down)
715
- ``"$...$"`` (math TeX string)
716
717
- ``markersize`` - the size of the marker in points
718
719
- ``markeredgecolor`` -- the color of the marker edge
720
721
- ``markerfacecolor`` -- the color of the marker face
722
723
- ``markeredgewidth`` - the size of the marker edge in points
724
725
- ``exclude`` - (Default: None) values which are excluded from the plot range.
726
Either a list of real numbers, or an equation in one variable.
727
728
FILLING OPTIONS:
729
730
- ``fill`` - (Default: False) One of:
731
732
- "axis" or True: Fill the area between the function and the x-axis.
733
734
- "min": Fill the area between the function and its minimal value.
735
736
- "max": Fill the area between the function and its maximal value.
737
738
- a number c: Fill the area between the function and the horizontal line y = c.
739
740
- a function g: Fill the area between the function that is plotted and g.
741
742
- a dictionary ``d`` (only if a list of functions are plotted):
743
The keys of the dictionary should be integers.
744
The value of ``d[i]`` specifies the fill options for the i-th function
745
in the list. If ``d[i] == [j]``: Fill the area between the i-th and
746
the j-th function in the list. (But if ``d[i] == j``: Fill the area
747
between the i-th function in the list and the horizontal line y = j.)
748
749
- ``fillcolor`` - (default: 'automatic') The color of the fill.
750
Either 'automatic' or a color.
751
752
- ``fillalpha`` - (default: 0.5) How transparent the fill is.
753
A number between 0 and 1.
754
755
Note that this function does NOT simply sample equally spaced
756
points between ``xmin`` and ``xmax``. Instead it computes equally spaced
757
points and add small perturbations to them. This reduces the
758
possibility of, e.g., sampling sin only at multiples of
759
`2\pi`, which would yield a very misleading graph.
760
761
EXAMPLES: We plot the sin function::
762
763
sage: P = plot(sin, (0,10)); print P
764
Graphics object consisting of 1 graphics primitive
765
sage: len(P) # number of graphics primitives
766
1
767
sage: len(P[0]) # how many points were computed (random)
768
225
769
sage: P # render
770
771
::
772
773
sage: P = plot(sin, (0,10), plot_points=10); print P
774
Graphics object consisting of 1 graphics primitive
775
sage: len(P[0]) # random output
776
32
777
sage: P # render
778
779
We plot with ``randomize=False``, which makes the initial sample points
780
evenly spaced (hence always the same). Adaptive plotting might
781
insert other points, however, unless ``adaptive_recursion=0``.
782
783
::
784
785
sage: p=plot(1, (x,0,3), plot_points=4, randomize=False, adaptive_recursion=0)
786
sage: list(p[0])
787
[(0.0, 1.0), (1.0, 1.0), (2.0, 1.0), (3.0, 1.0)]
788
789
Some colored functions::
790
791
sage: plot(sin, 0, 10, color='purple')
792
sage: plot(sin, 0, 10, color='#ff00ff')
793
794
We plot several functions together by passing a list of functions
795
as input::
796
797
sage: plot([sin(n*x) for n in [1..4]], (0, pi))
798
799
We can also build a plot step by step from an empty plot::
800
801
sage: a = plot([]); a # passing an empty list returns an empty plot (Graphics() object)
802
sage: a += plot(x**2); a # append another plot
803
sage: a += plot(x**3); a # append yet another plot
804
805
806
The function `\sin(1/x)` wiggles wildly near `0`.
807
Sage adapts to this and plots extra points near the origin.
808
809
::
810
811
sage: plot(sin(1/x), (x, -1, 1))
812
813
Via the matplotlib library, Sage makes it easy to tell whether
814
a graph is on both sides of both axes, as the axes only cross
815
if the origin is actually part of the viewing area::
816
817
sage: plot(x^3,(x,0,2)) # this one has the origin
818
sage: plot(x^3,(x,1,2)) # this one does not
819
820
Another thing to be aware of with axis labeling is that when
821
the labels have quite different orders of magnitude or are very
822
large, scientific notation (the `e` notation for powers of ten) is used::
823
824
sage: plot(x^2,(x,480,500)) # this one has no scientific notation
825
sage: plot(x^2,(x,300,500)) # this one has scientific notation on y-axis
826
827
You can put a legend with ``legend_label`` (the legend is only put
828
once in the case of multiple functions)::
829
830
sage: plot(exp(x), 0, 2, legend_label='$e^x$')
831
832
Sage understands TeX, so these all are slightly different, and you can choose
833
one based on your needs::
834
835
sage: plot(sin, legend_label='sin')
836
sage: plot(sin, legend_label='$sin$')
837
sage: plot(sin, legend_label='$\sin$')
838
839
It is possible to use a different color for the text of each label::
840
841
sage: p1 = plot(sin, legend_label='sin', legend_color='red')
842
sage: p2 = plot(cos, legend_label='cos', legend_color='green')
843
sage: p1 + p2
844
845
Note that the independent variable may be omitted if there is no
846
ambiguity::
847
848
sage: plot(sin(1/x), (-1, 1))
849
850
Plotting in logarithmic scale is possible for 2D plots. There
851
are two different syntaxes supported::
852
853
sage: plot(exp, (1, 10), scale='semilogy') # log axis on vertical
854
855
::
856
857
sage: plot_semilogy(exp, (1, 10)) # same thing
858
859
::
860
861
sage: plot_loglog(exp, (1, 10)) # both axes are log
862
863
::
864
865
sage: plot(exp, (1, 10), scale='loglog', base=2) # base of log is 2
866
867
We can also change the scale of the axes in the graphics just before
868
displaying::
869
870
sage: G = plot(exp, 1, 10)
871
sage: G.show(scale=('semilogy', 2))
872
873
The algorithm used to insert extra points is actually pretty
874
simple. On the picture drawn by the lines below::
875
876
sage: p = plot(x^2, (-0.5, 1.4)) + line([(0,0), (1,1)], color='green')
877
sage: p += line([(0.5, 0.5), (0.5, 0.5^2)], color='purple')
878
sage: p += point(((0, 0), (0.5, 0.5), (0.5, 0.5^2), (1, 1)), color='red', pointsize=20)
879
sage: p += text('A', (-0.05, 0.1), color='red')
880
sage: p += text('B', (1.01, 1.1), color='red')
881
sage: p += text('C', (0.48, 0.57), color='red')
882
sage: p += text('D', (0.53, 0.18), color='red')
883
sage: p.show(axes=False, xmin=-0.5, xmax=1.4, ymin=0, ymax=2)
884
885
You have the function (in blue) and its approximation (in green)
886
passing through the points A and B. The algorithm finds the
887
midpoint C of AB and computes the distance between C and D. If that
888
distance exceeds the ``adaptive_tolerance`` threshold (*relative* to
889
the size of the initial plot subintervals), the point D is
890
added to the curve. If D is added to the curve, then the
891
algorithm is applied recursively to the points A and D, and D and
892
B. It is repeated ``adaptive_recursion`` times (5, by default).
893
894
The actual sample points are slightly randomized, so the above
895
plots may look slightly different each time you draw them.
896
897
We draw the graph of an elliptic curve as the union of graphs of 2
898
functions.
899
900
::
901
902
sage: def h1(x): return abs(sqrt(x^3 - 1))
903
sage: def h2(x): return -abs(sqrt(x^3 - 1))
904
sage: P = plot([h1, h2], 1,4)
905
sage: P # show the result
906
907
We can also directly plot the elliptic curve::
908
909
sage: E = EllipticCurve([0,-1])
910
sage: plot(E, (1, 4), color=hue(0.6))
911
912
We can change the line style as well::
913
914
sage: plot(sin(x), (x, 0, 10), linestyle='-.')
915
916
If we have an empty linestyle and specify a marker, we can see the
917
points that are actually being plotted::
918
919
sage: plot(sin(x), (x,0,10), plot_points=20, linestyle='', marker='.')
920
921
The marker can be a TeX symbol as well::
922
923
sage: plot(sin(x), (x,0,10), plot_points=20, linestyle='', marker=r'$\checkmark$')
924
925
Sage currently ignores points that cannot be evaluated
926
927
::
928
929
sage: set_verbose(-1)
930
sage: plot(-x*log(x), (x,0,1)) # this works fine since the failed endpoint is just skipped.
931
sage: set_verbose(0)
932
933
This prints out a warning and plots where it can (we turn off the
934
warning by setting the verbose mode temporarily to -1.)
935
936
::
937
938
sage: set_verbose(-1)
939
sage: plot(x^(1/3), (x,-1,1))
940
sage: set_verbose(0)
941
942
To plot the negative real cube root, use something like the following::
943
944
sage: plot(lambda x : RR(x).nth_root(3), (x,-1, 1))
945
946
Another way to avoid getting complex numbers for negative input is to
947
calculate for the positive and negate the answer::
948
949
sage: plot(sign(x)*abs(x)^(1/3),-1,1)
950
951
We can detect the poles of a function::
952
953
sage: plot(gamma, (-3, 4), detect_poles = True).show(ymin = -5, ymax = 5)
954
955
We draw the Gamma-Function with its poles highlighted::
956
957
sage: plot(gamma, (-3, 4), detect_poles = 'show').show(ymin = -5, ymax = 5)
958
959
The basic options for filling a plot::
960
961
sage: p1 = plot(sin(x), -pi, pi, fill = 'axis')
962
sage: p2 = plot(sin(x), -pi, pi, fill = 'min')
963
sage: p3 = plot(sin(x), -pi, pi, fill = 'max')
964
sage: p4 = plot(sin(x), -pi, pi, fill = 0.5)
965
sage: graphics_array([[p1, p2], [p3, p4]]).show(frame=True, axes=False)
966
967
sage: plot([sin(x), cos(2*x)*sin(4*x)], -pi, pi, fill = {0: 1}, fillcolor = 'red', fillalpha = 1)
968
969
A example about the growth of prime numbers::
970
971
sage: plot(1.13*log(x), 1, 100, fill = lambda x: nth_prime(x)/floor(x), fillcolor = 'red')
972
973
Fill the area between a function and its asymptote::
974
975
sage: f = (2*x^3+2*x-1)/((x-2)*(x+1))
976
sage: plot([f, 2*x+2], -7,7, fill = {0: [1]}, fillcolor='#ccc').show(ymin=-20, ymax=20)
977
978
Fill the area between a list of functions and the x-axis::
979
980
sage: def b(n): return lambda x: bessel_J(n, x)
981
sage: plot([b(n) for n in [1..5]], 0, 20, fill = 'axis')
982
983
Note that to fill between the ith and jth functions, you
984
must use dictionary key-value pairs ``i:[j]``; key-value pairs
985
like ``i:j`` will fill between the ith function and the line y=j::
986
987
sage: def b(n): return lambda x: bessel_J(n, x) + 0.5*(n-1)
988
sage: plot([b(c) for c in [1..5]], 0, 40, fill = dict([(i, [i+1]) for i in [0..3]]))
989
sage: plot([b(c) for c in [1..5]], 0, 40, fill = dict([(i, i+1) for i in [0..3]]))
990
991
Extra options will get passed on to :meth:`~sage.plot.graphics.Graphics.show`,
992
as long as they are valid::
993
994
sage: plot(sin(x^2), (x, -3, 3), title='Plot of $\sin(x^2)$', axes_labels=['$x$','$y$']) # These labels will be nicely typeset
995
sage: plot(sin(x^2), (x, -3, 3), title='Plot of sin(x^2)', axes_labels=['x','y']) # These will not
996
997
::
998
999
sage: plot(sin(x^2), (x, -3, 3), figsize=[8,2])
1000
sage: plot(sin(x^2), (x, -3, 3)).show(figsize=[8,2]) # These are equivalent
1001
1002
This includes options for custom ticks and formatting. See documentation
1003
for :meth:`show` for more details.
1004
1005
::
1006
1007
sage: plot(sin(pi*x), (x, -8, 8), ticks=[[-7,-3,0,3,7],[-1/2,0,1/2]])
1008
sage: plot(2*x+1,(x,0,5),ticks=[[0,1,e,pi,sqrt(20)],2],tick_formatter="latex")
1009
1010
This is particularly useful when setting custom ticks in multiples of `pi`.
1011
1012
::
1013
1014
sage: plot(sin(x),(x,0,2*pi),ticks=pi/3,tick_formatter=pi)
1015
1016
You can even have custom tick labels along with custom positioning. ::
1017
1018
sage: plot(x**2, (x,0,3), ticks=[[1,2.5],[0.5,1,2]], tick_formatter=[["$x_1$","$x_2$"],["$y_1$","$y_2$","$y_3$"]])
1019
1020
You can force Type 1 fonts in your figures by providing the relevant
1021
option as shown below. This also requires that LaTeX, dvipng and
1022
Ghostscript be installed::
1023
1024
sage: plot(x, typeset='type1') # optional - latex
1025
1026
A example with excluded values::
1027
1028
sage: plot(floor(x), (x, 1, 10), exclude = [1..10])
1029
1030
We exclude all points where :class:`~sage.functions.prime_pi.PrimePi`
1031
makes a jump::
1032
1033
sage: jumps = [n for n in [1..100] if prime_pi(n) != prime_pi(n-1)]
1034
sage: plot(lambda x: prime_pi(x), (x, 1, 100), exclude = jumps)
1035
1036
Excluded points can also be given by an equation::
1037
1038
sage: g(x) = x^2-2*x-2
1039
sage: plot(1/g(x), (x, -3, 4), exclude = g(x) == 0, ymin = -5, ymax = 5)
1040
1041
``exclude`` and ``detect_poles`` can be used together::
1042
1043
sage: f(x) = (floor(x)+0.5) / (1-(x-0.5)^2)
1044
sage: plot(f, (x, -3.5, 3.5), detect_poles = 'show', exclude = [-3..3], ymin = -5, ymax = 5)
1045
1046
TESTS:
1047
1048
We do not randomize the endpoints::
1049
1050
sage: p = plot(x, (x,-1,1))
1051
sage: p[0].xdata[0] == -1
1052
True
1053
sage: p[0].xdata[-1] == 1
1054
True
1055
1056
We check to make sure that the x/y min/max data get set correctly
1057
when there are multiple functions.
1058
1059
::
1060
1061
sage: d = plot([sin(x), cos(x)], 100, 120).get_minmax_data()
1062
sage: d['xmin']
1063
100.0
1064
sage: d['xmax']
1065
120.0
1066
1067
We check various combinations of tuples and functions, ending with
1068
tests that lambda functions work properly with explicit variable
1069
declaration, without a tuple.
1070
1071
::
1072
1073
sage: p = plot(lambda x: x,(x,-1,1))
1074
sage: p = plot(lambda x: x,-1,1)
1075
sage: p = plot(x,x,-1,1)
1076
sage: p = plot(x,-1,1)
1077
sage: p = plot(x^2,x,-1,1)
1078
sage: p = plot(x^2,xmin=-1,xmax=2)
1079
sage: p = plot(lambda x: x,x,-1,1)
1080
sage: p = plot(lambda x: x^2,x,-1,1)
1081
sage: p = plot(lambda x: 1/x,x,-1,1)
1082
sage: f(x) = sin(x+3)-.1*x^3
1083
sage: p = plot(lambda x: f(x),x,-1,1)
1084
1085
We check to handle cases where the function gets evaluated at a
1086
point which causes an 'inf' or '-inf' result to be produced.
1087
1088
::
1089
1090
sage: p = plot(1/x, 0, 1)
1091
sage: p = plot(-1/x, 0, 1)
1092
1093
Bad options now give better errors::
1094
1095
sage: P = plot(sin(1/x), (x,-1,3), foo=10)
1096
Traceback (most recent call last):
1097
...
1098
RuntimeError: Error in line(): option 'foo' not valid.
1099
sage: P = plot(x, (x,1,1)) # trac ticket #11753
1100
Traceback (most recent call last):
1101
...
1102
ValueError: plot start point and end point must be different
1103
1104
We test that we can plot `f(x)=x` (see :trac:`10246`)::
1105
1106
sage: f(x)=x; f
1107
x |--> x
1108
sage: plot(f,(x,-1,1))
1109
"""
1110
G_kwds = Graphics._extract_kwds_for_show(kwds, ignore=['xmin', 'xmax'])
1111
1112
original_opts = kwds.pop('__original_opts', {})
1113
do_show = kwds.pop('show',False)
1114
1115
from sage.structure.element import is_Vector
1116
if kwds.get('parametric',False) and is_Vector(funcs):
1117
funcs = tuple(funcs)
1118
1119
1120
if hasattr(funcs, 'plot'):
1121
G = funcs.plot(*args, **original_opts)
1122
# if we are using the generic plotting method
1123
else:
1124
n = len(args)
1125
# if there are no extra args, try to get xmin,xmax from
1126
# keyword arguments or pick some silly default
1127
if n == 0:
1128
xmin = kwds.pop('xmin', -1)
1129
xmax = kwds.pop('xmax', 1)
1130
G = _plot(funcs, (xmin, xmax), **kwds)
1131
1132
# if there is one extra arg, then it had better be a tuple
1133
elif n == 1:
1134
G = _plot(funcs, *args, **kwds)
1135
elif n == 2:
1136
# if there are two extra args, then pull them out and pass them as a tuple
1137
xmin = args[0]
1138
xmax = args[1]
1139
args = args[2:]
1140
G = _plot(funcs, (xmin, xmax), *args, **kwds)
1141
elif n == 3:
1142
# if there are three extra args, then pull them out and pass them as a tuple
1143
var = args[0]
1144
xmin = args[1]
1145
xmax = args[2]
1146
args = args[3:]
1147
G = _plot(funcs, (var, xmin, xmax), *args, **kwds)
1148
elif ('xmin' in kwds) or ('xmax' in kwds):
1149
xmin = kwds.pop('xmin', -1)
1150
xmax = kwds.pop('xmax', 1)
1151
G = _plot(funcs, (xmin, xmax), *args, **kwds)
1152
pass
1153
else:
1154
sage.misc.misc.verbose("there were %s extra arguments (besides %s)" % (n, funcs), level=0)
1155
1156
G._set_extra_kwds(G_kwds)
1157
if do_show:
1158
G.show()
1159
return G
1160
1161
1162
def _plot(funcs, xrange, parametric=False,
1163
polar=False, fill=False, label='', randomize=True, **options):
1164
"""
1165
Internal function which does the actual plotting.
1166
1167
INPUT:
1168
1169
- ``funcs`` - function or list of functions to be plotted
1170
- ``xrange`` - two or three tuple of [input variable], min and max
1171
- ``parametric`` - (default: False) a boolean for whether
1172
this is a parametric plot
1173
- ``polar`` - (default: False) a boolean for whether
1174
this is a polar plot
1175
- ``fill`` - (default: False) an input for whether
1176
this plot is filled
1177
- ``randomize`` - (default: True) a boolean for whether
1178
to use random plot points
1179
1180
The following option is deprecated in favor of ``legend_label``:
1181
1182
- ``label`` - (default: '') a string for the label
1183
1184
All other usual plot options are also accepted, and a number
1185
are required (see the example below) which are normally passed
1186
through the options decorator to :func:`plot`.
1187
1188
OUTPUT:
1189
1190
- A ``Graphics`` object
1191
1192
EXAMPLES::
1193
1194
See :func:`plot` for many, many implicit examples.
1195
Here is an explicit one::
1196
1197
sage: from sage.plot.plot import _plot
1198
sage: P = _plot(e^(-x^2),(-3,3),fill=True,color='red',plot_points=50,adaptive_tolerance=2,adaptive_recursion=True,exclude=None)
1199
sage: P.show(aspect_ratio='automatic')
1200
1201
TESTS:
1202
1203
Make sure that we get the right number of legend entries as the number of
1204
functions varies (:trac:`10514`)::
1205
1206
sage: p1 = plot(1*x, legend_label='1x')
1207
sage: p2 = plot(2*x, legend_label='2x', color='green')
1208
sage: p1+p2
1209
1210
::
1211
1212
sage: len(p1.matplotlib().axes[0].legend().texts)
1213
1
1214
sage: len((p1+p2).matplotlib().axes[0].legend().texts)
1215
2
1216
sage: q1 = plot([sin(x), tan(x)], legend_label='trig')
1217
sage: len((q1).matplotlib().axes[0].legend().texts) # used to raise AttributeError
1218
1
1219
sage: q1
1220
1221
::
1222
1223
Make sure that we don't get multiple legend labels for plot segments
1224
(:trac:`11998`)::
1225
1226
sage: p1 = plot(1/(x^2-1),(x,-2,2),legend_label="foo",detect_poles=True)
1227
sage: len(p1.matplotlib().axes[0].legend().texts)
1228
1
1229
sage: p1.show(ymin=-10,ymax=10) # should be one legend
1230
1231
"""
1232
1233
from sage.plot.misc import setup_for_eval_on_grid
1234
if funcs == []:
1235
return Graphics()
1236
funcs, ranges = setup_for_eval_on_grid(funcs, [xrange], options['plot_points'])
1237
xmin, xmax, delta = ranges[0]
1238
xrange=ranges[0][:2]
1239
#parametric_plot will be a list or tuple of two functions (f,g)
1240
#and will plotted as (f(x), g(x)) for all x in the given range
1241
if parametric:
1242
f, g = funcs
1243
#or we have only a single function to be plotted:
1244
else:
1245
f = funcs
1246
1247
#check to see if funcs is a list of functions that will
1248
#be all plotted together.
1249
if isinstance(funcs, (list, tuple)) and not parametric:
1250
from sage.plot.colors import rainbow
1251
rainbow_colors = rainbow(len(funcs))
1252
1253
G = Graphics()
1254
for i, h in enumerate(funcs):
1255
if isinstance(fill, dict):
1256
if i in fill:
1257
fill_entry = fill[i]
1258
if isinstance(fill_entry, list):
1259
if fill_entry[0] < len(funcs):
1260
fill_temp = funcs[fill_entry[0]]
1261
else:
1262
fill_temp = None
1263
else:
1264
fill_temp = fill_entry
1265
else:
1266
fill_temp = None
1267
else:
1268
fill_temp = fill
1269
1270
options_temp = options.copy()
1271
fillcolor_temp = options_temp.pop('fillcolor', 'automatic')
1272
if i >= 1:
1273
legend_label=options_temp.pop('legend_label', None) # legend_label popped so the label isn't repeated for nothing
1274
if fillcolor_temp == 'automatic':
1275
fillcolor_temp = rainbow_colors[i]
1276
1277
G += plot(h, xrange, polar = polar, fill = fill_temp, \
1278
fillcolor = fillcolor_temp, **options_temp)
1279
return G
1280
1281
adaptive_tolerance = options.pop('adaptive_tolerance')
1282
adaptive_recursion = options.pop('adaptive_recursion')
1283
plot_points = int(options.pop('plot_points'))
1284
1285
exclude = options.pop('exclude')
1286
if exclude is not None:
1287
from sage.symbolic.expression import Expression
1288
if isinstance(exclude, Expression) and exclude.is_relational() == True:
1289
if len(exclude.variables()) > 1:
1290
raise ValueError('exclude has to be an equation of only one variable')
1291
v = exclude.variables()[0]
1292
points = [e.right() for e in exclude.solve(v) if e.left() == v and (v not in e.right().variables())]
1293
# We are only interested in real solutions
1294
exclude = []
1295
for x in points:
1296
try:
1297
exclude.append(float(x))
1298
except TypeError:
1299
pass
1300
1301
if isinstance(exclude, (list, tuple)):
1302
exclude = sorted(exclude)
1303
# We make sure that points plot points close to the excluded points are computed
1304
epsilon = 0.001*(xmax - xmin)
1305
initial_points = reduce(lambda a,b: a+b, [[x - epsilon, x + epsilon] for x in exclude], [])
1306
data = generate_plot_points(f, xrange, plot_points, adaptive_tolerance, adaptive_recursion, randomize, initial_points)
1307
else:
1308
raise ValueError('exclude needs to be a list of numbers or an equation')
1309
1310
if exclude == []:
1311
exclude = None
1312
else:
1313
data = generate_plot_points(f, xrange, plot_points, adaptive_tolerance, adaptive_recursion, randomize)
1314
1315
if parametric:
1316
# We need the original x-values to be able to exclude points in parametric plots
1317
exclude_data = data
1318
data = [(fdata, g(x)) for x, fdata in data]
1319
1320
G = Graphics()
1321
1322
fillcolor = options.pop('fillcolor', 'automatic')
1323
fillalpha = options.pop('fillalpha', 0.5)
1324
1325
# TODO: Use matplotlib's fill and fill_between commands.
1326
if fill is not False and fill is not None:
1327
if parametric:
1328
filldata = data
1329
else:
1330
if fill == 'axis' or fill is True:
1331
base_level = 0
1332
elif fill == 'min':
1333
base_level = min(t[1] for t in data)
1334
elif fill == 'max':
1335
base_level = max(t[1] for t in data)
1336
elif hasattr(fill, '__call__'):
1337
if fill == max or fill == min:
1338
if fill == max:
1339
fstr = 'max'
1340
else:
1341
fstr = 'min'
1342
msg = "WARNING: You use the built-in function %s for filling. You probably wanted the string '%s'." % (fstr, fstr)
1343
sage.misc.misc.verbose(msg, level=0)
1344
if not is_fast_float(fill):
1345
fill_f = fast_float(fill, expect_one_var=True)
1346
else:
1347
fill_f = fill
1348
1349
filldata = generate_plot_points(fill_f, xrange, plot_points, adaptive_tolerance, \
1350
adaptive_recursion, randomize)
1351
filldata.reverse()
1352
filldata += data
1353
else:
1354
try:
1355
base_level = float(fill)
1356
except TypeError:
1357
base_level = 0
1358
1359
if not hasattr(fill, '__call__') and polar:
1360
filldata = generate_plot_points(lambda x: base_level, xrange, plot_points, adaptive_tolerance, \
1361
adaptive_recursion, randomize)
1362
filldata.reverse()
1363
filldata += data
1364
if not hasattr(fill, '__call__') and not polar:
1365
filldata = [(data[0][0], base_level)] + data + [(data[-1][0], base_level)]
1366
1367
if fillcolor == 'automatic':
1368
fillcolor = (0.5, 0.5, 0.5)
1369
fill_options = {}
1370
fill_options['rgbcolor'] = fillcolor
1371
fill_options['alpha'] = fillalpha
1372
fill_options['thickness'] = 0
1373
if polar:
1374
filldata = [(y*cos(x), y*sin(x)) for x, y in filldata]
1375
G += polygon(filldata, **fill_options)
1376
1377
# We need the original data to be able to exclude points in polar plots
1378
if not parametric:
1379
exclude_data = data
1380
if polar:
1381
data = [(y*cos(x), y*sin(x)) for x, y in data]
1382
1383
from sage.plot.all import line, text
1384
1385
detect_poles = options.pop('detect_poles', False)
1386
legend_label = options.pop('legend_label', None)
1387
if exclude is not None or detect_poles != False:
1388
start_index = 0
1389
# setup for pole detection
1390
from sage.rings.all import RDF
1391
epsilon = 0.0001
1392
pole_options = {}
1393
pole_options['linestyle'] = '--'
1394
pole_options['thickness'] = 1
1395
pole_options['rgbcolor'] = '#ccc'
1396
1397
# setup for exclusion points
1398
exclusion_point = 0
1399
if exclude is not None:
1400
exclude.reverse()
1401
exclusion_point = exclude.pop()
1402
1403
for i in range(len(data)-1):
1404
x0, y0 = exclude_data[i]
1405
x1, y1 = exclude_data[i+1]
1406
# detect poles
1407
if (not (polar or parametric)) and detect_poles != False \
1408
and ((y1 > 0 and y0 < 0) or (y1 < 0 and y0 > 0)):
1409
# calculate the slope of the line segment
1410
dy = abs(y1-y0)
1411
dx = x1 - x0
1412
alpha = (RDF(dy)/RDF(dx)).arctan()
1413
if alpha >= RDF(pi/2) - epsilon:
1414
G += line(data[start_index:i], **options)
1415
if detect_poles == 'show':
1416
# draw a vertical asymptote
1417
G += line([(x0, y0), (x1, y1)], **pole_options)
1418
start_index = i+2
1419
1420
# exclude points
1421
if exclude is not None and (x0 <= exclusion_point <= x1):
1422
G += line(data[start_index:i], **options)
1423
start_index = i + 2
1424
try:
1425
exclusion_point = exclude.pop()
1426
except IndexError:
1427
# all excluded points were considered
1428
exclude = None
1429
1430
G += line(data[start_index:], legend_label=legend_label, **options)
1431
else:
1432
G += line(data, legend_label=legend_label, **options)
1433
1434
# Label?
1435
if label:
1436
from sage.misc.superseded import deprecation
1437
deprecation(4342, "Consider using legend_label instead")
1438
label = ' '+str(label)
1439
G += text(label, data[-1], horizontal_alignment='left',
1440
vertical_alignment='center')
1441
1442
return G
1443
1444
1445
1446
1447
########## misc functions ###################
1448
1449
@options(aspect_ratio=1.0)
1450
def parametric_plot(funcs, *args, **kwargs):
1451
r"""
1452
Plot a parametric curve or surface in 2d or 3d.
1453
1454
:func:`parametric_plot` takes two or three functions as a
1455
list or a tuple and makes a plot with the first function giving the
1456
`x` coordinates, the second function giving the `y`
1457
coordinates, and the third function (if present) giving the
1458
`z` coordinates.
1459
1460
In the 2d case, :func:`parametric_plot` is equivalent to the :func:`plot` command
1461
with the option ``parametric=True``. In the 3d case, :func:`parametric_plot`
1462
is equivalent to :func:`~sage.plot.plot3d.parametric_plot3d.parametric_plot3d`.
1463
See each of these functions for more help and examples.
1464
1465
INPUT:
1466
1467
1468
- ``funcs`` - 2 or 3-tuple of functions, or a vector of dimension 2 or 3.
1469
1470
- ``other options`` - passed to :func:`plot` or :func:`~sage.plot.plot3d.parametric_plot3d.parametric_plot3d`
1471
1472
1473
EXAMPLES: We draw some 2d parametric plots. Note that the default aspect ratio
1474
is 1, so that circles look like circles. ::
1475
1476
sage: t = var('t')
1477
sage: parametric_plot( (cos(t), sin(t)), (t, 0, 2*pi))
1478
1479
::
1480
1481
sage: parametric_plot( (sin(t), sin(2*t)), (t, 0, 2*pi), color=hue(0.6) )
1482
1483
::
1484
1485
sage: parametric_plot((1, t), (t, 0, 4))
1486
1487
Note that in parametric_plot, there is only fill or no fill.
1488
1489
::
1490
1491
sage: parametric_plot((t, t^2), (t, -4, 4), fill = True)
1492
1493
A filled Hypotrochoid::
1494
1495
sage: parametric_plot([cos(x) + 2 * cos(x/4), sin(x) - 2 * sin(x/4)], (x,0, 8*pi), fill = True)
1496
1497
sage: parametric_plot( (5*cos(x), 5*sin(x), x), (x,-12, 12), plot_points=150, color="red")
1498
1499
sage: y=var('y')
1500
sage: parametric_plot( (5*cos(x), x*y, cos(x*y)), (x, -4,4), (y,-4,4))
1501
1502
sage: t=var('t')
1503
sage: parametric_plot( vector((sin(t), sin(2*t))), (t, 0, 2*pi), color='green')
1504
sage: parametric_plot( vector([t, t+1, t^2]), (t, 0, 1))
1505
1506
Plotting in logarithmic scale is possible with 2D plots. The keyword
1507
``aspect_ratio`` will be ignored if the scale is not ``'loglog'`` or
1508
``'linear'``.::
1509
1510
sage: parametric_plot((x, x**2), (x, 1, 10), scale='loglog')
1511
1512
We can also change the scale of the axes in the graphics just before
1513
displaying. In this case, the ``aspect_ratio`` must be specified as
1514
``'automatic'`` if the ``scale`` is set to ``'semilogx'`` or ``'semilogy'``. For
1515
other values of the ``scale`` parameter, any ``aspect_ratio`` can be
1516
used, or the keyword need not be provided.::
1517
1518
sage: p = parametric_plot((x, x**2), (x, 1, 10))
1519
sage: p.show(scale='semilogy', aspect_ratio='automatic')
1520
1521
TESTS::
1522
1523
sage: parametric_plot((x, t^2), (x, -4, 4))
1524
Traceback (most recent call last):
1525
...
1526
ValueError: there are more variables than variable ranges
1527
1528
sage: parametric_plot((1, x+t), (x, -4, 4))
1529
Traceback (most recent call last):
1530
...
1531
ValueError: there are more variables than variable ranges
1532
1533
sage: parametric_plot((-t, x+t), (x, -4, 4))
1534
Traceback (most recent call last):
1535
...
1536
ValueError: there are more variables than variable ranges
1537
1538
sage: parametric_plot((1, x+t, y), (x, -4, 4), (t, -4, 4))
1539
Traceback (most recent call last):
1540
...
1541
ValueError: there are more variables than variable ranges
1542
1543
sage: parametric_plot((1, x, y), 0, 4)
1544
Traceback (most recent call last):
1545
...
1546
ValueError: there are more variables than variable ranges
1547
"""
1548
num_ranges=0
1549
for i in args:
1550
if isinstance(i, (list, tuple)):
1551
num_ranges+=1
1552
else:
1553
break
1554
1555
if num_ranges==0 and len(args)>=2:
1556
from sage.misc.superseded import deprecation
1557
deprecation(7008, "variable ranges to parametric_plot must be given as tuples, like (2,4) or (t,2,3)")
1558
args=tuple(args)
1559
num_ranges=1
1560
1561
num_funcs = len(funcs)
1562
1563
num_vars=len(sage.plot.misc.unify_arguments(funcs)[0])
1564
if num_vars>num_ranges:
1565
raise ValueError, "there are more variables than variable ranges"
1566
1567
# Reset aspect_ratio to 'automatic' in case scale is 'semilog[xy]'.
1568
# Otherwise matplotlib complains.
1569
scale = kwargs.get('scale', None)
1570
if isinstance(scale, (list, tuple)):
1571
scale = scale[0]
1572
if scale == 'semilogy' or scale == 'semilogx':
1573
kwargs['aspect_ratio'] = 'automatic'
1574
1575
if num_funcs == 2 and num_ranges == 1:
1576
kwargs['parametric'] = True
1577
return plot(funcs, *args, **kwargs)
1578
elif (num_funcs == 3 and num_ranges <= 2):
1579
return sage.plot.plot3d.parametric_plot3d.parametric_plot3d(funcs, *args, **kwargs)
1580
else:
1581
raise ValueError, "the number of functions and the number of variable ranges is not a supported combination for a 2d or 3d parametric plots"
1582
1583
@options(aspect_ratio=1.0)
1584
def polar_plot(funcs, *args, **kwds):
1585
r"""
1586
``polar_plot`` takes a single function or a list or
1587
tuple of functions and plots them with polar coordinates in the given
1588
domain.
1589
1590
This function is equivalent to the :func:`plot` command with the options
1591
``polar=True`` and ``aspect_ratio=1``. For more help on options,
1592
see the documentation for :func:`plot`.
1593
1594
INPUT:
1595
1596
- ``funcs`` - a function
1597
- other options are passed to plot
1598
1599
EXAMPLES:
1600
1601
Here is a blue 8-leaved petal::
1602
1603
sage: polar_plot(sin(5*x)^2, (x, 0, 2*pi), color='blue')
1604
1605
A red figure-8::
1606
1607
sage: polar_plot(abs(sqrt(1 - sin(x)^2)), (x, 0, 2*pi), color='red')
1608
1609
A green limacon of Pascal::
1610
1611
sage: polar_plot(2 + 2*cos(x), (x, 0, 2*pi), color=hue(0.3))
1612
1613
Several polar plots::
1614
1615
sage: polar_plot([2*sin(x), 2*cos(x)], (x, 0, 2*pi))
1616
1617
A filled spiral::
1618
1619
sage: polar_plot(sqrt, 0, 2 * pi, fill = True)
1620
1621
Fill the area between two functions::
1622
1623
sage: polar_plot(cos(4*x) + 1.5, 0, 2*pi, fill=0.5 * cos(4*x) + 2.5, fillcolor='orange')
1624
1625
Fill the area between several spirals::
1626
1627
sage: polar_plot([(1.2+k*0.2)*log(x) for k in range(6)], 1, 3 * pi, fill = {0: [1], 2: [3], 4: [5]})
1628
1629
Exclude points at discontinuities::
1630
1631
sage: polar_plot(log(floor(x)), (x, 1, 4*pi), exclude = [1..12])
1632
1633
"""
1634
kwds['polar']=True
1635
return plot(funcs, *args, **kwds)
1636
1637
@options(aspect_ratio='automatic')
1638
def list_plot(data, plotjoined=False, **kwargs):
1639
r"""
1640
``list_plot`` takes either a list of numbers, a list of tuples, a numpy
1641
array, or a dictionary and plots the corresponding points.
1642
1643
If given a list of numbers (that is, not a list of tuples or lists),
1644
``list_plot`` forms a list of tuples ``(i, x_i)`` where ``i`` goes from
1645
0 to ``len(data)-1`` and ``x_i`` is the ``i``-th data value, and puts
1646
points at those tuple values.
1647
1648
``list_plot`` will plot a list of complex numbers in the obvious
1649
way; any numbers for which
1650
:func:`CC()<sage.rings.complex_field.ComplexField>` makes sense will
1651
work.
1652
1653
``list_plot`` also takes a list of tuples ``(x_i, y_i)`` where ``x_i``
1654
and ``y_i`` are the ``i``-th values representing the ``x``- and
1655
``y``-values, respectively.
1656
1657
If given a dictionary, ``list_plot`` interprets the keys as
1658
`x`-values and the values as `y`-values.
1659
1660
The ``plotjoined=True`` option tells ``list_plot`` to plot a line
1661
joining all the data.
1662
1663
It is possible to pass empty dictionaries, lists, or tuples to
1664
``list_plot``. Doing so will plot nothing (returning an empty plot).
1665
1666
EXAMPLES::
1667
1668
sage: list_plot([i^2 for i in range(5)])
1669
1670
Here are a bunch of random red points::
1671
1672
sage: r = [(random(),random()) for _ in range(20)]
1673
sage: list_plot(r,color='red')
1674
1675
This gives all the random points joined in a purple line::
1676
1677
sage: list_plot(r, plotjoined=True, color='purple')
1678
1679
You can provide a numpy array.::
1680
1681
sage: import numpy
1682
sage: list_plot(numpy.arange(10))
1683
1684
sage: list_plot(numpy.array([[1,2], [2,3], [3,4]]))
1685
1686
Plot a list of complex numbers::
1687
1688
sage: list_plot([1, I, pi + I/2, CC(.25, .25)])
1689
1690
sage: list_plot([exp(I*theta) for theta in [0, .2..pi]])
1691
1692
Note that if your list of complex numbers are all actually real,
1693
they get plotted as real values, so this
1694
1695
::
1696
1697
sage: list_plot([CDF(1), CDF(1/2), CDF(1/3)])
1698
1699
is the same as ``list_plot([1, 1/2, 1/3])`` -- it produces a plot of
1700
the points `(0,1)`, `(1,1/2)`, and `(2,1/3)`.
1701
1702
If you have separate lists of `x` values and `y` values which you
1703
want to plot against each other, use the ``zip`` command to make a
1704
single list whose entries are pairs of `(x,y)` values, and feed
1705
the result into ``list_plot``::
1706
1707
sage: x_coords = [cos(t)^3 for t in srange(0, 2*pi, 0.02)]
1708
sage: y_coords = [sin(t)^3 for t in srange(0, 2*pi, 0.02)]
1709
sage: list_plot(zip(x_coords, y_coords))
1710
1711
If instead you try to pass the two lists as separate arguments,
1712
you will get an error message::
1713
1714
sage: list_plot(x_coords, y_coords)
1715
Traceback (most recent call last):
1716
...
1717
TypeError: The second argument 'plotjoined' should be boolean (True or False). If you meant to plot two lists 'x' and 'y' against each other, use 'list_plot(zip(x,y))'.
1718
1719
Dictionaries with numeric keys and values can be plotted::
1720
1721
sage: list_plot({22: 3365, 27: 3295, 37: 3135, 42: 3020, 47: 2880, 52: 2735, 57: 2550})
1722
1723
Plotting in logarithmic scale is possible for 2D list plots.
1724
There are two different syntaxes available::
1725
1726
sage: yl = [2**k for k in range(20)]
1727
sage: list_plot(yl, scale='semilogy') # log axis on vertical
1728
1729
::
1730
1731
sage: list_plot_semilogy(yl) # same
1732
1733
.. warning::
1734
1735
If ``plotjoined`` is ``False`` then the axis that is in log scale
1736
must have all points strictly positive. For instance, the following
1737
plot will show no points in the figure since the points in the
1738
horizontal axis starts from `(0,1)`.
1739
1740
::
1741
1742
sage: list_plot(yl, scale='loglog') # both axes are log
1743
1744
Instead this will work. We drop the point `(0,1)`.::
1745
1746
sage: list_plot(zip(range(1,len(yl)), yl[1:]), scale='loglog')
1747
1748
We use :func:`list_plot_loglog` and plot in a different base.::
1749
1750
sage: list_plot_loglog(zip(range(1,len(yl)), yl[1:]), base=2)
1751
1752
We can also change the scale of the axes in the graphics just before
1753
displaying::
1754
1755
sage: G = list_plot(yl)
1756
sage: G.show(scale=('semilogy', 2))
1757
1758
TESTS:
1759
1760
We check to see that the x/y min/max data are set correctly.
1761
1762
::
1763
1764
sage: d = list_plot([(100,100), (120, 120)]).get_minmax_data()
1765
sage: d['xmin']
1766
100.0
1767
sage: d['ymin']
1768
100.0
1769
"""
1770
from sage.plot.all import line, point
1771
try:
1772
if not data:
1773
return Graphics()
1774
except ValueError: # numpy raises ValueError if it is not empty
1775
pass
1776
if not isinstance(plotjoined, bool):
1777
raise TypeError("The second argument 'plotjoined' should be boolean "
1778
"(True or False). If you meant to plot two lists 'x' "
1779
"and 'y' against each other, use 'list_plot(zip(x,y))'.")
1780
if isinstance(data, dict):
1781
if plotjoined:
1782
list_data = sorted(list(data.iteritems()))
1783
else:
1784
list_data = list(data.iteritems())
1785
return list_plot(list_data, plotjoined=plotjoined, **kwargs)
1786
try:
1787
from sage.rings.all import RDF
1788
tmp = RDF(data[0])
1789
data = list(enumerate(data))
1790
except TypeError:
1791
pass
1792
try:
1793
if plotjoined:
1794
return line(data, **kwargs)
1795
else:
1796
return point(data, **kwargs)
1797
except (TypeError, IndexError):
1798
# Assume we have complex-valued input and plot real and imaginary parts.
1799
# Need to catch IndexError because if data is, say, [(0, 1), (1, I)],
1800
# point3d() throws an IndexError on the (0,1) before it ever
1801
# gets to (1, I).
1802
from sage.rings.complex_field import ComplexField
1803
CC = ComplexField()
1804
# if we get here, we already did "list(enumerate(data))",
1805
# so look at z[1] in inner list
1806
data = [(z.real(), z.imag()) for z in [CC(z[1]) for z in data]]
1807
if plotjoined:
1808
return line(data, **kwargs)
1809
else:
1810
return point(data, **kwargs)
1811
1812
#------------------------ Graphs on log scale ---------------------------#
1813
@options(base=10)
1814
def plot_loglog(funcs, *args, **kwds):
1815
"""
1816
Plot graphics in 'loglog' scale, that is, both the horizontal and the
1817
vertical axes will be in logarithmic scale.
1818
1819
INPUTS:
1820
1821
- ``base`` -- (default: 10) the base of the logarithm. This must be
1822
greater than 1. The base can be also given as a list or tuple
1823
``(basex, basey)``. ``basex`` sets the base of the logarithm along the
1824
horizontal axis and ``basey`` sets the base along the vertical axis.
1825
1826
- ``funcs`` -- any Sage object which is acceptable to the :func:`plot`.
1827
1828
For all other inputs, look at the documentation of :func:`plot`.
1829
1830
EXAMPLES::
1831
1832
sage: plot_loglog(exp, (1,10)) # plot in loglog scale with base 10
1833
1834
::
1835
1836
sage: plot_loglog(exp, (1,10), base=2.1) # with base 2.1 on both axes
1837
1838
::
1839
1840
sage: plot_loglog(exp, (1,10), base=(2,3))
1841
1842
"""
1843
return plot(funcs, *args, scale='loglog', **kwds)
1844
1845
@options(base=10)
1846
def plot_semilogx(funcs, *args, **kwds):
1847
"""
1848
Plot graphics in 'semilogx' scale, that is, the horizontal axis will be
1849
in logarithmic scale.
1850
1851
INPUTS:
1852
1853
- ``base`` -- (default: 10) the base of the logarithm. This must be
1854
greater than 1.
1855
1856
- ``funcs`` -- any Sage object which is acceptable to the :func:`plot`.
1857
1858
For all other inputs, look at the documentation of :func:`plot`.
1859
1860
EXAMPLES::
1861
1862
sage: plot_semilogx(exp, (1,10)) # plot in semilogx scale, base 10
1863
1864
::
1865
1866
sage: plot_semilogx(exp, (1,10), base=2) # with base 2
1867
1868
"""
1869
return plot(funcs, *args, scale='semilogx', **kwds)
1870
1871
@options(base=10)
1872
def plot_semilogy(funcs, *args, **kwds):
1873
"""
1874
Plot graphics in 'semilogy' scale, that is, the vertical axis will be
1875
in logarithmic scale.
1876
1877
INPUTS:
1878
1879
- ``base`` -- (default: 10) the base of the logarithm. This must be
1880
greater than 1.
1881
1882
- ``funcs`` -- any Sage object which is acceptable to the :func:`plot`.
1883
1884
For all other inputs, look at the documentation of :func:`plot`.
1885
1886
EXAMPLES::
1887
1888
sage: plot_semilogy(exp, (1,10)) # plot in semilogy scale, base 10
1889
1890
::
1891
1892
sage: plot_semilogy(exp, (1,10), base=2) # with base 2
1893
1894
"""
1895
return plot(funcs, *args, scale='semilogy', **kwds)
1896
1897
@options(base=10)
1898
def list_plot_loglog(data, plotjoined=False, **kwds):
1899
"""
1900
Plot the ``data`` in 'loglog' scale, that is, both the horizontal and the
1901
vertical axes will be in logarithmic scale.
1902
1903
INPUTS:
1904
1905
- ``base`` -- (default: 10) the base of the logarithm. This must be
1906
greater than 1. The base can be also given as a list or tuple
1907
``(basex, basey)``. ``basex`` sets the base of the logarithm along the
1908
horizontal axis and ``basey`` sets the base along the vertical axis.
1909
1910
For all other inputs, look at the documentation of :func:`list_plot`.
1911
1912
1913
EXAMPLES::
1914
1915
sage: yl = [5**k for k in range(10)]; xl = [2**k for k in range(10)]
1916
sage: list_plot_loglog(zip(xl, yl)) # plot in loglog scale with base 10
1917
1918
::
1919
1920
sage: list_plot_loglog(zip(xl, yl), base=2.1) # with base 2.1 on both axes
1921
1922
::
1923
1924
sage: list_plot_loglog(zip(xl, yl), base=(2,5))
1925
1926
.. warning::
1927
1928
If ``plotjoined`` is ``False`` then the axis that is in log scale
1929
must have all points strictly positive. For instance, the following
1930
plot will show no points in the figure since the points in the
1931
horizontal axis starts from `(0,1)`.
1932
1933
::
1934
1935
sage: yl = [2**k for k in range(20)]
1936
sage: list_plot_loglog(yl)
1937
1938
Instead this will work. We drop the point `(0,1)`.::
1939
1940
sage: list_plot_loglog(zip(range(1,len(yl)), yl[1:]))
1941
1942
"""
1943
return list_plot(data, plotjoined=plotjoined, scale='loglog', **kwds)
1944
1945
@options(base=10)
1946
def list_plot_semilogx(data, plotjoined=False, **kwds):
1947
"""
1948
Plot ``data`` in 'semilogx' scale, that is, the horizontal axis will be
1949
in logarithmic scale.
1950
1951
INPUTS:
1952
1953
- ``base`` -- (default: 10) the base of the logarithm. This must be
1954
greater than 1.
1955
1956
For all other inputs, look at the documentation of :func:`list_plot`.
1957
1958
EXAMPLES::
1959
1960
sage: yl = [2**k for k in range(12)]
1961
sage: list_plot_semilogx(zip(yl,yl))
1962
1963
.. warning::
1964
1965
If ``plotjoined`` is ``False`` then the horizontal axis must have all
1966
points strictly positive. Otherwise the plot will come up empty.
1967
For instance the following plot contains a point at `(0,1)`.
1968
1969
::
1970
1971
sage: yl = [2**k for k in range(12)]
1972
sage: list_plot_semilogx(yl) # plot is empty because of `(0,1)`
1973
1974
We remove `(0,1)` to fix this.::
1975
1976
sage: list_plot_semilogx(zip(range(1, len(yl)), yl[1:]))
1977
1978
::
1979
1980
sage: list_plot_semilogx([(1,2),(3,4),(3,-1),(25,3)], base=2) # with base 2
1981
1982
"""
1983
return list_plot(data, plotjoined=plotjoined, scale='semilogx', **kwds)
1984
1985
@options(base=10)
1986
def list_plot_semilogy(data, plotjoined=False, **kwds):
1987
"""
1988
Plot ``data`` in 'semilogy' scale, that is, the vertical axis will be
1989
in logarithmic scale.
1990
1991
INPUTS:
1992
1993
- ``base`` -- (default: 10) the base of the logarithm. This must be
1994
greater than 1.
1995
1996
For all other inputs, look at the documentation of :func:`list_plot`.
1997
1998
EXAMPLES::
1999
2000
sage: yl = [2**k for k in range(12)]
2001
sage: list_plot_semilogy(yl) # plot in semilogy scale, base 10
2002
2003
.. warning::
2004
2005
If ``plotjoined`` is ``False`` then the vertical axis must have all
2006
points strictly positive. Otherwise the plot will come up empty.
2007
For instance the following plot contains a point at `(1,0)`.
2008
2009
::
2010
2011
sage: xl = [2**k for k in range(12)]; yl = range(len(xl))
2012
sage: list_plot_semilogy(zip(xl,yl)) # plot empty due to (1,0)
2013
2014
We remove `(1,0)` to fix this.::
2015
2016
sage: list_plot_semilogy(zip(xl[1:],yl[1:]))
2017
2018
2019
::
2020
2021
sage: list_plot_semilogy([2, 4, 6, 8, 16, 31], base=2) # with base 2
2022
2023
"""
2024
return list_plot(data, plotjoined=plotjoined, scale='semilogy', **kwds)
2025
2026
def to_float_list(v):
2027
"""
2028
Given a list or tuple or iterable v, coerce each element of v to a
2029
float and make a list out of the result.
2030
2031
EXAMPLES::
2032
2033
sage: from sage.plot.plot import to_float_list
2034
sage: to_float_list([1,1/2,3])
2035
[1.0, 0.5, 3.0]
2036
"""
2037
return [float(x) for x in v]
2038
2039
2040
def reshape(v, n, m):
2041
"""
2042
Helper function for creating graphics arrays.
2043
2044
The input array is flattened and turned into an `n\times m`
2045
array, with blank graphics object padded at the end, if
2046
necessary.
2047
2048
INPUT:
2049
2050
- ``v`` - a list of lists or tuples
2051
2052
- ``n, m`` - integers
2053
2054
OUTPUT:
2055
2056
A list of lists of graphics objects
2057
2058
EXAMPLES::
2059
2060
sage: L = [plot(sin(k*x),(x,-pi,pi)) for k in range(10)]
2061
sage: graphics_array(L,3,4) # long time (up to 4s on sage.math, 2012)
2062
2063
::
2064
2065
sage: M = [[plot(sin(k*x),(x,-pi,pi)) for k in range(3)],[plot(cos(j*x),(x,-pi,pi)) for j in [3..5]]]
2066
sage: graphics_array(M,6,1) # long time (up to 4s on sage.math, 2012)
2067
2068
TESTS::
2069
2070
sage: L = [plot(sin(k*x),(x,-pi,pi)) for k in [1..3]]
2071
sage: graphics_array(L,0,-1) # indirect doctest
2072
Traceback (most recent call last):
2073
...
2074
AssertionError: array sizes must be positive
2075
"""
2076
assert n>0 and m>0, 'array sizes must be positive'
2077
G = Graphics()
2078
G.axes(False)
2079
if len(v) == 0:
2080
return [[G]*m]*n
2081
2082
if not isinstance(v[0], Graphics):
2083
# a list of lists -- flatten it
2084
v = sum([list(x) for x in v], [])
2085
2086
# Now v should be a single list.
2087
# First, make it have the right length.
2088
for i in xrange(n*m - len(v)):
2089
v.append(G)
2090
2091
# Next, create a list of lists out of it.
2092
L = []
2093
k = 0
2094
for i in range(n):
2095
w = []
2096
for j in range(m):
2097
w.append(v[k])
2098
k += 1
2099
L.append(w)
2100
2101
return L
2102
2103
def graphics_array(array, n=None, m=None):
2104
r"""
2105
``graphics_array`` take a list of lists (or tuples) of
2106
graphics objects and plots them all on one canvas (single plot).
2107
2108
INPUT:
2109
2110
- ``array`` - a list of lists or tuples
2111
2112
- ``n, m`` - (optional) integers - if n and m are
2113
given then the input array is flattened and turned into an n x m
2114
array, with blank graphics objects padded at the end, if
2115
necessary.
2116
2117
2118
EXAMPLE: Make some plots of `\sin` functions::
2119
2120
sage: f(x) = sin(x)
2121
sage: g(x) = sin(2*x)
2122
sage: h(x) = sin(4*x)
2123
sage: p1 = plot(f,(-2*pi,2*pi),color=hue(0.5))
2124
sage: p2 = plot(g,(-2*pi,2*pi),color=hue(0.9))
2125
sage: p3 = parametric_plot((f,g),(0,2*pi),color=hue(0.6))
2126
sage: p4 = parametric_plot((f,h),(0,2*pi),color=hue(1.0))
2127
2128
Now make a graphics array out of the plots::
2129
2130
sage: graphics_array(((p1,p2),(p3,p4)))
2131
2132
One can also name the array, and then use :meth:`~sage.plot.graphics.GraphicsArray.show`
2133
or :meth:`~sage.plot.graphics.GraphicsArray.save`::
2134
2135
sage: ga = graphics_array(((p1,p2),(p3,p4)))
2136
sage: ga.show()
2137
2138
Here we give only one row::
2139
2140
sage: p1 = plot(sin,(-4,4))
2141
sage: p2 = plot(cos,(-4,4))
2142
sage: g = graphics_array([p1, p2]); print g
2143
Graphics Array of size 1 x 2
2144
sage: g.show()
2145
2146
It is possible to use ``figsize`` to change the size of the plot
2147
as a whole::
2148
2149
sage: L = [plot(sin(k*x),(x,-pi,pi)) for k in [1..3]]
2150
sage: G = graphics_array(L)
2151
sage: G.show(figsize=[5,3]) # smallish and compact
2152
2153
::
2154
2155
sage: G.show(figsize=[10,20]) # bigger and tall and thin; long time (2s on sage.math, 2012)
2156
2157
::
2158
2159
sage: G.show(figsize=8) # figure as a whole is a square
2160
"""
2161
if not n is None:
2162
# Flatten then reshape input
2163
n = int(n)
2164
m = int(m)
2165
array = reshape(array, n, m)
2166
return GraphicsArray(array)
2167
2168
def var_and_list_of_values(v, plot_points):
2169
"""
2170
INPUT:
2171
2172
2173
- ``v`` - (v0, v1) or (var, v0, v1); if the former
2174
return the range of values between v0 and v1 taking plot_points
2175
steps; if var is given, also return var.
2176
2177
- ``plot_points`` - integer = 2 (the endpoints)
2178
2179
2180
OUTPUT:
2181
2182
2183
- ``var`` - a variable or None
2184
2185
- ``list`` - a list of floats
2186
2187
2188
EXAMPLES::
2189
2190
sage: from sage.plot.plot import var_and_list_of_values
2191
sage: var_and_list_of_values((var('theta'), 2, 5), 5)
2192
doctest:...: DeprecationWarning: var_and_list_of_values is deprecated. Please use sage.plot.misc.setup_for_eval_on_grid; note that that function has slightly different calling and return conventions which make it more generally applicable
2193
See http://trac.sagemath.org/7008 for details.
2194
(theta, [2.0, 2.75, 3.5, 4.25, 5.0])
2195
sage: var_and_list_of_values((2, 5), 5)
2196
(None, [2.0, 2.75, 3.5, 4.25, 5.0])
2197
sage: var_and_list_of_values((var('theta'), 2, 5), 2)
2198
(theta, [2.0, 5.0])
2199
sage: var_and_list_of_values((2, 5), 2)
2200
(None, [2.0, 5.0])
2201
"""
2202
from sage.misc.superseded import deprecation
2203
deprecation(7008, "var_and_list_of_values is deprecated. Please use sage.plot.misc.setup_for_eval_on_grid; note that that function has slightly different calling and return conventions which make it more generally applicable")
2204
plot_points = int(plot_points)
2205
if plot_points < 2:
2206
raise ValueError, "plot_points must be greater than 1"
2207
if not isinstance(v, (tuple, list)):
2208
raise TypeError, "v must be a tuple or list"
2209
if len(v) == 3:
2210
var = v[0]
2211
a, b = v[1], v[2]
2212
elif len(v) == 2:
2213
var = None
2214
a, b = v
2215
else:
2216
raise ValueError, "parametric value range must be a list or tuple of length 2 or 3."
2217
2218
a = float(a)
2219
b = float(b)
2220
if plot_points == 2:
2221
return var, [a, b]
2222
else:
2223
step = (b-a)/float(plot_points-1)
2224
values = [a + step*i for i in xrange(plot_points)]
2225
return var, values
2226
2227
2228
2229
def setup_for_eval_on_grid(v, xrange, yrange, plot_points):
2230
"""
2231
This function is deprecated. Please use
2232
``sage.plot.misc.setup_for_eval_on_grid`` instead. Please note that
2233
that function has slightly different calling and return
2234
conventions which make it more generally applicable.
2235
2236
INPUT:
2237
2238
2239
- ``v`` - a list of functions
2240
2241
- ``xrange`` - 2 or 3 tuple (if 3, first is a
2242
variable)
2243
2244
- ``yrange`` - 2 or 3 tuple
2245
2246
- ``plot_points`` - a positive integer
2247
2248
2249
OUTPUT:
2250
2251
2252
- ``g`` - tuple of fast callable functions
2253
2254
- ``xstep`` - step size in xdirection
2255
2256
- ``ystep`` - step size in ydirection
2257
2258
- ``xrange`` - tuple of 2 floats
2259
2260
- ``yrange`` - tuple of 2 floats
2261
2262
2263
EXAMPLES::
2264
2265
sage: x,y = var('x,y')
2266
sage: sage.plot.plot.setup_for_eval_on_grid([x^2 + y^2], (x,0,5), (y,0,pi), 11)
2267
doctest:...: DeprecationWarning: sage.plot.plot.setup_for_eval_on_grid is deprecated. Please use sage.plot.misc.setup_for_eval_on_grid; note that that function has slightly different calling and return conventions which make it more generally applicable
2268
See http://trac.sagemath.org/7008 for details.
2269
([<sage.ext... object at ...>],
2270
0.5,
2271
0.3141592653589793,
2272
(0.0, 5.0),
2273
(0.0, 3.141592653589793))
2274
2275
We always plot at least two points; one at the beginning and one at the end of the ranges.
2276
2277
::
2278
2279
sage: sage.plot.plot.setup_for_eval_on_grid([x^2+y^2], (x,0,1), (y,-1,1), 1)
2280
([<sage.ext... object at ...>],
2281
1.0,
2282
2.0,
2283
(0.0, 1.0),
2284
(-1.0, 1.0))
2285
2286
2287
"""
2288
from sage.misc.superseded import deprecation
2289
deprecation(7008, "sage.plot.plot.setup_for_eval_on_grid is deprecated. Please use sage.plot.misc.setup_for_eval_on_grid; note that that function has slightly different calling and return conventions which make it more generally applicable")
2290
2291
from sage.plot.misc import setup_for_eval_on_grid as setup
2292
g, ranges=setup(v, [xrange, yrange], plot_points)
2293
return list(g), ranges[0][2], ranges[1][2], ranges[0][:2], ranges[1][:2]
2294
2295
2296
def minmax_data(xdata, ydata, dict=False):
2297
"""
2298
Returns the minimums and maximums of xdata and ydata.
2299
2300
If dict is False, then minmax_data returns the tuple (xmin, xmax,
2301
ymin, ymax); otherwise, it returns a dictionary whose keys are
2302
'xmin', 'xmax', 'ymin', and 'ymax' and whose values are the
2303
corresponding values.
2304
2305
EXAMPLES::
2306
2307
sage: from sage.plot.plot import minmax_data
2308
sage: minmax_data([], [])
2309
(-1, 1, -1, 1)
2310
sage: minmax_data([-1, 2], [4, -3])
2311
(-1, 2, -3, 4)
2312
sage: d = minmax_data([-1, 2], [4, -3], dict=True)
2313
sage: list(sorted(d.items()))
2314
[('xmax', 2), ('xmin', -1), ('ymax', 4), ('ymin', -3)]
2315
"""
2316
xmin = min(xdata) if len(xdata) > 0 else -1
2317
xmax = max(xdata) if len(xdata) > 0 else 1
2318
ymin = min(ydata) if len(ydata) > 0 else -1
2319
ymax = max(ydata) if len(ydata) > 0 else 1
2320
if dict:
2321
return {'xmin':xmin, 'xmax':xmax,
2322
'ymin':ymin, 'ymax':ymax}
2323
else:
2324
return xmin, xmax, ymin, ymax
2325
2326
def adaptive_refinement(f, p1, p2, adaptive_tolerance=0.01, adaptive_recursion=5, level=0):
2327
r"""
2328
The adaptive refinement algorithm for plotting a function ``f``. See
2329
the docstring for plot for a description of the algorithm.
2330
2331
INPUT:
2332
2333
2334
- ``f`` - a function of one variable
2335
2336
- ``p1, p2`` - two points to refine between
2337
2338
- ``adaptive_recursion`` - (default: 5) how many
2339
levels of recursion to go before giving up when doing adaptive
2340
refinement. Setting this to 0 disables adaptive refinement.
2341
2342
- ``adaptive_tolerance`` - (default: 0.01) how large
2343
a relative difference should be before the adaptive refinement
2344
code considers it significant; see documentation for generate_plot_points
2345
for more information. See the documentation for :func:`plot` for more
2346
information on how the adaptive refinement algorithm works.
2347
2348
OUTPUT:
2349
2350
2351
- ``list`` - a list of points to insert between ``p1`` and
2352
``p2`` to get a better linear approximation between them
2353
2354
2355
TESTS::
2356
2357
sage: from sage.plot.plot import adaptive_refinement
2358
sage: adaptive_refinement(sin, (0,0), (pi,0), adaptive_tolerance=0.01, adaptive_recursion=0)
2359
[]
2360
sage: adaptive_refinement(sin, (0,0), (pi,0), adaptive_tolerance=0.01)
2361
[(0.125*pi, 0.3826834323650898), (0.1875*pi, 0.5555702330196022), (0.25*pi, 0.7071067811865475), (0.3125*pi, 0.8314696123025452), (0.375*pi, 0.9238795325112867), (0.4375*pi, 0.9807852804032304), (0.5*pi, 1.0), (0.5625*pi, 0.9807852804032304), (0.625*pi, 0.9238795325112867), (0.6875*pi, 0.8314696123025455), (0.75*pi, 0.7071067811865476), (0.8125*pi, 0.5555702330196022), (0.875*pi, 0.3826834323650899)]
2362
2363
This shows that lowering ``adaptive_tolerance`` and raising
2364
``adaptive_recursion`` both increase the number of subdivision
2365
points, though which one creates more points is heavily
2366
dependent upon the function being plotted.
2367
2368
::
2369
2370
sage: x = var('x')
2371
sage: f(x) = sin(1/x)
2372
sage: n1 = len(adaptive_refinement(f, (0,0), (pi,0), adaptive_tolerance=0.01)); n1
2373
15
2374
sage: n2 = len(adaptive_refinement(f, (0,0), (pi,0), adaptive_recursion=10, adaptive_tolerance=0.01)); n2
2375
79
2376
sage: n3 = len(adaptive_refinement(f, (0,0), (pi,0), adaptive_tolerance=0.001)); n3
2377
26
2378
"""
2379
if level >= adaptive_recursion:
2380
return []
2381
2382
x = (p1[0] + p2[0])/2.0
2383
msg = ''
2384
2385
try:
2386
y = float(f(x))
2387
if str(y) in ['nan', 'NaN', 'inf', '-inf']:
2388
sage.misc.misc.verbose("%s\nUnable to compute f(%s)"%(msg, x),1)
2389
# give up for this branch
2390
return []
2391
2392
except (ZeroDivisionError, TypeError, ValueError, OverflowError), msg:
2393
sage.misc.misc.verbose("%s\nUnable to compute f(%s)"%(msg, x), 1)
2394
# give up for this branch
2395
return []
2396
2397
# this distance calculation is not perfect.
2398
if abs((p1[1] + p2[1])/2.0 - y) > adaptive_tolerance:
2399
return adaptive_refinement(f, p1, (x, y),
2400
adaptive_tolerance=adaptive_tolerance,
2401
adaptive_recursion=adaptive_recursion,
2402
level=level+1) \
2403
+ [(x, y)] + \
2404
adaptive_refinement(f, (x, y), p2,
2405
adaptive_tolerance=adaptive_tolerance,
2406
adaptive_recursion=adaptive_recursion,
2407
level=level+1)
2408
else:
2409
return []
2410
2411
def generate_plot_points(f, xrange, plot_points=5, adaptive_tolerance=0.01, adaptive_recursion=5, randomize = True, initial_points = None):
2412
r"""
2413
Calculate plot points for a function f in the interval xrange. The
2414
adaptive refinement algorithm is also automatically invoked with a
2415
*relative* adaptive tolerance of adaptive_tolerance; see below.
2416
2417
INPUT:
2418
2419
- ``f`` - a function of one variable
2420
2421
- ``p1, p2`` - two points to refine between
2422
2423
- ``plot_points`` - (default: 5) the minimal number of plot points. (Note
2424
however that in any actual plot a number is passed to this, with default
2425
value 200.)
2426
2427
- ``adaptive_recursion`` - (default: 5) how many levels of recursion to go
2428
before giving up when doing adaptive refinement. Setting this to 0
2429
disables adaptive refinement.
2430
2431
- ``adaptive_tolerance`` - (default: 0.01) how large the relative difference
2432
should be before the adaptive refinement code considers it significant. If
2433
the actual difference is greater than adaptive_tolerance*delta, where delta
2434
is the initial subinterval size for the given xrange and plot_points, then
2435
the algorithm will consider it significant.
2436
2437
- ``initial_points`` - (default: None) a list of points that should be evaluated.
2438
2439
OUTPUT:
2440
2441
- a list of points (x, f(x)) in the interval xrange, which approximate
2442
the function f.
2443
2444
TESTS::
2445
2446
sage: from sage.plot.plot import generate_plot_points
2447
sage: generate_plot_points(sin, (0, pi), plot_points=2, adaptive_recursion=0)
2448
[(0.0, 0.0), (3.141592653589793, 1.2246...e-16)]
2449
2450
sage: from sage.plot.plot import generate_plot_points
2451
sage: generate_plot_points(lambda x: x^2, (0, 6), plot_points=2, adaptive_recursion=0, initial_points = [1,2,3])
2452
[(0.0, 0.0), (1.0, 1.0), (2.0, 4.0), (3.0, 9.0), (6.0, 36.0)]
2453
2454
sage: generate_plot_points(sin(x).function(x), (-pi, pi), randomize=False)
2455
[(-3.141592653589793, -1.2246...e-16), (-2.748893571891069,
2456
-0.3826834323650899), (-2.356194490192345, -0.707106781186547...),
2457
(-2.1598449493429825, -0.831469612302545...), (-1.9634954084936207,
2458
-0.9238795325112867), (-1.7671458676442586, -0.9807852804032304),
2459
(-1.5707963267948966, -1.0), (-1.3744467859455345,
2460
-0.9807852804032304), (-1.1780972450961724, -0.9238795325112867),
2461
(-0.9817477042468103, -0.831469612302545...), (-0.7853981633974483,
2462
-0.707106781186547...), (-0.39269908169872414, -0.3826834323650898),
2463
(0.0, 0.0), (0.39269908169872414, 0.3826834323650898),
2464
(0.7853981633974483, 0.707106781186547...), (0.9817477042468103,
2465
0.831469612302545...), (1.1780972450961724, 0.9238795325112867),
2466
(1.3744467859455345, 0.9807852804032304), (1.5707963267948966, 1.0),
2467
(1.7671458676442586, 0.9807852804032304), (1.9634954084936207,
2468
0.9238795325112867), (2.1598449493429825, 0.831469612302545...),
2469
(2.356194490192345, 0.707106781186547...), (2.748893571891069,
2470
0.3826834323650899), (3.141592653589793, 1.2246...e-16)]
2471
2472
This shows that lowering adaptive_tolerance and raising
2473
adaptive_recursion both increase the number of subdivision points.
2474
(Note that which creates more points is heavily dependent on the
2475
particular function plotted.)
2476
2477
::
2478
2479
sage: x = var('x')
2480
sage: f(x) = sin(1/x)
2481
sage: [len(generate_plot_points(f, (-pi, pi), plot_points=16, adaptive_tolerance=i, randomize=False)) for i in [0.01, 0.001, 0.0001]]
2482
[97, 161, 275]
2483
2484
sage: [len(generate_plot_points(f, (-pi, pi), plot_points=16, adaptive_recursion=i, randomize=False)) for i in [5, 10, 15]]
2485
[97, 499, 2681]
2486
"""
2487
from sage.plot.misc import setup_for_eval_on_grid
2488
ignore, ranges = setup_for_eval_on_grid([], [xrange], plot_points)
2489
xmin, xmax, delta = ranges[0]
2490
data = srange(*ranges[0], include_endpoint=True)
2491
2492
random = current_randstate().python_random().random
2493
2494
for i in range(len(data)):
2495
xi = data[i]
2496
# Slightly randomize the interior sample points if
2497
# randomize is true
2498
if randomize and i > 0 and i < plot_points-1:
2499
xi += delta*(random() - 0.5)
2500
data[i] = xi
2501
2502
# add initial points
2503
if isinstance(initial_points, list):
2504
data = sorted(data + initial_points)
2505
2506
exceptions = 0; msg=''
2507
exception_indices = []
2508
for i in range(len(data)):
2509
xi = data[i]
2510
2511
try:
2512
data[i] = (float(xi), float(f(xi)))
2513
if str(data[i][1]) in ['nan', 'NaN', 'inf', '-inf']:
2514
sage.misc.misc.verbose("%s\nUnable to compute f(%s)"%(msg, xi),1)
2515
exceptions += 1
2516
exception_indices.append(i)
2517
2518
except (ArithmeticError, TypeError, ValueError), msg:
2519
sage.misc.misc.verbose("%s\nUnable to compute f(%s)"%(msg, xi),1)
2520
2521
if i == 0: # Given an error for left endpoint, try to move it in slightly
2522
for j in range(1, 99):
2523
xj = xi + delta*j/100.0
2524
try:
2525
data[i] = (float(xj), float(f(xj)))
2526
# nan != nan
2527
if data[i][1] != data[i][1]:
2528
continue
2529
break
2530
except (ArithmeticError, TypeError, ValueError), msg:
2531
pass
2532
else:
2533
exceptions += 1
2534
exception_indices.append(i)
2535
2536
elif i == plot_points-1: # Given an error for right endpoint, try to move it in slightly
2537
for j in range(1, 99):
2538
xj = xi - delta*j/100.0
2539
try:
2540
data[i] = (float(xj), float(f(xj)))
2541
# nan != nan
2542
if data[i][1] != data[i][1]:
2543
continue
2544
break
2545
except (ArithmeticError, TypeError, ValueError), msg:
2546
pass
2547
else:
2548
exceptions += 1
2549
exception_indices.append(i)
2550
else:
2551
exceptions += 1
2552
exception_indices.append(i)
2553
2554
data = [data[i] for i in range(len(data)) if i not in exception_indices]
2555
2556
# calls adaptive refinement
2557
i, j = 0, 0
2558
adaptive_tolerance = delta * float(adaptive_tolerance)
2559
adaptive_recursion = int(adaptive_recursion)
2560
2561
while i < len(data) - 1:
2562
for p in adaptive_refinement(f, data[i], data[i+1],
2563
adaptive_tolerance=adaptive_tolerance,
2564
adaptive_recursion=adaptive_recursion):
2565
data.insert(i+1, p)
2566
i += 1
2567
i += 1
2568
2569
if (len(data) == 0 and exceptions > 0) or exceptions > 10:
2570
sage.misc.misc.verbose("WARNING: When plotting, failed to evaluate function at %s points."%exceptions, level=0)
2571
sage.misc.misc.verbose("Last error message: '%s'"%msg, level=0)
2572
2573
return data
2574
2575
#Lovely cruft to keep the pickle jar working
2576
from line import line, line2d, Line as GraphicPrimitive_Line
2577
from arrow import arrow, Arrow as GraphicPrimitive_Arrow
2578
from bar_chart import bar_chart, BarChart as GraphicPrimitive_BarChart
2579
from disk import disk, Disk as GraphicPrimitive_Disk
2580
from point import point, points, point2d, Point as GraphicPrimitive_Point
2581
from matrix_plot import matrix_plot, MatrixPlot as GraphicPrimitive_MatrixPlot
2582
from plot_field import plot_vector_field, plot_slope_field, PlotField as GraphicPrimitive_PlotField
2583
from text import text, Text as GraphicPrimitive_Text
2584
from polygon import polygon, Polygon as GraphicPrimitive_Polygon
2585
from circle import circle, Circle as GraphicPrimtive_Circle
2586
from contour_plot import contour_plot, implicit_plot, ContourPlot as GraphicPrimitive_ContourPlot
2587
2588
2589