예제 #1
0
    def add_layer(self, html_str: str, layer_name, data_dict: dict):
        '''
        add a further layer of top data_dict keys
        '''
        if data_dict.get("tooltip"):
            tooltip = "<div class=\"help-tip\"><p>{}</p></div>".format(
                data_dict.get("tooltip"))
        elif get_tooltip(
                layer_name):  # if no tooltip is parsed, try to look it up
            tooltip = "<div class=\"help-tip\"><p>{}</p></div>".format(
                get_tooltip(layer_name))
        else:
            tooltip = ""
        html_str += "<div class=\"accordion\">{0} {1}</div>\n".format(
            layer_name, tooltip)
        html_str += "<div class=\"panel\">\n"

        for k, v in data_dict.items():
            if isinstance(v, dict):
                html_str = self.add_layer(html_str, k, v)
            elif k == "figure":
                html_str += "<div align=\"center\">\n"
                if isinstance(v, str):
                    html_str += "<a href=\"{0}\" data-lightbox=\"{0}\" data-title=\"{0}\"><img src=\"{0}\" alt=\"Plot\" width=\"600px\"></a>\n".format(
                        v[len(self.output_dn):].lstrip("/"))
                else:
                    # List with multiple figures size relative, put next to each other
                    width = (100 - len(v)) / len(v)
                    for fig in v:
                        html_str += "<a href=\"{0}\" data-lightbox=\"{1}\" data-title=\"{0}\"><img src=\"{0}\" alt=\"Plot\" style=\"float: left; width: {2}%; margin-right: 1%; margin-bottom: 0.5em;\"></a>\n".format(
                            fig[len(self.output_dn):].lstrip("/"), str(v),
                            int(width))

                    html_str += "<p style=\"clear: both;\">"
                html_str += "</div>\n"
            elif k == "table":
                html_str += "<div align=\"center\">\n{}\n</div>\n".format(v)
            elif k == "html":
                html_str += "<div align=\"center\">\n<a href='{}'>Interactive Plot</a>\n</div>\n".format(
                    v[len(self.output_dn):].lstrip("/"))
                #html_str += "<div align=\"center\"><iframe src='{}' frameborder='0' scrolling='no' width='700px' height='500px'></iframe></div>\n".format(v[len(self.output_dn):].lstrip("/"))

        html_str += "</div>"
        return html_str
