What I want to do:
I made a dynamic map using bokeh, pandas and geopandas. The data to be displayed is loaded from a table, then mapped to a country per year. The year to be displayed is determined by a bokeh slider. You can also hover over a country and get its value. I now want to be able to change the data source by selecting a radio button. To display the data correctly, I want to change the color palette, rescale it (a range from e.g. 50 to 100 instead of 0 to 4.5), update the scaling on the slider to the new lowest year to highest year, and then display the world-map with the new data. I also want to update the title of the map from e.g. "Fertility" to "Life expectancy".
What I already have:
I have a working dynamic map with Slider and Hover tool. I also have a list from which the data to be used is taken (datapath, title to be used, color palette to be used, highest and lowest year, highest and lowest value). I have a radio button group, with three different data sources to choose from. All paths are relative, the data is provided with a consistent structure. I had the map changing the data below and displaying the new stuff, but than I did something and it stopped working. I also had the Hover tool display the right values, but with a wrong (old) description.
What I need help with:
- Updating the color bar to accomodate the new palette and the new range
- Updating the slider to accomodate a changed range
- Updating the title displayed to show what's actually displayed
What I already tried:
I've put the whole loading and displaying in the function executed when the radio button group is changed. The first thing this function does is clearing the layout and then rebuilding it. Unfortunately, this is neither efficient, nor working, since I only get the radio button Group and an empty space below, no matter what I do. I've searched for a solution, but all I found (and tried) didn't do what I needed.
I can provide the actual code, if needed (though some of the variables and documentations are in German), but since I'm pretty new to the whole python thing, I don't now, what exactly of that about 300 lines of code you need. Just let me now, and I'll try and provide.
Hope you can help me with that.
Thanks in advance,
Asd789
EDIT: As correctly pointed out in the comments, some code to help understand what I did. I'll cut all the imports for the sake of brevity, as a mistake there would have shown up as error in my terminal. Also leaving out comments.
geoFrame #dataframe for geopanda shapefile
configList = [0, "Fertility", 'YlGnBu', 'Year' ]
df #dataframe for the .csv file
higStep = df['step'].max()
lowStep = df['step'].min()
configList.append(higStep)
higVal = df['valueInterest'].max()
merged = geoFrame.merge(df, left_on = 'country_code', right_on = 'code')
merged_json = json.loads(merged.to_json())
json_data = json.dumps(merged_json)
geosource = GeoJSONDataSource(geojson = json_data)
palette = brewer[configList[2]][8]
color_mapper = LinearColorMapper(palette = palette, low = 0, high = 4)
color_bar = ColorBar(color_mapper=color_mapper, label_standoff=8,width = 500, height = 20,
border_line_color=None,location = (0,0), orientation = 'horizontal')
p = figure(title = configList[1], plot_height = 600 , plot_width = 950, toolbar_location = None)
p.xgrid.grid_line_color = None
p.ygrid.grid_line_color = None
p.patches('xs','ys', source = geosource,fill_color = {'field' :'valueInterest', 'transform' : color_mapper},
line_color = 'black', line_width = 0.25, fill_alpha = 1)
p.add_layout(color_bar, 'below')
df_curr = df[df['step'] == higStep]
color_mapper = LinearColorMapper(palette = palette, low = 0, high = 40, nan_color = '#d9d9d9')
def json_data(selectedStep):
st = selectedStep
df_st = df[df['step'] == st]
merged = geoFrame.merge(df_st, left_on = 'country_code', right_on = 'code', how = 'left')
merged_json = json.loads(merged.to_json())
json_data = json.dumps(merged_json)
return json_data
geosource = GeoJSONDataSource(geojson = json_data(higStep))
palette = brewer[configList[2]][8]
palette = palette[::-1]
color_mapper = LinearColorMapper(palette = palette, low = 0, high = higVal/2, nan_color = '#d9d9d9')
hover = HoverTool(tooltips = [ ('Country/region','@country'),(configList[1], '@valueInterest')])
color_bar = ColorBar(color_mapper=color_mapper, label_standoff=8,width = 500, height = 20,
border_line_color=None,location = (0,0), orientation = 'horizontal')
p = figure(title = configList[1], plot_height = 600 , plot_width = 950, toolbar_location = None, tools = [hover])
p.xgrid.grid_line_color = None
p.ygrid.grid_line_color = None
p.patches('xs','ys', source = geosource,fill_color = {'field' :'valueInterest', 'transform' : color_mapper},
line_color = 'black', line_width = 0.25, fill_alpha = 1)
p.add_layout(color_bar, 'below')
def update_plot(attr, old, new):
st = slider.value
new_data = json_data(st)
geosource.geojson = new_data
p.title.text = configList[1] %st
slider = Slider(title = configList[3],start = 1950, end = 2015, step = 1, value = 2015)
slider.on_change('value', update_plot)
def radHandler(attr, new, old):
if radio.active == 0:
datapath = os.path.join(dataloc, 'children-per-woman-UN.csv')
configList = [0, "Fertility", 'YlGnBu', 'Year']
elif radio.active == 1:
#see above with diferent data
elif radio.active == 2:
#see above with different data
curdoc().clear()
higStep = df['step'].max()
lowStep = df['step'].min()
configList.append(higStep)
update_plot(attr, new, old)
hover = HoverTool(tooltips = [ ('Country/region','@country'),(configList[1], '@valueInterest')])
palette = brewer[configList[2]][8]
palette = palette[::-1]
olor_mapper = LinearColorMapper(palette = palette, low = 0, high = higVal/2, nan_color = '#d9d9d9')
color_bar = ColorBar(color_mapper=color_mapper, label_standoff=8,width = 500, height = 20,
border_line_color=None,location = (0,0), orientation = 'horizontal'
p = figure(title = configList[1]+' '+str(configList[4]), plot_height = 600 , plot_width = 950, toolbar_location = None, tools = [hover])
layout = column(widgetbox(radio),p,widgetbox(slider))
curdoc().add_root(layout)
radio = RadioButtonGroup(labels=['Fertility', 'Life expectancy', 'Covid-19 total cases'], active=0)
radio.on_change('active',radHandler)
layout = column(p, widgetbox(radio),widgetbox(slider))
curdoc().title = configList[1]
curdoc().add_root(layout)
Sorry I could'nt cook it down further, but I don't know what's essential and what's just fancy stuff around.
This code works until I touch the radio button group. After that, the plot itself is just blank, without any prompts anywhere. The code itself is not entirely my fault, I got it to fix and maybe expand on it, the expansion being the ability to switch between data sources as decribed above.