コード例 #1
0
def _marker(
    locs_coordinates,
    location,
    carrier,
    tech,
    prod,
    scale_factor,
    techs_colors,
    is_initial_timestep,
    add_legend,
    name,
):
    # Example: "Region1: 3552.65 of pipe_import (gas)"
    hover_info = "%s: %.2f of %s (%s)" % (location, prod, tech, carrier)

    marker_dict = dict(
        visible=False,
        hoverinfo="text",
        text=hover_info,
        mode="markers",
        marker=dict(
            symbol="circle-dot",
            opacity=0.6,
            size=prod * scale_factor + 1,
            color=techs_colors[tech],
        ),
        legendgroup=tech,
        showlegend=False,
    )

    marker_legend = dict(
        visible=False,
        hoverinfo="text",
        text=hover_info,
        mode="markers",
        marker=dict(
            symbol="circle-dot", opacity=0.6, size=10, color=techs_colors[tech],
        ),
        legendgroup=tech,
        name=break_name(name, 18),
    )

    if set(locs_coordinates.index) == set(["x", "y"]):
        h_coord, v_coord = "x", "y"
    elif set(locs_coordinates.index) == set(["lon", "lat"]):
        h_coord, v_coord = "lon", "lat"

    marker_dict[h_coord] = [locs_coordinates[location][h_coord]]
    marker_dict[v_coord] = [locs_coordinates[location][v_coord]]
    marker_legend[h_coord] = [None]
    marker_legend[v_coord] = [None]

    if is_initial_timestep:
        # plot only the first timestep data when the chart is initialized
        marker_dict["visible"] = True
        marker_legend["visible"] = True
    if add_legend:
        return [marker_dict, marker_legend]
    else:
        return [marker_dict]
コード例 #2
0
def _line(
    locs_coordinates,
    transmission_type,
    to_location,
    from_location,
    carrier,
    tech,
    prod,
    scale_factor,
    techs_colors,
    is_initial_timestep,
    add_legend,
    name,
):
    # e.g. "Region1->Region2: 256.54 by gas_transmission (gas)"
    hover_info = "%s->%s: %.2f by %s (%s)" % (
        from_location,
        to_location,
        prod,
        transmission_type,
        carrier,
    )

    line = dict(
        visible=False,
        mode="lines",
        hoverinfo="text",
        text="",
        line=dict(width=prod * scale_factor + 1, color=techs_colors[transmission_type]),
        legendgroup=transmission_type,
        opacity=0.6,
        showlegend=False,
    )

    line_legend = dict(
        visible=False,
        mode="lines",
        hoverinfo="text",
        text="",
        line=dict(width=10, color=techs_colors[transmission_type]),
        legendgroup=transmission_type,
        name=break_name(name, 18),
        opacity=0.6,
    )

    line_info_marker = dict(
        visible=False,
        mode="markers",
        hoverinfo="text",
        text=hover_info,
        marker=dict(symbol="square", opacity=0, color=techs_colors[transmission_type]),
        legendgroup=transmission_type,
        name=tech,
        showlegend=False,
    )

    if set(locs_coordinates.index) == set(["x", "y"]):
        h_coord, v_coord = "x", "y"
    elif set(locs_coordinates.index) == set(["lon", "lat"]):
        h_coord, v_coord = "lon", "lat"

    line[h_coord] = [
        locs_coordinates[from_location][h_coord],
        locs_coordinates[to_location][h_coord],
    ]
    line[v_coord] = [
        locs_coordinates[from_location][v_coord],
        locs_coordinates[to_location][v_coord],
    ]
    line_legend[h_coord] = [None]
    line_legend[v_coord] = [None]
    line_info_marker[h_coord] = [
        (1 / 2)
        * (
            locs_coordinates[from_location][h_coord]
            + locs_coordinates[to_location][h_coord]
        )
    ]
    line_info_marker[v_coord] = [
        (1 / 2)
        * (
            locs_coordinates[from_location][v_coord]
            + locs_coordinates[to_location][v_coord]
        )
    ]

    if is_initial_timestep:
        # plot only the first timestep data when the chart is initialized
        line["visible"] = True
        line_legend["visible"] = True
        line_info_marker["visible"] = True
    if add_legend:
        return [line, line_legend, line_info_marker]
    else:
        return [line, line_info_marker]
