Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve flexibility of map plots #199

Merged
merged 7 commits into from
Jan 6, 2021
7 changes: 4 additions & 3 deletions postreise/analyze/transmission/utilization.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ def _flag(statistics, utilname, thresh, uflagname):

def generate_cong_stats(pf, grid_branch, util=None, thresh=None):
"""Generates congestion/utilization statistics from powerflow data (WECC congestion
reports' analyses are the inspiration for these analyses and are the source of the default parameters).
reports' analyses are the inspiration for these analyses and are the source of the
default parameters).

:param pandas.DataFrame pf: power flow data frame
:param pandas.DataFrame grid_branch: grid.branch branch info
Expand All @@ -56,8 +57,8 @@ def generate_cong_stats(pf, grid_branch, util=None, thresh=None):
:param list thresh: threshold for proportion time, for flag level 1, 2, 3. Default
values are values used by WECC: 0.5, 0.2, 0.05.
:return: (*pandas.DataFrame*) -- congestion statistics.
*'per_util1'*,*'per_util2'*, *'per_util3'*, *'u1flag'*,*'u2flag'*,
*'u3flag'*,*'sumflag'*, *'risk'*.
*'per_util1'*, *'per_util2'*, *'per_util3'*, *'u1flag'*, *'u2flag'*,
*'u3flag'*, *'sumflag'*, *'bind'*, *'risk'*.
"""

if util is None:
Expand Down
46 changes: 6 additions & 40 deletions postreise/plot/plot_carbon_map.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,49 +5,15 @@
from bokeh.plotting import figure
from bokeh.sampledata import us_states
from bokeh.tile_providers import Vendors, get_provider
from pyproj import Transformer

from postreise.plot.projection_helpers import project_bus

# make default states list, lower 48 only
default_states_dict = us_states.data.copy()
del default_states_dict["HI"]
del default_states_dict["AK"]
del default_states_dict["DC"]
default_states_list = list(default_states_dict.keys())
from postreise.plot.projection_helpers import project_borders, project_bus

# breakthrough energy (be) color names
be_purple = "#8B36FF"
be_green = "#78D911"
be_red = "#FF8563"


def get_borders(us_states_dat, state_list=None):
"""Prepares US state borders data for use on the map.

:param dict us_states_dat: us_states data file, imported from bokeh
:param list state_list: us states, defaults to all states except AK and HI
:return: (*tuple*) -- reprojected coordinates for use on map.
"""
# separate latitude and longitude points for the borders of the states.
if state_list is None:
state_list = default_states_list
num_states = len(state_list)
us_states_dat = [us_states_dat[k] for k in state_list]
state_lats = [state["lats"] for state in us_states_dat]
state_lons = [state["lons"] for state in us_states_dat]
# transform/re-project coordinates for Bokeh
transformer = Transformer.from_crs("epsg:4326", "epsg:3857")
all_state_xs = []
all_state_ys = []
for j in range(num_states):
state_xs, state_ys = transformer.transform(state_lats[j], state_lons[j])
all_state_xs.append(state_xs)
all_state_ys.append(state_ys)

return all_state_xs, all_state_ys


