Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/plot/line.py
4034 views
1
"""
2
Line Plots
3
"""
4
5
#*****************************************************************************
6
# Copyright (C) 2006 Alex Clemesha <[email protected]>,
7
# William Stein <[email protected]>,
8
# 2008 Mike Hansen <[email protected]>,
9
#
10
# Distributed under the terms of the GNU General Public License (GPL)
11
#
12
# This code is distributed in the hope that it will be useful,
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
# General Public License for more details.
16
#
17
# The full text of the GPL is available at:
18
#
19
# http://www.gnu.org/licenses/
20
#*****************************************************************************
21
from sage.plot.primitive import GraphicPrimitive_xydata
22
from sage.misc.decorators import options, rename_keyword
23
from sage.plot.colors import to_mpl_color
24
25
class Line(GraphicPrimitive_xydata):
26
"""
27
Primitive class that initializes the line graphics type.
28
29
EXAMPLES::
30
31
sage: from sage.plot.line import Line
32
sage: Line([1,2,7], [1,5,-1], {})
33
Line defined by 3 points
34
"""
35
def __init__(self, xdata, ydata, options):
36
"""
37
Initialize a line graphics primitive.
38
39
EXAMPLES::
40
41
sage: from sage.plot.line import Line
42
sage: Line([-1,2], [17,4], {'thickness':2})
43
Line defined by 2 points
44
"""
45
valid_options = self._allowed_options().keys()
46
for opt in options.iterkeys():
47
if opt not in valid_options:
48
raise RuntimeError("Error in line(): option '%s' not valid."%opt)
49
self.xdata = xdata
50
self.ydata = ydata
51
GraphicPrimitive_xydata.__init__(self, options)
52
53
def _allowed_options(self):
54
"""
55
Displayed the list of allowed line options.
56
57
EXAMPLES::
58
59
sage: from sage.plot.line import Line
60
sage: list(sorted(Line([-1,2], [17,4], {})._allowed_options().iteritems()))
61
[('alpha', 'How transparent the line is.'),
62
('hue', 'The color given as a hue.'),
63
('legend_label', 'The label for this item in the legend.'),
64
('linestyle',
65
"The style of the line, which is one of '--' (dashed), '-.' (dash dot), '-' (solid), 'steps', ':' (dotted)."),
66
('marker', 'the marker symbol (see documentation for line2d for details)'),
67
('markeredgecolor', 'the color of the marker edge'),
68
('markeredgewidth', 'the size of the marker edge in points'),
69
('markerfacecolor', 'the color of the marker face'),
70
('markersize', 'the size of the marker in points'),
71
('rgbcolor', 'The color as an RGB tuple.'),
72
('thickness', 'How thick the line is.'),
73
('zorder', 'The layer level in which to draw')]
74
"""
75
return {'alpha':'How transparent the line is.',
76
'legend_label':'The label for this item in the legend.',
77
'thickness':'How thick the line is.',
78
'rgbcolor':'The color as an RGB tuple.',
79
'hue':'The color given as a hue.',
80
'linestyle':"The style of the line, which is one of '--' (dashed), '-.' (dash dot), '-' (solid), 'steps', ':' (dotted).",
81
'marker':"the marker symbol (see documentation for line2d for details)",
82
'markersize':'the size of the marker in points',
83
'markeredgecolor':'the color of the marker edge',
84
'markeredgewidth':'the size of the marker edge in points',
85
'markerfacecolor':'the color of the marker face',
86
'zorder':'The layer level in which to draw'
87
}
88
89
def _plot3d_options(self, options=None):
90
"""
91
Translate 2D plot options into 3D plot options.
92
93
EXAMPLES::
94
95
sage: L = line([(1,1), (1,2), (2,2), (2,1)], alpha=.5, thickness=10, zorder=2)
96
sage: l=L[0]; l
97
Line defined by 4 points
98
sage: m=l.plot3d(z=2)
99
sage: m.texture.opacity
100
0.500000000000000
101
sage: m.thickness
102
10
103
sage: L = line([(1,1), (1,2), (2,2), (2,1)], linestyle=":")
104
sage: L.plot3d()
105
Traceback (most recent call last):
106
NotImplementedError: Invalid 3d line style: ':'
107
"""
108
if options == None:
109
options = dict(self.options())
110
options_3d = {}
111
if 'thickness' in options:
112
options_3d['thickness'] = options['thickness']
113
del options['thickness']
114
if 'zorder' in options:
115
del options['zorder']
116
if 'linestyle' in options:
117
if options['linestyle'] != '--':
118
raise NotImplementedError, "Invalid 3d line style: '%s'" % options['linestyle']
119
del options['linestyle']
120
options_3d.update(GraphicPrimitive_xydata._plot3d_options(self, options))
121
return options_3d
122
123
def plot3d(self, z=0, **kwds):
124
"""
125
Plots a 2D line in 3D, with default height zero.
126
127
EXAMPLES::
128
129
sage: E = EllipticCurve('37a').plot(thickness=5).plot3d()
130
sage: F = EllipticCurve('37a').plot(thickness=5).plot3d(z=2)
131
sage: E + F
132
"""
133
from sage.plot.plot3d.shapes2 import line3d
134
options = self._plot3d_options()
135
options.update(kwds)
136
return line3d([(x, y, z) for x, y in zip(self.xdata, self.ydata)], **options)
137
138
def _repr_(self):
139
"""
140
String representation of a line primitive.
141
142
EXAMPLES::
143
144
sage: from sage.plot.line import Line
145
sage: Line([-1,2,3,3], [17,4,0,2], {})._repr_()
146
'Line defined by 4 points'
147
"""
148
return "Line defined by %s points"%len(self)
149
150
def __getitem__(self, i):
151
"""
152
Extract the i-th element of the line (which is stored as a list of points).
153
154
INPUT:
155
156
- ``i`` -- an integer between 0 and the number of points minus 1
157
158
OUTPUT:
159
160
A 2-tuple of floats.
161
162
EXAMPLES::
163
164
sage: L = line([(1,2), (3,-4), (2, 5), (1,2)])
165
sage: line_primitive = L[0]; line_primitive
166
Line defined by 4 points
167
sage: line_primitive[0]
168
(1.0, 2.0)
169
sage: line_primitive[2]
170
(2.0, 5.0)
171
sage: list(line_primitive)
172
[(1.0, 2.0), (3.0, -4.0), (2.0, 5.0), (1.0, 2.0)]
173
"""
174
return self.xdata[i], self.ydata[i]
175
176
def __setitem__(self, i, point):
177
"""
178
Set the i-th element of this line (really a sequence of lines
179
through given points).
180
181
INPUT:
182
183
- ``i`` -- an integer between 0 and the number of points on the
184
line minus 1
185
186
- ``point`` -- a 2-tuple of floats
187
188
EXAMPLES:
189
190
We create a line graphics object $L$ and get ahold of the
191
corresponding line graphics primitive::
192
193
sage: L = line([(1,2), (3,-4), (2, 5), (1,2)])
194
sage: line_primitive = L[0]; line_primitive
195
Line defined by 4 points
196
197
We then set the 0th point to `(0,0)` instead of `(1,2)`::
198
199
sage: line_primitive[0] = (0,0)
200
sage: line_primitive[0]
201
(0.0, 0.0)
202
203
Plotting we visibly see the change -- now the line starts at `(0,0)`::
204
205
sage: L
206
"""
207
self.xdata[i] = float(point[0])
208
self.ydata[i] = float(point[1])
209
210
def __len__(self):
211
r"""
212
Return the number of points on this line (where a line is really a sequence
213
of line segments through a given list of points).
214
215
EXAMPLES:
216
217
We create a line, then grab the line primitive as \code{L[0]} and compute
218
its length::
219
220
sage: L = line([(1,2), (3,-4), (2, 5), (1,2)])
221
sage: len(L[0])
222
4
223
"""
224
return len(self.xdata)
225
226
def _render_on_subplot(self, subplot):
227
"""
228
Render this line on a matplotlib subplot.
229
230
INPUT:
231
232
- ``subplot`` -- a matplotlib subplot
233
234
EXAMPLES:
235
236
This implicitly calls this function::
237
238
sage: line([(1,2), (3,-4), (2, 5), (1,2)])
239
"""
240
import matplotlib.lines as lines
241
options = dict(self.options())
242
del options['alpha']
243
del options['thickness']
244
del options['rgbcolor']
245
del options['legend_label']
246
if 'linestyle' in options:
247
del options['linestyle']
248
p = lines.Line2D(self.xdata, self.ydata, **options)
249
options = self.options()
250
a = float(options['alpha'])
251
p.set_alpha(a)
252
p.set_linewidth(float(options['thickness']))
253
p.set_color(to_mpl_color(options['rgbcolor']))
254
p.set_label(options['legend_label'])
255
# we don't pass linestyle in directly since the drawstyles aren't
256
# pulled off automatically. This (I think) is a bug in matplotlib 1.0.1
257
if 'linestyle' in options:
258
p.set_linestyle(options['linestyle'])
259
subplot.add_line(p)
260
261
def line(points, **kwds):
262
"""
263
Returns either a 2-dimensional or 3-dimensional line depending
264
on value of points.
265
266
For information regarding additional arguments, see either line2d?
267
or line3d?.
268
269
EXAMPLES::
270
271
sage: line([(0,0), (1,1)])
272
273
::
274
275
sage: line([(0,0,1), (1,1,1)])
276
"""
277
try:
278
return line2d(points, **kwds)
279
except ValueError:
280
from sage.plot.plot3d.shapes2 import line3d
281
return line3d(points, **kwds)
282
283
284
@rename_keyword(color='rgbcolor')
285
@options(alpha=1, rgbcolor=(0,0,1), thickness=1, legend_label=None, aspect_ratio ='automatic')
286
def line2d(points, **options):
287
r"""
288
Create the line through the given list of points.
289
290
Type \code{line2d.options} for a dictionary of the default options for
291
lines. You can change this to change the defaults for all future
292
lines. Use \code{line2d.reset()} to reset to the default options.
293
294
INPUT:
295
296
- ``alpha`` -- How transparent the line is
297
298
- ``thickness`` -- How thick the line is
299
300
- ``rgbcolor`` -- The color as an RGB tuple
301
302
- ``hue`` -- The color given as a hue
303
304
- ``legend_label`` -- the label for this item in the legend
305
306
Any MATPLOTLIB line option may also be passed in. E.g.,
307
308
- ``linestyle`` - The style of the line, which is one of
309
- ``"-"`` (solid) -- default
310
- ``"--"`` (dashed)
311
- ``"-."`` (dash dot)
312
- ``":"`` (dotted)
313
- ``"None"`` or ``" "`` or ``""`` (nothing)
314
315
The linestyle can also be prefixed with a drawing style (e.g., ``"steps--"``)
316
317
- ``"default"`` (connect the points with straight lines)
318
- ``"steps"`` or ``"steps-pre"`` (step function; horizontal
319
line is to the left of point)
320
- ``"steps-mid"`` (step function; points are in the middle of
321
horizontal lines)
322
- ``"steps-post"`` (step function; horizontal line is to the
323
right of point)
324
325
- ``marker`` - The style of the markers, which is one of
326
- ``"None"`` or ``" "`` or ``""`` (nothing) -- default
327
- ``","`` (pixel), ``"."`` (point)
328
- ``"_"`` (horizontal line), ``"|"`` (vertical line)
329
- ``"o"`` (circle), ``"p"`` (pentagon), ``"s"`` (square), ``"x"`` (x), ``"+"`` (plus), ``"*"`` (star)
330
- ``"D"`` (diamond), ``"d"`` (thin diamond)
331
- ``"H"`` (hexagon), ``"h"`` (alternative hexagon)
332
- ``"<"`` (triangle left), ``">"`` (triangle right), ``"^"`` (triangle up), ``"v"`` (triangle down)
333
- ``"1"`` (tri down), ``"2"`` (tri up), ``"3"`` (tri left), ``"4"`` (tri right)
334
- ``0`` (tick left), ``1`` (tick right), ``2`` (tick up), ``3`` (tick down)
335
- ``4`` (caret left), ``5`` (caret right), ``6`` (caret up), ``7`` (caret down)
336
- ``"$...$"`` (math TeX string)
337
338
- ``markersize`` -- the size of the marker in points
339
340
- ``markeredgecolor`` -- the color of the marker edge
341
342
- ``markerfacecolor`` -- the color of the marker face
343
344
- ``markeredgewidth`` -- the size of the marker edge in points
345
346
EXAMPLES:
347
348
A blue conchoid of Nicomedes::
349
350
sage: L = [[1+5*cos(pi/2+pi*i/100), tan(pi/2+pi*i/100)*(1+5*cos(pi/2+pi*i/100))] for i in range(1,100)]
351
sage: line(L, rgbcolor=(1/4,1/8,3/4))
352
353
A line with 2 complex points::
354
355
sage: i = CC.0
356
sage: line([1+i, 2+3*i])
357
358
A blue hypotrochoid (3 leaves)::
359
360
sage: n = 4; h = 3; b = 2
361
sage: L = [[n*cos(pi*i/100)+h*cos((n/b)*pi*i/100),n*sin(pi*i/100)-h*sin((n/b)*pi*i/100)] for i in range(200)]
362
sage: line(L, rgbcolor=(1/4,1/4,3/4))
363
364
A blue hypotrochoid (4 leaves)::
365
366
sage: n = 6; h = 5; b = 2
367
sage: L = [[n*cos(pi*i/100)+h*cos((n/b)*pi*i/100),n*sin(pi*i/100)-h*sin((n/b)*pi*i/100)] for i in range(200)]
368
sage: line(L, rgbcolor=(1/4,1/4,3/4))
369
370
A red limacon of Pascal::
371
372
sage: L = [[sin(pi*i/100)+sin(pi*i/50),-(1+cos(pi*i/100)+cos(pi*i/50))] for i in range(-100,101)]
373
sage: line(L, rgbcolor=(1,1/4,1/2))
374
375
A light green trisectrix of Maclaurin::
376
377
sage: L = [[2*(1-4*cos(-pi/2+pi*i/100)^2),10*tan(-pi/2+pi*i/100)*(1-4*cos(-pi/2+pi*i/100)^2)] for i in range(1,100)]
378
sage: line(L, rgbcolor=(1/4,1,1/8))
379
380
A green lemniscate of Bernoulli::
381
382
sage: cosines = [cos(-pi/2+pi*i/100) for i in range(201)]
383
sage: v = [(1/c, tan(-pi/2+pi*i/100)) for i,c in enumerate(cosines) if c != 0]
384
sage: L = [(a/(a^2+b^2), b/(a^2+b^2)) for a,b in v]
385
sage: line(L, rgbcolor=(1/4,3/4,1/8))
386
387
A red plot of the Jacobi elliptic function `\text{sn}(x,2)`, `-3 < x < 3`::
388
389
sage: L = [(i/100.0, jacobi('sn', i/100.0 ,2.0)) for i in range(-300,300,30)]
390
sage: line(L, rgbcolor=(3/4,1/4,1/8))
391
392
A red plot of `J`-Bessel function `J_2(x)`, `0 < x < 10`::
393
394
sage: L = [(i/10.0, bessel_J(2,i/10.0)) for i in range(100)]
395
sage: line(L, rgbcolor=(3/4,1/4,5/8))
396
397
398
A purple plot of the Riemann zeta function `\zeta(1/2 + it)`, `0 < t < 30`::
399
400
sage: i = CDF.gen()
401
sage: v = [zeta(0.5 + n/10 * i) for n in range(300)]
402
sage: L = [(z.real(), z.imag()) for z in v]
403
sage: line(L, rgbcolor=(3/4,1/2,5/8))
404
405
A purple plot of the Hasse-Weil `L`-function `L(E, 1 + it)`, `-1 < t < 10`::
406
407
sage: E = EllipticCurve('37a')
408
sage: vals = E.lseries().values_along_line(1-I, 1+10*I, 100) # critical line
409
sage: L = [(z[1].real(), z[1].imag()) for z in vals]
410
sage: line(L, rgbcolor=(3/4,1/2,5/8))
411
412
A red, blue, and green "cool cat"::
413
414
sage: G = plot(-cos(x), -2, 2, thickness=5, rgbcolor=(0.5,1,0.5))
415
sage: P = polygon([[1,2], [5,6], [5,0]], rgbcolor=(1,0,0))
416
sage: Q = polygon([(-x,y) for x,y in P[0]], rgbcolor=(0,0,1))
417
sage: G + P + Q # show the plot
418
419
A line with no points or one point::
420
421
sage: line([]) #returns an empty plot
422
sage: line([(1,1)])
423
424
A line with a legend::
425
426
sage: line([(0,0),(1,1)], legend_label='line')
427
428
Extra options will get passed on to show(), as long as they are valid::
429
430
sage: line([(0,1), (3,4)], figsize=[10, 2])
431
sage: line([(0,1), (3,4)]).show(figsize=[10, 2]) # These are equivalent
432
"""
433
from sage.plot.all import Graphics
434
from sage.plot.plot import xydata_from_point_list
435
if points == []:
436
return Graphics()
437
xdata, ydata = xydata_from_point_list(points)
438
g = Graphics()
439
g._set_extra_kwds(Graphics._extract_kwds_for_show(options))
440
g.add_primitive(Line(xdata, ydata, options))
441
if options['legend_label']:
442
g.legend(True)
443
return g
444
445