コード例 #1
0
def test_nogo_graph_tool():
    net = pp.create_empty_network()
    add_test_line(net)
    mg = create_nxgraph(net, library="graph_tool")
    assert set(mg.nodes()) == set(net.bus.index)
    mg = create_nxgraph(net, nogobuses=[0], library="graph_tool")
    assert set(mg.nodes()) == set(net.bus.index) - {0}
コード例 #2
0
def test_impedance():
    net = pp.create_empty_network()
    add_test_impedance(net)
    impedance, oos_impedance = net.impedance.index
    f, t = net.impedance.from_bus.at[impedance], net.impedance.to_bus.at[
        impedance]

    #check that oos impedances are neglected and switches are respected
    mg = create_nxgraph(net)
    assert set(mg.get_edge_data(f, t).keys()) == {("impedance", impedance)}
    assert set(mg.nodes()) == set(net.bus.index)

    #check not including impedances
    mg = create_nxgraph(net, include_impedances=False)
    assert mg.get_edge_data(f, t) is None
    assert set(mg.nodes()) == set(net.bus.index)

    #check edge attributes
    mg = create_nxgraph(net,
                        calc_branch_impedances=True,
                        branch_impedance_unit="pu")
    pp.runpp(net)

    par = mg.get_edge_data(f, t, key=("impedance", impedance))
    assert np.isclose(par["weight"], 0)
    assert par["path"] == 1
    f, t = net._pd2ppc_lookups["branch"]["impedance"]
    assert np.isclose(par["r_pu"], net._ppc["branch"][f, BR_R])
    assert np.isclose(par["x_pu"], net._ppc["branch"][f, BR_X])
コード例 #3
0
def test_trafo3w():
    net = pp.create_empty_network()
    add_test_trafo3w(net)
    t1, t2 = net.trafo3w.index
    trafo3 = net.trafo3w.iloc[t1]
    hv, mv, lv = trafo3.hv_bus, trafo3.mv_bus, trafo3.lv_bus
    mg = create_nxgraph(net)
    for f, t in combinations([hv, mv, lv], 2):
        assert set(mg.get_edge_data(f, t).keys()) == {("trafo3w", t1)}
        assert set(mg.nodes()) == set(net.bus.index)

    net.trafo3w.in_service.at[t2] = True
    mg = create_nxgraph(net)
    for f, t in combinations([hv, mv, lv], 2):
        assert set(mg.get_edge_data(f, t).keys()) == {("trafo3w", t1),
                                                      ("trafo3w", t2)}
        assert set(mg.nodes()) == set(net.bus.index)

    for sb in [hv, mv, lv]:
        sw = pp.create_switch(net, bus=sb, element=t1, et="t3", closed=False)
        mg = create_nxgraph(net)
        for f, t in combinations([hv, mv, lv], 2):
            if sb == f or t == sb:
                assert set(mg.get_edge_data(f, t).keys()) == {("trafo3w", t2)}
            else:
                assert set(mg.get_edge_data(f, t).keys()) == {("trafo3w", t1),
                                                              ("trafo3w", t2)}
            assert set(mg.nodes()) == set(net.bus.index)
        net.switch.closed.at[sw] = True
コード例 #4
0
def test_nogo():
    net = pp.create_empty_network()
    add_test_line(net)
    mg = create_nxgraph(net)
    assert set(mg.nodes()) == set(net.bus.index)
    mg = create_nxgraph(net, nogobuses=[0])
    assert set(mg.nodes()) == set(net.bus.index) - {0}
コード例 #5
0
def test_bus_bus_switches():
    net = pp.create_empty_network()
    add_test_bus_bus_switch(net)
    s = net.switch.index[0]
    f, t = net.switch.bus.iloc[0], net.switch.element.iloc[0]

    net.switch.closed.at[s] = True
    mg = create_nxgraph(net)
    assert set(mg.get_edge_data(f, t)) == {("switch", s)}
    assert set(mg.nodes()) == set(net.bus.index)

    net.switch.closed.at[s] = False
    mg = create_nxgraph(net)
    assert mg.get_edge_data(f, t) is None
    assert set(mg.nodes()) == set(net.bus.index)

    mg = create_nxgraph(net, respect_switches=False)
    assert set(mg.get_edge_data(f, t)) == {("switch", s)}
    assert set(mg.nodes()) == set(net.bus.index)

    mg = create_nxgraph(net,
                        respect_switches=False,
                        calc_branch_impedances=True)
    #TODO check R/X/Z values
    par = mg.get_edge_data(f, t, key=("switch", s))
    assert np.isclose(par["r_ohm"], 0)
    assert np.isclose(par["z_ohm"], 0)
    assert np.isclose(par["weight"], 0)
    assert par["path"] == 1
コード例 #6
0
def test_trafo():
    net = pp.create_empty_network()
    add_test_trafo(net)

    for library in libraries:
        trafo, open_loop_trafo, oos_trafo = net.trafo.index
        f, t = net.trafo.hv_bus.at[trafo], net.trafo.lv_bus.at[trafo]
        # check that oos trafos are neglected and switches are respected
        mg = create_nxgraph(net, library=library)
        assert set(mg.get_edge_data(f, t).keys()) == {("trafo", trafo)}
        assert set(mg.nodes()) == set(net.bus.index)

        # check respect_switches
        mg = create_nxgraph(net, respect_switches=False, library=library)
        assert set(mg.get_edge_data(f,
                                    t).keys()) == {("trafo", trafo),
                                                   ("trafo", open_loop_trafo)}
        assert set(mg.nodes()) == set(net.bus.index)

        # check not including trafos
        mg = create_nxgraph(net, include_trafos=False, library=library)
        assert mg.get_edge_data(f, t) is None
        assert set(mg.nodes()) == set(net.bus.index)

        # check edge attributes
        net.trafo.vn_hv_kv = 20
        net.trafo.vn_lv_kv = 0.4
        net.trafo.pfe_kw = 0
        net.trafo.i0_percent = 0
        mg = create_nxgraph(net, calc_branch_impedances=True, library=library)
        trafo_tab = net.trafo.loc[trafo]
        par = mg.get_edge_data(f, t, key=("trafo", trafo))
        base_Z = (trafo_tab.sn_mva) / (trafo_tab.vn_hv_kv**2)
        r = (trafo_tab.vkr_percent / 100) / base_Z / trafo_tab.parallel
        z = (trafo_tab.vk_percent / 100) / base_Z / trafo_tab.parallel
        assert np.isclose(par["r_ohm"], r)
        assert np.isclose(par["z_ohm"], z)
        assert par["weight"] == 0
        assert par["path"] == 1

        mg = create_nxgraph(net,
                            calc_branch_impedances=True,
                            branch_impedance_unit="pu",
                            library=library)
        par = mg.get_edge_data(f, t, key=("trafo", trafo))
        pp.runpp(net)
        f, t = net._pd2ppc_lookups["branch"]["trafo"]
        assert np.isclose(par["r_pu"], net._ppc["branch"][f, BR_R])
        assert np.isclose(par["x_pu"], net._ppc["branch"][f, BR_X])
