Exemplo n.º 1
0
    def test_SaveGraph_0_normal_graph(self):
        saved_g = Graph()

        v1 = Vertex("1", "black")
        v2 = Vertex("2", "white")
        v3 = Vertex("3", "black")
        v4 = Vertex("4", "white")
        v5 = Vertex("5", "black")

        saved_g.add_vert(v1)
        saved_g.add_vert(v2)
        saved_g.add_vert(v3)
        saved_g.add_vert(v4)
        saved_g.add_vert(v5)

        saved_g.add_edge(v1.id, v2.id)
        saved_g.add_edge(v1.id, v3.id)
        saved_g.add_edge(v2.id, v3.id)
        saved_g.add_edge(v3.id, v4.id)

        saved_xml_str = save_graph(saved_g, "SaveGraph_0_saved_normal_graph.xml")
        # Note: testing the string against a model is tedious because the order
        # of edges varies.

        # Test loaded graph
        loaded_g = load_graph("SaveGraph_0_saved_normal_graph.xml")

        self.assertEqual(loaded_g.get_vert_count(), 5)
        self.assertEqual(loaded_g.get_edge_count(), 4)

        self.assertTrue(loaded_g.has_vert(v1.id))
        self.assertTrue(loaded_g.has_vert(v2.id))
        self.assertTrue(loaded_g.has_vert(v3.id))
        self.assertTrue(loaded_g.has_vert(v4.id))
        self.assertTrue(loaded_g.has_vert(v5.id))

        self.assertTrue(loaded_g.has_edge(v1.id, v2.id))
        self.assertTrue(loaded_g.has_edge(v1.id, v3.id))
        self.assertTrue(loaded_g.has_edge(v2.id, v3.id))
        self.assertTrue(loaded_g.has_edge(v3.id, v4.id))
        self.assertFalse(loaded_g.has_edge(v2.id, v4.id))

        self.assertEqual(loaded_g.get_vert(v1.id).color, "black")
        self.assertEqual(loaded_g.get_vert(v2.id).color, "white")
        self.assertEqual(loaded_g.get_vert(v3.id).color, "black")
        self.assertEqual(loaded_g.get_vert(v4.id).color, "white")
        self.assertEqual(loaded_g.get_vert(v5.id).color, "black")

        self.assertEqual(loaded_g.neighbors(v1.id), {v2, v3})
        self.assertEqual(loaded_g.neighbors(v2.id), {v3, v1})
        self.assertEqual(loaded_g.neighbors(v3.id), {v1, v2, v4})
        self.assertEqual(loaded_g.neighbors(v4.id), {v3})
        self.assertEqual(loaded_g.neighbors(v5.id), set())
Exemplo n.º 2
0
    def test_SaveGraph_1_empty_graph(self):
        saved_g = Graph()

        saved_xml_str = save_graph(saved_g, "SaveGraph_1_empty_graph.xml")
        empty_graph_xml_str = '<?xml version="1.0" ?>\n<graph/>\n'

        self.assertEqual(saved_xml_str, empty_graph_xml_str)

        loaded_g = load_graph("SaveGraph_1_empty_graph.xml")

        self.assertEqual(loaded_g.get_vert_count(), 0)
        self.assertEqual(loaded_g.get_edge_count(), 0)

        # Add some stuff to the graph
        v1 = Vertex("1", "black")
        v2 = Vertex("2", "white")

        loaded_g.add_vert(v1)
        loaded_g.add_vert(v2)
        loaded_g.add_edge("1", "2")

        saved_xml_str = save_graph(loaded_g, "SaveGraph_1_empty_graph.xml")

        reloaded_g = load_graph("SaveGraph_1_empty_graph.xml")

        self.assertEqual(reloaded_g.get_vert_count(), 2)
        self.assertEqual(reloaded_g.get_edge_count(), 1)
        self.assertTrue(reloaded_g.has_vert("1"))
        self.assertTrue(reloaded_g.has_vert("2"))
        self.assertTrue(reloaded_g.has_edge("2", "1"))
        self.assertEqual(reloaded_g.get_vert("1").color, "black")
        self.assertEqual(reloaded_g.get_vert("2").color, "white")

        # Remove the stuff
        reloaded_g.del_vert("1")
        reloaded_g.del_vert("2")

        saved_xml_str = save_graph(reloaded_g, "SaveGraph_1_empty_graph.xml")

        self.assertEqual(saved_xml_str, empty_graph_xml_str)
