0

I have a linear Bokeh plot under Bokeh version 3.3.0. I would like to add a (scatter) plot on an additional x-axis with logarithmic scale. This is my code:

import pandas as pd
from bokeh.plotting import figure, show, ColumnDataSource
from bokeh.layouts import gridplot 
from bokeh.models import LogAxis, LinearAxis, Label, LabelSet, Title, Range1d 

# A simple dataframe with time, UTCs, altitude and two columns of imaginary data
df = pd.DataFrame([['2024-06-21 06:22:38', 605.968389, 0.994548, 3],
                   ['2024-06-21 06:22:39', 616.009398, 0.983443, 4],
                   ['2024-06-21 06:22:40', 624.630573, 0.973647, 1],
                   ['2024-06-21 06:22:41', 633.476367, 1.017651, 2],
                   ['2024-06-21 06:22:42', 642.322161, 5.017651, 2],
                   ['2024-06-21 06:22:43', 650.268389, 30.726555, 4],
                   ['2024-06-21 06:22:44', 659.559398, 89.2359, 5],
                   ['2024-06-21 06:22:45', 665.630573, 6.92018, 3],
                   ['2024-06-21 06:22:47', 673.476367, 0.69398, 2],
                   ['2024-06-21 06:22:48', 685.322161, 0.770802, 1],
                   ['2024-06-21 06:22:49', 697.155939, 0.856488, 0],
                   ['2024-06-21 06:22:51', 716.763057, 0.934408, 3],
                   ['2024-06-21 06:22:52', 722.012345, 7.865522, 2],
                   ], 
                  columns=['time', 'Altitude', 'log_data', 'linear_data'])

#Linear Plot with second x-axis in logarithmic scale
p = figure(title="Combined linear / log x-axes", 
           x_axis_label="Linear Data",
           y_axis_label="Altitude / km", 
           x_axis_type='linear',
           frame_height = 900,
           frame_width = 650,
           )
p.xaxis.axis_label_text_color = "red"

# linear data
p1 = p.line('linear_data', 
            'Altitude',
            line_color='red', 
            line_width=2, 
            source = df)

# log data
p.add_layout(LinearAxis(x_range_name = "x2", 
                        axis_label="Log data",
                        axis_label_text_color='blue',),
            'below' )

p2 = p.scatter('log_data', 
               'Altitude', 
               line_color='blue', 
               line_width=2,
               x_range_name = 'x2', 
               source = df)

# Range of additional x-axis:
p.extra_x_ranges = {"x2": Range1d(start = 0, 
                                  end = 115),
                   }

# Graphical output:
layout_p =  gridplot([p], ncols=1, width=700, height=900)
show(layout_p)

I changed LinearAxis into LogAxis

# log data
p.add_layout(LogAxis(x_range_name = "x2", 
                        axis_label="Log data",
                        axis_label_text_color='blue',),
            'below' )

but this caused the second axis to be displayed without any ticks and the scatter plot was still shown on a linear base. Any hint for me?

2 Answers 2

1

The log axis has no ticks because the range includes 0, which is not defined for log scale and no valid tick values can be computed.

If you apply a change to your range `x2` like below, both x-axis will have some ticks.

p.extra_x_ranges = {"x2": Range1d(start = 0.1, end = 115)}

But it looks like bokeh is not able to allow linear and log axis at the same time. So I suggest that you try to make your data compatible for log to linear axis or you create two separate figures.

Sign up to request clarification or add additional context in comments.

1 Comment

the solution you suggested causes the additional axe to be displayed shifted in relation to the graphic and is unfortunately not a solution to my problem.
0

After another search, I finally found a solution. Once I had found it, it seemed logical that something was still missing:

In the header section, the following must also be imported: from bokeh.models import LogScale

And then the additional axis must be defined as a logarithmic scale: p.extra_x_scales['x2'] = LogScale()

I changed the code a bit to make the result easier to see:

  • the linear axis range is from 0 to 10 now

  • the logarithmic curve is now a line instead of a scatter plot

  • its starting range is 0,1 instead of 0

  • I also made the chart a bit smaller to save space ;-)

And here is the code:

import pandas as pd
from bokeh.plotting import figure, show, ColumnDataSource
from bokeh.layouts import gridplot 
from bokeh.models import LogAxis, LogScale, LinearAxis, Label, LabelSet, Title, Range1d 

# A simple dataframe with time, UTCs, altitude and two columns of imaginary data
df = pd.DataFrame([['2024-06-21 06:22:38', 605.968389, 0.994548, 3],
                   ['2024-06-21 06:22:39', 616.009398, 0.983443, 4],
                   ['2024-06-21 06:22:40', 624.630573, 0.973647, 1],
                   ['2024-06-21 06:22:41', 633.476367, 1.017651, 2],
                   ['2024-06-21 06:22:42', 642.322161, 5.017651, 2],
                   ['2024-06-21 06:22:43', 650.268389, 30.726555, 4],
                   ['2024-06-21 06:22:44', 659.559398, 89.2359, 5],
                   ['2024-06-21 06:22:45', 665.630573, 6.92018, 3],
                   ['2024-06-21 06:22:47', 673.476367, 0.69398, 2],
                   ['2024-06-21 06:22:48', 685.322161, 0.770802, 1],
                   ['2024-06-21 06:22:49', 697.155939, 0.856488, 0],
                   ['2024-06-21 06:22:51', 716.763057, 0.934408, 3],
                   ['2024-06-21 06:22:52', 722.012345, 7.865522, 2],
                   ], 
                  columns=['time', 'Altitude', 'log_data', 'linear_data'])

`#Linear Plot with second x-axis in logarithmic scale
p = figure(title="Combined linear / log x-axes", 
           x_axis_label="Linear Data",
           y_axis_label="Altitude / km", 
           x_axis_type='linear',
           x_range = (0,10),
           frame_height = 600,
           frame_width = 450,
           )
p.xaxis.axis_label_text_color = "red"

# linear data
p1 = p.line('linear_data', 
            'Altitude',
            #legend_label="Temperature", 
                    line_color='red', 
                    line_width=2, 
                    source = df )

# log data
p.add_layout(LogAxis(x_range_name = "x2", 
                       axis_label="Log data",
                       axis_label_text_color='blue',
                       ),
                     #axis_line_color=f2), 
                 'below' )

p2 = p.line('log_data', 
               'Altitude', 
                   #legend_label="Relative Humidity", 
                    line_color='blue', 
                    line_width=2,
                    x_range_name = 'x2', 
                    source = df)

# Range of additional x-axis:
p.extra_x_ranges = {"x2": Range1d(start = 0.1, 
                                  end = 115),
                   }
p.extra_x_scales['x2'] = LogScale()
                   
layout_p =  gridplot([p], ncols=1, width=400, height=500)
show(layout_p)

This is the resulting picture:

enter image description here

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.