test_datetimelike.py 65 KB

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