コード例 #3
0
ファイル: timeseries.py プロジェクト: wroldwiedbwe/calliope
def _get_var_data(var, model, dataset, visible, subset, sum_dims, squeeze):
    """
    Get variable data from model_data and use it to populate a list with Plotly plots
    """
    carriers = list(dataset.carriers.values)

    # list to populate
    data = []

    # Clustered data does not get plotted on a datetime axis
    if "clusters" in dataset.dims:
        clusters = dataset.timestep_cluster.to_pandas()
        cluster_groups = clusters.groupby(clusters).groups
        # Add an extra timestep at the end of each cluster, so we can break
        # scatter lines with a NaN between each cluster
        dummy_timestep = lambda x: pd.to_datetime(x[-1] + pd.Timedelta(100, unit="ns"))
        reindexing_timesteps = np.concatenate(
            [
                group_timesteps.append(
                    pd.Index([dummy_timestep(group_timesteps)])
                ).values
                for group_timesteps in cluster_groups.values()
            ]
        )
        timesteps = pd.Index(reindexing_timesteps).values.astype(str)
        # replace dummy timestep with NaN
        timesteps[pd.Index(reindexing_timesteps).nanosecond == 100] = np.nan
        timesteps = pd.to_datetime(timesteps, errors="ignore")
        if var == "storage_inter_cluster":
            datesteps = pd.to_datetime(model._model_data.datesteps.values)
    else:
        timesteps = pd.to_datetime(model._model_data.timesteps.values)

    def _get_reindexed_array(array, index=None, fillna=None):
        if index is None:
            index = ["nodes", "techs"]
        # reindexing data means that DataArrays have the same values in nodes and techs
        reindexer = {k: sorted(dataset[k].values) for k in index}
        formatted_array = model.get_formatted_array(array)
        if fillna is not None:
            return formatted_array.reindex(**reindexer).fillna(fillna)
        else:
            return formatted_array.reindex(**reindexer)

    def _get_y_vals(array, ignore_clustering=False):
        if "clusters" in dataset.dims and not ignore_clustering:
            return array.to_pandas().reindex(reindexing_timesteps).values
        else:
            return array.values

    if hasattr(model, "results"):
        array_prod = _get_reindexed_array(
            "carrier_prod", index=["nodes", "techs", "carriers"], fillna=0
        )
        array_con = _get_reindexed_array(
            "carrier_con", index=["nodes", "techs", "carriers"], fillna=0
        )
        if "resource_con" in dataset.data_vars:
            resource_con = _get_reindexed_array("resource_con", fillna=0)
        else:
            resource_con = 0

    # carrier flow is a combination of carrier_prod, carrier_con and
    # carrier_export for a given energy carrier
    if var in carriers:
        array_flow = (
            array_prod.loc[dict(carriers=var)] + array_con.loc[dict(carriers=var)]
        )
        if "carrier_export" in dataset:
            export_flow = subset_sum_squeeze(
                _get_reindexed_array(
                    "carrier_export", index=["nodes", "techs", "carriers"], fillna=0
                ).loc[dict(carriers=var)],
                subset,
                sum_dims,
                squeeze,
            )
        if "unmet_demand" in dataset:
            unmet_flow = subset_sum_squeeze(
                _get_reindexed_array(
                    "unmet_demand", index=["nodes", "carriers"], fillna=0
                ).loc[dict(carriers=var)],
                subset,
                sum_dims,
                squeeze=False,
            )

    # array flow for storage tracks stored energy. carrier_flow is
    # charge/discharge (including resource consumed for supply_plus techs)
    elif var == "storage":
        array_flow = _get_reindexed_array("storage")

        if "resource_eff" in dataset.data_vars:
            resource_eff = _get_reindexed_array("resource_eff", fillna=1)
        else:
            resource_eff = 1

        charge = subset_sum_squeeze(
            -array_con.sum("carriers") + resource_con * resource_eff,
            subset,
            sum_dims,
            squeeze=False,
        )
        discharge = -subset_sum_squeeze(
            array_prod.sum("carriers"), subset, sum_dims, squeeze=False
        )

    elif var == "resource_con":
        array_flow = resource_con

    else:
        array_flow = _get_reindexed_array(var)

    array_flow = subset_sum_squeeze(array_flow, subset, sum_dims, squeeze)

    err_details = " (variable: `{}`, subset: `{}`, sum_dims: `{}`.".format(
        var, subset, sum_dims
    )

    if "timesteps" not in array_flow.dims and "datesteps" not in array_flow.dims:
        raise ValueError(
            "`timesteps` not in plotting data, cannot proceed" + err_details
        )

    if len(array_flow.dims) > 2:
        if "costs" in array_flow.dims:
            err_details = err_details + (
                " Try subsetting to select a cost class, "
                "e.g. subset={'costs': ['monetary']}."
            )
        raise ValueError(
            "Too many dimensions to plot: `{}`".format(array_flow.dims) + err_details
        )

    # If techs not given as a subset (implying a desire to order manually),
    # sort techs such that those varying output least are at the bottom of the stack
    if subset.get("techs", None) or var == "storage_inter_cluster":
        sorted_techs = array_flow.techs.values
    else:
        sorted_techs = [
            array_flow.techs.values[i]
            for i in array_flow.var(dim="timesteps").argsort()
        ]

    # for tech in array_flow.techs.values:
    for tech in sorted_techs:
        tech_dict = {"techs": tech}
        if not array_flow.loc[tech_dict].sum():
            continue
        # We allow transmission tech information to show up in some cases
        if (
            "techs_transmission" in dataset
            and tech in dataset.techs_transmission.values
        ):
            base_tech = "transmission"
            color = dataset.colors.loc[{"techs": tech.split(":")[0]}].item()
            name = break_name(
                dataset.names.loc[{"techs": tech.split(":")[0]}].item(), 30
            )
            if var in carriers:
                continue  # no transmission in carrier flow
        else:
            base_tech = dataset.inheritance.loc[tech_dict].item().split(".")[0]
            color = dataset.colors.loc[tech_dict].item()
            name = break_name(dataset.names.loc[tech_dict].item(), 30)

        if base_tech == "demand":
            # Always insert demand at position 0 in the list, to make
            # sure it appears on top in the legend
            data.insert(
                0,
                go.Scatter(
                    x=timesteps,
                    y=_get_y_vals(-array_flow.loc[tech_dict]),
                    visible=visible,
                    line=dict(color=color),
                    name=name,
                    legendgroup=tech,
                ),
            )

        elif var == "storage":
            # stored energy as scatter, carrier/resource prod/con as stacked bar
            data.insert(
                0,
                go.Scatter(
                    x=timesteps,
                    y=_get_y_vals(array_flow.loc[tech_dict]),
                    visible=visible,
                    line=dict(color=color),
                    mode="lines",
                    name=name + " stored energy",
                    showlegend=False,
                    text=tech + " stored energy",
                    hoverinfo="x+y+text",
                    legendgroup=tech,
                ),
            )
            data.append(
                go.Bar(
                    x=timesteps,
                    y=_get_y_vals(charge.loc[tech_dict]),
                    visible=visible,
                    name=name,
                    marker=dict(color=color),
                    legendgroup=tech,
                    text=tech + " charge",
                    hoverinfo="x+y+text",
                )
            )
            data.append(
                go.Bar(
                    x=timesteps,
                    y=_get_y_vals(discharge.loc[tech_dict]),
                    visible=visible,
                    name=name,
                    marker=dict(color=color, opacity=0.8),
                    legendgroup=tech,
                    text=tech + " discharge",
                    hoverinfo="x+y+text",
                    showlegend=False,
                )
            )

        elif var == "storage_inter_cluster":
            data.append(
                go.Scatter(
                    x=datesteps,
                    y=_get_y_vals(array_flow.loc[tech_dict], ignore_clustering=True),
                    visible=visible,
                    line=dict(color=color),
                    mode="lines",
                    name=name,
                    showlegend=False,
                    text=tech,
                    hoverinfo="x+y+text",
                    legendgroup=tech,
                )
            )

        else:
            data.append(
                go.Bar(
                    x=timesteps,
                    y=_get_y_vals(array_flow.loc[tech_dict]),
                    visible=visible,
                    name=name,
                    legendgroup=tech,
                    marker=dict(color=color),
                )
            )

        if (
            var in carriers
            and "carrier_export" in dataset
            and export_flow.loc[tech_dict].sum()
        ):
            data.append(
                go.Bar(
                    x=timesteps,
                    y=_get_y_vals(-export_flow.loc[tech_dict]),
                    visible=visible,
                    name=name + " export",
                    legendgroup=tech,
                    marker=dict(color=hex_to_rgba(color, 0.5)),
                )
            )

    if var in carriers and "unmet_demand" in dataset:
        data.append(
            go.Bar(
                x=timesteps,
                y=_get_y_vals(unmet_flow),
                visible=visible,
                name="Unmet " + var + " demand",
                legendgroup="unmet_demand",
                marker=dict(color="grey"),
            )
        )

    return data
