test_plot.py 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764
  1. import os
  2. from tempfile import TemporaryDirectory
  3. from sympy.concrete.summations import Sum
  4. from sympy.core.numbers import (I, oo, pi)
  5. from sympy.core.relational import Ne
  6. from sympy.core.symbol import Symbol
  7. from sympy.functions.elementary.exponential import (LambertW, exp, exp_polar, log)
  8. from sympy.functions.elementary.miscellaneous import (real_root, sqrt)
  9. from sympy.functions.elementary.piecewise import Piecewise
  10. from sympy.functions.elementary.trigonometric import (cos, sin)
  11. from sympy.functions.special.hyper import meijerg
  12. from sympy.integrals.integrals import Integral
  13. from sympy.logic.boolalg import And
  14. from sympy.core.singleton import S
  15. from sympy.core.sympify import sympify
  16. from sympy.external import import_module
  17. from sympy.plotting.plot import (
  18. Plot, plot, plot_parametric, plot3d_parametric_line, plot3d,
  19. plot3d_parametric_surface)
  20. from sympy.plotting.plot import (
  21. unset_show, plot_contour, PlotGrid, DefaultBackend, MatplotlibBackend,
  22. TextBackend, BaseBackend)
  23. from sympy.testing.pytest import skip, raises, warns, warns_deprecated_sympy
  24. from sympy.utilities import lambdify as lambdify_
  25. from sympy.utilities.exceptions import ignore_warnings
  26. unset_show()
  27. matplotlib = import_module(
  28. 'matplotlib', min_module_version='1.1.0', catch=(RuntimeError,))
  29. class DummyBackendNotOk(BaseBackend):
  30. """ Used to verify if users can create their own backends.
  31. This backend is meant to raise NotImplementedError for methods `show`,
  32. `save`, `close`.
  33. """
  34. pass
  35. class DummyBackendOk(BaseBackend):
  36. """ Used to verify if users can create their own backends.
  37. This backend is meant to pass all tests.
  38. """
  39. def show(self):
  40. pass
  41. def save(self):
  42. pass
  43. def close(self):
  44. pass
  45. def test_plot_and_save_1():
  46. if not matplotlib:
  47. skip("Matplotlib not the default backend")
  48. x = Symbol('x')
  49. y = Symbol('y')
  50. with TemporaryDirectory(prefix='sympy_') as tmpdir:
  51. ###
  52. # Examples from the 'introduction' notebook
  53. ###
  54. p = plot(x, legend=True, label='f1')
  55. p = plot(x*sin(x), x*cos(x), label='f2')
  56. p.extend(p)
  57. p[0].line_color = lambda a: a
  58. p[1].line_color = 'b'
  59. p.title = 'Big title'
  60. p.xlabel = 'the x axis'
  61. p[1].label = 'straight line'
  62. p.legend = True
  63. p.aspect_ratio = (1, 1)
  64. p.xlim = (-15, 20)
  65. filename = 'test_basic_options_and_colors.png'
  66. p.save(os.path.join(tmpdir, filename))
  67. p._backend.close()
  68. p.extend(plot(x + 1))
  69. p.append(plot(x + 3, x**2)[1])
  70. filename = 'test_plot_extend_append.png'
  71. p.save(os.path.join(tmpdir, filename))
  72. p[2] = plot(x**2, (x, -2, 3))
  73. filename = 'test_plot_setitem.png'
  74. p.save(os.path.join(tmpdir, filename))
  75. p._backend.close()
  76. p = plot(sin(x), (x, -2*pi, 4*pi))
  77. filename = 'test_line_explicit.png'
  78. p.save(os.path.join(tmpdir, filename))
  79. p._backend.close()
  80. p = plot(sin(x))
  81. filename = 'test_line_default_range.png'
  82. p.save(os.path.join(tmpdir, filename))
  83. p._backend.close()
  84. p = plot((x**2, (x, -5, 5)), (x**3, (x, -3, 3)))
  85. filename = 'test_line_multiple_range.png'
  86. p.save(os.path.join(tmpdir, filename))
  87. p._backend.close()
  88. raises(ValueError, lambda: plot(x, y))
  89. #Piecewise plots
  90. p = plot(Piecewise((1, x > 0), (0, True)), (x, -1, 1))
  91. filename = 'test_plot_piecewise.png'
  92. p.save(os.path.join(tmpdir, filename))
  93. p._backend.close()
  94. p = plot(Piecewise((x, x < 1), (x**2, True)), (x, -3, 3))
  95. filename = 'test_plot_piecewise_2.png'
  96. p.save(os.path.join(tmpdir, filename))
  97. p._backend.close()
  98. # test issue 7471
  99. p1 = plot(x)
  100. p2 = plot(3)
  101. p1.extend(p2)
  102. filename = 'test_horizontal_line.png'
  103. p.save(os.path.join(tmpdir, filename))
  104. p._backend.close()
  105. # test issue 10925
  106. f = Piecewise((-1, x < -1), (x, And(-1 <= x, x < 0)), \
  107. (x**2, And(0 <= x, x < 1)), (x**3, x >= 1))
  108. p = plot(f, (x, -3, 3))
  109. filename = 'test_plot_piecewise_3.png'
  110. p.save(os.path.join(tmpdir, filename))
  111. p._backend.close()
  112. def test_plot_and_save_2():
  113. if not matplotlib:
  114. skip("Matplotlib not the default backend")
  115. x = Symbol('x')
  116. y = Symbol('y')
  117. z = Symbol('z')
  118. with TemporaryDirectory(prefix='sympy_') as tmpdir:
  119. #parametric 2d plots.
  120. #Single plot with default range.
  121. p = plot_parametric(sin(x), cos(x))
  122. filename = 'test_parametric.png'
  123. p.save(os.path.join(tmpdir, filename))
  124. p._backend.close()
  125. #Single plot with range.
  126. p = plot_parametric(
  127. sin(x), cos(x), (x, -5, 5), legend=True, label='parametric_plot')
  128. filename = 'test_parametric_range.png'
  129. p.save(os.path.join(tmpdir, filename))
  130. p._backend.close()
  131. #Multiple plots with same range.
  132. p = plot_parametric((sin(x), cos(x)), (x, sin(x)))
  133. filename = 'test_parametric_multiple.png'
  134. p.save(os.path.join(tmpdir, filename))
  135. p._backend.close()
  136. #Multiple plots with different ranges.
  137. p = plot_parametric(
  138. (sin(x), cos(x), (x, -3, 3)), (x, sin(x), (x, -5, 5)))
  139. filename = 'test_parametric_multiple_ranges.png'
  140. p.save(os.path.join(tmpdir, filename))
  141. p._backend.close()
  142. #depth of recursion specified.
  143. p = plot_parametric(x, sin(x), depth=13)
  144. filename = 'test_recursion_depth.png'
  145. p.save(os.path.join(tmpdir, filename))
  146. p._backend.close()
  147. #No adaptive sampling.
  148. p = plot_parametric(cos(x), sin(x), adaptive=False, nb_of_points=500)
  149. filename = 'test_adaptive.png'
  150. p.save(os.path.join(tmpdir, filename))
  151. p._backend.close()
  152. #3d parametric plots
  153. p = plot3d_parametric_line(
  154. sin(x), cos(x), x, legend=True, label='3d_parametric_plot')
  155. filename = 'test_3d_line.png'
  156. p.save(os.path.join(tmpdir, filename))
  157. p._backend.close()
  158. p = plot3d_parametric_line(
  159. (sin(x), cos(x), x, (x, -5, 5)), (cos(x), sin(x), x, (x, -3, 3)))
  160. filename = 'test_3d_line_multiple.png'
  161. p.save(os.path.join(tmpdir, filename))
  162. p._backend.close()
  163. p = plot3d_parametric_line(sin(x), cos(x), x, nb_of_points=30)
  164. filename = 'test_3d_line_points.png'
  165. p.save(os.path.join(tmpdir, filename))
  166. p._backend.close()
  167. # 3d surface single plot.
  168. p = plot3d(x * y)
  169. filename = 'test_surface.png'
  170. p.save(os.path.join(tmpdir, filename))
  171. p._backend.close()
  172. # Multiple 3D plots with same range.
  173. p = plot3d(-x * y, x * y, (x, -5, 5))
  174. filename = 'test_surface_multiple.png'
  175. p.save(os.path.join(tmpdir, filename))
  176. p._backend.close()
  177. # Multiple 3D plots with different ranges.
  178. p = plot3d(
  179. (x * y, (x, -3, 3), (y, -3, 3)), (-x * y, (x, -3, 3), (y, -3, 3)))
  180. filename = 'test_surface_multiple_ranges.png'
  181. p.save(os.path.join(tmpdir, filename))
  182. p._backend.close()
  183. # Single Parametric 3D plot
  184. p = plot3d_parametric_surface(sin(x + y), cos(x - y), x - y)
  185. filename = 'test_parametric_surface.png'
  186. p.save(os.path.join(tmpdir, filename))
  187. p._backend.close()
  188. # Multiple Parametric 3D plots.
  189. p = plot3d_parametric_surface(
  190. (x*sin(z), x*cos(z), z, (x, -5, 5), (z, -5, 5)),
  191. (sin(x + y), cos(x - y), x - y, (x, -5, 5), (y, -5, 5)))
  192. filename = 'test_parametric_surface.png'
  193. p.save(os.path.join(tmpdir, filename))
  194. p._backend.close()
  195. # Single Contour plot.
  196. p = plot_contour(sin(x)*sin(y), (x, -5, 5), (y, -5, 5))
  197. filename = 'test_contour_plot.png'
  198. p.save(os.path.join(tmpdir, filename))
  199. p._backend.close()
  200. # Multiple Contour plots with same range.
  201. p = plot_contour(x**2 + y**2, x**3 + y**3, (x, -5, 5), (y, -5, 5))
  202. filename = 'test_contour_plot.png'
  203. p.save(os.path.join(tmpdir, filename))
  204. p._backend.close()
  205. # Multiple Contour plots with different range.
  206. p = plot_contour(
  207. (x**2 + y**2, (x, -5, 5), (y, -5, 5)),
  208. (x**3 + y**3, (x, -3, 3), (y, -3, 3)))
  209. filename = 'test_contour_plot.png'
  210. p.save(os.path.join(tmpdir, filename))
  211. p._backend.close()
  212. def test_plot_and_save_3():
  213. if not matplotlib:
  214. skip("Matplotlib not the default backend")
  215. x = Symbol('x')
  216. y = Symbol('y')
  217. z = Symbol('z')
  218. with TemporaryDirectory(prefix='sympy_') as tmpdir:
  219. ###
  220. # Examples from the 'colors' notebook
  221. ###
  222. p = plot(sin(x))
  223. p[0].line_color = lambda a: a
  224. filename = 'test_colors_line_arity1.png'
  225. p.save(os.path.join(tmpdir, filename))
  226. p[0].line_color = lambda a, b: b
  227. filename = 'test_colors_line_arity2.png'
  228. p.save(os.path.join(tmpdir, filename))
  229. p._backend.close()
  230. p = plot(x*sin(x), x*cos(x), (x, 0, 10))
  231. p[0].line_color = lambda a: a
  232. filename = 'test_colors_param_line_arity1.png'
  233. p.save(os.path.join(tmpdir, filename))
  234. p[0].line_color = lambda a, b: a
  235. filename = 'test_colors_param_line_arity1.png'
  236. p.save(os.path.join(tmpdir, filename))
  237. p[0].line_color = lambda a, b: b
  238. filename = 'test_colors_param_line_arity2b.png'
  239. p.save(os.path.join(tmpdir, filename))
  240. p._backend.close()
  241. p = plot3d_parametric_line(sin(x) + 0.1*sin(x)*cos(7*x),
  242. cos(x) + 0.1*cos(x)*cos(7*x),
  243. 0.1*sin(7*x),
  244. (x, 0, 2*pi))
  245. p[0].line_color = lambdify_(x, sin(4*x))
  246. filename = 'test_colors_3d_line_arity1.png'
  247. p.save(os.path.join(tmpdir, filename))
  248. p[0].line_color = lambda a, b: b
  249. filename = 'test_colors_3d_line_arity2.png'
  250. p.save(os.path.join(tmpdir, filename))
  251. p[0].line_color = lambda a, b, c: c
  252. filename = 'test_colors_3d_line_arity3.png'
  253. p.save(os.path.join(tmpdir, filename))
  254. p._backend.close()
  255. p = plot3d(sin(x)*y, (x, 0, 6*pi), (y, -5, 5))
  256. p[0].surface_color = lambda a: a
  257. filename = 'test_colors_surface_arity1.png'
  258. p.save(os.path.join(tmpdir, filename))
  259. p[0].surface_color = lambda a, b: b
  260. filename = 'test_colors_surface_arity2.png'
  261. p.save(os.path.join(tmpdir, filename))
  262. p[0].surface_color = lambda a, b, c: c
  263. filename = 'test_colors_surface_arity3a.png'
  264. p.save(os.path.join(tmpdir, filename))
  265. p[0].surface_color = lambdify_((x, y, z), sqrt((x - 3*pi)**2 + y**2))
  266. filename = 'test_colors_surface_arity3b.png'
  267. p.save(os.path.join(tmpdir, filename))
  268. p._backend.close()
  269. p = plot3d_parametric_surface(x * cos(4 * y), x * sin(4 * y), y,
  270. (x, -1, 1), (y, -1, 1))
  271. p[0].surface_color = lambda a: a
  272. filename = 'test_colors_param_surf_arity1.png'
  273. p.save(os.path.join(tmpdir, filename))
  274. p[0].surface_color = lambda a, b: a*b
  275. filename = 'test_colors_param_surf_arity2.png'
  276. p.save(os.path.join(tmpdir, filename))
  277. p[0].surface_color = lambdify_((x, y, z), sqrt(x**2 + y**2 + z**2))
  278. filename = 'test_colors_param_surf_arity3.png'
  279. p.save(os.path.join(tmpdir, filename))
  280. p._backend.close()
  281. def test_plot_and_save_4():
  282. if not matplotlib:
  283. skip("Matplotlib not the default backend")
  284. x = Symbol('x')
  285. y = Symbol('y')
  286. ###
  287. # Examples from the 'advanced' notebook
  288. ###
  289. # XXX: This raises the warning "The evaluation of the expression is
  290. # problematic. We are trying a failback method that may still work. Please
  291. # report this as a bug." It has to use the fallback because using evalf()
  292. # is the only way to evaluate the integral. We should perhaps just remove
  293. # that warning.
  294. with TemporaryDirectory(prefix='sympy_') as tmpdir:
  295. with warns(
  296. UserWarning,
  297. match="The evaluation of the expression is problematic",
  298. test_stacklevel=False,
  299. ):
  300. i = Integral(log((sin(x)**2 + 1)*sqrt(x**2 + 1)), (x, 0, y))
  301. p = plot(i, (y, 1, 5))
  302. filename = 'test_advanced_integral.png'
  303. p.save(os.path.join(tmpdir, filename))
  304. p._backend.close()
  305. def test_plot_and_save_5():
  306. if not matplotlib:
  307. skip("Matplotlib not the default backend")
  308. x = Symbol('x')
  309. y = Symbol('y')
  310. with TemporaryDirectory(prefix='sympy_') as tmpdir:
  311. s = Sum(1/x**y, (x, 1, oo))
  312. p = plot(s, (y, 2, 10))
  313. filename = 'test_advanced_inf_sum.png'
  314. p.save(os.path.join(tmpdir, filename))
  315. p._backend.close()
  316. p = plot(Sum(1/x, (x, 1, y)), (y, 2, 10), show=False)
  317. p[0].only_integers = True
  318. p[0].steps = True
  319. filename = 'test_advanced_fin_sum.png'
  320. # XXX: This should be fixed in experimental_lambdify or by using
  321. # ordinary lambdify so that it doesn't warn. The error results from
  322. # passing an array of values as the integration limit.
  323. #
  324. # UserWarning: The evaluation of the expression is problematic. We are
  325. # trying a failback method that may still work. Please report this as a
  326. # bug.
  327. with ignore_warnings(UserWarning):
  328. p.save(os.path.join(tmpdir, filename))
  329. p._backend.close()
  330. def test_plot_and_save_6():
  331. if not matplotlib:
  332. skip("Matplotlib not the default backend")
  333. x = Symbol('x')
  334. with TemporaryDirectory(prefix='sympy_') as tmpdir:
  335. filename = 'test.png'
  336. ###
  337. # Test expressions that can not be translated to np and generate complex
  338. # results.
  339. ###
  340. p = plot(sin(x) + I*cos(x))
  341. p.save(os.path.join(tmpdir, filename))
  342. with ignore_warnings(RuntimeWarning):
  343. p = plot(sqrt(sqrt(-x)))
  344. p.save(os.path.join(tmpdir, filename))
  345. p = plot(LambertW(x))
  346. p.save(os.path.join(tmpdir, filename))
  347. p = plot(sqrt(LambertW(x)))
  348. p.save(os.path.join(tmpdir, filename))
  349. #Characteristic function of a StudentT distribution with nu=10
  350. x1 = 5 * x**2 * exp_polar(-I*pi)/2
  351. m1 = meijerg(((1 / 2,), ()), ((5, 0, 1 / 2), ()), x1)
  352. x2 = 5*x**2 * exp_polar(I*pi)/2
  353. m2 = meijerg(((1/2,), ()), ((5, 0, 1/2), ()), x2)
  354. expr = (m1 + m2) / (48 * pi)
  355. p = plot(expr, (x, 1e-6, 1e-2))
  356. p.save(os.path.join(tmpdir, filename))
  357. def test_plotgrid_and_save():
  358. if not matplotlib:
  359. skip("Matplotlib not the default backend")
  360. x = Symbol('x')
  361. y = Symbol('y')
  362. with TemporaryDirectory(prefix='sympy_') as tmpdir:
  363. p1 = plot(x)
  364. p2 = plot_parametric((sin(x), cos(x)), (x, sin(x)), show=False)
  365. p3 = plot_parametric(
  366. cos(x), sin(x), adaptive=False, nb_of_points=500, show=False)
  367. p4 = plot3d_parametric_line(sin(x), cos(x), x, show=False)
  368. # symmetric grid
  369. p = PlotGrid(2, 2, p1, p2, p3, p4)
  370. filename = 'test_grid1.png'
  371. p.save(os.path.join(tmpdir, filename))
  372. p._backend.close()
  373. # grid size greater than the number of subplots
  374. p = PlotGrid(3, 4, p1, p2, p3, p4)
  375. filename = 'test_grid2.png'
  376. p.save(os.path.join(tmpdir, filename))
  377. p._backend.close()
  378. p5 = plot(cos(x),(x, -pi, pi), show=False)
  379. p5[0].line_color = lambda a: a
  380. p6 = plot(Piecewise((1, x > 0), (0, True)), (x, -1, 1), show=False)
  381. p7 = plot_contour(
  382. (x**2 + y**2, (x, -5, 5), (y, -5, 5)),
  383. (x**3 + y**3, (x, -3, 3), (y, -3, 3)), show=False)
  384. # unsymmetric grid (subplots in one line)
  385. p = PlotGrid(1, 3, p5, p6, p7)
  386. filename = 'test_grid3.png'
  387. p.save(os.path.join(tmpdir, filename))
  388. p._backend.close()
  389. def test_append_issue_7140():
  390. if not matplotlib:
  391. skip("Matplotlib not the default backend")
  392. x = Symbol('x')
  393. p1 = plot(x)
  394. p2 = plot(x**2)
  395. plot(x + 2)
  396. # append a series
  397. p2.append(p1[0])
  398. assert len(p2._series) == 2
  399. with raises(TypeError):
  400. p1.append(p2)
  401. with raises(TypeError):
  402. p1.append(p2._series)
  403. def test_issue_15265():
  404. if not matplotlib:
  405. skip("Matplotlib not the default backend")
  406. x = Symbol('x')
  407. eqn = sin(x)
  408. p = plot(eqn, xlim=(-S.Pi, S.Pi), ylim=(-1, 1))
  409. p._backend.close()
  410. p = plot(eqn, xlim=(-1, 1), ylim=(-S.Pi, S.Pi))
  411. p._backend.close()
  412. p = plot(eqn, xlim=(-1, 1), ylim=(sympify('-3.14'), sympify('3.14')))
  413. p._backend.close()
  414. p = plot(eqn, xlim=(sympify('-3.14'), sympify('3.14')), ylim=(-1, 1))
  415. p._backend.close()
  416. raises(ValueError,
  417. lambda: plot(eqn, xlim=(-S.ImaginaryUnit, 1), ylim=(-1, 1)))
  418. raises(ValueError,
  419. lambda: plot(eqn, xlim=(-1, 1), ylim=(-1, S.ImaginaryUnit)))
  420. raises(ValueError,
  421. lambda: plot(eqn, xlim=(S.NegativeInfinity, 1), ylim=(-1, 1)))
  422. raises(ValueError,
  423. lambda: plot(eqn, xlim=(-1, 1), ylim=(-1, S.Infinity)))
  424. def test_empty_Plot():
  425. if not matplotlib:
  426. skip("Matplotlib not the default backend")
  427. # No exception showing an empty plot
  428. plot()
  429. p = Plot()
  430. p.show()
  431. def test_issue_17405():
  432. if not matplotlib:
  433. skip("Matplotlib not the default backend")
  434. x = Symbol('x')
  435. f = x**0.3 - 10*x**3 + x**2
  436. p = plot(f, (x, -10, 10), show=False)
  437. # Random number of segments, probably more than 100, but we want to see
  438. # that there are segments generated, as opposed to when the bug was present
  439. # RuntimeWarning: invalid value encountered in double_scalars
  440. with ignore_warnings(RuntimeWarning):
  441. assert len(p[0].get_data()[0]) >= 30
  442. def test_logplot_PR_16796():
  443. if not matplotlib:
  444. skip("Matplotlib not the default backend")
  445. x = Symbol('x')
  446. p = plot(x, (x, .001, 100), xscale='log', show=False)
  447. # Random number of segments, probably more than 100, but we want to see
  448. # that there are segments generated, as opposed to when the bug was present
  449. assert len(p[0].get_data()[0]) >= 30
  450. assert p[0].end == 100.0
  451. assert p[0].start == .001
  452. def test_issue_16572():
  453. if not matplotlib:
  454. skip("Matplotlib not the default backend")
  455. x = Symbol('x')
  456. p = plot(LambertW(x), show=False)
  457. # Random number of segments, probably more than 50, but we want to see
  458. # that there are segments generated, as opposed to when the bug was present
  459. assert len(p[0].get_data()[0]) >= 30
  460. def test_issue_11865():
  461. if not matplotlib:
  462. skip("Matplotlib not the default backend")
  463. k = Symbol('k', integer=True)
  464. f = Piecewise((-I*exp(I*pi*k)/k + I*exp(-I*pi*k)/k, Ne(k, 0)), (2*pi, True))
  465. p = plot(f, show=False)
  466. # Random number of segments, probably more than 100, but we want to see
  467. # that there are segments generated, as opposed to when the bug was present
  468. # and that there are no exceptions.
  469. assert len(p[0].get_data()[0]) >= 30
  470. def test_issue_11461():
  471. if not matplotlib:
  472. skip("Matplotlib not the default backend")
  473. x = Symbol('x')
  474. p = plot(real_root((log(x/(x-2))), 3), show=False)
  475. # Random number of segments, probably more than 100, but we want to see
  476. # that there are segments generated, as opposed to when the bug was present
  477. # and that there are no exceptions.
  478. assert len(p[0].get_data()[0]) >= 30
  479. def test_issue_11764():
  480. if not matplotlib:
  481. skip("Matplotlib not the default backend")
  482. x = Symbol('x')
  483. p = plot_parametric(cos(x), sin(x), (x, 0, 2 * pi), aspect_ratio=(1,1), show=False)
  484. assert p.aspect_ratio == (1, 1)
  485. # Random number of segments, probably more than 100, but we want to see
  486. # that there are segments generated, as opposed to when the bug was present
  487. assert len(p[0].get_data()[0]) >= 30
  488. def test_issue_13516():
  489. if not matplotlib:
  490. skip("Matplotlib not the default backend")
  491. x = Symbol('x')
  492. pm = plot(sin(x), backend="matplotlib", show=False)
  493. assert pm.backend == MatplotlibBackend
  494. assert len(pm[0].get_data()[0]) >= 30
  495. pt = plot(sin(x), backend="text", show=False)
  496. assert pt.backend == TextBackend
  497. assert len(pt[0].get_data()[0]) >= 30
  498. pd = plot(sin(x), backend="default", show=False)
  499. assert pd.backend == DefaultBackend
  500. assert len(pd[0].get_data()[0]) >= 30
  501. p = plot(sin(x), show=False)
  502. assert p.backend == DefaultBackend
  503. assert len(p[0].get_data()[0]) >= 30
  504. def test_plot_limits():
  505. if not matplotlib:
  506. skip("Matplotlib not the default backend")
  507. x = Symbol('x')
  508. p = plot(x, x**2, (x, -10, 10))
  509. backend = p._backend
  510. xmin, xmax = backend.ax[0].get_xlim()
  511. assert abs(xmin + 10) < 2
  512. assert abs(xmax - 10) < 2
  513. ymin, ymax = backend.ax[0].get_ylim()
  514. assert abs(ymin + 10) < 10
  515. assert abs(ymax - 100) < 10
  516. def test_plot3d_parametric_line_limits():
  517. if not matplotlib:
  518. skip("Matplotlib not the default backend")
  519. x = Symbol('x')
  520. v1 = (2*cos(x), 2*sin(x), 2*x, (x, -5, 5))
  521. v2 = (sin(x), cos(x), x, (x, -5, 5))
  522. p = plot3d_parametric_line(v1, v2)
  523. backend = p._backend
  524. xmin, xmax = backend.ax[0].get_xlim()
  525. assert abs(xmin + 2) < 1e-2
  526. assert abs(xmax - 2) < 1e-2
  527. ymin, ymax = backend.ax[0].get_ylim()
  528. assert abs(ymin + 2) < 1e-2
  529. assert abs(ymax - 2) < 1e-2
  530. zmin, zmax = backend.ax[0].get_zlim()
  531. assert abs(zmin + 10) < 1e-2
  532. assert abs(zmax - 10) < 1e-2
  533. p = plot3d_parametric_line(v2, v1)
  534. backend = p._backend
  535. xmin, xmax = backend.ax[0].get_xlim()
  536. assert abs(xmin + 2) < 1e-2
  537. assert abs(xmax - 2) < 1e-2
  538. ymin, ymax = backend.ax[0].get_ylim()
  539. assert abs(ymin + 2) < 1e-2
  540. assert abs(ymax - 2) < 1e-2
  541. zmin, zmax = backend.ax[0].get_zlim()
  542. assert abs(zmin + 10) < 1e-2
  543. assert abs(zmax - 10) < 1e-2
  544. def test_plot_size():
  545. if not matplotlib:
  546. skip("Matplotlib not the default backend")
  547. x = Symbol('x')
  548. p1 = plot(sin(x), backend="matplotlib", size=(8, 4))
  549. s1 = p1._backend.fig.get_size_inches()
  550. assert (s1[0] == 8) and (s1[1] == 4)
  551. p2 = plot(sin(x), backend="matplotlib", size=(5, 10))
  552. s2 = p2._backend.fig.get_size_inches()
  553. assert (s2[0] == 5) and (s2[1] == 10)
  554. p3 = PlotGrid(2, 1, p1, p2, size=(6, 2))
  555. s3 = p3._backend.fig.get_size_inches()
  556. assert (s3[0] == 6) and (s3[1] == 2)
  557. with raises(ValueError):
  558. plot(sin(x), backend="matplotlib", size=(-1, 3))
  559. def test_issue_20113():
  560. if not matplotlib:
  561. skip("Matplotlib not the default backend")
  562. x = Symbol('x')
  563. # verify the capability to use custom backends
  564. with raises(TypeError):
  565. plot(sin(x), backend=Plot, show=False)
  566. p2 = plot(sin(x), backend=MatplotlibBackend, show=False)
  567. assert p2.backend == MatplotlibBackend
  568. assert len(p2[0].get_data()[0]) >= 30
  569. p3 = plot(sin(x), backend=DummyBackendOk, show=False)
  570. assert p3.backend == DummyBackendOk
  571. assert len(p3[0].get_data()[0]) >= 30
  572. # test for an improper coded backend
  573. p4 = plot(sin(x), backend=DummyBackendNotOk, show=False)
  574. assert p4.backend == DummyBackendNotOk
  575. assert len(p4[0].get_data()[0]) >= 30
  576. with raises(NotImplementedError):
  577. p4.show()
  578. with raises(NotImplementedError):
  579. p4.save("test/path")
  580. with raises(NotImplementedError):
  581. p4._backend.close()
  582. def test_custom_coloring():
  583. x = Symbol('x')
  584. y = Symbol('y')
  585. plot(cos(x), line_color=lambda a: a)
  586. plot(cos(x), line_color=1)
  587. plot(cos(x), line_color="r")
  588. plot_parametric(cos(x), sin(x), line_color=lambda a: a)
  589. plot_parametric(cos(x), sin(x), line_color=1)
  590. plot_parametric(cos(x), sin(x), line_color="r")
  591. plot3d_parametric_line(cos(x), sin(x), x, line_color=lambda a: a)
  592. plot3d_parametric_line(cos(x), sin(x), x, line_color=1)
  593. plot3d_parametric_line(cos(x), sin(x), x, line_color="r")
  594. plot3d_parametric_surface(cos(x + y), sin(x - y), x - y,
  595. (x, -5, 5), (y, -5, 5),
  596. surface_color=lambda a, b: a**2 + b**2)
  597. plot3d_parametric_surface(cos(x + y), sin(x - y), x - y,
  598. (x, -5, 5), (y, -5, 5),
  599. surface_color=1)
  600. plot3d_parametric_surface(cos(x + y), sin(x - y), x - y,
  601. (x, -5, 5), (y, -5, 5),
  602. surface_color="r")
  603. plot3d(x*y, (x, -5, 5), (y, -5, 5),
  604. surface_color=lambda a, b: a**2 + b**2)
  605. plot3d(x*y, (x, -5, 5), (y, -5, 5), surface_color=1)
  606. plot3d(x*y, (x, -5, 5), (y, -5, 5), surface_color="r")
  607. def test_deprecated_get_segments():
  608. if not matplotlib:
  609. skip("Matplotlib not the default backend")
  610. x = Symbol('x')
  611. f = sin(x)
  612. p = plot(f, (x, -10, 10), show=False)
  613. with warns_deprecated_sympy():
  614. p[0].get_segments()