123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459 |
- import difflib
- import numpy as np
- import sys
- from pathlib import Path
- import pytest
- import matplotlib as mpl
- from matplotlib.testing import subprocess_run_for_testing
- from matplotlib import pyplot as plt
- def test_pyplot_up_to_date(tmpdir):
- pytest.importorskip("black")
- gen_script = Path(mpl.__file__).parents[2] / "tools/boilerplate.py"
- if not gen_script.exists():
- pytest.skip("boilerplate.py not found")
- orig_contents = Path(plt.__file__).read_text()
- plt_file = tmpdir.join('pyplot.py')
- plt_file.write_text(orig_contents, 'utf-8')
- subprocess_run_for_testing(
- [sys.executable, str(gen_script), str(plt_file)],
- check=True)
- new_contents = plt_file.read_text('utf-8')
- if orig_contents != new_contents:
- diff_msg = '\n'.join(
- difflib.unified_diff(
- orig_contents.split('\n'), new_contents.split('\n'),
- fromfile='found pyplot.py',
- tofile='expected pyplot.py',
- n=0, lineterm=''))
- pytest.fail(
- "pyplot.py is not up-to-date. Please run "
- "'python tools/boilerplate.py' to update pyplot.py. "
- "This needs to be done from an environment where your "
- "current working copy is installed (e.g. 'pip install -e'd). "
- "Here is a diff of unexpected differences:\n%s" % diff_msg
- )
- def test_copy_docstring_and_deprecators(recwarn):
- @mpl._api.rename_parameter("(version)", "old", "new")
- @mpl._api.make_keyword_only("(version)", "kwo")
- def func(new, kwo=None):
- pass
- @plt._copy_docstring_and_deprecators(func)
- def wrapper_func(new, kwo=None):
- pass
- wrapper_func(None)
- wrapper_func(new=None)
- wrapper_func(None, kwo=None)
- wrapper_func(new=None, kwo=None)
- assert not recwarn
- with pytest.warns(mpl.MatplotlibDeprecationWarning):
- wrapper_func(old=None)
- with pytest.warns(mpl.MatplotlibDeprecationWarning):
- wrapper_func(None, None)
- def test_pyplot_box():
- fig, ax = plt.subplots()
- plt.box(False)
- assert not ax.get_frame_on()
- plt.box(True)
- assert ax.get_frame_on()
- plt.box()
- assert not ax.get_frame_on()
- plt.box()
- assert ax.get_frame_on()
- def test_stackplot_smoke():
- # Small smoke test for stackplot (see #12405)
- plt.stackplot([1, 2, 3], [1, 2, 3])
- def test_nrows_error():
- with pytest.raises(TypeError):
- plt.subplot(nrows=1)
- with pytest.raises(TypeError):
- plt.subplot(ncols=1)
- def test_ioff():
- plt.ion()
- assert mpl.is_interactive()
- with plt.ioff():
- assert not mpl.is_interactive()
- assert mpl.is_interactive()
- plt.ioff()
- assert not mpl.is_interactive()
- with plt.ioff():
- assert not mpl.is_interactive()
- assert not mpl.is_interactive()
- def test_ion():
- plt.ioff()
- assert not mpl.is_interactive()
- with plt.ion():
- assert mpl.is_interactive()
- assert not mpl.is_interactive()
- plt.ion()
- assert mpl.is_interactive()
- with plt.ion():
- assert mpl.is_interactive()
- assert mpl.is_interactive()
- def test_nested_ion_ioff():
- # initial state is interactive
- plt.ion()
- # mixed ioff/ion
- with plt.ioff():
- assert not mpl.is_interactive()
- with plt.ion():
- assert mpl.is_interactive()
- assert not mpl.is_interactive()
- assert mpl.is_interactive()
- # redundant contexts
- with plt.ioff():
- with plt.ioff():
- assert not mpl.is_interactive()
- assert mpl.is_interactive()
- with plt.ion():
- plt.ioff()
- assert mpl.is_interactive()
- # initial state is not interactive
- plt.ioff()
- # mixed ioff/ion
- with plt.ion():
- assert mpl.is_interactive()
- with plt.ioff():
- assert not mpl.is_interactive()
- assert mpl.is_interactive()
- assert not mpl.is_interactive()
- # redundant contexts
- with plt.ion():
- with plt.ion():
- assert mpl.is_interactive()
- assert not mpl.is_interactive()
- with plt.ioff():
- plt.ion()
- assert not mpl.is_interactive()
- def test_close():
- try:
- plt.close(1.1)
- except TypeError as e:
- assert str(e) == "close() argument must be a Figure, an int, " \
- "a string, or None, not <class 'float'>"
- def test_subplot_reuse():
- ax1 = plt.subplot(121)
- assert ax1 is plt.gca()
- ax2 = plt.subplot(122)
- assert ax2 is plt.gca()
- ax3 = plt.subplot(121)
- assert ax1 is plt.gca()
- assert ax1 is ax3
- def test_axes_kwargs():
- # plt.axes() always creates new axes, even if axes kwargs differ.
- plt.figure()
- ax = plt.axes()
- ax1 = plt.axes()
- assert ax is not None
- assert ax1 is not ax
- plt.close()
- plt.figure()
- ax = plt.axes(projection='polar')
- ax1 = plt.axes(projection='polar')
- assert ax is not None
- assert ax1 is not ax
- plt.close()
- plt.figure()
- ax = plt.axes(projection='polar')
- ax1 = plt.axes()
- assert ax is not None
- assert ax1.name == 'rectilinear'
- assert ax1 is not ax
- plt.close()
- def test_subplot_replace_projection():
- # plt.subplot() searches for axes with the same subplot spec, and if one
- # exists, and the kwargs match returns it, create a new one if they do not
- fig = plt.figure()
- ax = plt.subplot(1, 2, 1)
- ax1 = plt.subplot(1, 2, 1)
- ax2 = plt.subplot(1, 2, 2)
- ax3 = plt.subplot(1, 2, 1, projection='polar')
- ax4 = plt.subplot(1, 2, 1, projection='polar')
- assert ax is not None
- assert ax1 is ax
- assert ax2 is not ax
- assert ax3 is not ax
- assert ax3 is ax4
- assert ax in fig.axes
- assert ax2 in fig.axes
- assert ax3 in fig.axes
- assert ax.name == 'rectilinear'
- assert ax2.name == 'rectilinear'
- assert ax3.name == 'polar'
- def test_subplot_kwarg_collision():
- ax1 = plt.subplot(projection='polar', theta_offset=0)
- ax2 = plt.subplot(projection='polar', theta_offset=0)
- assert ax1 is ax2
- ax1.remove()
- ax3 = plt.subplot(projection='polar', theta_offset=1)
- assert ax1 is not ax3
- assert ax1 not in plt.gcf().axes
- def test_gca():
- # plt.gca() returns an existing axes, unless there were no axes.
- plt.figure()
- ax = plt.gca()
- ax1 = plt.gca()
- assert ax is not None
- assert ax1 is ax
- plt.close()
- def test_subplot_projection_reuse():
- # create an Axes
- ax1 = plt.subplot(111)
- # check that it is current
- assert ax1 is plt.gca()
- # make sure we get it back if we ask again
- assert ax1 is plt.subplot(111)
- # remove it
- ax1.remove()
- # create a polar plot
- ax2 = plt.subplot(111, projection='polar')
- assert ax2 is plt.gca()
- # this should have deleted the first axes
- assert ax1 not in plt.gcf().axes
- # assert we get it back if no extra parameters passed
- assert ax2 is plt.subplot(111)
- ax2.remove()
- # now check explicitly setting the projection to rectilinear
- # makes a new axes
- ax3 = plt.subplot(111, projection='rectilinear')
- assert ax3 is plt.gca()
- assert ax3 is not ax2
- assert ax2 not in plt.gcf().axes
- def test_subplot_polar_normalization():
- ax1 = plt.subplot(111, projection='polar')
- ax2 = plt.subplot(111, polar=True)
- ax3 = plt.subplot(111, polar=True, projection='polar')
- assert ax1 is ax2
- assert ax1 is ax3
- with pytest.raises(ValueError,
- match="polar=True, yet projection='3d'"):
- ax2 = plt.subplot(111, polar=True, projection='3d')
- def test_subplot_change_projection():
- created_axes = set()
- ax = plt.subplot()
- created_axes.add(ax)
- projections = ('aitoff', 'hammer', 'lambert', 'mollweide',
- 'polar', 'rectilinear', '3d')
- for proj in projections:
- ax.remove()
- ax = plt.subplot(projection=proj)
- assert ax is plt.subplot()
- assert ax.name == proj
- created_axes.add(ax)
- # Check that each call created a new Axes.
- assert len(created_axes) == 1 + len(projections)
- def test_polar_second_call():
- # the first call creates the axes with polar projection
- ln1, = plt.polar(0., 1., 'ro')
- assert isinstance(ln1, mpl.lines.Line2D)
- # the second call should reuse the existing axes
- ln2, = plt.polar(1.57, .5, 'bo')
- assert isinstance(ln2, mpl.lines.Line2D)
- assert ln1.axes is ln2.axes
- def test_fallback_position():
- # check that position kwarg works if rect not supplied
- axref = plt.axes([0.2, 0.2, 0.5, 0.5])
- axtest = plt.axes(position=[0.2, 0.2, 0.5, 0.5])
- np.testing.assert_allclose(axtest.bbox.get_points(),
- axref.bbox.get_points())
- # check that position kwarg ignored if rect is supplied
- axref = plt.axes([0.2, 0.2, 0.5, 0.5])
- axtest = plt.axes([0.2, 0.2, 0.5, 0.5], position=[0.1, 0.1, 0.8, 0.8])
- np.testing.assert_allclose(axtest.bbox.get_points(),
- axref.bbox.get_points())
- def test_set_current_figure_via_subfigure():
- fig1 = plt.figure()
- subfigs = fig1.subfigures(2)
- plt.figure()
- assert plt.gcf() != fig1
- current = plt.figure(subfigs[1])
- assert plt.gcf() == fig1
- assert current == fig1
- def test_set_current_axes_on_subfigure():
- fig = plt.figure()
- subfigs = fig.subfigures(2)
- ax = subfigs[0].subplots(1, squeeze=True)
- subfigs[1].subplots(1, squeeze=True)
- assert plt.gca() != ax
- plt.sca(ax)
- assert plt.gca() == ax
- def test_pylab_integration():
- IPython = pytest.importorskip("IPython")
- mpl.testing.subprocess_run_helper(
- IPython.start_ipython,
- "--pylab",
- "-c",
- ";".join((
- "import matplotlib.pyplot as plt",
- "assert plt._REPL_DISPLAYHOOK == plt._ReplDisplayHook.IPYTHON",
- )),
- timeout=60,
- )
- def test_doc_pyplot_summary():
- """Test that pyplot_summary lists all the plot functions."""
- pyplot_docs = Path(__file__).parent / '../../../doc/api/pyplot_summary.rst'
- if not pyplot_docs.exists():
- pytest.skip("Documentation sources not available")
- def extract_documented_functions(lines):
- """
- Return a list of all the functions that are mentioned in the
- autosummary blocks contained in *lines*.
- An autosummary block looks like this::
- .. autosummary::
- :toctree: _as_gen
- :template: autosummary.rst
- :nosignatures:
- plot
- plot_date
- """
- functions = []
- in_autosummary = False
- for line in lines:
- if not in_autosummary:
- if line.startswith(".. autosummary::"):
- in_autosummary = True
- else:
- if not line or line.startswith(" :"):
- # empty line or autosummary parameter
- continue
- if not line[0].isspace():
- # no more indentation: end of autosummary block
- in_autosummary = False
- continue
- functions.append(line.strip())
- return functions
- lines = pyplot_docs.read_text().split("\n")
- doc_functions = set(extract_documented_functions(lines))
- plot_commands = set(plt._get_pyplot_commands())
- missing = plot_commands.difference(doc_functions)
- if missing:
- raise AssertionError(
- f"The following pyplot functions are not listed in the "
- f"documentation. Please add them to doc/api/pyplot_summary.rst: "
- f"{missing!r}")
- extra = doc_functions.difference(plot_commands)
- if extra:
- raise AssertionError(
- f"The following functions are listed in the pyplot documentation, "
- f"but they do not exist in pyplot. "
- f"Please remove them from doc/api/pyplot_summary.rst: {extra!r}")
- def test_minor_ticks():
- plt.figure()
- plt.plot(np.arange(1, 10))
- tick_pos, tick_labels = plt.xticks(minor=True)
- assert np.all(tick_labels == np.array([], dtype=np.float64))
- assert tick_labels == []
- plt.yticks(ticks=[3.5, 6.5], labels=["a", "b"], minor=True)
- ax = plt.gca()
- tick_pos = ax.get_yticks(minor=True)
- tick_labels = ax.get_yticklabels(minor=True)
- assert np.all(tick_pos == np.array([3.5, 6.5]))
- assert [l.get_text() for l in tick_labels] == ['a', 'b']
- def test_switch_backend_no_close():
- plt.switch_backend('agg')
- fig = plt.figure()
- fig = plt.figure()
- assert len(plt.get_fignums()) == 2
- plt.switch_backend('agg')
- assert len(plt.get_fignums()) == 2
- with pytest.warns(mpl.MatplotlibDeprecationWarning):
- plt.switch_backend('svg')
- assert len(plt.get_fignums()) == 0
- def figure_hook_example(figure):
- figure._test_was_here = True
- def test_figure_hook():
- test_rc = {
- 'figure.hooks': ['matplotlib.tests.test_pyplot:figure_hook_example']
- }
- with mpl.rc_context(test_rc):
- fig = plt.figure()
- assert fig._test_was_here
|