コード例 #4
0
ファイル: transmission.py プロジェクト: zenshuo100/calliope
def plot_transmission(model, mapbox_access_token=None, **kwargs):
    """
    Parameters
    ----------
    mapbox_access_token : str, optional
        If given and a valid Mapbox API key, a Mapbox map is drawn
        for lat-lon coordinates, else (by default), a more simple
        built-in map.

    """
    try:
        coordinates = model._model_data.loc_coordinates.sortby("locs")
    except AttributeError:
        raise ValueError(
            "Model does not define location coordinates "
            "- no transmission plotting possible."
        )

    colors = model._model_data.colors
    names = model._model_data.names

    plot_width = 1000

    if hasattr(model, "results"):
        energy_cap = _get_data(model, "energy_cap")
        carrier_prod = _get_data(
            model, "carrier_prod", sum_dims=["timesteps", "carriers"]
        )
        carrier_con = _get_data(
            model, "carrier_con", sum_dims=["timesteps", "carriers"]
        )
        energy_flow = carrier_con.fillna(0) + carrier_prod.fillna(0)
    else:
        energy_cap = _get_data(model, "energy_cap_max")
        energy_flow = energy_cap.copy()
        energy_flow.loc[dict()] = 0

    if sorted(coordinates.coordinates.values) == ["lat", "lon"]:
        h_coord, v_coord = ("lat", "lon")
        if mapbox_access_token:
            scatter_type = "scattermapbox"
            layout_dict = dict(
                mapbox=dict(
                    accesstoken=mapbox_access_token,
                    center=_get_centre(coordinates),
                    zoom=_get_zoom(coordinates, plot_width),
                    style="light",
                )
            )
        else:
            scatter_type = "scattergeo"
            layout_dict = dict(
                geo=dict(
                    scope="world",
                    projection=dict(type="mercator", scale=1),
                    showland=True,
                    showcountries=True,
                    showsubunits=True,
                    showocean=True,
                    showrivers=True,
                    showlakes=True,
                    lonaxis=dict(range=get_range(coordinates, "lon", 0.1)),
                    lataxis=dict(range=get_range(coordinates, "lat", 0.1)),
                    resolution=50,
                    landcolor="rgba(240, 240, 240, 0.8)",
                    oceancolor="#aec6cf",
                    subunitcolor="blue",
                    countrycolor="green",
                    countrywidth=0.5,
                    subunitwidth=0.5,
                )
            )
    else:
        h_coord, v_coord = ("x", "y")
        scatter_type = "scatter"
        layout_dict = dict()

    mid_edge_scatter_dict = {
        "type": scatter_type,
        "showlegend": False,
        "mode": "markers",
        "hoverinfo": "text",
        "opacity": 0,
    }

    edge_scatter_dict = {
        "type": scatter_type,
        "mode": "lines",
        "hoverinfo": "none",
        "opacity": 0.8,
    }

    data = []

    for tech in sorted(energy_cap.techs.values):
        per_tech_mid_edge_dict = mid_edge_scatter_dict.copy()
        per_tech_mid_edge_dict = {
            **mid_edge_scatter_dict,
            **{
                h_coord: _fill_scatter(
                    coordinates, energy_cap, "mid_edge", h_coord, tech
                ),
                v_coord: _fill_scatter(
                    coordinates, energy_cap, "mid_edge", v_coord, tech
                ),
                "text": _fill_scatter(
                    coordinates, energy_cap, "mid_edge", "text", tech
                ),
                "legendgroup": tech,
                "marker": {"color": colors.loc[dict(techs=tech)].item()},
            },
        }

        h_edge = _fill_scatter(coordinates, energy_cap, "edge", h_coord, tech)
        v_edge = _fill_scatter(coordinates, energy_cap, "edge", v_coord, tech)
        showlegend = True
        for i in range(len(h_edge)):
            data.append(
                {
                    **edge_scatter_dict,
                    **{
                        h_coord: h_edge[i],
                        v_coord: v_edge[i],
                        "showlegend": showlegend,
                        "legendgroup": tech,
                        "name": break_name(names.loc[dict(techs=tech)].item(), 30),
                        "line": {"color": colors.loc[dict(techs=tech)].item()},
                    },
                }
            )
            showlegend = False
        data.append(per_tech_mid_edge_dict)

    node_scatter_dict = {
        h_coord: [
            coordinates.loc[dict(locs=loc, coordinates=h_coord)].item()
            for loc in coordinates.locs
        ],
        v_coord: [
            coordinates.loc[dict(locs=loc, coordinates=v_coord)].item()
            for loc in coordinates.locs
        ],
        "text": [loc.item() for loc in coordinates.locs],
        "name": "Locations",
        "type": scatter_type,
        "legendgroup": "locations",
        "mode": "markers",
        "hoverinfo": "text",
        "marker": {"symbol": "square", "size": 8, "color": "grey"},
    }

    data.append(node_scatter_dict)

    layout_dict.update(
        dict(
            width=plot_width,
            title=model.model_config["name"],
            autosize=True,
            hovermode="closest",
            showlegend=True,
        )
    )

    if kwargs.get("html_only", False):
        del layout_dict["title"]
        del layout_dict["width"]

    return data, layout_dict