コード例 #7
0
def test_trafo3w_impedances(network_with_trafo3ws):
    net, t3, hv, mv, lv = network_with_trafo3ws
    net.trafo3w.vn_hv_kv = 20
    net.trafo3w.vn_mv_kv = 0.6
    net.trafo3w.vn_lv_kv = 0.4
    t3 = net.trafo3w.index[0]
    mg = create_nxgraph(net, calc_branch_impedances=True)
    trafo3 = net.trafo3w.loc[t3]
    hv, mv, lv = trafo3.hv_bus, trafo3.mv_bus, trafo3.lv_bus
    base_Z_hv = min(trafo3.sn_hv_mva, trafo3.sn_mv_mva) / (trafo3.vn_hv_kv**2)
    base_Z_mv = min(trafo3.sn_mv_mva, trafo3.sn_lv_mva) / (trafo3.vn_hv_kv**2)
    base_Z_lv = min(trafo3.sn_hv_mva, trafo3.sn_lv_mva) / (trafo3.vn_hv_kv**2)

    par = mg.get_edge_data(hv, mv, key=("trafo3w", t3))
    assert np.isclose(par["r_ohm"], (trafo3.vkr_hv_percent / 100) / base_Z_hv)
    assert np.isclose(par["z_ohm"], (trafo3.vk_hv_percent / 100) / base_Z_hv)
    assert par["weight"] == 0
    assert par["path"] == 1

    par = mg.get_edge_data(mv, lv, key=("trafo3w", t3))
    assert np.isclose(par["r_ohm"], (trafo3.vkr_mv_percent / 100) / base_Z_mv)
    assert np.isclose(par["z_ohm"], (trafo3.vk_mv_percent / 100) / base_Z_mv)
    assert par["weight"] == 0
    assert par["path"] == 1

    par = mg.get_edge_data(hv, lv, key=("trafo3w", t3))
    assert np.isclose(par["r_ohm"], (trafo3.vkr_lv_percent / 100) / base_Z_lv)
    assert np.isclose(par["z_ohm"], (trafo3.vk_lv_percent / 100) / base_Z_lv)
    assert par["weight"] == 0
    assert par["path"] == 1
コード例 #8
0
def test_connected_components(feeder_network):
    net = feeder_network
    mg = top.create_nxgraph(net)
    cc = top.connected_components(mg)
    assert list(cc) == [{0, 1, 2, 3}]
    cc_notrav = top.connected_components(mg, notravbuses={0, 2})
    assert list(cc_notrav) == [{0, 1, 2}, {0, 2, 3}]
コード例 #9
0
ファイル: generic_geodata.py プロジェクト: tazjel/pandapower
def create_generic_coordinates(net, mg=None, library="igraph", respect_switches=False):
    """
    This function will add arbitrary geo-coordinates for all buses based on an analysis of branches and rings.
    It will remove out of service buses/lines from the net. The coordinates will be created either by igraph or by
    using networkx library.

    INPUT:
        **net** - pandapower network

    OPTIONAL:
        **mg** - Existing networkx multigraph, if available. Convenience to save computation time.

        **library** - "igraph" to use igraph package or "networkx" to use networkx package

    OUTPUT:
        **net** - pandapower network with added geo coordinates for the buses

    EXAMPLE:
        net = create_generic_coordinates(net)

    """
    if "bus_geodata" in net and net.bus_geodata.shape[0]:
        print("Please delete all geodata. This function cannot be used with pre-existing geodata.")
        return
    if not "bus_geodata" in net:
        net.bus_geodata = pd.DataFrame(columns=["x", "y"])
    gnet = copy.deepcopy(net)
    gnet.bus = gnet.bus[gnet.bus.in_service == True]
    if library == "igraph":
        try:
            import igraph
        except ImportError:
            raise UserWarning("The library igraph is selected for plotting, "
                              "but not installed correctly.")
        graph, meshed, roots = build_igraph_from_pp(gnet, respect_switches)
        if meshed:
            layout = graph.layout("kk")
        else:
            graph.to_undirected(mode="each", combine_edges="first")
            layout = graph.layout("rt", root=roots)
        coords = list(zip(*layout.coords))
    elif library == "networkx":
        if mg is None:
            nxg = top.create_nxgraph(gnet, respect_switches)
        else:
            nxg = copy.deepcopy(mg)
        # workaround for bug in agraph
        for u, v in nxg.edges_iter(data=False, keys=False):
            if 'key' in nxg[int(u)][int(v)]:
                del nxg[int(u)][int(v)]['key']
            if 'key' in nxg[int(u)][int(v)][0]:
                del nxg[int(u)][int(v)][0]['key']
        coords = list(zip(*(list(nx.drawing.nx_agraph.graphviz_layout(nxg, prog='neato').values()))))
    else:
        raise ValueError("Unknown library %s - chose 'igraph' or 'networkx'"%library)
    net.bus_geodata.x = coords[0]
    net.bus_geodata.y = coords[1]
    net.bus_geodata.index = net.bus.index
    return net
