passagemath-plot 10.6.31rc3__cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of passagemath-plot might be problematic. Click here for more details.
- passagemath_plot-10.6.31rc3.dist-info/METADATA +172 -0
- passagemath_plot-10.6.31rc3.dist-info/RECORD +82 -0
- passagemath_plot-10.6.31rc3.dist-info/WHEEL +6 -0
- passagemath_plot-10.6.31rc3.dist-info/top_level.txt +2 -0
- passagemath_plot.libs/libgfortran-83c28eba.so.5.0.0 +0 -0
- passagemath_plot.libs/libgsl-cda90e79.so.28.0.0 +0 -0
- passagemath_plot.libs/libopenblasp-r0-6dcb67f9.3.29.so +0 -0
- passagemath_plot.libs/libquadmath-2284e583.so.0.0.0 +0 -0
- sage/all__sagemath_plot.py +15 -0
- sage/ext_data/threejs/animation.css +195 -0
- sage/ext_data/threejs/animation.html +85 -0
- sage/ext_data/threejs/animation.js +273 -0
- sage/ext_data/threejs/fat_lines.js +48 -0
- sage/ext_data/threejs/threejs-version.txt +1 -0
- sage/ext_data/threejs/threejs_template.html +597 -0
- sage/interfaces/all__sagemath_plot.py +1 -0
- sage/interfaces/gnuplot.py +196 -0
- sage/interfaces/jmoldata.py +208 -0
- sage/interfaces/povray.py +56 -0
- sage/plot/all.py +42 -0
- sage/plot/animate.py +1796 -0
- sage/plot/arc.py +504 -0
- sage/plot/arrow.py +671 -0
- sage/plot/bar_chart.py +205 -0
- sage/plot/bezier_path.py +400 -0
- sage/plot/circle.py +435 -0
- sage/plot/colors.py +1606 -0
- sage/plot/complex_plot.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/plot/complex_plot.pyx +1446 -0
- sage/plot/contour_plot.py +1792 -0
- sage/plot/density_plot.py +318 -0
- sage/plot/disk.py +373 -0
- sage/plot/ellipse.py +375 -0
- sage/plot/graphics.py +3580 -0
- sage/plot/histogram.py +354 -0
- sage/plot/hyperbolic_arc.py +404 -0
- sage/plot/hyperbolic_polygon.py +416 -0
- sage/plot/hyperbolic_regular_polygon.py +296 -0
- sage/plot/line.py +626 -0
- sage/plot/matrix_plot.py +629 -0
- sage/plot/misc.py +509 -0
- sage/plot/multigraphics.py +1294 -0
- sage/plot/plot.py +4183 -0
- sage/plot/plot3d/all.py +23 -0
- sage/plot/plot3d/base.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/plot/plot3d/base.pxd +12 -0
- sage/plot/plot3d/base.pyx +3378 -0
- sage/plot/plot3d/implicit_plot3d.py +659 -0
- sage/plot/plot3d/implicit_surface.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/plot/plot3d/implicit_surface.pyx +1453 -0
- sage/plot/plot3d/index_face_set.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/plot/plot3d/index_face_set.pxd +32 -0
- sage/plot/plot3d/index_face_set.pyx +1873 -0
- sage/plot/plot3d/introduction.py +131 -0
- sage/plot/plot3d/list_plot3d.py +649 -0
- sage/plot/plot3d/parametric_plot3d.py +1130 -0
- sage/plot/plot3d/parametric_surface.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/plot/plot3d/parametric_surface.pxd +12 -0
- sage/plot/plot3d/parametric_surface.pyx +893 -0
- sage/plot/plot3d/platonic.py +601 -0
- sage/plot/plot3d/plot3d.py +1442 -0
- sage/plot/plot3d/plot_field3d.py +162 -0
- sage/plot/plot3d/point_c.pxi +148 -0
- sage/plot/plot3d/revolution_plot3d.py +309 -0
- sage/plot/plot3d/shapes.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/plot/plot3d/shapes.pxd +22 -0
- sage/plot/plot3d/shapes.pyx +1382 -0
- sage/plot/plot3d/shapes2.py +1512 -0
- sage/plot/plot3d/tachyon.py +1779 -0
- sage/plot/plot3d/texture.py +453 -0
- sage/plot/plot3d/transform.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/plot/plot3d/transform.pxd +21 -0
- sage/plot/plot3d/transform.pyx +268 -0
- sage/plot/plot3d/tri_plot.py +589 -0
- sage/plot/plot_field.py +362 -0
- sage/plot/point.py +624 -0
- sage/plot/polygon.py +562 -0
- sage/plot/primitive.py +249 -0
- sage/plot/scatter_plot.py +199 -0
- sage/plot/step.py +85 -0
- sage/plot/streamline_plot.py +328 -0
- sage/plot/text.py +432 -0
sage/plot/misc.py
ADDED
|
@@ -0,0 +1,509 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-plot
|
|
2
|
+
# sage.doctest: needs sage.symbolic
|
|
3
|
+
"""
|
|
4
|
+
Plotting utilities
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
# ****************************************************************************
|
|
8
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
9
|
+
#
|
|
10
|
+
# This code is distributed in the hope that it will be useful,
|
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
13
|
+
# General Public License for more details.
|
|
14
|
+
#
|
|
15
|
+
# The full text of the GPL is available at:
|
|
16
|
+
#
|
|
17
|
+
# https://www.gnu.org/licenses/
|
|
18
|
+
# ****************************************************************************
|
|
19
|
+
from sage.ext.fast_callable import FastCallableFloatWrapper
|
|
20
|
+
from collections.abc import Iterable
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def setup_for_eval_on_grid(funcs,
|
|
24
|
+
ranges,
|
|
25
|
+
plot_points=None,
|
|
26
|
+
return_vars=False,
|
|
27
|
+
imaginary_tolerance=1e-8):
|
|
28
|
+
r"""
|
|
29
|
+
Calculate the necessary parameters to construct a list of points,
|
|
30
|
+
and make the functions fast_callable.
|
|
31
|
+
|
|
32
|
+
INPUT:
|
|
33
|
+
|
|
34
|
+
- ``funcs`` -- a function, or a list, tuple, or vector of functions
|
|
35
|
+
|
|
36
|
+
- ``ranges`` -- list of ranges. A range can be a 2-tuple of
|
|
37
|
+
numbers specifying the minimum and maximum, or a 3-tuple giving
|
|
38
|
+
the variable explicitly.
|
|
39
|
+
|
|
40
|
+
- ``plot_points`` -- tuple of integers specifying the number of
|
|
41
|
+
plot points for each range. If a single number is specified, it
|
|
42
|
+
will be the value for all ranges. This defaults to 2.
|
|
43
|
+
|
|
44
|
+
- ``return_vars`` -- (default: ``False``) if ``True``, return the variables,
|
|
45
|
+
in order
|
|
46
|
+
|
|
47
|
+
- ``imaginary_tolerance`` -- (default: ``1e-8``) if an imaginary
|
|
48
|
+
number arises (due, for example, to numerical issues), this
|
|
49
|
+
tolerance specifies how large it has to be in magnitude before
|
|
50
|
+
we raise an error. In other words, imaginary parts smaller than
|
|
51
|
+
this are ignored in your plot points.
|
|
52
|
+
|
|
53
|
+
OUTPUT:
|
|
54
|
+
|
|
55
|
+
- ``fast_funcs`` -- if only one function passed, then a fast
|
|
56
|
+
callable function. If funcs is a list or tuple, then a tuple
|
|
57
|
+
of fast callable functions is returned.
|
|
58
|
+
|
|
59
|
+
- ``range_specs`` -- list of range_specs: for each range, a
|
|
60
|
+
tuple is returned of the form (range_min, range_max,
|
|
61
|
+
range_step) such that ``srange(range_min, range_max,
|
|
62
|
+
range_step, include_endpoint=True)`` gives the correct points
|
|
63
|
+
for evaluation.
|
|
64
|
+
|
|
65
|
+
EXAMPLES::
|
|
66
|
+
|
|
67
|
+
sage: x,y,z = var('x,y,z')
|
|
68
|
+
sage: f(x,y) = x+y-z
|
|
69
|
+
sage: g(x,y) = x+y
|
|
70
|
+
sage: h(y) = -y
|
|
71
|
+
sage: sage.plot.misc.setup_for_eval_on_grid(f, [(0, 2),(1,3),(-4,1)], plot_points=5)
|
|
72
|
+
(<sage...>, [(0.0, 2.0, 0.5), (1.0, 3.0, 0.5), (-4.0, 1.0, 1.25)])
|
|
73
|
+
sage: sage.plot.misc.setup_for_eval_on_grid([g,h], [(0, 2),(-1,1)], plot_points=5)
|
|
74
|
+
((<sage...>, <sage...>), [(0.0, 2.0, 0.5), (-1.0, 1.0, 0.5)])
|
|
75
|
+
sage: sage.plot.misc.setup_for_eval_on_grid([sin,cos], [(-1,1)], plot_points=9)
|
|
76
|
+
((<sage...>, <sage...>), [(-1.0, 1.0, 0.25)])
|
|
77
|
+
sage: sage.plot.misc.setup_for_eval_on_grid([lambda x: x^2,cos], [(-1,1)], plot_points=9)
|
|
78
|
+
((<function <lambda> ...>, <sage...>), [(-1.0, 1.0, 0.25)])
|
|
79
|
+
sage: sage.plot.misc.setup_for_eval_on_grid([x+y], [(x,-1,1),(y,-2,2)])
|
|
80
|
+
((<sage...>,), [(-1.0, 1.0, 2.0), (-2.0, 2.0, 4.0)])
|
|
81
|
+
sage: sage.plot.misc.setup_for_eval_on_grid(x+y, [(x,-1,1),(y,-1,1)], plot_points=[4,9])
|
|
82
|
+
(<sage...>, [(-1.0, 1.0, 0.6666666666666666), (-1.0, 1.0, 0.25)])
|
|
83
|
+
sage: sage.plot.misc.setup_for_eval_on_grid(x+y, [(x,-1,1),(y,-1,1)], plot_points=[4,9,10])
|
|
84
|
+
Traceback (most recent call last):
|
|
85
|
+
...
|
|
86
|
+
ValueError: plot_points must be either an integer or a list of integers, one for each range
|
|
87
|
+
sage: sage.plot.misc.setup_for_eval_on_grid(x+y, [(1,-1),(y,-1,1)], plot_points=[4,9,10])
|
|
88
|
+
Traceback (most recent call last):
|
|
89
|
+
...
|
|
90
|
+
ValueError: Some variable ranges specify variables while others do not
|
|
91
|
+
|
|
92
|
+
Beware typos: a comma which should be a period, for instance::
|
|
93
|
+
|
|
94
|
+
sage: sage.plot.misc.setup_for_eval_on_grid(x+y, [(x, 1, 2), (y, 0,1, 0.2)], plot_points=[4,9,10])
|
|
95
|
+
Traceback (most recent call last):
|
|
96
|
+
...
|
|
97
|
+
ValueError: At least one variable range has more than 3 entries: each should either have 2 or 3 entries, with one of the forms (xmin, xmax) or (x, xmin, xmax)
|
|
98
|
+
|
|
99
|
+
sage: sage.plot.misc.setup_for_eval_on_grid(x+y, [(y,1,-1),(x,-1,1)], plot_points=5)
|
|
100
|
+
(<sage...>, [(-1.0, 1.0, 0.5), (-1.0, 1.0, 0.5)])
|
|
101
|
+
sage: sage.plot.misc.setup_for_eval_on_grid(x+y, [(x,1,-1),(x,-1,1)], plot_points=5)
|
|
102
|
+
Traceback (most recent call last):
|
|
103
|
+
...
|
|
104
|
+
ValueError: range variables should be distinct, but there are duplicates
|
|
105
|
+
sage: sage.plot.misc.setup_for_eval_on_grid(x+y, [(x,1,1),(y,-1,1)])
|
|
106
|
+
Traceback (most recent call last):
|
|
107
|
+
...
|
|
108
|
+
ValueError: plot start point and end point must be different
|
|
109
|
+
sage: sage.plot.misc.setup_for_eval_on_grid(x+y, [(x,1,-1),(y,-1,1)], return_vars=True)
|
|
110
|
+
(<sage...>, [(-1.0, 1.0, 2.0), (-1.0, 1.0, 2.0)], [x, y])
|
|
111
|
+
sage: sage.plot.misc.setup_for_eval_on_grid(x+y, [(y,1,-1),(x,-1,1)], return_vars=True)
|
|
112
|
+
(<sage...>, [(-1.0, 1.0, 2.0), (-1.0, 1.0, 2.0)], [y, x])
|
|
113
|
+
|
|
114
|
+
TESTS:
|
|
115
|
+
|
|
116
|
+
Ensure that we can plot expressions with intermediate complex
|
|
117
|
+
terms as in :issue:`8450`::
|
|
118
|
+
|
|
119
|
+
sage: x, y = SR.var('x y')
|
|
120
|
+
sage: contour_plot(abs(x+i*y), (x,-1,1), (y,-1,1))
|
|
121
|
+
Graphics object consisting of 1 graphics primitive
|
|
122
|
+
sage: density_plot(abs(x+i*y), (x,-1,1), (y,-1,1))
|
|
123
|
+
Graphics object consisting of 1 graphics primitive
|
|
124
|
+
sage: plot3d(abs(x+i*y), (x,-1,1),(y,-1,1))
|
|
125
|
+
Graphics3d Object
|
|
126
|
+
sage: streamline_plot(abs(x+i*y), (x,-1,1),(y,-1,1))
|
|
127
|
+
Graphics object consisting of 1 graphics primitive
|
|
128
|
+
"""
|
|
129
|
+
if max(map(len, ranges)) > 3:
|
|
130
|
+
raise ValueError("At least one variable range has more than 3 entries: each should either have 2 or 3 entries, with one of the forms (xmin, xmax) or (x, xmin, xmax)")
|
|
131
|
+
if max(map(len, ranges)) != min(map(len, ranges)):
|
|
132
|
+
raise ValueError("Some variable ranges specify variables while others do not")
|
|
133
|
+
|
|
134
|
+
if len(ranges[0]) == 3:
|
|
135
|
+
vars = [r[0] for r in ranges]
|
|
136
|
+
ranges = [r[1:] for r in ranges]
|
|
137
|
+
if len(set(vars)) < len(vars):
|
|
138
|
+
raise ValueError("range variables should be distinct, but there are duplicates")
|
|
139
|
+
else:
|
|
140
|
+
vars, free_vars = unify_arguments(funcs)
|
|
141
|
+
|
|
142
|
+
# check for invalid range (xmin > xmax or ymin > ymax) and swap
|
|
143
|
+
if len(ranges) > 1:
|
|
144
|
+
for i in range(len(ranges)):
|
|
145
|
+
if ranges[i][-2] > ranges[i][-1]:
|
|
146
|
+
ranges[i] = list(ranges[i])
|
|
147
|
+
ranges[i][-1], ranges[i][-2] = ranges[i][-2], ranges[i][-1]
|
|
148
|
+
ranges[i] = tuple(ranges[i])
|
|
149
|
+
|
|
150
|
+
# pad the variables if we don't have enough
|
|
151
|
+
nargs = len(ranges)
|
|
152
|
+
if len(vars) < nargs:
|
|
153
|
+
vars += ('_',) * (nargs - len(vars))
|
|
154
|
+
|
|
155
|
+
ranges = [[float(z) for z in r] for r in ranges]
|
|
156
|
+
|
|
157
|
+
if plot_points is None:
|
|
158
|
+
plot_points = 2
|
|
159
|
+
|
|
160
|
+
if not isinstance(plot_points, (list, tuple)):
|
|
161
|
+
plot_points = [plot_points] * len(ranges)
|
|
162
|
+
elif len(plot_points) != nargs:
|
|
163
|
+
raise ValueError("plot_points must be either an integer or a list of integers, one for each range")
|
|
164
|
+
|
|
165
|
+
plot_points = [int(p) if p >= 2 else 2 for p in plot_points]
|
|
166
|
+
range_steps = [abs(range[1] - range[0]) / (p - 1)
|
|
167
|
+
for range, p in zip(ranges, plot_points)]
|
|
168
|
+
if min(range_steps) == float(0):
|
|
169
|
+
raise ValueError("plot start point and end point must be different")
|
|
170
|
+
|
|
171
|
+
eov = False # eov = "expect one value"
|
|
172
|
+
if nargs == 1:
|
|
173
|
+
eov = True
|
|
174
|
+
|
|
175
|
+
from sage.ext.fast_callable import fast_callable
|
|
176
|
+
|
|
177
|
+
def try_make_fast(f):
|
|
178
|
+
# If "f" supports fast_callable(), use it. We can't guarantee
|
|
179
|
+
# that our arguments will actually support fast_callable()
|
|
180
|
+
# because, for example, the user may already have done it
|
|
181
|
+
# himself, and the result of fast_callable() can't be
|
|
182
|
+
# fast-callabled again.
|
|
183
|
+
from sage.rings.complex_double import CDF
|
|
184
|
+
from sage.ext.interpreters.wrapper_cdf import Wrapper_cdf
|
|
185
|
+
|
|
186
|
+
if hasattr(f, '_fast_callable_'):
|
|
187
|
+
ff = fast_callable(f, vars=vars, expect_one_var=eov, domain=CDF)
|
|
188
|
+
return FastCallablePlotWrapper(ff, imag_tol=imaginary_tolerance)
|
|
189
|
+
elif isinstance(f, Wrapper_cdf):
|
|
190
|
+
# Already a fast-callable, just wrap it. This can happen
|
|
191
|
+
# if, for example, a symbolic expression is passed to a
|
|
192
|
+
# higher-level plot() function that converts it to a
|
|
193
|
+
# fast-callable with expr._plot_fast_callable() before
|
|
194
|
+
# we ever see it.
|
|
195
|
+
return FastCallablePlotWrapper(f, imag_tol=imaginary_tolerance)
|
|
196
|
+
elif callable(f):
|
|
197
|
+
# This will catch python functions, among other things. We don't
|
|
198
|
+
# wrap these yet because we don't know what type they'll return.
|
|
199
|
+
return f
|
|
200
|
+
else:
|
|
201
|
+
# Convert things like ZZ(0) into constant functions.
|
|
202
|
+
from sage.symbolic.ring import SR
|
|
203
|
+
ff = fast_callable(SR(f),
|
|
204
|
+
vars=vars,
|
|
205
|
+
expect_one_var=eov,
|
|
206
|
+
domain=CDF)
|
|
207
|
+
return FastCallablePlotWrapper(ff, imag_tol=imaginary_tolerance)
|
|
208
|
+
|
|
209
|
+
# Handle vectors, lists, tuples, etc.
|
|
210
|
+
if isinstance(funcs, Iterable):
|
|
211
|
+
funcs = tuple(try_make_fast(f) for f in funcs)
|
|
212
|
+
else:
|
|
213
|
+
funcs = try_make_fast(funcs)
|
|
214
|
+
|
|
215
|
+
# TODO: raise an error if there is a function/method in funcs that
|
|
216
|
+
# takes more values than we have ranges
|
|
217
|
+
|
|
218
|
+
if return_vars:
|
|
219
|
+
return (funcs,
|
|
220
|
+
[tuple(_range + [range_step])
|
|
221
|
+
for _range, range_step in zip(ranges, range_steps)],
|
|
222
|
+
vars)
|
|
223
|
+
else:
|
|
224
|
+
return (funcs,
|
|
225
|
+
[tuple(_range + [range_step])
|
|
226
|
+
for _range, range_step in zip(ranges, range_steps)])
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def unify_arguments(funcs):
|
|
230
|
+
"""
|
|
231
|
+
Return a tuple of variables of the functions, as well as the
|
|
232
|
+
number of "free" variables (i.e., variables that defined in a
|
|
233
|
+
callable function).
|
|
234
|
+
|
|
235
|
+
INPUT:
|
|
236
|
+
|
|
237
|
+
- ``funcs`` -- list of functions; these can be symbolic
|
|
238
|
+
expressions, polynomials, etc.
|
|
239
|
+
|
|
240
|
+
OUTPUT: functions, expected arguments
|
|
241
|
+
|
|
242
|
+
- A tuple of variables in the functions
|
|
243
|
+
|
|
244
|
+
- A tuple of variables that were "free" in the functions
|
|
245
|
+
|
|
246
|
+
EXAMPLES::
|
|
247
|
+
|
|
248
|
+
sage: x,y,z = var('x,y,z')
|
|
249
|
+
sage: f(x,y) = x+y-z
|
|
250
|
+
sage: g(x,y) = x+y
|
|
251
|
+
sage: h(y) = -y
|
|
252
|
+
sage: sage.plot.misc.unify_arguments((f,g,h))
|
|
253
|
+
((x, y, z), (z,))
|
|
254
|
+
sage: sage.plot.misc.unify_arguments((g,h))
|
|
255
|
+
((x, y), ())
|
|
256
|
+
sage: sage.plot.misc.unify_arguments((f,z))
|
|
257
|
+
((x, y, z), (z,))
|
|
258
|
+
sage: sage.plot.misc.unify_arguments((h,z))
|
|
259
|
+
((y, z), (z,))
|
|
260
|
+
sage: sage.plot.misc.unify_arguments((x+y,x-y))
|
|
261
|
+
((x, y), (x, y))
|
|
262
|
+
"""
|
|
263
|
+
vars = set()
|
|
264
|
+
free_variables = set()
|
|
265
|
+
if not isinstance(funcs, (list, tuple)):
|
|
266
|
+
funcs = [funcs]
|
|
267
|
+
|
|
268
|
+
from sage.structure.element import Expression
|
|
269
|
+
for f in funcs:
|
|
270
|
+
if isinstance(f, Expression) and f.is_callable():
|
|
271
|
+
f_args = set(f.arguments())
|
|
272
|
+
vars.update(f_args)
|
|
273
|
+
else:
|
|
274
|
+
f_args = set()
|
|
275
|
+
|
|
276
|
+
try:
|
|
277
|
+
free_vars = set(f.variables()).difference(f_args)
|
|
278
|
+
vars.update(free_vars)
|
|
279
|
+
free_variables.update(free_vars)
|
|
280
|
+
except AttributeError:
|
|
281
|
+
# we probably have a constant
|
|
282
|
+
pass
|
|
283
|
+
return tuple(sorted(vars, key=str)), tuple(sorted(free_variables, key=str))
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
def _multiple_of_constant(n, pos, const):
|
|
287
|
+
r"""
|
|
288
|
+
Function for internal use in formatting ticks on axes with
|
|
289
|
+
nice-looking multiples of various symbolic constants, such
|
|
290
|
+
as `\pi` or `e`.
|
|
291
|
+
|
|
292
|
+
This should only be used via keyword argument
|
|
293
|
+
``tick_formatter`` in :meth:`plot.show`. See documentation
|
|
294
|
+
for the matplotlib.ticker module for more details.
|
|
295
|
+
|
|
296
|
+
EXAMPLES:
|
|
297
|
+
|
|
298
|
+
Here is the intended use::
|
|
299
|
+
|
|
300
|
+
sage: plot(sin(x), (x,0,2*pi), ticks=pi/3, tick_formatter=pi)
|
|
301
|
+
Graphics object consisting of 1 graphics primitive
|
|
302
|
+
|
|
303
|
+
Here is an unintended use, which yields unexpected (and probably
|
|
304
|
+
undesired) results::
|
|
305
|
+
|
|
306
|
+
sage: plot(x^2, (x, -2, 2), tick_formatter=pi)
|
|
307
|
+
Graphics object consisting of 1 graphics primitive
|
|
308
|
+
|
|
309
|
+
We can also use more unusual constant choices::
|
|
310
|
+
|
|
311
|
+
sage: plot(ln(x), (x,0,10), ticks=e, tick_formatter=e)
|
|
312
|
+
Graphics object consisting of 1 graphics primitive
|
|
313
|
+
sage: plot(x^2, (x,0,10), ticks=[sqrt(2),8], tick_formatter=sqrt(2))
|
|
314
|
+
Graphics object consisting of 1 graphics primitive
|
|
315
|
+
"""
|
|
316
|
+
from sage.misc.latex import latex
|
|
317
|
+
from sage.rings.continued_fraction import continued_fraction
|
|
318
|
+
from sage.rings.infinity import Infinity
|
|
319
|
+
cf = continued_fraction(n / const)
|
|
320
|
+
k = 1
|
|
321
|
+
while cf.quotient(k) != Infinity and cf.denominator(k) < 12:
|
|
322
|
+
k += 1
|
|
323
|
+
return '$%s$' % latex(cf.convergent(k - 1) * const)
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
def get_matplotlib_linestyle(linestyle, return_type):
|
|
327
|
+
"""
|
|
328
|
+
Function which translates between matplotlib linestyle in short notation
|
|
329
|
+
(i.e. '-', '--', ':', '-.') and long notation (i.e. 'solid', 'dashed',
|
|
330
|
+
'dotted', 'dashdot' ).
|
|
331
|
+
|
|
332
|
+
If linestyle is none of these allowed options, the function raises
|
|
333
|
+
a :exc:`ValueError`.
|
|
334
|
+
|
|
335
|
+
INPUT:
|
|
336
|
+
|
|
337
|
+
- ``linestyle`` -- the style of the line, which is one of
|
|
338
|
+
- ``'-'`` or ``'solid'``
|
|
339
|
+
- ``'--'`` or ``'dashed'``
|
|
340
|
+
- ``'-.'`` or ``'dash dot'``
|
|
341
|
+
- ``':'`` or ``'dotted'``
|
|
342
|
+
- ``"None"`` or ``" "`` or ``""`` (nothing)
|
|
343
|
+
|
|
344
|
+
The linestyle can also be prefixed with a drawing style (e.g., ``'steps--'``)
|
|
345
|
+
|
|
346
|
+
- ``'default'`` (connect the points with straight lines)
|
|
347
|
+
- ``'steps'`` or ``'steps-pre'`` (step function; horizontal
|
|
348
|
+
line is to the left of point)
|
|
349
|
+
- ``'steps-mid'`` (step function; points are in the middle of
|
|
350
|
+
horizontal lines)
|
|
351
|
+
- ``'steps-post'`` (step function; horizontal line is to the
|
|
352
|
+
right of point)
|
|
353
|
+
|
|
354
|
+
If ``linestyle`` is ``None`` (of type NoneType), then we return it
|
|
355
|
+
back unmodified.
|
|
356
|
+
|
|
357
|
+
- ``return_type`` -- the type of linestyle that should be output. This
|
|
358
|
+
argument takes only two values - ``'long'`` or ``'short'``
|
|
359
|
+
|
|
360
|
+
EXAMPLES:
|
|
361
|
+
|
|
362
|
+
Here is an example how to call this function::
|
|
363
|
+
|
|
364
|
+
sage: from sage.plot.misc import get_matplotlib_linestyle
|
|
365
|
+
sage: get_matplotlib_linestyle(':', return_type='short')
|
|
366
|
+
':'
|
|
367
|
+
|
|
368
|
+
sage: get_matplotlib_linestyle(':', return_type='long')
|
|
369
|
+
'dotted'
|
|
370
|
+
|
|
371
|
+
TESTS:
|
|
372
|
+
|
|
373
|
+
Make sure that if the input is already in the desired format, then it
|
|
374
|
+
is unchanged::
|
|
375
|
+
|
|
376
|
+
sage: get_matplotlib_linestyle(':', 'short')
|
|
377
|
+
':'
|
|
378
|
+
|
|
379
|
+
Empty linestyles should be handled properly::
|
|
380
|
+
|
|
381
|
+
sage: get_matplotlib_linestyle("", 'short')
|
|
382
|
+
''
|
|
383
|
+
sage: get_matplotlib_linestyle("", 'long')
|
|
384
|
+
'None'
|
|
385
|
+
sage: get_matplotlib_linestyle(None, 'short') is None
|
|
386
|
+
True
|
|
387
|
+
|
|
388
|
+
Linestyles with ``'default'`` or ``'steps'`` in them should also be
|
|
389
|
+
properly handled. For instance, matplotlib understands only the short
|
|
390
|
+
version when ``'steps'`` is used::
|
|
391
|
+
|
|
392
|
+
sage: get_matplotlib_linestyle("default", "short")
|
|
393
|
+
''
|
|
394
|
+
sage: get_matplotlib_linestyle("steps--", "short")
|
|
395
|
+
'steps--'
|
|
396
|
+
sage: get_matplotlib_linestyle("steps-predashed", "long")
|
|
397
|
+
'steps-pre--'
|
|
398
|
+
|
|
399
|
+
Finally, raise error on invalid linestyles::
|
|
400
|
+
|
|
401
|
+
sage: get_matplotlib_linestyle("isthissage", "long")
|
|
402
|
+
Traceback (most recent call last):
|
|
403
|
+
...
|
|
404
|
+
ValueError: WARNING: Unrecognized linestyle 'isthissage'. Possible
|
|
405
|
+
linestyle options are:
|
|
406
|
+
{'solid', 'dashed', 'dotted', dashdot', 'None'}, respectively {'-',
|
|
407
|
+
'--', ':', '-.', ''}
|
|
408
|
+
"""
|
|
409
|
+
long_to_short_dict = {'solid': '-',
|
|
410
|
+
'dashed': '--',
|
|
411
|
+
'dotted': ':',
|
|
412
|
+
'dashdot': '-.'}
|
|
413
|
+
short_to_long_dict = {'-': 'solid',
|
|
414
|
+
'--': 'dashed',
|
|
415
|
+
':': 'dotted',
|
|
416
|
+
'-.': 'dashdot'}
|
|
417
|
+
|
|
418
|
+
# We need this to take care of region plot. Essentially, if None is
|
|
419
|
+
# passed, then we just return back the same thing.
|
|
420
|
+
if linestyle is None:
|
|
421
|
+
return None
|
|
422
|
+
|
|
423
|
+
if linestyle.startswith("default"):
|
|
424
|
+
return get_matplotlib_linestyle(linestyle.strip("default"), "short")
|
|
425
|
+
elif linestyle.startswith("steps"):
|
|
426
|
+
if linestyle.startswith("steps-mid"):
|
|
427
|
+
return "steps-mid" + get_matplotlib_linestyle(
|
|
428
|
+
linestyle.strip("steps-mid"), "short")
|
|
429
|
+
elif linestyle.startswith("steps-post"):
|
|
430
|
+
return "steps-post" + get_matplotlib_linestyle(
|
|
431
|
+
linestyle.strip("steps-post"), "short")
|
|
432
|
+
elif linestyle.startswith("steps-pre"):
|
|
433
|
+
return "steps-pre" + get_matplotlib_linestyle(
|
|
434
|
+
linestyle.strip("steps-pre"), "short")
|
|
435
|
+
else:
|
|
436
|
+
return "steps" + get_matplotlib_linestyle(
|
|
437
|
+
linestyle.strip("steps"), "short")
|
|
438
|
+
|
|
439
|
+
if return_type == 'short':
|
|
440
|
+
if linestyle in short_to_long_dict.keys():
|
|
441
|
+
return linestyle
|
|
442
|
+
elif linestyle == "" or linestyle == " " or linestyle == "None":
|
|
443
|
+
return ''
|
|
444
|
+
elif linestyle in long_to_short_dict.keys():
|
|
445
|
+
return long_to_short_dict[linestyle]
|
|
446
|
+
else:
|
|
447
|
+
raise ValueError("WARNING: Unrecognized linestyle '%s'. "
|
|
448
|
+
"Possible linestyle options are:\n{'solid', "
|
|
449
|
+
"'dashed', 'dotted', dashdot', 'None'}, "
|
|
450
|
+
"respectively {'-', '--', ':', '-.', ''}" %
|
|
451
|
+
(linestyle))
|
|
452
|
+
|
|
453
|
+
elif return_type == 'long':
|
|
454
|
+
if linestyle in long_to_short_dict.keys():
|
|
455
|
+
return linestyle
|
|
456
|
+
elif linestyle == "" or linestyle == " " or linestyle == "None":
|
|
457
|
+
return "None"
|
|
458
|
+
elif linestyle in short_to_long_dict.keys():
|
|
459
|
+
return short_to_long_dict[linestyle]
|
|
460
|
+
else:
|
|
461
|
+
raise ValueError("WARNING: Unrecognized linestyle '%s'. "
|
|
462
|
+
"Possible linestyle options are:\n{'solid', "
|
|
463
|
+
"'dashed', 'dotted', dashdot', 'None'}, "
|
|
464
|
+
"respectively {'-', '--', ':', '-.', ''}" %
|
|
465
|
+
(linestyle))
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
class FastCallablePlotWrapper(FastCallableFloatWrapper):
|
|
469
|
+
r"""
|
|
470
|
+
A fast-callable wrapper for plotting that returns ``nan`` instead
|
|
471
|
+
of raising an error whenever the imaginary tolerance is exceeded.
|
|
472
|
+
|
|
473
|
+
A detailed rationale for this can be found in the superclass
|
|
474
|
+
documentation.
|
|
475
|
+
|
|
476
|
+
EXAMPLES:
|
|
477
|
+
|
|
478
|
+
The ``float`` incarnation of "not a number" is returned instead
|
|
479
|
+
of an error being thrown if the answer is complex::
|
|
480
|
+
|
|
481
|
+
sage: from sage.plot.misc import FastCallablePlotWrapper
|
|
482
|
+
sage: f = sqrt(x)
|
|
483
|
+
sage: ff = fast_callable(f, vars=[x], domain=CDF)
|
|
484
|
+
sage: fff = FastCallablePlotWrapper(ff, imag_tol=1e-8)
|
|
485
|
+
sage: fff(1)
|
|
486
|
+
1.0
|
|
487
|
+
sage: fff(-1)
|
|
488
|
+
nan
|
|
489
|
+
"""
|
|
490
|
+
def __call__(self, *args):
|
|
491
|
+
r"""
|
|
492
|
+
Evaluate the underlying fast-callable and convert the result to
|
|
493
|
+
``float``.
|
|
494
|
+
|
|
495
|
+
TESTS:
|
|
496
|
+
|
|
497
|
+
Evaluation never fails and always returns a ``float``::
|
|
498
|
+
|
|
499
|
+
sage: from sage.plot.misc import FastCallablePlotWrapper
|
|
500
|
+
sage: f = x
|
|
501
|
+
sage: ff = fast_callable(f, vars=[x], domain=CDF)
|
|
502
|
+
sage: fff = FastCallablePlotWrapper(ff, imag_tol=0.1)
|
|
503
|
+
sage: type(fff(CDF.random_element())) is float
|
|
504
|
+
True
|
|
505
|
+
"""
|
|
506
|
+
try:
|
|
507
|
+
return super().__call__(*args)
|
|
508
|
+
except ValueError:
|
|
509
|
+
return float("nan")
|