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.

562 lines
19 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. Scales
  17. ======
  18. .. currentmodule:: bqplot.scales
  19. .. autosummary::
  20. :toctree: _generate/
  21. Scale
  22. LinearScale
  23. LogScale
  24. DateScale
  25. OrdinalScale
  26. ColorScale
  27. DateColorScale
  28. OrdinalColorScale
  29. GeoScale
  30. Mercator
  31. AlbersUSA
  32. Gnomonic
  33. Stereographic
  34. """
  35. from ipywidgets import Widget, Color
  36. from traitlets import Unicode, List, Enum, Float, Bool, Type, Tuple
  37. import numpy as np
  38. from .traits import Date
  39. from ._version import __frontend_version__
  40. def register_scale(key=None):
  41. """Returns a decorator to register a scale type in the scale type
  42. registry.
  43. If no key is provided, the class name is used as a key. A key is
  44. provided for each core bqplot scale type so that the frontend can use
  45. this key regardless of the kernal language.
  46. """
  47. def wrap(scale):
  48. label = key if key is not None else scale.__module__ + scale.__name__
  49. Scale.scale_types[label] = scale
  50. return scale
  51. return wrap
  52. class Scale(Widget):
  53. """The base scale class.
  54. Scale objects represent a mapping between data (the domain) and a visual
  55. quantity (The range).
  56. Attributes
  57. ----------
  58. scale_types: dict (class-level attribute)
  59. A registry of existing scale types.
  60. domain_class: type (default: Float)
  61. traitlet type used to validate values in of the domain of the scale.
  62. reverse: bool (default: False)
  63. whether the scale should be reversed.
  64. allow_padding: bool (default: True)
  65. indicates whether figures are allowed to add data padding to this scale
  66. or not.
  67. precedence: int (class-level attribute)
  68. attribute used to determine which scale takes precedence in cases when
  69. two or more scales have the same rtype and dtype.
  70. """
  71. scale_types = {}
  72. precedence = 1
  73. domain_class = Type(Float)
  74. reverse = Bool().tag(sync=True)
  75. allow_padding = Bool(True).tag(sync=True)
  76. _view_name = Unicode('Scale').tag(sync=True)
  77. _model_name = Unicode('ScaleModel').tag(sync=True)
  78. _view_module = Unicode('bqplot').tag(sync=True)
  79. _model_module = Unicode('bqplot').tag(sync=True)
  80. _view_module_version = Unicode(__frontend_version__).tag(sync=True)
  81. _model_module_version = Unicode(__frontend_version__).tag(sync=True)
  82. _ipython_display_ = None # We cannot display a scale outside of a figure
  83. class GeoScale(Scale):
  84. """The base projection scale class for Map marks.
  85. The GeoScale represents a mapping between topographic data and a
  86. 2d visual representation.
  87. """
  88. _view_name = Unicode('GeoScale').tag(sync=True)
  89. _model_name = Unicode('GeoScaleModel').tag(sync=True)
  90. @register_scale('bqplot.Mercator')
  91. class Mercator(GeoScale):
  92. """A geographical projection scale commonly used for world maps.
  93. The Mercator projection is a cylindrical map projection which ensures that
  94. any course of constant bearing is a straight line.
  95. Attributes
  96. ----------
  97. scale_factor: float (default: 190)
  98. Specifies the scale value for the projection
  99. center: tuple (default: (0, 60))
  100. Specifies the longitude and latitude where the map is centered.
  101. rotate: tuple (default: (0, 0))
  102. Degree of rotation in each axis.
  103. rtype: (Number, Number) (class-level attribute)
  104. This attribute should not be modifed. The range type of a geo
  105. scale is a tuple.
  106. dtype: type (class-level attribute)
  107. the associated data type / domain type
  108. """
  109. scale_factor = Float(190).tag(sync=True)
  110. center = Tuple((0, 60)).tag(sync=True)
  111. rotate = Tuple((0, 0)).tag(sync=True)
  112. rtype = '(Number, Number)'
  113. dtype = np.number
  114. _view_name = Unicode('Mercator').tag(sync=True)
  115. _model_name = Unicode('MercatorModel').tag(sync=True)
  116. @register_scale('bqplot.Albers')
  117. class Albers(GeoScale):
  118. """A geographical scale which is an alias for a conic equal area projection.
  119. The Albers projection is a conic equal area map. It does not preserve scale
  120. or shape, though it is recommended for chloropleths since it preserves the
  121. relative areas of geographic features. Default values are US-centric.
  122. Attributes
  123. ----------
  124. scale_factor: float (default: 250)
  125. Specifies the scale value for the projection
  126. rotate: tuple (default: (96, 0))
  127. Degree of rotation in each axis.
  128. parallels: tuple (default: (29.5, 45.5))
  129. Sets the two parallels for the conic projection.
  130. center: tuple (default: (0, 60))
  131. Specifies the longitude and latitude where the map is centered.
  132. precision: float (default: 0.1)
  133. Specifies the threshold for the projections adaptive resampling to the
  134. specified value in pixels.
  135. rtype: (Number, Number) (class-level attribute)
  136. This attribute should not be modifed. The range type of a geo
  137. scale is a tuple.
  138. dtype: type (class-level attribute)
  139. the associated data type / domain type
  140. """
  141. scale_factor = Float(250).tag(sync=True)
  142. rotate = Tuple((96, 0)).tag(sync=True)
  143. center = Tuple((0, 60)).tag(sync=True)
  144. parallels = Tuple((29.5, 45.5)).tag(sync=True)
  145. precision = Float(0.1).tag(sync=True)
  146. rtype = '(Number, Number)'
  147. dtype = np.number
  148. _view_name = Unicode('Albers').tag(sync=True)
  149. _model_name = Unicode('AlbersModel').tag(sync=True)
  150. @register_scale('bqplot.AlbersUSA')
  151. class AlbersUSA(GeoScale):
  152. """A composite projection of four Albers projections meant specifically for
  153. the United States.
  154. Attributes
  155. ----------
  156. scale_factor: float (default: 1200)
  157. Specifies the scale value for the projection
  158. translate: tuple (default: (600, 490))
  159. rtype: (Number, Number) (class-level attribute)
  160. This attribute should not be modifed. The range type of a geo
  161. scale is a tuple.
  162. dtype: type (class-level attribute)
  163. the associated data type / domain type
  164. """
  165. scale_factor = Float(1200).tag(sync=True)
  166. translate = Tuple((600, 490)).tag(sync=True)
  167. rtype = '(Number, Number)'
  168. dtype = np.number
  169. _view_name = Unicode('AlbersUSA').tag(sync=True)
  170. _model_name = Unicode('AlbersUSAModel').tag(sync=True)
  171. @register_scale('bqplot.EquiRectangular')
  172. class EquiRectangular(GeoScale):
  173. """An elementary projection that uses the identity function.
  174. The projection is neither equal-area nor conformal.
  175. Attributes
  176. ----------
  177. scale_factor: float (default: 145)
  178. Specifies the scale value for the projection
  179. center: tuple (default: (0, 60))
  180. Specifies the longitude and latitude where the map is centered.
  181. """
  182. scale_factor = Float(145.0).tag(sync=True)
  183. center = Tuple((0, 60)).tag(sync=True)
  184. rtype = '(Number, Number)'
  185. dtype = np.number
  186. _view_name = Unicode('EquiRectangular').tag(sync=True)
  187. _model_name = Unicode('EquiRectangularModel').tag(sync=True)
  188. @register_scale('bqplot.Orthographic')
  189. class Orthographic(GeoScale):
  190. """A perspective projection that depicts a hemisphere as it appears from
  191. outer space.
  192. The projection is neither equal-area nor conformal.
  193. Attributes
  194. ----------
  195. scale_factor: float (default: 145)
  196. Specifies the scale value for the projection
  197. center: tuple (default: (0, 60))
  198. Specifies the longitude and latitude where the map is centered.
  199. rotate: tuple (default: (96, 0))
  200. Degree of rotation in each axis.
  201. clip_angle: float (default: 90.)
  202. Specifies the clipping circle radius to the specified angle in degrees.
  203. precision: float (default: 0.1)
  204. Specifies the threshold for the projections adaptive resampling to the
  205. specified value in pixels.
  206. """
  207. scale_factor = Float(145.0).tag(sync=True)
  208. center = Tuple((0, 60)).tag(sync=True)
  209. rotate = Tuple((0, 0)).tag(sync=True)
  210. clip_angle = Float(90.0, min=0.0, max=360.0).tag(sync=True)
  211. precision = Float(0.1).tag(sync=True)
  212. rtype = '(Number, Number)'
  213. dtype = np.number
  214. _view_name = Unicode('Orthographic').tag(sync=True)
  215. _model_name = Unicode('OrthographicModel').tag(sync=True)
  216. @register_scale('bqplot.Gnomonic')
  217. class Gnomonic(GeoScale):
  218. """A perspective projection which displays great circles as straight lines.
  219. The projection is neither equal-area nor conformal.
  220. Attributes
  221. ----------
  222. scale_factor: float (default: 145)
  223. Specifies the scale value for the projection
  224. center: tuple (default: (0, 60))
  225. Specifies the longitude and latitude where the map is centered.
  226. precision: float (default: 0.1)
  227. Specifies the threshold for the projections adaptive resampling to the
  228. specified value in pixels.
  229. clip_angle: float (default: 89.999)
  230. Specifies the clipping circle radius to the specified angle in degrees.
  231. """
  232. scale_factor = Float(145.0).tag(sync=True)
  233. center = Tuple((0, 60)).tag(sync=True)
  234. precision = Float(0.1).tag(sync=True)
  235. clip_angle = Float(89.999, min=0.0, max=360.0).tag(sync=True)
  236. rtype = '(Number, Number)'
  237. dtype = np.number
  238. _view_name = Unicode('Gnomonic').tag(sync=True)
  239. _model_name = Unicode('GnomonicModel').tag(sync=True)
  240. @register_scale('bqplot.Stereographic')
  241. class Stereographic(GeoScale):
  242. """A perspective projection that uses a bijective and smooth map at every
  243. point except the projection point.
  244. The projection is not an equal-area projection but it is conformal.
  245. Attributes
  246. ----------
  247. scale_factor: float (default: 250)
  248. Specifies the scale value for the projection
  249. rotate: tuple (default: (96, 0))
  250. Degree of rotation in each axis.
  251. center: tuple (default: (0, 60))
  252. Specifies the longitude and latitude where the map is centered.
  253. precision: float (default: 0.1)
  254. Specifies the threshold for the projections adaptive resampling to the
  255. specified value in pixels.
  256. clip_angle: float (default: 90.)
  257. Specifies the clipping circle radius to the specified angle in degrees.
  258. """
  259. scale_factor = Float(145.0).tag(sync=True)
  260. center = Tuple((0, 60)).tag(sync=True)
  261. precision = Float(0.1).tag(sync=True)
  262. rotate = Tuple((96, 0)).tag(sync=True)
  263. clip_angle = Float(179.9999, min=0.0, max=360.0).tag(sync=True)
  264. rtype = '(Number, Number)'
  265. dtype = np.number
  266. _view_name = Unicode('Stereographic').tag(sync=True)
  267. _model_name = Unicode('StereographicModel').tag(sync=True)
  268. @register_scale('bqplot.LinearScale')
  269. class LinearScale(Scale):
  270. """A linear scale.
  271. An affine mapping from a numerical domain to a numerical range.
  272. Attributes
  273. ----------
  274. min: float or None (default: None)
  275. if not None, min is the minimal value of the domain
  276. max: float or None (default: None)
  277. if not None, max is the maximal value of the domain
  278. rtype: string (class-level attribute)
  279. This attribute should not be modifed. The range type of a linear
  280. scale is numerical.
  281. dtype: type (class-level attribute)
  282. the associated data type / domain type
  283. precedence: int (class-level attribute, default_value=2)
  284. attribute used to determine which scale takes precedence in cases when
  285. two or more scales have the same rtype and dtype.
  286. default_value is 2 because for the same range and domain types,
  287. LinearScale should take precedence.
  288. stabilized: bool (default: False)
  289. if set to False, the domain of the scale is tied to the data range
  290. if set to True, the domain of the scale is updated only when
  291. the data range is beyond certain thresholds, given by the attributes
  292. mid_range and min_range.
  293. mid_range: float (default: 0.8)
  294. Proportion of the range that is spanned initially.
  295. Used only if stabilized is True.
  296. min_range: float (default: 0.6)
  297. Minimum proportion of the range that should be spanned by the data.
  298. If the data span falls beneath that level, the scale is reset.
  299. min_range must be <= mid_range.
  300. Used only if stabilized is True.
  301. """
  302. rtype = 'Number'
  303. dtype = np.number
  304. precedence = 2
  305. min = Float(None, allow_none=True).tag(sync=True)
  306. max = Float(None, allow_none=True).tag(sync=True)
  307. stabilized = Bool(False).tag(sync=True)
  308. min_range = Float(0.6, min=0.0, max=1.0).tag(sync=True)
  309. mid_range = Float(0.8, min=0.1, max=1.0).tag(sync=True)
  310. _view_name = Unicode('LinearScale').tag(sync=True)
  311. _model_name = Unicode('LinearScaleModel').tag(sync=True)
  312. @register_scale('bqplot.LogScale')
  313. class LogScale(Scale):
  314. """A log scale.
  315. A logarithmic mapping from a numerical domain to a numerical range.
  316. Attributes
  317. ----------
  318. min: float or None (default: None)
  319. if not None, min is the minimal value of the domain
  320. max: float or None (default: None)
  321. if not None, max is the maximal value of the domain
  322. rtype: string (class-level attribute)
  323. This attribute should not be modifed by the user.
  324. The range type of a linear scale is numerical.
  325. dtype: type (class-level attribute)
  326. the associated data type / domain type
  327. """
  328. rtype = 'Number'
  329. dtype = np.number
  330. min = Float(None, allow_none=True).tag(sync=True)
  331. max = Float(None, allow_none=True).tag(sync=True)
  332. _view_name = Unicode('LogScale').tag(sync=True)
  333. _model_name = Unicode('LogScaleModel').tag(sync=True)
  334. @register_scale('bqplot.DateScale')
  335. class DateScale(Scale):
  336. """A date scale, with customizable formatting.
  337. An affine mapping from dates to a numerical range.
  338. Attributes
  339. ----------
  340. min: Date or None (default: None)
  341. if not None, min is the minimal value of the domain
  342. max: Date (default: None)
  343. if not None, max is the maximal value of the domain
  344. domain_class: type (default: Date)
  345. traitlet type used to validate values in of the domain of the scale.
  346. rtype: string (class-level attribute)
  347. This attribute should not be modifed by the user.
  348. The range type of a linear scale is numerical.
  349. dtype: type (class-level attribute)
  350. the associated data type / domain type
  351. """
  352. rtype = 'Number'
  353. dtype = np.datetime64
  354. domain_class = Type(Date)
  355. min = Date(default_value=None, allow_none=True).tag(sync=True)
  356. max = Date(default_value=None, allow_none=True).tag(sync=True)
  357. _view_name = Unicode('DateScale').tag(sync=True)
  358. _model_name = Unicode('DateScaleModel').tag(sync=True)
  359. @register_scale('bqplot.OrdinalScale')
  360. class OrdinalScale(Scale):
  361. """An ordinal scale.
  362. A mapping from a discrete set of values to a numerical range.
  363. Attributes
  364. ----------
  365. domain: list (default: [])
  366. The discrete values mapped by the ordinal scale
  367. rtype: string (class-level attribute)
  368. This attribute should not be modifed by the user.
  369. The range type of a linear scale is numerical.
  370. dtype: type (class-level attribute)
  371. the associated data type / domain type
  372. """
  373. rtype = 'Number'
  374. dtype = np.str_
  375. domain = List().tag(sync=True)
  376. _view_name = Unicode('OrdinalScale').tag(sync=True)
  377. _model_name = Unicode('OrdinalScaleModel').tag(sync=True)
  378. @register_scale('bqplot.ColorScale')
  379. class ColorScale(Scale):
  380. """A color scale.
  381. A mapping from numbers to colors. The relation is affine by part.
  382. Attributes
  383. ----------
  384. scale_type: {'linear'}
  385. scale type
  386. colors: list of colors (default: [])
  387. list of colors
  388. min: float or None (default: None)
  389. if not None, min is the minimal value of the domain
  390. max: float or None (default: None)
  391. if not None, max is the maximal value of the domain
  392. mid: float or None (default: None)
  393. if not None, mid is the value corresponding to the mid color.
  394. scheme: string (default: 'RdYlGn')
  395. Colorbrewer color scheme of the color scale.
  396. extrapolation: {'constant', 'linear'} (default: 'constant')
  397. How to extrapolate values outside the [min, max] domain.
  398. rtype: string (class-level attribute)
  399. The range type of a color scale is 'Color'. This should not be modifed.
  400. dtype: type (class-level attribute)
  401. the associated data type / domain type
  402. """
  403. rtype = 'Color'
  404. dtype = np.number
  405. scale_type = Enum(['linear'], default_value='linear').tag(sync=True)
  406. colors = List(trait=Color(default_value=None, allow_none=True))\
  407. .tag(sync=True)
  408. min = Float(None, allow_none=True).tag(sync=True)
  409. max = Float(None, allow_none=True).tag(sync=True)
  410. mid = Float(None, allow_none=True).tag(sync=True)
  411. scheme = Unicode('RdYlGn').tag(sync=True)
  412. extrapolation = Enum(['constant', 'linear'], default_value='constant').tag(sync=True)
  413. _view_name = Unicode('ColorScale').tag(sync=True)
  414. _model_name = Unicode('ColorScaleModel').tag(sync=True)
  415. @register_scale('bqplot.DateColorScale')
  416. class DateColorScale(ColorScale):
  417. """A date color scale.
  418. A mapping from dates to a numerical domain.
  419. Attributes
  420. ----------
  421. min: Date or None (default: None)
  422. if not None, min is the minimal value of the domain
  423. max: Date or None (default: None)
  424. if not None, max is the maximal value of the domain
  425. mid: Date or None (default: None)
  426. if not None, mid is the value corresponding to the mid color.
  427. rtype: string (class-level attribute)
  428. This attribute should not be modifed by the user.
  429. The range type of a color scale is 'Color'.
  430. dtype: type (class-level attribute)
  431. the associated data type / domain type
  432. """
  433. dtype = np.datetime64
  434. domain_class = Type(Date)
  435. min = Date(default_value=None, allow_none=True).tag(sync=True)
  436. mid = Date(default_value=None, allow_none=True).tag(sync=True)
  437. max = Date(default_value=None, allow_none=True).tag(sync=True)
  438. _view_name = Unicode('DateColorScale').tag(sync=True)
  439. _model_name = Unicode('DateColorScaleModel').tag(sync=True)
  440. @register_scale('bqplot.OrdinalColorScale')
  441. class OrdinalColorScale(ColorScale):
  442. """An ordinal color scale.
  443. A mapping from a discrete set of values to colors.
  444. Attributes
  445. ----------
  446. domain: list (default: [])
  447. The discrete values mapped by the ordinal scales.
  448. rtype: string (class-level attribute)
  449. This attribute should not be modifed by the user.
  450. The range type of a color scale is 'color'.
  451. dtype: type (class-level attribute)
  452. the associated data type / domain type
  453. """
  454. rtype = 'Color'
  455. dtype = np.str_
  456. domain = List().tag(sync=True)
  457. _view_name = Unicode('OrdinalColorScale').tag(sync=True)
  458. _model_name = Unicode('OrdinalColorScaleModel').tag(sync=True)