test_relational.py 62 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776
  1. from itertools import product
  2. import warnings
  3. import numpy as np
  4. import pandas as pd
  5. import matplotlib as mpl
  6. import matplotlib.pyplot as plt
  7. import pytest
  8. from .. import relational as rel
  9. from ..palettes import color_palette
  10. from ..utils import categorical_order
  11. class TestRelationalPlotter(object):
  12. def scatter_rgbs(self, collections):
  13. rgbs = []
  14. for col in collections:
  15. rgb = tuple(col.get_facecolor().squeeze()[:3])
  16. rgbs.append(rgb)
  17. return rgbs
  18. def colors_equal(self, *args):
  19. equal = True
  20. for c1, c2 in zip(*args):
  21. c1 = mpl.colors.colorConverter.to_rgb(np.squeeze(c1))
  22. c2 = mpl.colors.colorConverter.to_rgb(np.squeeze(c1))
  23. equal &= c1 == c2
  24. return equal
  25. def paths_equal(self, *args):
  26. equal = True
  27. for p1, p2 in zip(*args):
  28. equal &= np.array_equal(p1.vertices, p2.vertices)
  29. equal &= np.array_equal(p1.codes, p2.codes)
  30. return equal
  31. @pytest.fixture
  32. def wide_df(self):
  33. columns = list("abc")
  34. index = pd.Int64Index(np.arange(10, 50, 2), name="wide_index")
  35. values = np.random.randn(len(index), len(columns))
  36. return pd.DataFrame(values, index=index, columns=columns)
  37. @pytest.fixture
  38. def wide_array(self):
  39. return np.random.randn(20, 3)
  40. @pytest.fixture
  41. def flat_array(self):
  42. return np.random.randn(20)
  43. @pytest.fixture
  44. def flat_series(self):
  45. index = pd.Int64Index(np.arange(10, 30), name="t")
  46. return pd.Series(np.random.randn(20), index, name="s")
  47. @pytest.fixture
  48. def wide_list(self):
  49. return [np.random.randn(20), np.random.randn(10)]
  50. @pytest.fixture
  51. def wide_list_of_series(self):
  52. return [pd.Series(np.random.randn(20), np.arange(20), name="a"),
  53. pd.Series(np.random.randn(10), np.arange(5, 15), name="b")]
  54. @pytest.fixture
  55. def long_df(self):
  56. n = 100
  57. rs = np.random.RandomState()
  58. df = pd.DataFrame(dict(
  59. x=rs.randint(0, 20, n),
  60. y=rs.randn(n),
  61. a=np.take(list("abc"), rs.randint(0, 3, n)),
  62. b=np.take(list("mnop"), rs.randint(0, 4, n)),
  63. c=np.take(list([0, 1]), rs.randint(0, 2, n)),
  64. d=np.repeat(np.datetime64('2005-02-25'), n),
  65. s=np.take([2, 4, 8], rs.randint(0, 3, n)),
  66. f=np.take(list([0.2, 0.3]), rs.randint(0, 2, n)),
  67. ))
  68. df["s_cat"] = df["s"].astype("category")
  69. return df
  70. @pytest.fixture
  71. def repeated_df(self):
  72. n = 100
  73. rs = np.random.RandomState()
  74. return pd.DataFrame(dict(
  75. x=np.tile(np.arange(n // 2), 2),
  76. y=rs.randn(n),
  77. a=np.take(list("abc"), rs.randint(0, 3, n)),
  78. u=np.repeat(np.arange(2), n // 2),
  79. ))
  80. @pytest.fixture
  81. def missing_df(self):
  82. n = 100
  83. rs = np.random.RandomState()
  84. df = pd.DataFrame(dict(
  85. x=rs.randint(0, 20, n),
  86. y=rs.randn(n),
  87. a=np.take(list("abc"), rs.randint(0, 3, n)),
  88. b=np.take(list("mnop"), rs.randint(0, 4, n)),
  89. s=np.take([2, 4, 8], rs.randint(0, 3, n)),
  90. ))
  91. for col in df:
  92. idx = rs.permutation(df.index)[:10]
  93. df.loc[idx, col] = np.nan
  94. return df
  95. @pytest.fixture
  96. def null_column(self):
  97. return pd.Series(index=np.arange(20), dtype='float64')
  98. def test_wide_df_variables(self, wide_df):
  99. p = rel._RelationalPlotter()
  100. p.establish_variables(data=wide_df)
  101. assert p.input_format == "wide"
  102. assert p.semantics == ["x", "y", "hue", "style"]
  103. assert len(p.plot_data) == np.product(wide_df.shape)
  104. x = p.plot_data["x"]
  105. expected_x = np.tile(wide_df.index, wide_df.shape[1])
  106. assert np.array_equal(x, expected_x)
  107. y = p.plot_data["y"]
  108. expected_y = wide_df.values.ravel(order="f")
  109. assert np.array_equal(y, expected_y)
  110. hue = p.plot_data["hue"]
  111. expected_hue = np.repeat(wide_df.columns.values, wide_df.shape[0])
  112. assert np.array_equal(hue, expected_hue)
  113. style = p.plot_data["style"]
  114. expected_style = expected_hue
  115. assert np.array_equal(style, expected_style)
  116. assert p.plot_data["size"].isnull().all()
  117. assert p.x_label == wide_df.index.name
  118. assert p.y_label is None
  119. assert p.hue_label == wide_df.columns.name
  120. assert p.size_label is None
  121. assert p.style_label == wide_df.columns.name
  122. def test_wide_df_variables_check(self, wide_df):
  123. p = rel._RelationalPlotter()
  124. wide_df = wide_df.copy()
  125. wide_df.loc[:, "not_numeric"] = "a"
  126. with pytest.raises(ValueError):
  127. p.establish_variables(data=wide_df)
  128. def test_wide_array_variables(self, wide_array):
  129. p = rel._RelationalPlotter()
  130. p.establish_variables(data=wide_array)
  131. assert p.input_format == "wide"
  132. assert p.semantics == ["x", "y", "hue", "style"]
  133. assert len(p.plot_data) == np.product(wide_array.shape)
  134. nrow, ncol = wide_array.shape
  135. x = p.plot_data["x"]
  136. expected_x = np.tile(np.arange(nrow), ncol)
  137. assert np.array_equal(x, expected_x)
  138. y = p.plot_data["y"]
  139. expected_y = wide_array.ravel(order="f")
  140. assert np.array_equal(y, expected_y)
  141. hue = p.plot_data["hue"]
  142. expected_hue = np.repeat(np.arange(ncol), nrow)
  143. assert np.array_equal(hue, expected_hue)
  144. style = p.plot_data["style"]
  145. expected_style = expected_hue
  146. assert np.array_equal(style, expected_style)
  147. assert p.plot_data["size"].isnull().all()
  148. assert p.x_label is None
  149. assert p.y_label is None
  150. assert p.hue_label is None
  151. assert p.size_label is None
  152. assert p.style_label is None
  153. def test_flat_array_variables(self, flat_array):
  154. p = rel._RelationalPlotter()
  155. p.establish_variables(data=flat_array)
  156. assert p.input_format == "wide"
  157. assert p.semantics == ["x", "y"]
  158. assert len(p.plot_data) == np.product(flat_array.shape)
  159. x = p.plot_data["x"]
  160. expected_x = np.arange(flat_array.shape[0])
  161. assert np.array_equal(x, expected_x)
  162. y = p.plot_data["y"]
  163. expected_y = flat_array
  164. assert np.array_equal(y, expected_y)
  165. assert p.plot_data["hue"].isnull().all()
  166. assert p.plot_data["style"].isnull().all()
  167. assert p.plot_data["size"].isnull().all()
  168. assert p.x_label is None
  169. assert p.y_label is None
  170. assert p.hue_label is None
  171. assert p.size_label is None
  172. assert p.style_label is None
  173. def test_flat_series_variables(self, flat_series):
  174. p = rel._RelationalPlotter()
  175. p.establish_variables(data=flat_series)
  176. assert p.input_format == "wide"
  177. assert p.semantics == ["x", "y"]
  178. assert len(p.plot_data) == len(flat_series)
  179. x = p.plot_data["x"]
  180. expected_x = flat_series.index
  181. assert np.array_equal(x, expected_x)
  182. y = p.plot_data["y"]
  183. expected_y = flat_series
  184. assert np.array_equal(y, expected_y)
  185. assert p.x_label is None
  186. assert p.y_label is None
  187. assert p.hue_label is None
  188. assert p.size_label is None
  189. assert p.style_label is None
  190. def test_wide_list_variables(self, wide_list):
  191. p = rel._RelationalPlotter()
  192. p.establish_variables(data=wide_list)
  193. assert p.input_format == "wide"
  194. assert p.semantics == ["x", "y", "hue", "style"]
  195. assert len(p.plot_data) == sum(len(l) for l in wide_list)
  196. x = p.plot_data["x"]
  197. expected_x = np.concatenate([np.arange(len(l)) for l in wide_list])
  198. assert np.array_equal(x, expected_x)
  199. y = p.plot_data["y"]
  200. expected_y = np.concatenate(wide_list)
  201. assert np.array_equal(y, expected_y)
  202. hue = p.plot_data["hue"]
  203. expected_hue = np.concatenate([
  204. np.ones_like(l) * i for i, l in enumerate(wide_list)
  205. ])
  206. assert np.array_equal(hue, expected_hue)
  207. style = p.plot_data["style"]
  208. expected_style = expected_hue
  209. assert np.array_equal(style, expected_style)
  210. assert p.plot_data["size"].isnull().all()
  211. assert p.x_label is None
  212. assert p.y_label is None
  213. assert p.hue_label is None
  214. assert p.size_label is None
  215. assert p.style_label is None
  216. def test_wide_list_of_series_variables(self, wide_list_of_series):
  217. p = rel._RelationalPlotter()
  218. p.establish_variables(data=wide_list_of_series)
  219. assert p.input_format == "wide"
  220. assert p.semantics == ["x", "y", "hue", "style"]
  221. assert len(p.plot_data) == sum(len(l) for l in wide_list_of_series)
  222. x = p.plot_data["x"]
  223. expected_x = np.concatenate([s.index for s in wide_list_of_series])
  224. assert np.array_equal(x, expected_x)
  225. y = p.plot_data["y"]
  226. expected_y = np.concatenate(wide_list_of_series)
  227. assert np.array_equal(y, expected_y)
  228. hue = p.plot_data["hue"]
  229. expected_hue = np.concatenate([
  230. np.full(len(s), s.name, object) for s in wide_list_of_series
  231. ])
  232. assert np.array_equal(hue, expected_hue)
  233. style = p.plot_data["style"]
  234. expected_style = expected_hue
  235. assert np.array_equal(style, expected_style)
  236. assert p.plot_data["size"].isnull().all()
  237. assert p.x_label is None
  238. assert p.y_label is None
  239. assert p.hue_label is None
  240. assert p.size_label is None
  241. assert p.style_label is None
  242. def test_long_df(self, long_df):
  243. p = rel._RelationalPlotter()
  244. p.establish_variables(x="x", y="y", data=long_df)
  245. assert p.input_format == "long"
  246. assert p.semantics == ["x", "y"]
  247. assert np.array_equal(p.plot_data["x"], long_df["x"])
  248. assert np.array_equal(p.plot_data["y"], long_df["y"])
  249. for col in ["hue", "style", "size"]:
  250. assert p.plot_data[col].isnull().all()
  251. assert (p.x_label, p.y_label) == ("x", "y")
  252. assert p.hue_label is None
  253. assert p.size_label is None
  254. assert p.style_label is None
  255. p.establish_variables(x=long_df.x, y="y", data=long_df)
  256. assert p.semantics == ["x", "y"]
  257. assert np.array_equal(p.plot_data["x"], long_df["x"])
  258. assert np.array_equal(p.plot_data["y"], long_df["y"])
  259. assert (p.x_label, p.y_label) == ("x", "y")
  260. p.establish_variables(x="x", y=long_df.y, data=long_df)
  261. assert p.semantics == ["x", "y"]
  262. assert np.array_equal(p.plot_data["x"], long_df["x"])
  263. assert np.array_equal(p.plot_data["y"], long_df["y"])
  264. assert (p.x_label, p.y_label) == ("x", "y")
  265. p.establish_variables(x="x", y="y", hue="a", data=long_df)
  266. assert p.semantics == ["x", "y", "hue"]
  267. assert np.array_equal(p.plot_data["hue"], long_df["a"])
  268. for col in ["style", "size"]:
  269. assert p.plot_data[col].isnull().all()
  270. assert p.hue_label == "a"
  271. assert p.size_label is None and p.style_label is None
  272. p.establish_variables(x="x", y="y", hue="a", style="a", data=long_df)
  273. assert p.semantics == ["x", "y", "hue", "style"]
  274. assert np.array_equal(p.plot_data["hue"], long_df["a"])
  275. assert np.array_equal(p.plot_data["style"], long_df["a"])
  276. assert p.plot_data["size"].isnull().all()
  277. assert p.hue_label == p.style_label == "a"
  278. assert p.size_label is None
  279. p.establish_variables(x="x", y="y", hue="a", style="b", data=long_df)
  280. assert p.semantics == ["x", "y", "hue", "style"]
  281. assert np.array_equal(p.plot_data["hue"], long_df["a"])
  282. assert np.array_equal(p.plot_data["style"], long_df["b"])
  283. assert p.plot_data["size"].isnull().all()
  284. p.establish_variables(x="x", y="y", size="y", data=long_df)
  285. assert p.semantics == ["x", "y", "size"]
  286. assert np.array_equal(p.plot_data["size"], long_df["y"])
  287. assert p.size_label == "y"
  288. assert p.hue_label is None and p.style_label is None
  289. def test_bad_input(self, long_df):
  290. p = rel._RelationalPlotter()
  291. with pytest.raises(ValueError):
  292. p.establish_variables(x=long_df.x)
  293. with pytest.raises(ValueError):
  294. p.establish_variables(y=long_df.y)
  295. with pytest.raises(ValueError):
  296. p.establish_variables(x="not_in_df", data=long_df)
  297. with pytest.raises(ValueError):
  298. p.establish_variables(x="x", y="not_in_df", data=long_df)
  299. with pytest.raises(ValueError):
  300. p.establish_variables(x="x", y="not_in_df", data=long_df)
  301. def test_empty_input(self):
  302. p = rel._RelationalPlotter()
  303. p.establish_variables(data=[])
  304. p.establish_variables(data=np.array([]))
  305. p.establish_variables(data=pd.DataFrame())
  306. p.establish_variables(x=[], y=[])
  307. def test_units(self, repeated_df):
  308. p = rel._RelationalPlotter()
  309. p.establish_variables(x="x", y="y", units="u", data=repeated_df)
  310. assert np.array_equal(p.plot_data["units"], repeated_df["u"])
  311. def test_parse_hue_null(self, wide_df, null_column):
  312. p = rel._LinePlotter(data=wide_df)
  313. p.parse_hue(null_column, "Blues", None, None)
  314. assert p.hue_levels == [None]
  315. assert p.palette == {}
  316. assert p.hue_type is None
  317. assert p.cmap is None
  318. def test_parse_hue_categorical(self, wide_df, long_df):
  319. p = rel._LinePlotter(data=wide_df)
  320. assert p.hue_levels == wide_df.columns.tolist()
  321. assert p.hue_type == "categorical"
  322. assert p.cmap is None
  323. # Test named palette
  324. palette = "Blues"
  325. expected_colors = color_palette(palette, wide_df.shape[1])
  326. expected_palette = dict(zip(wide_df.columns, expected_colors))
  327. p.parse_hue(p.plot_data.hue, palette, None, None)
  328. assert p.palette == expected_palette
  329. # Test list palette
  330. palette = color_palette("Reds", wide_df.shape[1])
  331. p.parse_hue(p.plot_data.hue, palette, None, None)
  332. expected_palette = dict(zip(wide_df.columns, palette))
  333. assert p.palette == expected_palette
  334. # Test dict palette
  335. colors = color_palette("Set1", 8)
  336. palette = dict(zip(wide_df.columns, colors))
  337. p.parse_hue(p.plot_data.hue, palette, None, None)
  338. assert p.palette == palette
  339. # Test dict with missing keys
  340. palette = dict(zip(wide_df.columns[:-1], colors))
  341. with pytest.raises(ValueError):
  342. p.parse_hue(p.plot_data.hue, palette, None, None)
  343. # Test list with wrong number of colors
  344. palette = colors[:-1]
  345. with pytest.raises(ValueError):
  346. p.parse_hue(p.plot_data.hue, palette, None, None)
  347. # Test hue order
  348. hue_order = ["a", "c", "d"]
  349. p.parse_hue(p.plot_data.hue, None, hue_order, None)
  350. assert p.hue_levels == hue_order
  351. # Test long data
  352. p = rel._LinePlotter(x="x", y="y", hue="a", data=long_df)
  353. assert p.hue_levels == categorical_order(long_df.a)
  354. assert p.hue_type == "categorical"
  355. assert p.cmap is None
  356. # Test default palette
  357. p.parse_hue(p.plot_data.hue, None, None, None)
  358. hue_levels = categorical_order(long_df.a)
  359. expected_colors = color_palette(n_colors=len(hue_levels))
  360. expected_palette = dict(zip(hue_levels, expected_colors))
  361. assert p.palette == expected_palette
  362. # Test default palette with many levels
  363. levels = pd.Series(list("abcdefghijklmnopqrstuvwxyz"))
  364. p.parse_hue(levels, None, None, None)
  365. expected_colors = color_palette("husl", n_colors=len(levels))
  366. expected_palette = dict(zip(levels, expected_colors))
  367. assert p.palette == expected_palette
  368. # Test binary data
  369. p = rel._LinePlotter(x="x", y="y", hue="c", data=long_df)
  370. assert p.hue_levels == [0, 1]
  371. assert p.hue_type == "categorical"
  372. df = long_df[long_df["c"] == 0]
  373. p = rel._LinePlotter(x="x", y="y", hue="c", data=df)
  374. assert p.hue_levels == [0]
  375. assert p.hue_type == "categorical"
  376. df = long_df[long_df["c"] == 1]
  377. p = rel._LinePlotter(x="x", y="y", hue="c", data=df)
  378. assert p.hue_levels == [1]
  379. assert p.hue_type == "categorical"
  380. # Test Timestamp data
  381. p = rel._LinePlotter(x="x", y="y", hue="d", data=long_df)
  382. assert p.hue_levels == [pd.Timestamp('2005-02-25')]
  383. assert p.hue_type == "categorical"
  384. # Test numeric data with category type
  385. p = rel._LinePlotter(x="x", y="y", hue="s_cat", data=long_df)
  386. assert p.hue_levels == categorical_order(long_df.s_cat)
  387. assert p.hue_type == "categorical"
  388. assert p.cmap is None
  389. # Test categorical palette specified for numeric data
  390. palette = "deep"
  391. p = rel._LinePlotter(x="x", y="y", hue="s",
  392. palette=palette, data=long_df)
  393. expected_colors = color_palette(palette, n_colors=len(levels))
  394. hue_levels = categorical_order(long_df["s"])
  395. expected_palette = dict(zip(hue_levels, expected_colors))
  396. assert p.palette == expected_palette
  397. assert p.hue_type == "categorical"
  398. def test_parse_hue_numeric(self, long_df):
  399. p = rel._LinePlotter(x="x", y="y", hue="s", data=long_df)
  400. hue_levels = list(np.sort(long_df.s.unique()))
  401. assert p.hue_levels == hue_levels
  402. assert p.hue_type == "numeric"
  403. assert p.cmap.name == "seaborn_cubehelix"
  404. # Test named colormap
  405. palette = "Purples"
  406. p.parse_hue(p.plot_data.hue, palette, None, None)
  407. assert p.cmap is mpl.cm.get_cmap(palette)
  408. # Test colormap object
  409. palette = mpl.cm.get_cmap("Greens")
  410. p.parse_hue(p.plot_data.hue, palette, None, None)
  411. assert p.cmap is palette
  412. # Test cubehelix shorthand
  413. palette = "ch:2,0,light=.2"
  414. p.parse_hue(p.plot_data.hue, palette, None, None)
  415. assert isinstance(p.cmap, mpl.colors.ListedColormap)
  416. # Test default hue limits
  417. p.parse_hue(p.plot_data.hue, None, None, None)
  418. assert p.hue_limits == (p.plot_data.hue.min(), p.plot_data.hue.max())
  419. # Test specified hue limits
  420. hue_norm = 1, 4
  421. p.parse_hue(p.plot_data.hue, None, None, hue_norm)
  422. assert p.hue_limits == hue_norm
  423. assert isinstance(p.hue_norm, mpl.colors.Normalize)
  424. assert p.hue_norm.vmin == hue_norm[0]
  425. assert p.hue_norm.vmax == hue_norm[1]
  426. # Test Normalize object
  427. hue_norm = mpl.colors.PowerNorm(2, vmin=1, vmax=10)
  428. p.parse_hue(p.plot_data.hue, None, None, hue_norm)
  429. assert p.hue_limits == (hue_norm.vmin, hue_norm.vmax)
  430. assert p.hue_norm is hue_norm
  431. # Test default colormap values
  432. hmin, hmax = p.plot_data.hue.min(), p.plot_data.hue.max()
  433. p.parse_hue(p.plot_data.hue, None, None, None)
  434. assert p.palette[hmin] == pytest.approx(p.cmap(0.0))
  435. assert p.palette[hmax] == pytest.approx(p.cmap(1.0))
  436. # Test specified colormap values
  437. hue_norm = hmin - 1, hmax - 1
  438. p.parse_hue(p.plot_data.hue, None, None, hue_norm)
  439. norm_min = (hmin - hue_norm[0]) / (hue_norm[1] - hue_norm[0])
  440. assert p.palette[hmin] == pytest.approx(p.cmap(norm_min))
  441. assert p.palette[hmax] == pytest.approx(p.cmap(1.0))
  442. # Test list of colors
  443. hue_levels = list(np.sort(long_df.s.unique()))
  444. palette = color_palette("Blues", len(hue_levels))
  445. p.parse_hue(p.plot_data.hue, palette, None, None)
  446. assert p.palette == dict(zip(hue_levels, palette))
  447. palette = color_palette("Blues", len(hue_levels) + 1)
  448. with pytest.raises(ValueError):
  449. p.parse_hue(p.plot_data.hue, palette, None, None)
  450. # Test dictionary of colors
  451. palette = dict(zip(hue_levels, color_palette("Reds")))
  452. p.parse_hue(p.plot_data.hue, palette, None, None)
  453. assert p.palette == palette
  454. palette.pop(hue_levels[0])
  455. with pytest.raises(ValueError):
  456. p.parse_hue(p.plot_data.hue, palette, None, None)
  457. # Test invalid palette
  458. palette = "not_a_valid_palette"
  459. with pytest.raises(ValueError):
  460. p.parse_hue(p.plot_data.hue, palette, None, None)
  461. # Test bad norm argument
  462. hue_norm = "not a norm"
  463. with pytest.raises(ValueError):
  464. p.parse_hue(p.plot_data.hue, None, None, hue_norm)
  465. def test_parse_size(self, long_df):
  466. p = rel._LinePlotter(x="x", y="y", size="s", data=long_df)
  467. # Test default size limits and range
  468. default_linewidth = mpl.rcParams["lines.linewidth"]
  469. default_limits = p.plot_data["size"].min(), p.plot_data["size"].max()
  470. default_range = .5 * default_linewidth, 2 * default_linewidth
  471. p.parse_size(p.plot_data["size"], None, None, None)
  472. assert p.size_limits == default_limits
  473. size_range = min(p.sizes.values()), max(p.sizes.values())
  474. assert size_range == default_range
  475. # Test specified size limits
  476. size_limits = (1, 5)
  477. p.parse_size(p.plot_data["size"], None, None, size_limits)
  478. assert p.size_limits == size_limits
  479. # Test specified size range
  480. sizes = (.1, .5)
  481. p.parse_size(p.plot_data["size"], sizes, None, None)
  482. assert p.size_limits == default_limits
  483. # Test size values with normalization range
  484. sizes = (1, 5)
  485. size_norm = (1, 10)
  486. p.parse_size(p.plot_data["size"], sizes, None, size_norm)
  487. normalize = mpl.colors.Normalize(*size_norm, clip=True)
  488. for level, width in p.sizes.items():
  489. assert width == sizes[0] + (sizes[1] - sizes[0]) * normalize(level)
  490. # Test size values with normalization object
  491. sizes = (1, 5)
  492. size_norm = mpl.colors.LogNorm(1, 10, clip=False)
  493. p.parse_size(p.plot_data["size"], sizes, None, size_norm)
  494. assert p.size_norm.clip
  495. for level, width in p.sizes.items():
  496. assert width == sizes[0] + (sizes[1] - sizes[0]) * size_norm(level)
  497. # Test specified size order
  498. var = "a"
  499. levels = long_df[var].unique()
  500. sizes = [1, 4, 6]
  501. size_order = [levels[1], levels[2], levels[0]]
  502. p = rel._LinePlotter(x="x", y="y", size=var, data=long_df)
  503. p.parse_size(p.plot_data["size"], sizes, size_order, None)
  504. assert p.sizes == dict(zip(size_order, sizes))
  505. # Test list of sizes
  506. var = "a"
  507. levels = categorical_order(long_df[var])
  508. sizes = list(np.random.rand(len(levels)))
  509. p = rel._LinePlotter(x="x", y="y", size=var, data=long_df)
  510. p.parse_size(p.plot_data["size"], sizes, None, None)
  511. assert p.sizes == dict(zip(levels, sizes))
  512. # Test dict of sizes
  513. var = "a"
  514. levels = categorical_order(long_df[var])
  515. sizes = dict(zip(levels, np.random.rand(len(levels))))
  516. p = rel._LinePlotter(x="x", y="y", size=var, data=long_df)
  517. p.parse_size(p.plot_data["size"], sizes, None, None)
  518. assert p.sizes == sizes
  519. # Test sizes list with wrong length
  520. sizes = list(np.random.rand(len(levels) + 1))
  521. with pytest.raises(ValueError):
  522. p.parse_size(p.plot_data["size"], sizes, None, None)
  523. # Test sizes dict with missing levels
  524. sizes = dict(zip(levels, np.random.rand(len(levels) - 1)))
  525. with pytest.raises(ValueError):
  526. p.parse_size(p.plot_data["size"], sizes, None, None)
  527. # Test bad sizes argument
  528. sizes = "bad_size"
  529. with pytest.raises(ValueError):
  530. p.parse_size(p.plot_data["size"], sizes, None, None)
  531. # Test bad norm argument
  532. size_norm = "not a norm"
  533. p = rel._LinePlotter(x="x", y="y", size="s", data=long_df)
  534. with pytest.raises(ValueError):
  535. p.parse_size(p.plot_data["size"], None, None, size_norm)
  536. def test_parse_style(self, long_df):
  537. p = rel._LinePlotter(x="x", y="y", style="a", data=long_df)
  538. # Test defaults
  539. markers, dashes = True, True
  540. p.parse_style(p.plot_data["style"], markers, dashes, None)
  541. assert p.markers == dict(zip(p.style_levels, p.default_markers))
  542. assert p.dashes == dict(zip(p.style_levels, p.default_dashes))
  543. # Test lists
  544. markers, dashes = ["o", "s", "d"], [(1, 0), (1, 1), (2, 1, 3, 1)]
  545. p.parse_style(p.plot_data["style"], markers, dashes, None)
  546. assert p.markers == dict(zip(p.style_levels, markers))
  547. assert p.dashes == dict(zip(p.style_levels, dashes))
  548. # Test dicts
  549. markers = dict(zip(p.style_levels, markers))
  550. dashes = dict(zip(p.style_levels, dashes))
  551. p.parse_style(p.plot_data["style"], markers, dashes, None)
  552. assert p.markers == markers
  553. assert p.dashes == dashes
  554. # Test style order with defaults
  555. style_order = np.take(p.style_levels, [1, 2, 0])
  556. markers = dashes = True
  557. p.parse_style(p.plot_data["style"], markers, dashes, style_order)
  558. assert p.markers == dict(zip(style_order, p.default_markers))
  559. assert p.dashes == dict(zip(style_order, p.default_dashes))
  560. # Test too many levels with style lists
  561. markers, dashes = ["o", "s"], False
  562. with pytest.raises(ValueError):
  563. p.parse_style(p.plot_data["style"], markers, dashes, None)
  564. markers, dashes = False, [(2, 1)]
  565. with pytest.raises(ValueError):
  566. p.parse_style(p.plot_data["style"], markers, dashes, None)
  567. # Test too many levels with style dicts
  568. markers, dashes = {"a": "o", "b": "s"}, False
  569. with pytest.raises(ValueError):
  570. p.parse_style(p.plot_data["style"], markers, dashes, None)
  571. markers, dashes = False, {"a": (1, 0), "b": (2, 1)}
  572. with pytest.raises(ValueError):
  573. p.parse_style(p.plot_data["style"], markers, dashes, None)
  574. # Test mixture of filled and unfilled markers
  575. markers, dashes = ["o", "x", "s"], None
  576. with pytest.raises(ValueError):
  577. p.parse_style(p.plot_data["style"], markers, dashes, None)
  578. def test_subset_data_quantities(self, long_df):
  579. p = rel._LinePlotter(x="x", y="y", data=long_df)
  580. assert len(list(p.subset_data())) == 1
  581. # --
  582. var = "a"
  583. n_subsets = len(long_df[var].unique())
  584. p = rel._LinePlotter(x="x", y="y", hue=var, data=long_df)
  585. assert len(list(p.subset_data())) == n_subsets
  586. p = rel._LinePlotter(x="x", y="y", style=var, data=long_df)
  587. assert len(list(p.subset_data())) == n_subsets
  588. n_subsets = len(long_df[var].unique())
  589. p = rel._LinePlotter(x="x", y="y", size=var, data=long_df)
  590. assert len(list(p.subset_data())) == n_subsets
  591. # --
  592. var = "a"
  593. n_subsets = len(long_df[var].unique())
  594. p = rel._LinePlotter(x="x", y="y", hue=var, style=var, data=long_df)
  595. assert len(list(p.subset_data())) == n_subsets
  596. # --
  597. var1, var2 = "a", "s"
  598. n_subsets = len(set(list(map(tuple, long_df[[var1, var2]].values))))
  599. p = rel._LinePlotter(x="x", y="y", hue=var1, style=var2,
  600. data=long_df)
  601. assert len(list(p.subset_data())) == n_subsets
  602. p = rel._LinePlotter(x="x", y="y", hue=var1, size=var2, style=var1,
  603. data=long_df)
  604. assert len(list(p.subset_data())) == n_subsets
  605. # --
  606. var1, var2, var3 = "a", "s", "b"
  607. cols = [var1, var2, var3]
  608. n_subsets = len(set(list(map(tuple, long_df[cols].values))))
  609. p = rel._LinePlotter(x="x", y="y", hue=var1, size=var2, style=var3,
  610. data=long_df)
  611. assert len(list(p.subset_data())) == n_subsets
  612. def test_subset_data_keys(self, long_df):
  613. p = rel._LinePlotter(x="x", y="y", data=long_df)
  614. for (hue, size, style), _ in p.subset_data():
  615. assert hue is None
  616. assert size is None
  617. assert style is None
  618. # --
  619. var = "a"
  620. p = rel._LinePlotter(x="x", y="y", hue=var, data=long_df)
  621. for (hue, size, style), _ in p.subset_data():
  622. assert hue in long_df[var].values
  623. assert size is None
  624. assert style is None
  625. p = rel._LinePlotter(x="x", y="y", style=var, data=long_df)
  626. for (hue, size, style), _ in p.subset_data():
  627. assert hue is None
  628. assert size is None
  629. assert style in long_df[var].values
  630. p = rel._LinePlotter(x="x", y="y", hue=var, style=var, data=long_df)
  631. for (hue, size, style), _ in p.subset_data():
  632. assert hue in long_df[var].values
  633. assert size is None
  634. assert style in long_df[var].values
  635. p = rel._LinePlotter(x="x", y="y", size=var, data=long_df)
  636. for (hue, size, style), _ in p.subset_data():
  637. assert hue is None
  638. assert size in long_df[var].values
  639. assert style is None
  640. # --
  641. var1, var2 = "a", "s"
  642. p = rel._LinePlotter(x="x", y="y", hue=var1, size=var2, data=long_df)
  643. for (hue, size, style), _ in p.subset_data():
  644. assert hue in long_df[var1].values
  645. assert size in long_df[var2].values
  646. assert style is None
  647. def test_subset_data_values(self, long_df):
  648. p = rel._LinePlotter(x="x", y="y", data=long_df)
  649. _, data = next(p.subset_data())
  650. expected = p.plot_data.loc[:, ["x", "y"]].sort_values(["x", "y"])
  651. assert np.array_equal(data.values, expected)
  652. p = rel._LinePlotter(x="x", y="y", data=long_df, sort=False)
  653. _, data = next(p.subset_data())
  654. expected = p.plot_data.loc[:, ["x", "y"]]
  655. assert np.array_equal(data.values, expected)
  656. p = rel._LinePlotter(x="x", y="y", hue="a", data=long_df)
  657. for (hue, _, _), data in p.subset_data():
  658. rows = p.plot_data["hue"] == hue
  659. cols = ["x", "y"]
  660. expected = p.plot_data.loc[rows, cols].sort_values(cols)
  661. assert np.array_equal(data.values, expected.values)
  662. p = rel._LinePlotter(x="x", y="y", hue="a", data=long_df, sort=False)
  663. for (hue, _, _), data in p.subset_data():
  664. rows = p.plot_data["hue"] == hue
  665. cols = ["x", "y"]
  666. expected = p.plot_data.loc[rows, cols]
  667. assert np.array_equal(data.values, expected.values)
  668. p = rel._LinePlotter(x="x", y="y", hue="a", style="a", data=long_df)
  669. for (hue, _, _), data in p.subset_data():
  670. rows = p.plot_data["hue"] == hue
  671. cols = ["x", "y"]
  672. expected = p.plot_data.loc[rows, cols].sort_values(cols)
  673. assert np.array_equal(data.values, expected.values)
  674. p = rel._LinePlotter(x="x", y="y", hue="a", size="s", data=long_df)
  675. for (hue, size, _), data in p.subset_data():
  676. rows = (p.plot_data["hue"] == hue) & (p.plot_data["size"] == size)
  677. cols = ["x", "y"]
  678. expected = p.plot_data.loc[rows, cols].sort_values(cols)
  679. assert np.array_equal(data.values, expected.values)
  680. class TestLinePlotter(TestRelationalPlotter):
  681. def test_aggregate(self, long_df):
  682. p = rel._LinePlotter(x="x", y="y", data=long_df)
  683. p.n_boot = 10000
  684. p.sort = False
  685. x = pd.Series(np.tile([1, 2], 100))
  686. y = pd.Series(np.random.randn(200))
  687. y_mean = y.groupby(x).mean()
  688. def sem(x):
  689. return np.std(x) / np.sqrt(len(x))
  690. y_sem = y.groupby(x).apply(sem)
  691. y_cis = pd.DataFrame(dict(low=y_mean - y_sem,
  692. high=y_mean + y_sem),
  693. columns=["low", "high"])
  694. p.ci = 68
  695. p.estimator = "mean"
  696. index, est, cis = p.aggregate(y, x)
  697. assert np.array_equal(index.values, x.unique())
  698. assert est.index.equals(index)
  699. assert est.values == pytest.approx(y_mean.values)
  700. assert cis.values == pytest.approx(y_cis.values, 4)
  701. assert list(cis.columns) == ["low", "high"]
  702. p.estimator = np.mean
  703. index, est, cis = p.aggregate(y, x)
  704. assert np.array_equal(index.values, x.unique())
  705. assert est.index.equals(index)
  706. assert est.values == pytest.approx(y_mean.values)
  707. assert cis.values == pytest.approx(y_cis.values, 4)
  708. assert list(cis.columns) == ["low", "high"]
  709. p.seed = 0
  710. _, _, ci1 = p.aggregate(y, x)
  711. _, _, ci2 = p.aggregate(y, x)
  712. assert np.array_equal(ci1, ci2)
  713. y_std = y.groupby(x).std()
  714. y_cis = pd.DataFrame(dict(low=y_mean - y_std,
  715. high=y_mean + y_std),
  716. columns=["low", "high"])
  717. p.ci = "sd"
  718. index, est, cis = p.aggregate(y, x)
  719. assert np.array_equal(index.values, x.unique())
  720. assert est.index.equals(index)
  721. assert est.values == pytest.approx(y_mean.values)
  722. assert cis.values == pytest.approx(y_cis.values)
  723. assert list(cis.columns) == ["low", "high"]
  724. p.ci = None
  725. index, est, cis = p.aggregate(y, x)
  726. assert cis is None
  727. p.ci = 68
  728. x, y = pd.Series([1, 2, 3]), pd.Series([4, 3, 2])
  729. index, est, cis = p.aggregate(y, x)
  730. assert np.array_equal(index.values, x)
  731. assert np.array_equal(est.values, y)
  732. assert cis is None
  733. x, y = pd.Series([1, 1, 2]), pd.Series([2, 3, 4])
  734. index, est, cis = p.aggregate(y, x)
  735. assert cis.loc[2].isnull().all()
  736. p = rel._LinePlotter(x="x", y="y", data=long_df)
  737. p.estimator = "mean"
  738. p.n_boot = 100
  739. p.ci = 95
  740. x = pd.Categorical(["a", "b", "a", "b"], ["a", "b", "c"])
  741. y = pd.Series([1, 1, 2, 2])
  742. with warnings.catch_warnings():
  743. warnings.simplefilter("error", RuntimeWarning)
  744. index, est, cis = p.aggregate(y, x)
  745. assert cis.loc[["c"]].isnull().all().all()
  746. def test_legend_data(self, long_df):
  747. f, ax = plt.subplots()
  748. p = rel._LinePlotter(x="x", y="y", data=long_df, legend="full")
  749. p.add_legend_data(ax)
  750. handles, labels = ax.get_legend_handles_labels()
  751. assert handles == []
  752. # --
  753. ax.clear()
  754. p = rel._LinePlotter(x="x", y="y", hue="a", data=long_df,
  755. legend="full")
  756. p.add_legend_data(ax)
  757. handles, labels = ax.get_legend_handles_labels()
  758. colors = [h.get_color() for h in handles]
  759. assert labels == ["a"] + p.hue_levels
  760. assert colors == ["w"] + [p.palette[l] for l in p.hue_levels]
  761. # --
  762. ax.clear()
  763. p = rel._LinePlotter(x="x", y="y", hue="a", style="a",
  764. markers=True, legend="full", data=long_df)
  765. p.add_legend_data(ax)
  766. handles, labels = ax.get_legend_handles_labels()
  767. colors = [h.get_color() for h in handles]
  768. markers = [h.get_marker() for h in handles]
  769. assert labels == ["a"] + p.hue_levels == ["a"] + p.style_levels
  770. assert colors == ["w"] + [p.palette[l] for l in p.hue_levels]
  771. assert markers == [""] + [p.markers[l] for l in p.style_levels]
  772. # --
  773. ax.clear()
  774. p = rel._LinePlotter(x="x", y="y", hue="a", style="b",
  775. markers=True, legend="full", data=long_df)
  776. p.add_legend_data(ax)
  777. handles, labels = ax.get_legend_handles_labels()
  778. colors = [h.get_color() for h in handles]
  779. markers = [h.get_marker() for h in handles]
  780. expected_colors = (["w"] + [p.palette[l] for l in p.hue_levels]
  781. + ["w"] + [".2" for _ in p.style_levels])
  782. expected_markers = ([""] + ["None" for _ in p.hue_levels]
  783. + [""] + [p.markers[l] for l in p.style_levels])
  784. assert labels == ["a"] + p.hue_levels + ["b"] + p.style_levels
  785. assert colors == expected_colors
  786. assert markers == expected_markers
  787. # --
  788. ax.clear()
  789. p = rel._LinePlotter(x="x", y="y", hue="a", size="a", data=long_df,
  790. legend="full")
  791. p.add_legend_data(ax)
  792. handles, labels = ax.get_legend_handles_labels()
  793. colors = [h.get_color() for h in handles]
  794. widths = [h.get_linewidth() for h in handles]
  795. assert labels == ["a"] + p.hue_levels == ["a"] + p.size_levels
  796. assert colors == ["w"] + [p.palette[l] for l in p.hue_levels]
  797. assert widths == [0] + [p.sizes[l] for l in p.size_levels]
  798. # --
  799. x, y = np.random.randn(2, 40)
  800. z = np.tile(np.arange(20), 2)
  801. p = rel._LinePlotter(x=x, y=y, hue=z)
  802. ax.clear()
  803. p.legend = "full"
  804. p.add_legend_data(ax)
  805. handles, labels = ax.get_legend_handles_labels()
  806. assert labels == [str(l) for l in p.hue_levels]
  807. ax.clear()
  808. p.legend = "brief"
  809. p.add_legend_data(ax)
  810. handles, labels = ax.get_legend_handles_labels()
  811. assert len(labels) == 4
  812. p = rel._LinePlotter(x=x, y=y, size=z)
  813. ax.clear()
  814. p.legend = "full"
  815. p.add_legend_data(ax)
  816. handles, labels = ax.get_legend_handles_labels()
  817. assert labels == [str(l) for l in p.size_levels]
  818. ax.clear()
  819. p.legend = "brief"
  820. p.add_legend_data(ax)
  821. handles, labels = ax.get_legend_handles_labels()
  822. assert len(labels) == 4
  823. ax.clear()
  824. p.legend = "bad_value"
  825. with pytest.raises(ValueError):
  826. p.add_legend_data(ax)
  827. ax.clear()
  828. p = rel._LinePlotter(x=x, y=y, hue=z,
  829. hue_norm=mpl.colors.LogNorm(),
  830. legend="brief")
  831. p.add_legend_data(ax)
  832. handles, labels = ax.get_legend_handles_labels()
  833. assert float(labels[2]) / float(labels[1]) == 10
  834. ax.clear()
  835. p = rel._LinePlotter(x=x, y=y, size=z,
  836. size_norm=mpl.colors.LogNorm(),
  837. legend="brief")
  838. p.add_legend_data(ax)
  839. handles, labels = ax.get_legend_handles_labels()
  840. assert float(labels[2]) / float(labels[1]) == 10
  841. ax.clear()
  842. p = rel._LinePlotter(
  843. x="x", y="y", hue="f", legend="brief", data=long_df)
  844. p.add_legend_data(ax)
  845. expected_levels = ['0.20', '0.24', '0.28', '0.32']
  846. handles, labels = ax.get_legend_handles_labels()
  847. assert labels == ["f"] + expected_levels
  848. ax.clear()
  849. p = rel._LinePlotter(
  850. x="x", y="y", size="f", legend="brief", data=long_df)
  851. p.add_legend_data(ax)
  852. expected_levels = ['0.20', '0.24', '0.28', '0.32']
  853. handles, labels = ax.get_legend_handles_labels()
  854. assert labels == ["f"] + expected_levels
  855. def test_plot(self, long_df, repeated_df):
  856. f, ax = plt.subplots()
  857. p = rel._LinePlotter(x="x", y="y", data=long_df,
  858. sort=False, estimator=None)
  859. p.plot(ax, {})
  860. line, = ax.lines
  861. assert np.array_equal(line.get_xdata(), long_df.x.values)
  862. assert np.array_equal(line.get_ydata(), long_df.y.values)
  863. ax.clear()
  864. p.plot(ax, {"color": "k", "label": "test"})
  865. line, = ax.lines
  866. assert line.get_color() == "k"
  867. assert line.get_label() == "test"
  868. p = rel._LinePlotter(x="x", y="y", data=long_df,
  869. sort=True, estimator=None)
  870. ax.clear()
  871. p.plot(ax, {})
  872. line, = ax.lines
  873. sorted_data = long_df.sort_values(["x", "y"])
  874. assert np.array_equal(line.get_xdata(), sorted_data.x.values)
  875. assert np.array_equal(line.get_ydata(), sorted_data.y.values)
  876. p = rel._LinePlotter(x="x", y="y", hue="a", data=long_df)
  877. ax.clear()
  878. p.plot(ax, {})
  879. assert len(ax.lines) == len(p.hue_levels)
  880. for line, level in zip(ax.lines, p.hue_levels):
  881. assert line.get_color() == p.palette[level]
  882. p = rel._LinePlotter(x="x", y="y", size="a", data=long_df)
  883. ax.clear()
  884. p.plot(ax, {})
  885. assert len(ax.lines) == len(p.size_levels)
  886. for line, level in zip(ax.lines, p.size_levels):
  887. assert line.get_linewidth() == p.sizes[level]
  888. p = rel._LinePlotter(x="x", y="y", hue="a", style="a",
  889. markers=True, data=long_df)
  890. ax.clear()
  891. p.plot(ax, {})
  892. assert len(ax.lines) == len(p.hue_levels) == len(p.style_levels)
  893. for line, level in zip(ax.lines, p.hue_levels):
  894. assert line.get_color() == p.palette[level]
  895. assert line.get_marker() == p.markers[level]
  896. p = rel._LinePlotter(x="x", y="y", hue="a", style="b",
  897. markers=True, data=long_df)
  898. ax.clear()
  899. p.plot(ax, {})
  900. levels = product(p.hue_levels, p.style_levels)
  901. assert len(ax.lines) == (len(p.hue_levels) * len(p.style_levels))
  902. for line, (hue, style) in zip(ax.lines, levels):
  903. assert line.get_color() == p.palette[hue]
  904. assert line.get_marker() == p.markers[style]
  905. p = rel._LinePlotter(x="x", y="y", data=long_df,
  906. estimator="mean", err_style="band", ci="sd",
  907. sort=True)
  908. ax.clear()
  909. p.plot(ax, {})
  910. line, = ax.lines
  911. expected_data = long_df.groupby("x").y.mean()
  912. assert np.array_equal(line.get_xdata(), expected_data.index.values)
  913. assert np.allclose(line.get_ydata(), expected_data.values)
  914. assert len(ax.collections) == 1
  915. p = rel._LinePlotter(x="x", y="y", hue="a", data=long_df,
  916. estimator="mean", err_style="band", ci="sd")
  917. ax.clear()
  918. p.plot(ax, {})
  919. assert len(ax.lines) == len(ax.collections) == len(p.hue_levels)
  920. for c in ax.collections:
  921. assert isinstance(c, mpl.collections.PolyCollection)
  922. p = rel._LinePlotter(x="x", y="y", hue="a", data=long_df,
  923. estimator="mean", err_style="bars", ci="sd")
  924. ax.clear()
  925. p.plot(ax, {})
  926. # assert len(ax.lines) / 2 == len(ax.collections) == len(p.hue_levels)
  927. # The lines are different on mpl 1.4 but I can't install to debug
  928. assert len(ax.collections) == len(p.hue_levels)
  929. for c in ax.collections:
  930. assert isinstance(c, mpl.collections.LineCollection)
  931. p = rel._LinePlotter(x="x", y="y", data=repeated_df,
  932. units="u", estimator=None)
  933. ax.clear()
  934. p.plot(ax, {})
  935. n_units = len(repeated_df["u"].unique())
  936. assert len(ax.lines) == n_units
  937. p = rel._LinePlotter(x="x", y="y", hue="a", data=repeated_df,
  938. units="u", estimator=None)
  939. ax.clear()
  940. p.plot(ax, {})
  941. n_units *= len(repeated_df["a"].unique())
  942. assert len(ax.lines) == n_units
  943. p.estimator = "mean"
  944. with pytest.raises(ValueError):
  945. p.plot(ax, {})
  946. p = rel._LinePlotter(x="x", y="y", hue="a", data=long_df,
  947. err_style="band", err_kws={"alpha": .5})
  948. ax.clear()
  949. p.plot(ax, {})
  950. for band in ax.collections:
  951. assert band.get_alpha() == .5
  952. p = rel._LinePlotter(x="x", y="y", hue="a", data=long_df,
  953. err_style="bars", err_kws={"elinewidth": 2})
  954. ax.clear()
  955. p.plot(ax, {})
  956. for lines in ax.collections:
  957. assert lines.get_linestyles() == 2
  958. p.err_style = "invalid"
  959. with pytest.raises(ValueError):
  960. p.plot(ax, {})
  961. x_str = long_df["x"].astype(str)
  962. p = rel._LinePlotter(x="x", y="y", hue=x_str, data=long_df)
  963. ax.clear()
  964. p.plot(ax, {})
  965. p = rel._LinePlotter(x="x", y="y", size=x_str, data=long_df)
  966. ax.clear()
  967. p.plot(ax, {})
  968. def test_axis_labels(self, long_df):
  969. f, (ax1, ax2) = plt.subplots(1, 2, sharey=True)
  970. p = rel._LinePlotter(x="x", y="y", data=long_df)
  971. p.plot(ax1, {})
  972. assert ax1.get_xlabel() == "x"
  973. assert ax1.get_ylabel() == "y"
  974. p.plot(ax2, {})
  975. assert ax2.get_xlabel() == "x"
  976. assert ax2.get_ylabel() == "y"
  977. assert not ax2.yaxis.label.get_visible()
  978. def test_lineplot_axes(self, wide_df):
  979. f1, ax1 = plt.subplots()
  980. f2, ax2 = plt.subplots()
  981. ax = rel.lineplot(data=wide_df)
  982. assert ax is ax2
  983. ax = rel.lineplot(data=wide_df, ax=ax1)
  984. assert ax is ax1
  985. def test_lineplot_smoke(self, flat_array, flat_series,
  986. wide_array, wide_list, wide_list_of_series,
  987. wide_df, long_df, missing_df):
  988. f, ax = plt.subplots()
  989. rel.lineplot([], [])
  990. ax.clear()
  991. rel.lineplot(data=flat_array)
  992. ax.clear()
  993. rel.lineplot(data=flat_series)
  994. ax.clear()
  995. rel.lineplot(data=wide_array)
  996. ax.clear()
  997. rel.lineplot(data=wide_list)
  998. ax.clear()
  999. rel.lineplot(data=wide_list_of_series)
  1000. ax.clear()
  1001. rel.lineplot(data=wide_df)
  1002. ax.clear()
  1003. rel.lineplot(x="x", y="y", data=long_df)
  1004. ax.clear()
  1005. rel.lineplot(x=long_df.x, y=long_df.y)
  1006. ax.clear()
  1007. rel.lineplot(x=long_df.x, y="y", data=long_df)
  1008. ax.clear()
  1009. rel.lineplot(x="x", y=long_df.y.values, data=long_df)
  1010. ax.clear()
  1011. rel.lineplot(x="x", y="y", hue="a", data=long_df)
  1012. ax.clear()
  1013. rel.lineplot(x="x", y="y", hue="a", style="a", data=long_df)
  1014. ax.clear()
  1015. rel.lineplot(x="x", y="y", hue="a", style="b", data=long_df)
  1016. ax.clear()
  1017. rel.lineplot(x="x", y="y", hue="a", style="a", data=missing_df)
  1018. ax.clear()
  1019. rel.lineplot(x="x", y="y", hue="a", style="b", data=missing_df)
  1020. ax.clear()
  1021. rel.lineplot(x="x", y="y", hue="a", size="a", data=long_df)
  1022. ax.clear()
  1023. rel.lineplot(x="x", y="y", hue="a", size="s", data=long_df)
  1024. ax.clear()
  1025. rel.lineplot(x="x", y="y", hue="a", size="a", data=missing_df)
  1026. ax.clear()
  1027. rel.lineplot(x="x", y="y", hue="a", size="s", data=missing_df)
  1028. ax.clear()
  1029. class TestScatterPlotter(TestRelationalPlotter):
  1030. def test_legend_data(self, long_df):
  1031. m = mpl.markers.MarkerStyle("o")
  1032. default_mark = m.get_path().transformed(m.get_transform())
  1033. m = mpl.markers.MarkerStyle("")
  1034. null_mark = m.get_path().transformed(m.get_transform())
  1035. f, ax = plt.subplots()
  1036. p = rel._ScatterPlotter(x="x", y="y", data=long_df, legend="full")
  1037. p.add_legend_data(ax)
  1038. handles, labels = ax.get_legend_handles_labels()
  1039. assert handles == []
  1040. # --
  1041. ax.clear()
  1042. p = rel._ScatterPlotter(x="x", y="y", hue="a", data=long_df,
  1043. legend="full")
  1044. p.add_legend_data(ax)
  1045. handles, labels = ax.get_legend_handles_labels()
  1046. colors = [h.get_facecolors()[0] for h in handles]
  1047. expected_colors = ["w"] + [p.palette[l] for l in p.hue_levels]
  1048. assert labels == ["a"] + p.hue_levels
  1049. assert self.colors_equal(colors, expected_colors)
  1050. # --
  1051. ax.clear()
  1052. p = rel._ScatterPlotter(x="x", y="y", hue="a", style="a",
  1053. markers=True, legend="full", data=long_df)
  1054. p.add_legend_data(ax)
  1055. handles, labels = ax.get_legend_handles_labels()
  1056. colors = [h.get_facecolors()[0] for h in handles]
  1057. expected_colors = ["w"] + [p.palette[l] for l in p.hue_levels]
  1058. paths = [h.get_paths()[0] for h in handles]
  1059. expected_paths = [null_mark] + [p.paths[l] for l in p.style_levels]
  1060. assert labels == ["a"] + p.hue_levels == ["a"] + p.style_levels
  1061. assert self.colors_equal(colors, expected_colors)
  1062. assert self.paths_equal(paths, expected_paths)
  1063. # --
  1064. ax.clear()
  1065. p = rel._ScatterPlotter(x="x", y="y", hue="a", style="b",
  1066. markers=True, legend="full", data=long_df)
  1067. p.add_legend_data(ax)
  1068. handles, labels = ax.get_legend_handles_labels()
  1069. colors = [h.get_facecolors()[0] for h in handles]
  1070. paths = [h.get_paths()[0] for h in handles]
  1071. expected_colors = (["w"] + [p.palette[l] for l in p.hue_levels]
  1072. + ["w"] + [".2" for _ in p.style_levels])
  1073. expected_paths = ([null_mark] + [default_mark for _ in p.hue_levels]
  1074. + [null_mark] + [p.paths[l] for l in p.style_levels])
  1075. assert labels == ["a"] + p.hue_levels + ["b"] + p.style_levels
  1076. assert self.colors_equal(colors, expected_colors)
  1077. assert self.paths_equal(paths, expected_paths)
  1078. # --
  1079. ax.clear()
  1080. p = rel._ScatterPlotter(x="x", y="y", hue="a", size="a",
  1081. data=long_df, legend="full")
  1082. p.add_legend_data(ax)
  1083. handles, labels = ax.get_legend_handles_labels()
  1084. colors = [h.get_facecolors()[0] for h in handles]
  1085. expected_colors = ["w"] + [p.palette[l] for l in p.hue_levels]
  1086. sizes = [h.get_sizes()[0] for h in handles]
  1087. expected_sizes = [0] + [p.sizes[l] for l in p.size_levels]
  1088. assert labels == ["a"] + p.hue_levels == ["a"] + p.size_levels
  1089. assert self.colors_equal(colors, expected_colors)
  1090. assert sizes == expected_sizes
  1091. # --
  1092. ax.clear()
  1093. sizes_list = [10, 100, 200]
  1094. p = rel._ScatterPlotter(x="x", y="y", size="s", sizes=sizes_list,
  1095. data=long_df, legend="full")
  1096. p.add_legend_data(ax)
  1097. handles, labels = ax.get_legend_handles_labels()
  1098. sizes = [h.get_sizes()[0] for h in handles]
  1099. expected_sizes = [0] + [p.sizes[l] for l in p.size_levels]
  1100. assert labels == ["s"] + [str(l) for l in p.size_levels]
  1101. assert sizes == expected_sizes
  1102. # --
  1103. ax.clear()
  1104. sizes_dict = {2: 10, 4: 100, 8: 200}
  1105. p = rel._ScatterPlotter(x="x", y="y", size="s", sizes=sizes_dict,
  1106. data=long_df, legend="full")
  1107. p.add_legend_data(ax)
  1108. handles, labels = ax.get_legend_handles_labels()
  1109. sizes = [h.get_sizes()[0] for h in handles]
  1110. expected_sizes = [0] + [p.sizes[l] for l in p.size_levels]
  1111. assert labels == ["s"] + [str(l) for l in p.size_levels]
  1112. assert sizes == expected_sizes
  1113. # --
  1114. x, y = np.random.randn(2, 40)
  1115. z = np.tile(np.arange(20), 2)
  1116. p = rel._ScatterPlotter(x=x, y=y, hue=z)
  1117. ax.clear()
  1118. p.legend = "full"
  1119. p.add_legend_data(ax)
  1120. handles, labels = ax.get_legend_handles_labels()
  1121. assert labels == [str(l) for l in p.hue_levels]
  1122. ax.clear()
  1123. p.legend = "brief"
  1124. p.add_legend_data(ax)
  1125. handles, labels = ax.get_legend_handles_labels()
  1126. assert len(labels) == 4
  1127. p = rel._ScatterPlotter(x=x, y=y, size=z)
  1128. ax.clear()
  1129. p.legend = "full"
  1130. p.add_legend_data(ax)
  1131. handles, labels = ax.get_legend_handles_labels()
  1132. assert labels == [str(l) for l in p.size_levels]
  1133. ax.clear()
  1134. p.legend = "brief"
  1135. p.add_legend_data(ax)
  1136. handles, labels = ax.get_legend_handles_labels()
  1137. assert len(labels) == 4
  1138. ax.clear()
  1139. p.legend = "bad_value"
  1140. with pytest.raises(ValueError):
  1141. p.add_legend_data(ax)
  1142. def test_plot(self, long_df, repeated_df):
  1143. f, ax = plt.subplots()
  1144. p = rel._ScatterPlotter(x="x", y="y", data=long_df)
  1145. p.plot(ax, {})
  1146. points = ax.collections[0]
  1147. assert np.array_equal(points.get_offsets(), long_df[["x", "y"]].values)
  1148. ax.clear()
  1149. p.plot(ax, {"color": "k", "label": "test"})
  1150. points = ax.collections[0]
  1151. assert self.colors_equal(points.get_facecolor(), "k")
  1152. assert points.get_label() == "test"
  1153. p = rel._ScatterPlotter(x="x", y="y", hue="a", data=long_df)
  1154. ax.clear()
  1155. p.plot(ax, {})
  1156. points = ax.collections[0]
  1157. expected_colors = [p.palette[k] for k in p.plot_data["hue"]]
  1158. assert self.colors_equal(points.get_facecolors(), expected_colors)
  1159. p = rel._ScatterPlotter(x="x", y="y", style="c",
  1160. markers=["+", "x"], data=long_df)
  1161. ax.clear()
  1162. color = (1, .3, .8)
  1163. p.plot(ax, {"color": color})
  1164. points = ax.collections[0]
  1165. assert self.colors_equal(points.get_edgecolors(), [color])
  1166. p = rel._ScatterPlotter(x="x", y="y", size="a", data=long_df)
  1167. ax.clear()
  1168. p.plot(ax, {})
  1169. points = ax.collections[0]
  1170. expected_sizes = [p.size_lookup(k) for k in p.plot_data["size"]]
  1171. assert np.array_equal(points.get_sizes(), expected_sizes)
  1172. p = rel._ScatterPlotter(x="x", y="y", hue="a", style="a",
  1173. markers=True, data=long_df)
  1174. ax.clear()
  1175. p.plot(ax, {})
  1176. expected_colors = [p.palette[k] for k in p.plot_data["hue"]]
  1177. expected_paths = [p.paths[k] for k in p.plot_data["style"]]
  1178. assert self.colors_equal(points.get_facecolors(), expected_colors)
  1179. assert self.paths_equal(points.get_paths(), expected_paths)
  1180. p = rel._ScatterPlotter(x="x", y="y", hue="a", style="b",
  1181. markers=True, data=long_df)
  1182. ax.clear()
  1183. p.plot(ax, {})
  1184. expected_colors = [p.palette[k] for k in p.plot_data["hue"]]
  1185. expected_paths = [p.paths[k] for k in p.plot_data["style"]]
  1186. assert self.colors_equal(points.get_facecolors(), expected_colors)
  1187. assert self.paths_equal(points.get_paths(), expected_paths)
  1188. x_str = long_df["x"].astype(str)
  1189. p = rel._ScatterPlotter(x="x", y="y", hue=x_str, data=long_df)
  1190. ax.clear()
  1191. p.plot(ax, {})
  1192. p = rel._ScatterPlotter(x="x", y="y", size=x_str, data=long_df)
  1193. ax.clear()
  1194. p.plot(ax, {})
  1195. def test_axis_labels(self, long_df):
  1196. f, (ax1, ax2) = plt.subplots(1, 2, sharey=True)
  1197. p = rel._ScatterPlotter(x="x", y="y", data=long_df)
  1198. p.plot(ax1, {})
  1199. assert ax1.get_xlabel() == "x"
  1200. assert ax1.get_ylabel() == "y"
  1201. p.plot(ax2, {})
  1202. assert ax2.get_xlabel() == "x"
  1203. assert ax2.get_ylabel() == "y"
  1204. assert not ax2.yaxis.label.get_visible()
  1205. def test_scatterplot_axes(self, wide_df):
  1206. f1, ax1 = plt.subplots()
  1207. f2, ax2 = plt.subplots()
  1208. ax = rel.scatterplot(data=wide_df)
  1209. assert ax is ax2
  1210. ax = rel.scatterplot(data=wide_df, ax=ax1)
  1211. assert ax is ax1
  1212. def test_scatterplot_smoke(self, flat_array, flat_series,
  1213. wide_array, wide_list, wide_list_of_series,
  1214. wide_df, long_df, missing_df):
  1215. f, ax = plt.subplots()
  1216. rel.scatterplot([], [])
  1217. ax.clear()
  1218. rel.scatterplot(data=flat_array)
  1219. ax.clear()
  1220. rel.scatterplot(data=flat_series)
  1221. ax.clear()
  1222. rel.scatterplot(data=wide_array)
  1223. ax.clear()
  1224. rel.scatterplot(data=wide_list)
  1225. ax.clear()
  1226. rel.scatterplot(data=wide_list_of_series)
  1227. ax.clear()
  1228. rel.scatterplot(data=wide_df)
  1229. ax.clear()
  1230. rel.scatterplot(x="x", y="y", data=long_df)
  1231. ax.clear()
  1232. rel.scatterplot(x=long_df.x, y=long_df.y)
  1233. ax.clear()
  1234. rel.scatterplot(x=long_df.x, y="y", data=long_df)
  1235. ax.clear()
  1236. rel.scatterplot(x="x", y=long_df.y.values, data=long_df)
  1237. ax.clear()
  1238. rel.scatterplot(x="x", y="y", hue="a", data=long_df)
  1239. ax.clear()
  1240. rel.scatterplot(x="x", y="y", hue="a", style="a", data=long_df)
  1241. ax.clear()
  1242. rel.scatterplot(x="x", y="y", hue="a", style="b", data=long_df)
  1243. ax.clear()
  1244. rel.scatterplot(x="x", y="y", hue="a", style="a", data=missing_df)
  1245. ax.clear()
  1246. rel.scatterplot(x="x", y="y", hue="a", style="b", data=missing_df)
  1247. ax.clear()
  1248. rel.scatterplot(x="x", y="y", hue="a", size="a", data=long_df)
  1249. ax.clear()
  1250. rel.scatterplot(x="x", y="y", hue="a", size="s", data=long_df)
  1251. ax.clear()
  1252. rel.scatterplot(x="x", y="y", hue="a", size="a", data=missing_df)
  1253. ax.clear()
  1254. rel.scatterplot(x="x", y="y", hue="a", size="s", data=missing_df)
  1255. ax.clear()
  1256. class TestRelPlotter(TestRelationalPlotter):
  1257. def test_relplot_simple(self, long_df):
  1258. g = rel.relplot(x="x", y="y", kind="scatter", data=long_df)
  1259. x, y = g.ax.collections[0].get_offsets().T
  1260. assert np.array_equal(x, long_df["x"])
  1261. assert np.array_equal(y, long_df["y"])
  1262. g = rel.relplot(x="x", y="y", kind="line", data=long_df)
  1263. x, y = g.ax.lines[0].get_xydata().T
  1264. expected = long_df.groupby("x").y.mean()
  1265. assert np.array_equal(x, expected.index)
  1266. assert y == pytest.approx(expected.values)
  1267. with pytest.raises(ValueError):
  1268. g = rel.relplot(x="x", y="y", kind="not_a_kind", data=long_df)
  1269. def test_relplot_complex(self, long_df):
  1270. for sem in ["hue", "size", "style"]:
  1271. g = rel.relplot(x="x", y="y", data=long_df, **{sem: "a"})
  1272. x, y = g.ax.collections[0].get_offsets().T
  1273. assert np.array_equal(x, long_df["x"])
  1274. assert np.array_equal(y, long_df["y"])
  1275. for sem in ["hue", "size", "style"]:
  1276. g = rel.relplot(x="x", y="y", col="c", data=long_df,
  1277. **{sem: "a"})
  1278. grouped = long_df.groupby("c")
  1279. for (_, grp_df), ax in zip(grouped, g.axes.flat):
  1280. x, y = ax.collections[0].get_offsets().T
  1281. assert np.array_equal(x, grp_df["x"])
  1282. assert np.array_equal(y, grp_df["y"])
  1283. for sem in ["size", "style"]:
  1284. g = rel.relplot(x="x", y="y", hue="b", col="c", data=long_df,
  1285. **{sem: "a"})
  1286. grouped = long_df.groupby("c")
  1287. for (_, grp_df), ax in zip(grouped, g.axes.flat):
  1288. x, y = ax.collections[0].get_offsets().T
  1289. assert np.array_equal(x, grp_df["x"])
  1290. assert np.array_equal(y, grp_df["y"])
  1291. for sem in ["hue", "size", "style"]:
  1292. g = rel.relplot(x="x", y="y", col="b", row="c",
  1293. data=long_df.sort_values(["c", "b"]),
  1294. **{sem: "a"})
  1295. grouped = long_df.groupby(["c", "b"])
  1296. for (_, grp_df), ax in zip(grouped, g.axes.flat):
  1297. x, y = ax.collections[0].get_offsets().T
  1298. assert np.array_equal(x, grp_df["x"])
  1299. assert np.array_equal(y, grp_df["y"])
  1300. def test_relplot_hues(self, long_df):
  1301. palette = ["r", "b", "g"]
  1302. g = rel.relplot(x="x", y="y", hue="a", style="b", col="c",
  1303. palette=palette, data=long_df)
  1304. palette = dict(zip(long_df["a"].unique(), palette))
  1305. grouped = long_df.groupby("c")
  1306. for (_, grp_df), ax in zip(grouped, g.axes.flat):
  1307. points = ax.collections[0]
  1308. expected_hues = [palette[val] for val in grp_df["a"]]
  1309. assert self.colors_equal(points.get_facecolors(), expected_hues)
  1310. def test_relplot_sizes(self, long_df):
  1311. sizes = [5, 12, 7]
  1312. g = rel.relplot(x="x", y="y", size="a", hue="b", col="c",
  1313. sizes=sizes, data=long_df)
  1314. sizes = dict(zip(long_df["a"].unique(), sizes))
  1315. grouped = long_df.groupby("c")
  1316. for (_, grp_df), ax in zip(grouped, g.axes.flat):
  1317. points = ax.collections[0]
  1318. expected_sizes = [sizes[val] for val in grp_df["a"]]
  1319. assert np.array_equal(points.get_sizes(), expected_sizes)
  1320. def test_relplot_styles(self, long_df):
  1321. markers = ["o", "d", "s"]
  1322. g = rel.relplot(x="x", y="y", style="a", hue="b", col="c",
  1323. markers=markers, data=long_df)
  1324. paths = []
  1325. for m in markers:
  1326. m = mpl.markers.MarkerStyle(m)
  1327. paths.append(m.get_path().transformed(m.get_transform()))
  1328. paths = dict(zip(long_df["a"].unique(), paths))
  1329. grouped = long_df.groupby("c")
  1330. for (_, grp_df), ax in zip(grouped, g.axes.flat):
  1331. points = ax.collections[0]
  1332. expected_paths = [paths[val] for val in grp_df["a"]]
  1333. assert self.paths_equal(points.get_paths(), expected_paths)
  1334. def test_relplot_stringy_numerics(self, long_df):
  1335. long_df["x_str"] = long_df["x"].astype(str)
  1336. g = rel.relplot(x="x", y="y", hue="x_str", data=long_df)
  1337. points = g.ax.collections[0]
  1338. xys = points.get_offsets()
  1339. mask = np.ma.getmask(xys)
  1340. assert not mask.any()
  1341. assert np.array_equal(xys, long_df[["x", "y"]])
  1342. g = rel.relplot(x="x", y="y", size="x_str", data=long_df)
  1343. points = g.ax.collections[0]
  1344. xys = points.get_offsets()
  1345. mask = np.ma.getmask(xys)
  1346. assert not mask.any()
  1347. assert np.array_equal(xys, long_df[["x", "y"]])
  1348. def test_relplot_legend(self, long_df):
  1349. g = rel.relplot(x="x", y="y", data=long_df)
  1350. assert g._legend is None
  1351. g = rel.relplot(x="x", y="y", hue="a", data=long_df)
  1352. texts = [t.get_text() for t in g._legend.texts]
  1353. expected_texts = np.append(["a"], long_df["a"].unique())
  1354. assert np.array_equal(texts, expected_texts)
  1355. g = rel.relplot(x="x", y="y", hue="s", size="s", data=long_df)
  1356. texts = [t.get_text() for t in g._legend.texts]
  1357. assert np.array_equal(texts[1:], np.sort(texts[1:]))
  1358. g = rel.relplot(x="x", y="y", hue="a", legend=False, data=long_df)
  1359. assert g._legend is None
  1360. palette = color_palette("deep", len(long_df["b"].unique()))
  1361. a_like_b = dict(zip(long_df["a"].unique(), long_df["b"].unique()))
  1362. long_df["a_like_b"] = long_df["a"].map(a_like_b)
  1363. g = rel.relplot(x="x", y="y", hue="b", style="a_like_b",
  1364. palette=palette, kind="line", estimator=None,
  1365. data=long_df)
  1366. lines = g._legend.get_lines()[1:] # Chop off title dummy
  1367. for line, color in zip(lines, palette):
  1368. assert line.get_color() == color
  1369. def test_ax_kwarg_removal(self, long_df):
  1370. f, ax = plt.subplots()
  1371. with pytest.warns(UserWarning):
  1372. g = rel.relplot("x", "y", data=long_df, ax=ax)
  1373. assert len(ax.collections) == 0
  1374. assert len(g.ax.collections) > 0