예제 #2
0
    def add_layer(self,
                  layer_name,
                  data_dict: OrderedDict,
                  is_tab: bool = False):
        '''
        add a further layer of top data_dict keys

        Parameters
        ----------
        layer_name: str
            name of the layer
        data_dict : OrderedDict
            see constructor
        is_tab: bool
            if True, don't use accordion but tab-structure to wrap content

        Returns
        -------
        (script, div): (str, str)
            script goes into header, div goes into body
        '''
        script, div = "", ""

        if layer_name is None:
            layer_name = ""
        unique_layer_name = layer_name + self.get_unique_id()

        # Add tooltip, if possible
        tooltip = data_dict.get("tooltip", None)
        if tooltip is not None:
            tooltip = "<div class=\"help-tip\"><p>{}</p></div>".format(tooltip)
        # TODO elif is obsolete / can be merged into first option (simplify!)
        elif get_tooltip(
                layer_name):  # if no tooltip is parsed, try to look it up
            tooltip = "<div class=\"help-tip\"><p>{}</p></div>".format(
                get_tooltip(layer_name))
        else:
            tooltip = ""

        # Start accordion-panel
        if not is_tab:
            div += "<div class=\"accordion\">{0} {1}</div>\n".format(
                layer_name, tooltip)
            div += "<div class=\"panel\">\n"

        # If this layer represents budgets, add tabs for this layer, add tabs-code
        sublayer_names = [
            k for k, v in data_dict.items() if isinstance(v, dict)
        ]
        use_tabs = False
        if len(sublayer_names) >= 1 and all(
            [sn.lower().startswith('budget') for sn in sublayer_names]):
            use_tabs = True

        if use_tabs:
            div += "<div class=\"tab\">\n"
            tabs_names = [
                k.replace('_', ' ') for k, v in data_dict.items()
                if isinstance(v, dict)
            ]

            default_open_id = "defaultOpen" + self.get_unique_id()
            div += "  <button class=\"tablinks\" onclick=\"openTab(event, '{0}', '{1}')\" "\
                   "id=\"{2}\">{1}</button>\n".format(unique_layer_name, tabs_names[0], default_open_id)
            for name in tabs_names[1:]:
                div += "  <button class=\"tablinks\" onclick=\"openTab(event, '{0}', '{1}')\">{1}</button>\n".format(
                    unique_layer_name, name)
            div += "</div>\n"

        for k, v in data_dict.items():
            if k == "tooltip":
                continue
            if k.startswith('budget'):
                self.budget = k[7:]
            if not v:
                if isinstance(v, dict):
                    continue
                else:
                    return '', ''
            elif isinstance(v, dict):
                if use_tabs:
                    div += "<div id=\"{0}\" class=\"tabcontent\">\n".format(
                        unique_layer_name + k.replace('_', ' '))
                    div += "<div class=\"pane\">\n"
                add_script, add_div = self.add_layer(k, v, is_tab=use_tabs)
                script += add_script
                div += add_div
                if use_tabs:  # close div
                    div += "</div>\n"
                    div += "</div>\n"
            elif k == "figure":
                div += figure_to_html(v, prefix=self.output_dn)
            elif k == "figure_x2":
                div += figure_to_html(v, prefix=self.output_dn, max_in_a_row=2)
            elif k == "table":
                div += "<div style=\"overflow-x: auto\" align=\"center\">\n{}\n</div>\n".format(
                    v)
            elif k == "html":
                div += ("<div align=\"center\">\n<a href='{}'>Interactive "
                        "Plot</a>\n</div>\n".format(
                            v[len(self.output_dn):].lstrip("/")))
            elif k == "bokeh":
                # Escape path for URL (remove spaces, slashes and single quotes)
                path_script = os.path.join(
                    self.relative_content_js, '_'.join([
                        layer_name, self.budget,
                        self.get_unique_id(), 'script.js'
                    ]))
                path_script = path_script.translate(
                    {ord(c): None
                     for c in ' \''})

                # Write script to file
                if self.output_dn:
                    with open(os.path.join(self.output_dn, path_script),
                              'w') as fn:
                        js_code = re.sub('<.*?>', '',
                                         v[0].strip())  # Remove script-tags
                        fn.write(js_code)
                    script += "<script src=\"" + path_script + "\"></script>\n"
                else:
                    script += v[0]
                div += "<div align=\"center\">\n{}\n</div>\n".format(v[1])
            else:
                try:
                    div += v
                except Exception as err:
                    self.logger.warning(
                        "Failed on interpreting: %s, %s, %s (Error: %s)",
                        str(layer_name),
                        str(k),
                        str(v),
                        err,
                        exc_info=1)

        if use_tabs:  # close tab with selecting first element by default
            div += "<script> \n"
            div += "// Get the element with id=\"{}\" and click on it \n".format(
                default_open_id)
            div += "document.getElementById(\"{}\").click(); \n".format(
                default_open_id)
            div += "</script> \n"

        if not is_tab:
            div += "</div>"
        return script, div
