def visualize_scenario(scenario, cps=None):
    '\n    Creates an HTML visualization of the given scenario. Starts a simple web server at localhost:8000 (blocking).\n    :param scenario: Either a list of worlds, each world representing a single scene or a single world representing a\n    whole scenario\n    :param cps: A list of criticality phenomena which optionally to visualize as well.\n    :return: The path to the directory in which to find the created HTML visualization.\n    '
    pl_html = []
    scenario_inst = None
    if (cps is None):
        cps = []
    if (type(scenario) == list):
        scenes = [scene_world.search(type=auto.auto.get_ontology(auto.auto.Ontology.Traffic_Model, scene_world).Scene)[0] for scene_world in scenario]
    elif ((type(scenario) == owlready2.namespace.World) or (type(scenario) == owlready2.World)):
        tm = auto.auto.get_ontology(auto.auto.Ontology.Traffic_Model, scenario)
        scenario_inst = scenario.search(type=tm.Scenario)[0]
        scenes = list(filter((lambda x: (tm.Scene in x.is_a)), scenario_inst.has_traffic_model))
    else:
        raise ValueError
    scenes = sorted(scenes, key=(lambda x: x.inTimePosition[0].numericPosition[0]))
    title = 'Scenario'
    if (scenario_inst and hasattr(scenario_inst, 'identifier') and (len(scenario_inst.identifier) > 0)):
        title += (' ' + str(scenario_inst.identifier[0]))
    scenario_info = (('(' + str(len(scenes))) + ' Scenes)')
    html_body = (((((((((('<!DOCTYPE html>\n<html>\n    <head>\n        <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">\n        <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>\n        <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>\n        <meta charset="utf-8">' + scenario_css) + '\n        <title>') + title) + '</title>\n    </head>\n    <body>\n        <div class="d-flex flex-row justify-content-center"><div class="mt-3 py-1 px-6 alert alert-info" style="display: inline-block" role="alert"><center><h5>') + title) + ' ') + scenario_info) + '</h5></center></div></div>\n        <div class="slidecontainer m-2">\n            <input type="range" min="1" max="') + str(len(scenes))) + '" value="1" class="slider" id="myRange">\n        </div>\n        <script>\n            var slider = document.getElementById("myRange");\n            var last_set = 1\n            var show_all_cps = true\n            slider.oninput = function() {\n              var output = document.getElementById("plt" + this.value);\n              var last_output = document.getElementById("plt" + last_set);\n              last_output.style.display = \'none\';\n              output.style.display = \'block\';\n              last_set = this.value\n            }\n            function toggle_cps_all_iframes() {\n                show_all_cps = !show_all_cps\n                $(".cp-all-button").each(function(i) {\n                  if (show_all_cps) {\n                      this.parentElement.classList.add("active")\n                      this.checked = true\n                  } else {\n                      this.parentElement.classList.remove("active")\n                      this.checked = false\n                  }\n                })\n                $(".cp-button").each(function(i) {\n                  if (show_all_cps) {\n                      this.parentElement.classList.add("active")\n                      this.checked = true\n                  } else {\n                      this.parentElement.classList.remove("active")\n                      this.checked = false\n                  }\n                })\n                $(".scene-plot").each(function(i) {\n                  this.contentWindow.toggle_cps(show_all_cps)\n                })\n            }\n            function toggle_cp_class(ele, cp_cls_id) {\n                // 0. disable automatically checked checkbox (will be added again at step 3)\n                ele.checked = !ele.checked\n                // 1. find active scene plot\n                active_scene = $(".scene-plot-container").filter(function(i) {\n                  return this.style.display !== "none"\n                })[0]\n                // 2. get CP pred. str for given cp_cls_id\n                cp_pred = active_scene.getElementsByClassName("scene-plot")[0].contentWindow.cp_predicates[cp_cls_id]\n                // 3. Toggle all buttons for this CP pred\n                $("label > span:contains(" + cp_pred + ")").each(function(i) {\n                  this.parentElement.classList.toggle("active")\n                  this.parentElement.querySelector(".cp-button").checked = !this.parentElement.querySelector(".cp-button").checked\n                })\n                // 4. check if (and where) CP pred. str is present in cp_predicates, pass the resulting index\n                $(".scene-plot").each(function(k) {\n                  cp_cls_id_scene = -1\n                  for (var i = 0; i < this.contentWindow.cp_predicates.length; i++) {\n                    if (cp_pred === this.contentWindow.cp_predicates[i]) {\n                        cp_cls_id_scene = i\n                    }\n                  }\n                  if (cp_cls_id_scene >= 0) {\n                    this.contentWindow.toggle_cp_class(cp_cls_id_scene, ele.checked)\n                  }\n                })\n            }\n        </script>\n    ')
    pl_html.append(html_body)
    iframes = []

    def get_color(p):
        _LUMA_LIMIT = 170
        color = 0
        luma = _LUMA_LIMIT
        while (luma >= _LUMA_LIMIT):
            color = random.randrange(0, 16777215, 15)
            luma = (((0.2126 * ((color >> 16) & 255)) + (0.7152 * ((color >> 8) & 255))) + (0.0722 * ((color >> 0) & 255)))
        return ('#' + ('%06x' % color))
    for (i, scene) in enumerate(scenes):
        logger.info(((('Plotting scene ' + str((i + 1))) + ' / ') + str(len(scenes))))
        scene_cps = [cp for cp in cps if cp.is_representable_in_scene(scene)]
        cp_colors = list(map(get_color, range(len([x for c in scene_cps for x in c.subjects]))))
        cp_color = 0
        no_geo_entities = []
        width = 24.5
        height = 10
        try:
            primary_screens = list(filter((lambda x: x.is_primary), screeninfo.get_monitors()))
            if (len(primary_screens) > 0):
                width = ((primary_screens[0].width_mm / 25.4) * 0.73)
                height = ((primary_screens[0].height_mm / 25.4) * 0.73)
        except screeninfo.common.ScreenInfoError:
            logger.info((((('No screens found, using default plot size of ' + str(width)) + ' in x ') + str(height)) + ' in'))
        fig = plt.figure(figsize=(width, height))
        plt.axis('equal')
        entity_labels = []
        entity_relations = []
        relations_per_cp_class = dict()
        cps_relations = []
        cps_for_tooltips = []
        centroids_x = []
        centroids_y = []
        plotted_labels = []
        entity_points = dict()
        traffic_entities = tqdm(scene.has_traffic_entity)
        for entity in traffic_entities:
            traffic_entities.set_description(str(entity))
            if (len(entity.hasGeometry) > 0):
                for geo in entity.hasGeometry:
                    shape = wkt.loads(geo.asWKT[0])
                    entity_cp_relations = []
                    points = None
                    if hasattr(shape, 'exterior'):
                        points = shape.exterior.xy
                    try:
                        hasattr(shape, 'coords')
                        points = shape.coords.xy
                    except NotImplementedError:
                        pass
                    if points:
                        if (np.isclose(centroids_x, shape.centroid.x) & np.isclose(centroids_y, shape.centroid.y)).any():
                            x = (shape.centroid.x + 0.0)
                            y = (shape.centroid.y + 0.8)
                            plt.plot((shape.centroid.x, x), (shape.centroid.y, y), 'k-')
                        else:
                            x = shape.centroid.x
                            y = shape.centroid.y
                        entity_points[entity] = (x, y)
                        centroids_x.append(x)
                        centroids_y.append(y)
                        plt.plot(*points, alpha=0.6)
                        if (auto.auto.get_ontology(auto.auto.Ontology.Physics, scenario).Dynamical_Object in entity.INDIRECT_is_a):
                            plt.fill(*points, alpha=0.3)
                            if (entity.has_yaw is not None):
                                x_dir = (0.9 * math.cos(math.radians(entity.has_yaw)))
                                y_dir = (0.9 * math.sin(math.radians(entity.has_yaw)))
                                plt.arrow(shape.centroid.x, shape.centroid.y, dx=x_dir, dy=y_dir, shape='full', length_includes_head=True, color='gray', alpha=0.6, head_width=1)
                        entity_labels.append(_describe_entity(entity))
                        entity_scene_cps = list(filter((lambda scp: (entity in scp.subjects)), scene_cps))
                        if (len(entity_scene_cps) > 0):
                            plt.plot(x, y, 'o', color='r', mec='k', markersize=3, alpha=1)
                            ent_color = 'red'
                        else:
                            ent_color = 'black'
                        if (entity.identifier and (len(entity.identifier) > 0) and (not entity.is_persistent) and (not (isinstance(entity.identifier[0], str) and entity.identifier[0].startswith('repr')))):
                            plt.annotate(entity.identifier[0], ((x + 0.2), (y + 0.2)), color=ent_color)
                        already_drawn_cps = []
                        for cp in entity_scene_cps:
                            if (cp.predicate not in relations_per_cp_class.keys()):
                                relations_per_cp_class[cp.predicate] = []
                        for cp in entity_scene_cps:
                            if (cp not in already_drawn_cps):
                                same_line_cps = [x for x in entity_scene_cps if ([y for z in x.objects.values() for y in z] == [y for z in cp.objects.values() for y in z])]
                                labels = [(x.predicate.split('(')[0], (x.predicate.split('(')[1].replace(')', ''), str(x))) for x in same_line_cps]
                                already_drawn_cps += same_line_cps
                                subj_x = x
                                subj_y = y
                                for objs in cp.objects.values():
                                    for obj in objs:
                                        if (len(obj.hasGeometry) > 0):
                                            if (obj in entity_points.keys()):
                                                obj_x = entity_points[obj][0]
                                                obj_y = entity_points[obj][1]
                                            else:
                                                geom_o = wkt.loads(obj.hasGeometry[0].asWKT[0])
                                                obj_x = geom_o.centroid.x
                                                obj_y = geom_o.centroid.y
                                            m = ((obj_y - subj_y) / (obj_x - subj_x))
                                            b = (subj_y - (m * subj_x))
                                            head_width = 0.2
                                            head_length = (1.5 * head_width)
                                            arrow = plt.arrow(subj_x, subj_y, dx=(obj_x - subj_x), dy=(obj_y - subj_y), color=cp_colors[cp_color], shape='full', length_includes_head=True, head_width=head_width, head_length=head_length)
                                            if (len(labels[0]) > 1):
                                                label_row = ' '.join([label[0] for label in labels])
                                            else:
                                                label_row = labels[0]
                                            x_offset = (((len(label_row) * 0.055) / 2) - 0.055)
                                            if (subj_x > obj_x):
                                                label_x = ((obj_x + (abs((subj_x - obj_x)) / 2)) - x_offset)
                                            else:
                                                label_x = ((obj_x - (abs((subj_x - obj_x)) / 2)) - x_offset)
                                            a = math.degrees(math.atan(m))
                                            for (l_i, label) in enumerate(labels):
                                                label_string = label[0].replace('CP_', '')
                                                label_len = ((len(label_string) * 0.09) + 0.1)
                                                label_x_offset = abs((math.cos(math.atan(m)) * label_len))
                                                while True:
                                                    label_y = (((m * label_x) + b) + 0.05)
                                                    label_x_1 = ((label_x - (label_x_offset / 2)) + 0.05)
                                                    label_y_1 = ((m * label_x_1) + b)
                                                    label_x_2 = ((label_x + (label_x_offset / 2)) + 0.05)
                                                    label_y_2 = ((m * label_x_2) + b)
                                                    label_line1 = geometry.LineString([(label_x_1, label_y_1), (label_x_2, label_y_2)])
                                                    new_bb = label_line1.buffer(0.1, cap_style=2)
                                                    new_bb_rect = list(zip(*new_bb.exterior.xy))[:(- 1)]
                                                    if ((not _AVOID_LABEL_COLLISIONS) or (not _has_collision_with_bbs(plotted_labels, new_bb_rect))):
                                                        break
                                                    label_x += (label_x_offset / 10)
                                                annot = plt.annotate(label_string, (label_x, label_y), color=cp_colors[cp_color], rotation=a, fontsize=2, rotation_mode='anchor')
                                                entity_cp_relations.append(annot)
                                                cps_relations.append(annot)
                                                relations_per_cp_class[same_line_cps[l_i].predicate] += [annot, arrow]
                                                cps_for_tooltips.append(same_line_cps[l_i])
                                                plotted_labels.append(new_bb_rect)
                                                label_x += label_x_offset
                                            subj_x = obj_x
                                            subj_y = obj_y
                                            entity_cp_relations += [arrow]
                                cp_color = ((cp_color + 1) % len(cp_colors))
                        entity_relations.append(entity_cp_relations)
            elif (len(set([str(y) for y in entity.INDIRECT_is_a]).intersection(_NO_PRINTING_CLASSES)) == 0):
                no_geo_entities.append(_describe_entity(entity))
        logger.info('Done with layout, creating MPLD3 plot, JS plugins, and HTML string')
        pl2 = plt.plot(centroids_x, centroids_y, 'o', color='b', mec='k', markersize=2, mew=1, alpha=0.4)
        tooltip_individuals = ToolTipAndClickInfo(pl2[0], labels=entity_labels, targets=entity_relations, targets_per_cp=relations_per_cp_class)
        fig.tight_layout()
        mpld3.plugins.connect(fig, tooltip_individuals)
        for (h, cp_text) in enumerate(cps_relations):
            tooltip_cp = CPTooltip(cp_text, cps_for_tooltips[h])
            mpld3.plugins.connect(fig, tooltip_cp)
        html = (('\n\t\t<div class="container-fluid scene-plot-container" id="plt' + str((i + 1))) + '" style ="')
        if (i != 0):
            html += 'display: none;'
        html += '">'
        html += '\n            <div class="row">\n                <div class="col-md-1">\n                    '
        cp_count_total = len([x for x in cps if ((isinstance(x.traffic_model, list) and (scene in x.traffic_model)) or (x.traffic_model == scenario_inst))])
        html += ('<div class="">\n                        <label class="btn btn-primary active" style="margin-bottom: 10px; width: %s">\n                            <input type="checkbox" class="cp-all-button" id="cp-all-button-%s" autocomplete="off" onclick="toggle_cps_all_iframes();" checked>\n                            <span>Show all criticality phenomena (%s)</span>\n                        </label>' % ('100%', str(i), str(cp_count_total)))
        for (l, pred) in enumerate(sorted(relations_per_cp_class.keys(), key=natural_sort_key)):
            cp_count = len([x for x in cps if ((x.predicate == pred) and ((isinstance(x.traffic_model, list) and (scene in x.traffic_model)) or (x.traffic_model == scenario_inst)))])
            html += ('\n                        <br />\n                        <label class="btn btn-secondary active" style="margin-bottom: 5px; width: %s">\n                            <input type="checkbox" class="cp-button" id="cp-button-%s-%s" autocomplete="off" onclick="toggle_cp_class(this, %s);" checked>\n                            <span>%s (%s)</span>\n                        </label>' % ('100%', str(i), str(l), str(l), pred, str(cp_count)))
        html += '\n                    </div>\n                </div>\n                <div class="col-md-11">\n                    '
        html += '<div class="embed-responsive embed-responsive-16by9">\n'
        html += (((('\t\t\t\t\t\t<iframe class="scene-plot" src="scene' + str((i + 1))) + '.html" class="embed-responsive-item" style="width: 100%; height: ') + str((height * 1.27))) + 'in" allowfullscreen></iframe>\n\t\t\t\t\t</div>\n')
        iframe_html = '<!DOCTYPE html>\n<html>\n    <head>\n        <meta charset="utf-8">\n        <meta HTTP-EQUIV="Access-Control-Allow-Origin" CONTENT="localhost">\n        <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">\n        <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>\n        <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>\n    </head>\n    <body>'
        iframe_html += scene_css
        iframe_html += '\n        <div class="d-flex flex-row justify-content-center">\n            <div class="btn-group btn-group-toggle" data-bs-toggle="buttons">\n                <label class="btn btn-secondary active">\n                    <input type="checkbox" id="tooltip_button" checked autocomplete="off" onclick="toggle_tooltips(this);"> Show tooltip with information of individuals\n                </label>\n                <label class="btn btn-secondary active">\n                    <input type="checkbox" id="descr_button" checked autocomplete="off" onclick="toggle_all_ind_relations(this);"> Show full individual relations in tooltip\n                </label>\n            </div>\n        </div>\n        <script>\n            var show_tooltips = true\n            var show_long_ind = true\n            cps = []\n            cp_targets = []\n            cp_targets_per_class = []\n            function toggle_tooltips(ele) {\n                ele.parentElement.classList.toggle("active")\n                show_tooltips = !show_tooltips\n            }\n            function toggle_all_ind_relations(ele) {\n                ele.parentElement.classList.toggle("active")\n                show_long_ind = !show_long_ind\n            }\n            function toggle_cp_targets(targets, state) {\n                for (let j = 0; j < targets.length; j++) {\n                    var x = mpld3.get_element(targets[j])\n                    if (x) {\n                        if ("path" in x) {\n                            tog = x.path\n                        } else if ("obj" in x) {\n                            tog = x.obj\n                        }\n                        for (var k = 0; k < tog._groups.length; k++) {\n                            for (var l = 0; l < tog._groups[k].length; l++){\n                                if (state) {\n                                    tog._groups[k][l].style.display = "block"\n                                } else {\n                                    tog._groups[k][l].style.display = "none"\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n            function toggle_cps(state) {\n                for (let i = 0; i < cp_targets.length; i++) {\n                    toggle_cp_targets(cp_targets[i], state)\n                }\n            }\n            function toggle_cp_class(cp_class, state) {\n                targets = cp_targets_per_class[cp_class]\n                toggle_cp_targets(targets, state)\n            }\n        </script>\n        <div class="card m-2">\n            <div class="card-title d-flex flex-row justify-content-center m-1">\n                <h5>'
        if ((len(scene.inTimePosition) > 0) and (len(scene.inTimePosition[0].numericPosition) > 0)):
            time = ('%.2f s' % scene.inTimePosition[0].numericPosition[0])
            if (scenario_inst and (len(scenario_inst.hasEnd) > 0) and (len(scenario_inst.hasEnd[0].inTimePosition) > 0) and (len(scenario_inst.hasEnd[0].inTimePosition[0].numericPosition) > 0)):
                time += (' / %.2f s' % scenario_inst.hasEnd[0].inTimePosition[0].numericPosition[0])
            else:
                time += (' / ' + str(len(scenes)))
        else:
            time = ((str(i) + ' / ') + str(len(scenes)))
        iframe_html += (('Scene ' + time) + '<br />')
        iframe_html += '\n                </h5>\n            </div>\n            <div class="card-body m-0 p-0 d-flex justify-content-center">\n        '
        scene_html = mpld3.fig_to_html(fig)
        iframe_html += ''.join(((('\t\t' + line) + '\n') for line in scene_html.splitlines()))
        iframe_html += '\n            </div>\n        </div>'
        if (len(no_geo_entities) > 0):
            iframe_html += ('\n        <div class="d-flex flex-row justify-content-center">\n            <a class="btn btn-primary" data-bs-toggle="collapse" href="#noGeoCollapse" role="button" aria-expanded="false" aria-controls="noGeoCollapse">\n                Show scene individuals with no geometric representation (%s)\n            </a>\n        </div>\n        <div class="container-fluid collapse" id="noGeoCollapse">\n            <div class="card card-body m-2">' % str(len(no_geo_entities)))
            iframe_html += ''.join(no_geo_entities)
            iframe_html += '\n            </div>\n        </div>'
        iframe_html += '\t</body>\n</html>'
        iframes.append(iframe_html)
        html += '\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>'
        pl_html.append(html)
    pl_html.append('\n\t</body>\n</html>')
    tmp_dir = tempfile.mkdtemp()
    index_path = (tmp_dir + '/index.html')
    with open(index_path, 'w') as file:
        for html in pl_html:
            file.write(html)
    for (i, iframe) in enumerate(iframes):
        frame_path = (((tmp_dir + '/scene') + str((i + 1))) + '.html')
        with open(frame_path, 'w') as file:
            for html in iframe:
                file.write(html)
    os.chdir(tmp_dir)
    threading.Thread(target=socketserver.TCPServer(('', 8000), http.server.SimpleHTTPRequestHandler).serve_forever).start()
    logger.info('Visualization is available at: http://localhost:8000')
    webbrowser.open('http://localhost:8000')
    return tmp_dir
