test_datetimelike.py 54 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514
  1. """ Test cases for time series specific (freq conversion, etc) """
  2. from datetime import (
  3. date,
  4. datetime,
  5. time,
  6. timedelta,
  7. )
  8. import pickle
  9. import numpy as np
  10. import pytest
  11. from pandas._libs.tslibs import (
  12. BaseOffset,
  13. to_offset,
  14. )
  15. import pandas.util._test_decorators as td
  16. from pandas import (
  17. DataFrame,
  18. Index,
  19. NaT,
  20. Series,
  21. concat,
  22. isna,
  23. to_datetime,
  24. )
  25. import pandas._testing as tm
  26. from pandas.core.indexes.datetimes import (
  27. DatetimeIndex,
  28. bdate_range,
  29. date_range,
  30. )
  31. from pandas.core.indexes.period import (
  32. Period,
  33. PeriodIndex,
  34. period_range,
  35. )
  36. from pandas.core.indexes.timedeltas import timedelta_range
  37. from pandas.tests.plotting.common import TestPlotBase
  38. from pandas.tseries.offsets import WeekOfMonth
  39. @td.skip_if_no_mpl
  40. class TestTSPlot(TestPlotBase):
  41. @pytest.mark.filterwarnings("ignore::UserWarning")
  42. def test_ts_plot_with_tz(self, tz_aware_fixture):
  43. # GH2877, GH17173, GH31205, GH31580
  44. tz = tz_aware_fixture
  45. index = date_range("1/1/2011", periods=2, freq="H", tz=tz)
  46. ts = Series([188.5, 328.25], index=index)
  47. _check_plot_works(ts.plot)
  48. ax = ts.plot()
  49. xdata = list(ax.get_lines())[0].get_xdata()
  50. # Check first and last points' labels are correct
  51. assert (xdata[0].hour, xdata[0].minute) == (0, 0)
  52. assert (xdata[-1].hour, xdata[-1].minute) == (1, 0)
  53. def test_fontsize_set_correctly(self):
  54. # For issue #8765
  55. df = DataFrame(np.random.randn(10, 9), index=range(10))
  56. fig, ax = self.plt.subplots()
  57. df.plot(fontsize=2, ax=ax)
  58. for label in ax.get_xticklabels() + ax.get_yticklabels():
  59. assert label.get_fontsize() == 2
  60. def test_frame_inferred(self):
  61. # inferred freq
  62. idx = date_range("1/1/1987", freq="MS", periods=100)
  63. idx = DatetimeIndex(idx.values, freq=None)
  64. df = DataFrame(np.random.randn(len(idx), 3), index=idx)
  65. _check_plot_works(df.plot)
  66. # axes freq
  67. idx = idx[0:40].union(idx[45:99])
  68. df2 = DataFrame(np.random.randn(len(idx), 3), index=idx)
  69. _check_plot_works(df2.plot)
  70. # N > 1
  71. idx = date_range("2008-1-1 00:15:00", freq="15T", periods=10)
  72. idx = DatetimeIndex(idx.values, freq=None)
  73. df = DataFrame(np.random.randn(len(idx), 3), index=idx)
  74. _check_plot_works(df.plot)
  75. def test_is_error_nozeroindex(self):
  76. # GH11858
  77. i = np.array([1, 2, 3])
  78. a = DataFrame(i, index=i)
  79. _check_plot_works(a.plot, xerr=a)
  80. _check_plot_works(a.plot, yerr=a)
  81. def test_nonnumeric_exclude(self):
  82. idx = date_range("1/1/1987", freq="A", periods=3)
  83. df = DataFrame({"A": ["x", "y", "z"], "B": [1, 2, 3]}, idx)
  84. fig, ax = self.plt.subplots()
  85. df.plot(ax=ax) # it works
  86. assert len(ax.get_lines()) == 1 # B was plotted
  87. self.plt.close(fig)
  88. msg = "no numeric data to plot"
  89. with pytest.raises(TypeError, match=msg):
  90. df["A"].plot()
  91. @pytest.mark.parametrize("freq", ["S", "T", "H", "D", "W", "M", "Q", "A"])
  92. def test_tsplot_period(self, freq):
  93. idx = period_range("12/31/1999", freq=freq, periods=100)
  94. ser = Series(np.random.randn(len(idx)), idx)
  95. _, ax = self.plt.subplots()
  96. _check_plot_works(ser.plot, ax=ax)
  97. @pytest.mark.parametrize(
  98. "freq", ["S", "T", "H", "D", "W", "M", "Q-DEC", "A", "1B30Min"]
  99. )
  100. def test_tsplot_datetime(self, freq):
  101. idx = date_range("12/31/1999", freq=freq, periods=100)
  102. ser = Series(np.random.randn(len(idx)), idx)
  103. _, ax = self.plt.subplots()
  104. _check_plot_works(ser.plot, ax=ax)
  105. def test_tsplot(self):
  106. ts = tm.makeTimeSeries()
  107. _, ax = self.plt.subplots()
  108. ts.plot(style="k", ax=ax)
  109. color = (0.0, 0.0, 0.0, 1)
  110. assert color == ax.get_lines()[0].get_color()
  111. def test_both_style_and_color(self):
  112. ts = tm.makeTimeSeries()
  113. msg = (
  114. "Cannot pass 'style' string with a color symbol and 'color' "
  115. "keyword argument. Please use one or the other or pass 'style' "
  116. "without a color symbol"
  117. )
  118. with pytest.raises(ValueError, match=msg):
  119. ts.plot(style="b-", color="#000099")
  120. s = ts.reset_index(drop=True)
  121. with pytest.raises(ValueError, match=msg):
  122. s.plot(style="b-", color="#000099")
  123. @pytest.mark.parametrize("freq", ["ms", "us"])
  124. def test_high_freq(self, freq):
  125. _, ax = self.plt.subplots()
  126. rng = date_range("1/1/2012", periods=100, freq=freq)
  127. ser = Series(np.random.randn(len(rng)), rng)
  128. _check_plot_works(ser.plot, ax=ax)
  129. def test_get_datevalue(self):
  130. from pandas.plotting._matplotlib.converter import get_datevalue
  131. assert get_datevalue(None, "D") is None
  132. assert get_datevalue(1987, "A") == 1987
  133. assert get_datevalue(Period(1987, "A"), "M") == Period("1987-12", "M").ordinal
  134. assert get_datevalue("1/1/1987", "D") == Period("1987-1-1", "D").ordinal
  135. def test_ts_plot_format_coord(self):
  136. def check_format_of_first_point(ax, expected_string):
  137. first_line = ax.get_lines()[0]
  138. first_x = first_line.get_xdata()[0].ordinal
  139. first_y = first_line.get_ydata()[0]
  140. assert expected_string == ax.format_coord(first_x, first_y)
  141. annual = Series(1, index=date_range("2014-01-01", periods=3, freq="A-DEC"))
  142. _, ax = self.plt.subplots()
  143. annual.plot(ax=ax)
  144. check_format_of_first_point(ax, "t = 2014 y = 1.000000")
  145. # note this is added to the annual plot already in existence, and
  146. # changes its freq field
  147. daily = Series(1, index=date_range("2014-01-01", periods=3, freq="D"))
  148. daily.plot(ax=ax)
  149. check_format_of_first_point(ax, "t = 2014-01-01 y = 1.000000")
  150. tm.close()
  151. @pytest.mark.parametrize("freq", ["S", "T", "H", "D", "W", "M", "Q", "A"])
  152. def test_line_plot_period_series(self, freq):
  153. idx = period_range("12/31/1999", freq=freq, periods=100)
  154. ser = Series(np.random.randn(len(idx)), idx)
  155. _check_plot_works(ser.plot, ser.index.freq)
  156. @pytest.mark.parametrize(
  157. "frqncy", ["1S", "3S", "5T", "7H", "4D", "8W", "11M", "3A"]
  158. )
  159. def test_line_plot_period_mlt_series(self, frqncy):
  160. # test period index line plot for series with multiples (`mlt`) of the
  161. # frequency (`frqncy`) rule code. tests resolution of issue #14763
  162. idx = period_range("12/31/1999", freq=frqncy, periods=100)
  163. s = Series(np.random.randn(len(idx)), idx)
  164. _check_plot_works(s.plot, s.index.freq.rule_code)
  165. @pytest.mark.parametrize(
  166. "freq", ["S", "T", "H", "D", "W", "M", "Q-DEC", "A", "1B30Min"]
  167. )
  168. def test_line_plot_datetime_series(self, freq):
  169. idx = date_range("12/31/1999", freq=freq, periods=100)
  170. ser = Series(np.random.randn(len(idx)), idx)
  171. _check_plot_works(ser.plot, ser.index.freq.rule_code)
  172. @pytest.mark.parametrize("freq", ["S", "T", "H", "D", "W", "M", "Q", "A"])
  173. def test_line_plot_period_frame(self, freq):
  174. idx = date_range("12/31/1999", freq=freq, periods=100)
  175. df = DataFrame(np.random.randn(len(idx), 3), index=idx, columns=["A", "B", "C"])
  176. _check_plot_works(df.plot, df.index.freq)
  177. @pytest.mark.parametrize(
  178. "frqncy", ["1S", "3S", "5T", "7H", "4D", "8W", "11M", "3A"]
  179. )
  180. def test_line_plot_period_mlt_frame(self, frqncy):
  181. # test period index line plot for DataFrames with multiples (`mlt`)
  182. # of the frequency (`frqncy`) rule code. tests resolution of issue
  183. # #14763
  184. idx = period_range("12/31/1999", freq=frqncy, periods=100)
  185. df = DataFrame(np.random.randn(len(idx), 3), index=idx, columns=["A", "B", "C"])
  186. freq = df.index.asfreq(df.index.freq.rule_code).freq
  187. _check_plot_works(df.plot, freq)
  188. @pytest.mark.parametrize(
  189. "freq", ["S", "T", "H", "D", "W", "M", "Q-DEC", "A", "1B30Min"]
  190. )
  191. def test_line_plot_datetime_frame(self, freq):
  192. idx = date_range("12/31/1999", freq=freq, periods=100)
  193. df = DataFrame(np.random.randn(len(idx), 3), index=idx, columns=["A", "B", "C"])
  194. freq = df.index.to_period(df.index.freq.rule_code).freq
  195. _check_plot_works(df.plot, freq)
  196. @pytest.mark.parametrize(
  197. "freq", ["S", "T", "H", "D", "W", "M", "Q-DEC", "A", "1B30Min"]
  198. )
  199. def test_line_plot_inferred_freq(self, freq):
  200. idx = date_range("12/31/1999", freq=freq, periods=100)
  201. ser = Series(np.random.randn(len(idx)), idx)
  202. ser = Series(ser.values, Index(np.asarray(ser.index)))
  203. _check_plot_works(ser.plot, ser.index.inferred_freq)
  204. ser = ser[[0, 3, 5, 6]]
  205. _check_plot_works(ser.plot)
  206. def test_fake_inferred_business(self):
  207. _, ax = self.plt.subplots()
  208. rng = date_range("2001-1-1", "2001-1-10")
  209. ts = Series(range(len(rng)), index=rng)
  210. ts = concat([ts[:3], ts[5:]])
  211. ts.plot(ax=ax)
  212. assert not hasattr(ax, "freq")
  213. def test_plot_offset_freq(self):
  214. ser = tm.makeTimeSeries()
  215. _check_plot_works(ser.plot)
  216. dr = date_range(ser.index[0], freq="BQS", periods=10)
  217. ser = Series(np.random.randn(len(dr)), index=dr)
  218. _check_plot_works(ser.plot)
  219. def test_plot_multiple_inferred_freq(self):
  220. dr = Index([datetime(2000, 1, 1), datetime(2000, 1, 6), datetime(2000, 1, 11)])
  221. ser = Series(np.random.randn(len(dr)), index=dr)
  222. _check_plot_works(ser.plot)
  223. @pytest.mark.xfail(reason="Api changed in 3.6.0")
  224. def test_uhf(self):
  225. import pandas.plotting._matplotlib.converter as conv
  226. idx = date_range("2012-6-22 21:59:51.960928", freq="L", periods=500)
  227. df = DataFrame(np.random.randn(len(idx), 2), index=idx)
  228. _, ax = self.plt.subplots()
  229. df.plot(ax=ax)
  230. axis = ax.get_xaxis()
  231. tlocs = axis.get_ticklocs()
  232. tlabels = axis.get_ticklabels()
  233. for loc, label in zip(tlocs, tlabels):
  234. xp = conv._from_ordinal(loc).strftime("%H:%M:%S.%f")
  235. rs = str(label.get_text())
  236. if len(rs):
  237. assert xp == rs
  238. def test_irreg_hf(self):
  239. idx = date_range("2012-6-22 21:59:51", freq="S", periods=100)
  240. df = DataFrame(np.random.randn(len(idx), 2), index=idx)
  241. irreg = df.iloc[[0, 1, 3, 4]]
  242. _, ax = self.plt.subplots()
  243. irreg.plot(ax=ax)
  244. diffs = Series(ax.get_lines()[0].get_xydata()[:, 0]).diff()
  245. sec = 1.0 / 24 / 60 / 60
  246. assert (np.fabs(diffs[1:] - [sec, sec * 2, sec]) < 1e-8).all()
  247. _, ax = self.plt.subplots()
  248. df2 = df.copy()
  249. df2.index = df.index.astype(object)
  250. df2.plot(ax=ax)
  251. diffs = Series(ax.get_lines()[0].get_xydata()[:, 0]).diff()
  252. assert (np.fabs(diffs[1:] - sec) < 1e-8).all()
  253. def test_irregular_datetime64_repr_bug(self):
  254. ser = tm.makeTimeSeries()
  255. ser = ser[[0, 1, 2, 7]]
  256. _, ax = self.plt.subplots()
  257. ret = ser.plot(ax=ax)
  258. assert ret is not None
  259. for rs, xp in zip(ax.get_lines()[0].get_xdata(), ser.index):
  260. assert rs == xp
  261. def test_business_freq(self):
  262. bts = tm.makePeriodSeries()
  263. _, ax = self.plt.subplots()
  264. bts.plot(ax=ax)
  265. assert ax.get_lines()[0].get_xydata()[0, 0] == bts.index[0].ordinal
  266. idx = ax.get_lines()[0].get_xdata()
  267. assert PeriodIndex(data=idx).freqstr == "B"
  268. def test_business_freq_convert(self):
  269. bts = tm.makeTimeSeries(300).asfreq("BM")
  270. ts = bts.to_period("M")
  271. _, ax = self.plt.subplots()
  272. bts.plot(ax=ax)
  273. assert ax.get_lines()[0].get_xydata()[0, 0] == ts.index[0].ordinal
  274. idx = ax.get_lines()[0].get_xdata()
  275. assert PeriodIndex(data=idx).freqstr == "M"
  276. def test_freq_with_no_period_alias(self):
  277. # GH34487
  278. freq = WeekOfMonth()
  279. bts = tm.makeTimeSeries(5).asfreq(freq)
  280. _, ax = self.plt.subplots()
  281. bts.plot(ax=ax)
  282. idx = ax.get_lines()[0].get_xdata()
  283. msg = "freq not specified and cannot be inferred"
  284. with pytest.raises(ValueError, match=msg):
  285. PeriodIndex(data=idx)
  286. def test_nonzero_base(self):
  287. # GH2571
  288. idx = date_range("2012-12-20", periods=24, freq="H") + timedelta(minutes=30)
  289. df = DataFrame(np.arange(24), index=idx)
  290. _, ax = self.plt.subplots()
  291. df.plot(ax=ax)
  292. rs = ax.get_lines()[0].get_xdata()
  293. assert not Index(rs).is_normalized
  294. def test_dataframe(self):
  295. bts = DataFrame({"a": tm.makeTimeSeries()})
  296. _, ax = self.plt.subplots()
  297. bts.plot(ax=ax)
  298. idx = ax.get_lines()[0].get_xdata()
  299. tm.assert_index_equal(bts.index.to_period(), PeriodIndex(idx))
  300. def test_axis_limits(self):
  301. def _test(ax):
  302. xlim = ax.get_xlim()
  303. ax.set_xlim(xlim[0] - 5, xlim[1] + 10)
  304. result = ax.get_xlim()
  305. assert result[0] == xlim[0] - 5
  306. assert result[1] == xlim[1] + 10
  307. # string
  308. expected = (Period("1/1/2000", ax.freq), Period("4/1/2000", ax.freq))
  309. ax.set_xlim("1/1/2000", "4/1/2000")
  310. result = ax.get_xlim()
  311. assert int(result[0]) == expected[0].ordinal
  312. assert int(result[1]) == expected[1].ordinal
  313. # datetime
  314. expected = (Period("1/1/2000", ax.freq), Period("4/1/2000", ax.freq))
  315. ax.set_xlim(datetime(2000, 1, 1), datetime(2000, 4, 1))
  316. result = ax.get_xlim()
  317. assert int(result[0]) == expected[0].ordinal
  318. assert int(result[1]) == expected[1].ordinal
  319. fig = ax.get_figure()
  320. self.plt.close(fig)
  321. ser = tm.makeTimeSeries()
  322. _, ax = self.plt.subplots()
  323. ser.plot(ax=ax)
  324. _test(ax)
  325. _, ax = self.plt.subplots()
  326. df = DataFrame({"a": ser, "b": ser + 1})
  327. df.plot(ax=ax)
  328. _test(ax)
  329. df = DataFrame({"a": ser, "b": ser + 1})
  330. axes = df.plot(subplots=True)
  331. for ax in axes:
  332. _test(ax)
  333. def test_get_finder(self):
  334. import pandas.plotting._matplotlib.converter as conv
  335. assert conv.get_finder(to_offset("B")) == conv._daily_finder
  336. assert conv.get_finder(to_offset("D")) == conv._daily_finder
  337. assert conv.get_finder(to_offset("M")) == conv._monthly_finder
  338. assert conv.get_finder(to_offset("Q")) == conv._quarterly_finder
  339. assert conv.get_finder(to_offset("A")) == conv._annual_finder
  340. assert conv.get_finder(to_offset("W")) == conv._daily_finder
  341. def test_finder_daily(self):
  342. day_lst = [10, 40, 252, 400, 950, 2750, 10000]
  343. xpl1 = xpl2 = [Period("1999-1-1", freq="B").ordinal] * len(day_lst)
  344. rs1 = []
  345. rs2 = []
  346. for n in day_lst:
  347. rng = bdate_range("1999-1-1", periods=n)
  348. ser = Series(np.random.randn(len(rng)), rng)
  349. _, ax = self.plt.subplots()
  350. ser.plot(ax=ax)
  351. xaxis = ax.get_xaxis()
  352. rs1.append(xaxis.get_majorticklocs()[0])
  353. vmin, vmax = ax.get_xlim()
  354. ax.set_xlim(vmin + 0.9, vmax)
  355. rs2.append(xaxis.get_majorticklocs()[0])
  356. self.plt.close(ax.get_figure())
  357. assert rs1 == xpl1
  358. assert rs2 == xpl2
  359. def test_finder_quarterly(self):
  360. yrs = [3.5, 11]
  361. xpl1 = xpl2 = [Period("1988Q1").ordinal] * len(yrs)
  362. rs1 = []
  363. rs2 = []
  364. for n in yrs:
  365. rng = period_range("1987Q2", periods=int(n * 4), freq="Q")
  366. ser = Series(np.random.randn(len(rng)), rng)
  367. _, ax = self.plt.subplots()
  368. ser.plot(ax=ax)
  369. xaxis = ax.get_xaxis()
  370. rs1.append(xaxis.get_majorticklocs()[0])
  371. (vmin, vmax) = ax.get_xlim()
  372. ax.set_xlim(vmin + 0.9, vmax)
  373. rs2.append(xaxis.get_majorticklocs()[0])
  374. self.plt.close(ax.get_figure())
  375. assert rs1 == xpl1
  376. assert rs2 == xpl2
  377. def test_finder_monthly(self):
  378. yrs = [1.15, 2.5, 4, 11]
  379. xpl1 = xpl2 = [Period("Jan 1988").ordinal] * len(yrs)
  380. rs1 = []
  381. rs2 = []
  382. for n in yrs:
  383. rng = period_range("1987Q2", periods=int(n * 12), freq="M")
  384. ser = Series(np.random.randn(len(rng)), rng)
  385. _, ax = self.plt.subplots()
  386. ser.plot(ax=ax)
  387. xaxis = ax.get_xaxis()
  388. rs1.append(xaxis.get_majorticklocs()[0])
  389. vmin, vmax = ax.get_xlim()
  390. ax.set_xlim(vmin + 0.9, vmax)
  391. rs2.append(xaxis.get_majorticklocs()[0])
  392. self.plt.close(ax.get_figure())
  393. assert rs1 == xpl1
  394. assert rs2 == xpl2
  395. def test_finder_monthly_long(self):
  396. rng = period_range("1988Q1", periods=24 * 12, freq="M")
  397. ser = Series(np.random.randn(len(rng)), rng)
  398. _, ax = self.plt.subplots()
  399. ser.plot(ax=ax)
  400. xaxis = ax.get_xaxis()
  401. rs = xaxis.get_majorticklocs()[0]
  402. xp = Period("1989Q1", "M").ordinal
  403. assert rs == xp
  404. def test_finder_annual(self):
  405. xp = [1987, 1988, 1990, 1990, 1995, 2020, 2070, 2170]
  406. xp = [Period(x, freq="A").ordinal for x in xp]
  407. rs = []
  408. for nyears in [5, 10, 19, 49, 99, 199, 599, 1001]:
  409. rng = period_range("1987", periods=nyears, freq="A")
  410. ser = Series(np.random.randn(len(rng)), rng)
  411. _, ax = self.plt.subplots()
  412. ser.plot(ax=ax)
  413. xaxis = ax.get_xaxis()
  414. rs.append(xaxis.get_majorticklocs()[0])
  415. self.plt.close(ax.get_figure())
  416. assert rs == xp
  417. @pytest.mark.slow
  418. def test_finder_minutely(self):
  419. nminutes = 50 * 24 * 60
  420. rng = date_range("1/1/1999", freq="Min", periods=nminutes)
  421. ser = Series(np.random.randn(len(rng)), rng)
  422. _, ax = self.plt.subplots()
  423. ser.plot(ax=ax)
  424. xaxis = ax.get_xaxis()
  425. rs = xaxis.get_majorticklocs()[0]
  426. xp = Period("1/1/1999", freq="Min").ordinal
  427. assert rs == xp
  428. def test_finder_hourly(self):
  429. nhours = 23
  430. rng = date_range("1/1/1999", freq="H", periods=nhours)
  431. ser = Series(np.random.randn(len(rng)), rng)
  432. _, ax = self.plt.subplots()
  433. ser.plot(ax=ax)
  434. xaxis = ax.get_xaxis()
  435. rs = xaxis.get_majorticklocs()[0]
  436. xp = Period("1/1/1999", freq="H").ordinal
  437. assert rs == xp
  438. def test_gaps(self):
  439. ts = tm.makeTimeSeries()
  440. ts.iloc[5:25] = np.nan
  441. _, ax = self.plt.subplots()
  442. ts.plot(ax=ax)
  443. lines = ax.get_lines()
  444. assert len(lines) == 1
  445. line = lines[0]
  446. data = line.get_xydata()
  447. data = np.ma.MaskedArray(data, mask=isna(data), fill_value=np.nan)
  448. assert isinstance(data, np.ma.core.MaskedArray)
  449. mask = data.mask
  450. assert mask[5:25, 1].all()
  451. self.plt.close(ax.get_figure())
  452. # irregular
  453. ts = tm.makeTimeSeries()
  454. ts = ts[[0, 1, 2, 5, 7, 9, 12, 15, 20]]
  455. ts.iloc[2:5] = np.nan
  456. _, ax = self.plt.subplots()
  457. ax = ts.plot(ax=ax)
  458. lines = ax.get_lines()
  459. assert len(lines) == 1
  460. line = lines[0]
  461. data = line.get_xydata()
  462. data = np.ma.MaskedArray(data, mask=isna(data), fill_value=np.nan)
  463. assert isinstance(data, np.ma.core.MaskedArray)
  464. mask = data.mask
  465. assert mask[2:5, 1].all()
  466. self.plt.close(ax.get_figure())
  467. # non-ts
  468. idx = [0, 1, 2, 5, 7, 9, 12, 15, 20]
  469. ser = Series(np.random.randn(len(idx)), idx)
  470. ser.iloc[2:5] = np.nan
  471. _, ax = self.plt.subplots()
  472. ser.plot(ax=ax)
  473. lines = ax.get_lines()
  474. assert len(lines) == 1
  475. line = lines[0]
  476. data = line.get_xydata()
  477. data = np.ma.MaskedArray(data, mask=isna(data), fill_value=np.nan)
  478. assert isinstance(data, np.ma.core.MaskedArray)
  479. mask = data.mask
  480. assert mask[2:5, 1].all()
  481. def test_gap_upsample(self):
  482. low = tm.makeTimeSeries()
  483. low.iloc[5:25] = np.nan
  484. _, ax = self.plt.subplots()
  485. low.plot(ax=ax)
  486. idxh = date_range(low.index[0], low.index[-1], freq="12h")
  487. s = Series(np.random.randn(len(idxh)), idxh)
  488. s.plot(secondary_y=True)
  489. lines = ax.get_lines()
  490. assert len(lines) == 1
  491. assert len(ax.right_ax.get_lines()) == 1
  492. line = lines[0]
  493. data = line.get_xydata()
  494. data = np.ma.MaskedArray(data, mask=isna(data), fill_value=np.nan)
  495. assert isinstance(data, np.ma.core.MaskedArray)
  496. mask = data.mask
  497. assert mask[5:25, 1].all()
  498. def test_secondary_y(self):
  499. ser = Series(np.random.randn(10))
  500. ser2 = Series(np.random.randn(10))
  501. fig, _ = self.plt.subplots()
  502. ax = ser.plot(secondary_y=True)
  503. assert hasattr(ax, "left_ax")
  504. assert not hasattr(ax, "right_ax")
  505. axes = fig.get_axes()
  506. line = ax.get_lines()[0]
  507. xp = Series(line.get_ydata(), line.get_xdata())
  508. tm.assert_series_equal(ser, xp)
  509. assert ax.get_yaxis().get_ticks_position() == "right"
  510. assert not axes[0].get_yaxis().get_visible()
  511. self.plt.close(fig)
  512. _, ax2 = self.plt.subplots()
  513. ser2.plot(ax=ax2)
  514. assert ax2.get_yaxis().get_ticks_position() == "left"
  515. self.plt.close(ax2.get_figure())
  516. ax = ser2.plot()
  517. ax2 = ser.plot(secondary_y=True)
  518. assert ax.get_yaxis().get_visible()
  519. assert not hasattr(ax, "left_ax")
  520. assert hasattr(ax, "right_ax")
  521. assert hasattr(ax2, "left_ax")
  522. assert not hasattr(ax2, "right_ax")
  523. def test_secondary_y_ts(self):
  524. idx = date_range("1/1/2000", periods=10)
  525. ser = Series(np.random.randn(10), idx)
  526. ser2 = Series(np.random.randn(10), idx)
  527. fig, _ = self.plt.subplots()
  528. ax = ser.plot(secondary_y=True)
  529. assert hasattr(ax, "left_ax")
  530. assert not hasattr(ax, "right_ax")
  531. axes = fig.get_axes()
  532. line = ax.get_lines()[0]
  533. xp = Series(line.get_ydata(), line.get_xdata()).to_timestamp()
  534. tm.assert_series_equal(ser, xp)
  535. assert ax.get_yaxis().get_ticks_position() == "right"
  536. assert not axes[0].get_yaxis().get_visible()
  537. self.plt.close(fig)
  538. _, ax2 = self.plt.subplots()
  539. ser2.plot(ax=ax2)
  540. assert ax2.get_yaxis().get_ticks_position() == "left"
  541. self.plt.close(ax2.get_figure())
  542. ax = ser2.plot()
  543. ax2 = ser.plot(secondary_y=True)
  544. assert ax.get_yaxis().get_visible()
  545. @td.skip_if_no_scipy
  546. def test_secondary_kde(self):
  547. ser = Series(np.random.randn(10))
  548. fig, ax = self.plt.subplots()
  549. ax = ser.plot(secondary_y=True, kind="density", ax=ax)
  550. assert hasattr(ax, "left_ax")
  551. assert not hasattr(ax, "right_ax")
  552. axes = fig.get_axes()
  553. assert axes[1].get_yaxis().get_ticks_position() == "right"
  554. def test_secondary_bar(self):
  555. ser = Series(np.random.randn(10))
  556. fig, ax = self.plt.subplots()
  557. ser.plot(secondary_y=True, kind="bar", ax=ax)
  558. axes = fig.get_axes()
  559. assert axes[1].get_yaxis().get_ticks_position() == "right"
  560. def test_secondary_frame(self):
  561. df = DataFrame(np.random.randn(5, 3), columns=["a", "b", "c"])
  562. axes = df.plot(secondary_y=["a", "c"], subplots=True)
  563. assert axes[0].get_yaxis().get_ticks_position() == "right"
  564. assert axes[1].get_yaxis().get_ticks_position() == "left"
  565. assert axes[2].get_yaxis().get_ticks_position() == "right"
  566. def test_secondary_bar_frame(self):
  567. df = DataFrame(np.random.randn(5, 3), columns=["a", "b", "c"])
  568. axes = df.plot(kind="bar", secondary_y=["a", "c"], subplots=True)
  569. assert axes[0].get_yaxis().get_ticks_position() == "right"
  570. assert axes[1].get_yaxis().get_ticks_position() == "left"
  571. assert axes[2].get_yaxis().get_ticks_position() == "right"
  572. def test_mixed_freq_regular_first(self):
  573. # TODO
  574. s1 = tm.makeTimeSeries()
  575. s2 = s1[[0, 5, 10, 11, 12, 13, 14, 15]]
  576. # it works!
  577. _, ax = self.plt.subplots()
  578. s1.plot(ax=ax)
  579. ax2 = s2.plot(style="g", ax=ax)
  580. lines = ax2.get_lines()
  581. idx1 = PeriodIndex(lines[0].get_xdata())
  582. idx2 = PeriodIndex(lines[1].get_xdata())
  583. tm.assert_index_equal(idx1, s1.index.to_period("B"))
  584. tm.assert_index_equal(idx2, s2.index.to_period("B"))
  585. left, right = ax2.get_xlim()
  586. pidx = s1.index.to_period()
  587. assert left <= pidx[0].ordinal
  588. assert right >= pidx[-1].ordinal
  589. def test_mixed_freq_irregular_first(self):
  590. s1 = tm.makeTimeSeries()
  591. s2 = s1[[0, 5, 10, 11, 12, 13, 14, 15]]
  592. _, ax = self.plt.subplots()
  593. s2.plot(style="g", ax=ax)
  594. s1.plot(ax=ax)
  595. assert not hasattr(ax, "freq")
  596. lines = ax.get_lines()
  597. x1 = lines[0].get_xdata()
  598. tm.assert_numpy_array_equal(x1, s2.index.astype(object).values)
  599. x2 = lines[1].get_xdata()
  600. tm.assert_numpy_array_equal(x2, s1.index.astype(object).values)
  601. def test_mixed_freq_regular_first_df(self):
  602. # GH 9852
  603. s1 = tm.makeTimeSeries().to_frame()
  604. s2 = s1.iloc[[0, 5, 10, 11, 12, 13, 14, 15], :]
  605. _, ax = self.plt.subplots()
  606. s1.plot(ax=ax)
  607. ax2 = s2.plot(style="g", ax=ax)
  608. lines = ax2.get_lines()
  609. idx1 = PeriodIndex(lines[0].get_xdata())
  610. idx2 = PeriodIndex(lines[1].get_xdata())
  611. assert idx1.equals(s1.index.to_period("B"))
  612. assert idx2.equals(s2.index.to_period("B"))
  613. left, right = ax2.get_xlim()
  614. pidx = s1.index.to_period()
  615. assert left <= pidx[0].ordinal
  616. assert right >= pidx[-1].ordinal
  617. def test_mixed_freq_irregular_first_df(self):
  618. # GH 9852
  619. s1 = tm.makeTimeSeries().to_frame()
  620. s2 = s1.iloc[[0, 5, 10, 11, 12, 13, 14, 15], :]
  621. _, ax = self.plt.subplots()
  622. s2.plot(style="g", ax=ax)
  623. s1.plot(ax=ax)
  624. assert not hasattr(ax, "freq")
  625. lines = ax.get_lines()
  626. x1 = lines[0].get_xdata()
  627. tm.assert_numpy_array_equal(x1, s2.index.astype(object).values)
  628. x2 = lines[1].get_xdata()
  629. tm.assert_numpy_array_equal(x2, s1.index.astype(object).values)
  630. def test_mixed_freq_hf_first(self):
  631. idxh = date_range("1/1/1999", periods=365, freq="D")
  632. idxl = date_range("1/1/1999", periods=12, freq="M")
  633. high = Series(np.random.randn(len(idxh)), idxh)
  634. low = Series(np.random.randn(len(idxl)), idxl)
  635. _, ax = self.plt.subplots()
  636. high.plot(ax=ax)
  637. low.plot(ax=ax)
  638. for line in ax.get_lines():
  639. assert PeriodIndex(data=line.get_xdata()).freq == "D"
  640. def test_mixed_freq_alignment(self):
  641. ts_ind = date_range("2012-01-01 13:00", "2012-01-02", freq="H")
  642. ts_data = np.random.randn(12)
  643. ts = Series(ts_data, index=ts_ind)
  644. ts2 = ts.asfreq("T").interpolate()
  645. _, ax = self.plt.subplots()
  646. ax = ts.plot(ax=ax)
  647. ts2.plot(style="r", ax=ax)
  648. assert ax.lines[0].get_xdata()[0] == ax.lines[1].get_xdata()[0]
  649. def test_mixed_freq_lf_first(self):
  650. idxh = date_range("1/1/1999", periods=365, freq="D")
  651. idxl = date_range("1/1/1999", periods=12, freq="M")
  652. high = Series(np.random.randn(len(idxh)), idxh)
  653. low = Series(np.random.randn(len(idxl)), idxl)
  654. _, ax = self.plt.subplots()
  655. low.plot(legend=True, ax=ax)
  656. high.plot(legend=True, ax=ax)
  657. for line in ax.get_lines():
  658. assert PeriodIndex(data=line.get_xdata()).freq == "D"
  659. leg = ax.get_legend()
  660. assert len(leg.texts) == 2
  661. self.plt.close(ax.get_figure())
  662. idxh = date_range("1/1/1999", periods=240, freq="T")
  663. idxl = date_range("1/1/1999", periods=4, freq="H")
  664. high = Series(np.random.randn(len(idxh)), idxh)
  665. low = Series(np.random.randn(len(idxl)), idxl)
  666. _, ax = self.plt.subplots()
  667. low.plot(ax=ax)
  668. high.plot(ax=ax)
  669. for line in ax.get_lines():
  670. assert PeriodIndex(data=line.get_xdata()).freq == "T"
  671. def test_mixed_freq_irreg_period(self):
  672. ts = tm.makeTimeSeries()
  673. irreg = ts[[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 16, 17, 18, 29]]
  674. rng = period_range("1/3/2000", periods=30, freq="B")
  675. ps = Series(np.random.randn(len(rng)), rng)
  676. _, ax = self.plt.subplots()
  677. irreg.plot(ax=ax)
  678. ps.plot(ax=ax)
  679. def test_mixed_freq_shared_ax(self):
  680. # GH13341, using sharex=True
  681. idx1 = date_range("2015-01-01", periods=3, freq="M")
  682. idx2 = idx1[:1].union(idx1[2:])
  683. s1 = Series(range(len(idx1)), idx1)
  684. s2 = Series(range(len(idx2)), idx2)
  685. fig, (ax1, ax2) = self.plt.subplots(nrows=2, sharex=True)
  686. s1.plot(ax=ax1)
  687. s2.plot(ax=ax2)
  688. assert ax1.freq == "M"
  689. assert ax2.freq == "M"
  690. assert ax1.lines[0].get_xydata()[0, 0] == ax2.lines[0].get_xydata()[0, 0]
  691. # using twinx
  692. fig, ax1 = self.plt.subplots()
  693. ax2 = ax1.twinx()
  694. s1.plot(ax=ax1)
  695. s2.plot(ax=ax2)
  696. assert ax1.lines[0].get_xydata()[0, 0] == ax2.lines[0].get_xydata()[0, 0]
  697. # TODO (GH14330, GH14322)
  698. # plotting the irregular first does not yet work
  699. # fig, ax1 = plt.subplots()
  700. # ax2 = ax1.twinx()
  701. # s2.plot(ax=ax1)
  702. # s1.plot(ax=ax2)
  703. # assert (ax1.lines[0].get_xydata()[0, 0] ==
  704. # ax2.lines[0].get_xydata()[0, 0])
  705. def test_nat_handling(self):
  706. _, ax = self.plt.subplots()
  707. dti = DatetimeIndex(["2015-01-01", NaT, "2015-01-03"])
  708. s = Series(range(len(dti)), dti)
  709. s.plot(ax=ax)
  710. xdata = ax.get_lines()[0].get_xdata()
  711. # plot x data is bounded by index values
  712. assert s.index.min() <= Series(xdata).min()
  713. assert Series(xdata).max() <= s.index.max()
  714. def test_to_weekly_resampling(self):
  715. idxh = date_range("1/1/1999", periods=52, freq="W")
  716. idxl = date_range("1/1/1999", periods=12, freq="M")
  717. high = Series(np.random.randn(len(idxh)), idxh)
  718. low = Series(np.random.randn(len(idxl)), idxl)
  719. _, ax = self.plt.subplots()
  720. high.plot(ax=ax)
  721. low.plot(ax=ax)
  722. for line in ax.get_lines():
  723. assert PeriodIndex(data=line.get_xdata()).freq == idxh.freq
  724. def test_from_weekly_resampling(self):
  725. idxh = date_range("1/1/1999", periods=52, freq="W")
  726. idxl = date_range("1/1/1999", periods=12, freq="M")
  727. high = Series(np.random.randn(len(idxh)), idxh)
  728. low = Series(np.random.randn(len(idxl)), idxl)
  729. _, ax = self.plt.subplots()
  730. low.plot(ax=ax)
  731. high.plot(ax=ax)
  732. expected_h = idxh.to_period().asi8.astype(np.float64)
  733. expected_l = np.array(
  734. [1514, 1519, 1523, 1527, 1531, 1536, 1540, 1544, 1549, 1553, 1558, 1562],
  735. dtype=np.float64,
  736. )
  737. for line in ax.get_lines():
  738. assert PeriodIndex(data=line.get_xdata()).freq == idxh.freq
  739. xdata = line.get_xdata(orig=False)
  740. if len(xdata) == 12: # idxl lines
  741. tm.assert_numpy_array_equal(xdata, expected_l)
  742. else:
  743. tm.assert_numpy_array_equal(xdata, expected_h)
  744. tm.close()
  745. def test_from_resampling_area_line_mixed(self):
  746. idxh = date_range("1/1/1999", periods=52, freq="W")
  747. idxl = date_range("1/1/1999", periods=12, freq="M")
  748. high = DataFrame(np.random.rand(len(idxh), 3), index=idxh, columns=[0, 1, 2])
  749. low = DataFrame(np.random.rand(len(idxl), 3), index=idxl, columns=[0, 1, 2])
  750. # low to high
  751. for kind1, kind2 in [("line", "area"), ("area", "line")]:
  752. _, ax = self.plt.subplots()
  753. low.plot(kind=kind1, stacked=True, ax=ax)
  754. high.plot(kind=kind2, stacked=True, ax=ax)
  755. # check low dataframe result
  756. expected_x = np.array(
  757. [
  758. 1514,
  759. 1519,
  760. 1523,
  761. 1527,
  762. 1531,
  763. 1536,
  764. 1540,
  765. 1544,
  766. 1549,
  767. 1553,
  768. 1558,
  769. 1562,
  770. ],
  771. dtype=np.float64,
  772. )
  773. expected_y = np.zeros(len(expected_x), dtype=np.float64)
  774. for i in range(3):
  775. line = ax.lines[i]
  776. assert PeriodIndex(line.get_xdata()).freq == idxh.freq
  777. tm.assert_numpy_array_equal(line.get_xdata(orig=False), expected_x)
  778. # check stacked values are correct
  779. expected_y += low[i].values
  780. tm.assert_numpy_array_equal(line.get_ydata(orig=False), expected_y)
  781. # check high dataframe result
  782. expected_x = idxh.to_period().asi8.astype(np.float64)
  783. expected_y = np.zeros(len(expected_x), dtype=np.float64)
  784. for i in range(3):
  785. line = ax.lines[3 + i]
  786. assert PeriodIndex(data=line.get_xdata()).freq == idxh.freq
  787. tm.assert_numpy_array_equal(line.get_xdata(orig=False), expected_x)
  788. expected_y += high[i].values
  789. tm.assert_numpy_array_equal(line.get_ydata(orig=False), expected_y)
  790. # high to low
  791. for kind1, kind2 in [("line", "area"), ("area", "line")]:
  792. _, ax = self.plt.subplots()
  793. high.plot(kind=kind1, stacked=True, ax=ax)
  794. low.plot(kind=kind2, stacked=True, ax=ax)
  795. # check high dataframe result
  796. expected_x = idxh.to_period().asi8.astype(np.float64)
  797. expected_y = np.zeros(len(expected_x), dtype=np.float64)
  798. for i in range(3):
  799. line = ax.lines[i]
  800. assert PeriodIndex(data=line.get_xdata()).freq == idxh.freq
  801. tm.assert_numpy_array_equal(line.get_xdata(orig=False), expected_x)
  802. expected_y += high[i].values
  803. tm.assert_numpy_array_equal(line.get_ydata(orig=False), expected_y)
  804. # check low dataframe result
  805. expected_x = np.array(
  806. [
  807. 1514,
  808. 1519,
  809. 1523,
  810. 1527,
  811. 1531,
  812. 1536,
  813. 1540,
  814. 1544,
  815. 1549,
  816. 1553,
  817. 1558,
  818. 1562,
  819. ],
  820. dtype=np.float64,
  821. )
  822. expected_y = np.zeros(len(expected_x), dtype=np.float64)
  823. for i in range(3):
  824. lines = ax.lines[3 + i]
  825. assert PeriodIndex(data=lines.get_xdata()).freq == idxh.freq
  826. tm.assert_numpy_array_equal(lines.get_xdata(orig=False), expected_x)
  827. expected_y += low[i].values
  828. tm.assert_numpy_array_equal(lines.get_ydata(orig=False), expected_y)
  829. def test_mixed_freq_second_millisecond(self):
  830. # GH 7772, GH 7760
  831. idxh = date_range("2014-07-01 09:00", freq="S", periods=50)
  832. idxl = date_range("2014-07-01 09:00", freq="100L", periods=500)
  833. high = Series(np.random.randn(len(idxh)), idxh)
  834. low = Series(np.random.randn(len(idxl)), idxl)
  835. # high to low
  836. _, ax = self.plt.subplots()
  837. high.plot(ax=ax)
  838. low.plot(ax=ax)
  839. assert len(ax.get_lines()) == 2
  840. for line in ax.get_lines():
  841. assert PeriodIndex(data=line.get_xdata()).freq == "L"
  842. tm.close()
  843. # low to high
  844. _, ax = self.plt.subplots()
  845. low.plot(ax=ax)
  846. high.plot(ax=ax)
  847. assert len(ax.get_lines()) == 2
  848. for line in ax.get_lines():
  849. assert PeriodIndex(data=line.get_xdata()).freq == "L"
  850. def test_irreg_dtypes(self):
  851. # date
  852. idx = [date(2000, 1, 1), date(2000, 1, 5), date(2000, 1, 20)]
  853. df = DataFrame(np.random.randn(len(idx), 3), Index(idx, dtype=object))
  854. _check_plot_works(df.plot)
  855. # np.datetime64
  856. idx = date_range("1/1/2000", periods=10)
  857. idx = idx[[0, 2, 5, 9]].astype(object)
  858. df = DataFrame(np.random.randn(len(idx), 3), idx)
  859. _, ax = self.plt.subplots()
  860. _check_plot_works(df.plot, ax=ax)
  861. def test_time(self):
  862. t = datetime(1, 1, 1, 3, 30, 0)
  863. deltas = np.random.randint(1, 20, 3).cumsum()
  864. ts = np.array([(t + timedelta(minutes=int(x))).time() for x in deltas])
  865. df = DataFrame(
  866. {"a": np.random.randn(len(ts)), "b": np.random.randn(len(ts))}, index=ts
  867. )
  868. fig, ax = self.plt.subplots()
  869. df.plot(ax=ax)
  870. # verify tick labels
  871. ticks = ax.get_xticks()
  872. labels = ax.get_xticklabels()
  873. for _tick, _label in zip(ticks, labels):
  874. m, s = divmod(int(_tick), 60)
  875. h, m = divmod(m, 60)
  876. rs = _label.get_text()
  877. if len(rs) > 0:
  878. if s != 0:
  879. xp = time(h, m, s).strftime("%H:%M:%S")
  880. else:
  881. xp = time(h, m, s).strftime("%H:%M")
  882. assert xp == rs
  883. def test_time_change_xlim(self):
  884. t = datetime(1, 1, 1, 3, 30, 0)
  885. deltas = np.random.randint(1, 20, 3).cumsum()
  886. ts = np.array([(t + timedelta(minutes=int(x))).time() for x in deltas])
  887. df = DataFrame(
  888. {"a": np.random.randn(len(ts)), "b": np.random.randn(len(ts))}, index=ts
  889. )
  890. fig, ax = self.plt.subplots()
  891. df.plot(ax=ax)
  892. # verify tick labels
  893. ticks = ax.get_xticks()
  894. labels = ax.get_xticklabels()
  895. for _tick, _label in zip(ticks, labels):
  896. m, s = divmod(int(_tick), 60)
  897. h, m = divmod(m, 60)
  898. rs = _label.get_text()
  899. if len(rs) > 0:
  900. if s != 0:
  901. xp = time(h, m, s).strftime("%H:%M:%S")
  902. else:
  903. xp = time(h, m, s).strftime("%H:%M")
  904. assert xp == rs
  905. # change xlim
  906. ax.set_xlim("1:30", "5:00")
  907. # check tick labels again
  908. ticks = ax.get_xticks()
  909. labels = ax.get_xticklabels()
  910. for _tick, _label in zip(ticks, labels):
  911. m, s = divmod(int(_tick), 60)
  912. h, m = divmod(m, 60)
  913. rs = _label.get_text()
  914. if len(rs) > 0:
  915. if s != 0:
  916. xp = time(h, m, s).strftime("%H:%M:%S")
  917. else:
  918. xp = time(h, m, s).strftime("%H:%M")
  919. assert xp == rs
  920. def test_time_musec(self):
  921. t = datetime(1, 1, 1, 3, 30, 0)
  922. deltas = np.random.randint(1, 20, 3).cumsum()
  923. ts = np.array([(t + timedelta(microseconds=int(x))).time() for x in deltas])
  924. df = DataFrame(
  925. {"a": np.random.randn(len(ts)), "b": np.random.randn(len(ts))}, index=ts
  926. )
  927. fig, ax = self.plt.subplots()
  928. ax = df.plot(ax=ax)
  929. # verify tick labels
  930. ticks = ax.get_xticks()
  931. labels = ax.get_xticklabels()
  932. for _tick, _label in zip(ticks, labels):
  933. m, s = divmod(int(_tick), 60)
  934. us = round((_tick - int(_tick)) * 1e6)
  935. h, m = divmod(m, 60)
  936. rs = _label.get_text()
  937. if len(rs) > 0:
  938. if (us % 1000) != 0:
  939. xp = time(h, m, s, us).strftime("%H:%M:%S.%f")
  940. elif (us // 1000) != 0:
  941. xp = time(h, m, s, us).strftime("%H:%M:%S.%f")[:-3]
  942. elif s != 0:
  943. xp = time(h, m, s, us).strftime("%H:%M:%S")
  944. else:
  945. xp = time(h, m, s, us).strftime("%H:%M")
  946. assert xp == rs
  947. def test_secondary_upsample(self):
  948. idxh = date_range("1/1/1999", periods=365, freq="D")
  949. idxl = date_range("1/1/1999", periods=12, freq="M")
  950. high = Series(np.random.randn(len(idxh)), idxh)
  951. low = Series(np.random.randn(len(idxl)), idxl)
  952. _, ax = self.plt.subplots()
  953. low.plot(ax=ax)
  954. ax = high.plot(secondary_y=True, ax=ax)
  955. for line in ax.get_lines():
  956. assert PeriodIndex(line.get_xdata()).freq == "D"
  957. assert hasattr(ax, "left_ax")
  958. assert not hasattr(ax, "right_ax")
  959. for line in ax.left_ax.get_lines():
  960. assert PeriodIndex(line.get_xdata()).freq == "D"
  961. def test_secondary_legend(self):
  962. fig = self.plt.figure()
  963. ax = fig.add_subplot(211)
  964. # ts
  965. df = tm.makeTimeDataFrame()
  966. df.plot(secondary_y=["A", "B"], ax=ax)
  967. leg = ax.get_legend()
  968. assert len(leg.get_lines()) == 4
  969. assert leg.get_texts()[0].get_text() == "A (right)"
  970. assert leg.get_texts()[1].get_text() == "B (right)"
  971. assert leg.get_texts()[2].get_text() == "C"
  972. assert leg.get_texts()[3].get_text() == "D"
  973. assert ax.right_ax.get_legend() is None
  974. colors = set()
  975. for line in leg.get_lines():
  976. colors.add(line.get_color())
  977. # TODO: color cycle problems
  978. assert len(colors) == 4
  979. self.plt.close(fig)
  980. fig = self.plt.figure()
  981. ax = fig.add_subplot(211)
  982. df.plot(secondary_y=["A", "C"], mark_right=False, ax=ax)
  983. leg = ax.get_legend()
  984. assert len(leg.get_lines()) == 4
  985. assert leg.get_texts()[0].get_text() == "A"
  986. assert leg.get_texts()[1].get_text() == "B"
  987. assert leg.get_texts()[2].get_text() == "C"
  988. assert leg.get_texts()[3].get_text() == "D"
  989. self.plt.close(fig)
  990. fig, ax = self.plt.subplots()
  991. df.plot(kind="bar", secondary_y=["A"], ax=ax)
  992. leg = ax.get_legend()
  993. assert leg.get_texts()[0].get_text() == "A (right)"
  994. assert leg.get_texts()[1].get_text() == "B"
  995. self.plt.close(fig)
  996. fig, ax = self.plt.subplots()
  997. df.plot(kind="bar", secondary_y=["A"], mark_right=False, ax=ax)
  998. leg = ax.get_legend()
  999. assert leg.get_texts()[0].get_text() == "A"
  1000. assert leg.get_texts()[1].get_text() == "B"
  1001. self.plt.close(fig)
  1002. fig = self.plt.figure()
  1003. ax = fig.add_subplot(211)
  1004. df = tm.makeTimeDataFrame()
  1005. ax = df.plot(secondary_y=["C", "D"], ax=ax)
  1006. leg = ax.get_legend()
  1007. assert len(leg.get_lines()) == 4
  1008. assert ax.right_ax.get_legend() is None
  1009. colors = set()
  1010. for line in leg.get_lines():
  1011. colors.add(line.get_color())
  1012. # TODO: color cycle problems
  1013. assert len(colors) == 4
  1014. self.plt.close(fig)
  1015. # non-ts
  1016. df = tm.makeDataFrame()
  1017. fig = self.plt.figure()
  1018. ax = fig.add_subplot(211)
  1019. ax = df.plot(secondary_y=["A", "B"], ax=ax)
  1020. leg = ax.get_legend()
  1021. assert len(leg.get_lines()) == 4
  1022. assert ax.right_ax.get_legend() is None
  1023. colors = set()
  1024. for line in leg.get_lines():
  1025. colors.add(line.get_color())
  1026. # TODO: color cycle problems
  1027. assert len(colors) == 4
  1028. self.plt.close()
  1029. fig = self.plt.figure()
  1030. ax = fig.add_subplot(211)
  1031. ax = df.plot(secondary_y=["C", "D"], ax=ax)
  1032. leg = ax.get_legend()
  1033. assert len(leg.get_lines()) == 4
  1034. assert ax.right_ax.get_legend() is None
  1035. colors = set()
  1036. for line in leg.get_lines():
  1037. colors.add(line.get_color())
  1038. # TODO: color cycle problems
  1039. assert len(colors) == 4
  1040. @pytest.mark.xfail(reason="Api changed in 3.6.0")
  1041. def test_format_date_axis(self):
  1042. rng = date_range("1/1/2012", periods=12, freq="M")
  1043. df = DataFrame(np.random.randn(len(rng), 3), rng)
  1044. _, ax = self.plt.subplots()
  1045. ax = df.plot(ax=ax)
  1046. xaxis = ax.get_xaxis()
  1047. for line in xaxis.get_ticklabels():
  1048. if len(line.get_text()) > 0:
  1049. assert line.get_rotation() == 30
  1050. def test_ax_plot(self):
  1051. x = date_range(start="2012-01-02", periods=10, freq="D")
  1052. y = list(range(len(x)))
  1053. _, ax = self.plt.subplots()
  1054. lines = ax.plot(x, y, label="Y")
  1055. tm.assert_index_equal(DatetimeIndex(lines[0].get_xdata()), x)
  1056. def test_mpl_nopandas(self):
  1057. dates = [date(2008, 12, 31), date(2009, 1, 31)]
  1058. values1 = np.arange(10.0, 11.0, 0.5)
  1059. values2 = np.arange(11.0, 12.0, 0.5)
  1060. kw = {"fmt": "-", "lw": 4}
  1061. _, ax = self.plt.subplots()
  1062. ax.plot_date([x.toordinal() for x in dates], values1, **kw)
  1063. ax.plot_date([x.toordinal() for x in dates], values2, **kw)
  1064. line1, line2 = ax.get_lines()
  1065. exp = np.array([x.toordinal() for x in dates], dtype=np.float64)
  1066. tm.assert_numpy_array_equal(line1.get_xydata()[:, 0], exp)
  1067. exp = np.array([x.toordinal() for x in dates], dtype=np.float64)
  1068. tm.assert_numpy_array_equal(line2.get_xydata()[:, 0], exp)
  1069. def test_irregular_ts_shared_ax_xlim(self):
  1070. # GH 2960
  1071. from pandas.plotting._matplotlib.converter import DatetimeConverter
  1072. ts = tm.makeTimeSeries()[:20]
  1073. ts_irregular = ts[[1, 4, 5, 6, 8, 9, 10, 12, 13, 14, 15, 17, 18]]
  1074. # plot the left section of the irregular series, then the right section
  1075. _, ax = self.plt.subplots()
  1076. ts_irregular[:5].plot(ax=ax)
  1077. ts_irregular[5:].plot(ax=ax)
  1078. # check that axis limits are correct
  1079. left, right = ax.get_xlim()
  1080. assert left <= DatetimeConverter.convert(ts_irregular.index.min(), "", ax)
  1081. assert right >= DatetimeConverter.convert(ts_irregular.index.max(), "", ax)
  1082. def test_secondary_y_non_ts_xlim(self):
  1083. # GH 3490 - non-timeseries with secondary y
  1084. index_1 = [1, 2, 3, 4]
  1085. index_2 = [5, 6, 7, 8]
  1086. s1 = Series(1, index=index_1)
  1087. s2 = Series(2, index=index_2)
  1088. _, ax = self.plt.subplots()
  1089. s1.plot(ax=ax)
  1090. left_before, right_before = ax.get_xlim()
  1091. s2.plot(secondary_y=True, ax=ax)
  1092. left_after, right_after = ax.get_xlim()
  1093. assert left_before >= left_after
  1094. assert right_before < right_after
  1095. def test_secondary_y_regular_ts_xlim(self):
  1096. # GH 3490 - regular-timeseries with secondary y
  1097. index_1 = date_range(start="2000-01-01", periods=4, freq="D")
  1098. index_2 = date_range(start="2000-01-05", periods=4, freq="D")
  1099. s1 = Series(1, index=index_1)
  1100. s2 = Series(2, index=index_2)
  1101. _, ax = self.plt.subplots()
  1102. s1.plot(ax=ax)
  1103. left_before, right_before = ax.get_xlim()
  1104. s2.plot(secondary_y=True, ax=ax)
  1105. left_after, right_after = ax.get_xlim()
  1106. assert left_before >= left_after
  1107. assert right_before < right_after
  1108. def test_secondary_y_mixed_freq_ts_xlim(self):
  1109. # GH 3490 - mixed frequency timeseries with secondary y
  1110. rng = date_range("2000-01-01", periods=10000, freq="min")
  1111. ts = Series(1, index=rng)
  1112. _, ax = self.plt.subplots()
  1113. ts.plot(ax=ax)
  1114. left_before, right_before = ax.get_xlim()
  1115. ts.resample("D").mean().plot(secondary_y=True, ax=ax)
  1116. left_after, right_after = ax.get_xlim()
  1117. # a downsample should not have changed either limit
  1118. assert left_before == left_after
  1119. assert right_before == right_after
  1120. def test_secondary_y_irregular_ts_xlim(self):
  1121. # GH 3490 - irregular-timeseries with secondary y
  1122. from pandas.plotting._matplotlib.converter import DatetimeConverter
  1123. ts = tm.makeTimeSeries()[:20]
  1124. ts_irregular = ts[[1, 4, 5, 6, 8, 9, 10, 12, 13, 14, 15, 17, 18]]
  1125. _, ax = self.plt.subplots()
  1126. ts_irregular[:5].plot(ax=ax)
  1127. # plot higher-x values on secondary axis
  1128. ts_irregular[5:].plot(secondary_y=True, ax=ax)
  1129. # ensure secondary limits aren't overwritten by plot on primary
  1130. ts_irregular[:5].plot(ax=ax)
  1131. left, right = ax.get_xlim()
  1132. assert left <= DatetimeConverter.convert(ts_irregular.index.min(), "", ax)
  1133. assert right >= DatetimeConverter.convert(ts_irregular.index.max(), "", ax)
  1134. def test_plot_outofbounds_datetime(self):
  1135. # 2579 - checking this does not raise
  1136. values = [date(1677, 1, 1), date(1677, 1, 2)]
  1137. _, ax = self.plt.subplots()
  1138. ax.plot(values)
  1139. values = [datetime(1677, 1, 1, 12), datetime(1677, 1, 2, 12)]
  1140. ax.plot(values)
  1141. def test_format_timedelta_ticks_narrow(self):
  1142. expected_labels = [f"00:00:00.0000000{i:0>2d}" for i in np.arange(10)]
  1143. rng = timedelta_range("0", periods=10, freq="ns")
  1144. df = DataFrame(np.random.randn(len(rng), 3), rng)
  1145. fig, ax = self.plt.subplots()
  1146. df.plot(fontsize=2, ax=ax)
  1147. self.plt.draw()
  1148. labels = ax.get_xticklabels()
  1149. result_labels = [x.get_text() for x in labels]
  1150. assert len(result_labels) == len(expected_labels)
  1151. assert result_labels == expected_labels
  1152. def test_format_timedelta_ticks_wide(self):
  1153. expected_labels = [
  1154. "00:00:00",
  1155. "1 days 03:46:40",
  1156. "2 days 07:33:20",
  1157. "3 days 11:20:00",
  1158. "4 days 15:06:40",
  1159. "5 days 18:53:20",
  1160. "6 days 22:40:00",
  1161. "8 days 02:26:40",
  1162. "9 days 06:13:20",
  1163. ]
  1164. rng = timedelta_range("0", periods=10, freq="1 d")
  1165. df = DataFrame(np.random.randn(len(rng), 3), rng)
  1166. fig, ax = self.plt.subplots()
  1167. ax = df.plot(fontsize=2, ax=ax)
  1168. self.plt.draw()
  1169. labels = ax.get_xticklabels()
  1170. result_labels = [x.get_text() for x in labels]
  1171. assert len(result_labels) == len(expected_labels)
  1172. assert result_labels == expected_labels
  1173. def test_timedelta_plot(self):
  1174. # test issue #8711
  1175. s = Series(range(5), timedelta_range("1day", periods=5))
  1176. _, ax = self.plt.subplots()
  1177. _check_plot_works(s.plot, ax=ax)
  1178. # test long period
  1179. index = timedelta_range("1 day 2 hr 30 min 10 s", periods=10, freq="1 d")
  1180. s = Series(np.random.randn(len(index)), index)
  1181. _, ax = self.plt.subplots()
  1182. _check_plot_works(s.plot, ax=ax)
  1183. # test short period
  1184. index = timedelta_range("1 day 2 hr 30 min 10 s", periods=10, freq="1 ns")
  1185. s = Series(np.random.randn(len(index)), index)
  1186. _, ax = self.plt.subplots()
  1187. _check_plot_works(s.plot, ax=ax)
  1188. def test_hist(self):
  1189. # https://github.com/matplotlib/matplotlib/issues/8459
  1190. rng = date_range("1/1/2011", periods=10, freq="H")
  1191. x = rng
  1192. w1 = np.arange(0, 1, 0.1)
  1193. w2 = np.arange(0, 1, 0.1)[::-1]
  1194. _, ax = self.plt.subplots()
  1195. ax.hist([x, x], weights=[w1, w2])
  1196. def test_overlapping_datetime(self):
  1197. # GB 6608
  1198. s1 = Series(
  1199. [1, 2, 3],
  1200. index=[
  1201. datetime(1995, 12, 31),
  1202. datetime(2000, 12, 31),
  1203. datetime(2005, 12, 31),
  1204. ],
  1205. )
  1206. s2 = Series(
  1207. [1, 2, 3],
  1208. index=[
  1209. datetime(1997, 12, 31),
  1210. datetime(2003, 12, 31),
  1211. datetime(2008, 12, 31),
  1212. ],
  1213. )
  1214. # plot first series, then add the second series to those axes,
  1215. # then try adding the first series again
  1216. _, ax = self.plt.subplots()
  1217. s1.plot(ax=ax)
  1218. s2.plot(ax=ax)
  1219. s1.plot(ax=ax)
  1220. @pytest.mark.xfail(reason="GH9053 matplotlib does not use ax.xaxis.converter")
  1221. def test_add_matplotlib_datetime64(self):
  1222. # GH9053 - ensure that a plot with PeriodConverter still understands
  1223. # datetime64 data. This still fails because matplotlib overrides the
  1224. # ax.xaxis.converter with a DatetimeConverter
  1225. s = Series(np.random.randn(10), index=date_range("1970-01-02", periods=10))
  1226. ax = s.plot()
  1227. with tm.assert_produces_warning(DeprecationWarning):
  1228. # multi-dimensional indexing
  1229. ax.plot(s.index, s.values, color="g")
  1230. l1, l2 = ax.lines
  1231. tm.assert_numpy_array_equal(l1.get_xydata(), l2.get_xydata())
  1232. def test_matplotlib_scatter_datetime64(self):
  1233. # https://github.com/matplotlib/matplotlib/issues/11391
  1234. df = DataFrame(np.random.RandomState(0).rand(10, 2), columns=["x", "y"])
  1235. df["time"] = date_range("2018-01-01", periods=10, freq="D")
  1236. fig, ax = self.plt.subplots()
  1237. ax.scatter(x="time", y="y", data=df)
  1238. self.plt.draw()
  1239. label = ax.get_xticklabels()[0]
  1240. expected = "2018-01-01"
  1241. assert label.get_text() == expected
  1242. def test_check_xticks_rot(self):
  1243. # https://github.com/pandas-dev/pandas/issues/29460
  1244. # regular time series
  1245. x = to_datetime(["2020-05-01", "2020-05-02", "2020-05-03"])
  1246. df = DataFrame({"x": x, "y": [1, 2, 3]})
  1247. axes = df.plot(x="x", y="y")
  1248. self._check_ticks_props(axes, xrot=0)
  1249. # irregular time series
  1250. x = to_datetime(["2020-05-01", "2020-05-02", "2020-05-04"])
  1251. df = DataFrame({"x": x, "y": [1, 2, 3]})
  1252. axes = df.plot(x="x", y="y")
  1253. self._check_ticks_props(axes, xrot=30)
  1254. # use timeseries index or not
  1255. axes = df.set_index("x").plot(y="y", use_index=True)
  1256. self._check_ticks_props(axes, xrot=30)
  1257. axes = df.set_index("x").plot(y="y", use_index=False)
  1258. self._check_ticks_props(axes, xrot=0)
  1259. # separate subplots
  1260. axes = df.plot(x="x", y="y", subplots=True, sharex=True)
  1261. self._check_ticks_props(axes, xrot=30)
  1262. axes = df.plot(x="x", y="y", subplots=True, sharex=False)
  1263. self._check_ticks_props(axes, xrot=0)
  1264. def _check_plot_works(f, freq=None, series=None, *args, **kwargs):
  1265. import matplotlib.pyplot as plt
  1266. fig = plt.gcf()
  1267. try:
  1268. plt.clf()
  1269. ax = fig.add_subplot(211)
  1270. orig_ax = kwargs.pop("ax", plt.gca())
  1271. orig_axfreq = getattr(orig_ax, "freq", None)
  1272. ret = f(*args, **kwargs)
  1273. assert ret is not None # do something more intelligent
  1274. ax = kwargs.pop("ax", plt.gca())
  1275. if series is not None:
  1276. dfreq = series.index.freq
  1277. if isinstance(dfreq, BaseOffset):
  1278. dfreq = dfreq.rule_code
  1279. if orig_axfreq is None:
  1280. assert ax.freq == dfreq
  1281. if freq is not None and orig_axfreq is None:
  1282. assert ax.freq == freq
  1283. ax = fig.add_subplot(212)
  1284. kwargs["ax"] = ax
  1285. ret = f(*args, **kwargs)
  1286. assert ret is not None # TODO: do something more intelligent
  1287. with tm.ensure_clean(return_filelike=True) as path:
  1288. plt.savefig(path)
  1289. # GH18439, GH#24088, statsmodels#4772
  1290. with tm.ensure_clean(return_filelike=True) as path:
  1291. pickle.dump(fig, path)
  1292. finally:
  1293. plt.close(fig)