コード例 #10
0
def create_generic_coordinates(net,
                               mg=None,
                               library="igraph",
                               respect_switches=False,
                               geodata_table="bus_geodata",
                               buses=None,
                               overwrite=False):
    """
    This function will add arbitrary geo-coordinates for all buses based on an analysis of branches
    and rings. It will remove out of service buses/lines from the net. The coordinates will be
    created either by igraph or by using networkx library.

    :param net: pandapower network
    :type net: pandapowerNet
    :param mg: Existing networkx multigraph, if available. Convenience to save computation time.
    :type mg: networkx.Graph
    :param library: "igraph" to use igraph package or "networkx" to use networkx package
    :type library: str
    :param geodata_table: table to write the generic geodatas to
    :type geodata_table: str
    :param buses: buses for which generic geodata are created, all buses will be used by default
    :type buses: list
    :param overwrite: overwrite existing geodata
    :type overwrite: bool
    :return: net - pandapower network with added geo coordinates for the buses

    :Example:
        net = create_generic_coordinates(net)
    """

    _prepare_geodata_table(net, geodata_table, overwrite)
    if library == "igraph":
        if not IGRAPH_INSTALLED:
            raise UserWarning(
                "The library igraph is selected for plotting, but not installed "
                "correctly. Please install python-igraph with "
                "`pip install python-igraph` or "
                "`conda install python-igraph` "
                "or from https://www.lfd.uci.edu/~gohlke/pythonlibs")
        graph, meshed, roots = build_igraph_from_pp(net,
                                                    respect_switches,
                                                    buses=buses)
        coords = coords_from_igraph(graph, roots, meshed)
    elif library == "networkx":
        if mg is None:
            nxg = top.create_nxgraph(net,
                                     respect_switches=respect_switches,
                                     include_out_of_service=True)
        else:
            nxg = copy.deepcopy(mg)
        coords = coords_from_nxgraph(nxg)
    else:
        raise ValueError("Unknown library %s - chose 'igraph' or 'networkx'" %
                         library)
    if len(coords):
        net[geodata_table].x = coords[1]
        net[geodata_table].y = coords[0]
        net[geodata_table].index = net.bus.index if buses is None else buses
    return net
コード例 #11
0
def test_line():
    net = pp.create_empty_network()
    add_test_line(net)
    line, open_loop_line, oos_line = net.line.index
    f, t = net.line.from_bus.at[line], net.line.to_bus.at[line]

    # check that oos lines are neglected and switches are respected
    for library in libraries:
        mg = create_nxgraph(net, library=library)
        assert set(mg.get_edge_data(f, t).keys()) == {("line", line)}
        assert set(mg.nodes()) == set(net.bus.index)

        # check respect_switches
        mg = create_nxgraph(net, respect_switches=False, library=library)
        assert set(mg.get_edge_data(f, t).keys()) == {("line", line),
                                                      ("line", open_loop_line)}
        assert set(mg.nodes()) == set(net.bus.index)

        # check not including lines
        mg = create_nxgraph(net, include_lines=False, library=library)
        assert mg.get_edge_data(f, t) is None
        assert set(mg.nodes()) == set(net.bus.index)

        # check edge attributes
        mg = create_nxgraph(net, calc_branch_impedances=True, library=library)
        line_tab = net.line.loc[line]
        par = mg.get_edge_data(f, t, key=("line", line))
        r = line_tab.length_km / line_tab.parallel * line_tab.r_ohm_per_km
        x = line_tab.length_km / line_tab.parallel * line_tab.x_ohm_per_km
        z = np.sqrt(r**2 + x**2)
        assert np.isclose(par["r_ohm"], r)
        assert np.isclose(par["x_ohm"], x)
        assert np.isclose(par["z_ohm"], z)
        assert np.isclose(par["weight"], line_tab.length_km)
        assert par["path"] == 1

        mg = create_nxgraph(net,
                            calc_branch_impedances=True,
                            branch_impedance_unit="pu",
                            library=library)
        line_tab = net.line.loc[line]
        par = mg.get_edge_data(f, t, key=("line", line))
        pp.runpp(net)
        f, t = net._pd2ppc_lookups["branch"]["line"]
        assert np.isclose(par["r_pu"], net._ppc["branch"][f, BR_R])
        assert np.isclose(par["x_pu"], net._ppc["branch"][f, BR_X])
コード例 #12
0
ファイル: generic_geodata.py プロジェクト: tazjel/pandapower
def fuse_geodata(net):
    mg = top.create_nxgraph(net, include_lines=False, respect_switches=False)
    geocoords = set(net.bus_geodata.index)
    for area in top.connected_components(mg):
        if len(area & geocoords) > 1:
            geo = net.bus_geodata.loc[area & geocoords].values[0]
            for bus in area:
                net.bus_geodata.loc[bus] = geo
コード例 #13
0
def test_elements_on_path():
    net = nw.example_simple()
    for multi in [True, False]:
        mg = top.create_nxgraph(net, multi=multi)
        path = nx.shortest_path(mg, 0, 6)
        assert top.elements_on_path(mg, path, "line") == [0, 3]
        assert top.lines_on_path(mg, path) == [0, 3]
        assert top.elements_on_path(mg, path, "trafo") == [0]
        assert top.elements_on_path(mg, path, "trafo3w") == []
        assert top.elements_on_path(mg, path, "switch") == [0, 1]    
コード例 #14
0
def detect_power_station_unit(net, mode="auto",
                              max_gen_voltage_kv=80, max_distance_km=0.01):
    """
    Identifies the power station units configuration (gen and trafo) according to IEC 60909.
    Updates the power_station_trafo in the gen table

    INPUT:
        **net** - panpdapower net

        **mode** (str, ("auto", trafo""))

        **max_gen_voltage_level** (float)

        **max_distance_km** (float)
    """
    logger.info("This function will overwrites the value 'power_station_trafo' in gen table")
    net.gen["power_station_trafo"] = np.nan

    required_gen = net.gen.loc[net.bus.loc[net.gen.bus.values, "vn_kv"].values < max_gen_voltage_kv,:]
    required_gen_bus = required_gen.loc[:, "bus"].values

    if mode.lower() == "auto":
        required_trafo = net.trafo.loc[net.bus.loc[net.trafo.lv_bus.values, "vn_kv"].values < max_gen_voltage_kv, :]
    elif mode.lower() == "trafo":
        if "power_station_unit" in net.trafo.columns:
            required_trafo = net.trafo.loc[net.trafo.power_station_unit, :]
        else:
            logger.warning("Using mode 'trafo' requires 'power_station_unit' defined for trafo! Using 'auto' mode instead!")
            required_trafo = net.trafo.loc[net.bus.loc[net.trafo.lv_bus.values, "vn_kv"].values < max_gen_voltage_kv, :]

    else:
        raise UserWarning(f"Unsupported modes: {mode}")

    trafo_lv_bus = net.trafo.loc[required_trafo.index, "lv_bus"].values
    trafo_hv_bus = net.trafo.loc[required_trafo.index, "hv_bus"].values

    g = create_nxgraph(net, respect_switches=True,
                       nogobuses=None, notravbuses=trafo_hv_bus)

    for t_ix in required_trafo.index:
        t_lv_bus = required_trafo.at[t_ix, "lv_bus"]
        bus_dist = pd.Series(nx.single_source_dijkstra_path_length(g, t_lv_bus, weight='weight'))

        connected_bus_at_lv_side = bus_dist[bus_dist < max_distance_km].index.values
        gen_bus_at_lv_side = np.intersect1d(connected_bus_at_lv_side, required_gen_bus)

        if len(gen_bus_at_lv_side) == 1:
            # Check parallel trafo
            if not len(np.intersect1d(connected_bus_at_lv_side, trafo_lv_bus)) == 1:
                raise UserWarning("Failure in power station units detection! Parallel trafos on generator detected!")
            if np.in1d(required_gen_bus, gen_bus_at_lv_side).sum() > 1:
                logger.info("More than 1 gen detected at the lv side of a power station trafo! Will not be considered as power station unit")
                continue
            net.gen.loc[np.in1d(net.gen.bus.values, gen_bus_at_lv_side),
                        "power_station_trafo"] = t_ix
