1

Suppose I have the following bar plot from the documentation:

from bokeh.io import show, output_notebook from bokeh.plotting import figure output_notebook() 
  • Here is a list of categorical values (or factors)
fruits = [`Apples, Pears`, `Nectarines`, `Plums`, `Grapes`, `Strawberries`] 
  • Set the x_range to the list of categories above
p = figure(x_range=fruits, plot_height=250, title=“Fruit Counts”) 
  • Categorical values can also be used as coordinates
p.vbar(x=fruits, top=[5, 3, 4, 2, 4, 6], width=0.9) 
  • Set some properties to make the plot look better
p.xgrid.grid_line_color = None p.y_range.start = 0 show(p) 

How do I set it so that the initial zoom shows only the first four categories (but the user can pan around to see the other two, zoom out, etc.)?

I tried modifying the x_range values, but it looks like x_range needs to equal fruits.

2 Answers 2

0

One option I'm thinking of is to add a slider that enables to filter rows in your dataframe.

You can try this code in a jupyter notebook:

from bokeh.io import show, output_notebook from bokeh.models import ColumnDataSource, CustomJS, Slider, DataRange1d from bokeh.plotting import figure import pandas as pd from bokeh.layouts import column output_notebook() def create_plots(doc): # Create dataframe df = pd.DataFrame({ 'fruits': ['Apples', 'Pears', 'Nectarines', 'Plums', 'Grapes', 'Strawberries'], 'top': [5, 3, 4, 2, 4, 6] }) fruits=list(df['fruits']) max_top = max(df['top']) # Create Column Data Source source = ColumnDataSource(data=df) # Create figure p = figure(x_range=fruits, plot_height=250, title='Fruit Counts', y_range=DataRange1d(0, max_top + 1, only_visible=True), # with DataRange1d + only_visible=True, the # y scale will be updated automatically depending on the data displayed on the chart ) p.vbar(x='fruits', top='top', width=0.9, source=source) p.xgrid.grid_line_color = None p.y_range.start = 0 # Create slider widget slider = Slider(start=1, end=max_top, value=max_top, step=1, title="Slider example - current value") # Update chart with widget value slider.js_on_change("value", CustomJS(code=""" console.log('slider: value=' + this.value, this.toString()) """)) # I'm not comfortable with javascript but this code can be found in Bokeh documentation: # https://docs.bokeh.org/en/latest/docs/user_guide/interaction/widgets.html#slider def update_data(df, max_index): # update the Column Data Source with the filtered data df = df[df.index <= max_index] source.data = df # update the x axis - hidden fruits should not be displayed on the x axis p.x_range.factors = list(df['fruits']) def update(attr, old, new): max_index_to_display = slider.value - 1 update_data(df, max_index_to_display) slider.on_change('value', update) # call the update funtion everytime the slider is clicked on # Layout doc.add_root(column(slider, p)) show(create_plots) 
Sign up to request clarification or add additional context in comments.

Comments

0

It is not possible to use a CategoricalAxis with a FactorRange and set the x_range because start and end are readonly properties.

But there are workarounds, two are listed below.

using CustomJSTickFormatter

In the bokeh version 3.0.0 a CustomJSTickFormatter was added. With this it is possible to use a normal LinearRange and format the ticks. With this approach you can set x_range as you like it.

from bokeh.models import CustomJSTickFormatter, Range1d from bokeh.plotting import figure, show, output_notebook output_notebook() fruits = ["Apples", "Pears", "Nectarines", "Plums", "Grapes", "Strawberries"] x = list(range(len(fruits))) y = [5, 3, 4, 2, 4, 6] p = figure(height=250, title="Fruit Counts") p.x_range = Range1d(-0.5, 3.5, bounds=(-0.5, 4.5)) p.y_range = Range1d(0, 7) p.vbar(x=x, top=y, width=0.9) p.xgrid.grid_line_color = None p.xaxis.formatter = CustomJSTickFormatter( code=""" var new_tick= tick.toFixed(2) const fruits = ["Apples", "Pears", "Nectarines", "Plums", "Grapes", "Strawberries"] const range = [...Array(fruits.length).keys()] if( tick in range ) new_tick= fruits[tick] else new_tick= '' return new_tick """ ) p.xaxis.minor_tick_line_color = None p.xaxis.axis_label_text_color = None show(p) 

using FixedTicker and major_label_overrides

With a FixedTicker you can set the ticks to you wanted positions and major_label_overrides offers you the opportunity to set the label text very precise. This is also available before the 3.0.0 release.

from bokeh.models import FixedTicker, Range1d from bokeh.plotting import figure, show, output_notebook output_notebook() fruits = ["Apples", "Pears", "Nectarines", "Plums", "Grapes", "Strawberries"] x = list(range(len(fruits))) y = [5, 3, 4, 2, 4, 6] p = figure(height=250, title="Fruit Counts") p.x_range = Range1d(-0.5, 3.5, bounds=(-0.5, 4.5)) p.y_range = Range1d(0, 7) p.vbar(x=x, top=y, width=0.9) p.xgrid.grid_line_color = None p.xaxis.ticker = FixedTicker( desired_num_ticks=len(fruits), num_minor_ticks = 0, ticks=x ) p.xaxis.major_label_overrides = {i: label for i, label in zip(x, fruits)} show(p) 

The visual results should be the same and the inital view looks like below:

initial view

1 Comment

Unfortunately I have to use an earlier version of Bokeh, which doesn't support CustomJStickFormatter.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.