You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1793 lines
72 KiB

4 years ago
  1. # Copyright 2015 Bloomberg Finance L.P.
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. r"""
  15. =====
  16. Marks
  17. =====
  18. .. currentmodule:: bqplot.marks
  19. .. autosummary::
  20. :toctree: _generate/
  21. Mark
  22. Lines
  23. FlexLine
  24. Scatter
  25. Hist
  26. Bars
  27. Graph
  28. GridHeatMap
  29. HeatMap
  30. Label
  31. OHLC
  32. Pie
  33. Map
  34. """
  35. import os
  36. import json
  37. from warnings import warn
  38. import ipywidgets as widgets
  39. from ipywidgets import (Widget, DOMWidget, CallbackDispatcher,
  40. Color, widget_serialization)
  41. from traitlets import (Int, Unicode, List, Enum, Dict, Bool, Float,
  42. Instance, TraitError, validate)
  43. from traittypes import Array
  44. from numpy import histogram
  45. import numpy as np
  46. from .scales import Scale, OrdinalScale, LinearScale
  47. from .traits import (Date, array_serialization,
  48. array_squeeze, array_dimension_bounds, array_supported_kinds)
  49. from ._version import __frontend_version__
  50. from .colorschemes import CATEGORY10
  51. def register_mark(key=None):
  52. """Returns a decorator registering a mark class in the mark type registry.
  53. If no key is provided, the class name is used as a key. A key is provided
  54. for each core bqplot mark so that the frontend can use
  55. this key regardless of the kernel language.
  56. """
  57. def wrap(mark):
  58. name = key if key is not None else mark.__module__ + mark.__name__
  59. Mark.mark_types[name] = mark
  60. return mark
  61. return wrap
  62. # Shape constraint for array-types
  63. def shape(*dimensions):
  64. def validator(trait, value):
  65. err_msg_tmpl = 'Expected an array of shape {} ' + \
  66. 'but got an array of shape {}'
  67. if value.shape != dimensions:
  68. raise TraitError(err_msg_tmpl.format(dimensions, value.shape))
  69. else:
  70. return value
  71. return validator
  72. class Mark(Widget):
  73. """The base mark class.
  74. Traitlet mark attributes may be decorated with metadata.
  75. **Data Attribute Decoration**
  76. Data attributes are decorated with the following values:
  77. scaled: bool
  78. Indicates whether the considered attribute is a data attribute which
  79. must be associated with a scale in order to be taken into account.
  80. rtype: string
  81. Range type of the associated scale.
  82. atype: string
  83. Key in bqplot's axis registry of the recommended axis type to represent
  84. this scale. When not specified, the default is 'bqplot.Axis'.
  85. Attributes
  86. ----------
  87. display_name: string
  88. Holds a user-friendly name for the trait attribute.
  89. mark_types: dict (class-level attribute)
  90. A registry of existing mark types.
  91. scales: Dict of scales (default: {})
  92. A dictionary of scales holding scales for each data attribute.
  93. - If a mark holds a scaled attribute named 'x', the scales dictionary
  94. must have a corresponding scale for the key 'x'.
  95. - The scale's range type should be equal to the scaled attribute's
  96. range type (rtype).
  97. scales_metadata: Dict (default: {})
  98. A dictionary of dictionaries holding metadata on the way scales are
  99. used by the mark. For example, a linear scale may be used to count
  100. pixels horizontally or vertically. The content of this dictionary
  101. may change dynamically. It is an instance-level attribute.
  102. preserve_domain: dict (default: {})
  103. Indicates if this mark affects the domain(s) of the specified scale(s).
  104. The keys of this dictionary are the same as the ones of the "scales"
  105. attribute, and values are boolean. If a key is missing, it is
  106. considered as False.
  107. display_legend: bool (default: False)
  108. Display toggle for the mark legend in the general figure legend
  109. labels: list of unicode strings (default: [])
  110. Labels of the items of the mark. This attribute has different meanings
  111. depending on the type of mark.
  112. apply_clip: bool (default: True)
  113. Indicates whether the items that are beyond the limits of the chart
  114. should be clipped.
  115. visible: bool (default: True)
  116. Visibility toggle for the mark.
  117. selected_style: dict (default: {})
  118. CSS style to be applied to selected items in the mark.
  119. unselected_style: dict (default: {})
  120. CSS style to be applied to items that are not selected in the mark,
  121. when a selection exists.
  122. selected: list of integers or None (default: None)
  123. Indices of the selected items in the mark.
  124. tooltip: DOMWidget or None (default: None)
  125. Widget to be displayed as tooltip when elements of the scatter are
  126. hovered on
  127. tooltip_style: Dictionary (default: {'opacity': 0.9})
  128. Styles to be applied to the tooltip widget
  129. enable_hover: Bool (default: True)
  130. Boolean attribute to control the hover interaction for the scatter. If
  131. this is false, the on_hover custom mssg is not sent back to the python
  132. side
  133. interactions: Dictionary (default: {'hover': 'tooltip'})
  134. Dictionary listing the different interactions for each mark. The key is
  135. the event which triggers the interaction and the value is the kind of
  136. interactions. Keys and values can only take strings from separate enums
  137. for each mark.
  138. tooltip_location : {'mouse', 'center'} (default: 'mouse')
  139. Enum specifying the location of the tooltip. 'mouse' places the tooltip
  140. at the location of the mouse when the tooltip is activated and 'center'
  141. places the tooltip at the center of the figure. If tooltip is linked to
  142. a click event, 'mouse' places the tooltip at the location of the click
  143. that triggered the tooltip to be visible.
  144. """
  145. mark_types = {}
  146. scales = Dict(trait=Instance(Scale)).tag(sync=True, **widget_serialization)
  147. scales_metadata = Dict().tag(sync=True)
  148. preserve_domain = Dict().tag(sync=True)
  149. display_legend = Bool().tag(sync=True, display_name='Display legend')
  150. labels = List(trait=Unicode()).tag(sync=True, display_name='Labels')
  151. apply_clip = Bool(True).tag(sync=True)
  152. visible = Bool(True).tag(sync=True)
  153. selected_style = Dict().tag(sync=True)
  154. unselected_style = Dict().tag(sync=True)
  155. selected = Array(None, allow_none=True).tag(sync=True, **array_serialization)
  156. enable_hover = Bool(True).tag(sync=True)
  157. tooltip = Instance(DOMWidget, allow_none=True, default_value=None)\
  158. .tag(sync=True, **widget_serialization)
  159. tooltip_style = Dict({'opacity': 0.9}).tag(sync=True)
  160. interactions = Dict({'hover': 'tooltip'}).tag(sync=True)
  161. tooltip_location = Enum(['mouse', 'center'], default_value='mouse')\
  162. .tag(sync=True)
  163. _model_name = Unicode('MarkModel').tag(sync=True)
  164. _model_module = Unicode('bqplot').tag(sync=True)
  165. _view_module = Unicode('bqplot').tag(sync=True)
  166. _view_module_version = Unicode(__frontend_version__).tag(sync=True)
  167. _model_module_version = Unicode(__frontend_version__).tag(sync=True)
  168. _ipython_display_ = None
  169. def _get_dimension_scales(self, dimension, preserve_domain=False):
  170. """
  171. Return the list of scales corresponding to a given dimension.
  172. The preserve_domain optional argument specifies whether one should
  173. filter out the scales for which preserve_domain is set to True.
  174. """
  175. if preserve_domain:
  176. return [
  177. self.scales[k] for k in self.scales if (
  178. k in self.scales_metadata and
  179. self.scales_metadata[k].get('dimension') == dimension and
  180. not self.preserve_domain.get(k)
  181. )
  182. ]
  183. else:
  184. return [
  185. self.scales[k] for k in self.scales if (
  186. k in self.scales_metadata and
  187. self.scales_metadata[k].get('dimension') == dimension
  188. )
  189. ]
  190. @validate('scales')
  191. def _validate_scales(self, proposal):
  192. """
  193. Validates the `scales` based on the mark's scaled attributes metadata.
  194. First checks for missing scale and then for 'rtype' compatibility.
  195. """
  196. # Validate scales' 'rtype' versus data attribute 'rtype' decoration
  197. # At this stage it is already validated that all values in self.scales
  198. # are instances of Scale.
  199. scales = proposal.value
  200. for name in self.trait_names(scaled=True):
  201. trait = self.traits()[name]
  202. if name not in scales:
  203. # Check for missing scale
  204. if not trait.allow_none:
  205. raise TraitError("Missing scale for data attribute %s." %
  206. name)
  207. else:
  208. # Check scale range type compatibility
  209. if scales[name].rtype != trait.get_metadata('rtype'):
  210. raise TraitError("Range type mismatch for scale %s." %
  211. name)
  212. return scales
  213. def __init__(self, **kwargs):
  214. super(Mark, self).__init__(**kwargs)
  215. self._hover_handlers = CallbackDispatcher()
  216. self._click_handlers = CallbackDispatcher()
  217. self._legend_click_handlers = CallbackDispatcher()
  218. self._legend_hover_handlers = CallbackDispatcher()
  219. self._element_click_handlers = CallbackDispatcher()
  220. self._bg_click_handlers = CallbackDispatcher()
  221. self.on_msg(self._handle_custom_msgs)
  222. def on_hover(self, callback, remove=False):
  223. self._hover_handlers.register_callback(callback, remove=remove)
  224. def on_click(self, callback, remove=False):
  225. self._click_handlers.register_callback(callback, remove=remove)
  226. def on_legend_click(self, callback, remove=False):
  227. self._legend_click_handlers.register_callback(callback, remove=remove)
  228. def on_legend_hover(self, callback, remove=False):
  229. self._legend_hover_handlers.register_callback(callback, remove=remove)
  230. def on_element_click(self, callback, remove=False):
  231. self._element_click_handlers.register_callback(callback, remove=remove)
  232. def on_background_click(self, callback, remove=False):
  233. self._bg_click_handlers.register_callback(callback, remove=remove)
  234. def _handle_custom_msgs(self, _, content, buffers=None):
  235. if content.get('event', '') == 'hover':
  236. self._hover_handlers(self, content)
  237. if content.get('event', '') == 'click':
  238. self._click_handlers(self, content)
  239. elif content.get('event', '') == 'legend_click':
  240. self._legend_click_handlers(self, content)
  241. elif content.get('event', '') == 'legend_hover':
  242. self._legend_hover_handlers(self, content)
  243. elif content.get('event', '') == 'element_click':
  244. self._element_click_handlers(self, content)
  245. elif content.get('event', '') == 'background_click':
  246. self._bg_click_handlers(self, content)
  247. @register_mark('bqplot.Lines')
  248. class Lines(Mark):
  249. """Lines mark.
  250. In the case of the Lines mark, scales for 'x' and 'y' MUST be provided.
  251. Attributes
  252. ----------
  253. icon: string (class-level attribute)
  254. Font-awesome icon for the respective mark
  255. name: string (class-level attribute)
  256. User-friendly name of the mark
  257. colors: list of colors (default: CATEGORY10)
  258. List of colors of the Lines. If the list is shorter than the number
  259. of lines, the colors are reused.
  260. close_path: bool (default: False)
  261. Whether to close the paths or not.
  262. fill: {'none', 'bottom', 'top', 'inside', 'between'}
  263. Fill in the area defined by the curves
  264. fill_colors: list of colors (default: [])
  265. Fill colors for the areas. Defaults to stroke-colors when no
  266. color provided
  267. opacities: list of floats (default: [])
  268. Opacity for the lines and patches. Defaults to 1 when the list is too
  269. short, or the element of the list is set to None.
  270. fill_opacities: list of floats (default: [])
  271. Opacity for the areas. Defaults to 1 when the list is too
  272. short, or the element of the list is set to None.
  273. stroke_width: float (default: 2)
  274. Stroke width of the Lines
  275. labels_visibility: {'none', 'label'}
  276. Visibility of the curve labels
  277. curves_subset: list of integers or None (default: [])
  278. If set to None, all the lines are displayed. Otherwise, only the items
  279. in the list will have full opacity, while others will be faded.
  280. line_style: {'solid', 'dashed', 'dotted', 'dash_dotted'}
  281. Line style.
  282. interpolation: {'linear', 'basis', 'cardinal', 'monotone'}
  283. Interpolation scheme used for interpolation between the data points
  284. provided. Please refer to the svg interpolate documentation for details
  285. about the different interpolation schemes.
  286. marker: {'circle', 'cross', 'diamond', 'square', 'triangle-down', 'triangle-up', 'arrow', 'rectangle', 'ellipse'}
  287. Marker shape
  288. marker_size: nonnegative int (default: 64)
  289. Default marker size in pixels
  290. Data Attributes
  291. x: numpy.ndarray (default: [])
  292. abscissas of the data points (1d or 2d array)
  293. y: numpy.ndarray (default: [])
  294. ordinates of the data points (1d or 2d array)
  295. color: numpy.ndarray (default: None)
  296. colors of the different lines based on data. If it is [], then the
  297. colors from the colors attribute are used. Each line has a single color
  298. and if the size of colors is less than the number of lines, the
  299. remaining lines are given the default colors.
  300. Notes
  301. -----
  302. The fields which can be passed to the default tooltip are:
  303. name: label of the line
  304. index: index of the line being hovered on
  305. color: data attribute for the color of the line
  306. The following are the events which can trigger interactions:
  307. click: left click of the mouse
  308. hover: mouse-over an element
  309. The following are the interactions which can be linked to the above events:
  310. tooltip: display tooltip
  311. """
  312. # Mark decoration
  313. icon = 'fa-line-chart'
  314. name = 'Lines'
  315. # Scaled attributes
  316. x = Array([]).tag(sync=True, scaled=True,
  317. rtype='Number', atype='bqplot.Axis',
  318. **array_serialization)\
  319. .valid(array_squeeze, array_dimension_bounds(1, 2), array_supported_kinds())
  320. y = Array([]).tag(sync=True, scaled=True,
  321. rtype='Number', atype='bqplot.Axis',
  322. **array_serialization)\
  323. .valid(array_squeeze, array_dimension_bounds(1, 2), array_supported_kinds())
  324. color = Array(None, allow_none=True).tag(sync=True,
  325. scaled=True,
  326. rtype='Color',
  327. atype='bqplot.ColorAxis',
  328. **array_serialization)\
  329. .valid(array_squeeze, array_dimension_bounds(1, 1))
  330. # Other attributes
  331. scales_metadata = Dict({
  332. 'x': {'orientation': 'horizontal', 'dimension': 'x'},
  333. 'y': {'orientation': 'vertical', 'dimension': 'y'},
  334. 'color': {'dimension': 'color'}
  335. }).tag(sync=True)
  336. colors = List(trait=Color(default_value=None, allow_none=True),
  337. default_value=CATEGORY10)\
  338. .tag(sync=True, display_name='Colors')
  339. fill_colors = List(trait=Color(default_value=None, allow_none=True))\
  340. .tag(sync=True, display_name='Fill colors')
  341. stroke_width = Float(2.0).tag(sync=True, display_name='Stroke width')
  342. labels_visibility = Enum(['none', 'label'], default_value='none')\
  343. .tag(sync=True, display_name='Labels visibility')
  344. curves_subset = List().tag(sync=True)
  345. line_style = Enum(['solid', 'dashed', 'dotted', 'dash_dotted'],
  346. default_value='solid')\
  347. .tag(sync=True, display_name='Line style')
  348. interpolation = Enum(['linear', 'basis', 'basis-open',
  349. 'basis-closed', 'bundle',
  350. 'cardinal', 'cardinal-open',
  351. 'cardinal-closed', 'monotone', 'step-before',
  352. 'step-after'],
  353. default_value='linear')\
  354. .tag(sync=True, display_name='Interpolation')
  355. close_path = Bool().tag(sync=True, display_name='Close path')
  356. fill = Enum(['none', 'bottom', 'top', 'inside', 'between'],
  357. default_value='none')\
  358. .tag(sync=True, display_name='Fill')
  359. marker = Enum(['circle', 'cross', 'diamond', 'square', 'triangle-down',
  360. 'triangle-up', 'arrow', 'rectangle', 'ellipse'],
  361. default_value=None, allow_none=True)\
  362. .tag(sync=True, display_name='Marker')
  363. marker_size = Int(64).tag(sync=True, display_name='Default size')
  364. opacities = List().tag(sync=True, display_name='Opacity')
  365. fill_opacities = List().tag(sync=True, display_name='Fill Opacity')
  366. _view_name = Unicode('Lines').tag(sync=True)
  367. _model_name = Unicode('LinesModel').tag(sync=True)
  368. @register_mark('bqplot.FlexLine')
  369. class FlexLine(Mark):
  370. """Flexible Lines mark.
  371. In the case of the FlexLines mark, scales for 'x' and 'y' MUST be provided.
  372. Scales for the color and width data attributes are optional. In the case
  373. where another data attribute than 'x' or 'y' is provided but the
  374. corresponding scale is missing, the data attribute is ignored.
  375. Attributes
  376. ----------
  377. name: string (class-level attributes)
  378. user-friendly name of the mark
  379. colors: list of colors (default: CATEGORY10)
  380. List of colors for the Lines
  381. stroke_width: float (default: 1.5)
  382. Default stroke width of the Lines
  383. Data Attributes
  384. x: numpy.ndarray (default: [])
  385. abscissas of the data points (1d array)
  386. y: numpy.ndarray (default: [])
  387. ordinates of the data points (1d array)
  388. color: numpy.ndarray or None (default: None)
  389. Array controlling the color of the data points
  390. width: numpy.ndarray or None (default: None)
  391. Array controlling the widths of the Lines.
  392. """
  393. # Mark decoration
  394. icon = 'fa-line-chart'
  395. name = 'Flexible lines'
  396. # Scaled attributes
  397. x = Array([]).tag(sync=True, scaled=True, rtype='Number',
  398. atype='bqplot.Axis',
  399. **array_serialization)\
  400. .valid(array_squeeze, array_dimension_bounds(1, 1))
  401. y = Array([]).tag(sync=True, scaled=True,
  402. rtype='Number',
  403. atype='bqplot.Axis',
  404. **array_serialization)\
  405. .valid(array_squeeze, array_dimension_bounds(1, 1))
  406. color = Array(None, allow_none=True)\
  407. .tag(sync=True, scaled=True, rtype='Color',
  408. atype='bqplot.ColorAxis',
  409. **array_serialization).valid(array_squeeze)
  410. width = Array(None, allow_none=True)\
  411. .tag(sync=True, scaled=True, rtype='Number',
  412. **array_serialization).valid(array_squeeze)
  413. # Other attributes
  414. scales_metadata = Dict({
  415. 'x': {'orientation': 'horizontal', 'dimension': 'x'},
  416. 'y': {'orientation': 'vertical', 'dimension': 'y'},
  417. 'color': {'dimension': 'color'}
  418. }).tag(sync=True)
  419. stroke_width = Float(1.5).tag(sync=True, display_name='Stroke width')
  420. colors = List(trait=Color(default_value=None, allow_none=True),
  421. default_value=CATEGORY10).tag(sync=True)
  422. _view_name = Unicode('FlexLine').tag(sync=True)
  423. _model_name = Unicode('FlexLineModel').tag(sync=True)
  424. class _ScatterBase(Mark):
  425. """
  426. Base Mark for Label and Scatter
  427. """
  428. # Scaled attributes
  429. x = Array([], allow_none=True).tag(sync=True, scaled=True,
  430. rtype='Number',
  431. atype='bqplot.Axis',
  432. **array_serialization)\
  433. .valid(array_dimension_bounds(1, 1))
  434. y = Array([], allow_none=True).tag(sync=True, scaled=True,
  435. rtype='Number',
  436. atype='bqplot.Axis',
  437. **array_serialization)\
  438. .valid(array_dimension_bounds(1, 1))
  439. color = Array(None, allow_none=True).tag(sync=True,
  440. scaled=True,
  441. rtype='Color',
  442. atype='bqplot.ColorAxis',
  443. **array_serialization)\
  444. .valid(array_squeeze, array_dimension_bounds(1, 1))
  445. opacity = Array(None, allow_none=True).tag(sync=True,
  446. scaled=True,
  447. rtype='Number',
  448. **array_serialization)\
  449. .valid(array_squeeze, array_dimension_bounds(1, 1))
  450. size = Array(None, allow_none=True).tag(sync=True, scaled=True,
  451. rtype='Number',
  452. **array_serialization)\
  453. .valid(array_squeeze, array_dimension_bounds(1, 1))
  454. rotation = Array(None, allow_none=True).tag(sync=True, scaled=True,
  455. rtype='Number',
  456. **array_serialization)\
  457. .valid(array_squeeze, array_dimension_bounds(1, 1))
  458. # Other attributes
  459. scales_metadata = Dict({
  460. 'x': {'orientation': 'horizontal', 'dimension': 'x'},
  461. 'y': {'orientation': 'vertical', 'dimension': 'y'},
  462. 'color': {'dimension': 'color'},
  463. 'size': {'dimension': 'size'},
  464. 'opacity': {'dimension': 'opacity'},
  465. 'rotation': {'dimension': 'rotation'}
  466. }).tag(sync=True)
  467. default_opacities = Array([1.0])\
  468. .tag(sync=True, display_name='Opacities', **array_serialization)\
  469. .valid(array_squeeze, array_dimension_bounds(1, 1))
  470. hovered_style = Dict().tag(sync=True)
  471. unhovered_style = Dict().tag(sync=True)
  472. hovered_point = Int(None, allow_none=True).tag(sync=True)
  473. enable_move = Bool().tag(sync=True)
  474. enable_delete = Bool().tag(sync=True)
  475. restrict_x = Bool().tag(sync=True)
  476. restrict_y = Bool().tag(sync=True)
  477. update_on_move = Bool().tag(sync=True)
  478. def __init__(self, **kwargs):
  479. self._drag_start_handlers = CallbackDispatcher()
  480. self._drag_handlers = CallbackDispatcher()
  481. self._drag_end_handlers = CallbackDispatcher()
  482. super(_ScatterBase, self).__init__(**kwargs)
  483. def on_drag_start(self, callback, remove=False):
  484. self._drag_start_handlers.register_callback(callback, remove=remove)
  485. def on_drag(self, callback, remove=False):
  486. self._drag_handlers.register_callback(callback, remove=remove)
  487. def on_drag_end(self, callback, remove=False):
  488. self._drag_end_handlers.register_callback(callback, remove=remove)
  489. def _handle_custom_msgs(self, _, content, buffers=None):
  490. event = content.get('event', '')
  491. if event == 'drag_start':
  492. self._drag_start_handlers(self, content)
  493. elif event == 'drag':
  494. self._drag_handlers(self, content)
  495. elif event == 'drag_end':
  496. self._drag_end_handlers(self, content)
  497. super(_ScatterBase, self)._handle_custom_msgs(self, content)
  498. @register_mark('bqplot.Scatter')
  499. class Scatter(_ScatterBase):
  500. """Scatter mark.
  501. In the case of the Scatter mark, scales for 'x' and 'y' MUST be provided.
  502. The scales of other data attributes are optional. In the case where another
  503. data attribute than 'x' or 'y' is provided but the corresponding scale is
  504. missing, the data attribute is ignored.
  505. Attributes
  506. ----------
  507. icon: string (class-level attribute)
  508. Font-awesome icon for that mark
  509. name: string (class-level attribute)
  510. User-friendly name of the mark
  511. marker: {'circle', 'cross', 'diamond', 'square', 'triangle-down', 'triangle-up', 'arrow', 'rectangle', 'ellipse'}
  512. Marker shape
  513. colors: list of colors (default: ['steelblue'])
  514. List of colors of the markers. If the list is shorter than the number
  515. of points, the colors are reused.
  516. default_colors: Deprecated
  517. Same as `colors`, deprecated as of version 0.8.4
  518. fill: Bool (default: True)
  519. Whether to fill the markers or not
  520. stroke: Color or None (default: None)
  521. Stroke color of the marker
  522. stroke_width: Float (default: 1.5)
  523. Stroke width of the marker
  524. default_opacities: list of floats (default: [1.0])
  525. Default opacities of the markers. If the list is shorter than
  526. the number
  527. of points, the opacities are reused.
  528. default_skew: float (default: 0.5)
  529. Default skew of the marker.
  530. This number is validated to be between 0 and 1.
  531. default_size: nonnegative int (default: 64)
  532. Default marker size in pixel.
  533. If size data is provided with a scale, default_size stands for the
  534. maximal marker size (i.e. the maximum value for the 'size' scale range)
  535. drag_size: nonnegative float (default: 5.)
  536. Ratio of the size of the dragged scatter size to the default
  537. scatter size.
  538. names: numpy.ndarray (default: None)
  539. Labels for the points of the chart
  540. display_names: bool (default: True)
  541. Controls whether names are displayed for points in the scatter
  542. enable_move: bool (default: False)
  543. Controls whether points can be moved by dragging. Refer to restrict_x,
  544. restrict_y for more options.
  545. restrict_x: bool (default: False)
  546. Restricts movement of the point to only along the x axis. This is valid
  547. only when enable_move is set to True. If both restrict_x and restrict_y
  548. are set to True, the point cannot be moved.
  549. restrict_y: bool (default: False)
  550. Restricts movement of the point to only along the y axis. This is valid
  551. only when enable_move is set to True. If both restrict_x and restrict_y
  552. are set to True, the point cannot be moved.
  553. Data Attributes
  554. x: numpy.ndarray (default: [])
  555. abscissas of the data points (1d array)
  556. y: numpy.ndarray (default: [])
  557. ordinates of the data points (1d array)
  558. color: numpy.ndarray or None (default: None)
  559. color of the data points (1d array). Defaults to default_color when not
  560. provided or when a value is NaN
  561. opacity: numpy.ndarray or None (default: None)
  562. opacity of the data points (1d array). Defaults to default_opacity when
  563. not provided or when a value is NaN
  564. size: numpy.ndarray or None (default: None)
  565. size of the data points. Defaults to default_size when not provided or
  566. when a value is NaN
  567. skew: numpy.ndarray or None (default: None)
  568. skewness of the markers representing the data points. Defaults to
  569. default_skew when not provided or when a value is NaN
  570. rotation: numpy.ndarray or None (default: None)
  571. orientation of the markers representing the data points.
  572. The rotation scale's range is [0, 180]
  573. Defaults to 0 when not provided or when a value is NaN.
  574. Notes
  575. -----
  576. The fields which can be passed to the default tooltip are:
  577. All the data attributes
  578. index: index of the marker being hovered on
  579. The following are the events which can trigger interactions:
  580. click: left click of the mouse
  581. hover: mouse-over an element
  582. The following are the interactions which can be linked to the above events:
  583. tooltip: display tooltip
  584. add: add new points to the scatter (can only linked to click)
  585. """
  586. # Mark decoration
  587. icon = 'fa-cloud'
  588. name = 'Scatter'
  589. # Scaled attribtes
  590. skew = Array(None, allow_none=True).tag(sync=True, scaled=True,
  591. rtype='Number',
  592. **array_serialization)\
  593. .valid(array_squeeze, array_dimension_bounds(1, 1))
  594. # Other attributes
  595. marker = Enum(['circle', 'cross', 'diamond', 'square', 'triangle-down',
  596. 'triangle-up', 'arrow', 'rectangle', 'ellipse'],
  597. default_value='circle').tag(sync=True, display_name='Marker')
  598. colors = List(trait=Color(default_value=None, allow_none=True),
  599. default_value=['steelblue'])\
  600. .tag(sync=True, display_name='Colors')
  601. scales_metadata = Dict({
  602. 'x': {'orientation': 'horizontal', 'dimension': 'x'},
  603. 'y': {'orientation': 'vertical', 'dimension': 'y'},
  604. 'color': {'dimension': 'color'},
  605. 'size': {'dimension': 'size'},
  606. 'opacity': {'dimension': 'opacity'},
  607. 'rotation': {'dimension': 'rotation'},
  608. 'skew': {'dimension': 'skew'}
  609. }).tag(sync=True)
  610. @property
  611. def default_colors(self):
  612. return self.colors
  613. @default_colors.setter
  614. def default_colors(self, value):
  615. warn("default_colors is deprecated, use colors instead.",
  616. DeprecationWarning)
  617. self.colors = value
  618. stroke = Color(None, allow_none=True).tag(sync=True,
  619. display_name='Stroke color')
  620. stroke_width = Float(1.5).tag(sync=True, display_name='Stroke width')
  621. default_skew = Float(0.5, min=0, max=1).tag(sync=True)
  622. default_size = Int(64).tag(sync=True, display_name='Default size')
  623. names = Array(None, allow_none=True)\
  624. .tag(sync=True, **array_serialization).valid(array_squeeze)
  625. display_names = Bool(True).tag(sync=True, display_name='Display names')
  626. fill = Bool(True).tag(sync=True)
  627. drag_color = Color(None, allow_none=True).tag(sync=True)
  628. drag_size = Float(5.).tag(sync=True)
  629. names_unique = Bool(True).tag(sync=True)
  630. _view_name = Unicode('Scatter').tag(sync=True)
  631. _model_name = Unicode('ScatterModel').tag(sync=True)
  632. @register_mark('bqplot.ScatterGL')
  633. class ScatterGL(Scatter):
  634. _view_name = Unicode('ScatterGL').tag(sync=True)
  635. _model_name = Unicode('ScatterGLModel').tag(sync=True)
  636. @register_mark('bqplot.Label')
  637. class Label(_ScatterBase):
  638. """Label mark.
  639. Attributes
  640. ----------
  641. x_offset: int (default: 0)
  642. horizontal offset in pixels from the stated x location
  643. y_offset: int (default: 0)
  644. vertical offset in pixels from the stated y location
  645. text: string (default: '')
  646. text to be displayed
  647. default_size: string (default: '14px')
  648. font size in px, em or ex
  649. font_weight: {'bold', 'normal', 'bolder'}
  650. font weight of the caption
  651. drag_size: nonnegative float (default: 1.)
  652. Ratio of the size of the dragged label font size to the default
  653. label font size.
  654. align: {'start', 'middle', 'end'}
  655. alignment of the text with respect to the provided location
  656. enable_move: Bool (default: False)
  657. Enable the label to be moved by dragging. Refer to restrict_x,
  658. restrict_y for more options.
  659. restrict_x: bool (default: False)
  660. Restricts movement of the label to only along the x axis. This is valid
  661. only when enable_move is set to True. If both restrict_x and restrict_y
  662. are set to True, the label cannot be moved.
  663. restrict_y: bool (default: False)
  664. Restricts movement of the label to only along the y axis. This is valid
  665. only when enable_move is set to True. If both restrict_x and restrict_y
  666. are set to True, the label cannot be moved.
  667. Data Attributes
  668. x: numpy.ndarray (default: [])
  669. horizontal position of the labels, in data coordinates or in
  670. figure coordinates
  671. y: numpy.ndarray (default: [])
  672. vertical position of the labels, in data coordinates or in
  673. figure coordinates
  674. color: numpy.ndarray or None (default: None)
  675. label colors
  676. size: numpy.ndarray or None (default: None)
  677. label sizes
  678. rotation: numpy.ndarray or None (default: None)
  679. label rotations
  680. opacity: numpy.ndarray or None (default: None)
  681. label opacities
  682. """
  683. # Mark decoration
  684. icon = 'fa-font'
  685. name = 'Labels'
  686. # Other attributes
  687. x_offset = Int(0).tag(sync=True)
  688. y_offset = Int(0).tag(sync=True)
  689. colors = List(trait=Color(default_value=None,
  690. allow_none=True),
  691. default_value=CATEGORY10)\
  692. .tag(sync=True, display_name='Colors')
  693. rotate_angle = Float(0.0).tag(sync=True)
  694. text = Array(None, allow_none=True)\
  695. .tag(sync=True, **array_serialization).valid(array_squeeze)
  696. default_size = Float(16.).tag(sync=True)
  697. drag_size = Float(1.).tag(sync=True)
  698. font_unit = Enum(['px', 'em', 'pt', '%'],
  699. default_value='px').tag(sync=True)
  700. font_weight = Enum(['bold', 'normal', 'bolder'],
  701. default_value='bold').tag(sync=True)
  702. align = Enum(['start', 'middle', 'end'],
  703. default_value='start').tag(sync=True)
  704. _view_name = Unicode('Label').tag(sync=True)
  705. _model_name = Unicode('LabelModel').tag(sync=True)
  706. @register_mark('bqplot.Hist')
  707. class Hist(Mark):
  708. """Histogram mark.
  709. In the case of the Hist mark, scales for 'sample' and 'count' MUST be
  710. provided.
  711. Attributes
  712. ----------
  713. icon: string (class-level attribute)
  714. font-awesome icon for that mark
  715. name: string (class-level attribute)
  716. user-friendly name of the mark
  717. bins: nonnegative int (default: 10)
  718. number of bins in the histogram
  719. normalized: bool (default: False)
  720. Boolean attribute to return normalized values which
  721. sum to 1 or direct counts for the `count` attribute. The scale of
  722. `count` attribute is determined by the value of this flag.
  723. colors: list of colors (default: ['steelblue'])
  724. List of colors of the Histogram. If the list is shorter than the number
  725. of bins, the colors are reused.
  726. stroke: Color or None (default: None)
  727. Stroke color of the histogram
  728. opacities: list of floats (default: [])
  729. Opacity for the bins of the histogram. Defaults to 1 when the list
  730. is too short, or the element of the list is set to None.
  731. midpoints: list (default: [])
  732. midpoints of the bins of the histogram. It is a read-only attribute.
  733. Data Attributes
  734. sample: numpy.ndarray (default: [])
  735. sample of which the histogram must be computed.
  736. count: numpy.ndarray (read-only)
  737. number of sample points per bin. It is a read-only attribute.
  738. Notes
  739. -----
  740. The fields which can be passed to the default tooltip are:
  741. midpoint: mid-point of the bin related to the rectangle hovered on
  742. count: number of elements in the bin hovered on
  743. bin_start: start point of the bin
  744. bin-end: end point of the bin
  745. index: index of the bin
  746. """
  747. # Mark decoration
  748. icon = 'fa-signal'
  749. name = 'Histogram'
  750. # Scaled attributes
  751. sample = Array([]).tag(sync=True, display_name='Sample',
  752. scaled=True, rtype='Number',
  753. atype='bqplot.Axis',
  754. **array_serialization)\
  755. .valid(array_squeeze, array_dimension_bounds(1, 1))
  756. count = Array([], read_only=True).tag(sync=True,
  757. display_name='Count',
  758. scaled=True,
  759. rtype='Number',
  760. atype='bqplot.Axis',
  761. **array_serialization)\
  762. .valid(array_squeeze)
  763. normalized = Bool().tag(sync=True)
  764. # Other attributes
  765. scales_metadata = Dict({
  766. 'sample': {'orientation': 'horizontal', 'dimension': 'x'},
  767. 'count': {'orientation': 'vertical', 'dimension': 'y'}
  768. }).tag(sync=True)
  769. bins = Int(10).tag(sync=True, display_name='Number of bins')
  770. midpoints = List(read_only=True).tag(sync=True, display_name='Mid points')
  771. # midpoints is a read-only attribute that is set when the mark is drawn
  772. colors = List(trait=Color(default_value=None, allow_none=True),
  773. default_value=['steelblue'])\
  774. .tag(sync=True, display_name='Colors')
  775. stroke = Color(None, allow_none=True).tag(sync=True)
  776. opacities = List(trait=Float(1.0, min=0, max=1, allow_none=True))\
  777. .tag(sync=True, display_name='Opacities')
  778. _view_name = Unicode('Hist').tag(sync=True)
  779. _model_name = Unicode('HistModel').tag(sync=True)
  780. @register_mark('bqplot.Boxplot')
  781. class Boxplot(Mark):
  782. """Boxplot marks.
  783. Attributes
  784. ----------
  785. stroke: Color or None
  786. stroke color of the marker
  787. color: Color
  788. fill color of the box
  789. opacities: list of floats (default: [])
  790. Opacities for the markers of the boxplot. Defaults to 1 when the
  791. list is too short, or the element of the list is set to None.
  792. outlier-color: color
  793. color for the outlier
  794. box_width: int (default: None)
  795. width of the box in pixels. The minimum value is 5.
  796. If set to None, box_with is auto calculated
  797. auto_detect_outliers: bool (default: True)
  798. Flag to toggle outlier auto-detection
  799. Data Attributes
  800. x: numpy.ndarray (default: [])
  801. abscissas of the data points (1d array)
  802. y: numpy.ndarray (default: [[]])
  803. Sample data points (2d array)
  804. """
  805. # Mark decoration
  806. icon = 'fa-birthday-cake'
  807. name = 'Boxplot chart'
  808. # Scaled attributes
  809. x = Array([]).tag(sync=True, scaled=True, rtype='Number',
  810. atype='bqplot.Axis', **array_serialization)\
  811. .valid(array_squeeze, array_dimension_bounds(1, 1))
  812. # Second dimension must contain OHLC data, otherwise the behavior
  813. # is undefined.
  814. y = Array([[]]).tag(sync=True, scaled=True, rtype='Number',
  815. atype='bqplot.Axis', **array_serialization)\
  816. .valid(array_dimension_bounds(1, 2), array_supported_kinds())
  817. # Other attributes
  818. scales_metadata = Dict({
  819. 'x': {'orientation': 'horizontal', 'dimension': 'x'},
  820. 'y': {'orientation': 'vertical', 'dimension': 'y'}
  821. }).tag(sync=True)
  822. stroke = Color(None, allow_none=True)\
  823. .tag(sync=True, display_name='Stroke color')
  824. box_fill_color = Color('steelblue', sync=True,
  825. display_name='Fill color for the box')
  826. outlier_fill_color = Color('gray').tag(sync=True,
  827. display_name='Outlier fill color')
  828. opacities = List(trait=Float(1.0, min=0, max=1, allow_none=True))\
  829. .tag(sync=True, display_name='Opacities')
  830. box_width = Int(None, min=5, allow_none=True).tag(sync=True, display_name='Box Width')
  831. auto_detect_outliers = Bool(True).tag(sync=True, display_name='Auto-detect Outliers')
  832. _view_name = Unicode('Boxplot').tag(sync=True)
  833. _model_name = Unicode('BoxplotModel').tag(sync=True)
  834. @register_mark('bqplot.Bars')
  835. class Bars(Mark):
  836. """Bar mark.
  837. In the case of the Bars mark, scales for 'x' and 'y' MUST be provided.
  838. The scales of other data attributes are optional. In the case where another
  839. data attribute than 'x' or 'y' is provided but the corresponding scale is
  840. missing, the data attribute is ignored.
  841. Attributes
  842. ----------
  843. icon: string (class-level attribute)
  844. font-awesome icon for that mark
  845. name: string (class-level attribute)
  846. user-friendly name of the mark
  847. color_mode: {'auto', 'group', 'element'}
  848. enum attribute to specify if color should be the same for all bars with
  849. the same x or for all bars which belong to the same array in Y
  850. 'group' means for every x all bars have same color.
  851. 'element' means for every dimension of y, all bars have same color.
  852. 'auto' picks 'group' and 'element' for 1-d and 2-d values of
  853. Y respectively.
  854. type: {'stacked', 'grouped'}
  855. whether 2-dimensional bar charts should appear grouped or stacked.
  856. colors: list of colors (default: ['steelblue'])
  857. list of colors for the bars.
  858. orientation: {'horizontal', 'vertical'}
  859. Specifies whether the bar chart is drawn horizontally or vertically.
  860. If a horizontal bar chart is drawn, the x data is drawn vertically.
  861. padding: float (default: 0.05)
  862. Attribute to control the spacing between the bars value is specified
  863. as a percentage of the width of the bar
  864. fill: Bool (default: True)
  865. Whether to fill the bars or not
  866. stroke: Color or None (default: None)
  867. Stroke color for the bars
  868. stroke_width: Float (default: 0.)
  869. Stroke width of the bars
  870. opacities: list of floats (default: [])
  871. Opacities for the bars. Defaults to 1 when the list is too
  872. short, or the element of the list is set to None.
  873. base: float (default: 0.0)
  874. reference value from which the bars are drawn. defaults to 0.0
  875. align: {'center', 'left', 'right'}
  876. alignment of bars with respect to the tick value
  877. label_display: bool (default: False)
  878. whether or not to display bar data labels
  879. label_display_format: string (default: .2f)
  880. format for displaying values.
  881. label_font_style: dict
  882. CSS style for the text of each cell
  883. label_display_vertical_offset: float
  884. vertical offset value for the label display
  885. label_display_horizontal_offset: float
  886. horizontal offset value for the label display
  887. Data Attributes
  888. x: numpy.ndarray (default: [])
  889. abscissas of the data points (1d array)
  890. y: numpy.ndarray (default: [])
  891. ordinates of the values for the data points
  892. color: numpy.ndarray or None (default: None)
  893. color of the data points (1d array). Defaults to default_color when not
  894. provided or when a value is NaN
  895. Notes
  896. -----
  897. The fields which can be passed to the default tooltip are:
  898. All the data attributes
  899. index: index of the bar being hovered on
  900. sub_index: if data is two dimensional, this is the minor index
  901. """
  902. # Mark decoration
  903. icon = 'fa-bar-chart'
  904. name = 'Bar chart'
  905. # Scaled attributes
  906. x = Array([]).tag(sync=True, scaled=True, rtype='Number',
  907. atype='bqplot.Axis',
  908. **array_serialization)\
  909. .valid(array_squeeze, array_dimension_bounds(1, 1))
  910. y = Array([]).tag(sync=True, scaled=True, rtype='Number',
  911. atype='bqplot.Axis',
  912. **array_serialization)\
  913. .valid(array_dimension_bounds(1, 2), array_supported_kinds())
  914. color = Array(None, allow_none=True)\
  915. .tag(sync=True, scaled=True, rtype='Color',
  916. atype='bqplot.ColorAxis', **array_serialization)\
  917. .valid(array_squeeze, array_dimension_bounds(1, 1))
  918. # Bar text labels attributes -- add default values.
  919. # Add bool for displaying a label or not. Add d3 formatting in docstring
  920. label_display = Bool(default_value=False).tag(sync=True)
  921. label_display_format = Unicode(default_value=".2f",
  922. allow_none=False).tag(sync=True)
  923. label_font_style = Dict().tag(sync=True)
  924. label_display_vertical_offset = Float(default_value=0.0,
  925. allow_none=False).tag(sync=True)
  926. label_display_horizontal_offset = Float(default_value=0.0,
  927. allow_none=False).tag(sync=True)
  928. # Other attributes
  929. scales_metadata = Dict({
  930. 'x': {'orientation': 'horizontal', 'dimension': 'x'},
  931. 'y': {'orientation': 'vertical', 'dimension': 'y'},
  932. 'color': {'dimension': 'color'}
  933. }).tag(sync=True)
  934. color_mode = Enum(['auto', 'group', 'element'], default_value='auto')\
  935. .tag(sync=True)
  936. type = Enum(['stacked', 'grouped'], default_value='stacked')\
  937. .tag(sync=True, display_name='Type')
  938. colors = List(trait=Color(default_value=None,
  939. allow_none=True),
  940. default_value=['steelblue'])\
  941. .tag(sync=True, display_name='Colors')
  942. padding = Float(0.05).tag(sync=True)
  943. fill = Bool(True).tag(sync=True)
  944. stroke = Color(None, allow_none=True).tag(sync=True)
  945. stroke_width = Float(1.).tag(sync=True, display_name='Stroke width')
  946. base = Float().tag(sync=True)
  947. opacities = List(trait=Float(1.0, min=0, max=1, allow_none=True))\
  948. .tag(sync=True, display_name='Opacities')
  949. align = Enum(['center', 'left', 'right'], default_value='center')\
  950. .tag(sync=True)
  951. orientation = Enum(['vertical', 'horizontal'], default_value='vertical')\
  952. .tag(sync=True)
  953. @validate('orientation')
  954. def _validate_orientation(self, proposal):
  955. value = proposal['value']
  956. x_orient = "horizontal" if value == "vertical" else "vertical"
  957. self.scales_metadata = {'x': {'orientation': x_orient,
  958. 'dimension': 'x'},
  959. 'y': {'orientation': value, 'dimension': 'y'}}
  960. return value
  961. _view_name = Unicode('Bars').tag(sync=True)
  962. _model_name = Unicode('BarsModel').tag(sync=True)
  963. @register_mark('bqplot.Bins')
  964. class Bins(Bars):
  965. """Backend histogram mark.
  966. A `Bars` instance that bins sample data.
  967. It is very similar in purpose to the `Hist` mark, the difference being that
  968. the binning is done in the backend (python), which avoids large amounts of
  969. data being shipped back and forth to the frontend. It should therefore be
  970. preferred for large data.
  971. The binning method is the numpy `histogram` method.
  972. The following documentation is in part taken from the numpy documentation.
  973. Attributes
  974. ----------
  975. icon: string (class-level attribute)
  976. font-awesome icon for that mark
  977. name: string (class-level attribute)
  978. user-friendly name of the mark
  979. bins: nonnegative int (default: 10)
  980. or {'auto', 'fd', 'doane', 'scott', 'rice', 'sturges', 'sqrt'}
  981. If `bins` is an int, it defines the number of equal-width
  982. bins in the given range (10, by default).
  983. If `bins` is a string (method name), `histogram` will use
  984. the method chosen to calculate the optimal bin width and
  985. consequently the number of bins (see `Notes` for more detail on
  986. the estimators) from the data that falls within the requested
  987. range.
  988. density : bool (default: `False`)
  989. If `False`, the height of each bin is the number of samples in it.
  990. If `True`, the height of each bin is the value of the
  991. probability *density* function at the bin, normalized such that
  992. the *integral* over the range is 1. Note that the sum of the
  993. histogram values will not be equal to 1 unless bins of unity
  994. width are chosen; it is not a probability *mass* function.
  995. min : float (default: None)
  996. The lower range of the bins. If not provided, lower range
  997. is simply `x.min()`.
  998. max : float (default: None)
  999. The upper range of the bins. If not provided, lower range
  1000. is simply `x.max()`.
  1001. Data Attributes
  1002. sample: numpy.ndarray (default: [])
  1003. sample of which the histogram must be computed.
  1004. Notes
  1005. -----
  1006. The fields which can be passed to the default tooltip are:
  1007. All the `Bars` data attributes (`x`, `y`, `color`)
  1008. index: index of the bin
  1009. """
  1010. # Mark decoration
  1011. icon = 'fa-signal'
  1012. name = 'Backend Histogram'
  1013. # Scaled Attributes
  1014. sample = Array([]).tag(
  1015. sync=False, display_name='Sample', rtype='Number',
  1016. atype='bqplot.Axis', **array_serialization)\
  1017. .valid(array_squeeze, array_dimension_bounds(1, 1))
  1018. # Binning options
  1019. min = Float(None, allow_none=True).tag(sync=True)
  1020. max = Float(None, allow_none=True).tag(sync=True)
  1021. density = Bool().tag(sync=True)
  1022. bins = (Int(10) | List() | Enum(['auto', 'fd', 'doane',
  1023. 'scott', 'rice', 'sturges', 'sqrt']))\
  1024. .tag(sync=True, display_name='Number of bins')
  1025. def __init__(self, **kwargs):
  1026. '''
  1027. Sets listeners on the data and the binning parameters.
  1028. Adjusts `Bars` defaults to suit a histogram better.
  1029. '''
  1030. self.observe(self.bin_data,
  1031. names=['sample', 'bins', 'density', 'min', 'max'])
  1032. # One unique color by default
  1033. kwargs.setdefault('colors', [CATEGORY10[0]])
  1034. # No spacing between bars
  1035. kwargs.setdefault('padding', 0.)
  1036. super(Bins, self).__init__(**kwargs)
  1037. def bin_data(self, *args):
  1038. '''
  1039. Performs the binning of `sample` data, and draws the corresponding bars
  1040. '''
  1041. # Get range
  1042. _min = self.sample.min() if self.min is None else self.min
  1043. _max = self.sample.max() if self.max is None else self.max
  1044. _range = (min(_min, _max), max(_min, _max))
  1045. # Bin the samples
  1046. counts, bin_edges = histogram(self.sample, bins=self.bins,
  1047. range=_range, density=self.density)
  1048. midpoints = (bin_edges[:-1] + bin_edges[1:]) / 2
  1049. # Redraw the underlying Bars
  1050. with self.hold_sync():
  1051. self.x, self.y = midpoints, counts
  1052. @register_mark('bqplot.OHLC')
  1053. class OHLC(Mark):
  1054. """Open/High/Low/Close marks.
  1055. Attributes
  1056. ----------
  1057. icon: string (class-level attribute)
  1058. font-awesome icon for that mark
  1059. name: string (class-level attribute)
  1060. user-friendly name of the mark
  1061. marker: {'candle', 'bar'}
  1062. marker type
  1063. stroke: color (default: None)
  1064. stroke color of the marker
  1065. stroke_width: float (default: 1.0)
  1066. stroke width of the marker
  1067. colors: List of colors (default: ['limegreen', 'red'])
  1068. fill colors for the markers (up/down)
  1069. opacities: list of floats (default: [])
  1070. Opacities for the markers of the OHLC mark. Defaults to 1 when
  1071. the list is too short, or the element of the list is set to None.
  1072. format: string (default: 'ohlc')
  1073. description of y data being passed
  1074. supports all permutations of the strings 'ohlc', 'oc', and 'hl'
  1075. Data Attributes
  1076. x: numpy.ndarray
  1077. abscissas of the data points (1d array)
  1078. y: numpy.ndarrays
  1079. Open/High/Low/Close ordinates of the data points (2d array)
  1080. Notes
  1081. -----
  1082. The fields which can be passed to the default tooltip are:
  1083. x: the x value associated with the bar/candle
  1084. open: open value for the bar/candle
  1085. high: high value for the bar/candle
  1086. low: low value for the bar/candle
  1087. close: close value for the bar/candle
  1088. index: index of the bar/candle being hovered on
  1089. """
  1090. # Mark decoration
  1091. icon = 'fa-birthday-cake'
  1092. name = 'OHLC chart'
  1093. # Scaled attributes
  1094. x = Array([]).tag(sync=True, scaled=True,
  1095. rtype='Number', atype='bqplot.Axis',
  1096. **array_serialization)\
  1097. .valid(array_squeeze, array_dimension_bounds(1, 1))
  1098. y = Array([[]]).tag(sync=True, scaled=True,
  1099. rtype='Number', atype='bqplot.Axis',
  1100. **array_serialization)\
  1101. .valid(array_dimension_bounds(1, 2))
  1102. # Other attributes
  1103. scales_metadata = Dict({
  1104. 'x': {'orientation': 'horizontal', 'dimension': 'x'},
  1105. 'y': {'orientation': 'vertical', 'dimension': 'y'}
  1106. }).tag(sync=True)
  1107. marker = Enum(['candle', 'bar'], default_value='candle',
  1108. display_name='Marker').tag(sync=True)
  1109. stroke = Color(None, display_name='Stroke color', allow_none=True)\
  1110. .tag(sync=True)
  1111. stroke_width = Float(1.0).tag(sync=True, display_name='Stroke Width')
  1112. colors = List(trait=Color(default_value=None, allow_none=True),
  1113. default_value=['green', 'red'])\
  1114. .tag(sync=True, display_name='Colors')
  1115. opacities = List(trait=Float(1.0, min=0, max=1, allow_none=True))\
  1116. .tag(sync=True, display_name='Opacities')
  1117. format = Unicode('ohlc').tag(sync=True, display_name='Format')
  1118. _view_name = Unicode('OHLC').tag(sync=True)
  1119. _model_name = Unicode('OHLCModel').tag(sync=True)
  1120. @register_mark('bqplot.Pie')
  1121. class Pie(Mark):
  1122. """Piechart mark.
  1123. Attributes
  1124. ----------
  1125. colors: list of colors (default: CATEGORY10)
  1126. list of colors for the slices.
  1127. stroke: color (default: 'white')
  1128. stroke color for the marker
  1129. opacities: list of floats (default: [])
  1130. Opacities for the slices of the Pie mark. Defaults to 1 when the list
  1131. is too short, or the element of the list is set to None.
  1132. sort: bool (default: False)
  1133. sort the pie slices by descending sizes
  1134. x: Float (default: 0.5) or Date
  1135. horizontal position of the pie center, in data coordinates or in figure
  1136. coordinates
  1137. y: Float (default: 0.5)
  1138. vertical y position of the pie center, in data coordinates or in figure
  1139. coordinates
  1140. radius: Float
  1141. radius of the pie, in pixels
  1142. inner_radius: Float
  1143. inner radius of the pie, in pixels
  1144. start_angle: Float (default: 0.0)
  1145. start angle of the pie (from top), in degrees
  1146. end_angle: Float (default: 360.0)
  1147. end angle of the pie (from top), in degrees
  1148. display_labels: {'none', 'inside', 'outside'} (default: 'inside')
  1149. label display options
  1150. display_values: bool (default: False)
  1151. if True show values along with labels
  1152. values_format: string (default: '.2f')
  1153. format for displaying values
  1154. label_color: Color or None (default: None)
  1155. color of the labels
  1156. font_size: string (default: '14px')
  1157. label font size in px, em or ex
  1158. font_weight: {'bold', 'normal', 'bolder'} (default: 'normal')
  1159. label font weight
  1160. Data Attributes
  1161. sizes: numpy.ndarray (default: [])
  1162. proportions of the pie slices
  1163. color: numpy.ndarray or None (default: None)
  1164. color of the data points. Defaults to colors when not provided.
  1165. Notes
  1166. -----
  1167. The fields which can be passed to the default tooltip are:
  1168. : the x value associated with the bar/candle
  1169. open: open value for the bar/candle
  1170. high: high value for the bar/candle
  1171. low: low value for the bar/candle
  1172. close: close value for the bar/candle
  1173. index: index of the bar/candle being hovered on
  1174. """
  1175. # Mark decoration
  1176. icon = 'fa-pie-chart'
  1177. name = 'Pie chart'
  1178. # Scaled attributes
  1179. sizes = Array([]).tag(sync=True, rtype='Number', **array_serialization)\
  1180. .valid(array_squeeze, array_dimension_bounds(1, 1))
  1181. color = Array(None, allow_none=True).tag(sync=True,
  1182. scaled=True,
  1183. rtype='Color',
  1184. atype='bqplot.ColorAxis',
  1185. **array_serialization)\
  1186. .valid(array_squeeze, array_dimension_bounds(1, 1))
  1187. # Other attributes
  1188. x = (Float(0.5) | Date() | Unicode()).tag(sync=True)
  1189. y = (Float(0.5) | Date() | Unicode()).tag(sync=True)
  1190. scales_metadata = Dict({'color': {'dimension': 'color'}}).tag(sync=True)
  1191. sort = Bool().tag(sync=True)
  1192. colors = List(trait=Color(default_value=None, allow_none=True),
  1193. default_value=CATEGORY10).tag(sync=True,
  1194. display_name='Colors')
  1195. stroke = Color(None, allow_none=True).tag(sync=True)
  1196. opacities = List(trait=Float(1.0, min=0, max=1, allow_none=True))\
  1197. .tag(sync=True, display_name='Opacities')
  1198. radius = Float(180.0, min=0.0, max=float('inf')).tag(sync=True)
  1199. inner_radius = Float(0.1, min=0.0, max=float('inf')).tag(sync=True)
  1200. start_angle = Float().tag(sync=True)
  1201. end_angle = Float(360.0).tag(sync=True)
  1202. display_labels = Enum(['none', 'inside', 'outside'],
  1203. default_value='inside').tag(sync=True)
  1204. display_values = Bool(False).tag(sync=True)
  1205. values_format = Unicode(default_value='.1f').tag(sync=True)
  1206. label_color = Color(None, allow_none=True).tag(sync=True)
  1207. font_size = Unicode(default_value='12px').tag(sync=True)
  1208. font_weight = Enum(['bold', 'normal', 'bolder'],
  1209. default_value='normal').tag(sync=True)
  1210. _view_name = Unicode('Pie').tag(sync=True)
  1211. _model_name = Unicode('PieModel').tag(sync=True)
  1212. def topo_load(name):
  1213. with open(os.path.join(os.path.split(os.path.realpath(__file__))[0],
  1214. name)) as data_file:
  1215. data = json.load(data_file)
  1216. return data
  1217. @register_mark('bqplot.Map')
  1218. class Map(Mark):
  1219. """Map mark.
  1220. Attributes
  1221. ----------
  1222. colors: Dict (default: {})
  1223. default colors for items of the map when no color data is passed.
  1224. The dictionary should be indexed by the id of the element and have
  1225. the corresponding colors as values. The key `default_color`
  1226. controls the items for which no color is specified.
  1227. selected_styles: Dict (default: {'selected_fill': 'Red',
  1228. 'selected_stroke': None, 'selected_stroke_width': 2.0})
  1229. Dictionary containing the styles for selected subunits
  1230. hovered_styles: Dict (default: {'hovered_fill': 'Orange',
  1231. 'hovered_stroke': None, 'hovered_stroke_width': 2.0})
  1232. Dictionary containing the styles for hovered subunits
  1233. hover_highlight: bool (default: True)
  1234. boolean to control if the map should be aware of which country is being
  1235. hovered on.
  1236. map_data: dict (default: topo_load("map_data/WorldMap.json"))
  1237. a topojson-formatted dictionary with the objects to map under the key
  1238. 'subunits'.
  1239. Data Attributes
  1240. color: Dict or None (default: None)
  1241. dictionary containing the data associated with every country for the
  1242. color scale
  1243. """
  1244. # Mark decoration
  1245. icon = 'fa-globe'
  1246. name = 'Map'
  1247. # Scaled attributes
  1248. color = Dict(allow_none=True).tag(sync=True, scaled=True, rtype='Color',
  1249. atype='bqplot.ColorAxis')
  1250. # Other attributes
  1251. scales_metadata = Dict({'color': {'dimension': 'color'}}).tag(sync=True)
  1252. hover_highlight = Bool(True).tag(sync=True)
  1253. hovered_styles = Dict({
  1254. 'hovered_fill': 'Orange',
  1255. 'hovered_stroke': None,
  1256. 'hovered_stroke_width': 2.0}, allow_none=True).tag(sync=True)
  1257. stroke_color = Color(default_value=None, allow_none=True).tag(sync=True)
  1258. colors = Dict().tag(sync=True, display_name='Colors')
  1259. scales_metadata = Dict({'color': {'dimension': 'color'},
  1260. 'projection': {'dimension': 'geo'}}).tag(sync=True)
  1261. selected_styles = Dict({
  1262. 'selected_fill': 'Red',
  1263. 'selected_stroke': None,
  1264. 'selected_stroke_width': 2.0
  1265. }).tag(sync=True)
  1266. map_data = Dict(topo_load('map_data/WorldMap.json')).tag(sync=True)
  1267. _view_name = Unicode('Map').tag(sync=True)
  1268. _model_name = Unicode('MapModel').tag(sync=True)
  1269. @register_mark('bqplot.GridHeatMap')
  1270. class GridHeatMap(Mark):
  1271. """GridHeatMap mark.
  1272. Alignment: The tiles can be aligned so that the data matches either the
  1273. start, the end or the midpoints of the tiles. This is controlled by the
  1274. align attribute.
  1275. Suppose the data passed is a m-by-n matrix. If the scale for the rows is
  1276. Ordinal, then alignment is by default the mid points. For a non-ordinal
  1277. scale, the data cannot be aligned to the mid points of the rectangles.
  1278. If it is not ordinal, then two cases arise. If the number of rows passed
  1279. is m, then align attribute can be used. If the number of rows passed
  1280. is m+1, then the data are the boundaries of the m rectangles.
  1281. If rows and columns are not passed, and scales for them are also
  1282. not passed, then ordinal scales are generated for the rows and columns.
  1283. Attributes
  1284. ----------
  1285. row_align: Enum(['start', 'end'])
  1286. This is only valid if the number of entries in `row` exactly match the
  1287. number of rows in `color` and the `row_scale` is not `OrdinalScale`.
  1288. `start` aligns the row values passed to be aligned with the start
  1289. of the tiles and `end` aligns the row values to the end of the tiles.
  1290. column_align: Enum(['start', end'])
  1291. This is only valid if the number of entries in `column` exactly
  1292. match the number of columns in `color` and the `column_scale` is
  1293. not `OrdinalScale`. `start` aligns the column values passed to
  1294. be aligned with the start of the tiles and `end` aligns the
  1295. column values to the end of the tiles.
  1296. anchor_style: dict (default: {})
  1297. Controls the style for the element which serves as the anchor during
  1298. selection.
  1299. display_format: string (default: None)
  1300. format for displaying values. If None, then values are not displayed
  1301. font_style: dict
  1302. CSS style for the text of each cell
  1303. Data Attributes
  1304. color: numpy.ndarray or None (default: None)
  1305. color of the data points (2d array). The number of elements in
  1306. this array correspond to the number of cells created in the heatmap.
  1307. row: numpy.ndarray or None (default: None)
  1308. labels for the rows of the `color` array passed. The length of
  1309. this can be no more than 1 away from the number of rows in `color`.
  1310. This is a scaled attribute and can be used to affect the height of the
  1311. cells as the entries of `row` can indicate the start or the end points
  1312. of the cells. Refer to the property `row_align`.
  1313. If this property is None, then a uniformly spaced grid is generated in
  1314. the row direction.
  1315. column: numpy.ndarray or None (default: None)
  1316. labels for the columns of the `color` array passed. The length of
  1317. this can be no more than 1 away from the number of columns in `color`
  1318. This is a scaled attribute and can be used to affect the width of the
  1319. cells as the entries of `column` can indicate the start or the
  1320. end points of the cells. Refer to the property `column_align`.
  1321. If this property is None, then a uniformly spaced grid is generated in
  1322. the column direction.
  1323. """
  1324. # Scaled attributes
  1325. row = Array(None, allow_none=True).tag(sync=True, scaled=True,
  1326. rtype='Number',
  1327. atype='bqplot.Axis',
  1328. **array_serialization)\
  1329. .valid(array_squeeze, array_dimension_bounds(1, 1))
  1330. column = Array(None, allow_none=True).tag(sync=True, scaled=True,
  1331. rtype='Number',
  1332. atype='bqplot.Axis',
  1333. **array_serialization)\
  1334. .valid(array_squeeze, array_dimension_bounds(1, 1))
  1335. color = Array(None, allow_none=True).tag(sync=True, scaled=True,
  1336. rtype='Color',
  1337. atype='bqplot.ColorAxis',
  1338. **array_serialization)\
  1339. .valid(array_squeeze, array_dimension_bounds(1, 2))
  1340. # Other attributes
  1341. scales_metadata = Dict({
  1342. 'row': {'orientation': 'vertical', 'dimension': 'y'},
  1343. 'column': {'orientation': 'horizontal', 'dimension': 'x'},
  1344. 'color': {'dimension': 'color'}
  1345. }).tag(sync=True)
  1346. row_align = Enum(['start', 'end'], default_value='start').tag(sync=True)
  1347. column_align = Enum(['start', 'end'], default_value='start').tag(sync=True)
  1348. null_color = Color('black', allow_none=True).tag(sync=True)
  1349. stroke = Color('black', allow_none=True).tag(sync=True)
  1350. opacity = Float(1.0, min=0.2, max=1).tag(sync=True, display_name='Opacity')
  1351. anchor_style = Dict().tag(sync=True)
  1352. display_format = Unicode(default_value=None, allow_none=True)\
  1353. .tag(sync=True)
  1354. font_style = Dict().tag(sync=True)
  1355. def __init__(self, **kwargs):
  1356. # Adding scales in case they are not passed too.
  1357. scales = kwargs.pop('scales', {})
  1358. if(scales.get('row', None) is None):
  1359. row_scale = OrdinalScale(reverse=True)
  1360. scales['row'] = row_scale
  1361. if(scales.get('column', None) is None):
  1362. column_scale = OrdinalScale()
  1363. scales['column'] = column_scale
  1364. kwargs['scales'] = scales
  1365. super(GridHeatMap, self).__init__(**kwargs)
  1366. @validate('row')
  1367. def _validate_row(self, proposal):
  1368. row = proposal.value
  1369. if row is None:
  1370. return row
  1371. color = np.asarray(self.color)
  1372. n_rows = color.shape[0]
  1373. if len(row) != n_rows and len(row) != n_rows + 1 and len(row) != n_rows - 1:
  1374. raise TraitError('row must be an array of size color.shape[0]')
  1375. return row
  1376. @validate('column')
  1377. def _validate_column(self, proposal):
  1378. column = proposal.value
  1379. if column is None:
  1380. return column
  1381. color = np.asarray(self.color)
  1382. n_columns = color.shape[1]
  1383. if len(column) != n_columns and len(column) != n_columns + 1 and len(column) != n_columns - 1:
  1384. raise TraitError('column must be an array of size color.shape[1]')
  1385. return column
  1386. _view_name = Unicode('GridHeatMap').tag(sync=True)
  1387. _model_name = Unicode('GridHeatMapModel').tag(sync=True)
  1388. @register_mark('bqplot.HeatMap')
  1389. class HeatMap(Mark):
  1390. """HeatMap mark.
  1391. Attributes
  1392. ----------
  1393. Data Attributes
  1394. color: numpy.ndarray or None (default: None)
  1395. color of the data points (2d array).
  1396. x: numpy.ndarray or None (default: None)
  1397. labels for the columns of the `color` array passed. The length of
  1398. this has to be the number of columns in `color`.
  1399. This is a scaled attribute.
  1400. y: numpy.ndarray or None (default: None)
  1401. labels for the rows of the `color` array passed. The length of this has
  1402. to be the number of rows in `color`.
  1403. This is a scaled attribute.
  1404. """
  1405. # Scaled attributes
  1406. x = Array(None, allow_none=True).tag(sync=True, scaled=True,
  1407. rtype='Number',
  1408. atype='bqplot.Axis',
  1409. **array_serialization)\
  1410. .valid(array_squeeze, array_dimension_bounds(1, 1))
  1411. y = Array(None, allow_none=True).tag(sync=True, scaled=True,
  1412. rtype='Number',
  1413. atype='bqplot.Axis',
  1414. **array_serialization)\
  1415. .valid(array_squeeze, array_dimension_bounds(1, 1))
  1416. color = Array(None, allow_none=True).tag(sync=True, scaled=True,
  1417. rtype='Color',
  1418. atype='bqplot.ColorAxis',
  1419. **array_serialization)\
  1420. .valid(array_squeeze, array_dimension_bounds(2, 2))
  1421. # Other attributes
  1422. scales_metadata = Dict({
  1423. 'x': {'orientation': 'horizontal', 'dimension': 'x'},
  1424. 'y': {'orientation': 'vertical', 'dimension': 'y'},
  1425. 'color': {'dimension': 'color'}
  1426. }).tag(sync=True)
  1427. null_color = Color('black', allow_none=True).tag(sync=True)
  1428. def __init__(self, **kwargs):
  1429. data = kwargs['color']
  1430. kwargs.setdefault('x', range(data.shape[1]))
  1431. kwargs.setdefault('y', range(data.shape[0]))
  1432. scales = kwargs.pop('scales', {})
  1433. # Adding default x and y data if they are not passed.
  1434. # Adding scales in case they are not passed too.
  1435. if(scales.get('x', None) is None):
  1436. x_scale = LinearScale()
  1437. scales['x'] = x_scale
  1438. if(scales.get('y', None) is None):
  1439. y_scale = LinearScale()
  1440. scales['y'] = y_scale
  1441. kwargs['scales'] = scales
  1442. super(HeatMap, self).__init__(**kwargs)
  1443. _view_name = Unicode('HeatMap').tag(sync=True)
  1444. _model_name = Unicode('HeatMapModel').tag(sync=True)
  1445. @register_mark('bqplot.Graph')
  1446. class Graph(Mark):
  1447. """Graph with nodes and links.
  1448. Attributes
  1449. ----------
  1450. node_data: List
  1451. list of node attributes for the graph
  1452. link_matrix: numpy.ndarray of shape(len(nodes), len(nodes))
  1453. link data passed as 2d matrix
  1454. link_data: List
  1455. list of link attributes for the graph
  1456. charge: int (default: -300)
  1457. charge of force layout. Will be ignored when x and y data attributes
  1458. are set
  1459. link_distance: float (default: 100)
  1460. link distance in pixels between nodes. Will be ignored when x and y
  1461. data attributes are set
  1462. link_type: {'arc', 'line', 'slant_line'} (default: 'arc')
  1463. Enum representing link type
  1464. directed: bool (default: True)
  1465. directed or undirected graph
  1466. highlight_links: bool (default: True)
  1467. highlights incoming and outgoing links when hovered on a node
  1468. colors: list (default: CATEGORY10)
  1469. list of node colors
  1470. Data Attributes
  1471. x: numpy.ndarray (default: [])
  1472. abscissas of the node data points (1d array)
  1473. y: numpy.ndarray (default: [])
  1474. ordinates of the node data points (1d array)
  1475. color: numpy.ndarray or None (default: None)
  1476. color of the node data points (1d array).
  1477. link_color: numpy.ndarray of shape(len(nodes), len(nodes))
  1478. link data passed as 2d matrix
  1479. """
  1480. charge = Int(-600).tag(sync=True)
  1481. link_distance = Float(100).tag(sync=True)
  1482. node_data = List().tag(sync=True)
  1483. link_data = List().tag(sync=True)
  1484. link_matrix = Array([]).tag(sync=True, rtype='Number',
  1485. **array_serialization)\
  1486. .valid(array_squeeze, array_dimension_bounds(1, 2))
  1487. link_type = Enum(['arc', 'line', 'slant_line'],
  1488. default_value='arc').tag(sync=True)
  1489. directed = Bool(True).tag(sync=True)
  1490. colors = List(trait=Color(default_value=None, allow_none=True),
  1491. default_value=CATEGORY10).tag(sync=True,
  1492. display_name='Colors')
  1493. interactions = Dict({'hover': 'tooltip', 'click': 'select'}).tag(sync=True)
  1494. highlight_links = Bool(True).tag(sync=True)
  1495. # Scaled attributes
  1496. x = Array([], allow_none=True).tag(sync=True,
  1497. scaled=True,
  1498. rtype='Number',
  1499. atype='bqplot.Axis',
  1500. **array_serialization)\
  1501. .valid(array_dimension_bounds(1, 1))
  1502. y = Array([], allow_none=True).tag(sync=True,
  1503. scaled=True,
  1504. rtype='Number',
  1505. atype='bqplot.Axis',
  1506. **array_serialization)\
  1507. .valid(array_dimension_bounds(1, 1))
  1508. color = Array(None, allow_none=True).tag(sync=True,
  1509. scaled=True,
  1510. rtype='Color',
  1511. atype='bqplot.ColorAxis',
  1512. **array_serialization)\
  1513. .valid(array_squeeze, array_dimension_bounds(1, 1))
  1514. link_color = Array([]).tag(sync=True, rtype='Color',
  1515. atype='bqplot.ColorAxis',
  1516. **array_serialization)\
  1517. .valid(array_squeeze, array_dimension_bounds(1, 2))
  1518. hovered_style = Dict().tag(sync=True)
  1519. unhovered_style = Dict().tag(sync=True)
  1520. hovered_point = Int(None, allow_none=True).tag(sync=True)
  1521. # Other attributes
  1522. scales_metadata = Dict({
  1523. 'x': {'orientation': 'horizontal', 'dimension': 'x'},
  1524. 'y': {'orientation': 'vertical', 'dimension': 'y'},
  1525. 'color': {'dimension': 'color'},
  1526. 'link_color': {'dimension': 'link_color'}
  1527. }).tag(sync=True)
  1528. _model_name = Unicode('GraphModel').tag(sync=True)
  1529. _view_name = Unicode('Graph').tag(sync=True)
  1530. @register_mark('bqplot.Image')
  1531. class Image(Mark):
  1532. """Image mark, based on the ipywidgets image
  1533. If no scales are passed, uses the parent Figure scales.
  1534. Attributes
  1535. ----------
  1536. image: Instance of ipywidgets.Image
  1537. Image to be displayed
  1538. Data Attributes
  1539. x: tuple (default: (0, 1))
  1540. abscissas of the left and right-hand side of the image
  1541. in the format (x0, x1)
  1542. y: tuple (default: (0, 1))
  1543. ordinates of the bottom and top side of the image
  1544. in the format (y0, y1)
  1545. """
  1546. _view_name = Unicode('Image').tag(sync=True)
  1547. _model_name = Unicode('ImageModel').tag(sync=True)
  1548. image = Instance(widgets.Image).tag(sync=True, **widget_serialization)
  1549. x = Array(default_value=(0, 1)).tag(sync=True, scaled=True,
  1550. rtype='Number',
  1551. atype='bqplot.Axis',
  1552. **array_serialization)\
  1553. .valid(array_squeeze, shape(2))
  1554. y = Array(default_value=(0, 1)).tag(sync=True, scaled=True,
  1555. rtype='Number',
  1556. atype='bqplot.Axis',
  1557. **array_serialization)\
  1558. .valid(array_squeeze, shape(2))
  1559. scales_metadata = Dict({
  1560. 'x': {'orientation': 'horizontal', 'dimension': 'x'},
  1561. 'y': {'orientation': 'vertical', 'dimension': 'y'},
  1562. }).tag(sync=True)