コード例 #15
0
ファイル: generic_geodata.py プロジェクト: znicoy/pandapower
def create_generic_coordinates(net,
                               mg=None,
                               library="igraph",
                               respect_switches=False):
    """
    This function will add arbitrary geo-coordinates for all buses based on an analysis of branches
    and rings. It will remove out of service buses/lines from the net. The coordinates will be
    created either by igraph or by using networkx library.

    :param net: pandapower network
    :type net: pandapowerNet
    :param mg: Existing networkx multigraph, if available. Convenience to save computation time.
    :type mg: networkx.Graph
    :param library: "igraph" to use igraph package or "networkx" to use networkx package
    :type library: str
    :return: net - pandapower network with added geo coordinates for the buses

    :Example:
        net = create_generic_coordinates(net)
    """

    if "bus_geodata" in net and net.bus_geodata.shape[0]:
        logger.warning(
            "Please delete all geodata. This function cannot be used with pre-existing"
            " geodata.")
        return
    if "bus_geodata" not in net or net.bus_geodata is None:
        net.bus_geodata = pd.DataFrame(columns=["x", "y"])

    gnet = copy.deepcopy(net)
    gnet.bus = gnet.bus[gnet.bus.in_service == True]

    if library == "igraph":
        if not IGRAPH_INSTALLED:
            raise UserWarning(
                "The library igraph is selected for plotting, but not installed "
                "correctly.")
        graph, meshed, roots = build_igraph_from_pp(gnet, respect_switches)
        coords = coords_from_igraph(graph, roots, meshed)
    elif library == "networkx":
        if mg is None:
            nxg = top.create_nxgraph(gnet, respect_switches=respect_switches)
        else:
            nxg = copy.deepcopy(mg)
        coords = coords_from_nxgraph(nxg)
    else:
        raise ValueError("Unknown library %s - chose 'igraph' or 'networkx'" %
                         library)

    net.bus_geodata.x = coords[1]
    net.bus_geodata.y = coords[0]
    net.bus_geodata.index = gnet.bus.index
    return net
コード例 #16
0
def test_json_different_nets():
    net = networks.mv_oberrhein()
    net2 = networks.simple_four_bus_system()
    control.ContinuousTapControl(net, 114, 1.02)
    net.tuple = (1, "4")
    net.mg = topology.create_nxgraph(net)
    json_string = json.dumps([net, net2], cls=PPJSONEncoder)
    [net_out, net2_out] = json.loads(json_string, cls=PPJSONDecoder)
    assert_net_equal(net_out, net)
    assert_net_equal(net2_out, net2)
    pp.runpp(net_out, run_control=True)
    pp.runpp(net, run_control=True)
    assert_net_equal(net, net_out)
コード例 #17
0
def test_elements_on_path():
    net = nw.example_simple()
    for multi in [True, False]:
        mg = top.create_nxgraph(net, multi=multi)
        path = nx.shortest_path(mg, 0, 6)
        assert top.elements_on_path(mg, path, "line") == [0, 3]
        assert top.lines_on_path(mg, path) == [0, 3]
        assert top.elements_on_path(mg, path, "trafo") == [0]
        assert top.elements_on_path(mg, path, "trafo3w") == []
        assert top.elements_on_path(mg, path, "switch") == [0, 1]
        with pytest.raises(ValueError) as exception_info:
            top.elements_on_path(mg, path, element="sgen")
        assert str(exception_info.value) == "Invalid element type sgen"
コード例 #18
0
def test_graph_characteristics(feeder_network):
    # adapt network
    net = feeder_network
    bus0 = pp.create_bus(net, vn_kv=20.0)
    bus1 = pp.create_bus(net, vn_kv=20.0)
    bus2 = pp.create_bus(net, vn_kv=20.0)
    bus3 = pp.create_bus(net, vn_kv=20.0)
    bus4 = pp.create_bus(net, vn_kv=20.0)
    bus5 = pp.create_bus(net, vn_kv=20.0)
    bus6 = pp.create_bus(net, vn_kv=20.0)
    bus7 = pp.create_bus(net, vn_kv=20.0)
    bus8 = pp.create_bus(net, vn_kv=20.0)
    bus9 = pp.create_bus(net, vn_kv=20.0)
    new_connections = [(3, bus0), (bus0, bus1), (bus0, bus2), (1, bus3),
                       (2, bus4), (bus3, bus4), (bus4, bus5), (bus4, bus6),
                       (bus5, bus6), (2, bus7), (bus7, bus8), (bus8, bus9),
                       (bus9, bus7)]
    for fb, tb in new_connections:
        pp.create_line(net,
                       fb,
                       tb,
                       length_km=1.0,
                       std_type="NA2XS2Y 1x185 RM/25 12/20 kV")

    # get characteristics
    mg = top.create_nxgraph(net, respect_switches=False)
    characteristics = [
        "bridges", "articulation_points", "connected", "stub_buses",
        "required_bridges", "notn1_areas"
    ]
    char_dict = top.find_graph_characteristics(mg, net.ext_grid.bus,
                                               characteristics)
    bridges = char_dict["bridges"]
    articulation_points = char_dict["articulation_points"]
    connected = char_dict["connected"]
    stub_buses = char_dict["stub_buses"]
    required_bridges = char_dict["required_bridges"]
    notn1_areas = char_dict["notn1_areas"]
    assert bridges == {(3, 4), (4, 5), (4, 6), (2, 11)}
    assert articulation_points == {8, 3, 4, 2, 11}
    assert connected == {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}
    assert stub_buses == {4, 5, 6, 11, 12, 13}
    assert required_bridges == {
        4: [(3, 4)],
        5: [(3, 4), (4, 5)],
        6: [(3, 4), (4, 6)],
        11: [(2, 11)],
        12: [(2, 11)],
        13: [(2, 11)]
    }
    assert notn1_areas == {8: {9, 10}, 3: {4, 5, 6}, 2: {11, 12, 13}}