Exemplo n.º 3
0
    def test_LoadGoodXML_1_good_colors(self):
        correct_g = Graph()

        v1 = Vertex("1", "white")
        v2 = Vertex("2", "black")
        v3 = Vertex("3", "white")
        v4 = Vertex("4", "white")
        v5 = Vertex("5", "white")
        v6 = Vertex("6", "white")
        v7 = Vertex("7", "white")
        v8 = Vertex("8", "black")
        v9 = Vertex("9", "black")

        correct_g.add_vert(v1)
        correct_g.add_vert(v2)
        correct_g.add_vert(v3)
        correct_g.add_vert(v4)
        correct_g.add_vert(v5)
        correct_g.add_vert(v6)
        correct_g.add_vert(v7)
        correct_g.add_vert(v8)
        correct_g.add_vert(v9)

        correct_g.add_edge(v1.id, v2.id)
        correct_g.add_edge(v1.id, v3.id)
        correct_g.add_edge(v2.id, v3.id)
        correct_g.add_edge(v3.id, v4.id)

        parsed_g = load_graph("LoadGoodXML_1_good_color.xml")

        self.assertTrue(parsed_g == correct_g)

        self.assertEqual(parsed_g.get_vert(v1.id).color, "white")
        self.assertEqual(parsed_g.get_vert(v2.id).color, "black")
        self.assertEqual(parsed_g.get_vert(v3.id).color, "white")
        self.assertEqual(parsed_g.get_vert(v4.id).color, "white")
        self.assertEqual(parsed_g.get_vert(v5.id).color, "white")
        self.assertEqual(parsed_g.get_vert(v6.id).color, "white")
        self.assertEqual(parsed_g.get_vert(v7.id).color, "white")
        self.assertEqual(parsed_g.get_vert(v8.id).color, "black")
        self.assertEqual(parsed_g.get_vert(v9.id).color, "black")
