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.

205 lines
7.9 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. Figure
  17. ======
  18. .. currentmodule:: bqplot.figure
  19. .. autosummary::
  20. :toctree: _generate/
  21. Figure
  22. """
  23. from traitlets import (
  24. Unicode, Instance, List, Dict, Enum, Float, Int, TraitError, default,
  25. validate
  26. )
  27. from ipywidgets import DOMWidget, register, widget_serialization
  28. from ipywidgets.widgets.widget_layout import LayoutTraitType
  29. from .scales import Scale, LinearScale
  30. from .interacts import Interaction
  31. from .marks import Mark
  32. from .axes import Axis
  33. from ._version import __frontend_version__
  34. @register
  35. class Figure(DOMWidget):
  36. """Main canvas for drawing a chart.
  37. The Figure object holds the list of Marks and Axes. It also holds an
  38. optional Interaction object that is responsible for figure-level mouse
  39. interactions, the "interaction layer".
  40. Besides, the Figure object has two reference scales, for positioning items
  41. in an absolute fashion in the figure canvas.
  42. Attributes
  43. ----------
  44. title: string (default: '')
  45. title of the figure
  46. axes: List of Axes (default: [])
  47. list containing the instances of the axes for the figure
  48. marks: List of Marks (default: [])
  49. list containing the marks which are to be appended to the figure
  50. interaction: Interaction or None (default: None)
  51. optional interaction layer for the figure
  52. scale_x: Scale
  53. Scale representing the x values of the figure
  54. scale_y: Scale
  55. Scale representing the y values of the figure
  56. padding_x: Float (default: 0.0)
  57. Padding to be applied in the horizontal direction of the figure
  58. around the data points, proportion of the horizontal length
  59. padding_y: Float (default: 0.025)
  60. Padding to be applied in the vertical direction of the figure
  61. around the data points, proportion of the vertical length
  62. legend_location: {'top-right', 'top', 'top-left', 'left',
  63. 'bottom-left', 'bottom', 'bottom-right', 'right'}
  64. location of the legend relative to the center of the figure
  65. background_style: Dict (default: {})
  66. CSS style to be applied to the background of the figure
  67. legend_style: Dict (default: {})
  68. CSS style to be applied to the SVG legend e.g, {'fill': 'white'}
  69. legend_text: Dict (default: {})
  70. CSS style to be applied to the legend text e.g., {'font-size': 20}
  71. title_style: Dict (default: {})
  72. CSS style to be applied to the title of the figure
  73. animation_duration: nonnegative int (default: 0)
  74. Duration of transition on change of data attributes, in milliseconds.
  75. pixel_ratio:
  76. Pixel ratio of the WebGL canvas (2 on retina screens). Set to 1 for better performance,
  77. but less crisp edges. If set to None it will use the browser's window.devicePixelRatio.
  78. Layout Attributes
  79. fig_margin: dict (default: {top=60, bottom=60, left=60, right=60})
  80. Dictionary containing the top, bottom, left and right margins. The user
  81. is responsible for making sure that the width and height are greater
  82. than the sum of the margins.
  83. min_aspect_ratio: float
  84. minimum width / height ratio of the figure
  85. max_aspect_ratio: float
  86. maximum width / height ratio of the figure
  87. Methods
  88. -------
  89. save_png:
  90. Saves the figure as a PNG file
  91. save_svg:
  92. Saves the figure as an SVG file
  93. Note
  94. ----
  95. The aspect ratios stand for width / height ratios.
  96. - If the available space is within bounds in terms of min and max aspect
  97. ratio, we use the entire available space.
  98. - If the available space is too oblong horizontally, we use the client
  99. height and the width that corresponds max_aspect_ratio (maximize width
  100. under the constraints).
  101. - If the available space is too oblong vertically, we use the client width
  102. and the height that corresponds to min_aspect_ratio (maximize height
  103. under the constraint).
  104. This corresponds to maximizing the area under the constraints.
  105. Default min and max aspect ratio are both equal to 16 / 9.
  106. """
  107. title = Unicode().tag(sync=True, display_name='Title')
  108. axes = List(Instance(Axis)).tag(sync=True, **widget_serialization)
  109. marks = List(Instance(Mark)).tag(sync=True, **widget_serialization)
  110. interaction = Instance(Interaction, default_value=None,
  111. allow_none=True).tag(sync=True,
  112. **widget_serialization)
  113. scale_x = Instance(Scale).tag(sync=True, **widget_serialization)
  114. scale_y = Instance(Scale).tag(sync=True, **widget_serialization)
  115. title_style = Dict(trait=Unicode()).tag(sync=True)
  116. background_style = Dict().tag(sync=True)
  117. legend_style = Dict().tag(sync=True)
  118. legend_text = Dict().tag(sync=True)
  119. theme = Enum(['classic', 'gg'], default_value='classic').tag(sync=True)
  120. min_aspect_ratio = Float(0.01).tag(sync=True)
  121. max_aspect_ratio = Float(100).tag(sync=True)
  122. pixel_ratio = Float(None, allow_none=True).tag(sync=True)
  123. fig_margin = Dict(dict(top=60, bottom=60, left=60, right=60))\
  124. .tag(sync=True)
  125. padding_x = Float(0.0, min=0.0, max=1.0).tag(sync=True)
  126. padding_y = Float(0.025, min=0.0, max=1.0).tag(sync=True)
  127. legend_location = Enum(['top-right', 'top', 'top-left', 'left',
  128. 'bottom-left', 'bottom', 'bottom-right', 'right'],
  129. default_value='top-right')\
  130. .tag(sync=True, display_name='Legend position')
  131. animation_duration = Int().tag(sync=True,
  132. display_name='Animation duration')
  133. @default('scale_x')
  134. def _default_scale_x(self):
  135. return LinearScale(min=0, max=1, allow_padding=False)
  136. @default('scale_y')
  137. def _default_scale_y(self):
  138. return LinearScale(min=0, max=1, allow_padding=False)
  139. def save_png(self, filename='bqplot.png', scale=None):
  140. '''
  141. Saves the Figure as a PNG file
  142. Parameters
  143. ----------
  144. filename: str (default: 'bqplot.png')
  145. name of the saved file
  146. scale: float (default: None)
  147. Scale up the png resolution when scale > 1, when not given base this on the screen pixel ratio.
  148. '''
  149. self.send({'type': 'save_png', 'filename': filename, 'scale': scale})
  150. def save_svg(self, filename='bqplot.svg'):
  151. '''
  152. Saves the Figure as an SVG file
  153. Parameters
  154. ----------
  155. filename: str (default: 'bqplot.svg')
  156. name of the saved file
  157. '''
  158. self.send({"type": "save_svg", "filename": filename})
  159. @validate('min_aspect_ratio', 'max_aspect_ratio')
  160. def _validate_aspect_ratio(self, proposal):
  161. value = proposal['value']
  162. if proposal['trait'].name == 'min_aspect_ratio' and \
  163. value > self.max_aspect_ratio:
  164. raise TraitError('setting min_aspect_ratio > max_aspect_ratio')
  165. if proposal['trait'].name == 'max_aspect_ratio' and \
  166. value < self.min_aspect_ratio:
  167. raise TraitError('setting max_aspect_ratio < min_aspect_ratio')
  168. return value
  169. _view_name = Unicode('Figure').tag(sync=True)
  170. _model_name = Unicode('FigureModel').tag(sync=True)
  171. _view_module = Unicode('bqplot').tag(sync=True)
  172. _model_module = Unicode('bqplot').tag(sync=True)
  173. _view_module_version = Unicode(__frontend_version__).tag(sync=True)
  174. _model_module_version = Unicode(__frontend_version__).tag(sync=True)