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
|
@@ -0,0 +1,1792 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-plot
|
|
2
|
+
# sage.doctest: needs sage.symbolic
|
|
3
|
+
"""
|
|
4
|
+
Contour plots
|
|
5
|
+
"""
|
|
6
|
+
# ****************************************************************************
|
|
7
|
+
# Copyright (C) 2006 Alex Clemesha <clemesha@gmail.com>,
|
|
8
|
+
# William Stein <wstein@gmail.com>,
|
|
9
|
+
# 2008 Mike Hansen <mhansen@gmail.com>,
|
|
10
|
+
#
|
|
11
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
12
|
+
#
|
|
13
|
+
# This code is distributed in the hope that it will be useful,
|
|
14
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
15
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
16
|
+
# General Public License for more details.
|
|
17
|
+
#
|
|
18
|
+
# The full text of the GPL is available at:
|
|
19
|
+
#
|
|
20
|
+
# https://www.gnu.org/licenses/
|
|
21
|
+
# ****************************************************************************
|
|
22
|
+
import operator
|
|
23
|
+
from sage.plot.primitive import GraphicPrimitive
|
|
24
|
+
from sage.misc.decorators import options, suboptions
|
|
25
|
+
from sage.plot.colors import rgbcolor, get_cmap
|
|
26
|
+
from sage.arith.srange import xsrange
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class ContourPlot(GraphicPrimitive):
|
|
30
|
+
"""
|
|
31
|
+
Primitive class for the contour plot graphics type.
|
|
32
|
+
|
|
33
|
+
See ``contour_plot?`` for help actually doing contour plots.
|
|
34
|
+
|
|
35
|
+
INPUT:
|
|
36
|
+
|
|
37
|
+
- ``xy_data_array`` -- list of lists giving evaluated values of the function
|
|
38
|
+
on the grid
|
|
39
|
+
|
|
40
|
+
- ``xrange`` -- tuple of 2 floats indicating range for horizontal direction
|
|
41
|
+
|
|
42
|
+
- ``yrange`` -- tuple of 2 floats indicating range for vertical direction
|
|
43
|
+
|
|
44
|
+
- ``options`` -- dictionary of valid plot options to pass to constructor
|
|
45
|
+
|
|
46
|
+
EXAMPLES:
|
|
47
|
+
|
|
48
|
+
Note this should normally be used indirectly via ``contour_plot``::
|
|
49
|
+
|
|
50
|
+
sage: from sage.plot.contour_plot import ContourPlot
|
|
51
|
+
sage: C = ContourPlot([[1,3],[2,4]], (1,2), (2,3), options={})
|
|
52
|
+
sage: C
|
|
53
|
+
ContourPlot defined by a 2 x 2 data grid
|
|
54
|
+
sage: C.xrange
|
|
55
|
+
(1, 2)
|
|
56
|
+
|
|
57
|
+
TESTS:
|
|
58
|
+
|
|
59
|
+
We test creating a contour plot::
|
|
60
|
+
|
|
61
|
+
sage: x,y = var('x,y')
|
|
62
|
+
sage: contour_plot(x^2-y^3+10*sin(x*y), (x,-4,4), (y,-4,4),
|
|
63
|
+
....: plot_points=121, cmap='hsv')
|
|
64
|
+
Graphics object consisting of 1 graphics primitive
|
|
65
|
+
"""
|
|
66
|
+
def __init__(self, xy_data_array, xrange, yrange, options):
|
|
67
|
+
"""
|
|
68
|
+
Initialize base class ``ContourPlot``.
|
|
69
|
+
|
|
70
|
+
EXAMPLES::
|
|
71
|
+
|
|
72
|
+
sage: x,y = var('x,y')
|
|
73
|
+
sage: C = contour_plot(x^2-y^3+10*sin(x*y), (x,-4,4), (y,-4,4),
|
|
74
|
+
....: plot_points=121, cmap='hsv')
|
|
75
|
+
sage: C[0].xrange
|
|
76
|
+
(-4.0, 4.0)
|
|
77
|
+
sage: C[0].options()['plot_points']
|
|
78
|
+
121
|
|
79
|
+
"""
|
|
80
|
+
self.xrange = xrange
|
|
81
|
+
self.yrange = yrange
|
|
82
|
+
self.xy_data_array = xy_data_array
|
|
83
|
+
self.xy_array_row = len(xy_data_array)
|
|
84
|
+
self.xy_array_col = len(xy_data_array[0])
|
|
85
|
+
GraphicPrimitive.__init__(self, options)
|
|
86
|
+
|
|
87
|
+
def get_minmax_data(self):
|
|
88
|
+
"""
|
|
89
|
+
Return a dictionary with the bounding box data.
|
|
90
|
+
|
|
91
|
+
EXAMPLES::
|
|
92
|
+
|
|
93
|
+
sage: x,y = var('x,y')
|
|
94
|
+
sage: f(x,y) = x^2 + y^2
|
|
95
|
+
sage: d = contour_plot(f, (3,6), (3,6))[0].get_minmax_data()
|
|
96
|
+
sage: d['xmin']
|
|
97
|
+
3.0
|
|
98
|
+
sage: d['ymin']
|
|
99
|
+
3.0
|
|
100
|
+
"""
|
|
101
|
+
from sage.plot.plot import minmax_data
|
|
102
|
+
return minmax_data(self.xrange, self.yrange, dict=True)
|
|
103
|
+
|
|
104
|
+
def _allowed_options(self):
|
|
105
|
+
"""
|
|
106
|
+
Return the allowed options for the ContourPlot class.
|
|
107
|
+
|
|
108
|
+
EXAMPLES::
|
|
109
|
+
|
|
110
|
+
sage: x,y = var('x,y')
|
|
111
|
+
sage: C = contour_plot(x^2 - y^2, (x,-2,2), (y,-2,2))
|
|
112
|
+
sage: isinstance(C[0]._allowed_options(), dict)
|
|
113
|
+
True
|
|
114
|
+
"""
|
|
115
|
+
return {'plot_points': 'How many points to use for plotting precision',
|
|
116
|
+
'cmap': """the name of a predefined colormap,
|
|
117
|
+
a list of colors, or an instance of a
|
|
118
|
+
matplotlib Colormap. Type: import matplotlib.cm;
|
|
119
|
+
matplotlib.cm.datad.keys()
|
|
120
|
+
for available colormap names.""",
|
|
121
|
+
'colorbar': "Include a colorbar indicating the levels",
|
|
122
|
+
'colorbar_options': "a dictionary of options for colorbars",
|
|
123
|
+
'fill': 'Fill contours or not',
|
|
124
|
+
'legend_label': 'The label for this item in the legend.',
|
|
125
|
+
'contours': """Either an integer specifying the number of
|
|
126
|
+
contour levels, or a sequence of numbers giving
|
|
127
|
+
the actual contours to use.""",
|
|
128
|
+
'linewidths': 'the width of the lines to be plotted',
|
|
129
|
+
'linestyles': 'the style of the lines to be plotted',
|
|
130
|
+
'labels': 'show line labels or not',
|
|
131
|
+
'label_options': 'a dictionary of options for the labels',
|
|
132
|
+
'zorder': 'The layer level in which to draw'}
|
|
133
|
+
|
|
134
|
+
def _repr_(self):
|
|
135
|
+
"""
|
|
136
|
+
String representation of ``ContourPlot`` primitive.
|
|
137
|
+
|
|
138
|
+
EXAMPLES::
|
|
139
|
+
|
|
140
|
+
sage: x,y = var('x,y')
|
|
141
|
+
sage: C = contour_plot(x^2 - y^2, (x,-2,2), (y,-2,2))
|
|
142
|
+
sage: c = C[0]; c
|
|
143
|
+
ContourPlot defined by a 100 x 100 data grid
|
|
144
|
+
"""
|
|
145
|
+
msg = "ContourPlot defined by a %s x %s data grid"
|
|
146
|
+
return msg % (self.xy_array_row, self.xy_array_col)
|
|
147
|
+
|
|
148
|
+
def _render_on_subplot(self, subplot):
|
|
149
|
+
"""
|
|
150
|
+
TESTS:
|
|
151
|
+
|
|
152
|
+
A somewhat random plot, but fun to look at::
|
|
153
|
+
|
|
154
|
+
sage: x,y = var('x,y')
|
|
155
|
+
sage: contour_plot(x^2 - y^3 + 10*sin(x*y), (x,-4,4), (y,-4,4),
|
|
156
|
+
....: plot_points=121, cmap='hsv')
|
|
157
|
+
Graphics object consisting of 1 graphics primitive
|
|
158
|
+
"""
|
|
159
|
+
from sage.rings.integer import Integer
|
|
160
|
+
options = self.options()
|
|
161
|
+
fill = options['fill']
|
|
162
|
+
contours = options['contours']
|
|
163
|
+
if 'cmap' in options:
|
|
164
|
+
cmap = get_cmap(options['cmap'])
|
|
165
|
+
elif fill or contours is None:
|
|
166
|
+
cmap = get_cmap('gray')
|
|
167
|
+
else:
|
|
168
|
+
if isinstance(contours, (int, Integer)):
|
|
169
|
+
cmap = get_cmap([(i, i, i)
|
|
170
|
+
for i in xsrange(0, 1, 1 / contours)])
|
|
171
|
+
else:
|
|
172
|
+
step = 1 / Integer(len(contours))
|
|
173
|
+
cmap = get_cmap([(i, i, i) for i in xsrange(0, 1, step)])
|
|
174
|
+
|
|
175
|
+
x0, x1 = float(self.xrange[0]), float(self.xrange[1])
|
|
176
|
+
y0, y1 = float(self.yrange[0]), float(self.yrange[1])
|
|
177
|
+
|
|
178
|
+
if isinstance(contours, (int, Integer)):
|
|
179
|
+
contours = int(contours)
|
|
180
|
+
|
|
181
|
+
CSF = None
|
|
182
|
+
if fill:
|
|
183
|
+
if contours is None:
|
|
184
|
+
CSF = subplot.contourf(self.xy_data_array, cmap=cmap,
|
|
185
|
+
extent=(x0, x1, y0, y1))
|
|
186
|
+
else:
|
|
187
|
+
CSF = subplot.contourf(self.xy_data_array, contours, cmap=cmap,
|
|
188
|
+
extent=(x0, x1, y0, y1), extend='both')
|
|
189
|
+
|
|
190
|
+
linewidths = options.get('linewidths', None)
|
|
191
|
+
if isinstance(linewidths, (int, Integer)):
|
|
192
|
+
linewidths = int(linewidths)
|
|
193
|
+
elif isinstance(linewidths, (list, tuple)):
|
|
194
|
+
linewidths = tuple(int(x) for x in linewidths)
|
|
195
|
+
|
|
196
|
+
from sage.plot.misc import get_matplotlib_linestyle
|
|
197
|
+
linestyles = options.get('linestyles', None)
|
|
198
|
+
if isinstance(linestyles, (list, tuple)):
|
|
199
|
+
linestyles = [get_matplotlib_linestyle(i, 'long')
|
|
200
|
+
for i in linestyles]
|
|
201
|
+
else:
|
|
202
|
+
linestyles = get_matplotlib_linestyle(linestyles, 'long')
|
|
203
|
+
if contours is None:
|
|
204
|
+
CS = subplot.contour(self.xy_data_array, cmap=cmap,
|
|
205
|
+
extent=(x0, x1, y0, y1),
|
|
206
|
+
linewidths=linewidths, linestyles=linestyles)
|
|
207
|
+
else:
|
|
208
|
+
CS = subplot.contour(self.xy_data_array, contours, cmap=cmap,
|
|
209
|
+
extent=(x0, x1, y0, y1),
|
|
210
|
+
linewidths=linewidths, linestyles=linestyles)
|
|
211
|
+
if options.get('labels', False):
|
|
212
|
+
label_options = options['label_options']
|
|
213
|
+
label_options['fontsize'] = int(label_options['fontsize'])
|
|
214
|
+
if fill and label_options is None:
|
|
215
|
+
label_options['inline'] = False
|
|
216
|
+
subplot.clabel(CS, **label_options)
|
|
217
|
+
if options.get('colorbar', False):
|
|
218
|
+
colorbar_options = options['colorbar_options']
|
|
219
|
+
from matplotlib import colorbar
|
|
220
|
+
cax, kwds = colorbar.make_axes_gridspec(subplot, **colorbar_options)
|
|
221
|
+
if CSF is None:
|
|
222
|
+
cb = colorbar.Colorbar(cax, CS, **kwds)
|
|
223
|
+
else:
|
|
224
|
+
cb = colorbar.Colorbar(cax, CSF, **kwds)
|
|
225
|
+
cb.add_lines(CS)
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
@suboptions('colorbar', orientation='vertical', format=None, spacing='uniform')
|
|
229
|
+
@suboptions('label', fontsize=9, colors='blue', inline=None, inline_spacing=3,
|
|
230
|
+
fmt="%1.2f")
|
|
231
|
+
@options(plot_points=100, fill=True, contours=None, linewidths=None,
|
|
232
|
+
linestyles=None, labels=False, frame=True, axes=False, colorbar=False,
|
|
233
|
+
legend_label=None, aspect_ratio=1, region=None)
|
|
234
|
+
def contour_plot(f, xrange, yrange, **options):
|
|
235
|
+
r"""
|
|
236
|
+
``contour_plot`` takes a function of two variables, `f(x,y)`
|
|
237
|
+
and plots contour lines of the function over the specified
|
|
238
|
+
``xrange`` and ``yrange`` as demonstrated below.
|
|
239
|
+
|
|
240
|
+
``contour_plot(f, (xmin,xmax), (ymin,ymax), ...)``
|
|
241
|
+
|
|
242
|
+
INPUT:
|
|
243
|
+
|
|
244
|
+
- ``f`` -- a function of two variables
|
|
245
|
+
|
|
246
|
+
- ``(xmin, xmax)`` -- 2-tuple, the range of ``x`` values OR 3-tuple
|
|
247
|
+
``(x,xmin,xmax)``
|
|
248
|
+
|
|
249
|
+
- ``(ymin, ymax)`` -- 2-tuple, the range of ``y`` values OR 3-tuple
|
|
250
|
+
``(y,ymin,ymax)``
|
|
251
|
+
|
|
252
|
+
The following inputs must all be passed in as named parameters:
|
|
253
|
+
|
|
254
|
+
- ``plot_points`` -- integer (default: 100); number of points to plot
|
|
255
|
+
in each direction of the grid. For old computers, 25 is fine, but
|
|
256
|
+
should not be used to verify specific intersection points.
|
|
257
|
+
|
|
258
|
+
- ``fill`` -- boolean (default: ``True``); whether to color in the area
|
|
259
|
+
between contour lines
|
|
260
|
+
|
|
261
|
+
- ``cmap`` -- a colormap (default: ``'gray'``), the name of
|
|
262
|
+
a predefined colormap, a list of colors or an instance of a matplotlib
|
|
263
|
+
Colormap. Type: ``import matplotlib.cm; matplotlib.cm.datad.keys()``
|
|
264
|
+
for available colormap names.
|
|
265
|
+
|
|
266
|
+
- ``contours`` -- integer or list of numbers (default: ``None``):
|
|
267
|
+
If a list of numbers is given, then this specifies the contour levels
|
|
268
|
+
to use. If an integer is given, then this many contour lines are
|
|
269
|
+
used, but the exact levels are determined automatically. If ``None``
|
|
270
|
+
is passed (or the option is not given), then the number of contour
|
|
271
|
+
lines is determined automatically, and is usually about 5.
|
|
272
|
+
|
|
273
|
+
- ``linewidths`` -- integer or list of integer (default: ``None``), if
|
|
274
|
+
a single integer all levels will be of the width given,
|
|
275
|
+
otherwise the levels will be plotted with the width in the order
|
|
276
|
+
given. If the list is shorter than the number of contours, then
|
|
277
|
+
the widths will be repeated cyclically.
|
|
278
|
+
|
|
279
|
+
- ``linestyles`` -- string or list of strings (default: ``None``), the
|
|
280
|
+
style of the lines to be plotted, one of: ``'solid'``, ``'dashed'``,
|
|
281
|
+
``'dashdot'``, ``'dotted'``, respectively ``'-'``, ``'--'``,
|
|
282
|
+
``'-.'``, ``':'``. If the list is shorter than the number of
|
|
283
|
+
contours, then the styles will be repeated cyclically.
|
|
284
|
+
|
|
285
|
+
- ``labels`` -- boolean (default: ``False``); show level labels or not
|
|
286
|
+
|
|
287
|
+
The following options are to adjust the style and placement of
|
|
288
|
+
labels, they have no effect if no labels are shown.
|
|
289
|
+
|
|
290
|
+
- ``label_fontsize`` -- integer (default: 9); the font size of
|
|
291
|
+
the labels
|
|
292
|
+
|
|
293
|
+
- ``label_colors`` -- string or sequence of colors (default:
|
|
294
|
+
None) If a string, gives the name of a single color with which
|
|
295
|
+
to draw all labels. If a sequence, gives the colors of the
|
|
296
|
+
labels. A color is a string giving the name of one or a
|
|
297
|
+
3-tuple of floats.
|
|
298
|
+
|
|
299
|
+
- ``label_inline`` -- boolean (default: ``False`` if fill is True,
|
|
300
|
+
otherwise True), controls whether the underlying contour is
|
|
301
|
+
removed or not.
|
|
302
|
+
|
|
303
|
+
- ``label_inline_spacing`` -- integer (default: 3); when inline,
|
|
304
|
+
this is the amount of contour that is removed from each side,
|
|
305
|
+
in pixels.
|
|
306
|
+
|
|
307
|
+
- ``label_fmt`` -- a format string (default: ``"%1.2f"``), this is
|
|
308
|
+
used to get the label text from the level. This can also be a
|
|
309
|
+
dictionary with the contour levels as keys and corresponding
|
|
310
|
+
text string labels as values. It can also be any callable which
|
|
311
|
+
returns a string when called with a numeric contour level.
|
|
312
|
+
|
|
313
|
+
- ``colorbar`` -- boolean (default: ``False``); show a colorbar or not
|
|
314
|
+
|
|
315
|
+
The following options are to adjust the style and placement of
|
|
316
|
+
colorbars. They have no effect if a colorbar is not shown.
|
|
317
|
+
|
|
318
|
+
- ``colorbar_orientation`` -- string (default: ``'vertical'``),
|
|
319
|
+
controls placement of the colorbar, can be either 'vertical'
|
|
320
|
+
or 'horizontal'
|
|
321
|
+
|
|
322
|
+
- ``colorbar_format`` -- a format string, this is used to format
|
|
323
|
+
the colorbar labels
|
|
324
|
+
|
|
325
|
+
- ``colorbar_spacing`` -- string (default: ``'proportional'``); if
|
|
326
|
+
'proportional', make the contour divisions proportional to
|
|
327
|
+
values. If 'uniform', space the colorbar divisions uniformly,
|
|
328
|
+
without regard for numeric values.
|
|
329
|
+
|
|
330
|
+
- ``legend_label`` -- the label for this item in the legend
|
|
331
|
+
|
|
332
|
+
- ``region`` -- (default: ``None``) if region is given, it must be a function
|
|
333
|
+
of two variables. Only segments of the surface where region(x,y)
|
|
334
|
+
returns a number >0 will be included in the plot.
|
|
335
|
+
|
|
336
|
+
.. WARNING::
|
|
337
|
+
|
|
338
|
+
Due to an implementation detail in matplotlib, single-contour
|
|
339
|
+
plots whose data all lie on one side of the sole contour may
|
|
340
|
+
not be plotted correctly. We attempt to detect this situation
|
|
341
|
+
and to produce something better than an empty plot when it
|
|
342
|
+
happens; a ``UserWarning`` is emitted in that case.
|
|
343
|
+
|
|
344
|
+
EXAMPLES:
|
|
345
|
+
|
|
346
|
+
Here we plot a simple function of two variables. Note that
|
|
347
|
+
since the input function is an expression, we need to explicitly
|
|
348
|
+
declare the variables in 3-tuples for the range::
|
|
349
|
+
|
|
350
|
+
sage: x,y = var('x,y')
|
|
351
|
+
sage: contour_plot(cos(x^2 + y^2), (x,-4,4), (y,-4,4))
|
|
352
|
+
Graphics object consisting of 1 graphics primitive
|
|
353
|
+
|
|
354
|
+
.. PLOT::
|
|
355
|
+
|
|
356
|
+
x,y = var('x,y')
|
|
357
|
+
g = contour_plot(cos(x**2 + y**2), (x,-4,4), (y,-4,4))
|
|
358
|
+
sphinx_plot(g)
|
|
359
|
+
|
|
360
|
+
Here we change the ranges and add some options::
|
|
361
|
+
|
|
362
|
+
sage: x,y = var('x,y')
|
|
363
|
+
sage: contour_plot((x^2) * cos(x*y), (x,-10,5), (y,-5,5), fill=False, plot_points=150)
|
|
364
|
+
Graphics object consisting of 1 graphics primitive
|
|
365
|
+
|
|
366
|
+
.. PLOT::
|
|
367
|
+
|
|
368
|
+
x,y = var('x,y')
|
|
369
|
+
g = contour_plot((x**2) * cos(x*y), (x,-10,5), (y,-5,5), fill=False, plot_points=150)
|
|
370
|
+
sphinx_plot(g)
|
|
371
|
+
|
|
372
|
+
An even more complicated plot::
|
|
373
|
+
|
|
374
|
+
sage: x,y = var('x,y')
|
|
375
|
+
sage: contour_plot(sin(x^2+y^2) * cos(x) * sin(y), (x,-4,4), (y,-4,4), plot_points=150)
|
|
376
|
+
Graphics object consisting of 1 graphics primitive
|
|
377
|
+
|
|
378
|
+
.. PLOT::
|
|
379
|
+
|
|
380
|
+
x,y = var('x,y')
|
|
381
|
+
g = contour_plot(sin(x**2+y**2) * cos(x) * sin(y), (x,-4,4), (y,-4,4),plot_points=150)
|
|
382
|
+
sphinx_plot(g)
|
|
383
|
+
|
|
384
|
+
Some elliptic curves, but with symbolic endpoints. In the first
|
|
385
|
+
example, the plot is rotated 90 degrees because we switch the
|
|
386
|
+
variables `x`, `y`::
|
|
387
|
+
|
|
388
|
+
sage: x,y = var('x,y')
|
|
389
|
+
sage: contour_plot(y^2 + 1 - x^3 - x, (y,-pi,pi), (x,-pi,pi))
|
|
390
|
+
Graphics object consisting of 1 graphics primitive
|
|
391
|
+
|
|
392
|
+
.. PLOT::
|
|
393
|
+
|
|
394
|
+
x,y = var('x,y')
|
|
395
|
+
g = contour_plot(y**2 + 1 - x**3 - x, (y,-pi,pi), (x,-pi,pi))
|
|
396
|
+
sphinx_plot(g)
|
|
397
|
+
|
|
398
|
+
::
|
|
399
|
+
|
|
400
|
+
sage: contour_plot(y^2 + 1 - x^3 - x, (x,-pi,pi), (y,-pi,pi))
|
|
401
|
+
Graphics object consisting of 1 graphics primitive
|
|
402
|
+
|
|
403
|
+
.. PLOT::
|
|
404
|
+
|
|
405
|
+
x,y = var('x,y')
|
|
406
|
+
g = contour_plot(y**2 + 1 - x**3 - x, (x,-pi,pi), (y,-pi,pi))
|
|
407
|
+
sphinx_plot(g)
|
|
408
|
+
|
|
409
|
+
We can play with the contour levels::
|
|
410
|
+
|
|
411
|
+
sage: x,y = var('x,y')
|
|
412
|
+
sage: f(x,y) = x^2 + y^2
|
|
413
|
+
sage: contour_plot(f, (-2,2), (-2,2))
|
|
414
|
+
Graphics object consisting of 1 graphics primitive
|
|
415
|
+
|
|
416
|
+
.. PLOT::
|
|
417
|
+
|
|
418
|
+
x,y = var('x,y')
|
|
419
|
+
def f(x, y): return x**2 + y**2
|
|
420
|
+
g = contour_plot(f, (-2,2), (-2,2))
|
|
421
|
+
sphinx_plot(g)
|
|
422
|
+
|
|
423
|
+
::
|
|
424
|
+
|
|
425
|
+
sage: contour_plot(f, (-2,2), (-2,2), contours=2, cmap=[(1,0,0), (0,1,0), (0,0,1)])
|
|
426
|
+
Graphics object consisting of 1 graphics primitive
|
|
427
|
+
|
|
428
|
+
.. PLOT::
|
|
429
|
+
|
|
430
|
+
x,y = var('x,y')
|
|
431
|
+
def f(x, y): return x**2 + y**2
|
|
432
|
+
g = contour_plot(f, (-2, 2), (-2, 2), contours=2, cmap=[(1,0,0), (0,1,0), (0,0,1)])
|
|
433
|
+
sphinx_plot(g)
|
|
434
|
+
|
|
435
|
+
::
|
|
436
|
+
|
|
437
|
+
sage: contour_plot(f, (-2,2), (-2,2),
|
|
438
|
+
....: contours=(0.1,1.0,1.2,1.4), cmap='hsv')
|
|
439
|
+
Graphics object consisting of 1 graphics primitive
|
|
440
|
+
|
|
441
|
+
.. PLOT::
|
|
442
|
+
|
|
443
|
+
x,y = var('x,y')
|
|
444
|
+
def f(x, y): return x**2 + y**2
|
|
445
|
+
g = contour_plot(f, (-2,2), (-2,2), contours=(0.1,1.0,1.2,1.4), cmap='hsv')
|
|
446
|
+
sphinx_plot(g)
|
|
447
|
+
|
|
448
|
+
::
|
|
449
|
+
|
|
450
|
+
sage: contour_plot(f, (-2,2), (-2,2), contours=(1.0,), fill=False)
|
|
451
|
+
Graphics object consisting of 1 graphics primitive
|
|
452
|
+
|
|
453
|
+
.. PLOT::
|
|
454
|
+
|
|
455
|
+
x,y = var('x,y')
|
|
456
|
+
def f(x, y): return x**2 + y**2
|
|
457
|
+
g = contour_plot(f, (-2,2), (-2,2), contours=(1.0,), fill=False)
|
|
458
|
+
sphinx_plot(g)
|
|
459
|
+
|
|
460
|
+
::
|
|
461
|
+
|
|
462
|
+
sage: contour_plot(x - y^2, (x,-5,5), (y,-3,3), contours=[-4,0,1])
|
|
463
|
+
Graphics object consisting of 1 graphics primitive
|
|
464
|
+
|
|
465
|
+
.. PLOT::
|
|
466
|
+
|
|
467
|
+
x,y = var('x,y')
|
|
468
|
+
g = contour_plot(x - y**2, (x,-5,5), (y,-3,3), contours=[-4,0,1])
|
|
469
|
+
sphinx_plot(g)
|
|
470
|
+
|
|
471
|
+
We can change the style of the lines::
|
|
472
|
+
|
|
473
|
+
sage: contour_plot(f, (-2,2), (-2,2), fill=False, linewidths=10)
|
|
474
|
+
Graphics object consisting of 1 graphics primitive
|
|
475
|
+
|
|
476
|
+
.. PLOT::
|
|
477
|
+
|
|
478
|
+
x,y = var('x,y')
|
|
479
|
+
def f(x, y): return x**2 + y**2
|
|
480
|
+
g = contour_plot(f, (-2,2), (-2,2), fill=False, linewidths=10)
|
|
481
|
+
sphinx_plot(g)
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
::
|
|
485
|
+
|
|
486
|
+
sage: contour_plot(f, (-2,2), (-2,2), fill=False, linestyles='dashdot')
|
|
487
|
+
Graphics object consisting of 1 graphics primitive
|
|
488
|
+
|
|
489
|
+
.. PLOT::
|
|
490
|
+
|
|
491
|
+
x,y = var('x,y')
|
|
492
|
+
def f(x, y): return x**2 + y**2
|
|
493
|
+
g = contour_plot(f, (-2,2), (-2,2), fill=False, linestyles='dashdot')
|
|
494
|
+
sphinx_plot(g)
|
|
495
|
+
|
|
496
|
+
::
|
|
497
|
+
|
|
498
|
+
sage: P = contour_plot(x^2 - y^2, (x,-3,3), (y,-3,3),
|
|
499
|
+
....: contours=[0,1,2,3,4], linewidths=[1,5],
|
|
500
|
+
....: linestyles=['solid','dashed'], fill=False)
|
|
501
|
+
sage: P
|
|
502
|
+
Graphics object consisting of 1 graphics primitive
|
|
503
|
+
|
|
504
|
+
.. PLOT::
|
|
505
|
+
|
|
506
|
+
x,y = var('x,y')
|
|
507
|
+
P = contour_plot(x**2 - y**2, (x,-3,3), (y,-3,3),
|
|
508
|
+
contours=[0,1,2,3,4], linewidths=[1,5],
|
|
509
|
+
linestyles=['solid','dashed'], fill=False)
|
|
510
|
+
sphinx_plot(P)
|
|
511
|
+
|
|
512
|
+
::
|
|
513
|
+
|
|
514
|
+
sage: P = contour_plot(x^2 - y^2, (x,-3,3), (y,-3,3),
|
|
515
|
+
....: contours=[0,1,2,3,4], linewidths=[1,5],
|
|
516
|
+
....: linestyles=['solid','dashed'])
|
|
517
|
+
sage: P
|
|
518
|
+
Graphics object consisting of 1 graphics primitive
|
|
519
|
+
|
|
520
|
+
.. PLOT::
|
|
521
|
+
|
|
522
|
+
x,y = var('x,y')
|
|
523
|
+
P = contour_plot(x**2 - y**2, (x,-3,3), (y,-3,3),
|
|
524
|
+
contours=[0,1,2,3,4], linewidths=[1,5],
|
|
525
|
+
linestyles=['solid','dashed'])
|
|
526
|
+
sphinx_plot(P)
|
|
527
|
+
|
|
528
|
+
::
|
|
529
|
+
|
|
530
|
+
sage: P = contour_plot(x^2 - y^2, (x,-3,3), (y,-3,3),
|
|
531
|
+
....: contours=[0,1,2,3,4], linewidths=[1,5],
|
|
532
|
+
....: linestyles=['-',':'])
|
|
533
|
+
sage: P
|
|
534
|
+
Graphics object consisting of 1 graphics primitive
|
|
535
|
+
|
|
536
|
+
.. PLOT::
|
|
537
|
+
|
|
538
|
+
x,y = var('x,y')
|
|
539
|
+
P = contour_plot(x**2 - y**2, (x,-3,3), (y,-3,3),
|
|
540
|
+
contours=[0,1,2,3,4], linewidths=[1,5],
|
|
541
|
+
linestyles=['-',':'])
|
|
542
|
+
sphinx_plot(P)
|
|
543
|
+
|
|
544
|
+
We can add labels and play with them::
|
|
545
|
+
|
|
546
|
+
sage: contour_plot(y^2 + 1 - x^3 - x, (x,-pi,pi), (y,-pi,pi),
|
|
547
|
+
....: fill=False, cmap='hsv', labels=True)
|
|
548
|
+
Graphics object consisting of 1 graphics primitive
|
|
549
|
+
|
|
550
|
+
.. PLOT::
|
|
551
|
+
|
|
552
|
+
x,y = var('x,y')
|
|
553
|
+
P = contour_plot(y**2 + 1 - x**3 - x, (x,-pi,pi), (y,-pi,pi),
|
|
554
|
+
fill=False, cmap='hsv', labels=True)
|
|
555
|
+
sphinx_plot(P)
|
|
556
|
+
|
|
557
|
+
::
|
|
558
|
+
|
|
559
|
+
sage: P=contour_plot(y^2 + 1 - x^3 - x, (x,-pi,pi), (y,-pi,pi),
|
|
560
|
+
....: fill=False, cmap='hsv',
|
|
561
|
+
....: labels=True, label_fmt="%1.0f",
|
|
562
|
+
....: label_colors='black')
|
|
563
|
+
sage: P
|
|
564
|
+
Graphics object consisting of 1 graphics primitive
|
|
565
|
+
|
|
566
|
+
.. PLOT::
|
|
567
|
+
|
|
568
|
+
x,y = var('x,y')
|
|
569
|
+
P=contour_plot(y**2 + 1 - x**3 - x, (x,-pi,pi), (y,-pi,pi),
|
|
570
|
+
fill=False, cmap='hsv',
|
|
571
|
+
labels=True, label_fmt="%1.0f",
|
|
572
|
+
label_colors='black')
|
|
573
|
+
sphinx_plot(P)
|
|
574
|
+
|
|
575
|
+
::
|
|
576
|
+
|
|
577
|
+
sage: P = contour_plot(y^2 + 1 - x^3 - x, (x,-pi,pi), (y,-pi,pi),
|
|
578
|
+
....: fill=False, cmap='hsv', labels=True,
|
|
579
|
+
....: contours=[-4,0,4],
|
|
580
|
+
....: label_fmt={-4:"low", 0:"medium", 4: "hi"},
|
|
581
|
+
....: label_colors='black')
|
|
582
|
+
sage: P
|
|
583
|
+
Graphics object consisting of 1 graphics primitive
|
|
584
|
+
|
|
585
|
+
.. PLOT::
|
|
586
|
+
|
|
587
|
+
x,y = var('x,y')
|
|
588
|
+
P = contour_plot(y**2 + 1 - x**3 - x, (x,-pi,pi), (y,-pi,pi),
|
|
589
|
+
fill=False, cmap='hsv', labels=True,
|
|
590
|
+
contours=[-4,0,4],
|
|
591
|
+
label_fmt={-4:"low", 0:"medium", 4: "hi"},
|
|
592
|
+
label_colors='black')
|
|
593
|
+
sphinx_plot(P)
|
|
594
|
+
|
|
595
|
+
::
|
|
596
|
+
|
|
597
|
+
sage: P = contour_plot(y^2 + 1 - x^3 - x, (x,-pi,pi), (y,-pi,pi),
|
|
598
|
+
....: fill=False, cmap='hsv', labels=True,
|
|
599
|
+
....: contours=[-4,0,4], label_fmt=lambda x: "$z=%s$"%x,
|
|
600
|
+
....: label_colors='black', label_inline=True,
|
|
601
|
+
....: label_fontsize=12)
|
|
602
|
+
sage: P
|
|
603
|
+
Graphics object consisting of 1 graphics primitive
|
|
604
|
+
|
|
605
|
+
.. PLOT::
|
|
606
|
+
|
|
607
|
+
x,y = var('x,y')
|
|
608
|
+
P = contour_plot(y**2 + 1 - x**3 - x, (x,-pi,pi), (y,-pi,pi),
|
|
609
|
+
fill=False, cmap='hsv', labels=True,
|
|
610
|
+
contours=[-4,0,4], label_fmt=lambda x: "$z=%s$"%x,
|
|
611
|
+
label_colors='black', label_inline=True,
|
|
612
|
+
label_fontsize=12)
|
|
613
|
+
sphinx_plot(P)
|
|
614
|
+
|
|
615
|
+
::
|
|
616
|
+
|
|
617
|
+
sage: P = contour_plot(y^2 + 1 - x^3 - x, (x,-pi,pi), (y,-pi,pi),
|
|
618
|
+
....: fill=False, cmap='hsv', labels=True,
|
|
619
|
+
....: label_fontsize=18)
|
|
620
|
+
sage: P
|
|
621
|
+
Graphics object consisting of 1 graphics primitive
|
|
622
|
+
|
|
623
|
+
.. PLOT::
|
|
624
|
+
|
|
625
|
+
x,y = var('x,y')
|
|
626
|
+
P = contour_plot(y**2 + 1 - x**3 - x, (x,-pi,pi), (y,-pi,pi),
|
|
627
|
+
fill=False, cmap='hsv', labels=True,
|
|
628
|
+
label_fontsize=18)
|
|
629
|
+
sphinx_plot(P)
|
|
630
|
+
|
|
631
|
+
::
|
|
632
|
+
|
|
633
|
+
sage: P = contour_plot(y^2 + 1 - x^3 - x, (x,-pi,pi), (y,-pi,pi),
|
|
634
|
+
....: fill=False, cmap='hsv', labels=True,
|
|
635
|
+
....: label_inline_spacing=1)
|
|
636
|
+
sage: P
|
|
637
|
+
Graphics object consisting of 1 graphics primitive
|
|
638
|
+
|
|
639
|
+
.. PLOT::
|
|
640
|
+
|
|
641
|
+
x,y = var('x,y')
|
|
642
|
+
P = contour_plot(y**2 + 1 - x**3 - x, (x,-pi,pi), (y,-pi,pi),
|
|
643
|
+
fill=False, cmap='hsv', labels=True,
|
|
644
|
+
label_inline_spacing=1)
|
|
645
|
+
sphinx_plot(P)
|
|
646
|
+
|
|
647
|
+
::
|
|
648
|
+
|
|
649
|
+
sage: P = contour_plot(y^2 + 1 - x^3 - x, (x,-pi,pi), (y,-pi,pi),
|
|
650
|
+
....: fill=False, cmap='hsv', labels=True,
|
|
651
|
+
....: label_inline=False)
|
|
652
|
+
sage: P
|
|
653
|
+
Graphics object consisting of 1 graphics primitive
|
|
654
|
+
|
|
655
|
+
.. PLOT::
|
|
656
|
+
|
|
657
|
+
x,y = var('x,y')
|
|
658
|
+
P = contour_plot(y**2 + 1 - x**3 - x, (x,-pi,pi), (y,-pi,pi),
|
|
659
|
+
fill=False, cmap='hsv', labels=True,
|
|
660
|
+
label_inline=False)
|
|
661
|
+
sphinx_plot(P)
|
|
662
|
+
|
|
663
|
+
We can change the color of the labels if so desired::
|
|
664
|
+
|
|
665
|
+
sage: contour_plot(f, (-2,2), (-2,2), labels=True, label_colors='red')
|
|
666
|
+
Graphics object consisting of 1 graphics primitive
|
|
667
|
+
|
|
668
|
+
.. PLOT::
|
|
669
|
+
|
|
670
|
+
x,y = var('x,y')
|
|
671
|
+
def f(x, y): return x**2 + y**2
|
|
672
|
+
g = contour_plot(f, (-2,2), (-2,2), labels=True, label_colors='red')
|
|
673
|
+
sphinx_plot(g)
|
|
674
|
+
|
|
675
|
+
We can add a colorbar as well::
|
|
676
|
+
|
|
677
|
+
sage: f(x, y) = x^2 + y^2
|
|
678
|
+
sage: contour_plot(f, (x,-3,3), (y,-3,3), colorbar=True)
|
|
679
|
+
Graphics object consisting of 1 graphics primitive
|
|
680
|
+
|
|
681
|
+
.. PLOT::
|
|
682
|
+
|
|
683
|
+
x,y = var('x,y')
|
|
684
|
+
def f(x, y): return x**2 + y**2
|
|
685
|
+
g = contour_plot(f, (x,-3,3), (y,-3,3), colorbar=True)
|
|
686
|
+
sphinx_plot(g)
|
|
687
|
+
|
|
688
|
+
::
|
|
689
|
+
|
|
690
|
+
sage: contour_plot(f, (x,-3,3), (y,-3,3), colorbar=True, colorbar_orientation='horizontal')
|
|
691
|
+
Graphics object consisting of 1 graphics primitive
|
|
692
|
+
|
|
693
|
+
.. PLOT::
|
|
694
|
+
|
|
695
|
+
x,y = var('x,y')
|
|
696
|
+
def f(x, y): return x**2 + y**2
|
|
697
|
+
g = contour_plot(f, (x,-3,3), (y,-3,3), colorbar=True, colorbar_orientation='horizontal')
|
|
698
|
+
sphinx_plot(g)
|
|
699
|
+
|
|
700
|
+
::
|
|
701
|
+
|
|
702
|
+
sage: contour_plot(f, (x,-3,3), (y,-3,3), contours=[-2,-1,4], colorbar=True)
|
|
703
|
+
Graphics object consisting of 1 graphics primitive
|
|
704
|
+
|
|
705
|
+
.. PLOT::
|
|
706
|
+
|
|
707
|
+
x,y = var('x,y')
|
|
708
|
+
def f(x, y): return x**2 + y**2
|
|
709
|
+
g = contour_plot(f, (x,-3,3), (y,-3,3), contours=[-2,-1,4],
|
|
710
|
+
colorbar=True)
|
|
711
|
+
sphinx_plot(g)
|
|
712
|
+
|
|
713
|
+
::
|
|
714
|
+
|
|
715
|
+
sage: contour_plot(f, (x,-3,3), (y,-3,3), contours=[-2,-1,4],
|
|
716
|
+
....: colorbar=True, colorbar_spacing='uniform')
|
|
717
|
+
Graphics object consisting of 1 graphics primitive
|
|
718
|
+
|
|
719
|
+
.. PLOT::
|
|
720
|
+
|
|
721
|
+
x,y = var('x,y')
|
|
722
|
+
def f(x, y): return x**2 + y**2
|
|
723
|
+
g = contour_plot(f, (x,-3,3), (y,-3,3), contours=[-2,-1,4],
|
|
724
|
+
colorbar=True, colorbar_spacing='uniform')
|
|
725
|
+
sphinx_plot(g)
|
|
726
|
+
|
|
727
|
+
::
|
|
728
|
+
|
|
729
|
+
sage: contour_plot(f, (x,-3,3), (y,-3,3), contours=[0,2,3,6],
|
|
730
|
+
....: colorbar=True, colorbar_format='%.3f')
|
|
731
|
+
Graphics object consisting of 1 graphics primitive
|
|
732
|
+
|
|
733
|
+
.. PLOT::
|
|
734
|
+
|
|
735
|
+
x,y = var('x,y')
|
|
736
|
+
def f(x, y): return x**2 + y**2
|
|
737
|
+
g = contour_plot(f, (x,-3,3), (y,-3,3), contours=[0,2,3,6],
|
|
738
|
+
colorbar=True, colorbar_format='%.3f')
|
|
739
|
+
sphinx_plot(g)
|
|
740
|
+
|
|
741
|
+
::
|
|
742
|
+
|
|
743
|
+
sage: contour_plot(f, (x,-3,3), (y,-3,3), labels=True,
|
|
744
|
+
....: label_colors='red', contours=[0,2,3,6],
|
|
745
|
+
....: colorbar=True)
|
|
746
|
+
Graphics object consisting of 1 graphics primitive
|
|
747
|
+
|
|
748
|
+
.. PLOT::
|
|
749
|
+
|
|
750
|
+
x,y = var('x,y')
|
|
751
|
+
def f(x, y): return x**2 + y**2
|
|
752
|
+
g = contour_plot(f, (x,-3,3), (y,-3,3), labels=True,
|
|
753
|
+
label_colors='red', contours=[0,2,3,6],
|
|
754
|
+
colorbar=True)
|
|
755
|
+
sphinx_plot(g)
|
|
756
|
+
|
|
757
|
+
::
|
|
758
|
+
|
|
759
|
+
sage: contour_plot(f, (x,-3,3), (y,-3,3), cmap='winter',
|
|
760
|
+
....: contours=20, fill=False, colorbar=True)
|
|
761
|
+
Graphics object consisting of 1 graphics primitive
|
|
762
|
+
|
|
763
|
+
.. PLOT::
|
|
764
|
+
|
|
765
|
+
x,y = var('x,y')
|
|
766
|
+
def f(x, y): return x**2 + y**2
|
|
767
|
+
g = contour_plot(f, (x,-3,3), (y,-3,3), cmap='winter',
|
|
768
|
+
contours=20, fill=False, colorbar=True)
|
|
769
|
+
sphinx_plot(g)
|
|
770
|
+
|
|
771
|
+
This should plot concentric circles centered at the origin::
|
|
772
|
+
|
|
773
|
+
sage: x,y = var('x,y')
|
|
774
|
+
sage: contour_plot(x^2 + y^2-2,(x,-1,1), (y,-1,1))
|
|
775
|
+
Graphics object consisting of 1 graphics primitive
|
|
776
|
+
|
|
777
|
+
.. PLOT::
|
|
778
|
+
|
|
779
|
+
x,y = var('x,y')
|
|
780
|
+
g = contour_plot(x**2 + y**2-2,(x,-1,1), (y,-1,1))
|
|
781
|
+
sphinx_plot(g)
|
|
782
|
+
|
|
783
|
+
|
|
784
|
+
Extra options will get passed on to show(), as long as they are valid::
|
|
785
|
+
|
|
786
|
+
sage: f(x,y) = cos(x) + sin(y)
|
|
787
|
+
sage: contour_plot(f, (0,pi), (0,pi), axes=True)
|
|
788
|
+
Graphics object consisting of 1 graphics primitive
|
|
789
|
+
|
|
790
|
+
::
|
|
791
|
+
|
|
792
|
+
sage: contour_plot(f, (0,pi), (0,pi)).show(axes=True) # These are equivalent
|
|
793
|
+
|
|
794
|
+
.. PLOT::
|
|
795
|
+
|
|
796
|
+
x,y = var('x,y')
|
|
797
|
+
def f(x, y): return cos(x) + sin(y)
|
|
798
|
+
g = contour_plot(f, (0,pi), (0,pi), axes=True)
|
|
799
|
+
sphinx_plot(g)
|
|
800
|
+
|
|
801
|
+
One can also plot over a reduced region::
|
|
802
|
+
|
|
803
|
+
sage: contour_plot(x**2 - y**2, (x,-2,2), (y,-2,2), region=x - y, plot_points=300)
|
|
804
|
+
Graphics object consisting of 1 graphics primitive
|
|
805
|
+
|
|
806
|
+
.. PLOT::
|
|
807
|
+
|
|
808
|
+
x,y = var('x,y')
|
|
809
|
+
g = contour_plot(x**2 - y**2, (x,-2,2), (y,-2,2), region=x - y,
|
|
810
|
+
plot_points=300)
|
|
811
|
+
sphinx_plot(g)
|
|
812
|
+
|
|
813
|
+
Note that with ``fill=False`` and grayscale contours, there is the
|
|
814
|
+
possibility of confusion between the contours and the axes, so use
|
|
815
|
+
``fill=False`` together with ``axes=True`` with caution::
|
|
816
|
+
|
|
817
|
+
sage: contour_plot(f, (-pi,pi), (-pi,pi), fill=False, axes=True)
|
|
818
|
+
Graphics object consisting of 1 graphics primitive
|
|
819
|
+
|
|
820
|
+
.. PLOT::
|
|
821
|
+
|
|
822
|
+
x,y = var('x,y')
|
|
823
|
+
def f(x, y): return cos(x) + sin(y)
|
|
824
|
+
g = contour_plot(f, (-pi,pi), (-pi,pi), fill=False, axes=True)
|
|
825
|
+
sphinx_plot(g)
|
|
826
|
+
|
|
827
|
+
If you are plotting a sole contour and if all of your data lie on
|
|
828
|
+
one side of it, then (as part of :issue:`21042`) a heuristic may be
|
|
829
|
+
used to improve the result; in that case, a warning is emitted::
|
|
830
|
+
|
|
831
|
+
sage: contour_plot(lambda x,y: abs(x^2-y^2), (-1,1), (-1,1),
|
|
832
|
+
....: contours=[0], fill=False, cmap=['blue'])
|
|
833
|
+
...
|
|
834
|
+
UserWarning: pathological contour plot of a function whose values
|
|
835
|
+
all lie on one side of the sole contour; we are adding more plot
|
|
836
|
+
points and perturbing your function values.
|
|
837
|
+
Graphics object consisting of 1 graphics primitive
|
|
838
|
+
|
|
839
|
+
.. PLOT::
|
|
840
|
+
|
|
841
|
+
import warnings
|
|
842
|
+
with warnings.catch_warnings():
|
|
843
|
+
warnings.simplefilter("ignore")
|
|
844
|
+
g = contour_plot(lambda x,y: abs(x**2-y**2), (-1,1), (-1,1),
|
|
845
|
+
contours=[0], fill=False, cmap=['blue'])
|
|
846
|
+
sphinx_plot(g)
|
|
847
|
+
|
|
848
|
+
Constant functions (with a single contour) can be plotted as well;
|
|
849
|
+
this was not possible before :issue:`21042`::
|
|
850
|
+
|
|
851
|
+
sage: contour_plot(lambda x,y: 0, (-1,1), (-1,1),
|
|
852
|
+
....: contours=[0], fill=False, cmap=['blue'])
|
|
853
|
+
...Graphics object consisting of 1 graphics primitive
|
|
854
|
+
|
|
855
|
+
.. PLOT::
|
|
856
|
+
|
|
857
|
+
import warnings
|
|
858
|
+
with warnings.catch_warnings():
|
|
859
|
+
warnings.simplefilter("ignore")
|
|
860
|
+
g = contour_plot(lambda x,y: 0, (-1,1), (-1,1),
|
|
861
|
+
contours=[0], fill=False, cmap=['blue'])
|
|
862
|
+
sphinx_plot(g)
|
|
863
|
+
|
|
864
|
+
TESTS:
|
|
865
|
+
|
|
866
|
+
To check that :issue:`5221` is fixed, note that this has three curves, not
|
|
867
|
+
two::
|
|
868
|
+
|
|
869
|
+
sage: x,y = var('x,y')
|
|
870
|
+
sage: contour_plot(x - y^2, (x,-5,5), (y,-3,3),
|
|
871
|
+
....: contours=[-4,-2,0], fill=False)
|
|
872
|
+
Graphics object consisting of 1 graphics primitive
|
|
873
|
+
|
|
874
|
+
Check that :issue:`18074` is fixed::
|
|
875
|
+
|
|
876
|
+
sage: contour_plot(0, (0,1), (0,1))
|
|
877
|
+
...Graphics object consisting of 1 graphics primitive
|
|
878
|
+
|
|
879
|
+
Domain points in :issue:`11648` with complex output are now skipped::
|
|
880
|
+
|
|
881
|
+
sage: x,y = SR.var('x,y', domain='real')
|
|
882
|
+
sage: contour_plot(log(x) + log(y), (-1, 5), (-1, 5))
|
|
883
|
+
Graphics object consisting of 1 graphics primitive
|
|
884
|
+
"""
|
|
885
|
+
from sage.plot.all import Graphics
|
|
886
|
+
from sage.plot.misc import setup_for_eval_on_grid
|
|
887
|
+
|
|
888
|
+
region = options.pop('region')
|
|
889
|
+
ev = [f] if region is None else [f, region]
|
|
890
|
+
|
|
891
|
+
F, ranges = setup_for_eval_on_grid(ev, [xrange, yrange],
|
|
892
|
+
options['plot_points'])
|
|
893
|
+
h = F[0]
|
|
894
|
+
xrange, yrange = (r[:2] for r in ranges)
|
|
895
|
+
|
|
896
|
+
xy_data_array = [[h(x, y) for x in xsrange(*ranges[0],
|
|
897
|
+
include_endpoint=True)]
|
|
898
|
+
for y in xsrange(*ranges[1], include_endpoint=True)]
|
|
899
|
+
|
|
900
|
+
g = Graphics()
|
|
901
|
+
|
|
902
|
+
# Reset aspect_ratio to 'automatic' in case scale is 'semilog[xy]'.
|
|
903
|
+
# Otherwise matplotlib complains.
|
|
904
|
+
scale = options.get('scale', None)
|
|
905
|
+
if isinstance(scale, (list, tuple)):
|
|
906
|
+
scale = scale[0]
|
|
907
|
+
if scale in ('semilogy', 'semilogx'):
|
|
908
|
+
options['aspect_ratio'] = 'automatic'
|
|
909
|
+
|
|
910
|
+
g._set_extra_kwds(Graphics._extract_kwds_for_show(options,
|
|
911
|
+
ignore=['xmin', 'xmax']))
|
|
912
|
+
|
|
913
|
+
# Was a single contour level explicitly given? If "contours" is
|
|
914
|
+
# the integer 1, then there will be a single level, but we can't
|
|
915
|
+
# know what it is because it's determined within matplotlib's
|
|
916
|
+
# "contour" or "contourf" function. So we punt in that case. If
|
|
917
|
+
# there's a single contour and fill=True, we fall through to let
|
|
918
|
+
# matplotlib complain that "Filled contours require at least 2
|
|
919
|
+
# levels."
|
|
920
|
+
if (isinstance(options["contours"], (list, tuple))
|
|
921
|
+
and len(options["contours"]) == 1
|
|
922
|
+
and options.get("fill") is False):
|
|
923
|
+
# When there's only one level (say, zero), matplotlib doesn't
|
|
924
|
+
# handle it well. If all of the data lie on one side of that
|
|
925
|
+
# level -- for example, if f(x,y) >= 0 for all x,y -- then it
|
|
926
|
+
# will fail to plot the points where f(x,y) == 0. This is
|
|
927
|
+
# especially catastrophic for implicit_plot(), which tries to
|
|
928
|
+
# do just that. Here we handle that special case: if there's
|
|
929
|
+
# only one level, and if all of the data lie on one side of
|
|
930
|
+
# it, we perturb the data a bit so that they don't. The resulting
|
|
931
|
+
# plots don't look great, but they're not empty, which is an
|
|
932
|
+
# improvement.
|
|
933
|
+
import numpy as np
|
|
934
|
+
dx = ranges[0][2]
|
|
935
|
+
dy = ranges[1][2]
|
|
936
|
+
z0 = options["contours"][0]
|
|
937
|
+
|
|
938
|
+
# This works OK for the examples in the doctests, but basing
|
|
939
|
+
# it off the plot scale rather than how fast the function
|
|
940
|
+
# changes can never be truly satisfactory.
|
|
941
|
+
tol = max(dx, dy) / 4.0
|
|
942
|
+
xy_data_array = np.ma.asarray(xy_data_array, dtype=float)
|
|
943
|
+
|
|
944
|
+
# Special case for constant functions. This is needed because
|
|
945
|
+
# otherwise the forthcoming perturbation trick will take values
|
|
946
|
+
# like 0,0,0... and perturb them to -tol, -tol, -tol... which
|
|
947
|
+
# doesn't work for the same reason 0,0,0... doesn't work.
|
|
948
|
+
if np.all(np.abs(xy_data_array - z0) <= tol):
|
|
949
|
+
# Up to our tolerance, this is the const_z0 function.
|
|
950
|
+
# ...make it actually the const_z0 function.
|
|
951
|
+
xy_data_array.fill(z0)
|
|
952
|
+
|
|
953
|
+
# We're going to set fill=True in a moment, so we need to
|
|
954
|
+
# prepend an entry to the cmap so that the user's original
|
|
955
|
+
# cmap winds up in the right place.
|
|
956
|
+
if "cmap" in options:
|
|
957
|
+
if isinstance(options["cmap"], (list, tuple)):
|
|
958
|
+
oldcmap = options["cmap"][0]
|
|
959
|
+
else:
|
|
960
|
+
oldcmap = options["cmap"]
|
|
961
|
+
else:
|
|
962
|
+
# The docs promise this as the default.
|
|
963
|
+
oldcmap = "gray"
|
|
964
|
+
|
|
965
|
+
# Trick matplotlib into plotting all of the points (minus
|
|
966
|
+
# those masked) by using a single, filled contour that
|
|
967
|
+
# covers the entire plotting surface.
|
|
968
|
+
options["cmap"] = ["white", oldcmap]
|
|
969
|
+
options["contours"] = (z0 - 1, z0)
|
|
970
|
+
options["fill"] = True
|
|
971
|
+
else:
|
|
972
|
+
# The "c" constant is set to plus/minus one to handle both
|
|
973
|
+
# of the "all values greater than z0" and "all values less
|
|
974
|
+
# than z0" cases at once.
|
|
975
|
+
c = 1
|
|
976
|
+
if np.all(xy_data_array <= z0):
|
|
977
|
+
xy_data_array *= -1
|
|
978
|
+
c = -1
|
|
979
|
+
# Now we check if (a) all of the data lie on one side of
|
|
980
|
+
# z0, and (b) if perturbing the data will actually help by
|
|
981
|
+
# moving anything across z0.
|
|
982
|
+
if (np.all(xy_data_array >= z0) and
|
|
983
|
+
np.any(xy_data_array - z0 < tol)):
|
|
984
|
+
|
|
985
|
+
from warnings import warn
|
|
986
|
+
warn("pathological contour plot of a function whose "
|
|
987
|
+
"values all lie on one side of the sole contour; "
|
|
988
|
+
"we are adding more plot points and perturbing "
|
|
989
|
+
"your function values.")
|
|
990
|
+
|
|
991
|
+
# The choice of "4" here is not based on much of anything.
|
|
992
|
+
# It works well enough for the examples in the doctests.
|
|
993
|
+
if not isinstance(options["plot_points"], (list, tuple)):
|
|
994
|
+
options["plot_points"] = (options["plot_points"],
|
|
995
|
+
options["plot_points"])
|
|
996
|
+
options["plot_points"] = (options["plot_points"][0] * 4,
|
|
997
|
+
options["plot_points"][1] * 4)
|
|
998
|
+
|
|
999
|
+
# Re-plot with more points...
|
|
1000
|
+
F, ranges = setup_for_eval_on_grid(ev, [xrange, yrange],
|
|
1001
|
+
options['plot_points'])
|
|
1002
|
+
h = F[0]
|
|
1003
|
+
xrange, yrange = (r[:2] for r in ranges)
|
|
1004
|
+
|
|
1005
|
+
# ...and a function whose values are shifted towards
|
|
1006
|
+
# z0 by "tol".
|
|
1007
|
+
xy_data_array = [[h(x, y) - c * tol
|
|
1008
|
+
for x in xsrange(*ranges[0],
|
|
1009
|
+
include_endpoint=True)]
|
|
1010
|
+
for y in xsrange(*ranges[1],
|
|
1011
|
+
include_endpoint=True)]
|
|
1012
|
+
|
|
1013
|
+
if region is not None:
|
|
1014
|
+
import numpy
|
|
1015
|
+
|
|
1016
|
+
xy_data_array = numpy.ma.asarray(xy_data_array, dtype=float)
|
|
1017
|
+
|
|
1018
|
+
m = F[1]
|
|
1019
|
+
|
|
1020
|
+
mask = numpy.asarray([[m(x, y) <= 0
|
|
1021
|
+
for x in xsrange(*ranges[0],
|
|
1022
|
+
include_endpoint=True)]
|
|
1023
|
+
for y in xsrange(*ranges[1],
|
|
1024
|
+
include_endpoint=True)],
|
|
1025
|
+
dtype=bool)
|
|
1026
|
+
|
|
1027
|
+
xy_data_array[mask] = numpy.ma.masked
|
|
1028
|
+
|
|
1029
|
+
g.add_primitive(ContourPlot(xy_data_array, xrange, yrange, options))
|
|
1030
|
+
|
|
1031
|
+
return g
|
|
1032
|
+
|
|
1033
|
+
|
|
1034
|
+
@options(plot_points=150, contours=(0,), fill=False, cmap=["blue"])
|
|
1035
|
+
def implicit_plot(f, xrange, yrange, **options):
|
|
1036
|
+
r"""
|
|
1037
|
+
``implicit_plot`` takes a function of two variables, `f(x, y)`
|
|
1038
|
+
and plots the curve `f(x,y) = 0` over the specified
|
|
1039
|
+
``xrange`` and ``yrange`` as demonstrated below.
|
|
1040
|
+
|
|
1041
|
+
``implicit_plot(f, (xmin,xmax), (ymin,ymax), ...)``
|
|
1042
|
+
|
|
1043
|
+
``implicit_plot(f, (x,xmin,xmax), (y,ymin,ymax), ...)``
|
|
1044
|
+
|
|
1045
|
+
INPUT:
|
|
1046
|
+
|
|
1047
|
+
- ``f`` -- a function of two variables or equation in two variables
|
|
1048
|
+
|
|
1049
|
+
- ``(xmin, xmax)`` -- 2-tuple, the range of ``x``
|
|
1050
|
+
values or ``(x,xmin,xmax)``
|
|
1051
|
+
|
|
1052
|
+
- ``(ymin, ymax)`` -- 2-tuple, the range of ``y``
|
|
1053
|
+
values or ``(y,ymin,ymax)``
|
|
1054
|
+
|
|
1055
|
+
The following inputs must all be passed in as named parameters:
|
|
1056
|
+
|
|
1057
|
+
- ``plot_points`` -- integer (default: 150); number of points to plot
|
|
1058
|
+
in each direction of the grid
|
|
1059
|
+
|
|
1060
|
+
- ``fill`` -- boolean (default: ``False``); if ``True``, fill the region
|
|
1061
|
+
`f(x, y) < 0`
|
|
1062
|
+
|
|
1063
|
+
- ``fillcolor`` -- string (default: ``'blue'``); the color of the region
|
|
1064
|
+
where `f(x,y) < 0` if ``fill = True``. Colors are defined in
|
|
1065
|
+
:mod:`sage.plot.colors`; try ``colors?`` to see them all.
|
|
1066
|
+
|
|
1067
|
+
- ``linewidth`` -- integer (default: ``None``); if a single integer all levels
|
|
1068
|
+
will be of the width given, otherwise the levels will be plotted with the
|
|
1069
|
+
widths in the order given.
|
|
1070
|
+
|
|
1071
|
+
- ``linestyle`` -- string (default: ``None``); the style of the line to be
|
|
1072
|
+
plotted, one of: ``'solid'``, ``'dashed'``, ``'dashdot'`` or
|
|
1073
|
+
``'dotted'``, respectively ``'-'``, ``'--'``, ``'-.'``, or ``':'``.
|
|
1074
|
+
|
|
1075
|
+
- ``color`` -- string (default: ``'blue'``); the color of the plot. Colors
|
|
1076
|
+
are defined in :mod:`sage.plot.colors`; try ``colors?`` to see them all.
|
|
1077
|
+
If ``fill = True``, then this sets only the color of the border of the
|
|
1078
|
+
plot. See ``fillcolor`` for setting the color of the fill region.
|
|
1079
|
+
|
|
1080
|
+
- ``legend_label`` -- the label for this item in the legend
|
|
1081
|
+
|
|
1082
|
+
- ``base`` -- (default: 10) the base of the logarithm if
|
|
1083
|
+
a logarithmic scale is set. This must be greater than 1. The base
|
|
1084
|
+
can be also given as a list or tuple ``(basex, basey)``.
|
|
1085
|
+
``basex`` sets the base of the logarithm along the horizontal
|
|
1086
|
+
axis and ``basey`` sets the base along the vertical axis.
|
|
1087
|
+
|
|
1088
|
+
- ``scale`` -- (default: ``'linear'``) string. The scale of the axes.
|
|
1089
|
+
Possible values are ``'linear'``, ``'loglog'``, ``'semilogx'``,
|
|
1090
|
+
``'semilogy'``.
|
|
1091
|
+
|
|
1092
|
+
The scale can be also be given as single argument that is a list
|
|
1093
|
+
or tuple ``(scale, base)`` or ``(scale, basex, basey)``.
|
|
1094
|
+
|
|
1095
|
+
The ``'loglog'`` scale sets both the horizontal and vertical axes to
|
|
1096
|
+
logarithmic scale. The ``'semilogx'`` scale sets the horizontal axis
|
|
1097
|
+
to logarithmic scale. The ``'semilogy'`` scale sets the vertical axis
|
|
1098
|
+
to logarithmic scale. The ``'linear'`` scale is the default value
|
|
1099
|
+
when :class:`~sage.plot.graphics.Graphics` is initialized.
|
|
1100
|
+
|
|
1101
|
+
.. WARNING::
|
|
1102
|
+
|
|
1103
|
+
Due to an implementation detail in matplotlib, implicit plots
|
|
1104
|
+
whose data are all nonpositive or nonnegative may not be
|
|
1105
|
+
plotted correctly. We attempt to detect this situation and to
|
|
1106
|
+
produce something better than an empty plot when it happens; a
|
|
1107
|
+
``UserWarning`` is emitted in that case.
|
|
1108
|
+
|
|
1109
|
+
EXAMPLES:
|
|
1110
|
+
|
|
1111
|
+
A simple circle with a radius of 2. Note that
|
|
1112
|
+
since the input function is an expression, we need to explicitly
|
|
1113
|
+
declare the variables in 3-tuples for the range::
|
|
1114
|
+
|
|
1115
|
+
sage: var("x y")
|
|
1116
|
+
(x, y)
|
|
1117
|
+
sage: implicit_plot(x^2 + y^2 - 2, (x,-3,3), (y,-3,3))
|
|
1118
|
+
Graphics object consisting of 1 graphics primitive
|
|
1119
|
+
|
|
1120
|
+
.. PLOT::
|
|
1121
|
+
|
|
1122
|
+
x, y =var("x y")
|
|
1123
|
+
g = implicit_plot(x**2 + y**2 - 2, (x,-3,3), (y,-3,3))
|
|
1124
|
+
sphinx_plot(g)
|
|
1125
|
+
|
|
1126
|
+
We can do the same thing, but using a callable function so we do not
|
|
1127
|
+
need to explicitly define the variables in the ranges. We also fill
|
|
1128
|
+
the inside::
|
|
1129
|
+
|
|
1130
|
+
sage: f(x,y) = x^2 + y^2 - 2
|
|
1131
|
+
sage: implicit_plot(f, (-3,3), (-3,3), fill=True, plot_points=500) # long time
|
|
1132
|
+
Graphics object consisting of 2 graphics primitives
|
|
1133
|
+
|
|
1134
|
+
.. PLOT::
|
|
1135
|
+
|
|
1136
|
+
def f(x, y): return x**2 + y**2 - 2
|
|
1137
|
+
g = implicit_plot(f, (-3,3), (-3,3), fill=True, plot_points=500)
|
|
1138
|
+
sphinx_plot(g)
|
|
1139
|
+
|
|
1140
|
+
The same circle but with a different line width::
|
|
1141
|
+
|
|
1142
|
+
sage: implicit_plot(f, (-3,3), (-3,3), linewidth=6)
|
|
1143
|
+
Graphics object consisting of 1 graphics primitive
|
|
1144
|
+
|
|
1145
|
+
.. PLOT::
|
|
1146
|
+
|
|
1147
|
+
def f(x, y): return x**2 + y**2 - 2
|
|
1148
|
+
g = implicit_plot(f, (-3,3), (-3,3), linewidth=6)
|
|
1149
|
+
sphinx_plot(g)
|
|
1150
|
+
|
|
1151
|
+
Again the same circle but this time with a dashdot border::
|
|
1152
|
+
|
|
1153
|
+
sage: implicit_plot(f, (-3,3), (-3,3), linestyle='dashdot')
|
|
1154
|
+
Graphics object consisting of 1 graphics primitive
|
|
1155
|
+
|
|
1156
|
+
.. PLOT::
|
|
1157
|
+
|
|
1158
|
+
x, y =var("x y")
|
|
1159
|
+
def f(x, y): return x**2 + y**2 - 2
|
|
1160
|
+
g = implicit_plot(f, (-3,3), (-3,3), linestyle='dashdot')
|
|
1161
|
+
sphinx_plot(g)
|
|
1162
|
+
|
|
1163
|
+
The same circle with different line and fill colors::
|
|
1164
|
+
|
|
1165
|
+
sage: implicit_plot(f, (-3,3), (-3,3), color='red', # long time
|
|
1166
|
+
....: fill=True, fillcolor='green',
|
|
1167
|
+
....: plot_points=500)
|
|
1168
|
+
Graphics object consisting of 2 graphics primitives
|
|
1169
|
+
|
|
1170
|
+
.. PLOT::
|
|
1171
|
+
|
|
1172
|
+
def f(x, y): return x**2 + y**2 - 2
|
|
1173
|
+
g = implicit_plot(f, (-3,3), (-3,3), color='red', fill=True, fillcolor='green',
|
|
1174
|
+
plot_points=500)
|
|
1175
|
+
sphinx_plot(g)
|
|
1176
|
+
|
|
1177
|
+
You can also plot an equation::
|
|
1178
|
+
|
|
1179
|
+
sage: var("x y")
|
|
1180
|
+
(x, y)
|
|
1181
|
+
sage: implicit_plot(x^2 + y^2 == 2, (x,-3,3), (y,-3,3))
|
|
1182
|
+
Graphics object consisting of 1 graphics primitive
|
|
1183
|
+
|
|
1184
|
+
.. PLOT::
|
|
1185
|
+
|
|
1186
|
+
x, y =var("x y")
|
|
1187
|
+
g = implicit_plot(x**2 + y**2 == 2, (x,-3,3), (y,-3,3))
|
|
1188
|
+
sphinx_plot(g)
|
|
1189
|
+
|
|
1190
|
+
You can even change the color of the plot::
|
|
1191
|
+
|
|
1192
|
+
sage: implicit_plot(x^2 + y^2 == 2, (x,-3,3), (y,-3,3), color='red')
|
|
1193
|
+
Graphics object consisting of 1 graphics primitive
|
|
1194
|
+
|
|
1195
|
+
.. PLOT::
|
|
1196
|
+
|
|
1197
|
+
x, y =var("x y")
|
|
1198
|
+
g = implicit_plot(x**2 + y**2 == 2, (x,-3,3), (y,-3,3), color='red')
|
|
1199
|
+
sphinx_plot(g)
|
|
1200
|
+
|
|
1201
|
+
The color of the fill region can be changed::
|
|
1202
|
+
|
|
1203
|
+
sage: implicit_plot(x**2 + y**2 == 2, (x,-3,3), (y,-3,3), fill=True, fillcolor='red')
|
|
1204
|
+
Graphics object consisting of 2 graphics primitives
|
|
1205
|
+
|
|
1206
|
+
.. PLOT::
|
|
1207
|
+
|
|
1208
|
+
x, y =var("x y")
|
|
1209
|
+
g = implicit_plot(x**2 + y**2 == 2, (x,-3,3), (y,-3,3), fill=True, fillcolor='red')
|
|
1210
|
+
sphinx_plot(g)
|
|
1211
|
+
|
|
1212
|
+
Here is a beautiful (and long) example which also tests that all
|
|
1213
|
+
colors work with this::
|
|
1214
|
+
|
|
1215
|
+
sage: G = Graphics()
|
|
1216
|
+
sage: counter = 0
|
|
1217
|
+
sage: for col in colors.keys(): # long time
|
|
1218
|
+
....: G += implicit_plot(x^2 + y^2 == 1 + counter*.1, (x,-4,4),(y,-4,4), color=col)
|
|
1219
|
+
....: counter += 1
|
|
1220
|
+
sage: G # long time
|
|
1221
|
+
Graphics object consisting of 148 graphics primitives
|
|
1222
|
+
|
|
1223
|
+
.. PLOT::
|
|
1224
|
+
|
|
1225
|
+
x, y = var("x y")
|
|
1226
|
+
G = Graphics()
|
|
1227
|
+
counter = 0
|
|
1228
|
+
for col in colors.keys():
|
|
1229
|
+
G += implicit_plot(x**2 + y**2 == 1 + counter*.1, (x,-4,4), (y,-4,4), color=col)
|
|
1230
|
+
counter += 1
|
|
1231
|
+
sphinx_plot(G)
|
|
1232
|
+
|
|
1233
|
+
We can define a level-`n` approximation of the boundary of the
|
|
1234
|
+
Mandelbrot set::
|
|
1235
|
+
|
|
1236
|
+
sage: def mandel(n):
|
|
1237
|
+
....: c = polygen(CDF, 'c')
|
|
1238
|
+
....: z = 0
|
|
1239
|
+
....: for i in range(n):
|
|
1240
|
+
....: z = z*z + c
|
|
1241
|
+
....: def f(x, y):
|
|
1242
|
+
....: val = z(CDF(x, y))
|
|
1243
|
+
....: return val.norm() - 4
|
|
1244
|
+
....: return f
|
|
1245
|
+
|
|
1246
|
+
The first-level approximation is just a circle::
|
|
1247
|
+
|
|
1248
|
+
sage: implicit_plot(mandel(1), (-3,3), (-3,3))
|
|
1249
|
+
Graphics object consisting of 1 graphics primitive
|
|
1250
|
+
|
|
1251
|
+
.. PLOT::
|
|
1252
|
+
|
|
1253
|
+
def mandel(n):
|
|
1254
|
+
c = polygen(CDF, 'c')
|
|
1255
|
+
z = 0
|
|
1256
|
+
for i in range(n):
|
|
1257
|
+
z = z*z + c
|
|
1258
|
+
def f(x, y):
|
|
1259
|
+
val = z(CDF(x, y))
|
|
1260
|
+
return val.norm() - 4
|
|
1261
|
+
return f
|
|
1262
|
+
g = implicit_plot(mandel(1), (-3,3), (-3,3))
|
|
1263
|
+
sphinx_plot(g)
|
|
1264
|
+
|
|
1265
|
+
A third-level approximation starts to get interesting::
|
|
1266
|
+
|
|
1267
|
+
sage: implicit_plot(mandel(3), (-2,1), (-1.5,1.5))
|
|
1268
|
+
Graphics object consisting of 1 graphics primitive
|
|
1269
|
+
|
|
1270
|
+
.. PLOT::
|
|
1271
|
+
|
|
1272
|
+
def mandel(n):
|
|
1273
|
+
c = polygen(CDF, 'c')
|
|
1274
|
+
z = 0
|
|
1275
|
+
for i in range(n):
|
|
1276
|
+
z = z*z + c
|
|
1277
|
+
def f(x, y):
|
|
1278
|
+
val = z(CDF(x, y))
|
|
1279
|
+
return val.norm() - 4
|
|
1280
|
+
return f
|
|
1281
|
+
g = implicit_plot(mandel(3), (-2,1), (-1.5,1.5))
|
|
1282
|
+
sphinx_plot(g)
|
|
1283
|
+
|
|
1284
|
+
The seventh-level approximation is a degree 64 polynomial, and
|
|
1285
|
+
``implicit_plot`` does a pretty good job on this part of the curve.
|
|
1286
|
+
(``plot_points=200`` looks even better, but it takes over a second.)
|
|
1287
|
+
|
|
1288
|
+
::
|
|
1289
|
+
|
|
1290
|
+
sage: implicit_plot(mandel(7), (-0.3, 0.05), (-1.15, -0.9), plot_points=50)
|
|
1291
|
+
Graphics object consisting of 1 graphics primitive
|
|
1292
|
+
|
|
1293
|
+
.. PLOT::
|
|
1294
|
+
|
|
1295
|
+
def mandel(n):
|
|
1296
|
+
c = polygen(CDF, 'c')
|
|
1297
|
+
z = 0
|
|
1298
|
+
for i in range(n):
|
|
1299
|
+
z = z*z + c
|
|
1300
|
+
def f(x, y):
|
|
1301
|
+
val = z(CDF(x, y))
|
|
1302
|
+
return val.norm() - 4
|
|
1303
|
+
return f
|
|
1304
|
+
g = implicit_plot(mandel(7), (-0.3,0.05), (-1.15,-0.9),
|
|
1305
|
+
plot_points=50)
|
|
1306
|
+
sphinx_plot(g)
|
|
1307
|
+
|
|
1308
|
+
When making a filled implicit plot using a python function rather than a
|
|
1309
|
+
symbolic expression the user should increase the number of plot points to
|
|
1310
|
+
avoid artifacts::
|
|
1311
|
+
|
|
1312
|
+
sage: implicit_plot(lambda x, y: x^2 + y^2 - 2, (x,-3,3), # long time
|
|
1313
|
+
....: (y,-3,3), fill=True, plot_points=500)
|
|
1314
|
+
Graphics object consisting of 2 graphics primitives
|
|
1315
|
+
|
|
1316
|
+
.. PLOT::
|
|
1317
|
+
|
|
1318
|
+
x, y = var("x y")
|
|
1319
|
+
g = implicit_plot(lambda x, y: x**2 + y**2 - 2, (x,-3,3), (y,-3,3),
|
|
1320
|
+
fill=True, plot_points=500)
|
|
1321
|
+
sphinx_plot(g)
|
|
1322
|
+
|
|
1323
|
+
An example of an implicit plot on 'loglog' scale::
|
|
1324
|
+
|
|
1325
|
+
sage: implicit_plot(x^2 + y^2 == 200, (x,1,200), (y,1,200), scale='loglog')
|
|
1326
|
+
Graphics object consisting of 1 graphics primitive
|
|
1327
|
+
|
|
1328
|
+
.. PLOT::
|
|
1329
|
+
|
|
1330
|
+
x, y = var("x y")
|
|
1331
|
+
g = implicit_plot(x**2 + y**2 == 200, (x,1,200), (y,1,200), scale='loglog')
|
|
1332
|
+
sphinx_plot(g)
|
|
1333
|
+
|
|
1334
|
+
TESTS::
|
|
1335
|
+
|
|
1336
|
+
sage: f(x,y) = x^2 + y^2 - 2
|
|
1337
|
+
sage: implicit_plot(f, (-3,3), (-3,3), fill=5)
|
|
1338
|
+
Traceback (most recent call last):
|
|
1339
|
+
...
|
|
1340
|
+
ValueError: fill=5 is not supported
|
|
1341
|
+
|
|
1342
|
+
To check that :issue:`9654` is fixed::
|
|
1343
|
+
|
|
1344
|
+
sage: f(x,y) = x^2 + y^2 - 2
|
|
1345
|
+
sage: implicit_plot(f, (-3,3), (-3,3), rgbcolor=(1,0,0))
|
|
1346
|
+
Graphics object consisting of 1 graphics primitive
|
|
1347
|
+
sage: implicit_plot(f, (-3,3), (-3,3), color='green')
|
|
1348
|
+
Graphics object consisting of 1 graphics primitive
|
|
1349
|
+
sage: implicit_plot(f, (-3,3), (-3,3), rgbcolor=(1,0,0), color='green')
|
|
1350
|
+
Traceback (most recent call last):
|
|
1351
|
+
...
|
|
1352
|
+
ValueError: only one of color or rgbcolor should be specified
|
|
1353
|
+
"""
|
|
1354
|
+
from sage.structure.element import Expression
|
|
1355
|
+
if isinstance(f, Expression) and f.is_relational():
|
|
1356
|
+
if f.operator() != operator.eq:
|
|
1357
|
+
raise ValueError("input to implicit plot must be function "
|
|
1358
|
+
"or equation")
|
|
1359
|
+
f = f.lhs() - f.rhs()
|
|
1360
|
+
linewidths = options.pop('linewidth', None)
|
|
1361
|
+
linestyles = options.pop('linestyle', None)
|
|
1362
|
+
|
|
1363
|
+
if 'color' in options and 'rgbcolor' in options:
|
|
1364
|
+
raise ValueError('only one of color or rgbcolor should be specified')
|
|
1365
|
+
|
|
1366
|
+
if 'color' in options:
|
|
1367
|
+
options['cmap'] = [options.pop('color', None)]
|
|
1368
|
+
elif 'rgbcolor' in options:
|
|
1369
|
+
options['cmap'] = [rgbcolor(options.pop('rgbcolor', None))]
|
|
1370
|
+
|
|
1371
|
+
if options['fill'] is True:
|
|
1372
|
+
options.pop('fill')
|
|
1373
|
+
options.pop('contours', None)
|
|
1374
|
+
incol = options.pop('fillcolor', 'blue')
|
|
1375
|
+
bordercol = options.pop('cmap', [None])[0]
|
|
1376
|
+
from sage.structure.element import Expression
|
|
1377
|
+
if not isinstance(f, Expression):
|
|
1378
|
+
return region_plot(lambda x, y: f(x, y) < 0, xrange, yrange,
|
|
1379
|
+
borderwidth=linewidths, borderstyle=linestyles,
|
|
1380
|
+
incol=incol, bordercol=bordercol,
|
|
1381
|
+
**options)
|
|
1382
|
+
return region_plot(f < 0, xrange, yrange, borderwidth=linewidths,
|
|
1383
|
+
borderstyle=linestyles,
|
|
1384
|
+
incol=incol, bordercol=bordercol,
|
|
1385
|
+
**options)
|
|
1386
|
+
elif options['fill'] is False:
|
|
1387
|
+
options.pop('fillcolor', None)
|
|
1388
|
+
return contour_plot(f, xrange, yrange, linewidths=linewidths,
|
|
1389
|
+
linestyles=linestyles, **options)
|
|
1390
|
+
else:
|
|
1391
|
+
raise ValueError("fill=%s is not supported" % options['fill'])
|
|
1392
|
+
|
|
1393
|
+
|
|
1394
|
+
@options(plot_points=100, incol='blue', outcol=None, bordercol=None,
|
|
1395
|
+
borderstyle=None, borderwidth=None, frame=False, axes=True,
|
|
1396
|
+
legend_label=None, aspect_ratio=1, alpha=1)
|
|
1397
|
+
def region_plot(f, xrange, yrange, **options):
|
|
1398
|
+
r"""
|
|
1399
|
+
``region_plot`` takes a boolean function of two variables, `f(x, y)`
|
|
1400
|
+
and plots the region where f is ``True`` over the specified
|
|
1401
|
+
``xrange`` and ``yrange`` as demonstrated below.
|
|
1402
|
+
|
|
1403
|
+
``region_plot(f, (xmin,xmax), (ymin,ymax), ...)``
|
|
1404
|
+
|
|
1405
|
+
INPUT:
|
|
1406
|
+
|
|
1407
|
+
- ``f`` -- boolean function or a list of boolean functions of
|
|
1408
|
+
two variables
|
|
1409
|
+
|
|
1410
|
+
- ``(xmin, xmax)`` -- 2-tuple, the range of ``x`` values OR 3-tuple
|
|
1411
|
+
``(x,xmin,xmax)``
|
|
1412
|
+
|
|
1413
|
+
- ``(ymin, ymax)`` -- 2-tuple, the range of ``y`` values OR 3-tuple
|
|
1414
|
+
``(y,ymin,ymax)``
|
|
1415
|
+
|
|
1416
|
+
- ``plot_points`` -- integer (default: 100); number of points to plot
|
|
1417
|
+
in each direction of the grid
|
|
1418
|
+
|
|
1419
|
+
- ``incol`` -- a color (default: ``'blue'``), the color inside the region
|
|
1420
|
+
|
|
1421
|
+
- ``outcol`` -- a color (default: ``None``), the color of the outside
|
|
1422
|
+
of the region
|
|
1423
|
+
|
|
1424
|
+
If any of these options are specified, the border will be shown as
|
|
1425
|
+
indicated, otherwise it is only implicit (with color ``incol``) as the
|
|
1426
|
+
border of the inside of the region.
|
|
1427
|
+
|
|
1428
|
+
- ``bordercol`` -- a color (default: ``None``), the color of the border
|
|
1429
|
+
(``'black'`` if ``borderwidth`` or ``borderstyle`` is specified but
|
|
1430
|
+
not ``bordercol``)
|
|
1431
|
+
|
|
1432
|
+
- ``borderstyle`` -- string (default: ``'solid'``); one of ``'solid'``,
|
|
1433
|
+
``'dashed'``, ``'dotted'``, ``'dashdot'``, respectively ``'-'``,
|
|
1434
|
+
``'--'``, ``':'``, ``'-.'``
|
|
1435
|
+
|
|
1436
|
+
- ``borderwidth`` -- integer (default: ``None``); the width of the
|
|
1437
|
+
border in pixels
|
|
1438
|
+
|
|
1439
|
+
- ``alpha`` -- (default: 1) how transparent the fill is; a number
|
|
1440
|
+
between 0 and 1
|
|
1441
|
+
|
|
1442
|
+
- ``legend_label`` -- the label for this item in the legend
|
|
1443
|
+
|
|
1444
|
+
- ``base`` -- (default: 10) the base of the logarithm if
|
|
1445
|
+
a logarithmic scale is set. This must be greater than 1. The base
|
|
1446
|
+
can be also given as a list or tuple ``(basex, basey)``.
|
|
1447
|
+
``basex`` sets the base of the logarithm along the horizontal
|
|
1448
|
+
axis and ``basey`` sets the base along the vertical axis.
|
|
1449
|
+
|
|
1450
|
+
- ``scale`` -- string (default: ``'linear'``); the scale of the axes.
|
|
1451
|
+
Possible values are ``'linear'``, ``'loglog'``, ``'semilogx'``,
|
|
1452
|
+
``'semilogy'``.
|
|
1453
|
+
|
|
1454
|
+
The scale can be also be given as single argument that is a list
|
|
1455
|
+
or tuple ``(scale, base)`` or ``(scale, basex, basey)``.
|
|
1456
|
+
|
|
1457
|
+
The ``'loglog'`` scale sets both the horizontal and vertical axes to
|
|
1458
|
+
logarithmic scale. The ``'semilogx'`` scale sets the horizontal axis
|
|
1459
|
+
to logarithmic scale. The ``'semilogy'`` scale sets the vertical axis
|
|
1460
|
+
to logarithmic scale. The ``'linear'`` scale is the default value
|
|
1461
|
+
when :class:`~sage.plot.graphics.Graphics` is initialized.
|
|
1462
|
+
|
|
1463
|
+
EXAMPLES:
|
|
1464
|
+
|
|
1465
|
+
Here we plot a simple function of two variables::
|
|
1466
|
+
|
|
1467
|
+
sage: x,y = var('x,y')
|
|
1468
|
+
sage: region_plot(cos(x^2 + y^2) <= 0, (x,-3,3), (y,-3,3))
|
|
1469
|
+
Graphics object consisting of 1 graphics primitive
|
|
1470
|
+
|
|
1471
|
+
.. PLOT::
|
|
1472
|
+
|
|
1473
|
+
x,y = var('x,y')
|
|
1474
|
+
g = region_plot(cos(x**2 + y**2) <= 0, (x,-3,3), (y,-3,3))
|
|
1475
|
+
sphinx_plot(g)
|
|
1476
|
+
|
|
1477
|
+
Here we play with the colors::
|
|
1478
|
+
|
|
1479
|
+
sage: region_plot(x^2 + y^3 < 2, (x,-2,2), (y,-2,2), incol='lightblue', bordercol='gray')
|
|
1480
|
+
Graphics object consisting of 2 graphics primitives
|
|
1481
|
+
|
|
1482
|
+
.. PLOT::
|
|
1483
|
+
|
|
1484
|
+
x,y = var('x,y')
|
|
1485
|
+
g = region_plot(x**2 + y**3 < 2, (x,-2,2), (y,-2,2), incol='lightblue', bordercol='gray')
|
|
1486
|
+
sphinx_plot(g)
|
|
1487
|
+
|
|
1488
|
+
An even more complicated plot, with dashed borders::
|
|
1489
|
+
|
|
1490
|
+
sage: region_plot(sin(x) * sin(y) >= 1/4, (x,-10,10), (y,-10,10),
|
|
1491
|
+
....: incol='yellow', bordercol='black',
|
|
1492
|
+
....: borderstyle='dashed', plot_points=250)
|
|
1493
|
+
Graphics object consisting of 2 graphics primitives
|
|
1494
|
+
|
|
1495
|
+
.. PLOT::
|
|
1496
|
+
|
|
1497
|
+
x,y = var('x,y')
|
|
1498
|
+
g = region_plot(sin(x) * sin(y) >= 1/4, (x,-10,10), (y,-10,10),
|
|
1499
|
+
incol='yellow', bordercol='black',
|
|
1500
|
+
borderstyle='dashed', plot_points=250)
|
|
1501
|
+
sphinx_plot(g)
|
|
1502
|
+
|
|
1503
|
+
A disk centered at the origin::
|
|
1504
|
+
|
|
1505
|
+
sage: region_plot(x^2 + y^2 < 1, (x,-1,1), (y,-1,1))
|
|
1506
|
+
Graphics object consisting of 1 graphics primitive
|
|
1507
|
+
|
|
1508
|
+
.. PLOT::
|
|
1509
|
+
|
|
1510
|
+
x,y = var('x,y')
|
|
1511
|
+
g = region_plot(x**2 + y**2 < 1, (x,-1,1), (y,-1,1))
|
|
1512
|
+
sphinx_plot(g)
|
|
1513
|
+
|
|
1514
|
+
A plot with more than one condition (all conditions must be true for the
|
|
1515
|
+
statement to be true)::
|
|
1516
|
+
|
|
1517
|
+
sage: region_plot([x^2 + y^2 < 1, x < y], (x,-2,2), (y,-2,2))
|
|
1518
|
+
Graphics object consisting of 1 graphics primitive
|
|
1519
|
+
|
|
1520
|
+
.. PLOT::
|
|
1521
|
+
|
|
1522
|
+
x,y = var('x,y')
|
|
1523
|
+
g = region_plot([x**2 + y**2 < 1, x < y], (x,-2,2), (y,-2,2))
|
|
1524
|
+
sphinx_plot(g)
|
|
1525
|
+
|
|
1526
|
+
Since it does not look very good, let us increase ``plot_points``::
|
|
1527
|
+
|
|
1528
|
+
sage: region_plot([x^2 + y^2 < 1, x< y], (x,-2,2), (y,-2,2), plot_points=400)
|
|
1529
|
+
Graphics object consisting of 1 graphics primitive
|
|
1530
|
+
|
|
1531
|
+
.. PLOT::
|
|
1532
|
+
|
|
1533
|
+
x,y = var('x,y')
|
|
1534
|
+
g = region_plot([x**2 + y**2 < 1, x < y], (x,-2,2), (y,-2,2), plot_points=400)
|
|
1535
|
+
sphinx_plot(g)
|
|
1536
|
+
|
|
1537
|
+
To get plots where only one condition needs to be true, use a function.
|
|
1538
|
+
Using lambda functions, we definitely need the extra ``plot_points``::
|
|
1539
|
+
|
|
1540
|
+
sage: region_plot(lambda x, y: x^2 + y^2 < 1 or x < y, (x,-2,2), (y,-2,2), plot_points=400)
|
|
1541
|
+
Graphics object consisting of 1 graphics primitive
|
|
1542
|
+
|
|
1543
|
+
.. PLOT::
|
|
1544
|
+
|
|
1545
|
+
x,y = var('x,y')
|
|
1546
|
+
g = region_plot(lambda x, y: x**2 + y**2 < 1 or x < y, (x,-2,2), (y,-2,2), plot_points=400)
|
|
1547
|
+
sphinx_plot(g)
|
|
1548
|
+
|
|
1549
|
+
The first quadrant of the unit circle::
|
|
1550
|
+
|
|
1551
|
+
sage: region_plot([y > 0, x > 0, x^2 + y^2 < 1], (x,-1.1,1.1), (y,-1.1,1.1), plot_points=400)
|
|
1552
|
+
Graphics object consisting of 1 graphics primitive
|
|
1553
|
+
|
|
1554
|
+
.. PLOT::
|
|
1555
|
+
|
|
1556
|
+
x, y = var("x y")
|
|
1557
|
+
g = region_plot([y > 0, x > 0, x**2 + y**2 < 1], (x,-1.1,1.1), (y,-1.1,1.1), plot_points=400)
|
|
1558
|
+
sphinx_plot(g)
|
|
1559
|
+
|
|
1560
|
+
Here is another plot, with a huge border::
|
|
1561
|
+
|
|
1562
|
+
sage: region_plot(x*(x-1)*(x+1) + y^2 < 0, (x,-3,2), (y,-3,3),
|
|
1563
|
+
....: incol='lightblue', bordercol='gray', borderwidth=10,
|
|
1564
|
+
....: plot_points=50)
|
|
1565
|
+
Graphics object consisting of 2 graphics primitives
|
|
1566
|
+
|
|
1567
|
+
.. PLOT::
|
|
1568
|
+
|
|
1569
|
+
x, y = var("x y")
|
|
1570
|
+
g = region_plot(x*(x-1)*(x+1) + y**2 < 0, (x,-3,2), (y,-3,3),
|
|
1571
|
+
incol='lightblue', bordercol='gray', borderwidth=10,
|
|
1572
|
+
plot_points=50)
|
|
1573
|
+
sphinx_plot(g)
|
|
1574
|
+
|
|
1575
|
+
If we want to keep only the region where x is positive::
|
|
1576
|
+
|
|
1577
|
+
sage: region_plot([x*(x-1)*(x+1) + y^2 < 0, x > -1], (x,-3,2), (y,-3,3),
|
|
1578
|
+
....: incol='lightblue', plot_points=50)
|
|
1579
|
+
Graphics object consisting of 1 graphics primitive
|
|
1580
|
+
|
|
1581
|
+
.. PLOT::
|
|
1582
|
+
|
|
1583
|
+
x, y =var("x y")
|
|
1584
|
+
g = region_plot([x*(x-1)*(x+1) + y**2 < 0, x > -1], (x,-3,2), (y,-3,3),
|
|
1585
|
+
incol='lightblue', plot_points=50)
|
|
1586
|
+
sphinx_plot(g)
|
|
1587
|
+
|
|
1588
|
+
Here we have a cut circle::
|
|
1589
|
+
|
|
1590
|
+
sage: region_plot([x^2 + y^2 < 4, x > -1], (x,-2,2), (y,-2,2),
|
|
1591
|
+
....: incol='lightblue', bordercol='gray', plot_points=200)
|
|
1592
|
+
Graphics object consisting of 2 graphics primitives
|
|
1593
|
+
|
|
1594
|
+
.. PLOT::
|
|
1595
|
+
|
|
1596
|
+
x, y =var("x y")
|
|
1597
|
+
g = region_plot([x**2 + y**2 < 4, x > -1], (x,-2,2), (y,-2,2),
|
|
1598
|
+
incol='lightblue', bordercol='gray', plot_points=200)
|
|
1599
|
+
sphinx_plot(g)
|
|
1600
|
+
|
|
1601
|
+
The first variable range corresponds to the horizontal axis and
|
|
1602
|
+
the second variable range corresponds to the vertical axis::
|
|
1603
|
+
|
|
1604
|
+
sage: s, t = var('s, t')
|
|
1605
|
+
sage: region_plot(s > 0, (t,-2,2), (s,-2,2))
|
|
1606
|
+
Graphics object consisting of 1 graphics primitive
|
|
1607
|
+
|
|
1608
|
+
.. PLOT::
|
|
1609
|
+
|
|
1610
|
+
s, t = var('s, t')
|
|
1611
|
+
g = region_plot(s > 0, (t,-2,2), (s,-2,2))
|
|
1612
|
+
sphinx_plot(g)
|
|
1613
|
+
|
|
1614
|
+
::
|
|
1615
|
+
|
|
1616
|
+
sage: region_plot(s>0,(s,-2,2),(t,-2,2))
|
|
1617
|
+
Graphics object consisting of 1 graphics primitive
|
|
1618
|
+
|
|
1619
|
+
.. PLOT::
|
|
1620
|
+
|
|
1621
|
+
s, t = var('s, t')
|
|
1622
|
+
g = region_plot(s > 0, (s,-2,2), (t,-2,2))
|
|
1623
|
+
sphinx_plot(g)
|
|
1624
|
+
|
|
1625
|
+
An example of a region plot in 'loglog' scale::
|
|
1626
|
+
|
|
1627
|
+
sage: region_plot(x^2 + y^2 < 100, (x,1,10), (y,1,10), scale='loglog')
|
|
1628
|
+
Graphics object consisting of 1 graphics primitive
|
|
1629
|
+
|
|
1630
|
+
.. PLOT::
|
|
1631
|
+
|
|
1632
|
+
x, y = var("x y")
|
|
1633
|
+
g = region_plot(x**2 + y**2 < 100, (x,1,10), (y,1,10), scale='loglog')
|
|
1634
|
+
sphinx_plot(g)
|
|
1635
|
+
|
|
1636
|
+
TESTS:
|
|
1637
|
+
|
|
1638
|
+
To check that :issue:`16907` is fixed::
|
|
1639
|
+
|
|
1640
|
+
sage: x, y = var('x, y')
|
|
1641
|
+
sage: disc1 = region_plot(x^2 + y^2 < 1, (x,-1,1), (y,-1,1), alpha=0.5)
|
|
1642
|
+
sage: disc2 = region_plot((x-0.7)^2 + (y-0.7)^2 < 0.5, (x,-2,2), (y,-2,2), incol='red', alpha=0.5)
|
|
1643
|
+
sage: disc1 + disc2
|
|
1644
|
+
Graphics object consisting of 2 graphics primitives
|
|
1645
|
+
|
|
1646
|
+
To check that :issue:`18286` is fixed::
|
|
1647
|
+
|
|
1648
|
+
sage: x, y = var('x, y')
|
|
1649
|
+
sage: region_plot([x == 0], (x,-1,1), (y,-1,1))
|
|
1650
|
+
Graphics object consisting of 1 graphics primitive
|
|
1651
|
+
sage: region_plot([x^2 + y^2 == 1, x < y], (x,-1,1), (y,-1,1))
|
|
1652
|
+
Graphics object consisting of 1 graphics primitive
|
|
1653
|
+
"""
|
|
1654
|
+
from sage.plot.all import Graphics
|
|
1655
|
+
from sage.plot.misc import setup_for_eval_on_grid
|
|
1656
|
+
from sage.structure.element import Expression
|
|
1657
|
+
from warnings import warn
|
|
1658
|
+
import numpy
|
|
1659
|
+
|
|
1660
|
+
plot_points = options['plot_points']
|
|
1661
|
+
incol = options.pop('incol')
|
|
1662
|
+
outcol = options.pop('outcol')
|
|
1663
|
+
bordercol = options.pop('bordercol')
|
|
1664
|
+
borderstyle = options.pop('borderstyle')
|
|
1665
|
+
borderwidth = options.pop('borderwidth')
|
|
1666
|
+
alpha = options.pop('alpha')
|
|
1667
|
+
|
|
1668
|
+
if not isinstance(f, (list, tuple)):
|
|
1669
|
+
f = [f]
|
|
1670
|
+
|
|
1671
|
+
feqs = [equify(g) for g in f
|
|
1672
|
+
if isinstance(g, Expression) and g.operator() is operator.eq
|
|
1673
|
+
and not equify(g).is_zero()]
|
|
1674
|
+
f = [equify(g) for g in f
|
|
1675
|
+
if not (isinstance(g, Expression) and g.operator() is operator.eq)]
|
|
1676
|
+
neqs = len(feqs)
|
|
1677
|
+
if neqs > 1:
|
|
1678
|
+
warn("There are at least 2 equations; "
|
|
1679
|
+
"If the region is degenerated to points, "
|
|
1680
|
+
"plotting might show nothing.")
|
|
1681
|
+
feqs = [sum([fn**2 for fn in feqs])]
|
|
1682
|
+
neqs = 1
|
|
1683
|
+
if neqs and not bordercol:
|
|
1684
|
+
bordercol = incol
|
|
1685
|
+
if not f:
|
|
1686
|
+
return implicit_plot(feqs[0], xrange, yrange, fill=False,
|
|
1687
|
+
linewidth=borderwidth, linestyle=borderstyle,
|
|
1688
|
+
color=bordercol, **options)
|
|
1689
|
+
f_all, ranges = setup_for_eval_on_grid(feqs + f,
|
|
1690
|
+
[xrange, yrange],
|
|
1691
|
+
plot_points)
|
|
1692
|
+
xrange, yrange = (r[:2] for r in ranges)
|
|
1693
|
+
|
|
1694
|
+
xy_data_arrays = numpy.asarray([[[func(x, y)
|
|
1695
|
+
for x in xsrange(*ranges[0],
|
|
1696
|
+
include_endpoint=True)]
|
|
1697
|
+
for y in xsrange(*ranges[1],
|
|
1698
|
+
include_endpoint=True)]
|
|
1699
|
+
for func in f_all[neqs::]], dtype=float)
|
|
1700
|
+
xy_data_array = numpy.abs(xy_data_arrays.prod(axis=0))
|
|
1701
|
+
# Now we need to set entries to negative iff all
|
|
1702
|
+
# functions were negative at that point.
|
|
1703
|
+
neg_indices = (xy_data_arrays < 0).all(axis=0)
|
|
1704
|
+
xy_data_array[neg_indices] = -xy_data_array[neg_indices]
|
|
1705
|
+
|
|
1706
|
+
from matplotlib.colors import ListedColormap
|
|
1707
|
+
incol = rgbcolor(incol)
|
|
1708
|
+
if outcol:
|
|
1709
|
+
outcol = rgbcolor(outcol)
|
|
1710
|
+
cmap = ListedColormap([incol, outcol])
|
|
1711
|
+
cmap.set_over(outcol, alpha=alpha)
|
|
1712
|
+
else:
|
|
1713
|
+
outcol = rgbcolor('white')
|
|
1714
|
+
cmap = ListedColormap([incol, outcol])
|
|
1715
|
+
cmap.set_over(outcol, alpha=0)
|
|
1716
|
+
cmap.set_under(incol, alpha=alpha)
|
|
1717
|
+
|
|
1718
|
+
g = Graphics()
|
|
1719
|
+
|
|
1720
|
+
# Reset aspect_ratio to 'automatic' in case scale is 'semilog[xy]'.
|
|
1721
|
+
# Otherwise matplotlib complains.
|
|
1722
|
+
scale = options.get('scale', None)
|
|
1723
|
+
if isinstance(scale, (list, tuple)):
|
|
1724
|
+
scale = scale[0]
|
|
1725
|
+
if scale in ('semilogy', 'semilogx'):
|
|
1726
|
+
options['aspect_ratio'] = 'automatic'
|
|
1727
|
+
|
|
1728
|
+
g._set_extra_kwds(Graphics._extract_kwds_for_show(options,
|
|
1729
|
+
ignore=['xmin', 'xmax']))
|
|
1730
|
+
|
|
1731
|
+
if neqs == 0:
|
|
1732
|
+
g.add_primitive(ContourPlot(xy_data_array, xrange, yrange,
|
|
1733
|
+
dict(contours=[-1e-20, 0, 1e-20],
|
|
1734
|
+
cmap=cmap,
|
|
1735
|
+
fill=True, **options)))
|
|
1736
|
+
else:
|
|
1737
|
+
mask = numpy.asarray([[elt > 0 for elt in rows]
|
|
1738
|
+
for rows in xy_data_array],
|
|
1739
|
+
dtype=bool)
|
|
1740
|
+
xy_data_array = numpy.asarray([[f_all[0](x, y)
|
|
1741
|
+
for x in xsrange(*ranges[0],
|
|
1742
|
+
include_endpoint=True)]
|
|
1743
|
+
for y in xsrange(*ranges[1],
|
|
1744
|
+
include_endpoint=True)],
|
|
1745
|
+
dtype=float)
|
|
1746
|
+
xy_data_array[mask] = None
|
|
1747
|
+
if bordercol or borderstyle or borderwidth:
|
|
1748
|
+
cmap = [rgbcolor(bordercol)] if bordercol else ['black']
|
|
1749
|
+
linestyles = [borderstyle] if borderstyle else None
|
|
1750
|
+
linewidths = [borderwidth] if borderwidth else None
|
|
1751
|
+
g.add_primitive(ContourPlot(xy_data_array, xrange, yrange,
|
|
1752
|
+
dict(linestyles=linestyles,
|
|
1753
|
+
linewidths=linewidths,
|
|
1754
|
+
contours=[0], cmap=[bordercol],
|
|
1755
|
+
fill=False, **options)))
|
|
1756
|
+
|
|
1757
|
+
return g
|
|
1758
|
+
|
|
1759
|
+
|
|
1760
|
+
def equify(f):
|
|
1761
|
+
"""
|
|
1762
|
+
Return the equation rewritten as a symbolic function to give
|
|
1763
|
+
negative values when ``True``, positive when ``False``.
|
|
1764
|
+
|
|
1765
|
+
EXAMPLES::
|
|
1766
|
+
|
|
1767
|
+
sage: from sage.plot.contour_plot import equify
|
|
1768
|
+
sage: var('x, y')
|
|
1769
|
+
(x, y)
|
|
1770
|
+
sage: equify(x^2 < 2)
|
|
1771
|
+
x^2 - 2
|
|
1772
|
+
sage: equify(x^2 > 2)
|
|
1773
|
+
-x^2 + 2
|
|
1774
|
+
sage: equify(x*y > 1)
|
|
1775
|
+
-x*y + 1
|
|
1776
|
+
sage: equify(y > 0)
|
|
1777
|
+
-y
|
|
1778
|
+
sage: f = equify(lambda x, y: x > y)
|
|
1779
|
+
sage: f(1, 2)
|
|
1780
|
+
1
|
|
1781
|
+
sage: f(2, 1)
|
|
1782
|
+
-1
|
|
1783
|
+
"""
|
|
1784
|
+
from sage.calculus.all import symbolic_expression
|
|
1785
|
+
from sage.structure.element import Expression
|
|
1786
|
+
if not isinstance(f, Expression):
|
|
1787
|
+
return lambda x, y: -1 if f(x, y) else 1
|
|
1788
|
+
|
|
1789
|
+
op = f.operator()
|
|
1790
|
+
if op is operator.gt or op is operator.ge:
|
|
1791
|
+
return symbolic_expression(f.rhs() - f.lhs())
|
|
1792
|
+
return symbolic_expression(f.lhs() - f.rhs())
|