예제 #3
0
    def add_layer(self, layer_name, data_dict: OrderedDict):
        '''
        add a further layer of top data_dict keys

        Parameters
        ----------
        layer_name: str
            name of the layer
        data_dict : OrderedDict
            {"top1" : {
                        "tooltip": str|None,
                        "subtop1": {  # generates a further bottom if it is dictionary
                                "tooltip": str|None,
                                ...
                                }
                        "table": str|None (html table)
                        "figure" : str|None (file name)
                        "bokeh" : ( str,str)|None  # (script, div)
                        }
            "top2": { ... }
            }

        Returns
        -------
        (script, div): (str, str)
            script goes into header, div goes into body
        '''
        script, div = "", ""
        if data_dict.get("tooltip"):
            tooltip = "<div class=\"help-tip\"><p>{}</p></div>".format(
                data_dict.get("tooltip"))
        elif get_tooltip(
                layer_name):  # if no tooltip is parsed, try to look it up
            tooltip = "<div class=\"help-tip\"><p>{}</p></div>".format(
                get_tooltip(layer_name))
        else:
            tooltip = ""
        div += "<div class=\"accordion\">{0} {1}</div>\n".format(
            layer_name, tooltip)
        div += "<div class=\"panel\">\n"

        for k, v in data_dict.items():
            if k.startswith('budget'):
                self.budget = k[7:]
            if not v:
                return '', ''
            elif isinstance(v, dict):
                add_script, add_div = self.add_layer(k, v)
                script += add_script
                div += add_div
            elif k == "figure":
                div += "<div align=\"center\">\n"
                if isinstance(v, str):
                    div += ("<a href=\"{0}\" data-lightbox=\"{0}\" "
                            "data-title=\"{0}\"><img src=\"{0}\" alt=\"Plot\" "
                            "width=\"600px\"></a>\n".format(
                                v[len(self.output_dn):].lstrip("/")))
                else:
                    # List with multiple figures size relative, put next to each other
                    width = (100 - len(v)) / len(v)
                    for fig in v:
                        div += "<a href=\"{0}\" data-lightbox=\"{1}\" data-title=\"{0}\"><img src=\"{0}\"".format(
                            fig[len(self.output_dn):].lstrip("/"), str(v))
                        div += " alt=\"Plot\" style=\"float: left; width: {}%; margin-right: "\
                               "1%; margin-bottom: 0.5em;\"></a>\n".format(int(width))

                    div += "<p style=\"clear: both;\">"
                div += "</div>\n"
            elif k == "figure_x2":
                # four figures in a grid
                div += "<div align=\"center\">\n"
                for fig in v:
                    path = fig[len(self.output_dn):].lstrip("/")
                    div += "<a href=\"{}\" ".format(path)
                    div += "data-lightbox=\"{}\" ".format(str(v))
                    div += "data-title=\"{0}\"><img src=\"{0}\" alt=\"Plot\" ".format(
                        path)
                    div += "style=\"float: left; width: 49%; margin-right: 1%; margin-bottom: 0.5em;\"></a>\n"
                    if v.index(fig) % 2 == 1:
                        div += " <br> "

                div += "<p style=\"clear: both;\">"
                div += "</div>\n"
            elif k == "table":
                div += "<div align=\"center\">\n{}\n</div>\n".format(v)
            elif k == "html":
                div += ("<div align=\"center\">\n<a href='{}'>Interactive "
                        "Plot</a>\n</div>\n".format(
                            v[len(self.output_dn):].lstrip("/")))
            elif k == "bokeh":
                # Escape path for URL (replace   and ' with   . ;)
                path_script = os.path.join(
                    self.relative_content_js,
                    layer_name + self.budget + '_script.js')
                path_script = path_script.translate(
                    {ord(c): None
                     for c in ' \''})

                # Write script to file
                with open(os.path.join(self.output_dn, path_script),
                          'w') as fn:
                    js_code = re.sub('<.*?>', '',
                                     v[0].strip())  # Remove script-tags
                    fn.write(js_code)
                script += "<script src=\"" + path_script + "\"></script>\n"
                div += "<div align=\"center\">\n{}\n</div>\n".format(v[1])
            else:
                div += v

        div += "</div>"
        return script, div
