1#----------------------------------------------------------------------------- 2# Copyright (c) 2012 - 2021, Anaconda, Inc., and Bokeh Contributors. 3# All rights reserved. 4# 5# The full license is in the file LICENSE.txt, distributed with this software. 6#----------------------------------------------------------------------------- 7''' Guide renderers for various kinds of axes that can be added to 8Bokeh plots 9 10''' 11 12#----------------------------------------------------------------------------- 13# Boilerplate 14#----------------------------------------------------------------------------- 15import logging # isort:skip 16log = logging.getLogger(__name__) 17 18#----------------------------------------------------------------------------- 19# Imports 20#----------------------------------------------------------------------------- 21 22# Bokeh imports 23from ..core.enums import TickLabelOrientation 24from ..core.has_props import abstract 25from ..core.properties import ( 26 Auto, 27 Datetime, 28 Dict, 29 Either, 30 Enum, 31 Factor, 32 Float, 33 Include, 34 Instance, 35 Int, 36 Null, 37 Nullable, 38 Override, 39 Seq, 40 String, 41 Tuple, 42) 43from ..core.property_mixins import ScalarLineProps, ScalarTextProps 44from .formatters import ( 45 BasicTickFormatter, 46 CategoricalTickFormatter, 47 DatetimeTickFormatter, 48 LogTickFormatter, 49 MercatorTickFormatter, 50 TickFormatter, 51) 52from .labeling import AllLabels, LabelingPolicy 53from .renderers import GuideRenderer 54from .tickers import ( 55 BasicTicker, 56 CategoricalTicker, 57 DatetimeTicker, 58 FixedTicker, 59 LogTicker, 60 MercatorTicker, 61 Ticker, 62) 63 64#----------------------------------------------------------------------------- 65# Globals and constants 66#----------------------------------------------------------------------------- 67 68__all__ = ( 69 'Axis', 70 'CategoricalAxis', 71 'ContinuousAxis', 72 'DatetimeAxis', 73 'LinearAxis', 74 'LogAxis', 75 'MercatorAxis', 76) 77 78#----------------------------------------------------------------------------- 79# General API 80#----------------------------------------------------------------------------- 81 82@abstract 83class Axis(GuideRenderer): 84 ''' A base class that defines common properties for all axis types. 85 86 ''' 87 88 bounds = Either(Auto, Tuple(Float, Float), Tuple(Datetime, Datetime), help=""" 89 Bounds for the rendered axis. If unset, the axis will span the 90 entire plot in the given dimension. 91 """) 92 93 ticker = Instance(Ticker, help=""" 94 A Ticker to use for computing locations of axis components. 95 96 The property may also be passed a sequence of floating point numbers as 97 a shorthand for creating and configuring a ``FixedTicker``, e.g. the 98 following code 99 100 .. code-block:: python 101 102 from bokeh.plotting import figure 103 104 p = figure() 105 p.xaxis.ticker = [10, 20, 37.4] 106 107 is equivalent to: 108 109 .. code-block:: python 110 111 from bokeh.plotting import figure 112 from bokeh.models import FixedTicker 113 114 p = figure() 115 p.xaxis.ticker = FixedTicker(ticks=[10, 20, 37.4]) 116 117 """).accepts(Seq(Float), lambda ticks: FixedTicker(ticks=ticks)) 118 119 formatter = Instance(TickFormatter, help=""" 120 A ``TickFormatter`` to use for formatting the visual appearance 121 of ticks. 122 """) 123 124 axis_label = Nullable(String, default="", help=""" 125 A text label for the axis, displayed parallel to the axis rule. 126 127 .. note:: 128 LaTeX notation is not currently supported; please see 129 :bokeh-issue:`647` to track progress or contribute. 130 131 """) 132 133 axis_label_standoff = Int(default=5, help=""" 134 The distance in pixels that the axis labels should be offset 135 from the tick labels. 136 """) 137 138 axis_label_props = Include(ScalarTextProps, help=""" 139 The %s of the axis label. 140 """) 141 142 axis_label_text_font_size = Override(default="13px") 143 144 axis_label_text_font_style = Override(default="italic") 145 146 major_label_standoff = Int(default=5, help=""" 147 The distance in pixels that the major tick labels should be 148 offset from the associated ticks. 149 """) 150 151 major_label_orientation = Either(Enum("horizontal", "vertical"), Float, help=""" 152 What direction the major label text should be oriented. If a 153 number is supplied, the angle of the text is measured from horizontal. 154 """) 155 156 major_label_overrides = Dict(Either(Float, String), String, default={}, help=""" 157 Provide explicit tick label values for specific tick locations that 158 override normal formatting. 159 """) 160 161 major_label_policy = Instance(LabelingPolicy, default=lambda: AllLabels(), help=""" 162 Allows to filter out labels, e.g. declutter labels to avoid overlap. 163 """) 164 165 major_label_props = Include(ScalarTextProps, help=""" 166 The %s of the major tick labels. 167 """) 168 169 major_label_text_align = Override(default="center") 170 171 major_label_text_baseline = Override(default="alphabetic") 172 173 major_label_text_font_size = Override(default="11px") 174 175 axis_props = Include(ScalarLineProps, help=""" 176 The %s of the axis line. 177 """) 178 179 major_tick_props = Include(ScalarLineProps, help=""" 180 The %s of the major ticks. 181 """) 182 183 major_tick_in = Int(default=2, help=""" 184 The distance in pixels that major ticks should extend into the 185 main plot area. 186 """) 187 188 major_tick_out = Int(default=6, help=""" 189 The distance in pixels that major ticks should extend out of the 190 main plot area. 191 """) 192 193 minor_tick_props = Include(ScalarLineProps, help=""" 194 The %s of the minor ticks. 195 """) 196 197 minor_tick_in = Int(default=0, help=""" 198 The distance in pixels that minor ticks should extend into the 199 main plot area. 200 """) 201 202 minor_tick_out = Int(default=4, help=""" 203 The distance in pixels that major ticks should extend out of the 204 main plot area. 205 """) 206 207 fixed_location = Either(Null, Float, Factor, help=""" 208 Set to specify a fixed coordinate location to draw the axis. The direction 209 of ticks and major labels is determined by the side panel that the axis 210 belongs to. 211 212 .. note:: 213 Axes labels are suppressed when axes are positioned at fixed locations 214 inside the central plot area. 215 """) 216 217@abstract 218class ContinuousAxis(Axis): 219 ''' A base class for all numeric, non-categorical axes types. 220 221 ''' 222 pass 223 224class LinearAxis(ContinuousAxis): 225 ''' An axis that picks nice numbers for tick locations on a 226 linear scale. Configured with a ``BasicTickFormatter`` by default. 227 228 ''' 229 ticker = Override(default=lambda: BasicTicker()) 230 231 formatter = Override(default=lambda: BasicTickFormatter()) 232 233class LogAxis(ContinuousAxis): 234 ''' An axis that picks nice numbers for tick locations on a 235 log scale. Configured with a ``LogTickFormatter`` by default. 236 237 ''' 238 ticker = Override(default=lambda: LogTicker()) 239 240 formatter = Override(default=lambda: LogTickFormatter()) 241 242class CategoricalAxis(Axis): 243 ''' An axis that displays ticks and labels for categorical ranges. 244 245 The ``CategoricalAxis`` can handle factor ranges with up to two levels of 246 nesting, including drawing a separator line between top-level groups of 247 factors. 248 249 ''' 250 ticker = Override(default=lambda: CategoricalTicker()) 251 252 formatter = Override(default=lambda: CategoricalTickFormatter()) 253 254 separator_props = Include(ScalarLineProps, help=""" 255 The %s of the separator line between top-level categorical groups. 256 257 This property always applies to factors in the outermost level of nesting. 258 """) 259 260 separator_line_color = Override(default="lightgrey") 261 separator_line_width = Override(default=2) 262 263 group_props = Include(ScalarTextProps, help=""" 264 The %s of the group categorical labels. 265 266 This property always applies to factors in the outermost level of nesting. 267 If the list of categorical factors is flat (i.e. no nesting) then this 268 property has no effect. 269 """) 270 271 group_label_orientation = Either(Enum(TickLabelOrientation), Float, default="parallel", help=""" 272 What direction the group label text should be oriented. 273 274 If a number is supplied, the angle of the text is measured from horizontal. 275 276 This property always applies to factors in the outermost level of nesting. 277 If the list of categorical factors is flat (i.e. no nesting) then this 278 property has no effect. 279 """) 280 281 group_text_font_size = Override(default="11px") 282 group_text_font_style = Override(default="bold") 283 group_text_color = Override(default="grey") 284 285 subgroup_props = Include(ScalarTextProps, help=""" 286 The %s of the subgroup categorical labels. 287 288 This property always applies to factors in the middle level of nesting. 289 If the list of categorical factors is has only zero or one levels of nesting, 290 then this property has no effect. 291 """) 292 293 subgroup_label_orientation = Either(Enum(TickLabelOrientation), Float, default="parallel", help=""" 294 What direction the subgroup label text should be oriented. 295 296 If a number is supplied, the angle of the text is measured from horizontal. 297 298 This property always applies to factors in the middle level of nesting. 299 If the list of categorical factors is has only zero or one levels of nesting, 300 then this property has no effect. 301 """) 302 303 subgroup_text_font_size = Override(default="11px") 304 subgroup_text_font_style = Override(default="bold") 305 306class DatetimeAxis(LinearAxis): 307 ''' A ``LinearAxis`` that picks nice numbers for tick locations on 308 a datetime scale. Configured with a ``DatetimeTickFormatter`` by 309 default. 310 311 ''' 312 313 ticker = Override(default=lambda: DatetimeTicker()) 314 315 formatter = Override(default=lambda: DatetimeTickFormatter()) 316 317class MercatorAxis(LinearAxis): 318 ''' An axis that picks nice numbers for tick locations on a 319 Mercator scale. Configured with a ``MercatorTickFormatter`` by default. 320 321 Args: 322 dimension ('lat' or 'lon', optional) : 323 Whether this axis will display latitude or longitude values. 324 (default: 'lat') 325 326 ''' 327 def __init__(self, dimension='lat', **kw): 328 super().__init__(**kw) 329 330 # Just being careful. It would be defeat the purpose for anyone to actually 331 # configure this axis with different kinds of tickers or formatters. 332 if isinstance(self.ticker, MercatorTicker): 333 self.ticker.dimension = dimension 334 if isinstance(self.formatter, MercatorTickFormatter): 335 self.formatter.dimension = dimension 336 337 ticker = Override(default=lambda: MercatorTicker()) 338 339 formatter = Override(default=lambda: MercatorTickFormatter()) 340 341#----------------------------------------------------------------------------- 342# Dev API 343#----------------------------------------------------------------------------- 344 345#----------------------------------------------------------------------------- 346# Private API 347#----------------------------------------------------------------------------- 348 349#----------------------------------------------------------------------------- 350# Code 351#----------------------------------------------------------------------------- 352