test_subplots.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. import itertools
  2. import numpy
  3. import matplotlib.pyplot as plt
  4. from matplotlib.testing.decorators import image_comparison
  5. import pytest
  6. def check_shared(axs, x_shared, y_shared):
  7. """
  8. x_shared and y_shared are n x n boolean matrices; entry (i, j) indicates
  9. whether the x (or y) axes of subplots i and j should be shared.
  10. """
  11. for (i1, ax1), (i2, ax2), (i3, (name, shared)) in itertools.product(
  12. enumerate(axs),
  13. enumerate(axs),
  14. enumerate(zip("xy", [x_shared, y_shared]))):
  15. if i2 <= i1:
  16. continue
  17. assert \
  18. (getattr(axs[0], "_shared_{}_axes".format(name)).joined(ax1, ax2)
  19. == shared[i1, i2]), \
  20. "axes %i and %i incorrectly %ssharing %s axis" % (
  21. i1, i2, "not " if shared[i1, i2] else "", name)
  22. def check_visible(axs, x_visible, y_visible):
  23. for i, (ax, vx, vy) in enumerate(zip(axs, x_visible, y_visible)):
  24. for l in ax.get_xticklabels() + [ax.get_xaxis().offsetText]:
  25. assert l.get_visible() == vx, \
  26. f"Visibility of x axis #{i} is incorrectly {vx}"
  27. for l in ax.get_yticklabels() + [ax.get_yaxis().offsetText]:
  28. assert l.get_visible() == vy, \
  29. f"Visibility of y axis #{i} is incorrectly {vy}"
  30. def test_shared():
  31. rdim = (4, 4, 2)
  32. share = {
  33. 'all': numpy.ones(rdim[:2], dtype=bool),
  34. 'none': numpy.zeros(rdim[:2], dtype=bool),
  35. 'row': numpy.array([
  36. [False, True, False, False],
  37. [True, False, False, False],
  38. [False, False, False, True],
  39. [False, False, True, False]]),
  40. 'col': numpy.array([
  41. [False, False, True, False],
  42. [False, False, False, True],
  43. [True, False, False, False],
  44. [False, True, False, False]]),
  45. }
  46. visible = {
  47. 'x': {
  48. 'all': [False, False, True, True],
  49. 'col': [False, False, True, True],
  50. 'row': [True] * 4,
  51. 'none': [True] * 4,
  52. False: [True] * 4,
  53. True: [False, False, True, True],
  54. },
  55. 'y': {
  56. 'all': [True, False, True, False],
  57. 'col': [True] * 4,
  58. 'row': [True, False, True, False],
  59. 'none': [True] * 4,
  60. False: [True] * 4,
  61. True: [True, False, True, False],
  62. },
  63. }
  64. share[False] = share['none']
  65. share[True] = share['all']
  66. # test default
  67. f, ((a1, a2), (a3, a4)) = plt.subplots(2, 2)
  68. axs = [a1, a2, a3, a4]
  69. check_shared(axs, share['none'], share['none'])
  70. plt.close(f)
  71. # test all option combinations
  72. ops = [False, True, 'all', 'none', 'row', 'col']
  73. for xo in ops:
  74. for yo in ops:
  75. f, ((a1, a2), (a3, a4)) = plt.subplots(2, 2, sharex=xo, sharey=yo)
  76. axs = [a1, a2, a3, a4]
  77. check_shared(axs, share[xo], share[yo])
  78. check_visible(axs, visible['x'][xo], visible['y'][yo])
  79. plt.close(f)
  80. # test label_outer
  81. f, ((a1, a2), (a3, a4)) = plt.subplots(2, 2, sharex=True, sharey=True)
  82. axs = [a1, a2, a3, a4]
  83. for ax in axs:
  84. ax.label_outer()
  85. check_visible(axs, [False, False, True, True], [True, False, True, False])
  86. def test_label_outer_span():
  87. fig = plt.figure()
  88. gs = fig.add_gridspec(3, 3)
  89. # +---+---+---+
  90. # | 1 | |
  91. # +---+---+---+
  92. # | | | 3 |
  93. # + 2 +---+---+
  94. # | | 4 | |
  95. # +---+---+---+
  96. a1 = fig.add_subplot(gs[0, 0:2])
  97. a2 = fig.add_subplot(gs[1:3, 0])
  98. a3 = fig.add_subplot(gs[1, 2])
  99. a4 = fig.add_subplot(gs[2, 1])
  100. for ax in fig.axes:
  101. ax.label_outer()
  102. check_visible(
  103. fig.axes, [False, True, False, True], [True, True, False, False])
  104. def test_shared_and_moved():
  105. # test if sharey is on, but then tick_left is called that labels don't
  106. # re-appear. Seaborn does this just to be sure yaxis is on left...
  107. f, (a1, a2) = plt.subplots(1, 2, sharey=True)
  108. check_visible([a2], [True], [False])
  109. a2.yaxis.tick_left()
  110. check_visible([a2], [True], [False])
  111. f, (a1, a2) = plt.subplots(2, 1, sharex=True)
  112. check_visible([a1], [False], [True])
  113. a2.xaxis.tick_bottom()
  114. check_visible([a1], [False], [True])
  115. def test_exceptions():
  116. # TODO should this test more options?
  117. with pytest.raises(ValueError):
  118. plt.subplots(2, 2, sharex='blah')
  119. with pytest.raises(ValueError):
  120. plt.subplots(2, 2, sharey='blah')
  121. # We filter warnings in this test which are genuine since
  122. # the point of this test is to ensure that this raises.
  123. with pytest.warns(UserWarning, match='.*sharex argument to subplots'), \
  124. pytest.raises(ValueError):
  125. plt.subplots(2, 2, -1)
  126. with pytest.warns(UserWarning, match='.*sharex argument to subplots'), \
  127. pytest.raises(ValueError):
  128. plt.subplots(2, 2, 0)
  129. with pytest.warns(UserWarning, match='.*sharex argument to subplots'), \
  130. pytest.raises(ValueError):
  131. plt.subplots(2, 2, 5)
  132. @image_comparison(['subplots_offset_text'], remove_text=False)
  133. def test_subplots_offsettext():
  134. x = numpy.arange(0, 1e10, 1e9)
  135. y = numpy.arange(0, 100, 10)+1e4
  136. fig, axs = plt.subplots(2, 2, sharex='col', sharey='all')
  137. axs[0, 0].plot(x, x)
  138. axs[1, 0].plot(x, x)
  139. axs[0, 1].plot(y, x)
  140. axs[1, 1].plot(y, x)
  141. def test_get_gridspec():
  142. # ahem, pretty trivial, but...
  143. fig, ax = plt.subplots()
  144. assert ax.get_subplotspec().get_gridspec() == ax.get_gridspec()
  145. def test_dont_mutate_kwargs():
  146. subplot_kw = {'sharex': 'all'}
  147. gridspec_kw = {'width_ratios': [1, 2]}
  148. fig, ax = plt.subplots(1, 2, subplot_kw=subplot_kw,
  149. gridspec_kw=gridspec_kw)
  150. assert subplot_kw == {'sharex': 'all'}
  151. assert gridspec_kw == {'width_ratios': [1, 2]}