Search code examples
pythonfloating-pointprecisionbokehweibull

Custom tick labels in Bokeh with floating point tick values


I want to make "Weibull paper" in Bokeh, which requires me to do a custom transform on the y-axis and add appropriate y-axis labels.

I am following the instructions in the accepted answer to this stackoverflow question: How do I use custom labels for ticks in Bokeh?

Here are the relevant five lines of my code:

yticks = np.array([1, 5, 10, 50, 99])
ytick_loc = np.log(np.log(1 / (1 - yticks/100)))
fig.yaxis.ticker = ytick_loc
tick_labels = [str(ytick) for ytick in yticks]
fig.yaxis.major_label_overrides = dict(zip(ytick_loc, tick_labels))

What I would expect: 5 ticks on the plot, with the labels '1', '5', '10', '50', and '99'.

What I get: 5 ticks on the plot, with the labels '1', '-2.97', '10', '-0.367', and '99'. So some of the labels changed as I wanted them to and some stayed at their figure y-values.

Picture of Bokeh plot showing weird y-axis labelling

I am guessing this has something to do with tolerances on floating point numbers or something, with the ticks in the dictionary not exactly matching the ticks on the plot. I would be ok with very slightly rounding the values if it would fix this issue, but I am not sure to what tolerance I could do that and have it work.

Any suggestions for workarounds?


Solution

  • As I mentioned in a comment to the other answer, the behaviour in the question only happens on my work computer, and not on my home computer. I haven't figured out if it is the browser, the python version, or some other libraries, but it's not the Bokeh version.

    The following code doesn't have the problem:

    from bokeh.io import output_file, show
    from bokeh.plotting import figure
    import numpy as np
    
    fig = figure()
    fig.circle(x=[5,5,5,5,5], y=[-10,-5,0,1,2], size=10)
    
    yticks = np.array([1, 5, 10, 50, 99])
    ytick_loc = np.log(np.log(1 / (1 - yticks/100)))
    ytick_loc = np.around(ytick_loc, 15)
    fig.yaxis.ticker = ytick_loc
    tick_labels = [str(ytick) for ytick in yticks]
    fig.yaxis.major_label_overrides = dict(zip(ytick_loc, tick_labels))
    
    output_file("test.html")
    
    show(fig)
    

    The specific line that I added was:

    ytick_loc = np.around(ytick_loc, 15)
    

    I will note that rounding to 16 figures was enough to fix one of the two ticks with errors, but it took rounding to 15 to fix both. I don't know how general a solution this is, that is, whether it would work for arbitrary floating point numbers, but it has solved my current issue.