Exemplo n.º 4
0
def clicked_vertex_or_go_or_turn_button(clickData, go_clicks, load_clicks, displayed_fig, k_curr, path, curr_turn):
    """
    This callback handles reaction to clicking:
        - a vertex in the graph
        - the "GO" button to advance the turn
        - the "Load" button to import a graph
    All three events are lumped together in this callback because all share
    Output("displayed-graph", "figure"), and an Output can only be assigned
    to one callback.
    """
    global loaded_hr_graph
    global clicked_verts_this_turn
    global node_positions

    ctx = dash.callback_context
    thing_clicked = ctx.triggered[0]["prop_id"].split(".")[0]

    k_nums = [int(i) for i in k_curr.split("/")]
    turn_num = int(curr_turn[6:])
    normal_k_color = {
        "display": "inline-block",
        "color": "black",
        "background": "white"
    }
    inverted_k_color = {
        "display": "inline-block",
        "color": "white",
        "background": "black"
    }
    ret_color = normal_k_color

    # Clicked graph vertex ###################################################
    if (thing_clicked == "displayed-graph") and (clickData is not None):
        clicked_vert_color = clickData["points"][0]["marker.color"]
        clicked_vert_id = clickData["points"][0]["text"]

        #############################
        # Flip clicked vertex color #
        #############################
        if clicked_vert_color == "black":
            new_color = "white"
        else:
            new_color = "black"

        displayed_fig["data"][0]["marker"]["color"][clickData["points"][0]["pointNumber"]] = new_color

        ####################
        # Update k readout #
        ####################
        if clicked_vert_id not in clicked_verts_this_turn:
            # If clicking this vertex for the first time (its id is not in
            # clicked_verts_this_turn), increment k
            # and store new_color (for reference when recoloring
            # loaded_hr_graph later)
            clicked_verts_this_turn[clicked_vert_id] = new_color
            if len(k_nums) == 1:
                # Still on first turn; k is shown as a single number with
                # no denominator.
                ret_str = f"{k_nums[0] + 1}"
            elif len(k_nums) == 2:
                # On turn 2 or greater; show k as n/d where n is the d from
                # previous turn and n is verts clicked this turn
                ret_str = f"{k_nums[0] + 1} / {k_nums[1]}"

                # Invert k background and color if n != d
                # (This serves as a visual aid so the user clicks the
                # same number of vertices each turn)
                if (k_nums[0] + 1) != k_nums[1]:
                    ret_color = inverted_k_color
                else:
                    ret_color = normal_k_color
        else:
            # If this vertex was already clicked (its id is already in
            # clicked_verts_this_turn), decrement k.
            clicked_verts_this_turn.pop(clicked_vert_id)
            if len(k_nums) == 1:
                ret_str = f"{k_nums[0] - 1}"
            elif len(k_nums) == 2:
                ret_str = f"{k_nums[0] - 1 } / {k_nums[1]}"

                if (k_nums[0] - 1) != k_nums[1]:
                    ret_color = inverted_k_color
                else:
                    ret_color = normal_k_color

        return displayed_fig, ret_str, ret_color, False, "", curr_turn
    # Clicked GO button ########################################################
    elif (thing_clicked == "go-button") and (go_clicks):
        ################################
        # Recolor graph and update fig #
        ################################
        for id in clicked_verts_this_turn.keys():
            loaded_hr_graph.get_vert(id).color = clicked_verts_this_turn[id]
        hr_logic.recolor(loaded_hr_graph)

        new_fig = figure_from_hr_graph(loaded_hr_graph)

        ####################
        # Update k readout #
        ####################
        clicked_verts_this_turn.clear()

        # Show n/d where n is 0 and d is n from previous turn
        if k_nums[0] == 0:
            ret_color = normal_k_color
        else:
            ret_color = inverted_k_color

        return new_fig, f"0 / {k_nums[0]}", ret_color, False, "", f"Turn: {turn_num + 1}"
    # Clicked Load button ######################################################
    elif (thing_clicked == "load-button") and (load_clicks):
        try:
            loaded_hr_graph = hr_io.load_graph(path)
        except Exception as e:
            return displayed_fig, k_curr, normal_k_color, True, repr(e), curr_turn

        node_positions = None # Wipe positions to regenerate for new graph
        new_fig = figure_from_hr_graph(loaded_hr_graph)

        return new_fig, k_curr, normal_k_color, False, "", "Turn: 0"
    # Nothing clicked; standard Dash trigger of all callbacks at startup #######
    else:
        return displayed_fig, k_curr, normal_k_color, False, "", curr_turn
Exemplo n.º 5
0
 def test_LoadBadXML_9_bad_color(self):
     with self.assertRaises(RuntimeError):
         parsed_g = load_graph("LoadBadXML_9_bad_color.xml")
Exemplo n.º 6
0
 def test_LoadBadXML_6_invalid_elt(self):
     with self.assertRaises(RuntimeError):
         parsed_g = load_graph("LoadBadXML_6_invalid_elt.xml")
Exemplo n.º 7
0
 def test_LoadBadXML_8_bad_vert_elt(self):
     with self.assertRaises(RuntimeError):
         parsed_g = load_graph("LoadBadXML_8_bad_edge_elt.xml")
Exemplo n.º 8
0
 def test_LoadBadXML_3_bad_edge_id_att(self):
     with self.assertRaises(RuntimeError):
         parsed_g = load_graph("LoadBadXML_3_bad_edge_id_att.xml")
Exemplo n.º 9
0
 def test_LoadBadXML_4_missing_file(self):
     with self.assertRaises(FileNotFoundError):
         parsed_g = load_graph("thisfiledoesnotexist")
Exemplo n.º 10
0
 def test_LoadBadXML_0_missing_vert_id_att(self):
     with self.assertRaises(RuntimeError):
         parsed_g = load_graph("LoadBadXML_0_missing_vert_id_att.xml")