コード例 #5
0
def _get_var_data(
    cap, model, dataset, visible, subset, sum_dims, squeeze, locations, orientation
):
    if "systemwide" in cap:
        array_cap = subset_sum_squeeze(dataset[cap], subset)
        if "costs" in array_cap.dims and len(array_cap["costs"]) == 1:
            array_cap = array_cap.squeeze("costs")
        elif "costs" in array_cap.dims and len(array_cap["costs"]) > 1:
            raise ValueError(
                "Cannot plot {} without subsetting to pick one cost type "
                "of interest".format(cap)
            )
        if "carriers" not in subset.keys():
            array_cap = array_cap.sortby("carriers")

    else:
        array_cap = model.get_formatted_array(cap).reindex(locs=locations)
        array_cap = subset_sum_squeeze(array_cap, subset, sum_dims, squeeze)

    if len(array_cap.dims) > 2:
        raise ValueError(
            "Maximum two dimensions allowed for plotting capacity, but {} "
            "given as dimensions for {}".format(array_cap.dims, cap)
        )

    if "techs" not in array_cap.dims:
        raise ValueError("Cannot plot capacity without `techs` in dimensions")

    elif "techs" not in subset.keys():
        array_cap = array_cap.sortby("techs")

    data = []

    for tech in array_cap.techs.values:
        if tech not in dataset.techs.values:
            continue

        if (
            "techs_transmission" in dataset
            and tech in dataset.techs_transmission.values
        ):
            continue
        else:
            base_tech = dataset.inheritance.loc[{"techs": tech}].item().split(".")[0]

        if base_tech in "demand":
            continue

        if array_cap.loc[{"techs": tech}].sum() > 0:
            x = array_cap.loc[{"techs": tech}].values
            name = break_name(model._model_data.names.loc[{"techs": tech}].item(), 30)
            if "systemwide" in cap:
                y = natsorted(array_cap.carriers.values)
            else:
                if "locs" in array_cap.dims:
                    y = natsorted(array_cap.locs.values)
                else:  # Single location
                    y = [array_cap.locs.values]

            if orientation == "v":
                x, y = y, x  # Flip axes
                hoverinfo = "y+name"
            else:
                hoverinfo = "x+name"
                x, y = x[::-1], y[::-1]  # Make sure that sorting is from bottom down

            data.append(
                go.Bar(
                    x=x,
                    y=y,
                    visible=visible,
                    name=name,
                    legendgroup=tech,
                    text=tech,
                    hoverinfo=hoverinfo,
                    marker=dict(
                        color=model._model_data.colors.loc[{"techs": tech}].item()
                    ),
                    orientation=orientation,
                )
            )

    return data