change figure properties like "axis_label" dynamically

Hi All,

I wanted to change the properties of my figure dynamically.

I have two “Select” widgets and a “Button” widget in my application.

I can select different values in the “Select” widget and my scatter plot should update based on the different values selected in the “Select” widget.

I wanted to change X, Y axis_label properties of the figure based on the values selected in “Select” widget.

I am unable to dynamically change the properties of my figure after changing the values in “Select” widget. Can anybody suggest how to achieve this?

I posted my code as below.

import numpy as np

import pandas as pd

from pandas import DataFrame, Series

from bokeh.plotting import figure

from bokeh.charts import Scatter, defaults

from bokeh.io import output_file, show

from bokeh.layouts import widgetbox, column, row

from bokeh.models.widgets import Dropdown, Select

from bokeh.models import ColumnDataSource, CustomJS, Button, Plot

output_file(“callback.html”)

infy_df = pd.read_csv(“infosys_2011_2016.csv”, sep=’,’)

tcs_df = pd.read_csv(“tcs_2011_2016.csv”, sep=’,’)

wipro_df = pd.read_csv(“wipro_2011_2016.csv”, sep=’,’)

infy_df[‘infy_change’] = ((infy_df[‘Open’] - infy_df[‘Close’])/infy_df[‘Open’]) * 100

tcs_df[‘tcs_change’] = ((tcs_df[‘Open’] - tcs_df[‘Close’])/tcs_df[‘Open’]) * 100

wipro_df[‘wipro_change’] = ((wipro_df[‘Open’] - wipro_df[‘Close’])/wipro_df[‘Open’]) * 100

new_df = pd.merge(infy_df, tcs_df, how=‘inner’, on=‘Date’)[[‘Date’, ‘infy_change’, ‘tcs_change’]]

new_df = pd.merge(new_df, wipro_df, how=‘inner’, on=‘Date’)[[‘Date’, ‘infy_change’, ‘tcs_change’, ‘wipro_change’]]

data_source = ColumnDataSource(data=dict(x=pd.Series(new_df[‘infy_change’]).tolist(),

y=pd.Series(new_df[‘tcs_change’]).tolist(),

Infosys=pd.Series(new_df[‘infy_change’]).tolist(),

TCS=pd.Series(new_df[‘tcs_change’]).tolist(),

Wipro=pd.Series(new_df[‘wipro_change’]).tolist()))

select_source_1 = ColumnDataSource(data=dict(first_stock=‘Infosys’, plt_title=‘Variation in Stock Prices’))

select_source_2 = ColumnDataSource(data=dict(second_stock=‘TCS’))

stock_figure = figure(width=700, height=700)

stock_figure.xaxis.axis_label =‘Infosys’

stock_figure.xaxis.axis_label_text_color = ‘red’

stock_figure.xaxis.axis_label_text_font_style = ‘bold’

stock_figure.yaxis.axis_label =‘TCS’

stock_figure.yaxis.axis_label_text_color = ‘red’

stock_figure.yaxis.axis_label_text_font_style = ‘bold’

stock_figure.title.text = select_source_1.data[‘plt_title’]

stock_figure.scatter(‘x’, ‘y’, source=data_source, fill_color=‘blue’)

button_callback = CustomJS(args=dict(source=data_source,

select_source_1=select_source_1,

select_source_2=select_source_2), code="""

var data = source.get(‘data’);

var select_data_1 = select_source_1.get(‘data’);

var select_data_2 = select_source_2.get(‘data’);

data[‘x’] = data[select_data_1[‘first_stock’]];

data[‘y’] = data[select_data_2[‘second_stock’]];

source.trigger(‘change’);

“”")

select_callback_1 = CustomJS(args=dict(source=select_source_1), code="""

var data = source.get(‘data’);

data[‘first_stock’] = cb_obj.get(‘value’);

source.trigger(‘change’);

“”")

select_callback_2 = CustomJS(args=dict(source=select_source_2), code="""

var data = source.get(‘data’);

data[‘second_stock’] = cb_obj.get(‘value’);

source.trigger(‘change’);

“”")

select_1 = Select(title=“Select Stock 1”, value=“Infosys”, options=[“Infosys”, “TCS”, “Wipro”],

callback=select_callback_1)

select_2 = Select(title=“Select Stock 2”, value=“TCS”, options=[“TCS”, “Infosys”, “Wipro”],

callback=select_callback_2)

#slider = Slider(start=0.1, end=4, value=1, step=.1, title=“power”,callback=CustomJS.from_py_func(callback))

button = Button(label=“Click to Plot Graph”, button_type=“success”, callback=button_callback) #, callback=button_callback

column_layout = column(select_1, select_2, button)

row_layout = row(column_layout, stock_figure)

show(row_layout)

I came up with this technique to change axis labels using CustomJS:

  1. On your fig = figure(…) declaration, set x_axis_location and y_axis_location where you don’t want the final axis to be. For example, If you wanted to have the x-axis on the bottom and y-axis on the left in the final figure, set the following:

x_axis_location=‘above’, y_axis_location=‘right’

  1. Hide the original axes:

fig.xaxis.visible = None

fig.yaxis.visible = None

  1. Declare new axes and add them to the figure (i.e., add them to the opposite sides of the ones that you set in step 1):

from bokeh.models import LinearAxis

xaxis = LinearAxis(axis_label=“Initial x-axis label”)

yaxis = LinearAxis(axis_label=“Initial y-axis label”)

fig.add_layout(xaxis, ‘below’)

fig.add_layout(yaxis, ‘left’)

  1. Add the new axes to the arguments of CustomJS, where you can change their axis_labels:

callback = CustomJS(args=dict(source=source,

xaxis=xaxis,

yaxis=yaxis), code="""

xaxis.attributes.axis_label = “New x-axis label”;

yaxis.attributes.axis_label = “New y-axis label”;

xaxis.trigger(‘change’);

yaxis.trigger(‘change’);

“”")