def bivariate_plot(self): df = self._bivariate_dataset() p = figure(x_range=DataRange1d(range_padding=.1), y_range=DataRange1d(range_padding=0.1), background_fill_color="#fafafa") source = ColumnDataSource(df) p.scatter('x', 'y', source=source) def bivariate_custom_js(source, col): return CustomJS(args={ 'source': source, 'col': col }, code=""" var data = source.data; data[col] = data[cb_obj.value]; source.change.emit(); """) cols = self.data.columns.tolist() x_select = Select(title="Select x:", value=cols[0], options=cols) y_select = Select(title="Select y:", value=cols[1], options=cols) # Add the callback to the select widget. y_select.callback = bivariate_custom_js(source=source, col='y') x_select.callback = bivariate_custom_js(source=source, col='x') l = layout([[x_select, y_select], [p]]) show(l)
def univariate_plot(self, bins=25, density=True): objs = self._univariate_dataset(bins, density) # Change this to df.assign df = pd.concat(*[objs], axis=1) df[['top', 'left', 'right']] = df.iloc[:, 0:3] source = ColumnDataSource(df) p = figure(tools='', background_fill_color="#fafafa") p.quad(top='top', bottom=0, left='left', right='right', source=source, fill_color="navy", line_color="white", alpha=0.5) def univariate_custom_js(source): return CustomJS(args={'source': source}, code=""" var data = source.data; var prefix = cb_obj.value; data['top'] = data['top_'.concat(prefix)]; data['left'] = data['left_'.concat(prefix)]; data['right'] = data['right_'.concat(prefix)]; source.change.emit(); """) cols = self.data.columns.tolist() x_select = Select(title="Select x:", value=cols[0], options=cols) x_select.callback = univariate_custom_js(source=source) show(layout([p, x_select]))
def create_dropdown_ycom(n_ycom_meta, callback_ycom): """ Setting up dropdown menu for census and associating the callback to autoupdate inputs: n_ycom_meta: list of dropdown options based on ycom variable descriptions from metadata callback_ycom: custom javascript describing callback behaviour """ ycom_menu = Select(options=n_ycom_meta, value='v', title='YCOM Variables') ycom_menu.callback = callback_ycom return ycom_menu
def create_dropdown_census(n_census, callback_census): """ Setting up dropdown menu for census and associating the callback to autoupdate inputs: n_census: list of dropdown options based on variable names callback_census: custom javascript describing callback behaviour """ census_menu = Select(options=n_census, value='v', title='Census Variables') census_menu.callback = callback_census return census_menu
def _make_plot(n_cols): df = self.data source = ColumnDataSource( df.assign(**{ 'feature_{}'.format(i): df.iloc[:, i] for i in range(n_cols) })) grid_size = range(n_cols) cols = df.columns.to_list() for i, (x, y) in enumerate(product(grid_size, grid_size)): p = figure(x_range=DataRange1d(range_padding=0.1), y_range=DataRange1d(range_padding=0.1), plot_width=175, plot_height=175, output_backend="webgl") p.scatter('feature_{}'.format(y), 'feature_{}'.format(x), source=source) #Define show axis conditions cond_one, cond_two = i % n_cols == 0, x == n_cols - 1 #Add explanation for logic here if cond_one: p.plot_width += (p.plot_width // 4) p.yaxis.axis_label = 'Feature {}'.format(x + 1) if cond_two: p.plot_height += (p.plot_height // 4) p.xaxis.axis_label = 'Feature {}'.format(y + 1) p.xaxis.visible = True else: p.xaxis.visible = False elif cond_two: p.yaxis.visible = False p.xaxis.axis_label = 'Feature {}'.format(y + 1) p.plot_height += (p.plot_height // 4) else: p.yaxis.visible = p.xaxis.visible = False # Remove the gridlines p.xgrid.grid_line_color = p.ygrid.grid_line_color = None # Remove the minor axis lines p.yaxis.minor_tick_line_color = None p.xaxis.minor_tick_line_color = None yield p for i in range(n_cols): select = Select( value=cols[i], options=cols, width=(p.plot_width + (p.plot_width // 4)) if i == 0 else p.plot_width) # Once None has been yielded for the first def xaxis_custom_js(source, i): return CustomJS(args={ 'source': source, 'i': i }, code=""" var data = source.data; var col = i; data['feature_'.concat(col)] = data[cb_obj.value]; source.change.emit(); """) select.callback = xaxis_custom_js(source=source, i=i) yield select
def create_ui(self, data): self.logger.info("number of data items %d", len(data)) # Create data source and data table # path, score, software_id, featcnt, featfreq, app name, app path, decision, status, comment, active in play, still voilating decision_editor = SelectEditor(options=[ "Unprocessed", "GPL Violation", "LGPL Violation", "Open Source App", "False Positive", "False Negative (LGPL)", "False Negative (GPL)" ]) status_editor = SelectEditor(options=[ "Unprocessed", "Emailed", "Confirmed", "Denied", "Authorized" ]) if self.app_info: columns = [ TableColumn(field="myindex", title="Id"), TableColumn(field="path", title="File Path"), TableColumn(field="score", title="Score"), TableColumn(field="normscore", title="NormScore", formatter=NumberFormatter(format="0.00")), TableColumn(field="partial", title="PartialMatch"), TableColumn(field="repo_id", title="Repo ID"), TableColumn(field="software_name", title="OSS"), TableColumn(field="version", title="Version"), TableColumn( field="featcnt", title="FeatCount", ), TableColumn( field="featfreq", title="FeatFreq", ), TableColumn(field="package_name", title="Package"), TableColumn(field="app_path", title="App Path"), TableColumn(field="app_count", title="App Count"), TableColumn(field="decision", title="Decision", editor=decision_editor), TableColumn(field="status", title="Status", editor=status_editor), TableColumn(field="comment", title="Comment"), # I am not sure whether we should add these two fields here. # TableColumn(field="active", title="Active in Play"), # TableColumn(field="still_violating", title="Still Violating"), ] else: template_str = '<a href="' + self.REPO_URL + '/<%= value %>"><%= value %></a>' columns = [ TableColumn( field="myindex", title="Id", ), TableColumn(field="name", title="Name"), TableColumn(field="score", title="Score", formatter=NumberFormatter(format="0.00")), TableColumn(field="normscore", title="NormScore", formatter=NumberFormatter(format="0.00")), TableColumn(field="partial", title="PartialMatch"), TableColumn(field="repo_id", title="RepoID"), TableColumn( field="software_name", title="OSS", formatter=HTMLTemplateFormatter(template=template_str)), TableColumn(field="featcnt", title="FeatCount", formatter=NumberFormatter(format="0,000,000")), TableColumn(field="featfreq", title="FeatFreq", formatter=NumberFormatter(format="0,000,000")), TableColumn(field="version", title="Version"), TableColumn(field="decision", title="Decision", editor=decision_editor), TableColumn(field="status", title="Status", editor=status_editor), TableColumn(field="comment", title="Comment"), TableColumn(field="path", title="Path"), ] # source is the displayed table, and can be modified by user # original_source is the original data, it is the base, and can only be modified by the program self.source = ColumnDataSource(self._data) self.original_source = ColumnDataSource(self._data) self.data_table = DataTable(source=self.source, columns=columns, width=2000, height=2000, editable=True, sortable=True) # Disable sortable for now! # selector or filters # reference link for callback: https://gist.github.com/dennisobrien/450d7da20daaba6d39d0 min_matching_score_slider = Slider(start=0, end=2, value=0.3, step=.01, title="Minimum Matching Score") max_matching_score_slider = Slider(start=0, end=2, value=0.7, step=.01, title="Maximum Matching Score") featfreq_slider = Slider(start=0, end=10000, value=0, step=1, title="Minimum Matching Num of Features") featcnt_slider = Slider(start=0, end=10000, value=50, step=1, title="Minimum Feature Count is OSS") kind_select = Select(value="All", options=["All", "Java", "Native"]) file_select = Select(value="Name", options=["Name", "MD5", "Path"]) search_input = TextInput(value=None, title="Enter library to search", callback=None) search_button = Button(label="Search", button_type="success") download_callback_code = """ var data = source.get('data'); var filetext = 'Id,File Name,Matching Score,Normalized Matching Score,Repo ID,Software Name,Feature Count,Feature Freq.,Version,Decision,Status,Comment,File Path\\n'; var order = ['myindex', 'name', 'score', 'normscore', 'repo_id', 'software_name', 'featcnt', 'featfreq', 'version', 'decision', 'status', 'comment', 'path']; for (var i = 0; i < data['path'].length; ++i) { var currRow = []; for (var item in order) { key = order[item] currRow.push(data[key][i]); } var joined = currRow.join().concat('\\n'); filetext = filetext.concat(joined); } var filename = 'violations.csv'; var blob = new Blob([filetext], { type: 'text/csv;charset=utf-8;' }); //addresses IE if (navigator.msSaveBlob) { //navigator.msSaveBlob(blob, filename); } else { var link = document.createElement("a"); link = document.createElement('a'); link.href = URL.createObjectURL(blob); link.download = filename; link.target = "_blank"; link.style.visibility = 'hidden'; link.dispatchEvent(new MouseEvent('click')); } """ # enable downloading of results as a csv file download_button = Button(label="Download", button_type="success") download_button.callback = CustomJS(args=dict(source=self.source), code=download_callback_code) # enable comparison of selected rows compare_button = Button(label="Compare", button_type="success") compare_button.on_click(self.compare_callback) # update on change #controls = [min_matching_score_slider, max_matching_score_slider, featfreq_slider, \ # featcnt_slider, kind_select, file_select, button] #for item in controls: # item.on_change('value', lambda attr, old, new: self.update_source(item)) combined_callback_code = """ var data = source.get('data'); var original_data = original_source.get('data'); var min_score = min_matching_score_slider.get('value'); var max_score = max_matching_score_slider.get('value'); var search_input = search_input.get('value'); var min_featfreq = featfreq_slider.get('value'); var min_featcnt = featcnt_slider.get('value'); var kind = kind_select.get('value'); console.log("min score: " + min_score + ", max score: " + max_score + ", min_featfreq: " + min_featfreq + ", min_featcnt" + min_featcnt + ", kind" + kind); var java_suffix = ".dex"; var native_suffix = ".so"; console.log("searchinput: " + search_input); var re; if (search_input) { re = new RegExp(search_input); } else { re = new RegExp(".*"); } for (var key in original_data) { data[key] = []; for (var i = 0; i < original_data['path'].length; ++i) { if ((original_data['normscore'][i] >= min_score) && (original_data['normscore'][i] <= max_score) && (original_data['featfreq'][i] >= min_featfreq) && (original_data['featcnt'][i] >= min_featcnt)) { // filter by java if (kind == "Java" && original_data['path'][i].indexOf(java_suffix, original_data['path'][i].length - java_suffix.length) === -1) continue; // filter by native if (kind == "Native" && original_data['path'][i].indexOf(native_suffix, original_data['path'][i].length - native_suffix.length) === -1) continue; // filter by search regex if (!re.test(original_data['name'][i])) { console.log("mismatch: " + original_data['name'][i]); continue; } // this row is the expected kind data[key].push(original_data[key][i]); } } } source.trigger('change'); target.trigger('change'); """ generic_callback = CustomJS(args=dict( source=self.source, original_source=self.original_source, search_input=search_input, max_matching_score_slider=max_matching_score_slider, min_matching_score_slider=min_matching_score_slider, featfreq_slider=featfreq_slider, featcnt_slider=featcnt_slider, kind_select=kind_select, target=self.data_table), code=combined_callback_code) min_matching_score_slider.callback = generic_callback max_matching_score_slider.callback = generic_callback featfreq_slider.callback = generic_callback featcnt_slider.callback = generic_callback search_button.callback = generic_callback kind_select.callback = generic_callback # install callback when a row gets selected self.source.on_change('selected', self.selected_callback) ########################################################### # Main ########################################################### controls = [min_matching_score_slider, max_matching_score_slider, featfreq_slider, \ featcnt_slider, kind_select, file_select, search_input, search_button, \ download_button, compare_button] plots_box = widgetbox(*controls, width=800, sizing_mode="fixed") layout = column(plots_box, self.data_table, sizing_mode="fixed") return layout
def generateDiffHtml(self, normalized = False, html_out = None, show_page = False, combined = False, fullStats = False): """ Use `bokeh` to convert a summaryStats dataframe to interactive html table. Parameters ---------- normalized : bool, opt If True generate html table with normalizedStats html_out : str, opt Name of the html that will be output and saved. If no string is provided then the html table will not be saved. show_page : bool, opt If True the html page generate by this function will automatically open in your browser combined : bool, opt If True the html produce will have columns for the original summaryStats values, as well as their normalized values. The baselineRun used to calculate the normalized values will be dropped from the table. fullStats : bool, opt If False the final html table will not include summaryStats that contain '3Sigma','Rms','Min','Max','RobustRms', or '%ile' in their names. """ if not _BOKEH_HERE: raise ImportError('This method requires bokeh to be installed.'+ '\n' 'Run: pip install bokeh'+'\n' + 'Then restart your jupyter notebook kernel.') if html_out is not None: output_file(html_out, title = html_out.strip('.html')) if normalized is False: # HTML table based on summary stat values dataframe = self.headerStats.T.merge(self.summaryStats.T, left_index=True, right_index=True) else: # HTML table based on normalized summary stats dataframe = self.headerStats.T.merge(self.normalizedStats.T, left_index=True, right_index=True) if combined is True: # HTML table of combined stat values and normalized values into single table. # The baseline run is removed from the final table. # The normalized values are given a suffix of '_norm' combo = self.summaryStats.T.merge(self.normalizedStats.T, left_index=True, right_index=True, suffixes=('','_norm')).drop([self.baselineRun+'_norm'],axis=1) dataframe = self.headerStats.T.merge(combo, left_index=True, right_index=True) dataframe.reset_index(level=0, inplace=True) dataframe.columns.values[0]='FullName' if fullStats is False: # For a more manageable table do no include the summaryStats that # have names included in the avoid_summarys list. avoid_summarys = ['3Sigma','Rms','Min','Max','RobustRms','%ile'] summary_pattern = '|'.join(avoid_summarys) dataframe = dataframe[((dataframe['SummaryName'].str.contains(summary_pattern))==False) & ((dataframe['MetricName'].str.contains(summary_pattern))==False)] columns = [] for col in dataframe.columns: if col not in ['FullName', 'BaseName','MetricName', 'MetricMetadata', 'SlicerName', 'SummaryName']: columns.append(TableColumn(field=col, title=col, formatter=NumberFormatter(format="0.0000"))) else: columns.append(TableColumn(field=col, title=col)) source = ColumnDataSource(dataframe) original_source = ColumnDataSource(dataframe) data_table = DataTable(source=source, columns=columns, width=1900, height=900) js_code = """ var data = source.data; var original_data = original_source.data; var FullName= FullName_select_obj.value; var BaseName = BaseName_select_obj.value; var SummaryName = SummaryName_select_obj.value; var MetricName = MetricName_select_obj.value; var MetricMetadata = MetricMetadata_select_obj.value; for (var key in original_data) { data[key] = []; for (var i = 0; i < original_data['FullName'].length; ++i) { if ((FullName === "ALL" || original_data['FullName'][i] === FullName) && (BaseName === "ALL" || original_data['BaseName'][i] === BaseName) && (MetricMetadata === "ALL" || original_data['MetricMetadata'][i] === MetricMetadata) && (MetricName === "ALL" || original_data['MetricName'][i] === MetricName) && (SummaryName === "ALL" || original_data['SummaryName'][i] === SummaryName)) { data[key].push(original_data[key][i]); } } } source.change.emit(); target_obj.change.emit(); """ FullName_list = dataframe['FullName'].unique().tolist() FullName_list.sort() FullName_list.insert(0,'ALL') FullName_select = Select(title="FullName:", value=FullName_list[0], options=FullName_list) BaseName_list = dataframe['BaseName'].unique().tolist() BaseName_list.sort() BaseName_list.insert(0,'ALL') BaseName_select = Select(title="BaseName:", value=BaseName_list[0], options=BaseName_list) dataframe['SummaryName'].fillna('None', inplace = True) SummaryName_list = dataframe['SummaryName'].unique().tolist() SummaryName_list.sort() SummaryName_list.insert(0,'ALL') SummaryName_select = Select(title="SummaryName:", value=SummaryName_list[0], options=SummaryName_list) MetricName_list = dataframe['MetricName'].unique().tolist() MetricName_list.sort() MetricName_list.insert(0,'ALL') MetricName_select = Select(title="MetricName:", value=MetricName_list[0], options=MetricName_list) MetricMetadata_list = dataframe['MetricMetadata'].unique().tolist() MetricMetadata_list.sort() MetricMetadata_list.insert(0,'ALL') MetricMetadata_select = Select(title="MetricMetadata:", value=MetricMetadata_list[0], options=MetricMetadata_list) generic_callback = CustomJS(args=dict(source=source, original_source=original_source, FullName_select_obj=FullName_select, BaseName_select_obj=BaseName_select, SummaryName_select_obj=SummaryName_select, MetricName_select_obj=MetricName_select, MetricMetadata_select_obj=MetricMetadata_select, target_obj=data_table), code=js_code) FullName_select.callback = generic_callback BaseName_select.callback = generic_callback SummaryName_select.callback = generic_callback MetricName_select.callback = generic_callback MetricMetadata_select.callback = generic_callback dropdownMenus = column([SummaryName_select, MetricName_select, MetricMetadata_select, FullName_select, BaseName_select]) page_layout = layout([dropdownMenus,data_table]) show(page_layout)
def plot_datatable(df): df = df.copy() # deal with some atomic mass values of the form '[98]' df['atomic mass'] = df['atomic mass'].str.extract('([\d\.]+)').astype( float) columns = [ TableColumn(field='atomic number', title='Atomic Number'), TableColumn(field='symbol', title='Symbol'), TableColumn(field='name', title='Name'), TableColumn(field='metal', title='Type'), TableColumn(field='atomic mass', title='Atomic Mass') ] column_names = [tc.field for tc in columns] source = ColumnDataSource(df[column_names]) original_source = ColumnDataSource(df) data_table = DataTable(source=source, columns=columns, height=600, editable=False) widget_callback_code = """ var filtered_data = filtered_source.get('data'); var original_data = original_source.get('data'); var element_type = element_type_select.get('value'); var min_mass = min_mass_slider.get('value'); // now construct the new data object based on the filtered values for (var key in original_data) { filtered_data[key] = []; for (var i = 0; i < original_data[key].length; ++i) { if ((element_type === "ALL" || original_data["metal"][i] === element_type) && (original_data['atomic mass'][i] >= min_mass)) { filtered_data[key].push(original_data[key][i]); } } } target_obj.trigger('change'); filtered_source.trigger('change'); """ # define the filter widgets, without callbacks for now element_type_list = ['ALL'] + df['metal'].unique().tolist() element_type_select = Select(title="Element Type:", value=element_type_list[0], options=element_type_list) min_mass_slider = Slider(start=0, end=df['atomic mass'].max(), value=1, step=1, title="minimum atomic mass") # now define the callback objects now that the filter widgets exist arg_dct = dict(filtered_source=source, original_source=original_source, element_type_select=element_type_select, min_mass_slider=min_mass_slider, target_obj=data_table) generic_callback = CustomJS(args=arg_dct, code=widget_callback_code) # connect the callbacks to the filter widgets element_type_select.callback = generic_callback min_mass_slider.callback = generic_callback # create a button to collect the filtered results # for now, just send json to new window send_button_callback_code = """ var filtered_data = filtered_source.get('data'); var action_items = []; for (var i = 0; i < filtered_data['atomic number'].length; ++i) { var item = new Object(); for (var key in filtered_data) { item[key] = filtered_data[key][i] } action_items.push(item); } var new_window = window.open("data:text/html," + encodeURIComponent(JSON.stringify(action_items)), "_blank", "location=yes,height=570,width=520,scrollbars=yes,status=yes"); new_window.focus(); """ send_button_callback = CustomJS(args=dict(filtered_source=source), code=send_button_callback_code) send_button = Button(label="Send", type="success", callback=send_button_callback) input_widgets = HBox(children=[ HBox(children=[ element_type_select, ]), HBox(children=[min_mass_slider]), HBox(children=[send_button]), ]) p = vplot(input_widgets, data_table) show(p)
title="Max", width=100, tags=['max_{0:d}'.format(i)])) # Bokeh CustomJS for handling figure data select change figure_data_callback = CustomJS(args=dict(source=source, circ=circle_handle, xaxis_data_obj=xaxis_data_select, yaxis_data_obj=yaxis_data_select, target_figure_obj=data_figure, labels=axis_label_source, xaxis=xAxisHandle, yaxis=yAxisHandle), code=figure_data_callback_code) # Now attach the callback to the figure control widgets xaxis_data_select.callback = figure_data_callback yaxis_data_select.callback = figure_data_callback # START JAVASCRIPT literal # Callback code used by all filter widgets ccc = """ var data = source.data; var original_data = original_source.data; var filter_label = filter_label_source.data; var f_active = []; var f_on = []; var mn = []; var mx = []; // check if the callback object was the checkbox or minmax value if (typeof cb_obj.value !== 'undefined') {
def loadGraphic(df,integerColumns ): output_notebook() colValues = pd.read_json (r"""JSONData/Bezeichnungen.json""") defaultZDimension = 'WinOscar' defaultXAxis = 'Runtime' defaultYAxis = 'TomatoRating' selectAxisOptions = [ colValues.loc[x]['DE'] for x in colValues.index.tolist() if 'Win' not in x and 'Nomination' not in x ] colorOptions = list(colValues['DE']) #DataSources erstellen colValuesDS = ColumnDataSource(colValues) min_max_DF = ColumnDataSource(df[integerColumns].describe().loc[['min','max']]) source = ColumnDataSource(dict(x=df[defaultXAxis], y=df['imdbRating'], z=df[defaultZDimension],Title=df['Title'], Year=df['Year'] )) allsource = ColumnDataSource(df[integerColumns]) mapper = linear_cmap(field_name='z', palette=Spectral11 ,low=min(df[defaultZDimension]) ,high=max(df[defaultZDimension])) #Select Elemente erstellen selectX = Select(title = 'X Achse',height = 50, options = selectAxisOptions , value=colValues.loc[defaultXAxis]['DE']) selectY = Select(title = 'Y Achse',height = 50, options = selectAxisOptions, value=colValues.loc[defaultYAxis]['DE']) selectC = Select(title = 'Einfärbung',height = 50, options = colorOptions, value=colValues.loc[defaultZDimension]['DE']) # Formatter formatter = NumeralTickFormatter(format='0.0a') #Erstellung des Plot p = figure() p.circle(x='x', y='y',source=source,size=10, line_color=mapper,color=mapper) p.xaxis.axis_label = colValues.loc[defaultXAxis]['Axis'] p.yaxis.axis_label = colValues.loc[defaultYAxis]['Axis'] p.xaxis.formatter =formatter p.yaxis.formatter =formatter #Hover erstellen hover = HoverTool() hover.tooltips=[('Name', '@Title'),('Jahr', '@Year'),(colValues.loc[defaultZDimension]['DE'], '@z')] p.add_tools(hover) #Title erstellen subtitle = Title(text='mit Einfärbung ' + hover.tooltips[2][0], text_font_style="italic") title = Title(text='Gegenüberstellung ' + colValues.loc[defaultXAxis]['Axis'] + ' vs ' + colValues.loc[defaultYAxis]['Axis'] , text_font_size="10pt") p.add_layout(subtitle, 'above') p.add_layout(title, 'above') #Color Bar erstellen color_bar = ColorBar(color_mapper=mapper['transform'], width=8, location=(0,0), label_standoff=12, formatter = formatter ) p.add_layout(color_bar, 'right') # Callback Funktion callback = CustomJS(args=dict(hover = hover, allsources = allsource,title = title, source=source,color_bar=color_bar,min_max = min_max_DF, yaxis=p.yaxis[0], xaxis=p.xaxis[0], mapper = mapper, colDS = colValuesDS, subtitle = subtitle ), code=javaScript()) # Callback Funktion übergeben selectX.callback = callback selectY.callback = callback selectC.callback = callback return row(p,row(widgetbox(selectX,selectY, selectC)))
def loadGraphic2(): data = pd.read_json (r"""JSONData/barPlotData.json""") types = ['Actors', 'Genre', 'Director', 'Title', 'Production'] years1 = [str(i) for i in range(1980,2020,1)] sort = ['Gesamt Durchschnitt', 'Metascore','imdbRating','TomatoRating'] output_notebook() typeDict ={ 'akteur' : data['Gesamt Durchschnitt_1980_2019_Actors']['akteur'], 'Metascore' : data['Gesamt Durchschnitt_1980_2019_Actors']['Metascore'], 'imdbRating' : data['Gesamt Durchschnitt_1980_2019_Actors']['imdbRating'], 'TomatoRating' : data['Gesamt Durchschnitt_1980_2019_Actors']['TomatoRating']} resetSource = pd.DataFrame() resetSource['fromYear'] = '1980' resetSource['toYear'] = '2019' mainSource = ColumnDataSource(data=data) resetSource = ColumnDataSource(data=resetSource) source = ColumnDataSource(data=typeDict) selectW = Select(title = 'Sortierung nach:',height = 50, options = sort, value = "Gesamt Durchschnitt" ) selectX = Select(title = 'Dimension:',height = 50, options = types, value = "Actors" ) selectY = Select(title = 'Jahr von:',height = 50, options = years1, value = "1980" ) selectZ = Select(title = 'Jahr bis:',height = 50, options = years1, value = "2019") p = figure(y_range=typeDict['akteur'], x_range=(0, 1.25), plot_height=450, plot_width=850, toolbar_location=None, tools="") p.hbar(y=dodge('akteur', -0.25, range=p.y_range), right='Metascore', height=0.2, source=source, color=Spectral3[0], legend ="Meta") p.hbar(y=dodge('akteur', 0.0, range=p.y_range), right='imdbRating', height=0.2, source=source, color=Spectral3[1], legend ="IMDB") p.hbar(y=dodge('akteur', 0.25, range=p.y_range), right='TomatoRating', height=0.2, source=source, color=Spectral3[2], legend ="Tomato" ) title = Title(text="Durchschnitt Bewertung der Top 10 Schauspieler aus den Jahren 1980 bis 2019", text_font_size="10pt") p.add_layout(title, 'above') p.xaxis.axis_label = "Bewertungen in %" p.yaxis.axis_label = "Top 10 Schauspieler sortiert von oben nach unten" p.xgrid.grid_line_color = None p.legend.location = "top_right" callback = CustomJS(args=dict(source=source, presource = mainSource, xr=p.y_range, reset = resetSource, fromYear =selectY , toYear = selectZ, sort = selectW , value = selectX, title = title, yaxis=p.yaxis[0], xaxis=p.xaxis[0] ), code=js()) selectX.callback = callback selectY.callback = callback selectZ.callback = callback selectW.callback = callback show(column(column(column(row(selectX,selectY),row(selectW,selectZ ) ), p)))