Visualization¶
Warning
The visualization library is still in active development and we hope to improve on it in future releases. Please use its functionality at your own discretion.
The IDAES visualization module is built on top of bokeh and is meant to support multiple plot types. The data for these plots is input through dataframes defined via data-frame schemas.
The Plot class¶
The plot class implements different IDAES plots. Each of its methods acts like a factory method returning an instance of the Plot that can then be modified by calls to helper methods (e.g: saving a plot to disk). Currently only heat exchanger network diagrams are supported.
-
class
idaes.vis.plot.
Plot
(current_plot=None)[source]¶ -
annotate
(x, y, label)[source]¶ Annotate a plot with a given point and a label.
Parameters: - x – Value of independent variable.
- y – Value of dependent variable.
- label – Text label.
Returns: None
Raises: None
-
classmethod
goodness_of_fit
(data_frame, x='', y=[], title='', xlab='', ylab='', y_axis_type='auto', legend=[])[source]¶ Draw y against predicted value (y^) and display (calculate?) value of R^2.
Parameters: - data_frame – a data frame with keys contained in x and y.
- x – Key in data-frame to use as x-axis.
- y – Keys in data-frame to plot on y-axis.
- title – Title for a plot.
- xlab – Label for x-axis.
- ylab – Label for y-axis.
- y_axis_type – Specify “log” to pass logarithmic scale.
- legend – List of strings matching y.
Returns: Plot object on success.
Raises: MissingVariablesException
– Dependent variable or their data not passed.BadDataFrameException
– No data-frame was generated for the model object.
-
classmethod
heat_exchanger_network
(exchangers, stream_list, mark_temperatures_with_tooltips=False, mark_modules_with_tooltips=False, stage_width=2, y_stream_step=1)[source]¶ Plot a heat exchanger network diagram.
Parameters: - exchangers –
List of exchangers where each exchanger is a dict of the form:
{'hot': 'H2', 'cold': 'C1', 'Q': 1400, 'A': 159, 'annual_cost': 28358, 'stg': 2}
where hot is the hot stream name, cold is the cold stream name, A is the area (in m^2), annual_cost is the annual cost in $, Q is the amount of heat transferred from one stream to another in a given exchanger and stg is the stage the exchanger belongs to. The utility_type, if present, will specify if we plot the cold stream as water (
idaes.vis.plot_utils.HENStreamType.cold_utility
) or the hot stream as steam (idaes.vis.plot_utils.HENStreamType.hot_utility
).Additionally, the exchanger could have the key modules, like this:
{'hot': 'H1', 'cold': 'C1', 'Q': 667, 'A': 50, 'annual_cost': 10979, 'stg': 3, 'modules': {10: 1, 20: 2}}
The value of this key is a dictionary where each key is a module area and each value is how many modules of that area are in the exchanger. It’s indicated as a tooltip on the resulting diagram.
If a stream is involved in multiple exchanges in teh same stage, the stream will split into multiple sub-streams with each sub-stream carrying one of the exchanges.
- stream_list –
List of dicts representing streams where each item is a dict of the form:
{'name':'H1', 'temps': [443, 435, 355, 333], 'type': HENStreamType.hot}
- mark_temperatures_with_tooltips – if True, we plot the stream temperatures and assign hover tooltips to them. Otherwise, we label them with text labels.
- mark_modules_with_tooltips – if True, we plot markers for modules (if present) and assign hover tooltips to them. Otherwise, we don’t add module info.
- stage_width – How many units to use for each stage in the diagram (defaults to 2).
- y_stream_step – How many units to use to separate each stream/sub-stream from the next (defaults to 1).
- exchangers –
-
classmethod
isobar
(data_frame, x='', y=[], title='', xlab='', ylab='', y_axis_type='auto', legend=[])[source]¶ Need more information.
-
classmethod
profile
(data_frame, x='', y=[], title='', xlab='', ylab='', y_axis_type='auto', legend=[])[source]¶ A profile plot includes 2 dependent variables and a single independent variable. Based on the Jupyter notebook here.
Parameters: - data_frame – a data frame with keys contained in x and y.
- x – Key in data-frame to use as x-axis.
- y – Keys in data-frame to use as y-axis.
- title – Title for a plot.
- xlab – Label for x-axis.
- ylab – Label for y-axis.
- y_axis_type – Specify “log” to pass logarithmic scale.
- legend – List of strings matching y.
Returns: Plot object on success.
Raises: MissingVariablesException
– Dependent variable or their data not passed.BadDataFrameException
– No data-frame was generated for the model object.
-
classmethod
property_model
(data_frame, x='', y=[], title='', xlab='', ylab='', y_axis_type='auto', legend=[])[source]¶ Draw pressure/enthalpy plots for different levels of temperature.
Parameters: - data_frame – a data frame with keys contained in x and y.
- x – Key in data-frame to plot on x-axis.
- y – Keys in data-frame to plot on y-axis.
- title – Title for a plot.
- xlab – Label for x-axis.
- ylab – Label for y-axis.
- y_axis_type – Specify “log” to pass logarithmic scale.
- legend – List of strings matching y.
Returns: Plot object on success.
Raises: MissingVariablesException
– Dependent variable or their data not passed.BadDataFrameException
– No data-frame was generated for the model object.
-
classmethod
residual
(data_frame, x='', y=[], title='', xlab='', ylab='', y_axis_type='auto', legend=[])[source]¶ Plot x, some continuous value (e.g: T, P), against Y (% residual value). Is this %-value calculated from variables in the idaes_model_object?
Parameters: - data_frame – a data frame with keys contained in x and y.
- x – Key in data-frame to use as x-axis.
- y – Keys in data-frame to plot on y-axis.
- title – Title for a plot.
- xlab – Label for x-axis.
- ylab – Label for y-axis.
- y_axis_type – Specify “log” to pass logarithmic scale.
- legend – List of strings matching y.
Returns: Plot object on success.
Raises: MissingVariablesException
– Dependent variable or their data not passed.BadDataFrameException
– No data-frame was generated for the model object.
-
resize
(height=-1, width=-1)[source]¶ Resize a plot’s height and width.
Parameters: - height – Height in screen units.
- width – Width in screen units.
Returns: None
Raises: None
-
save
(destination)[source]¶ Save the current plot object to HTML in filepath provided by destination.
Parameters: destination – Valid file path to save HTML to. Returns: filename where HTML is saved. Raises: None
-
classmethod
sensitivity
(data_frame, x='', y=[], title='', xlab='', ylab='', y_axis_type='auto', legend=[])[source]¶ Need more information.
-
show
(in_notebook=True)[source]¶ Display plot in a Jupyter notebook.
Parameters: - self – Plot object.
- in_notebook – Display in Jupyter notebook or generate HTML file.
Returns: None
Raises: None
-
classmethod
stream_table
(data_frame, title='')[source]¶ Display a table for all names in the idaes_model_object_names indexing rows according to row_start and row_stop.
Parameters: - data_frame – a data frame with keys contained in x and y.
- title – Title for a plot.
Returns: Plot object on success.
Raises: MissingVariablesException
– Dependent variable or their data not passed.BadDataFrameException
– No data-frame was generated for the model object.
-
classmethod
tradeoff
(data_frame, x='', y=[], title='', xlab='', ylab='', y_axis_type='auto', legend=[])[source]¶ Draw some parameter varying and the result on the objective value.
Parameters: - data_frame – a data frame with keys contained in x and y.
- x – Key in data-frame to use as x-axis.
- y – Keys in data-frame to plot on y-axis.
- title – Title for a plot.
- xlab – Label for x-axis.
- ylab – Label for y-axis.
- y_axis_type – Specify “log” to pass logarithmic scale.
- legend – List of strings matching y.
Returns: Plot object on success.
Raises: MissingVariablesException
– Dependent variable or their data not passed.BadDataFrameException
– No data-frame was generated for the model object.
-
Plot utilities¶
The plot utilities module implements helper/utility methods used for visualization.
-
idaes.vis.plot_utils.
add_exchanger_labels
(plot, x, y_start, y_end, label_font_size, exchanger, module_marker_line_color, module_marker_fill_color, mark_modules_with_tooltips)[source]¶ Plot exchanger labels for an exchanger (for Q and A) on a heat exchanger network diagram and add module markers (if needed).
Parameters: - plot – bokeh.plotting.plotting.figure instance.
- label_font_size – font-size for labels.
- x – x-axis coordinate of exchanger (exchangers are vertical lines so we just need 1 x-value)
- y_start – y-axis coordinate of exchanger start.
- y_end – y-axis coordinate of exchanger end.
- exchanger –
exchanger dictionary of the form:
{'hot': 'H2', 'cold': 'C1', 'Q': 1400, 'A': 159, 'annual_cost': 28358, 'stg': 2}
- module_marker_line_color – color of border of the module marker.
- module_marker_fill_color – color inside the module marker.
- mark_modules_with_tooltips – whether to add tooltips to plot or not (currently not utilized).
Returns: modified bokeh.plotting.plotting.figure instance with labels added.
Raises: None
-
idaes.vis.plot_utils.
add_module_markers_to_heat_exchanger_plot
(plot, x, y, modules, line_color, fill_color, mark_modules_with_tooltips)[source]¶ Plot module markers as tooltips to a heat exchanger network diagram.
Parameters: - plot – bokeh.plotting.plotting.figure instance.
- x – x-axis coordinate of module marker tooltip.
- y – y-axis coordinate of module marker tooltip.
- modules – dict containing modules.
- line_color – color of border of the module marker.
- fill_color – color inside the module marker.
- mark_modules_with_tooltips – whether to add tooltips to plot or not (currently not utilized).
Returns: bokeh.plotting.plotting.figure instance with module markers added.
Raises: None
-
idaes.vis.plot_utils.
get_color_dictionary
(set_to_color)[source]¶ Given a set, return a dictionary of the form:
{'set_member': valid_bokeh_color}
- Args:
- set_to_color: set of unique elements, e.g: [1,2,3] or [“1”, “2”, “3”]
- Returns:
Dictionary of the form:
{'set_member': valid_bokeh_color}
- Raises:
- None
-
idaes.vis.plot_utils.
get_stream_y_values
(exchangers, hot_streams, cold_streams, y_stream_step=1)[source]¶ Return a dict containing the layout of the heat exchanger diagram including any stage splits.
Parameters: - exchangers –
List of exchangers where each exchanger is a dict of the form:
{'hot': 'H2', 'cold': 'C1', 'Q': 1400, 'A': 159, 'annual_cost': 28358, 'stg': 2}
where hot is the hot stream name, cold is the cold stream name, A is the area (in m^2), annual_cost is the annual cost in $, Q is the amount of heat transferred from one stream to another in a given exchanger and stg is the stage the exchanger belongs to. Additionally a ‘utility_type’ can specify if we draw the cold stream as water (
idaes.vis.plot_utils.HENStreamType.cold_utility
) or the hot stream as steam (idaes.vis.plot_utils.HENStreamType.hot_utility
).Additionally, the exchanger could have the key ‘modules’, like this:
{'hot': 'H1', 'cold': 'C1', 'Q': 667, 'A': 50, 'annual_cost': 10979, 'stg': 3, 'modules': {10: 1, 20: 2}}
- hot_streams –
List of dicts representing hot streams where each item is a dict of the form:
{'name':'H1', 'temps': [443, 435, 355, 333], 'type': HENStreamType.hot}
- cold_streams –
List of dicts representing cold streams where each item is a dict of the form:
{'name':'H1', 'temps': [443, 435, 355, 333], 'type': HENStreamType.hot}
- y_stream_step – how many units on the HEN diagram to leave between each stream (or sub-stream) and the one above it. Defaults to 1.
Returns: * stream_y_values_dict : a dict of each stream name as key and value being a dict of the form
This indicates what the default y value of this stream will be on the diagram and what values we’ll use when it splits.
* hot_split_streams : list of tuples of the form (a,b) where a is a hot stream name and b is the max. times it will split over all the stages.
* cold_split_streams : list of tuples of the form (a,b) where a is a cold stream name and b is the max. times it will split over all the stages.
Return type: Tuple containing 3 dictionaries to be used when plotting the HEN
Raises: None
- exchangers –
-
idaes.vis.plot_utils.
is_hot_or_cold_utility
(exchanger)[source]¶ Return if an exchanger is a hot or a cold utility by checking if it has the key utility_type.
Parameters: exchanger – dict representing the exchanger. Returns: True if utility_type in the exchanger dict passed. Raises: None
-
idaes.vis.plot_utils.
plot_line_segment
(plot, x_start, x_end, y_start, y_end, color='white', legend=None)[source]¶ Plot a line segment on a bokeh figure.
Parameters: - plot – bokeh.plotting.plotting.figure instance.
- x_start – x-axis coordinate of 1st point in line.
- x_end – x-axis coordinate of 2nd point in line.
- y_start – y-axis coordinate of 1st point in line.
- y_end – y-axis coordinate of 2nd point in line.
- color – color of line (defaults to white).
- legend – what legend to associate with (defaults to None).
Returns: modified bokeh.plotting.plotting.figure instance with line added.
Raises: None
-
idaes.vis.plot_utils.
plot_stream_arrow
(plot, line_color, stream_arrow_temp, temp_label_font_size, x_start, x_end, y_start, y_end, stream_name=None)[source]¶ Plot a stream arrow for the heat exchanger network diagram.
Parameters: - plot – bokeh.plotting.plotting.figure instance.
- line_color – color of arrow (defaults to white).
- stream_arrow_temp – Tempreature of the stream to be plotted.
- temp_label_font_size – font-size of the temperature label to be added.
- x_start – x-axis coordinate of arrow base.
- x_end – x-axis coordinate of arrow head.
- y_start – y-axis coordinate of arrow base.
- y_end – y-axis coordinate of arrow head.
- stream_name – Name of the stream to add as a label to arrow (defaults to None).
Returns: modified bokeh.plotting.plotting.figure instance with stream arrow added.
Raises: None
-
idaes.vis.plot_utils.
turn_off_grid_and_axes_ticks
(plot)[source]¶ Turn off axis ticks and grid lines on a bokeh figure object.
Parameters: plot – bokeh.plotting.plotting.figure instance. Returns: modified bokeh.plotting.plotting.figure instance. Raises: None
-
idaes.vis.plot_utils.
validate
(data_frame, x, y, legend=None)[source]¶ Validate that the plot parameters are valid.
Parameters: - data_frame – a pandas data frame of any type.
- x – Key in data-frame to use as x-axis.
- y – Keys in data-frame to use as y-axis.
- legend – List of labels to use as legend for a plot.
Returns: True on valid data frames (if x and y are in the data frame keys) Raises exceptions otherwise.
Raises: - MissingVariablesException - on bad legend labels (if passed)
- BadDataFrameException - on invalid data frame.
Examples¶
Drawing heat exchanger network diagrams¶
The following example demonstrates how to generate a heat exchanger network diagram.
In the code below, different streams are defined in the streams list. For each stream, we expect a name (name), a list of temperatures (temps) and a type field specifying if this is a hot stream (HENStreamType.hot) or a cold one (HENStreamType.cold).
The exchangers list defines the heat exchangers. Each exchanger is defined by its hot/cold stream (hot, cold) which must match one of the streams in the streams list above. We also require for each exchanger the area (A),the amount of heat transferred from one stream to another (Q), annual cost (annual_cost) and stage (stg). If the utility_type key is passed and it’s set to HENStreamType.cold_utility then we draw the cold stream of the exchanger as water. If the utility_type key is passed and it’s set to HENStreamType.hot_utility then we draw the hot stream of the exchanger as steam.
The color-codes of each stage are picked randomly in the final diagram.
from bokeh.io import output_notebook
from bokeh.plotting import show
from idaes.vis.plot import Plot
from idaes.vis.plot_utils import HENStreamType
exchangers = [
{'hot': 'H2', 'cold': 'C1', 'Q': 1400, 'A': 159, 'annual_cost': 28358, 'stg': 2},
{'hot': 'H1', 'cold': 'C1', 'Q': 667, 'A': 50, 'annual_cost': 10979, 'stg': 3},
{'hot': 'H1', 'cold': 'C1', 'Q': 233, 'A': 10, 'annual_cost': 4180, 'stg': 1},
{'hot': 'H1', 'cold': 'C2', 'Q': 2400, 'A': 355, 'annual_cost': 35727, 'stg': 2},
{'hot': 'H2', 'cold': 'W', 'Q': 400, 'A': 50, 'annual_cost': 10979, 'stg': 3, 'utility_type': HENStreamType.cold_utility},
{'hot': 'S', 'cold': 'C2', 'Q': 450, 'A': 50, 'annual_cost': 0, 'stg': 1, 'utility_type': HENStreamType.hot_utility}
]
streams = [
{'name':'H2', 'temps': [423, 423, 330, 303], 'type': HENStreamType.hot},
{'name':'H1', 'temps': [443, 435, 355, 333], 'type': HENStreamType.hot},
{'name':'C1', 'temps': [408, 396, 326, 293], 'type': HENStreamType.cold},
{'name':'C2', 'temps': [413, 413, 353, 353], 'type': HENStreamType.cold}
]
plot_obj = Plot.heat_exchanger_network(exchangers, streams,
mark_temperatures_with_tooltips=True)
plot_obj.show()
By default tooltips are used to mark stream temperatures. We can disable those and add labels instead as seen below. They can be a bit crowded and for now you can just zoom in to decipher crowded labels (but we’re working on that!)
plot_obj = Plot.heat_exchanger_network(exchangers, streams,
mark_temperatures_with_tooltips=False)
plot_obj.show()
In case a stream exchanges with multiple streams in the same stage, this is handled through a stage split. We also currently support describing modules for each exchanger that are added as tooltips to the area label on each exchanger. The example below demonstrates this functionality:
exchangers = [
{'hot': 'H1', 'cold': 'C2', 'Q': 2400, 'A': 355, 'annual_cost': 35727, 'stg': 2},
{'hot': 'H2', 'cold': 'C2', 'Q': 1700, 'A': 159, 'annual_cost': 28358, 'stg': 2},
{'hot': 'H1', 'cold': 'C2', 'Q': 1700, 'A': 159, 'annual_cost': 28358, 'stg': 3},
{'hot': 'H1', 'cold': 'C1', 'Q': 667, 'A': 50, 'annual_cost': 10979, 'stg': 3, 'modules': {10: 1, 20: 2}},
{'hot': 'H2', 'cold': 'C3', 'Q': 1700, 'A': 159, 'annual_cost': 28358, 'stg': 3},
{'hot': 'H2', 'cold': 'C2', 'Q': 1700, 'A': 159, 'annual_cost': 28358, 'stg': 3, 'modules': {10: 1, 20: 2}},
{'hot': 'H3', 'cold': 'C2', 'Q': 1700, 'A': 159, 'annual_cost': 28358, 'stg': 3},
{'hot': 'H2', 'cold': 'W', 'Q': 400, 'A': 50, 'annual_cost': 10979, 'stg': 3, 'utility_type': HENStreamType.cold_utility},
{'hot': 'S', 'cold': 'C2', 'Q': 450, 'A': 50, 'annual_cost': 0, 'stg': 1, 'utility_type': HENStreamType.hot_utility}
]
streams = [
{'name':'H3', 'temps': [423, 423, 330, 303], 'type': HENStreamType.hot},
{'name':'H2', 'temps': [423, 423, 330, 303], 'type': HENStreamType.hot},
{'name':'H1', 'temps': [443, 435, 355, 333], 'type': HENStreamType.hot},
{'name':'C1', 'temps': [408, 396, 326, 293], 'type': HENStreamType.cold},
{'name':'C2', 'temps': [413, 413, 353, 353], 'type': HENStreamType.cold},
{'name':'C3', 'temps': [413, 413, 353, 353], 'type': HENStreamType.cold}
]
plot_obj = Plot.heat_exchanger_network(exchangers, streams,
mark_temperatures_with_tooltips=True,
mark_modules_with_tooltips=True,
stage_width=2,
y_stream_step=1)
plot_obj.show()
Plotting profile plots from the MEA example¶
Note: The following has not been tested recently and should be considered a work in progress.
The following examples demonstrate the resize, annotation and saving functionalities.
In the following example, we being by preparing a data frame from our flowsheet variables.
# Absorber CO2 Levels
from pandas import DataFrame
import os
tmp = fs.absorb.make_profile(t=0)
tmp = fs.regen.make_profile(t=0)
plot_dict = {'z':fs.absorb.profile_1['z'],
'y1':fs.absorb.profile_1.y_vap_CO2*101325.0,
'y2':fs.absorb.profile_1.P_star_CO2}
plot_data_frame = DataFrame(data=plot_dict)
We can then plot the data frame we just made, show it, resize it and save it.
absorber_co2_plot = Plot.profile(plot_data_frame,
x = 'z',
y = ['y1','y2'],
title = 'Absorber CO2 Levels',
xlab = 'Axial distance from top (m)',
ylab = 'Partial Pressure CO2 (Pa)',
legend = ['Bulk vapor','Equilibrium'])
absorber_co2_plot.show()
absorber_co2_plot.save('/home/jovyan/model_contrib/absorber_co2_plot.html')
assert(os.path.isfile('/home/jovyan/model_contrib/absorber_co2_plot.html'))
absorber_co2_plot.resize(height=400,width=600)
absorber_co2_plot.show()
absorber_co2_plot.save('/home/jovyan/model_contrib/absorber_co2_plot_resized.html')
assert(os.path.isfile('/home/jovyan/model_contrib/absorber_co2_plot_resized.html'))
The following demonstrates the annotate functionality by plotting a second plot from the same flowsheet.
from IPython.core.display import display,HTML
stripper_co2_plot = Plot.profile(plot_data_frame,
x = 'z',
y = ['y1','y2'],
title = 'Stripper CO2 Levels',
xlab = 'Axial distance from top (m)',
ylab = 'Partial Pressure CO2 (Pa)',
legend = ['Bulk vapor','Equilibrium'])
stripper_co2_plot.show()
stripper_co2_plot.save('/home/jovyan/model_contrib/stripper_co2_plot.html')
assert(os.path.isfile('/home/jovyan/model_contrib/stripper_co2_plot.html'))
We can then annotate the “Reboiler vapor” point as shown below:
stripper_co2_plot.annotate(rloc,rco2p,'Reboiler vapor')
stripper_co2_plot.show()
stripper_co2_plot.save('/home/jovyan/model_contrib/stripper_co2_plot_annotated.html')