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.

Files changed (82) hide show
  1. passagemath_plot-10.6.31rc3.dist-info/METADATA +172 -0
  2. passagemath_plot-10.6.31rc3.dist-info/RECORD +82 -0
  3. passagemath_plot-10.6.31rc3.dist-info/WHEEL +6 -0
  4. passagemath_plot-10.6.31rc3.dist-info/top_level.txt +2 -0
  5. passagemath_plot.libs/libgfortran-83c28eba.so.5.0.0 +0 -0
  6. passagemath_plot.libs/libgsl-cda90e79.so.28.0.0 +0 -0
  7. passagemath_plot.libs/libopenblasp-r0-6dcb67f9.3.29.so +0 -0
  8. passagemath_plot.libs/libquadmath-2284e583.so.0.0.0 +0 -0
  9. sage/all__sagemath_plot.py +15 -0
  10. sage/ext_data/threejs/animation.css +195 -0
  11. sage/ext_data/threejs/animation.html +85 -0
  12. sage/ext_data/threejs/animation.js +273 -0
  13. sage/ext_data/threejs/fat_lines.js +48 -0
  14. sage/ext_data/threejs/threejs-version.txt +1 -0
  15. sage/ext_data/threejs/threejs_template.html +597 -0
  16. sage/interfaces/all__sagemath_plot.py +1 -0
  17. sage/interfaces/gnuplot.py +196 -0
  18. sage/interfaces/jmoldata.py +208 -0
  19. sage/interfaces/povray.py +56 -0
  20. sage/plot/all.py +42 -0
  21. sage/plot/animate.py +1796 -0
  22. sage/plot/arc.py +504 -0
  23. sage/plot/arrow.py +671 -0
  24. sage/plot/bar_chart.py +205 -0
  25. sage/plot/bezier_path.py +400 -0
  26. sage/plot/circle.py +435 -0
  27. sage/plot/colors.py +1606 -0
  28. sage/plot/complex_plot.cpython-314-x86_64-linux-gnu.so +0 -0
  29. sage/plot/complex_plot.pyx +1446 -0
  30. sage/plot/contour_plot.py +1792 -0
  31. sage/plot/density_plot.py +318 -0
  32. sage/plot/disk.py +373 -0
  33. sage/plot/ellipse.py +375 -0
  34. sage/plot/graphics.py +3580 -0
  35. sage/plot/histogram.py +354 -0
  36. sage/plot/hyperbolic_arc.py +404 -0
  37. sage/plot/hyperbolic_polygon.py +416 -0
  38. sage/plot/hyperbolic_regular_polygon.py +296 -0
  39. sage/plot/line.py +626 -0
  40. sage/plot/matrix_plot.py +629 -0
  41. sage/plot/misc.py +509 -0
  42. sage/plot/multigraphics.py +1294 -0
  43. sage/plot/plot.py +4183 -0
  44. sage/plot/plot3d/all.py +23 -0
  45. sage/plot/plot3d/base.cpython-314-x86_64-linux-gnu.so +0 -0
  46. sage/plot/plot3d/base.pxd +12 -0
  47. sage/plot/plot3d/base.pyx +3378 -0
  48. sage/plot/plot3d/implicit_plot3d.py +659 -0
  49. sage/plot/plot3d/implicit_surface.cpython-314-x86_64-linux-gnu.so +0 -0
  50. sage/plot/plot3d/implicit_surface.pyx +1453 -0
  51. sage/plot/plot3d/index_face_set.cpython-314-x86_64-linux-gnu.so +0 -0
  52. sage/plot/plot3d/index_face_set.pxd +32 -0
  53. sage/plot/plot3d/index_face_set.pyx +1873 -0
  54. sage/plot/plot3d/introduction.py +131 -0
  55. sage/plot/plot3d/list_plot3d.py +649 -0
  56. sage/plot/plot3d/parametric_plot3d.py +1130 -0
  57. sage/plot/plot3d/parametric_surface.cpython-314-x86_64-linux-gnu.so +0 -0
  58. sage/plot/plot3d/parametric_surface.pxd +12 -0
  59. sage/plot/plot3d/parametric_surface.pyx +893 -0
  60. sage/plot/plot3d/platonic.py +601 -0
  61. sage/plot/plot3d/plot3d.py +1442 -0
  62. sage/plot/plot3d/plot_field3d.py +162 -0
  63. sage/plot/plot3d/point_c.pxi +148 -0
  64. sage/plot/plot3d/revolution_plot3d.py +309 -0
  65. sage/plot/plot3d/shapes.cpython-314-x86_64-linux-gnu.so +0 -0
  66. sage/plot/plot3d/shapes.pxd +22 -0
  67. sage/plot/plot3d/shapes.pyx +1382 -0
  68. sage/plot/plot3d/shapes2.py +1512 -0
  69. sage/plot/plot3d/tachyon.py +1779 -0
  70. sage/plot/plot3d/texture.py +453 -0
  71. sage/plot/plot3d/transform.cpython-314-x86_64-linux-gnu.so +0 -0
  72. sage/plot/plot3d/transform.pxd +21 -0
  73. sage/plot/plot3d/transform.pyx +268 -0
  74. sage/plot/plot3d/tri_plot.py +589 -0
  75. sage/plot/plot_field.py +362 -0
  76. sage/plot/point.py +624 -0
  77. sage/plot/polygon.py +562 -0
  78. sage/plot/primitive.py +249 -0
  79. sage/plot/scatter_plot.py +199 -0
  80. sage/plot/step.py +85 -0
  81. sage/plot/streamline_plot.py +328 -0
  82. 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())