예제 #4
0
    def analyze(self,
                performance=True,
                cdf=True,
                scatter=True,
                confviz=True,
                param_importance=['forward_selection', 'ablation', 'fanova'],
                feature_analysis=[
                    "box_violin", "correlation", "feat_importance",
                    "clustering", "feature_cdf"
                ],
                parallel_coordinates=True,
                cost_over_time=True,
                algo_footprint=True):
        """Analyze the available data and build HTML-webpage as dict.
        Save webpage in 'self.output/CAVE/report.html'.
        Analyzing is performed with the analyzer-instance that is initialized in
        the __init__

        Parameters
        ----------
        performance: bool
            whether to calculate par10-values
        cdf: bool
            whether to plot cdf
        scatter: bool
            whether to plot scatter
        confviz: bool
            whether to perform configuration visualization
        param_importance: List[str]
            containing methods for parameter importance
        feature_analysis: List[str]
            containing methods for feature analysis
        parallel_coordinates: bool
            whether to plot parallel coordinates
        cost_over_time: bool
            whether to plot cost over time
        algo_footprint: bool
            whether to plot algorithm footprints
        """

        # Check arguments
        for p in param_importance:
            if p not in [
                    'forward_selection', 'ablation', 'fanova', 'incneighbor'
            ]:
                raise ValueError(
                    "%s not a valid option for parameter "
                    "importance!", p)
        for f in feature_analysis:
            if f not in [
                    "box_violin", "correlation", "importance", "clustering",
                    "feature_cdf"
            ]:
                raise ValueError("%s not a valid option for feature analysis!",
                                 f)

        # Start analysis
        overview = self.analyzer.create_overview_table(self.best_run.folder)
        self.website["Meta Data"] = {"table": overview}

        compare_config = self.analyzer.config_to_html(self.default,
                                                      self.incumbent)
        self.website["Best configuration"] = {"table": compare_config}

        ########## PERFORMANCE ANALYSIS
        self.website["Performance Analysis"] = OrderedDict()

        if performance:
            performance_table = self.analyzer.create_performance_table(
                self.default, self.incumbent)
            self.website["Performance Analysis"]["Performance Table"] = {
                "table": performance_table
            }

        if cdf:
            cdf_path = self.analyzer.plot_cdf()
            self.website["Performance Analysis"][
                "empirical Cumulative Distribution Function (eCDF)"] = {
                    "figure": cdf_path
                }

        if scatter and (self.scenario.train_insts != [[None]]):
            scatter_path = self.analyzer.plot_scatter()
            self.website["Performance Analysis"]["Scatterplot"] = {
                "figure": scatter_path
            }
        elif scatter:
            self.logger.info(
                "Scatter plot desired, but no instances available.")

        # Build report before time-consuming analysis
        self.build_website()

        if algo_footprint and self.scenario.feature_dict:
            algorithms = {self.default: "default", self.incumbent: "incumbent"}
            # Add all available incumbents to test portfolio strategy
            #for r in self.runs:
            #    if not r.get_incumbent() in algorithms:
            #        algorithms[r.get_incumbent()] = str(self.runs.index(r))

            algo_footprint_plots = self.analyzer.plot_algorithm_footprint(
                algorithms)
            self.website["Performance Analysis"][
                "Algorithm Footprints"] = OrderedDict()
            for p in algo_footprint_plots:
                header = os.path.splitext(os.path.split(p)[1])[0]  # algo name
                self.website["Performance Analysis"]["Algorithm Footprints"][
                    header] = {
                        "figure": p,
                        "tooltip":
                        get_tooltip("Algorithm Footprints") + ": " + header
                    }

        self.build_website()

        ########### Configurator's behavior
        self.website["Configurator's behavior"] = OrderedDict()

        if confviz:
            if self.scenario.feature_array is None:
                self.scenario.feature_array = np.array([[]])
            # Sort runhistories and incs wrt cost
            incumbents = [r.solver.incumbent for r in self.runs]
            trajectories = [r.traj for r in self.runs]
            runhistories = [r.runhistory for r in self.runs]
            costs = [self.validated_rh.get_cost(i) for i in incumbents]
            costs, incumbents, runhistories, trajectories = (
                list(t) for t in zip(
                    *sorted(zip(costs, incumbents, runhistories, trajectories),
                            key=lambda x: x[0])))
            incumbents = list(map(lambda x: x['incumbent'], trajectories[0]))

            confviz_script = self.analyzer.plot_confviz(
                incumbents, runhistories)
            self.website["Configurator's behavior"][
                "Configurator Footprint"] = {
                    "table": confviz_script
                }
        elif confviz:
            self.logger.info("Configuration visualization desired, but no "
                             "instance-features available.")

        self.build_website()

        if cost_over_time:
            cost_over_time_path = self.analyzer.plot_cost_over_time(
                self.best_run.traj, self.validator)
            self.website["Configurator's behavior"]["Cost over time"] = {
                "figure": cost_over_time_path
            }

        self.build_website()

        self.parameter_importance(ablation='ablation' in param_importance,
                                  fanova='fanova' in param_importance,
                                  forward_selection='forward_selection'
                                  in param_importance,
                                  incneighbor='incneighbor'
                                  in param_importance)

        self.build_website()

        if parallel_coordinates:
            # Should be after parameter importance, if performed.
            n_params = 6
            parallel_path = self.analyzer.plot_parallel_coordinates(n_params)
            self.website["Configurator's behavior"]["Parallel Coordinates"] = {
                "figure": parallel_path
            }

        self.build_website()

        if self.scenario.feature_dict:
            self.feature_analysis(box_violin='box_violin' in feature_analysis,
                                  correlation='correlation'
                                  in feature_analysis,
                                  clustering='clustering' in feature_analysis,
                                  importance='importance' in feature_analysis)
        else:
            self.logger.info('No feature analysis possible')

        self.logger.info("CAVE finished. Report is located in %s",
                         os.path.join(self.output, 'report.html'))

        self.build_website()