Search code examples
pythonbokeh

how to add secondary x-axis with my String labels


I have plot enter image description here

with secondary axis added like this:

    plot.extra_x_ranges['sec_x_axis'] = Range1d(0, 100)
    ax2 = LinearAxis(x_range_name="sec_x_axis", axis_label="secondary x-axis")
    plot.add_layout(ax2, 'above')

x_axis is x_axis_type='datetime', so bokeh show ms on second x-axis too. This is not good.
Is there a way I can put my labels on this axis? I have a list of str labels like:

my_labels = ['21.5; 315.1', '21.6; 315.0', '21.7; 315.0', '21.7; 314.9',.....]

I found FuncTickFormatter but it takes JS code inside, so I can't handle it. Maybe there is another way to do this?


Solution

  • To override the values of the labels use major_label_overrides on the appropriate axis. You can pass a dictionary like {1:'A', ...}, where 1 is the place to overwrite and A is the new label. To avoid "wrong" labels while zooming, you can set the ticker direcetlly as list unsing ticker. In your case the axis is p.above[0].

    Comment

    If you add a LinearAxis to a figure with an already existing DatetimeAxis, the new axis shoudn't be effected and therefor shouldn't be formatted as datetime. I used the latest version 2.4.3 and it works as expected. Use the minimal example to try it on your own.

    Minimal Example

    This code is based on the twin_axis.py example published by the authors of bokeh.

    from numpy import arange, linspace, pi, sin
    
    from bokeh.models import LinearAxis, Range1d
    from bokeh.plotting import figure, show, output_notebook
    output_notebook()
    
    x = arange(-2*pi, 2*pi, 0.2)
    x2 = arange(-pi, pi, 0.1)
    y = sin(x)
    y2 = sin(x2)
    
    p = figure(
        width=400,
        height=400,
        x_range=(-6.5, 6.5),
        y_range=(-1.1, 1.1),
        min_border=80,
        x_axis_type="datetime"
    )
    
    p.circle(x, y, color="crimson", size=8)
    p.yaxis.axis_label = "red circles"
    p.yaxis.axis_label_text_color ="crimson"
    
    p.extra_x_ranges['foo'] = Range1d(-pi, pi)
    p.circle(x2, y2, color="navy", size=8, x_range_name="foo")
    ax2 = LinearAxis(x_range_name="foo", axis_label="blue circles")
    ax2.axis_label_text_color ="navy"
    p.add_layout(ax2, 'above')
    
    # set ticker to avoid wrong formatted labels while zooming
    p.above[0].ticker = list(range(-3,4))
    # overwrite labels
    p.above[0].major_label_overrides = {key: item for key, item in zip(range(-3,4), list('ABCDEFG'))}
    
    show(p)
    
    default overwritten labels
    sinus over time default sinus over time