コード例 #19
0
ファイル: ieee_118_analysis.py プロジェクト: xjtu13/Grid2Op
def plot_feeder():
    net = nw.case118()
    fig, ax = plt.subplots(1, 1)
    mg = top.create_nxgraph(net, nogobuses=set(net.trafo.lv_bus.values))
    colors = sns.color_palette()
    collections = list()
    sizes = pplt.get_collection_sizes(net)
    voltage_levels = net.bus.vn_kv.unique()
    voltage_level_colors = dict(zip(voltage_levels, colors))
    legend_entries = dict()
    gens = set(net.gen.loc[:, "bus"].values)
    for area, color in zip(top.connected_components(mg), colors):
        vn_area = net.bus.loc[list(area)[0], "vn_kv"]
        color = voltage_level_colors[vn_area]
        legend_entries[vn_area] = color
        area_gens = gens - area
        other = area - gens

        collections.append(
            pplt.create_bus_collection(net,
                                       area_gens,
                                       color=color,
                                       size=sizes["bus"],
                                       zorder=11,
                                       patch_type="rect"))
        collections.append(
            pplt.create_bus_collection(net,
                                       other,
                                       color=color,
                                       size=sizes["bus"],
                                       zorder=11))
        line_ind = net.line.loc[:, "from_bus"].isin(
            area) | net.line.loc[:, "to_bus"].isin(area)
        lines = net.line.loc[line_ind].index
        collections.append(pplt.create_line_collection(net, lines,
                                                       color=color))

    eg_vn = net.bus.at[net.ext_grid.bus.values[0], "vn_kv"]
    collections.append(
        pplt.create_ext_grid_collection(net,
                                        size=sizes["ext_grid"],
                                        color=voltage_level_colors[eg_vn]))
    collections.append(
        pplt.create_trafo_collection(net, size=sizes["trafo"], zorder=1))
    pplt.draw_collections(collections, ax=ax)
    custom_legend(fig, entries=legend_entries)
    legend_entries = {"gen": "grey"}
    custom_legend(fig, entries=legend_entries, loc='center right', marker="s")
    print_info(net, fig)
    plt.show()
コード例 #20
0
def voltage_profile_to_bus_geodata(net, voltages=None):
    if voltages is None:
        if not net.converged:
            raise ValueError("no results in this pandapower network")
        voltages = net.res_bus.vm_pu

    mg =  top.create_nxgraph(net, respect_switches=True)
    first_eg = net.ext_grid.bus.values[0]
    mg.add_edges_from([(first_eg, y, {"weight": 0}) for y in net.ext_grid.bus.values[1:]])
    dist = pd.Series(nx.single_source_dijkstra_path_length(mg, first_eg))

    bgd = pd.DataFrame({"x": dist.loc[net.bus.index.values].values,
                        "y": voltages.loc[net.bus.index.values].values},
                       index=net.bus.index)
    return bgd
コード例 #21
0
def estimate_voltage_vector(net):
    """
    Function initializes the voltage vector of net with a rough estimation. All buses are set to the
    slack bus voltage. Transformer differences in magnitude and phase shifting are accounted for.
    :param net: pandapower network
    :return: pandas dataframe with estimated vm_pu and va_degree
    """
    res_bus = DataFrame(index=net.bus.index, columns=["vm_pu", "va_degree"])
    net_graph = create_nxgraph(net, include_trafos=False)
    for _, ext_grid in net.ext_grid.iterrows():
        area = list(connected_component(net_graph, ext_grid.bus))
        res_bus.vm_pu.loc[area] = ext_grid.vm_pu
        res_bus.va_degree.loc[area] = ext_grid.va_degree
    trafos = net.trafo[net.trafo.in_service == 1]
    trafo_index = trafos.index.tolist()
    while len(trafo_index):
        for tix in trafo_index:
            trafo = trafos.loc[tix]
            if notnull(res_bus.vm_pu.at[trafo.hv_bus]) and isnull(
                    res_bus.vm_pu.at[trafo.lv_bus]):
                try:
                    area = list(connected_component(net_graph, trafo.lv_bus))
                    shift = trafo.shift_degree if "shift_degree" in trafo else 0
                    ratio = (trafo.vn_hv_kv / trafo.vn_lv_kv) / (
                        net.bus.vn_kv.at[trafo.hv_bus] /
                        net.bus.vn_kv.at[trafo.lv_bus])
                    res_bus.vm_pu.loc[area] = res_bus.vm_pu.at[
                        trafo.hv_bus] * ratio
                    res_bus.va_degree.loc[area] = res_bus.va_degree.at[
                        trafo.hv_bus] - shift
                except KeyError:
                    raise UserWarning(
                        "An out-of-service bus is connected to an in-service "
                        "transformer. Please set the transformer out of service or"
                        "put the bus into service. Treat results with caution!"
                    )
                trafo_index.remove(tix)
            elif notnull(res_bus.vm_pu.at[trafo.hv_bus]):
                # parallel transformer, lv buses are already set from previous transformer
                trafo_index.remove(tix)
            if len(trafo_index) == len(trafos):
                # after the initial run we could not identify any areas correctly, it's probably a transmission grid
                # with slack on the LV bus and multiple transformers/gens. do flat init and return
                res_bus.vm_pu.loc[res_bus.vm_pu.isnull()] = 1.
                res_bus.va_degree.loc[res_bus.va_degree.isnull()] = 0.
                return res_bus
    return res_bus
コード例 #22
0
def test_json_encoding_decoding():
    net = nw.mv_oberrhein()
    net.tuple = (1, "4")
    net.mg = top.create_nxgraph(net)
    s = set(['1', 4])
    t = tuple(['2', 3])
    f = frozenset(['12', 3])
    a = np.array([1., 2.])
    d = {"a": net, "b": f}
    json_string = json.dumps([s, t, f, net, a, d], cls=PPJSONEncoder)
    s1, t1, f1, net1, a1, d1 = json.loads(json_string, cls=PPJSONDecoder)

    assert s == s1
    assert t == t1
    assert f == f1
    assert net.tuple == net1.tuple
    assert np.allclose(a, a1)

    # TODO line_geodata isn't the same since tuples inside DataFrames are converted to lists (see test_json_tuple_in_dataframe)
    assert pp.nets_equal(net, net1, exclude_elms=["line_geodata"])
    assert pp.nets_equal(d["a"], d1["a"], exclude_elms=["line_geodata"])
    assert d["b"] == d1["b"]
    assert_graphs_equal(net.mg, net1.mg)
