test_series.py 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938
  1. # coding: utf-8
  2. """ Test cases for Series.plot """
  3. from datetime import datetime
  4. from itertools import chain
  5. import numpy as np
  6. from numpy.random import randn
  7. import pytest
  8. import pandas.util._test_decorators as td
  9. import pandas as pd
  10. from pandas import DataFrame, Series, date_range
  11. import pandas._testing as tm
  12. from pandas.tests.plotting.common import TestPlotBase, _check_plot_works
  13. import pandas.plotting as plotting
  14. @td.skip_if_no_mpl
  15. class TestSeriesPlots(TestPlotBase):
  16. def setup_method(self, method):
  17. TestPlotBase.setup_method(self, method)
  18. import matplotlib as mpl
  19. mpl.rcdefaults()
  20. self.ts = tm.makeTimeSeries()
  21. self.ts.name = "ts"
  22. self.series = tm.makeStringSeries()
  23. self.series.name = "series"
  24. self.iseries = tm.makePeriodSeries()
  25. self.iseries.name = "iseries"
  26. @pytest.mark.slow
  27. def test_plot(self):
  28. _check_plot_works(self.ts.plot, label="foo")
  29. _check_plot_works(self.ts.plot, use_index=False)
  30. axes = _check_plot_works(self.ts.plot, rot=0)
  31. self._check_ticks_props(axes, xrot=0)
  32. ax = _check_plot_works(self.ts.plot, style=".", logy=True)
  33. self._check_ax_scales(ax, yaxis="log")
  34. ax = _check_plot_works(self.ts.plot, style=".", logx=True)
  35. self._check_ax_scales(ax, xaxis="log")
  36. ax = _check_plot_works(self.ts.plot, style=".", loglog=True)
  37. self._check_ax_scales(ax, xaxis="log", yaxis="log")
  38. _check_plot_works(self.ts[:10].plot.bar)
  39. _check_plot_works(self.ts.plot.area, stacked=False)
  40. _check_plot_works(self.iseries.plot)
  41. for kind in ["line", "bar", "barh", "kde", "hist", "box"]:
  42. _check_plot_works(self.series[:5].plot, kind=kind)
  43. _check_plot_works(self.series[:10].plot.barh)
  44. ax = _check_plot_works(Series(randn(10)).plot.bar, color="black")
  45. self._check_colors([ax.patches[0]], facecolors=["black"])
  46. # GH 6951
  47. ax = _check_plot_works(self.ts.plot, subplots=True)
  48. self._check_axes_shape(ax, axes_num=1, layout=(1, 1))
  49. ax = _check_plot_works(self.ts.plot, subplots=True, layout=(-1, 1))
  50. self._check_axes_shape(ax, axes_num=1, layout=(1, 1))
  51. ax = _check_plot_works(self.ts.plot, subplots=True, layout=(1, -1))
  52. self._check_axes_shape(ax, axes_num=1, layout=(1, 1))
  53. @pytest.mark.slow
  54. def test_plot_figsize_and_title(self):
  55. # figsize and title
  56. _, ax = self.plt.subplots()
  57. ax = self.series.plot(title="Test", figsize=(16, 8), ax=ax)
  58. self._check_text_labels(ax.title, "Test")
  59. self._check_axes_shape(ax, axes_num=1, layout=(1, 1), figsize=(16, 8))
  60. def test_dont_modify_rcParams(self):
  61. # GH 8242
  62. key = "axes.prop_cycle"
  63. colors = self.plt.rcParams[key]
  64. _, ax = self.plt.subplots()
  65. Series([1, 2, 3]).plot(ax=ax)
  66. assert colors == self.plt.rcParams[key]
  67. def test_ts_line_lim(self):
  68. fig, ax = self.plt.subplots()
  69. ax = self.ts.plot(ax=ax)
  70. xmin, xmax = ax.get_xlim()
  71. lines = ax.get_lines()
  72. assert xmin <= lines[0].get_data(orig=False)[0][0]
  73. assert xmax >= lines[0].get_data(orig=False)[0][-1]
  74. tm.close()
  75. ax = self.ts.plot(secondary_y=True, ax=ax)
  76. xmin, xmax = ax.get_xlim()
  77. lines = ax.get_lines()
  78. assert xmin <= lines[0].get_data(orig=False)[0][0]
  79. assert xmax >= lines[0].get_data(orig=False)[0][-1]
  80. def test_ts_area_lim(self):
  81. _, ax = self.plt.subplots()
  82. ax = self.ts.plot.area(stacked=False, ax=ax)
  83. xmin, xmax = ax.get_xlim()
  84. line = ax.get_lines()[0].get_data(orig=False)[0]
  85. assert xmin <= line[0]
  86. assert xmax >= line[-1]
  87. tm.close()
  88. # GH 7471
  89. _, ax = self.plt.subplots()
  90. ax = self.ts.plot.area(stacked=False, x_compat=True, ax=ax)
  91. xmin, xmax = ax.get_xlim()
  92. line = ax.get_lines()[0].get_data(orig=False)[0]
  93. assert xmin <= line[0]
  94. assert xmax >= line[-1]
  95. tm.close()
  96. tz_ts = self.ts.copy()
  97. tz_ts.index = tz_ts.tz_localize("GMT").tz_convert("CET")
  98. _, ax = self.plt.subplots()
  99. ax = tz_ts.plot.area(stacked=False, x_compat=True, ax=ax)
  100. xmin, xmax = ax.get_xlim()
  101. line = ax.get_lines()[0].get_data(orig=False)[0]
  102. assert xmin <= line[0]
  103. assert xmax >= line[-1]
  104. tm.close()
  105. _, ax = self.plt.subplots()
  106. ax = tz_ts.plot.area(stacked=False, secondary_y=True, ax=ax)
  107. xmin, xmax = ax.get_xlim()
  108. line = ax.get_lines()[0].get_data(orig=False)[0]
  109. assert xmin <= line[0]
  110. assert xmax >= line[-1]
  111. def test_label(self):
  112. s = Series([1, 2])
  113. _, ax = self.plt.subplots()
  114. ax = s.plot(label="LABEL", legend=True, ax=ax)
  115. self._check_legend_labels(ax, labels=["LABEL"])
  116. self.plt.close()
  117. _, ax = self.plt.subplots()
  118. ax = s.plot(legend=True, ax=ax)
  119. self._check_legend_labels(ax, labels=["None"])
  120. self.plt.close()
  121. # get name from index
  122. s.name = "NAME"
  123. _, ax = self.plt.subplots()
  124. ax = s.plot(legend=True, ax=ax)
  125. self._check_legend_labels(ax, labels=["NAME"])
  126. self.plt.close()
  127. # override the default
  128. _, ax = self.plt.subplots()
  129. ax = s.plot(legend=True, label="LABEL", ax=ax)
  130. self._check_legend_labels(ax, labels=["LABEL"])
  131. self.plt.close()
  132. # Add lebel info, but don't draw
  133. _, ax = self.plt.subplots()
  134. ax = s.plot(legend=False, label="LABEL", ax=ax)
  135. assert ax.get_legend() is None # Hasn't been drawn
  136. ax.legend() # draw it
  137. self._check_legend_labels(ax, labels=["LABEL"])
  138. def test_boolean(self):
  139. # GH 23719
  140. s = Series([False, False, True])
  141. _check_plot_works(s.plot, include_bool=True)
  142. msg = "no numeric data to plot"
  143. with pytest.raises(TypeError, match=msg):
  144. _check_plot_works(s.plot)
  145. def test_line_area_nan_series(self):
  146. values = [1, 2, np.nan, 3]
  147. s = Series(values)
  148. ts = Series(values, index=tm.makeDateIndex(k=4))
  149. for d in [s, ts]:
  150. ax = _check_plot_works(d.plot)
  151. masked = ax.lines[0].get_ydata()
  152. # remove nan for comparison purpose
  153. exp = np.array([1, 2, 3], dtype=np.float64)
  154. tm.assert_numpy_array_equal(np.delete(masked.data, 2), exp)
  155. tm.assert_numpy_array_equal(
  156. masked.mask, np.array([False, False, True, False])
  157. )
  158. expected = np.array([1, 2, 0, 3], dtype=np.float64)
  159. ax = _check_plot_works(d.plot, stacked=True)
  160. tm.assert_numpy_array_equal(ax.lines[0].get_ydata(), expected)
  161. ax = _check_plot_works(d.plot.area)
  162. tm.assert_numpy_array_equal(ax.lines[0].get_ydata(), expected)
  163. ax = _check_plot_works(d.plot.area, stacked=False)
  164. tm.assert_numpy_array_equal(ax.lines[0].get_ydata(), expected)
  165. def test_line_use_index_false(self):
  166. s = Series([1, 2, 3], index=["a", "b", "c"])
  167. s.index.name = "The Index"
  168. _, ax = self.plt.subplots()
  169. ax = s.plot(use_index=False, ax=ax)
  170. label = ax.get_xlabel()
  171. assert label == ""
  172. _, ax = self.plt.subplots()
  173. ax2 = s.plot.bar(use_index=False, ax=ax)
  174. label2 = ax2.get_xlabel()
  175. assert label2 == ""
  176. @pytest.mark.slow
  177. def test_bar_log(self):
  178. expected = np.array([1e-1, 1e0, 1e1, 1e2, 1e3, 1e4])
  179. _, ax = self.plt.subplots()
  180. ax = Series([200, 500]).plot.bar(log=True, ax=ax)
  181. tm.assert_numpy_array_equal(ax.yaxis.get_ticklocs(), expected)
  182. tm.close()
  183. _, ax = self.plt.subplots()
  184. ax = Series([200, 500]).plot.barh(log=True, ax=ax)
  185. tm.assert_numpy_array_equal(ax.xaxis.get_ticklocs(), expected)
  186. tm.close()
  187. # GH 9905
  188. expected = np.array([1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1e0, 1e1])
  189. _, ax = self.plt.subplots()
  190. ax = Series([0.1, 0.01, 0.001]).plot(log=True, kind="bar", ax=ax)
  191. ymin = 0.0007943282347242822
  192. ymax = 0.12589254117941673
  193. res = ax.get_ylim()
  194. tm.assert_almost_equal(res[0], ymin)
  195. tm.assert_almost_equal(res[1], ymax)
  196. tm.assert_numpy_array_equal(ax.yaxis.get_ticklocs(), expected)
  197. tm.close()
  198. _, ax = self.plt.subplots()
  199. ax = Series([0.1, 0.01, 0.001]).plot(log=True, kind="barh", ax=ax)
  200. res = ax.get_xlim()
  201. tm.assert_almost_equal(res[0], ymin)
  202. tm.assert_almost_equal(res[1], ymax)
  203. tm.assert_numpy_array_equal(ax.xaxis.get_ticklocs(), expected)
  204. @pytest.mark.slow
  205. def test_bar_ignore_index(self):
  206. df = Series([1, 2, 3, 4], index=["a", "b", "c", "d"])
  207. _, ax = self.plt.subplots()
  208. ax = df.plot.bar(use_index=False, ax=ax)
  209. self._check_text_labels(ax.get_xticklabels(), ["0", "1", "2", "3"])
  210. def test_bar_user_colors(self):
  211. s = Series([1, 2, 3, 4])
  212. ax = s.plot.bar(color=["red", "blue", "blue", "red"])
  213. result = [p.get_facecolor() for p in ax.patches]
  214. expected = [
  215. (1.0, 0.0, 0.0, 1.0),
  216. (0.0, 0.0, 1.0, 1.0),
  217. (0.0, 0.0, 1.0, 1.0),
  218. (1.0, 0.0, 0.0, 1.0),
  219. ]
  220. assert result == expected
  221. def test_rotation(self):
  222. df = DataFrame(randn(5, 5))
  223. # Default rot 0
  224. _, ax = self.plt.subplots()
  225. axes = df.plot(ax=ax)
  226. self._check_ticks_props(axes, xrot=0)
  227. _, ax = self.plt.subplots()
  228. axes = df.plot(rot=30, ax=ax)
  229. self._check_ticks_props(axes, xrot=30)
  230. def test_irregular_datetime(self):
  231. rng = date_range("1/1/2000", "3/1/2000")
  232. rng = rng[[0, 1, 2, 3, 5, 9, 10, 11, 12]]
  233. ser = Series(randn(len(rng)), rng)
  234. _, ax = self.plt.subplots()
  235. ax = ser.plot(ax=ax)
  236. xp = datetime(1999, 1, 1).toordinal()
  237. ax.set_xlim("1/1/1999", "1/1/2001")
  238. assert xp == ax.get_xlim()[0]
  239. def test_unsorted_index_xlim(self):
  240. ser = Series(
  241. [0.0, 1.0, np.nan, 3.0, 4.0, 5.0, 6.0],
  242. index=[1.0, 0.0, 3.0, 2.0, np.nan, 3.0, 2.0],
  243. )
  244. _, ax = self.plt.subplots()
  245. ax = ser.plot(ax=ax)
  246. xmin, xmax = ax.get_xlim()
  247. lines = ax.get_lines()
  248. assert xmin <= np.nanmin(lines[0].get_data(orig=False)[0])
  249. assert xmax >= np.nanmax(lines[0].get_data(orig=False)[0])
  250. @pytest.mark.slow
  251. def test_pie_series(self):
  252. # if sum of values is less than 1.0, pie handle them as rate and draw
  253. # semicircle.
  254. series = Series(
  255. np.random.randint(1, 5), index=["a", "b", "c", "d", "e"], name="YLABEL"
  256. )
  257. ax = _check_plot_works(series.plot.pie)
  258. self._check_text_labels(ax.texts, series.index)
  259. assert ax.get_ylabel() == "YLABEL"
  260. # without wedge labels
  261. ax = _check_plot_works(series.plot.pie, labels=None)
  262. self._check_text_labels(ax.texts, [""] * 5)
  263. # with less colors than elements
  264. color_args = ["r", "g", "b"]
  265. ax = _check_plot_works(series.plot.pie, colors=color_args)
  266. color_expected = ["r", "g", "b", "r", "g"]
  267. self._check_colors(ax.patches, facecolors=color_expected)
  268. # with labels and colors
  269. labels = ["A", "B", "C", "D", "E"]
  270. color_args = ["r", "g", "b", "c", "m"]
  271. ax = _check_plot_works(series.plot.pie, labels=labels, colors=color_args)
  272. self._check_text_labels(ax.texts, labels)
  273. self._check_colors(ax.patches, facecolors=color_args)
  274. # with autopct and fontsize
  275. ax = _check_plot_works(
  276. series.plot.pie, colors=color_args, autopct="%.2f", fontsize=7
  277. )
  278. pcts = [f"{s*100:.2f}" for s in series.values / float(series.sum())]
  279. expected_texts = list(chain.from_iterable(zip(series.index, pcts)))
  280. self._check_text_labels(ax.texts, expected_texts)
  281. for t in ax.texts:
  282. assert t.get_fontsize() == 7
  283. # includes negative value
  284. with pytest.raises(ValueError):
  285. series = Series([1, 2, 0, 4, -1], index=["a", "b", "c", "d", "e"])
  286. series.plot.pie()
  287. # includes nan
  288. series = Series([1, 2, np.nan, 4], index=["a", "b", "c", "d"], name="YLABEL")
  289. ax = _check_plot_works(series.plot.pie)
  290. self._check_text_labels(ax.texts, ["a", "b", "", "d"])
  291. def test_pie_nan(self):
  292. s = Series([1, np.nan, 1, 1])
  293. _, ax = self.plt.subplots()
  294. ax = s.plot.pie(legend=True, ax=ax)
  295. expected = ["0", "", "2", "3"]
  296. result = [x.get_text() for x in ax.texts]
  297. assert result == expected
  298. @pytest.mark.slow
  299. def test_hist_df_kwargs(self):
  300. df = DataFrame(np.random.randn(10, 2))
  301. _, ax = self.plt.subplots()
  302. ax = df.plot.hist(bins=5, ax=ax)
  303. assert len(ax.patches) == 10
  304. @pytest.mark.slow
  305. def test_hist_df_with_nonnumerics(self):
  306. # GH 9853
  307. with tm.RNGContext(1):
  308. df = DataFrame(np.random.randn(10, 4), columns=["A", "B", "C", "D"])
  309. df["E"] = ["x", "y"] * 5
  310. _, ax = self.plt.subplots()
  311. ax = df.plot.hist(bins=5, ax=ax)
  312. assert len(ax.patches) == 20
  313. _, ax = self.plt.subplots()
  314. ax = df.plot.hist(ax=ax) # bins=10
  315. assert len(ax.patches) == 40
  316. @pytest.mark.slow
  317. def test_hist_legacy(self):
  318. _check_plot_works(self.ts.hist)
  319. _check_plot_works(self.ts.hist, grid=False)
  320. _check_plot_works(self.ts.hist, figsize=(8, 10))
  321. # _check_plot_works adds an ax so catch warning. see GH #13188
  322. with tm.assert_produces_warning(UserWarning):
  323. _check_plot_works(self.ts.hist, by=self.ts.index.month)
  324. with tm.assert_produces_warning(UserWarning):
  325. _check_plot_works(self.ts.hist, by=self.ts.index.month, bins=5)
  326. fig, ax = self.plt.subplots(1, 1)
  327. _check_plot_works(self.ts.hist, ax=ax)
  328. _check_plot_works(self.ts.hist, ax=ax, figure=fig)
  329. _check_plot_works(self.ts.hist, figure=fig)
  330. tm.close()
  331. fig, (ax1, ax2) = self.plt.subplots(1, 2)
  332. _check_plot_works(self.ts.hist, figure=fig, ax=ax1)
  333. _check_plot_works(self.ts.hist, figure=fig, ax=ax2)
  334. with pytest.raises(ValueError):
  335. self.ts.hist(by=self.ts.index, figure=fig)
  336. @pytest.mark.slow
  337. def test_hist_bins_legacy(self):
  338. df = DataFrame(np.random.randn(10, 2))
  339. ax = df.hist(bins=2)[0][0]
  340. assert len(ax.patches) == 2
  341. @pytest.mark.slow
  342. def test_hist_layout(self):
  343. df = self.hist_df
  344. with pytest.raises(ValueError):
  345. df.height.hist(layout=(1, 1))
  346. with pytest.raises(ValueError):
  347. df.height.hist(layout=[1, 1])
  348. @pytest.mark.slow
  349. def test_hist_layout_with_by(self):
  350. df = self.hist_df
  351. # _check_plot_works adds an ax so catch warning. see GH #13188
  352. with tm.assert_produces_warning(UserWarning):
  353. axes = _check_plot_works(df.height.hist, by=df.gender, layout=(2, 1))
  354. self._check_axes_shape(axes, axes_num=2, layout=(2, 1))
  355. with tm.assert_produces_warning(UserWarning):
  356. axes = _check_plot_works(df.height.hist, by=df.gender, layout=(3, -1))
  357. self._check_axes_shape(axes, axes_num=2, layout=(3, 1))
  358. with tm.assert_produces_warning(UserWarning):
  359. axes = _check_plot_works(df.height.hist, by=df.category, layout=(4, 1))
  360. self._check_axes_shape(axes, axes_num=4, layout=(4, 1))
  361. with tm.assert_produces_warning(UserWarning):
  362. axes = _check_plot_works(df.height.hist, by=df.category, layout=(2, -1))
  363. self._check_axes_shape(axes, axes_num=4, layout=(2, 2))
  364. with tm.assert_produces_warning(UserWarning):
  365. axes = _check_plot_works(df.height.hist, by=df.category, layout=(3, -1))
  366. self._check_axes_shape(axes, axes_num=4, layout=(3, 2))
  367. with tm.assert_produces_warning(UserWarning):
  368. axes = _check_plot_works(df.height.hist, by=df.category, layout=(-1, 4))
  369. self._check_axes_shape(axes, axes_num=4, layout=(1, 4))
  370. with tm.assert_produces_warning(UserWarning):
  371. axes = _check_plot_works(df.height.hist, by=df.classroom, layout=(2, 2))
  372. self._check_axes_shape(axes, axes_num=3, layout=(2, 2))
  373. axes = df.height.hist(by=df.category, layout=(4, 2), figsize=(12, 7))
  374. self._check_axes_shape(axes, axes_num=4, layout=(4, 2), figsize=(12, 7))
  375. @pytest.mark.slow
  376. def test_hist_no_overlap(self):
  377. from matplotlib.pyplot import subplot, gcf
  378. x = Series(randn(2))
  379. y = Series(randn(2))
  380. subplot(121)
  381. x.hist()
  382. subplot(122)
  383. y.hist()
  384. fig = gcf()
  385. axes = fig.axes
  386. assert len(axes) == 2
  387. @pytest.mark.slow
  388. def test_hist_secondary_legend(self):
  389. # GH 9610
  390. df = DataFrame(np.random.randn(30, 4), columns=list("abcd"))
  391. # primary -> secondary
  392. _, ax = self.plt.subplots()
  393. ax = df["a"].plot.hist(legend=True, ax=ax)
  394. df["b"].plot.hist(ax=ax, legend=True, secondary_y=True)
  395. # both legends are dran on left ax
  396. # left and right axis must be visible
  397. self._check_legend_labels(ax, labels=["a", "b (right)"])
  398. assert ax.get_yaxis().get_visible()
  399. assert ax.right_ax.get_yaxis().get_visible()
  400. tm.close()
  401. # secondary -> secondary
  402. _, ax = self.plt.subplots()
  403. ax = df["a"].plot.hist(legend=True, secondary_y=True, ax=ax)
  404. df["b"].plot.hist(ax=ax, legend=True, secondary_y=True)
  405. # both legends are draw on left ax
  406. # left axis must be invisible, right axis must be visible
  407. self._check_legend_labels(ax.left_ax, labels=["a (right)", "b (right)"])
  408. assert not ax.left_ax.get_yaxis().get_visible()
  409. assert ax.get_yaxis().get_visible()
  410. tm.close()
  411. # secondary -> primary
  412. _, ax = self.plt.subplots()
  413. ax = df["a"].plot.hist(legend=True, secondary_y=True, ax=ax)
  414. # right axes is returned
  415. df["b"].plot.hist(ax=ax, legend=True)
  416. # both legends are draw on left ax
  417. # left and right axis must be visible
  418. self._check_legend_labels(ax.left_ax, labels=["a (right)", "b"])
  419. assert ax.left_ax.get_yaxis().get_visible()
  420. assert ax.get_yaxis().get_visible()
  421. tm.close()
  422. @pytest.mark.slow
  423. def test_df_series_secondary_legend(self):
  424. # GH 9779
  425. df = DataFrame(np.random.randn(30, 3), columns=list("abc"))
  426. s = Series(np.random.randn(30), name="x")
  427. # primary -> secondary (without passing ax)
  428. _, ax = self.plt.subplots()
  429. ax = df.plot(ax=ax)
  430. s.plot(legend=True, secondary_y=True, ax=ax)
  431. # both legends are dran on left ax
  432. # left and right axis must be visible
  433. self._check_legend_labels(ax, labels=["a", "b", "c", "x (right)"])
  434. assert ax.get_yaxis().get_visible()
  435. assert ax.right_ax.get_yaxis().get_visible()
  436. tm.close()
  437. # primary -> secondary (with passing ax)
  438. _, ax = self.plt.subplots()
  439. ax = df.plot(ax=ax)
  440. s.plot(ax=ax, legend=True, secondary_y=True)
  441. # both legends are dran on left ax
  442. # left and right axis must be visible
  443. self._check_legend_labels(ax, labels=["a", "b", "c", "x (right)"])
  444. assert ax.get_yaxis().get_visible()
  445. assert ax.right_ax.get_yaxis().get_visible()
  446. tm.close()
  447. # secondary -> secondary (without passing ax)
  448. _, ax = self.plt.subplots()
  449. ax = df.plot(secondary_y=True, ax=ax)
  450. s.plot(legend=True, secondary_y=True, ax=ax)
  451. # both legends are dran on left ax
  452. # left axis must be invisible and right axis must be visible
  453. expected = ["a (right)", "b (right)", "c (right)", "x (right)"]
  454. self._check_legend_labels(ax.left_ax, labels=expected)
  455. assert not ax.left_ax.get_yaxis().get_visible()
  456. assert ax.get_yaxis().get_visible()
  457. tm.close()
  458. # secondary -> secondary (with passing ax)
  459. _, ax = self.plt.subplots()
  460. ax = df.plot(secondary_y=True, ax=ax)
  461. s.plot(ax=ax, legend=True, secondary_y=True)
  462. # both legends are dran on left ax
  463. # left axis must be invisible and right axis must be visible
  464. expected = ["a (right)", "b (right)", "c (right)", "x (right)"]
  465. self._check_legend_labels(ax.left_ax, expected)
  466. assert not ax.left_ax.get_yaxis().get_visible()
  467. assert ax.get_yaxis().get_visible()
  468. tm.close()
  469. # secondary -> secondary (with passing ax)
  470. _, ax = self.plt.subplots()
  471. ax = df.plot(secondary_y=True, mark_right=False, ax=ax)
  472. s.plot(ax=ax, legend=True, secondary_y=True)
  473. # both legends are dran on left ax
  474. # left axis must be invisible and right axis must be visible
  475. expected = ["a", "b", "c", "x (right)"]
  476. self._check_legend_labels(ax.left_ax, expected)
  477. assert not ax.left_ax.get_yaxis().get_visible()
  478. assert ax.get_yaxis().get_visible()
  479. tm.close()
  480. @pytest.mark.slow
  481. @pytest.mark.parametrize(
  482. "input_logy, expected_scale", [(True, "log"), ("sym", "symlog")]
  483. )
  484. def test_secondary_logy(self, input_logy, expected_scale):
  485. # GH 25545
  486. s1 = Series(np.random.randn(30))
  487. s2 = Series(np.random.randn(30))
  488. # GH 24980
  489. ax1 = s1.plot(logy=input_logy)
  490. ax2 = s2.plot(secondary_y=True, logy=input_logy)
  491. assert ax1.get_yscale() == expected_scale
  492. assert ax2.get_yscale() == expected_scale
  493. @pytest.mark.slow
  494. def test_plot_fails_with_dupe_color_and_style(self):
  495. x = Series(randn(2))
  496. with pytest.raises(ValueError):
  497. _, ax = self.plt.subplots()
  498. x.plot(style="k--", color="k", ax=ax)
  499. @pytest.mark.slow
  500. @td.skip_if_no_scipy
  501. def test_hist_kde(self):
  502. _, ax = self.plt.subplots()
  503. ax = self.ts.plot.hist(logy=True, ax=ax)
  504. self._check_ax_scales(ax, yaxis="log")
  505. xlabels = ax.get_xticklabels()
  506. # ticks are values, thus ticklabels are blank
  507. self._check_text_labels(xlabels, [""] * len(xlabels))
  508. ylabels = ax.get_yticklabels()
  509. self._check_text_labels(ylabels, [""] * len(ylabels))
  510. _check_plot_works(self.ts.plot.kde)
  511. _check_plot_works(self.ts.plot.density)
  512. _, ax = self.plt.subplots()
  513. ax = self.ts.plot.kde(logy=True, ax=ax)
  514. self._check_ax_scales(ax, yaxis="log")
  515. xlabels = ax.get_xticklabels()
  516. self._check_text_labels(xlabels, [""] * len(xlabels))
  517. ylabels = ax.get_yticklabels()
  518. self._check_text_labels(ylabels, [""] * len(ylabels))
  519. @pytest.mark.slow
  520. @td.skip_if_no_scipy
  521. def test_kde_kwargs(self):
  522. sample_points = np.linspace(-100, 100, 20)
  523. _check_plot_works(self.ts.plot.kde, bw_method="scott", ind=20)
  524. _check_plot_works(self.ts.plot.kde, bw_method=None, ind=20)
  525. _check_plot_works(self.ts.plot.kde, bw_method=None, ind=np.int(20))
  526. _check_plot_works(self.ts.plot.kde, bw_method=0.5, ind=sample_points)
  527. _check_plot_works(self.ts.plot.density, bw_method=0.5, ind=sample_points)
  528. _, ax = self.plt.subplots()
  529. ax = self.ts.plot.kde(logy=True, bw_method=0.5, ind=sample_points, ax=ax)
  530. self._check_ax_scales(ax, yaxis="log")
  531. self._check_text_labels(ax.yaxis.get_label(), "Density")
  532. @pytest.mark.slow
  533. @td.skip_if_no_scipy
  534. def test_kde_missing_vals(self):
  535. s = Series(np.random.uniform(size=50))
  536. s[0] = np.nan
  537. axes = _check_plot_works(s.plot.kde)
  538. # gh-14821: check if the values have any missing values
  539. assert any(~np.isnan(axes.lines[0].get_xdata()))
  540. @pytest.mark.slow
  541. def test_hist_kwargs(self):
  542. _, ax = self.plt.subplots()
  543. ax = self.ts.plot.hist(bins=5, ax=ax)
  544. assert len(ax.patches) == 5
  545. self._check_text_labels(ax.yaxis.get_label(), "Frequency")
  546. tm.close()
  547. _, ax = self.plt.subplots()
  548. ax = self.ts.plot.hist(orientation="horizontal", ax=ax)
  549. self._check_text_labels(ax.xaxis.get_label(), "Frequency")
  550. tm.close()
  551. _, ax = self.plt.subplots()
  552. ax = self.ts.plot.hist(align="left", stacked=True, ax=ax)
  553. tm.close()
  554. @pytest.mark.slow
  555. @td.skip_if_no_scipy
  556. def test_hist_kde_color(self):
  557. _, ax = self.plt.subplots()
  558. ax = self.ts.plot.hist(logy=True, bins=10, color="b", ax=ax)
  559. self._check_ax_scales(ax, yaxis="log")
  560. assert len(ax.patches) == 10
  561. self._check_colors(ax.patches, facecolors=["b"] * 10)
  562. _, ax = self.plt.subplots()
  563. ax = self.ts.plot.kde(logy=True, color="r", ax=ax)
  564. self._check_ax_scales(ax, yaxis="log")
  565. lines = ax.get_lines()
  566. assert len(lines) == 1
  567. self._check_colors(lines, ["r"])
  568. @pytest.mark.slow
  569. def test_boxplot_series(self):
  570. _, ax = self.plt.subplots()
  571. ax = self.ts.plot.box(logy=True, ax=ax)
  572. self._check_ax_scales(ax, yaxis="log")
  573. xlabels = ax.get_xticklabels()
  574. self._check_text_labels(xlabels, [self.ts.name])
  575. ylabels = ax.get_yticklabels()
  576. self._check_text_labels(ylabels, [""] * len(ylabels))
  577. @pytest.mark.slow
  578. def test_kind_both_ways(self):
  579. s = Series(range(3))
  580. kinds = (
  581. plotting.PlotAccessor._common_kinds + plotting.PlotAccessor._series_kinds
  582. )
  583. _, ax = self.plt.subplots()
  584. for kind in kinds:
  585. s.plot(kind=kind, ax=ax)
  586. getattr(s.plot, kind)()
  587. @pytest.mark.slow
  588. def test_invalid_plot_data(self):
  589. s = Series(list("abcd"))
  590. _, ax = self.plt.subplots()
  591. for kind in plotting.PlotAccessor._common_kinds:
  592. msg = "no numeric data to plot"
  593. with pytest.raises(TypeError, match=msg):
  594. s.plot(kind=kind, ax=ax)
  595. @pytest.mark.slow
  596. def test_valid_object_plot(self):
  597. s = Series(range(10), dtype=object)
  598. for kind in plotting.PlotAccessor._common_kinds:
  599. _check_plot_works(s.plot, kind=kind)
  600. def test_partially_invalid_plot_data(self):
  601. s = Series(["a", "b", 1.0, 2])
  602. _, ax = self.plt.subplots()
  603. for kind in plotting.PlotAccessor._common_kinds:
  604. msg = "no numeric data to plot"
  605. with pytest.raises(TypeError, match=msg):
  606. s.plot(kind=kind, ax=ax)
  607. def test_invalid_kind(self):
  608. s = Series([1, 2])
  609. with pytest.raises(ValueError):
  610. s.plot(kind="aasdf")
  611. @pytest.mark.slow
  612. def test_dup_datetime_index_plot(self):
  613. dr1 = date_range("1/1/2009", periods=4)
  614. dr2 = date_range("1/2/2009", periods=4)
  615. index = dr1.append(dr2)
  616. values = randn(index.size)
  617. s = Series(values, index=index)
  618. _check_plot_works(s.plot)
  619. @pytest.mark.slow
  620. def test_errorbar_plot(self):
  621. s = Series(np.arange(10), name="x")
  622. s_err = np.random.randn(10)
  623. d_err = DataFrame(randn(10, 2), index=s.index, columns=["x", "y"])
  624. # test line and bar plots
  625. kinds = ["line", "bar"]
  626. for kind in kinds:
  627. ax = _check_plot_works(s.plot, yerr=Series(s_err), kind=kind)
  628. self._check_has_errorbars(ax, xerr=0, yerr=1)
  629. ax = _check_plot_works(s.plot, yerr=s_err, kind=kind)
  630. self._check_has_errorbars(ax, xerr=0, yerr=1)
  631. ax = _check_plot_works(s.plot, yerr=s_err.tolist(), kind=kind)
  632. self._check_has_errorbars(ax, xerr=0, yerr=1)
  633. ax = _check_plot_works(s.plot, yerr=d_err, kind=kind)
  634. self._check_has_errorbars(ax, xerr=0, yerr=1)
  635. ax = _check_plot_works(s.plot, xerr=0.2, yerr=0.2, kind=kind)
  636. self._check_has_errorbars(ax, xerr=1, yerr=1)
  637. ax = _check_plot_works(s.plot, xerr=s_err)
  638. self._check_has_errorbars(ax, xerr=1, yerr=0)
  639. # test time series plotting
  640. ix = date_range("1/1/2000", "1/1/2001", freq="M")
  641. ts = Series(np.arange(12), index=ix, name="x")
  642. ts_err = Series(np.random.randn(12), index=ix)
  643. td_err = DataFrame(randn(12, 2), index=ix, columns=["x", "y"])
  644. ax = _check_plot_works(ts.plot, yerr=ts_err)
  645. self._check_has_errorbars(ax, xerr=0, yerr=1)
  646. ax = _check_plot_works(ts.plot, yerr=td_err)
  647. self._check_has_errorbars(ax, xerr=0, yerr=1)
  648. # check incorrect lengths and types
  649. with pytest.raises(ValueError):
  650. s.plot(yerr=np.arange(11))
  651. s_err = ["zzz"] * 10
  652. with pytest.raises(TypeError):
  653. s.plot(yerr=s_err)
  654. def test_table(self):
  655. _check_plot_works(self.series.plot, table=True)
  656. _check_plot_works(self.series.plot, table=self.series)
  657. @pytest.mark.slow
  658. def test_series_grid_settings(self):
  659. # Make sure plot defaults to rcParams['axes.grid'] setting, GH 9792
  660. self._check_grid_settings(
  661. Series([1, 2, 3]),
  662. plotting.PlotAccessor._series_kinds + plotting.PlotAccessor._common_kinds,
  663. )
  664. @pytest.mark.slow
  665. def test_standard_colors(self):
  666. from pandas.plotting._matplotlib.style import _get_standard_colors
  667. for c in ["r", "red", "green", "#FF0000"]:
  668. result = _get_standard_colors(1, color=c)
  669. assert result == [c]
  670. result = _get_standard_colors(1, color=[c])
  671. assert result == [c]
  672. result = _get_standard_colors(3, color=c)
  673. assert result == [c] * 3
  674. result = _get_standard_colors(3, color=[c])
  675. assert result == [c] * 3
  676. @pytest.mark.slow
  677. def test_standard_colors_all(self):
  678. import matplotlib.colors as colors
  679. from pandas.plotting._matplotlib.style import _get_standard_colors
  680. # multiple colors like mediumaquamarine
  681. for c in colors.cnames:
  682. result = _get_standard_colors(num_colors=1, color=c)
  683. assert result == [c]
  684. result = _get_standard_colors(num_colors=1, color=[c])
  685. assert result == [c]
  686. result = _get_standard_colors(num_colors=3, color=c)
  687. assert result == [c] * 3
  688. result = _get_standard_colors(num_colors=3, color=[c])
  689. assert result == [c] * 3
  690. # single letter colors like k
  691. for c in colors.ColorConverter.colors:
  692. result = _get_standard_colors(num_colors=1, color=c)
  693. assert result == [c]
  694. result = _get_standard_colors(num_colors=1, color=[c])
  695. assert result == [c]
  696. result = _get_standard_colors(num_colors=3, color=c)
  697. assert result == [c] * 3
  698. result = _get_standard_colors(num_colors=3, color=[c])
  699. assert result == [c] * 3
  700. def test_series_plot_color_kwargs(self):
  701. # GH1890
  702. _, ax = self.plt.subplots()
  703. ax = Series(np.arange(12) + 1).plot(color="green", ax=ax)
  704. self._check_colors(ax.get_lines(), linecolors=["green"])
  705. def test_time_series_plot_color_kwargs(self):
  706. # #1890
  707. _, ax = self.plt.subplots()
  708. ax = Series(np.arange(12) + 1, index=date_range("1/1/2000", periods=12)).plot(
  709. color="green", ax=ax
  710. )
  711. self._check_colors(ax.get_lines(), linecolors=["green"])
  712. def test_time_series_plot_color_with_empty_kwargs(self):
  713. import matplotlib as mpl
  714. def_colors = self._unpack_cycler(mpl.rcParams)
  715. index = date_range("1/1/2000", periods=12)
  716. s = Series(np.arange(1, 13), index=index)
  717. ncolors = 3
  718. _, ax = self.plt.subplots()
  719. for i in range(ncolors):
  720. ax = s.plot(ax=ax)
  721. self._check_colors(ax.get_lines(), linecolors=def_colors[:ncolors])
  722. def test_xticklabels(self):
  723. # GH11529
  724. s = Series(np.arange(10), index=[f"P{i:02d}" for i in range(10)])
  725. _, ax = self.plt.subplots()
  726. ax = s.plot(xticks=[0, 3, 5, 9], ax=ax)
  727. exp = [f"P{i:02d}" for i in [0, 3, 5, 9]]
  728. self._check_text_labels(ax.get_xticklabels(), exp)
  729. def test_xtick_barPlot(self):
  730. # GH28172
  731. s = pd.Series(range(10), index=[f"P{i:02d}" for i in range(10)])
  732. ax = s.plot.bar(xticks=range(0, 11, 2))
  733. exp = np.array(list(range(0, 11, 2)))
  734. tm.assert_numpy_array_equal(exp, ax.get_xticks())
  735. def test_custom_business_day_freq(self):
  736. # GH7222
  737. from pandas.tseries.offsets import CustomBusinessDay
  738. s = Series(
  739. range(100, 121),
  740. index=pd.bdate_range(
  741. start="2014-05-01",
  742. end="2014-06-01",
  743. freq=CustomBusinessDay(holidays=["2014-05-26"]),
  744. ),
  745. )
  746. _check_plot_works(s.plot)
  747. @pytest.mark.xfail
  748. def test_plot_accessor_updates_on_inplace(self):
  749. s = Series([1, 2, 3, 4])
  750. _, ax = self.plt.subplots()
  751. ax = s.plot(ax=ax)
  752. before = ax.xaxis.get_ticklocs()
  753. s.drop([0, 1], inplace=True)
  754. _, ax = self.plt.subplots()
  755. after = ax.xaxis.get_ticklocs()
  756. tm.assert_numpy_array_equal(before, after)
  757. @pytest.mark.parametrize("kind", ["line", "area"])
  758. def test_plot_xlim_for_series(self, kind):
  759. # test if xlim is also correctly plotted in Series for line and area
  760. # GH 27686
  761. s = Series([2, 3])
  762. _, ax = self.plt.subplots()
  763. s.plot(kind=kind, ax=ax)
  764. xlims = ax.get_xlim()
  765. assert xlims[0] < 0
  766. assert xlims[1] > 1
  767. def test_plot_no_rows(self):
  768. # GH 27758
  769. df = pd.Series(dtype=int)
  770. assert df.empty
  771. ax = df.plot()
  772. assert len(ax.get_lines()) == 1
  773. line = ax.get_lines()[0]
  774. assert len(line.get_xdata()) == 0
  775. assert len(line.get_ydata()) == 0
  776. def test_plot_no_numeric_data(self):
  777. df = pd.Series(["a", "b", "c"])
  778. with pytest.raises(TypeError):
  779. df.plot()
  780. def test_style_single_ok(self):
  781. s = pd.Series([1, 2])
  782. ax = s.plot(style="s", color="C3")
  783. assert ax.lines[0].get_color() == ["C3"]