Exemplo n.º 11
0
    def test_LoadGoodXML_5_bad_graph_edge_to_missing_vert(self):
        parsed_g = load_graph("LoadGoodXML_5_empty.xml")

        self.assertEqual(parsed_g.get_vert_count(), 0)
        self.assertEqual(parsed_g.get_edge_count(), 0)
Exemplo n.º 12
0
    def test_LoadGoodXML_0_normal(self):
        correct_g = Graph()

        v1 = Vertex("1", 0)
        v2 = Vertex("2", 0)
        v3 = Vertex("3", 0)
        v4 = Vertex("4", 0)
        v5 = Vertex("5", 0)

        correct_g.add_vert(v1)
        correct_g.add_vert(v2)
        correct_g.add_vert(v3)
        correct_g.add_vert(v4)
        correct_g.add_vert(v5)

        correct_g.add_edge(v1.id, v2.id)
        correct_g.add_edge(v1.id, v3.id)
        correct_g.add_edge(v2.id, v3.id)
        correct_g.add_edge(v3.id, v4.id)

        # Sanity check
        self.assertEqual(correct_g.get_vert_count(), 5)
        self.assertEqual(correct_g.get_edge_count(), 4)

        self.assertTrue(correct_g.has_vert(v1.id))
        self.assertTrue(correct_g.has_vert(v2.id))
        self.assertTrue(correct_g.has_vert(v3.id))
        self.assertTrue(correct_g.has_vert(v4.id))
        self.assertTrue(correct_g.has_vert(v5.id))

        self.assertTrue(correct_g.has_edge(v1.id, v2.id))
        self.assertTrue(correct_g.has_edge(v1.id, v3.id))
        self.assertTrue(correct_g.has_edge(v2.id, v3.id))
        self.assertTrue(correct_g.has_edge(v3.id, v4.id))
        self.assertFalse(correct_g.has_edge(v2.id, v4.id))

        self.assertEqual(correct_g.get_vert(v1.id).color, 0)
        self.assertEqual(correct_g.get_vert(v2.id).color, 0)
        self.assertEqual(correct_g.get_vert(v3.id).color, 0)
        self.assertEqual(correct_g.get_vert(v4.id).color, 0)
        self.assertEqual(correct_g.get_vert(v5.id).color, 0)

        self.assertEqual(correct_g.neighbors(v1.id), {v2, v3})
        self.assertEqual(correct_g.neighbors(v2.id), {v3, v1})
        self.assertEqual(correct_g.neighbors(v3.id), {v1, v2, v4})
        self.assertEqual(correct_g.neighbors(v4.id), {v3})
        self.assertEqual(correct_g.neighbors(v5.id), set())

        # Parse XML file
        parsed_g = load_graph("LoadGoodXML_0_normal.xml")

        # g1 == g2 if they have same edges and same vertices by id
        # (even if vertices differ otherwise)
        self.assertTrue(parsed_g == correct_g)

        self.assertEqual(parsed_g.get_vert(v1.id).color, "black")
        self.assertEqual(parsed_g.get_vert(v2.id).color, "black")
        self.assertEqual(parsed_g.get_vert(v3.id).color, "black")
        self.assertEqual(parsed_g.get_vert(v4.id).color, "black")
        self.assertEqual(parsed_g.get_vert(v5.id).color, "black")

        # Modify edge or vert inventory to break equality
        correct_g.del_edge("1", "2")
        self.assertTrue(parsed_g != correct_g)
Exemplo n.º 13
0
 def test_LoadGoodXML_4_bad_graph_edge_to_missing_vert(self):
     with self.assertRaises(KeyError):
         parsed_g = load_graph("LoadGoodXML_4_bad_graph_edge_to_missing_vert.xml")
Exemplo n.º 14
0
 def test_LoadGoodXML_3_bad_graph_repeated_edge(self):
     with self.assertRaises(ValueError):
         parsed_g = load_graph("LoadGoodXML_3_bad_graph_repeated_edge.xml")