コード例 #23
0
# Youtube Tutorial: https://www.youtube.com/watch?v=QYDp_-TX7C4
import pandapower as pp
import pandapower.plotting as pplt
import pandapower.topology as top
import pandapower.networks as nw
import matplotlib.pyplot as plt
import seaborn as sns

net = nw.mv_oberrhein()
pplt.simple_plot(net)

mg = top.create_nxgraph(net, nogobuses=set(net.trafo.lv_bus.values) | set(net.trafo.hv_bus.values))
colors = sns.color_palette()
collections = list()
sizes = pplt.get_collection_sizes(net)
for area, color in zip(top.connected_components(mg), colors):
    collections.append(pplt.create_bus_collection(net, area, color=color, size=sizes["bus"]))
    line_ind = net.line.loc[:, "from_bus"].isin(area) | net.line.loc[:, "to_bus"].isin(area)
    lines = net.line.loc[line_ind].index
    collections.append(pplt.create_line_collection(net, lines, color=color))
collections.append(pplt.create_ext_grid_collection(net, size=sizes["ext_grid"]))
pplt.draw_collections(collections)
plt.show()
コード例 #24
0
def vlevel_plotly(net, respect_switches=True, use_line_geodata=None, colors_dict=None, on_map=False,
                  projection=None, map_style='basic', figsize=1, aspectratio='auto', line_width=2,
                  bus_size=10, filename="temp-plot.html", auto_open=True):
    """
    Plots a pandapower network in plotly
    using lines/buses colors according to the voltage level they belong to.
    If no geodata is available, artificial geodata is generated. For advanced plotting see the
    tutorial

    INPUT:
        **net** - The pandapower format network. If none is provided, mv_oberrhein() will be
        plotted as an example

    OPTIONAL:
        **respect_switches** (bool, True) - Respect switches when artificial geodata is created

        **use_line_geodata** (bool, True) - defines if lines patches are based on net.line_geodata
            of the lines (True) or on net.bus_geodata of the connected buses (False)

        *colors_dict** (dict, None) - dictionary for customization of colors for each voltage level
            in the form: voltage : color

        **on_map** (bool, False) - enables using mapbox plot in plotly If provided geodata are not
            real geo-coordinates in lon/lat form, on_map will be set to False.

        **projection** (String, None) - defines a projection from which network geo-data will be
            transformed to lat-long. For each projection a string can be found at
            http://spatialreference.org/ref/epsg/

        **map_style** (str, 'basic') - enables using mapbox plot in plotly

            - 'streets'
            - 'bright'
            - 'light'
            - 'dark'
            - 'satellite'

        **figsize** (float, 1) - aspectratio is multiplied by it in order to get final image size

        **aspectratio** (tuple, 'auto') - when 'auto' it preserves original aspect ratio of the
            network geodata any custom aspectration can be given as a tuple, e.g. (1.2, 1)

        **line_width** (float, 1.0) - width of lines

        **bus_size** (float, 10.0) -  size of buses to plot.

        **filename** (str, "temp-plot.html") - filename / path to plot to. Should end on `*.html`

        **auto_open** (bool, True) - automatically open plot in browser

    OUTPUT:
        **figure** (graph_objs._figure.Figure) figure object

    """
    # getting connected componenets without consideration of trafos
    graph = create_nxgraph(net, include_trafos=False)
    vlev_buses = connected_components(graph)
    # getting unique sets of buses for each voltage level
    vlev_bus_dict = {}
    for vl_buses in vlev_buses:
        if net.bus.loc[vl_buses, 'vn_kv'].unique().shape[0] > 1:
            logger.warning('buses from the same voltage level does not have the same vn_kv !?')
        vn_kv = net.bus.loc[vl_buses, 'vn_kv'].unique()[0]
        if vlev_bus_dict.get(vn_kv):
            vlev_bus_dict[vn_kv].update(vl_buses)
        else:
            vlev_bus_dict[vn_kv] = vl_buses

    # create a default colormap for voltage levels
    nvlevs = len(vlev_bus_dict)
    colors = get_plotly_color_palette(nvlevs)
    colors_dict = colors_dict or dict(zip(vlev_bus_dict.keys(), colors))
    bus_groups = [(buses, colors_dict[vlev], f"{vlev} kV") for vlev, buses in vlev_bus_dict.items()]

    return _draw_colored_bus_groups_plotly(
        net, bus_groups, respect_switches=respect_switches,
        use_line_geodata=use_line_geodata, on_map=on_map, projection=projection,
        map_style=map_style, figsize=figsize, aspectratio=aspectratio, line_width=line_width,
        bus_size=bus_size, filename=filename, auto_open=auto_open)
コード例 #25
0
def test_branch_impedance_unit():
    net = pp.create_empty_network()
    with pytest.raises(ValueError) as exception_info:
        mg = create_nxgraph(net, branch_impedance_unit="p.u.")
    assert str(exception_info.value
               ) == "branch impedance unit can be either 'ohm' or 'pu'"