def plot_states(
state_list,
col_list,
Expand Down Expand Up @@ -80,7 +46,7 @@ def plot_states(
if len(state_list) != len(labels_list):
print("warning: state_list and labels_list must be same length")

a, b = get_borders(us_states_dat.copy())
a, b = project_borders(us_states_dat)

tools: str = "pan,wheel_zoom,reset,save"
p = figure(
Expand Down Expand Up @@ -110,7 +76,7 @@ def plot_states(
# plot state borders
p.patches(a, b, fill_alpha=0, fill_color="blue", line_color="gray", line_width=2)

a1, b1 = get_borders(us_states_dat.copy(), state_list=state_list)
a1, b1 = project_borders(us_states_dat, state_list=state_list)
source = ColumnDataSource(
dict(
xs=a1,
Expand All @@ -136,7 +102,7 @@ def plot_states(
# loop through states and colors, plot patches
for i in state_list:
n = n + 1
a1, b1 = get_borders(us_states_dat.copy(), state_list=[i])
a1, b1 = project_borders(us_states_dat, state_list=[i])
citation = Label(
x=min(a1[0]) + 100000,
y=(max(b1[0]) + min(b1[0])) / 2,
Expand Down Expand Up @@ -254,7 +220,7 @@ def map_carbon_emission_bar(
bus_map = project_bus(bus_info_and_emission)
bus_map = group_zone(bus_map)

a, b = get_borders(us_states_dat.copy())
a, b = project_borders(us_states_dat)

# plotting adjustment constants
ha = 85000
Expand Down Expand Up @@ -457,7 +423,7 @@ def map_carbon_emission(
# us states borders, prepare data
if us_states_dat is None:
us_states_dat = us_states.data
a, b = get_borders(us_states_dat.copy())
a, b = project_borders(us_states_dat)

# prepare data frame for emissions data
bus_map = _prepare_busmap(
Expand Down
7 changes: 2 additions & 5 deletions postreise/plot/plot_interconnection_map.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@
from powersimdata.network.usa_tamu.constants import zones
from powersimdata.utility import distance

from postreise.plot import plot_carbon_map
from postreise.plot.projection_helpers import project_branch
from postreise.plot.projection_helpers import project_borders, project_branch


def count_nodes_per_state(grid):
Expand Down Expand Up @@ -92,9 +91,7 @@ def map_interconnections(
)

# state borders
a, b = plot_carbon_map.get_borders(
us_states_dat.copy(), state_list=list(state_counts["state"])
)
a, b = project_borders(us_states_dat, state_list=list(state_counts["state"]))

# transmission data sources
line_width_const = 0.000225
Expand Down
64 changes: 27 additions & 37 deletions postreise/plot/plot_lmp_map.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# This plotting module has a corresponding demo notebook in
# PostREISE/postreise/plot/demo: plot_lmp_map.ipynb
# PostREISE/postreise/plot/demo: lmp_map_demo.ipynb

import pandas as pd
from bokeh.layouts import row
Expand All @@ -9,53 +9,40 @@
from bokeh.sampledata import us_states
from bokeh.tile_providers import Vendors, get_provider

from postreise.plot.plot_carbon_map import get_borders
from postreise.plot.projection_helpers import project_bus
from postreise.plot.projection_helpers import project_borders, project_bus

# make default states list for drawing of state borders
default_states_dict = us_states.data.copy()
del default_states_dict["HI"]
del default_states_dict["AK"]
default_states_list = list(default_states_dict.keys())


def map_lmp(s_grid, lmp, us_states_dat=None):
def map_lmp(s_grid, lmp, us_states_dat=None, lmp_min=20, lmp_max=45):
"""Plots average LMP by color coding buses

:param powersimdata.input.grid.Grid s_grid: scenario grid
:param pandas.DataFrame lmp: locational marginal prices calculated for the scenario
:param str file_name: name for output png file
:param dict us_states_dat: if None default to us_states data file, imported from bokeh
:return: (bokeh.layout.row) bokeh map visual in row layout
:param inf/float lmp_min: minimum LMP to clamp plot range to.
:param inf/float lmp_max: maximum LMP to clamp plot range to.
:return: (*bokeh.models.layout.Row*) bokeh map visual in row layout
"""
if us_states_dat is None:
us_states_dat = us_states.data

bus = project_bus(s_grid.bus)
lmp_split_points = list(range(0, 256, 1))
bus_segments = _construct_bus_data(bus, lmp, lmp_split_points)
return _construct_shadowprice_visuals(lmp_split_points, bus_segments, us_states_dat)
bus_segments = _construct_bus_data(bus, lmp, lmp_min, lmp_max)
return _construct_shadowprice_visuals(bus_segments, us_states_dat, lmp_min, lmp_max)


def _construct_bus_data(bus_map, lmp, lmp_split_points):
def _construct_bus_data(bus_map, lmp, lmp_min, lmp_max):
"""Adds lmp data to each bus, splits buses into lmp segments for coloring

:param pandas.DataFrame bus_map: bus dataframe with location data
:param pandas.DataFrame lmp: lmp dataframe
:param list(float) lmp_split_points: lmp values to split the bus data.
:param inf/float lmp_min: minimum LMP to clamp plot range to.
:param inf/float lmp_max: maximum LMP to clamp plot range to.
:return: (list(pandas.DataFrame)) -- bus data split into segments
"""
# Add mean lmp to bus dataframe
lmp_mean = pd.DataFrame(lmp.mean())
lmp_mean = lmp_mean.rename(columns={lmp_mean.columns[0]: "lmp"})

# min and max values for 'continuous' color scale, in $MW/h
min_lmp_clamp = 20
max_lmp_clamp = 45

lmp_mean["lmp_norm"] = (
(lmp_mean.lmp - min_lmp_clamp) / (max_lmp_clamp - min_lmp_clamp) * 256
)
lmp_mean["lmp_norm"] = (lmp_mean.lmp - lmp_min) / (lmp_max - lmp_min) * 256
bus_map = pd.concat([bus_map, lmp_mean], axis=1)
bus_map_agg = group_lat_lon(bus_map)

Expand Down Expand Up @@ -88,14 +75,15 @@ def group_lat_lon(bus_map):
return bus_map2


def _construct_shadowprice_visuals(lmp_split_points, bus_segments, us_states_dat):
def _construct_shadowprice_visuals(bus_segments, us_states_dat, lmp_min, lmp_max):
"""Uses bokeh to plot formatted data. Make map showing lmp using color.

:param list(float) lmp_split_points: the lmp vals we have chosen to split bus data
:param list(pandas.DataFrame) bus_segments: bus data split by lmp
:param dict us_states_dat: us_states data file, imported from bokeh
:param str file_name: name for output png file
return: (bokeh.layout.row) bokeh map in row layout
:param inf/float lmp_min: minimum LMP to clamp plot range to.
:param inf/float lmp_max: maximum LMP to clamp plot range to.
:return: (*bokeh.models.layout.Row*) bokeh map visual in row layout
"""

tools = "pan,wheel_zoom,reset,save"
Expand All @@ -113,7 +101,7 @@ def _construct_shadowprice_visuals(lmp_split_points, bus_segments, us_states_dat
# Add USA map
p.add_tile(get_provider(Vendors.CARTODBPOSITRON))
# state borders
a, b = get_borders(us_states_dat.copy())
a, b = project_borders(us_states_dat)
p.patches(a, b, fill_alpha=0.0, line_color="gray", line_width=1)
# Add colored circles for bus locations

Expand All @@ -138,20 +126,20 @@ def _construct_shadowprice_visuals(lmp_split_points, bus_segments, us_states_dat
)
p.add_tools(hover)
# Add legend
bus_legend = _construct_bus_legend(lmp_split_points)
bus_legend = _construct_bus_legend(lmp_min, lmp_max)
return row(bus_legend, p)


def _construct_bus_legend(lmp_split_points):
def _construct_bus_legend(lmp_min, lmp_max):
"""Constructs the legend for lmp at each bus

:param list(float) lmp_split_points: the lmp values we have chosen to
split the bus data
:param inf/float lmp_min: minimum LMP to clamp plot range to.
:param inf/float lmp_max: maximum LMP to clamp plot range to.
:return: (bokeh.plotting.figure) the legend showing lmp for each bus
"""
x_range = [""]
bars, bar_len_sum, labels = _get_bus_legend_bars_and_labels(
lmp_split_points, x_range
x_range, lmp_min, lmp_max
)

# Make legend
Expand Down Expand Up @@ -184,14 +172,16 @@ def _construct_bus_legend(lmp_split_points):
return p


def _get_bus_legend_bars_and_labels(lmp_split_points, x_range):
def _get_bus_legend_bars_and_labels(x_range, lmp_min, lmp_max):
"""Gets the bar lengths and labels for the bus legend

:param list(float) lmp_split_points: the lmp vs we have chosen to split the bus data
:param list(string) x_range: the x-range for the vbar_stack
:param inf/float lmp_min: minimum LMP to clamp plot range to.
:param inf/float lmp_max: maximum LMP to clamp plot range to.
:return: (dict, float, dict) bar lengths and labels for the bus legend
"""
bars = {"x_range": x_range}
lmp_split_points = list(range(0, 256, 1))
bar_length_sum = 0
labels = {} # { y-position: label_text, ... }
for i in range(len(lmp_split_points) - 2):
Expand All @@ -208,7 +198,7 @@ def _get_bus_legend_bars_and_labels(lmp_split_points, x_range):
bar_length = max(1, round(lmp_diff, 1))

labels[round(bar_length_sum, -1)] = str(
round(((lmp_split_points[i] - 1) * (45 - 20) / 256 + 20), 0)
round(((lmp_split_points[i] - 1) * (lmp_max - lmp_min) / 256 + lmp_min), 0)
)
if i != len(lmp_split_points) - 1:
bars[str(i)] = [bar_length]
Expand Down
8 changes: 5 additions & 3 deletions postreise/plot/plot_renewable_capacity_map.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
# This plotting module has a corresponding demo notebook in
# PostREISE/postreise/plot/demo: renewable_capacity_map_demo.ipynb

import pandas as pd
from bokeh.models import ColumnDataSource, HoverTool
from bokeh.plotting import figure
from bokeh.sampledata import us_states
from bokeh.tile_providers import Vendors, get_provider

from postreise.analyze.check import _check_scenario_is_in_analyze_state
from postreise.plot.plot_carbon_map import get_borders
from postreise.plot.projection_helpers import project_bus
from postreise.plot.projection_helpers import project_borders, project_bus

# green, breakthrough energy colors (be)
be_green = "#36D78C"
Expand Down Expand Up @@ -52,7 +54,7 @@ def map_plant_capacity(
{"Pmax": "sum", "x": "mean", "y": "mean"}
)

a, b = get_borders(us_states_dat.copy())
a, b = project_borders(us_states_dat)

rar_source = ColumnDataSource(
{
Expand Down
Loading