def gen_x_series(self, timestamps): ''' From an array of timestamps, returns the array of runs names (for the x axis ticks), as well as the metadata (in a dict of arrays) associated to this array (will be used in tooltips) ''' # Initialize the objects to return x_series = [] x_metadata = dict(date=[], is_git_commit=[], hash=[], author=[], message=[]) # n == 0 means we want all runs, we also make sure not to go out of # bound if asked for more runs than we have n = self.current_n_runs if n == 0 or n > len(timestamps): n = len(timestamps) for i in range(0, n): # Get metadata associated to this run row_metadata = helper.get_metadata(self.metadata, timestamps[-i - 1]) date = time.ctime(timestamps[-i - 1]) # Fill the x series str = row_metadata["name"] x_series.insert( 0, helper.get_metadata(self.metadata, timestamps[-i - 1])["name"]) # Fill the metadata lists x_metadata["date"].insert(0, date) x_metadata["is_git_commit"].insert(0, row_metadata["is_git_commit"]) x_metadata["hash"].insert(0, row_metadata["hash"]) x_metadata["author"].insert(0, row_metadata["author"]) x_metadata["message"].insert(0, row_metadata["message"]) return x_series, x_metadata
def __init__(self, master, doc, data, metadata): ''' Here are the most important attributes of the InspectRuns class master : reference to the ViewMaster class doc : an object provided by Bokeh to add elements to the HTML document data : pandas dataframe containing all the tests data metadata : pandas dataframe containing all the tests metadata sources : ColumnDataSource object provided by Bokeh, contains current data for the plots (inside the .data attribute) plots : dictionary of Bokeh plots widgets : dictionary of Bokeh widgets ''' self.master = master self.doc = doc self.data = data self.metadata = metadata self.sources = { "mu_source": ColumnDataSource(data={}), "sigma_source": ColumnDataSource(data={}), "s10_source": ColumnDataSource(data={}), "s2_source": ColumnDataSource(data={}) } self.plots = {} self.widgets = {} # Setup Bokeh objects self.setup_plots() self.setup_widgets() # Pass the initial metadata to the template (will be updated in CustomJS # callbacks). This is required because metadata is not displayed in a # Bokeh widget, so we can't update this with a server callback. initial_run = helper.get_metadata(self.metadata, self.current_run) self.doc.template_variables["initial_timestamp"] = initial_run.name self.doc.template_variables["initial_repo"] = initial_run.repo_name # At this point, everything should have been initialized, so we can # show the plots for the first time self.update_plots()
"variable", "backend", "value", "accuracy_threshold", "reference_value", "check", "check_mode", "timestamp"]) # Generate the display strings for runs (runs ticks) # By doing this in master, we ensure the homogeneity of display strings # across all plots metadata["name"] = metadata.index.to_series().map( lambda x: helper.get_run_name( x, helper.get_metadata(metadata, x)["hash"] ) ) helper.reset_run_strings() metadata["date"] = metadata.index.to_series().map( lambda x: time.ctime(x) ) ########################################################################## # Setup report views class ViewsMaster: '''
def setup_widgets(self): # Generation of selectable items # Dict contains all inspectable runs (maps display strings to timestamps) # The dict structure allows to get the timestamp from the display string # in O(1) self.runs_dict = helper.gen_runs_selection(self.metadata) # Dict maps display strings to column names for the different factors # (var, backend, test) self.factors_dict = { "Variables": "variable", "Backends": "vfc_backend", "Tests": "test" } # Run selection # Contains all options strings runs_display = list(self.runs_dict.keys()) # Will be used when updating plots (contains actual number) self.current_run = self.runs_dict[runs_display[-1]] # Contains the selected option string, used to update current_n_runs current_run_display = runs_display[-1] # This contains only entries matching the run self.run_data = self.data[self.data["timestamp"] == self.current_run] change_run_callback_js = "updateRunMetadata(cb_obj.value, \"\");" self.widgets["select_run"] = Select(name="select_run", title="Run :", value=current_run_display, options=runs_display) self.doc.add_root(self.widgets["select_run"]) self.widgets["select_run"].on_change("value", self.update_run) self.widgets["select_run"].js_on_change( "value", CustomJS( code=change_run_callback_js, args=(dict(metadata=helper.metadata_to_dict( helper.get_metadata(self.metadata, self.current_run)))))) # Factors selection # "Group by" radio self.widgets["groupby_radio"] = RadioButtonGroup( name="groupby_radio", labels=list(self.factors_dict.keys()), active=0) self.doc.add_root(self.widgets["groupby_radio"]) # The functions are defined inside the template to avoid writing too # much JS server side self.widgets["groupby_radio"].on_change("active", self.update_groupby) # "Filter by" radio # Get all possible factors, and remove the one selected in "Group by" filterby_list = list(self.factors_dict.keys()) del filterby_list[self.widgets["groupby_radio"].active] self.widgets["filterby_radio"] = RadioButtonGroup( name="filterby_radio", labels=filterby_list, active=0) self.doc.add_root(self.widgets["filterby_radio"]) # The functions are defined inside the template to avoid writing too # much JS server side self.widgets["filterby_radio"].on_change("active", self.update_filterby) # Filter selector filterby = self.widgets["filterby_radio"].labels[ self.widgets["filterby_radio"].active] filterby = self.factors_dict[filterby] if not self.run_data.empty: options = self.run_data.index\ .get_level_values(filterby).drop_duplicates().tolist() else: options = ["None"] self.widgets["select_filter"] = Select( # We need a different name to avoid collision in the template with # the runs comparison's widget name="select_filter", title="Select a filter :", value=options[0], options=options) self.doc.add_root(self.widgets["select_filter"]) self.widgets["select_filter"]\ .on_change("value", self.update_filter) # Toggle for outliers filtering self.widgets["outliers_filtering_inspect"] = CheckboxGroup( name="outliers_filtering_inspect", labels=["Filter outliers"], active=[]) self.doc.add_root(self.widgets["outliers_filtering_inspect"]) self.widgets["outliers_filtering_inspect"]\ .on_change("active", self.update_outliers_filtering)
def setup_widgets(self): # Run selection # Dict contains all inspectable runs (maps display strings to timestamps) # The dict structure allows to get the timestamp from the display string # in O(1) self.runs_dict = helper.gen_runs_selection(self.metadata) # Contains all options strings runs_display = list(self.runs_dict.keys()) # Will be used when updating plots (contains actual number) self.current_run = self.runs_dict[runs_display[-1]] self.current_deterministic_run = self.runs_dict[runs_display[-1]] # Contains the selected option string, used to update current_n_runs current_run_display = runs_display[-1] # This contains only entries matching the run self.run_data = self.data[self.data["timestamp"] == self.current_run] self.deterministic_run_data = self.deterministic_data[ self.deterministic_data["timestamp"] == self.current_deterministic_run] # Only keep interesting columns self.run_data = self.run_data[[ "check", "accuracy_threshold", "check_mode", "mu", "sigma", ]] self.deterministic_run_data = self.deterministic_run_data[[ "check", "accuracy_threshold", "check_mode", "value", "reference_value", ]] # Only keep probes that have an check self.run_data = self.run_data[self.run_data.accuracy_threshold != 0] self.deterministic_run_data = self.deterministic_run_data[ self.deterministic_run_data.accuracy_threshold != 0 ] # Uppercase first letter of "check_mode" for display self.run_data["check_mode"] = self.run_data["check_mode"].apply( lambda x: x.capitalize()) self.deterministic_run_data["check_mode"] = self.deterministic_run_data["check_mode"].apply( lambda x: x.capitalize()) # Generate the data source objects self.run_data.reset_index(inplace=True) self.deterministic_run_data.reset_index(inplace=True) self.sources["non_deterministic"].data = self.run_data self.sources["deterministic"].data = self.deterministic_run_data # Non-deterministic run selector change_run_callback_js = "updateRunMetadata(cb_obj.value, \"non-deterministic-checks-\");" self.widgets["select_check_run_non_deterministic"] = Select( name="select_check_run_non_deterministic", title="Run :", value=current_run_display, options=runs_display ) self.doc.add_root(self.widgets["select_check_run_non_deterministic"]) self.widgets["select_check_run_non_deterministic"].on_change( "value", self.update_non_deterministic_run) self.widgets["select_check_run_non_deterministic"].js_on_change( "value", CustomJS( code=change_run_callback_js, args=( dict( metadata=helper.metadata_to_dict( helper.get_metadata( self.metadata, self.current_run)))))) # Deterministic run selector change_run_callback_js = "updateRunMetadata(cb_obj.value, \"deterministic-checks-\");" self.widgets["select_check_run_deterministic"] = Select( name="select_check_run_deterministic", title="Run :", value=current_run_display, options=runs_display ) self.doc.add_root(self.widgets["select_check_run_deterministic"]) self.widgets["select_check_run_deterministic"].on_change( "value", self.update_deterministic_run) self.widgets["select_check_run_deterministic"].js_on_change( "value", CustomJS( code=change_run_callback_js, args=( dict( metadata=helper.metadata_to_dict( helper.get_metadata( self.metadata, self.current_deterministic_run)))))) # Non-deterministic checks table: non_deterministic_olumns = [ TableColumn(field="test", title="Test"), TableColumn(field="variable", title="Variable"), TableColumn(field="vfc_backend", title="Backend"), TableColumn(field="accuracy_threshold", title="Target precision"), TableColumn(field="check_mode", title="Check mode"), TableColumn(field="mu", title="Emp. avg. μ"), TableColumn(field="sigma", title="Std. dev. σ"), TableColumn(field="check", title="Passed") ] self.widgets["non_deterministic_checks_table"] = DataTable( name="non_deterministic_checks_table", source=self.sources["non_deterministic"], columns=non_deterministic_olumns, width=895, sizing_mode="scale_width") self.doc.add_root(self.widgets["non_deterministic_checks_table"]) # Deterministic checks table: deterministic_columns = [ TableColumn(field="test", title="Test"), TableColumn(field="variable", title="Variable"), TableColumn(field="vfc_backend", title="Backend"), TableColumn(field="accuracy_threshold", title="Target precision"), TableColumn(field="check_mode", title="Check mode"), TableColumn(field="value", title="Backend value"), TableColumn(field="reference_value", title="IEEE value"), TableColumn(field="check", title="Passed") ] self.widgets["deterministic_checks_table"] = DataTable( name="deterministic_checks_table", source=self.sources["deterministic"], columns=deterministic_columns, width=895, sizing_mode="scale_width") self.doc.add_root(self.widgets["deterministic_checks_table"])