コード例 #26
0
def disconnected_elements(net):
    """
    Checks, if there are network sections without a connection to an ext_grid. Returns all network
    elements in these sections, that are in service. Elements belonging to the same disconnected
    networks section are grouped in lists (e.g. disconnected lines: [[1, 2, 3], [4, 5]]
    means, that lines 1, 2 and 3 are in one disconncted section but are connected to each other.
    The same stands for lines 4, 5.)

     INPUT:
        **net** (pandapowerNet)         - pandapower network

     OUTPUT:
        **disc_elements** (dict)        - list that contains all network elements, without a
                                          connection to an ext_grid.

                                          format: {'disconnected buses'   : bus_indices,
                                                   'disconnected switches' : switch_indices,
                                                   'disconnected lines'    : line_indices,
                                                   'disconnected trafos'   : trafo_indices
                                                   'disconnected loads'    : load_indices,
                                                   'disconnected gens'     : gen_indices,
                                                   'disconnected sgens'    : sgen_indices}

    """
    import pandapower.topology as top
    mg = top.create_nxgraph(net)
    sections = top.connected_components(mg)
    disc_elements = []

    for section in sections:
        section_dict = {}

        if not section & set(net.ext_grid.bus[net.ext_grid.in_service]).union(
                net.gen.bus[net.gen.slack & net.gen.in_service]) and any(
                net.bus.in_service.loc[section]):
            section_buses = list(net.bus[net.bus.index.isin(section)
                                         & (net.bus.in_service == True)].index)
            section_switches = list(net.switch[net.switch.bus.isin(section_buses)].index)
            section_lines = list(get_connected_elements(net, 'line', section_buses,
                                                        respect_switches=True,
                                                        respect_in_service=True))
            section_trafos = list(get_connected_elements(net, 'trafo', section_buses,
                                                         respect_switches=True,
                                                         respect_in_service=True))

            section_trafos3w = list(get_connected_elements(net, 'trafo3w', section_buses,
                                                           respect_switches=True,
                                                           respect_in_service=True))
            section_gens = list(net.gen[net.gen.bus.isin(section)
                                        & (net.gen.in_service == True)].index)
            section_sgens = list(net.sgen[net.sgen.bus.isin(section)
                                          & (net.sgen.in_service == True)].index)
            section_loads = list(net.load[net.load.bus.isin(section)
                                          & (net.load.in_service == True)].index)

            if section_buses:
                section_dict['buses'] = section_buses
            if section_switches:
                section_dict['switches'] = section_switches
            if section_lines:
                section_dict['lines'] = section_lines
            if section_trafos:
                section_dict['trafos'] = section_trafos
            if section_trafos3w:
                section_dict['trafos3w'] = section_trafos3w
            if section_loads:
                section_dict['loads'] = section_loads
            if section_gens:
                section_dict['gens'] = section_gens
            if section_sgens:
                section_dict['sgens'] = section_sgens

            if any(section_dict.values()):
                disc_elements.append(section_dict)

    open_trafo_switches = net.switch[(net.switch.et == 't') & (net.switch.closed == 0)]
    isolated_trafos = set(
        (open_trafo_switches.groupby("element").count().query("bus > 1").index))
    isolated_trafos_is = isolated_trafos.intersection((set(net.trafo[net.trafo.in_service == True]
                                                           .index)))
    if isolated_trafos_is:
        disc_elements.append({'isolated_trafos': list(isolated_trafos_is)})

    isolated_trafos3w = set(
        (open_trafo_switches.groupby("element").count().query("bus > 2").index))
    isolated_trafos3w_is = isolated_trafos3w.intersection((
        set(net.trafo[net.trafo.in_service == True].index)))
    if isolated_trafos3w_is:
        disc_elements.append({'isolated_trafos3w': list(isolated_trafos3w_is)})

    if disc_elements:
        return disc_elements
コード例 #27
0
ファイル: mv_oberrhein.py プロジェクト: zypher22/pandapower
def mv_oberrhein(scenario="load",
                 cosphi_load=0.98,
                 cosphi_pv=1.0,
                 include_substations=False,
                 separation_by_sub=False):
    """
    Loads the Oberrhein network, a generic 20 kV network serviced by two 25 MVA HV/MV transformer
    stations. The network supplies 141 MV/LV substations and 6 MV loads through four MV feeders.
    The network layout is meshed, but the network is operated as a radial network with 6 open
    sectioning points.

    The network can be loaded with two different worst case scenarios for load and generation,
    which are defined by scaling factors for loads / generators as well as tap positions of the
    HV/MV transformers. These worst case scenarios are a good starting point for working with this
    network, but you are of course free to parametrize the network for your use case.

    The network also includes geographical information of lines and buses for plotting.

    OPTIONAL:
        **scenario** - (str, "load"): defines the scaling for load and generation

                - "load": high load scenario, load = 0.6 / sgen = 0, trafo taps [-2, -3]
                - "generation": high feed-in scenario: load = 0.1, generation = 0.8, trafo taps [0, 0]

        **cosphi_load** - (str, 0.98): cosine(phi) of the loads

        **cosphi_sgen** - (str, 1.0): cosine(phi) of the static generators

        **include_substations** - (bool, False): if True, the transformers of the MV/LV level are
        modelled, otherwise the loads representing the LV networks are connected directly to the
        MV node
        
        **separation_by_sub** - (bool, False): if True, the network gets separated into two 
        sections, referring to both substations

    OUTPUT:
         **net** - pandapower network
         
         **net0, net1** - both sections of the pandapower network

    EXAMPLE:

        ``import pandapower.networks``
    
        ``net = pandapower.networks.mv_oberrhein("generation")``
    
        or with separation
    
        ``net0, net1 = pandapower.networks.mv_oberrhein(separation_by_sub=True)``
    """
    if include_substations:
        net = pp.from_json(
            os.path.join(pp_dir, "networks", "mv_oberrhein_substations.json"))
    else:
        net = pp.from_json(
            os.path.join(pp_dir, "networks", "mv_oberrhein.json"))
    net.load.q_mvar = np.tan(np.arccos(cosphi_load)) * net.load.p_mw
    net.sgen.q_mvar = np.tan(np.arccos(cosphi_pv)) * net.sgen.p_mw

    hv_trafos = net.trafo[net.trafo.sn_mva > 1].index
    if scenario == "load":
        net.load.scaling = 0.6
        net.sgen.scaling = 0.0
        net.trafo.tap_pos.loc[hv_trafos] = [-2, -3]
    elif scenario == "generation":
        net.load.scaling = 0.1
        net.sgen.scaling = 0.8
        net.trafo.tap_pos.loc[hv_trafos] = [0, 0]
    else:
        raise ValueError("Unknown scenario %s - chose 'load' or 'generation'" %
                         scenario)

    if separation_by_sub == True:
        # creating multigraph
        mg = top.create_nxgraph(net)
        # clustering connected buses
        zones = [list(area) for area in top.connected_components(mg)]
        net1 = pp.select_subnet(net,
                                buses=zones[0],
                                include_switch_buses=False,
                                include_results=True,
                                keep_everything_else=True)
        net0 = pp.select_subnet(net,
                                buses=zones[1],
                                include_switch_buses=False,
                                include_results=True,
                                keep_everything_else=True)

        pp.runpp(net0)
        pp.runpp(net1)
        return net0, net1

    pp.runpp(net)
    return net
コード例 #28
0
    trafo_traces = create_trafo_trace(net, color='gray', width=line_width * 2)

    draw_traces(line_traces + trafo_traces + bus_traces, showlegend=True,
                aspectratio=aspectratio, on_map=on_map, map_style=map_style, figsize=figsize)
    
if __name__ == '__main__':
    from pandapower.plotting.plotly import simple_plotly
    from pandapower.networks import mv_oberrhein
    from pandapower import runpp
    net = mv_oberrhein()
    vlevel_plotly(net)
    runpp(net)
    line_width=2
    bus_size=10
    use_line_geodata = None
    graph = create_nxgraph(net, include_trafos=False)
    vlev_buses = connected_components(graph)
    respect_switches = True
    
    # getting unique sets of buses for each voltage level
    vlev_bus_dict = {}
    for vl_buses in vlev_buses:
        if net.bus.loc[vl_buses, 'vn_kv'].unique().shape[0] > 1:
            logger.warning('buses from the same voltage level does not have the same vn_kv !?')
        vn_kv = net.bus.loc[vl_buses, 'vn_kv'].unique()[0]
        if vlev_bus_dict.get(vn_kv):
            vlev_bus_dict[vn_kv].update(vl_buses)
        else:
            vlev_bus_dict[vn_kv] = vl_buses
            
    # create a default colormap for voltage levels
