Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/plot/disk.py
8815 views
1
"""
2
Disks
3
"""
4
#*****************************************************************************
5
# Copyright (C) 2006 Alex Clemesha <[email protected]>,
6
# William Stein <[email protected]>,
7
# 2008 Mike Hansen <[email protected]>,
8
#
9
# Distributed under the terms of the GNU General Public License (GPL)
10
#
11
# This code is distributed in the hope that it will be useful,
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
# General Public License for more details.
15
#
16
# The full text of the GPL is available at:
17
#
18
# http://www.gnu.org/licenses/
19
#*****************************************************************************
20
from sage.plot.primitive import GraphicPrimitive
21
from sage.misc.decorators import options, rename_keyword
22
from sage.plot.colors import to_mpl_color
23
from math import sin, cos, pi
24
25
class Disk(GraphicPrimitive):
26
"""
27
Primitive class for the ``Disk`` graphics type. See ``disk?`` for
28
information about actually plotting a disk (the Sage term for a sector
29
or wedge of a circle).
30
31
INPUT:
32
33
- ``point`` - coordinates of center of disk
34
35
- ``r`` - radius of disk
36
37
- ``angle`` - beginning and ending angles of disk (i.e.
38
angle extent of sector/wedge)
39
40
- ``options`` - dict of valid plot options to pass to constructor
41
42
EXAMPLES:
43
44
Note this should normally be used indirectly via ``disk``::
45
46
sage: from sage.plot.disk import Disk
47
sage: D = Disk((1,2), 2, (pi/2,pi), {'zorder':3})
48
sage: D
49
Disk defined by (1.0,2.0) with r=2.0 spanning (1.57079632679, 3.14159265359) radians
50
sage: D.options()['zorder']
51
3
52
sage: D.x
53
1.0
54
55
TESTS:
56
57
We test creating a disk::
58
59
sage: disk((2,3), 2, (0,pi/2))
60
"""
61
def __init__(self, point, r, angle, options):
62
"""
63
Initializes base class ``Disk``.
64
65
EXAMPLES::
66
67
sage: D = disk((2,3), 1, (pi/2, pi), fill=False, color='red', thickness=1, alpha=.5)
68
sage: D[0].x
69
2.0
70
sage: D[0].r
71
1.0
72
sage: D[0].rad1
73
1.5707963267948966
74
sage: D[0].options()['rgbcolor']
75
'red'
76
sage: D[0].options()['alpha']
77
0.500000000000000
78
sage: print loads(dumps(D))
79
Graphics object consisting of 1 graphics primitive
80
"""
81
self.x = float(point[0])
82
self.y = float(point[1])
83
self.r = float(r)
84
self.rad1 = float(angle[0])
85
self.rad2 = float(angle[1])
86
GraphicPrimitive.__init__(self, options)
87
88
def get_minmax_data(self):
89
"""
90
Returns a dictionary with the bounding box data.
91
92
EXAMPLES::
93
94
sage: D = disk((5,4), 1, (pi/2, pi))
95
sage: d = D.get_minmax_data()
96
sage: d['xmin']
97
4.0
98
sage: d['ymin']
99
3.0
100
sage: d['xmax']
101
6.0
102
sage: d['ymax']
103
5.0
104
105
"""
106
from sage.plot.plot import minmax_data
107
return minmax_data([self.x - self.r, self.x + self.r],
108
[self.y - self.r, self.y + self.r],
109
dict=True)
110
111
def _allowed_options(self):
112
"""
113
Return the allowed options for the ``Disk`` class.
114
115
EXAMPLES::
116
117
sage: p = disk((3, 3), 1, (0, pi/2))
118
sage: p[0]._allowed_options()['alpha']
119
'How transparent the figure is.'
120
sage: p[0]._allowed_options()['zorder']
121
'The layer level in which to draw'
122
"""
123
return {'alpha':'How transparent the figure is.',
124
'fill':'Whether or not to fill the disk.',
125
'legend_label':'The label for this item in the legend.',
126
'legend_color':'The color of the legend text.',
127
'thickness':'How thick the border of the disk is.',
128
'rgbcolor':'The color as an RGB tuple.',
129
'hue':'The color given as a hue.',
130
'zorder':'The layer level in which to draw'}
131
132
def _repr_(self):
133
"""
134
String representation of ``Disk`` primitive.
135
136
EXAMPLES::
137
138
sage: P = disk((3, 3), 1, (0, pi/2))
139
sage: p = P[0]; p
140
Disk defined by (3.0,3.0) with r=1.0 spanning (0.0, 1.57079632679) radians
141
"""
142
return "Disk defined by (%s,%s) with r=%s spanning (%s, %s) radians"%(self.x,
143
self.y, self.r, self.rad1, self.rad2)
144
145
def _render_on_subplot(self, subplot):
146
"""
147
TESTS::
148
149
sage: D = disk((2,-1), 2, (0, pi), color='black', thickness=3, fill=False); D
150
151
Save alpha information in pdf (see :trac:`13732`)::
152
153
sage: f = tmp_filename(ext='.pdf')
154
sage: p = disk((0,0), 5, (0, pi/4), alpha=0.5)
155
sage: p.save(f)
156
157
"""
158
import matplotlib.patches as patches
159
options = self.options()
160
deg1 = self.rad1*(180./pi) #convert radians to degrees
161
deg2 = self.rad2*(180./pi)
162
z = int(options.pop('zorder', 0))
163
p = patches.Wedge((float(self.x), float(self.y)), float(self.r), float(deg1),
164
float(deg2), zorder=z)
165
a = float(options['alpha'])
166
p.set_alpha(a)
167
p.set_linewidth(float(options['thickness']))
168
p.set_fill(options['fill'])
169
c = to_mpl_color(options['rgbcolor'])
170
p.set_edgecolor(c)
171
p.set_facecolor(c)
172
p.set_label(options['legend_label'])
173
subplot.add_patch(p)
174
175
def plot3d(self, z=0, **kwds):
176
"""
177
Plots a 2D disk (actually a 52-gon) in 3D,
178
with default height zero.
179
180
INPUT:
181
182
183
- ``z`` - optional 3D height above `xy`-plane.
184
185
AUTHORS:
186
187
- Karl-Dieter Crisman (05-09)
188
189
EXAMPLES::
190
191
sage: disk((0,0), 1, (0, pi/2)).plot3d()
192
sage: disk((0,0), 1, (0, pi/2)).plot3d(z=2)
193
sage: disk((0,0), 1, (pi/2, 0), fill=False).plot3d(3)
194
195
These examples show that the appropriate options are passed::
196
197
sage: D = disk((2,3), 1, (pi/4,pi/3), hue=.8, alpha=.3, fill=True)
198
sage: d = D[0]
199
sage: d.plot3d(z=2).texture.opacity
200
0.300000000000000
201
202
::
203
204
sage: D = disk((2,3), 1, (pi/4,pi/3), hue=.8, alpha=.3, fill=False)
205
sage: d = D[0]
206
sage: dd = d.plot3d(z=2)
207
sage: dd.jmol_repr(dd.testing_render_params())[0][-1]
208
'color $line_4 translucent 0.7 [204,0,255]'
209
"""
210
options = dict(self.options())
211
fill = options['fill']
212
del options['fill']
213
if 'zorder' in options:
214
del options['zorder']
215
n = 50
216
x, y, r, rad1, rad2 = self.x, self.y, self.r, self.rad1, self.rad2
217
dt = float((rad2-rad1)/n)
218
xdata = [x]
219
ydata = [y]
220
xdata.extend([x+r*cos(t*dt+rad1) for t in range(n+1)])
221
ydata.extend([y+r*sin(t*dt+rad1) for t in range(n+1)])
222
xdata.append(x)
223
ydata.append(y)
224
if fill:
225
from polygon import Polygon
226
return Polygon(xdata, ydata, options).plot3d(z)
227
else:
228
from line import Line
229
return Line(xdata, ydata, options).plot3d().translate((0,0,z))
230
231
@rename_keyword(color='rgbcolor')
232
@options(alpha=1, fill=True, rgbcolor=(0,0,1), thickness=0, legend_label=None,
233
aspect_ratio=1.0)
234
def disk(point, radius, angle, **options):
235
r"""
236
A disk (that is, a sector or wedge of a circle) with center
237
at a point = `(x,y)` (or `(x,y,z)` and parallel to the
238
`xy`-plane) with radius = `r` spanning (in radians)
239
angle=`(rad1, rad2)`.
240
241
Type ``disk.options`` to see all options.
242
243
EXAMPLES:
244
245
Make some dangerous disks::
246
247
sage: bl = disk((0.0,0.0), 1, (pi, 3*pi/2), color='yellow')
248
sage: tr = disk((0.0,0.0), 1, (0, pi/2), color='yellow')
249
sage: tl = disk((0.0,0.0), 1, (pi/2, pi), color='black')
250
sage: br = disk((0.0,0.0), 1, (3*pi/2, 2*pi), color='black')
251
sage: P = tl+tr+bl+br
252
sage: P.show(xmin=-2,xmax=2,ymin=-2,ymax=2)
253
254
The default aspect ratio is 1.0::
255
256
sage: disk((0.0,0.0), 1, (pi, 3*pi/2)).aspect_ratio()
257
1.0
258
259
Another example of a disk::
260
261
sage: bl = disk((0.0,0.0), 1, (pi, 3*pi/2), rgbcolor=(1,1,0))
262
sage: bl.show(figsize=[5,5])
263
264
Note that since ``thickness`` defaults to zero, it is best to change
265
that option when using ``fill=False``::
266
267
sage: disk((2,3), 1, (pi/4,pi/3), hue=.8, alpha=.3, fill=False, thickness=2)
268
269
The previous two examples also illustrate using ``hue`` and ``rgbcolor``
270
as ways of specifying the color of the graphic.
271
272
We can also use this command to plot three-dimensional disks parallel
273
to the `xy`-plane::
274
275
sage: d = disk((1,1,3), 1, (pi,3*pi/2), rgbcolor=(1,0,0))
276
sage: d
277
sage: type(d)
278
<type 'sage.plot.plot3d.index_face_set.IndexFaceSet'>
279
280
Extra options will get passed on to ``show()``, as long as they are valid::
281
282
sage: disk((0, 0), 5, (0, pi/2), xmin=0, xmax=5, ymin=0, ymax=5, figsize=(2,2), rgbcolor=(1, 0, 1))
283
sage: disk((0, 0), 5, (0, pi/2), rgbcolor=(1, 0, 1)).show(xmin=0, xmax=5, ymin=0, ymax=5, figsize=(2,2)) # These are equivalent
284
285
TESTS:
286
287
Testing that legend labels work right::
288
289
sage: disk((2,4), 3, (pi/8, pi/4), hue=1, legend_label='disk', legend_color='blue')
290
291
We cannot currently plot disks in more than three dimensions::
292
293
sage: d = disk((1,1,1,1), 1, (0,pi))
294
Traceback (most recent call last):
295
...
296
ValueError: The center point of a plotted disk should have two or three coordinates.
297
"""
298
from sage.plot.all import Graphics
299
g = Graphics()
300
301
# Reset aspect_ratio to 'automatic' in case scale is 'semilog[xy]'.
302
# Otherwise matplotlib complains.
303
scale = options.get('scale', None)
304
if isinstance(scale, (list, tuple)):
305
scale = scale[0]
306
if scale == 'semilogy' or scale == 'semilogx':
307
options['aspect_ratio'] = 'automatic'
308
309
g._set_extra_kwds(Graphics._extract_kwds_for_show(options))
310
g.add_primitive(Disk(point, radius, angle, options))
311
if options['legend_label']:
312
g.legend(True)
313
g._legend_colors = [options['legend_color']]
314
if len(point)==2:
315
return g
316
elif len(point)==3:
317
return g[0].plot3d(z=point[2])
318
else:
319
raise ValueError, 'The center point of a plotted disk should have two or three coordinates.'
320
321