widgets.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. import numpy as np
  2. import matplotlib.pyplot as plt
  3. from matplotlib.colors import LinearSegmentedColormap
  4. # Lots of different places that widgets could come from...
  5. try:
  6. from ipywidgets import interact, FloatSlider, IntSlider
  7. except ImportError:
  8. import warnings
  9. # ignore ShimWarning raised by IPython, see GH #892
  10. with warnings.catch_warnings():
  11. warnings.simplefilter("ignore")
  12. try:
  13. from IPython.html.widgets import interact, FloatSlider, IntSlider
  14. except ImportError:
  15. try:
  16. from IPython.html.widgets import (interact,
  17. FloatSliderWidget,
  18. IntSliderWidget)
  19. FloatSlider = FloatSliderWidget
  20. IntSlider = IntSliderWidget
  21. except ImportError:
  22. pass
  23. from .miscplot import palplot
  24. from .palettes import (color_palette, dark_palette, light_palette,
  25. diverging_palette, cubehelix_palette)
  26. __all__ = ["choose_colorbrewer_palette", "choose_cubehelix_palette",
  27. "choose_dark_palette", "choose_light_palette",
  28. "choose_diverging_palette"]
  29. def _init_mutable_colormap():
  30. """Create a matplotlib colormap that will be updated by the widgets."""
  31. greys = color_palette("Greys", 256)
  32. cmap = LinearSegmentedColormap.from_list("interactive", greys)
  33. cmap._init()
  34. cmap._set_extremes()
  35. return cmap
  36. def _update_lut(cmap, colors):
  37. """Change the LUT values in a matplotlib colormap in-place."""
  38. cmap._lut[:256] = colors
  39. cmap._set_extremes()
  40. def _show_cmap(cmap):
  41. """Show a continuous matplotlib colormap."""
  42. from .rcmod import axes_style # Avoid circular import
  43. with axes_style("white"):
  44. f, ax = plt.subplots(figsize=(8.25, .75))
  45. ax.set(xticks=[], yticks=[])
  46. x = np.linspace(0, 1, 256)[np.newaxis, :]
  47. ax.pcolormesh(x, cmap=cmap)
  48. def choose_colorbrewer_palette(data_type, as_cmap=False):
  49. """Select a palette from the ColorBrewer set.
  50. These palettes are built into matplotlib and can be used by name in
  51. many seaborn functions, or by passing the object returned by this function.
  52. Parameters
  53. ----------
  54. data_type : {'sequential', 'diverging', 'qualitative'}
  55. This describes the kind of data you want to visualize. See the seaborn
  56. color palette docs for more information about how to choose this value.
  57. Note that you can pass substrings (e.g. 'q' for 'qualitative.
  58. as_cmap : bool
  59. If True, the return value is a matplotlib colormap rather than a
  60. list of discrete colors.
  61. Returns
  62. -------
  63. pal or cmap : list of colors or matplotlib colormap
  64. Object that can be passed to plotting functions.
  65. See Also
  66. --------
  67. dark_palette : Create a sequential palette with dark low values.
  68. light_palette : Create a sequential palette with bright low values.
  69. diverging_palette : Create a diverging palette from selected colors.
  70. cubehelix_palette : Create a sequential palette or colormap using the
  71. cubehelix system.
  72. """
  73. if data_type.startswith("q") and as_cmap:
  74. raise ValueError("Qualitative palettes cannot be colormaps.")
  75. pal = []
  76. if as_cmap:
  77. cmap = _init_mutable_colormap()
  78. if data_type.startswith("s"):
  79. opts = ["Greys", "Reds", "Greens", "Blues", "Oranges", "Purples",
  80. "BuGn", "BuPu", "GnBu", "OrRd", "PuBu", "PuRd", "RdPu", "YlGn",
  81. "PuBuGn", "YlGnBu", "YlOrBr", "YlOrRd"]
  82. variants = ["regular", "reverse", "dark"]
  83. @interact
  84. def choose_sequential(name=opts, n=(2, 18),
  85. desat=FloatSlider(min=0, max=1, value=1),
  86. variant=variants):
  87. if variant == "reverse":
  88. name += "_r"
  89. elif variant == "dark":
  90. name += "_d"
  91. if as_cmap:
  92. colors = color_palette(name, 256, desat)
  93. _update_lut(cmap, np.c_[colors, np.ones(256)])
  94. _show_cmap(cmap)
  95. else:
  96. pal[:] = color_palette(name, n, desat)
  97. palplot(pal)
  98. elif data_type.startswith("d"):
  99. opts = ["RdBu", "RdGy", "PRGn", "PiYG", "BrBG",
  100. "RdYlBu", "RdYlGn", "Spectral"]
  101. variants = ["regular", "reverse"]
  102. @interact
  103. def choose_diverging(name=opts, n=(2, 16),
  104. desat=FloatSlider(min=0, max=1, value=1),
  105. variant=variants):
  106. if variant == "reverse":
  107. name += "_r"
  108. if as_cmap:
  109. colors = color_palette(name, 256, desat)
  110. _update_lut(cmap, np.c_[colors, np.ones(256)])
  111. _show_cmap(cmap)
  112. else:
  113. pal[:] = color_palette(name, n, desat)
  114. palplot(pal)
  115. elif data_type.startswith("q"):
  116. opts = ["Set1", "Set2", "Set3", "Paired", "Accent",
  117. "Pastel1", "Pastel2", "Dark2"]
  118. @interact
  119. def choose_qualitative(name=opts, n=(2, 16),
  120. desat=FloatSlider(min=0, max=1, value=1)):
  121. pal[:] = color_palette(name, n, desat)
  122. palplot(pal)
  123. if as_cmap:
  124. return cmap
  125. return pal
  126. def choose_dark_palette(input="husl", as_cmap=False):
  127. """Launch an interactive widget to create a dark sequential palette.
  128. This corresponds with the :func:`dark_palette` function. This kind
  129. of palette is good for data that range between relatively uninteresting
  130. low values and interesting high values.
  131. Requires IPython 2+ and must be used in the notebook.
  132. Parameters
  133. ----------
  134. input : {'husl', 'hls', 'rgb'}
  135. Color space for defining the seed value. Note that the default is
  136. different than the default input for :func:`dark_palette`.
  137. as_cmap : bool
  138. If True, the return value is a matplotlib colormap rather than a
  139. list of discrete colors.
  140. Returns
  141. -------
  142. pal or cmap : list of colors or matplotlib colormap
  143. Object that can be passed to plotting functions.
  144. See Also
  145. --------
  146. dark_palette : Create a sequential palette with dark low values.
  147. light_palette : Create a sequential palette with bright low values.
  148. cubehelix_palette : Create a sequential palette or colormap using the
  149. cubehelix system.
  150. """
  151. pal = []
  152. if as_cmap:
  153. cmap = _init_mutable_colormap()
  154. if input == "rgb":
  155. @interact
  156. def choose_dark_palette_rgb(r=(0., 1.),
  157. g=(0., 1.),
  158. b=(0., 1.),
  159. n=(3, 17)):
  160. color = r, g, b
  161. if as_cmap:
  162. colors = dark_palette(color, 256, input="rgb")
  163. _update_lut(cmap, colors)
  164. _show_cmap(cmap)
  165. else:
  166. pal[:] = dark_palette(color, n, input="rgb")
  167. palplot(pal)
  168. elif input == "hls":
  169. @interact
  170. def choose_dark_palette_hls(h=(0., 1.),
  171. l=(0., 1.),
  172. s=(0., 1.),
  173. n=(3, 17)):
  174. color = h, l, s
  175. if as_cmap:
  176. colors = dark_palette(color, 256, input="hls")
  177. _update_lut(cmap, colors)
  178. _show_cmap(cmap)
  179. else:
  180. pal[:] = dark_palette(color, n, input="hls")
  181. palplot(pal)
  182. elif input == "husl":
  183. @interact
  184. def choose_dark_palette_husl(h=(0, 359),
  185. s=(0, 99),
  186. l=(0, 99),
  187. n=(3, 17)):
  188. color = h, s, l
  189. if as_cmap:
  190. colors = dark_palette(color, 256, input="husl")
  191. _update_lut(cmap, colors)
  192. _show_cmap(cmap)
  193. else:
  194. pal[:] = dark_palette(color, n, input="husl")
  195. palplot(pal)
  196. if as_cmap:
  197. return cmap
  198. return pal
  199. def choose_light_palette(input="husl", as_cmap=False):
  200. """Launch an interactive widget to create a light sequential palette.
  201. This corresponds with the :func:`light_palette` function. This kind
  202. of palette is good for data that range between relatively uninteresting
  203. low values and interesting high values.
  204. Requires IPython 2+ and must be used in the notebook.
  205. Parameters
  206. ----------
  207. input : {'husl', 'hls', 'rgb'}
  208. Color space for defining the seed value. Note that the default is
  209. different than the default input for :func:`light_palette`.
  210. as_cmap : bool
  211. If True, the return value is a matplotlib colormap rather than a
  212. list of discrete colors.
  213. Returns
  214. -------
  215. pal or cmap : list of colors or matplotlib colormap
  216. Object that can be passed to plotting functions.
  217. See Also
  218. --------
  219. light_palette : Create a sequential palette with bright low values.
  220. dark_palette : Create a sequential palette with dark low values.
  221. cubehelix_palette : Create a sequential palette or colormap using the
  222. cubehelix system.
  223. """
  224. pal = []
  225. if as_cmap:
  226. cmap = _init_mutable_colormap()
  227. if input == "rgb":
  228. @interact
  229. def choose_light_palette_rgb(r=(0., 1.),
  230. g=(0., 1.),
  231. b=(0., 1.),
  232. n=(3, 17)):
  233. color = r, g, b
  234. if as_cmap:
  235. colors = light_palette(color, 256, input="rgb")
  236. _update_lut(cmap, colors)
  237. _show_cmap(cmap)
  238. else:
  239. pal[:] = light_palette(color, n, input="rgb")
  240. palplot(pal)
  241. elif input == "hls":
  242. @interact
  243. def choose_light_palette_hls(h=(0., 1.),
  244. l=(0., 1.),
  245. s=(0., 1.),
  246. n=(3, 17)):
  247. color = h, l, s
  248. if as_cmap:
  249. colors = light_palette(color, 256, input="hls")
  250. _update_lut(cmap, colors)
  251. _show_cmap(cmap)
  252. else:
  253. pal[:] = light_palette(color, n, input="hls")
  254. palplot(pal)
  255. elif input == "husl":
  256. @interact
  257. def choose_light_palette_husl(h=(0, 359),
  258. s=(0, 99),
  259. l=(0, 99),
  260. n=(3, 17)):
  261. color = h, s, l
  262. if as_cmap:
  263. colors = light_palette(color, 256, input="husl")
  264. _update_lut(cmap, colors)
  265. _show_cmap(cmap)
  266. else:
  267. pal[:] = light_palette(color, n, input="husl")
  268. palplot(pal)
  269. if as_cmap:
  270. return cmap
  271. return pal
  272. def choose_diverging_palette(as_cmap=False):
  273. """Launch an interactive widget to choose a diverging color palette.
  274. This corresponds with the :func:`diverging_palette` function. This kind
  275. of palette is good for data that range between interesting low values
  276. and interesting high values with a meaningful midpoint. (For example,
  277. change scores relative to some baseline value).
  278. Requires IPython 2+ and must be used in the notebook.
  279. Parameters
  280. ----------
  281. as_cmap : bool
  282. If True, the return value is a matplotlib colormap rather than a
  283. list of discrete colors.
  284. Returns
  285. -------
  286. pal or cmap : list of colors or matplotlib colormap
  287. Object that can be passed to plotting functions.
  288. See Also
  289. --------
  290. diverging_palette : Create a diverging color palette or colormap.
  291. choose_colorbrewer_palette : Interactively choose palettes from the
  292. colorbrewer set, including diverging palettes.
  293. """
  294. pal = []
  295. if as_cmap:
  296. cmap = _init_mutable_colormap()
  297. @interact
  298. def choose_diverging_palette(h_neg=IntSlider(min=0,
  299. max=359,
  300. value=220),
  301. h_pos=IntSlider(min=0,
  302. max=359,
  303. value=10),
  304. s=IntSlider(min=0, max=99, value=74),
  305. l=IntSlider(min=0, max=99, value=50),
  306. sep=IntSlider(min=1, max=50, value=10),
  307. n=(2, 16),
  308. center=["light", "dark"]):
  309. if as_cmap:
  310. colors = diverging_palette(h_neg, h_pos, s, l, sep, 256, center)
  311. _update_lut(cmap, colors)
  312. _show_cmap(cmap)
  313. else:
  314. pal[:] = diverging_palette(h_neg, h_pos, s, l, sep, n, center)
  315. palplot(pal)
  316. if as_cmap:
  317. return cmap
  318. return pal
  319. def choose_cubehelix_palette(as_cmap=False):
  320. """Launch an interactive widget to create a sequential cubehelix palette.
  321. This corresponds with the :func:`cubehelix_palette` function. This kind
  322. of palette is good for data that range between relatively uninteresting
  323. low values and interesting high values. The cubehelix system allows the
  324. palette to have more hue variance across the range, which can be helpful
  325. for distinguishing a wider range of values.
  326. Requires IPython 2+ and must be used in the notebook.
  327. Parameters
  328. ----------
  329. as_cmap : bool
  330. If True, the return value is a matplotlib colormap rather than a
  331. list of discrete colors.
  332. Returns
  333. -------
  334. pal or cmap : list of colors or matplotlib colormap
  335. Object that can be passed to plotting functions.
  336. See Also
  337. --------
  338. cubehelix_palette : Create a sequential palette or colormap using the
  339. cubehelix system.
  340. """
  341. pal = []
  342. if as_cmap:
  343. cmap = _init_mutable_colormap()
  344. @interact
  345. def choose_cubehelix(n_colors=IntSlider(min=2, max=16, value=9),
  346. start=FloatSlider(min=0, max=3, value=0),
  347. rot=FloatSlider(min=-1, max=1, value=.4),
  348. gamma=FloatSlider(min=0, max=5, value=1),
  349. hue=FloatSlider(min=0, max=1, value=.8),
  350. light=FloatSlider(min=0, max=1, value=.85),
  351. dark=FloatSlider(min=0, max=1, value=.15),
  352. reverse=False):
  353. if as_cmap:
  354. colors = cubehelix_palette(256, start, rot, gamma,
  355. hue, light, dark, reverse)
  356. _update_lut(cmap, np.c_[colors, np.ones(256)])
  357. _show_cmap(cmap)
  358. else:
  359. pal[:] = cubehelix_palette(n_colors, start, rot, gamma,
  360. hue, light, dark, reverse)
  361. palplot(pal)
  362. if as_cmap:
  363. return cmap
  364. return pal