Creates an HTML visualization of the given scenario. Starts a simple web server at localhost:8000 (blocking).
:param scenario: Either a list of worlds, each world representing a single scene or a single world representing a
whole scenario
:param cps: A list of criticality phenomena which optionally to visualize as well.
:return: The path to the directory in which to find the created HTML visualization.
def visualize_scenario(scenario, cps=None):
    '\n    Creates an HTML visualization of the given scenario. Starts a simple web server at localhost:8000 (blocking).\n    :param scenario: Either a list of worlds, each world representing a single scene or a single world representing a\n    whole scenario\n    :param cps: A list of criticality phenomena which optionally to visualize as well.\n    :return: The path to the directory in which to find the created HTML visualization.\n    '
    pl_html = []
    scenario_inst = None
    if (cps is None):
        cps = []
    if (type(scenario) == list):
        scenes = [scene_world.search(type=auto.auto.get_ontology(auto.auto.Ontology.Traffic_Model, scene_world).Scene)[0] for scene_world in scenario]
    elif ((type(scenario) == owlready2.namespace.World) or (type(scenario) == owlready2.World)):
        tm = auto.auto.get_ontology(auto.auto.Ontology.Traffic_Model, scenario)
        scenario_inst = scenario.search(type=tm.Scenario)[0]
        scenes = list(filter((lambda x: (tm.Scene in x.is_a)), scenario_inst.has_traffic_model))
    else:
        raise ValueError
    scenes = sorted(scenes, key=(lambda x: x.inTimePosition[0].numericPosition[0]))
    title = 'Scenario'
    if (scenario_inst and hasattr(scenario_inst, 'identifier') and (len(scenario_inst.identifier) > 0)):
        title += (' ' + str(scenario_inst.identifier[0]))
    scenario_info = (('(' + str(len(scenes))) + ' Scenes)')
    html_body = (((((((((('<!DOCTYPE html>\n<html>\n    <head>\n        <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">\n        <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>\n        <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>\n        <meta charset="utf-8">' + scenario_css) + '\n        <title>') + title) + '</title>\n    </head>\n    <body>\n        <div class="d-flex flex-row justify-content-center"><div class="mt-3 py-1 px-6 alert alert-info" style="display: inline-block" role="alert"><center><h5>') + title) + ' ') + scenario_info) + '</h5></center></div></div>\n        <div class="slidecontainer m-2">\n            <input type="range" min="1" max="') + str(len(scenes))) + '" value="1" class="slider" id="myRange">\n        </div>\n        <script>\n            var slider = document.getElementById("myRange");\n            var last_set = 1\n            var show_all_cps = true\n            slider.oninput = function() {\n              var output = document.getElementById("plt" + this.value);\n              var last_output = document.getElementById("plt" + last_set);\n              last_output.style.display = \'none\';\n              output.style.display = \'block\';\n              last_set = this.value\n            }\n            function toggle_cps_all_iframes() {\n                show_all_cps = !show_all_cps\n                $(".cp-all-button").each(function(i) {\n                  if (show_all_cps) {\n                      this.parentElement.classList.add("active")\n                      this.checked = true\n                  } else {\n                      this.parentElement.classList.remove("active")\n                      this.checked = false\n                  }\n                })\n                $(".cp-button").each(function(i) {\n                  if (show_all_cps) {\n                      this.parentElement.classList.add("active")\n                      this.checked = true\n                  } else {\n                      this.parentElement.classList.remove("active")\n                      this.checked = false\n                  }\n                })\n                $(".scene-plot").each(function(i) {\n                  this.contentWindow.toggle_cps(show_all_cps)\n                })\n            }\n            function toggle_cp_class(ele, cp_cls_id) {\n                // 0. disable automatically checked checkbox (will be added again at step 3)\n                ele.checked = !ele.checked\n                // 1. find active scene plot\n                active_scene = $(".scene-plot-container").filter(function(i) {\n                  return this.style.display !== "none"\n                })[0]\n                // 2. get CP pred. str for given cp_cls_id\n                cp_pred = active_scene.getElementsByClassName("scene-plot")[0].contentWindow.cp_predicates[cp_cls_id]\n                // 3. Toggle all buttons for this CP pred\n                $("label > span:contains(" + cp_pred + ")").each(function(i) {\n                  this.parentElement.classList.toggle("active")\n                  this.parentElement.querySelector(".cp-button").checked = !this.parentElement.querySelector(".cp-button").checked\n                })\n                // 4. check if (and where) CP pred. str is present in cp_predicates, pass the resulting index\n                $(".scene-plot").each(function(k) {\n                  cp_cls_id_scene = -1\n                  for (var i = 0; i < this.contentWindow.cp_predicates.length; i++) {\n                    if (cp_pred === this.contentWindow.cp_predicates[i]) {\n                        cp_cls_id_scene = i\n                    }\n                  }\n                  if (cp_cls_id_scene >= 0) {\n                    this.contentWindow.toggle_cp_class(cp_cls_id_scene, ele.checked)\n                  }\n                })\n            }\n        </script>\n    ')
    pl_html.append(html_body)
    iframes = []

    def get_color(p):
        _LUMA_LIMIT = 170
        color = 0
        luma = _LUMA_LIMIT
        while (luma >= _LUMA_LIMIT):
            color = random.randrange(0, 16777215, 15)
            luma = (((0.2126 * ((color >> 16) & 255)) + (0.7152 * ((color >> 8) & 255))) + (0.0722 * ((color >> 0) & 255)))
        return ('#' + ('%06x' % color))
    for (i, scene) in enumerate(scenes):
        logger.info(((('Plotting scene ' + str((i + 1))) + ' / ') + str(len(scenes))))
        scene_cps = [cp for cp in cps if cp.is_representable_in_scene(scene)]
        cp_colors = list(map(get_color, range(len([x for c in scene_cps for x in c.subjects]))))
        cp_color = 0
        no_geo_entities = []
        width = 24.5
        height = 10
        try:
            primary_screens = list(filter((lambda x: x.is_primary), screeninfo.get_monitors()))
            if (len(primary_screens) > 0):
                width = ((primary_screens[0].width_mm / 25.4) * 0.73)
                height = ((primary_screens[0].height_mm / 25.4) * 0.73)
        except screeninfo.common.ScreenInfoError:
            logger.info((((('No screens found, using default plot size of ' + str(width)) + ' in x ') + str(height)) + ' in'))
        fig = plt.figure(figsize=(width, height))
        plt.axis('equal')
        entity_labels = []
        entity_relations = []
        relations_per_cp_class = dict()
        cps_relations = []
        cps_for_tooltips = []
        centroids_x = []
        centroids_y = []
        plotted_labels = []
        entity_points = dict()
        traffic_entities = tqdm(scene.has_traffic_entity)
        for entity in traffic_entities:
            traffic_entities.set_description(str(entity))
            if (len(entity.hasGeometry) > 0):
                for geo in entity.hasGeometry:
                    shape = wkt.loads(geo.asWKT[0])
                    entity_cp_relations = []
                    points = None
                    if hasattr(shape, 'exterior'):
                        points = shape.exterior.xy
                    try:
                        hasattr(shape, 'coords')
                        points = shape.coords.xy
                    except NotImplementedError:
                        pass
                    if points:
                        if (np.isclose(centroids_x, shape.centroid.x) & np.isclose(centroids_y, shape.centroid.y)).any():
                            x = (shape.centroid.x + 0.0)
                            y = (shape.centroid.y + 0.8)
                            plt.plot((shape.centroid.x, x), (shape.centroid.y, y), 'k-')
                        else:
                            x = shape.centroid.x
                            y = shape.centroid.y
                        entity_points[entity] = (x, y)
                        centroids_x.append(x)
                        centroids_y.append(y)
                        plt.plot(*points, alpha=0.6)
                        if (auto.auto.get_ontology(auto.auto.Ontology.Physics, scenario).Dynamical_Object in entity.INDIRECT_is_a):
                            plt.fill(*points, alpha=0.3)
                            if (entity.has_yaw is not None):
                                x_dir = (0.9 * math.cos(math.radians(entity.has_yaw)))
                                y_dir = (0.9 * math.sin(math.radians(entity.has_yaw)))
                                plt.arrow(shape.centroid.x, shape.centroid.y, dx=x_dir, dy=y_dir, shape='full', length_includes_head=True, color='gray', alpha=0.6, head_width=1)
                        entity_labels.append(_describe_entity(entity))
                        entity_scene_cps = list(filter((lambda scp: (entity in scp.subjects)), scene_cps))
                        if (len(entity_scene_cps) > 0):
                            plt.plot(x, y, 'o', color='r', mec='k', markersize=3, alpha=1)
                            ent_color = 'red'
                        else:
                            ent_color = 'black'
                        if (entity.identifier and (len(entity.identifier) > 0) and (not entity.is_persistent) and (not (isinstance(entity.identifier[0], str) and entity.identifier[0].startswith('repr')))):
                            plt.annotate(entity.identifier[0], ((x + 0.2), (y + 0.2)), color=ent_color)
                        already_drawn_cps = []
                        for cp in entity_scene_cps:
                            if (cp.predicate not in relations_per_cp_class.keys()):
                                relations_per_cp_class[cp.predicate] = []
                        for cp in entity_scene_cps:
                            if (cp not in already_drawn_cps):
                                same_line_cps = [x for x in entity_scene_cps if ([y for z in x.objects.values() for y in z] == [y for z in cp.objects.values() for y in z])]
                                labels = [(x.predicate.split('(')[0], (x.predicate.split('(')[1].replace(')', ), str(x))) for x in same_line_cps]
                                already_drawn_cps += same_line_cps
                                subj_x = x
                                subj_y = y
                                for objs in cp.objects.values():
                                    for obj in objs:
                                        if (len(obj.hasGeometry) > 0):
                                            if (obj in entity_points.keys()):
                                                obj_x = entity_points[obj][0]
                                                obj_y = entity_points[obj][1]
                                            else:
                                                geom_o = wkt.loads(obj.hasGeometry[0].asWKT[0])
                                                obj_x = geom_o.centroid.x
                                                obj_y = geom_o.centroid.y
                                            m = ((obj_y - subj_y) / (obj_x - subj_x))
                                            b = (subj_y - (m * subj_x))
                                            head_width = 0.2
                                            head_length = (1.5 * head_width)
                                            arrow = plt.arrow(subj_x, subj_y, dx=(obj_x - subj_x), dy=(obj_y - subj_y), color=cp_colors[cp_color], shape='full', length_includes_head=True, head_width=head_width, head_length=head_length)
                                            if (len(labels[0]) > 1):
                                                label_row = ' '.join([label[0] for label in labels])
                                            else:
                                                label_row = labels[0]
                                            x_offset = (((len(label_row) * 0.055) / 2) - 0.055)
                                            if (subj_x > obj_x):
                                                label_x = ((obj_x + (abs((subj_x - obj_x)) / 2)) - x_offset)
                                            else:
                                                label_x = ((obj_x - (abs((subj_x - obj_x)) / 2)) - x_offset)
                                            a = math.degrees(math.atan(m))
                                            for (l_i, label) in enumerate(labels):
                                                label_string = label[0].replace('CP_', )
                                                label_len = ((len(label_string) * 0.09) + 0.1)
                                                label_x_offset = abs((math.cos(math.atan(m)) * label_len))
                                                while True:
                                                    label_y = (((m * label_x) + b) + 0.05)
                                                    label_x_1 = ((label_x - (label_x_offset / 2)) + 0.05)
                                                    label_y_1 = ((m * label_x_1) + b)
                                                    label_x_2 = ((label_x + (label_x_offset / 2)) + 0.05)
                                                    label_y_2 = ((m * label_x_2) + b)
                                                    label_line1 = geometry.LineString([(label_x_1, label_y_1), (label_x_2, label_y_2)])
                                                    new_bb = label_line1.buffer(0.1, cap_style=2)
                                                    new_bb_rect = list(zip(*new_bb.exterior.xy))[:(- 1)]
                                                    if ((not _AVOID_LABEL_COLLISIONS) or (not _has_collision_with_bbs(plotted_labels, new_bb_rect))):
                                                        break
                                                    label_x += (label_x_offset / 10)
                                                annot = plt.annotate(label_string, (label_x, label_y), color=cp_colors[cp_color], rotation=a, fontsize=2, rotation_mode='anchor')
                                                entity_cp_relations.append(annot)
                                                cps_relations.append(annot)
                                                relations_per_cp_class[same_line_cps[l_i].predicate] += [annot, arrow]
                                                cps_for_tooltips.append(same_line_cps[l_i])
                                                plotted_labels.append(new_bb_rect)
                                                label_x += label_x_offset
                                            subj_x = obj_x
                                            subj_y = obj_y
                                            entity_cp_relations += [arrow]
                                cp_color = ((cp_color + 1) % len(cp_colors))
                        entity_relations.append(entity_cp_relations)
            elif (len(set([str(y) for y in entity.INDIRECT_is_a]).intersection(_NO_PRINTING_CLASSES)) == 0):
                no_geo_entities.append(_describe_entity(entity))
        logger.info('Done with layout, creating MPLD3 plot, JS plugins, and HTML string')
        pl2 = plt.plot(centroids_x, centroids_y, 'o', color='b', mec='k', markersize=2, mew=1, alpha=0.4)
        tooltip_individuals = ToolTipAndClickInfo(pl2[0], labels=entity_labels, targets=entity_relations, targets_per_cp=relations_per_cp_class)
        fig.tight_layout()
        mpld3.plugins.connect(fig, tooltip_individuals)
        for (h, cp_text) in enumerate(cps_relations):
            tooltip_cp = CPTooltip(cp_text, cps_for_tooltips[h])
            mpld3.plugins.connect(fig, tooltip_cp)
        html = (('\n\t\t<div class="container-fluid scene-plot-container" id="plt' + str((i + 1))) + '" style ="')
        if (i != 0):
            html += 'display: none;'
        html += '">'
        html += '\n            <div class="row">\n                <div class="col-md-1">\n                    '
        cp_count_total = len([x for x in cps if ((isinstance(x.traffic_model, list) and (scene in x.traffic_model)) or (x.traffic_model == scenario_inst))])
        html += ('<div class=>\n                        <label class="btn btn-primary active" style="margin-bottom: 10px; width: %s">\n                            <input type="checkbox" class="cp-all-button" id="cp-all-button-%s" autocomplete="off" onclick="toggle_cps_all_iframes();" checked>\n                            <span>Show all criticality phenomena (%s)</span>\n                        </label>' % ('100%', str(i), str(cp_count_total)))
        for (l, pred) in enumerate(sorted(relations_per_cp_class.keys(), key=natural_sort_key)):
            cp_count = len([x for x in cps if ((x.predicate == pred) and ((isinstance(x.traffic_model, list) and (scene in x.traffic_model)) or (x.traffic_model == scenario_inst)))])
            html += ('\n                        <br />\n                        <label class="btn btn-secondary active" style="margin-bottom: 5px; width: %s">\n                            <input type="checkbox" class="cp-button" id="cp-button-%s-%s" autocomplete="off" onclick="toggle_cp_class(this, %s);" checked>\n                            <span>%s (%s)</span>\n                        </label>' % ('100%', str(i), str(l), str(l), pred, str(cp_count)))
        html += '\n                    </div>\n                </div>\n                <div class="col-md-11">\n                    '
        html += '<div class="embed-responsive embed-responsive-16by9">\n'
        html += (((('\t\t\t\t\t\t<iframe class="scene-plot" src="scene' + str((i + 1))) + '.html" class="embed-responsive-item" style="width: 100%; height: ') + str((height * 1.27))) + 'in" allowfullscreen></iframe>\n\t\t\t\t\t</div>\n')
        iframe_html = '<!DOCTYPE html>\n<html>\n    <head>\n        <meta charset="utf-8">\n        <meta HTTP-EQUIV="Access-Control-Allow-Origin" CONTENT="localhost">\n        <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">\n        <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>\n        <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>\n    </head>\n    <body>'
        iframe_html += scene_css
        iframe_html += '\n        <div class="d-flex flex-row justify-content-center">\n            <div class="btn-group btn-group-toggle" data-bs-toggle="buttons">\n                <label class="btn btn-secondary active">\n                    <input type="checkbox" id="tooltip_button" checked autocomplete="off" onclick="toggle_tooltips(this);"> Show tooltip with information of individuals\n                </label>\n                <label class="btn btn-secondary active">\n                    <input type="checkbox" id="descr_button" checked autocomplete="off" onclick="toggle_all_ind_relations(this);"> Show full individual relations in tooltip\n                </label>\n            </div>\n        </div>\n        <script>\n            var show_tooltips = true\n            var show_long_ind = true\n            cps = []\n            cp_targets = []\n            cp_targets_per_class = []\n            function toggle_tooltips(ele) {\n                ele.parentElement.classList.toggle("active")\n                show_tooltips = !show_tooltips\n            }\n            function toggle_all_ind_relations(ele) {\n                ele.parentElement.classList.toggle("active")\n                show_long_ind = !show_long_ind\n            }\n            function toggle_cp_targets(targets, state) {\n                for (let j = 0; j < targets.length; j++) {\n                    var x = mpld3.get_element(targets[j])\n                    if (x) {\n                        if ("path" in x) {\n                            tog = x.path\n                        } else if ("obj" in x) {\n                            tog = x.obj\n                        }\n                        for (var k = 0; k < tog._groups.length; k++) {\n                            for (var l = 0; l < tog._groups[k].length; l++){\n                                if (state) {\n                                    tog._groups[k][l].style.display = "block"\n                                } else {\n                                    tog._groups[k][l].style.display = "none"\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n            function toggle_cps(state) {\n                for (let i = 0; i < cp_targets.length; i++) {\n                    toggle_cp_targets(cp_targets[i], state)\n                }\n            }\n            function toggle_cp_class(cp_class, state) {\n                targets = cp_targets_per_class[cp_class]\n                toggle_cp_targets(targets, state)\n            }\n        </script>\n        <div class="card m-2">\n            <div class="card-title d-flex flex-row justify-content-center m-1">\n                <h5>'
        if ((len(scene.inTimePosition) > 0) and (len(scene.inTimePosition[0].numericPosition) > 0)):
            time = ('%.2f s' % scene.inTimePosition[0].numericPosition[0])
            if (scenario_inst and (len(scenario_inst.hasEnd) > 0) and (len(scenario_inst.hasEnd[0].inTimePosition) > 0) and (len(scenario_inst.hasEnd[0].inTimePosition[0].numericPosition) > 0)):
                time += (' / %.2f s' % scenario_inst.hasEnd[0].inTimePosition[0].numericPosition[0])
            else:
                time += (' / ' + str(len(scenes)))
        else:
            time = ((str(i) + ' / ') + str(len(scenes)))
        iframe_html += (('Scene ' + time) + '<br />')
        iframe_html += '\n                </h5>\n            </div>\n            <div class="card-body m-0 p-0 d-flex justify-content-center">\n        '
        scene_html = mpld3.fig_to_html(fig)
        iframe_html += .join(((('\t\t' + line) + '\n') for line in scene_html.splitlines()))
        iframe_html += '\n            </div>\n        </div>'
        if (len(no_geo_entities) > 0):
            iframe_html += ('\n        <div class="d-flex flex-row justify-content-center">\n            <a class="btn btn-primary" data-bs-toggle="collapse" href="#noGeoCollapse" role="button" aria-expanded="false" aria-controls="noGeoCollapse">\n                Show scene individuals with no geometric representation (%s)\n            </a>\n        </div>\n        <div class="container-fluid collapse" id="noGeoCollapse">\n            <div class="card card-body m-2">' % str(len(no_geo_entities)))
            iframe_html += .join(no_geo_entities)
            iframe_html += '\n            </div>\n        </div>'
        iframe_html += '\t</body>\n</html>'
        iframes.append(iframe_html)
        html += '\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>'
        pl_html.append(html)
    pl_html.append('\n\t</body>\n</html>')
    tmp_dir = tempfile.mkdtemp()
    index_path = (tmp_dir + '/index.html')
    with open(index_path, 'w') as file:
        for html in pl_html:
            file.write(html)
    for (i, iframe) in enumerate(iframes):
        frame_path = (((tmp_dir + '/scene') + str((i + 1))) + '.html')
        with open(frame_path, 'w') as file:
            for html in iframe:
                file.write(html)
    os.chdir(tmp_dir)
    threading.Thread(target=socketserver.TCPServer((, 8000), http.server.SimpleHTTPRequestHandler).serve_forever).start()
    logger.info('Visualization is available at: http://localhost:8000')
    webbrowser.open('http://localhost:8000')
    return tmp_dir