Hello, I’m trying to build an interactive pie chart that displays data from a csv file depending on the year specified by the user.
This is a picture of the data frame im working with
This is an auxiliary function I’ve defined to help with the plotting of the pie chart
# Create custom data to be displayed onto the chart i.e gen_data(1990) = CDS({"Disease: [" Meningitis ", " Alzheimer's disease and other dementias ",...], "Deaths":[2159, 1116...],...})
def gen_data2(year):
idx = year - 1990
data = {
"Disease": df.columns[1:].to_list(),
"Deaths": df.loc[idx][1:].reset_index(drop=True).to_list(),
"Percentage": (df.loc[idx][1:] / sum(df.loc[idx][1:]) * 100).reset_index(drop=True).to_list(),
"Angle": (df.loc[idx][1:] / sum(df.loc[idx][1:]) * 2*pi).reset_index(drop=True).to_list(),
"Colour": colours}
return ColumnDataSource(data=data)
# Not important but here is the code for the colours list
from bokeh.palettes import Turbo256
split = 0
for i in range(len(df.columns[1:])):
colours.append(Turbo256[split])
split += int(len(Turbo256) / (len(df.columns)) - 1)
# source_dict = {"1990": CDS(gen_data2(1990)), 1991: CDS(gen_data2(1991)), ...}
# rend_dict, creates a pie chart for every year's data
for j in df["Year"]:
source_dict[str(j)] = gen_data2(j)
rend_dict[str(j)] = p.wedge(x=0, y=0, radius=0.5, start_angle=cumsum('Angle', include_zero=True), end_angle=cumsum('Angle'), line_color="white", fill_color='Colour', source=source_dict[str(j)])
So the idea of the JS callback is to effectively “remove” (empty) the CDS data for a specific year in source_dict if the year is not selected by the slider widget and hence this won’t be displayed on the final plot. Or vice versa start with an empty source_dict and add data for years selected by the slider widget, same idea.
This is the code for my master source pretty much, so its similar to source_dict but instead the format is CDS(“Disease”:[list all names once, twice, three times etc etc], ‘Deaths’: [death numbers for disease 1, disease 2, disease 3 etc])
all values are stored in a single list
source = ColumnDataSource({'Disease': [], 'Deaths': [], 'Percentage': [], 'Angle': [], 'Colour': []})
for i in source.data.keys():
for j in df["Year"]:
for k in gen_data2(j).data[i]:
source.data[i].append(k)
cjs = CustomJS(args=dict(sl=slider, source=source, source_dict=source_dict),code='''
var year = cb_obj.value;
var upd_source = {};
var multiplier = year - 1990;
for (const [k,v] of Object.entries(source_dict)){
upd_source[k] = [];
}
for (const [k,v] of Object.entries(source.data)) {
if (v >= multiplier * 31 && v < multiplier * 32) {
upd_source[k].push(source.data[k][v]);
}
}
// Loops through the source_dict (i.e {"1990": CDS({Disease: [...]...,})})
/* Find whether the year k is the same as the slider value, if so set the CDS data for that year
as the value in upd_source["Disease"/"Deaths"...] (for e.g) */
for (const [k,v] of Object.entries(source_dict)){
if (k == year) {
for (const [a,b] of Object.entries(source.data)) {
v.data = upd_source[a];
}
} else {
for (let key in v.data) {
v.data[key] = [];
}
}
}
''')
Above is my js code to do what I mentioned above about removing values from source_dict however I keep getting an invalid value message. Any help on why this js code is not working would be greatly appreciated
data from Causes of Death - Our World in Data