コード例 #29
0
            "y": voltages.loc[net.bus.index.values].values
        },
        index=net.bus.index)
    return bgd


if __name__ == "__main__":
    import pandapower as pp
    import pandapower.networks as nw
    import pandas as pd
    import networkx as nx
    import plotting

    net = nw.mv_oberrhein()
    pp.runpp(net)
    mg = top.create_nxgraph(net, respect_switches=True)
    feeders = list(
        top.connected_components(mg, notravbuses=set(net.trafo.lv_bus.values)))
    lines_with_open_switches = set(
        net.switch.query("not closed and et == 'l'").element.values)

    fig, axs = plt.subplots(2)
    for bgd, ax in zip(
        [net.bus_geodata, voltage_profile_to_bus_geodata(net)], axs):
        for color, f in zip(["C0", "C1", "C2", "C3"], feeders):
            l = set(net.line.index[net.line.from_bus.isin(
                f)]) - lines_with_open_switches
            c = plotting.create_line_collection(net,
                                                lines=l,
                                                use_bus_geodata=True,
                                                color=color,
コード例 #30
0
def vlevel_plotly(net, respect_switches=True, use_line_geodata=None, colors_dict=None, on_map=False,
                  projection=None, map_style='basic', figsize=1, aspectratio='auto', line_width=2,
                  bus_size=10):
    """
    Plots a pandapower network in plotly
    using lines/buses colors according to the voltage level they belong to.
    If no geodata is available, artificial geodata is generated. For advanced plotting see the tutorial

    INPUT:
        **net** - The pandapower format network. If none is provided, mv_oberrhein() will be
        plotted as an example

    OPTIONAL:
        **respect_switches** (bool, True) - Respect switches when artificial geodata is created

        **use_line_geodata** (bool, True) - defines if lines patches are based on net.line_geodata of the lines (True)
        or on net.bus_geodata of the connected buses (False)

        *colors_dict** (dict, None) - dictionary for customization of colors for each voltage level in the form:
        voltage_kv : color

        **on_map** (bool, False) - enables using mapbox plot in plotly If provided geodata are not real
        geo-coordinates in lon/lat form, on_map will be set to False.

        **projection** (String, None) - defines a projection from which network geo-data will be transformed to
        lat-long. For each projection a string can be found at http://spatialreference.org/ref/epsg/

        **map_style** (str, 'basic') - enables using mapbox plot in plotly

            - 'streets'
            - 'bright'
            - 'light'
            - 'dark'
            - 'satellite'

        **figsize** (float, 1) - aspectratio is multiplied by it in order to get final image size

        **aspectratio** (tuple, 'auto') - when 'auto' it preserves original aspect ratio of the network geodata
        any custom aspectration can be given as a tuple, e.g. (1.2, 1)

        **line_width** (float, 1.0) - width of lines

        **bus_size** (float, 10.0) -  size of buses to plot.

    """
    version_check()
    # create geocoord if none are available
    if 'line_geodata' not in net:
        net.line_geodata = pd.DataFrame(columns=['coords'])
    if 'bus_geodata' not in net:
        net.bus_geodata = pd.DataFrame(columns=["x", "y"])
    if len(net.line_geodata) == 0 and len(net.bus_geodata) == 0:
        logger.warning("No or insufficient geodata available --> Creating artificial coordinates." +
                       " This may take some time")
        create_generic_coordinates(net, respect_switches=respect_switches)
        if on_map:
            logger.warning("Map plots not available with artificial coordinates and will be disabled!")
            on_map = False

    # check if geodata are real geographycal lat/lon coordinates using geopy
    if on_map and projection is not None:
        geo_data_to_latlong(net, projection=projection)

    # if bus geodata is available, but no line geodata
    if use_line_geodata is None:
        use_line_geodata = False if len(net.line_geodata) == 0 else True
    elif use_line_geodata and len(net.line_geodata) == 0:
        logger.warning("No or insufficient line geodata available --> only bus geodata will be used.")
        use_line_geodata = False

    # getting connected componenets without consideration of trafos
    graph = create_nxgraph(net, include_trafos=False)
    vlev_buses = connected_components(graph)
    # getting unique sets of buses for each voltage level
    vlev_bus_dict = {}
    for vl_buses in vlev_buses:
        if net.bus.loc[vl_buses, 'vn_kv'].unique().shape[0] > 1:
            logger.warning('buses from the same voltage level does not have the same vn_kv !?')
        vn_kv = net.bus.loc[vl_buses, 'vn_kv'].unique()[0]
        if vlev_bus_dict.get(vn_kv):
            vlev_bus_dict[vn_kv].update(vl_buses)
        else:
            vlev_bus_dict[vn_kv] = vl_buses

    # create a default colormap for voltage levels
    nvlevs = len(vlev_bus_dict)
    colors = get_plotly_color_palette(nvlevs)
    colors_dict = dict(zip(vlev_bus_dict.keys(), colors))

    # creating traces for buses and lines for each voltage level
    bus_traces = []
    line_traces = []
    for vn_kv, buses_vl in vlev_bus_dict.items():

        vlev_color = colors_dict[vn_kv]
        bus_trace_vlev = create_bus_trace(net, buses=buses_vl, size=bus_size, legendgroup=str(vn_kv),
                                          color=vlev_color, trace_name='buses {0} kV'.format(vn_kv))
        if bus_trace_vlev is not None:
            bus_traces += bus_trace_vlev

        vlev_lines = net.line[net.line.from_bus.isin(buses_vl) & net.line.to_bus.isin(buses_vl)].index.tolist()
        line_trace_vlev = create_line_trace(net, lines=vlev_lines, use_line_geodata=use_line_geodata,
                                            respect_switches=respect_switches, legendgroup=str(vn_kv),
                                            color=vlev_color, width=line_width, trace_name='lines {0} kV'.format(vn_kv))
        if line_trace_vlev is not None:
            line_traces += line_trace_vlev

    trafo_traces = create_trafo_trace(net, color='gray', width=line_width * 2)

    draw_traces(line_traces + trafo_traces + bus_traces, showlegend=True,
                aspectratio=aspectratio, on_map=on_map, map_style=map_style, figsize=figsize)