Skip to content

Commit

Permalink
Color variable types (#825)
Browse files Browse the repository at this point in the history
* Adding visual indicators to identify variable types in the Stream table

* Cleaning up code and adding a Variable type panel to indicate which types exist in the table

* Fixing tests and cleaning up var types panel

* Cleaning up code

* Fixing potential bug

* Removing unused import

* Fix bug to show types correctly

* Fixing test reference files

* Adding a test to test fixed vs unfixed variables

* Having a separate function for creating the stream table for the ui application

* Updating reference files

* Round floating numbers to 5 digits in the stream table

* Cleaning up code + Fix lib deletion

Co-authored-by: Keith Beattie <[email protected]>
  • Loading branch information
elbashandy and ksbeattie authored May 20, 2022
1 parent e276cde commit f2b81bd
Show file tree
Hide file tree
Showing 22 changed files with 35,574 additions and 23 deletions.
25 changes: 18 additions & 7 deletions idaes/core/ui/flowsheet.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
# third-party
import pandas as pd
import numpy as np
import pint
from pyomo.environ import Block, value
from pyomo.network import Arc
from pyomo.network.port import Port
Expand Down Expand Up @@ -323,13 +324,24 @@ def _clean_units(self, df):
Return:
The dataframe that now has valid JSON
"""
if "Units" in df.columns:
df["Units"] = df["Units"].apply(
lambda pint_unit: {
def get_valid_unit_format(pint_unit):
"""Get different formats from the Units' pint object"""
if isinstance(pint_unit, pint.Unit):
return {
"raw": str(pint_unit),
"html": "{:~H}".format(pint_unit),
"latex": "{:~L}".format(pint_unit),
}
else:
return {
"raw": str(pint_unit),
"html": "",
"latex": "",
}

if "Units" in df.columns:
df["Units"] = df["Units"].apply(
lambda pint_unit: get_valid_unit_format(pint_unit)
)
return df

Expand Down Expand Up @@ -495,13 +507,13 @@ def _construct_output_json(self):

def _construct_model_json(self):
from idaes.core.util.tables import (
create_stream_table_dataframe
create_stream_table_ui
) # deferred to avoid circular import

# Get the stream table and add it to the model json
# Change the index of the pandas dataframe to not be the variables
self._stream_table_df = (
create_stream_table_dataframe(self.streams)
create_stream_table_ui(self.streams)
# Change the index of the pandas dataframe to not be the variables
.reset_index()
.rename(columns={"index": "Variable"})
Expand All @@ -517,8 +529,7 @@ def _construct_model_json(self):
(pd.notnull(self._stream_table_df)), None
)

# Get different formats from the Units' pint object
self._stream_table_df = self._clean_units(self._stream_table_df)
self._stream_table_df = self._make_valid_json(self._stream_table_df)

# Order the stream table based on the right order:
# feed streams -> middle streams -> product streams
Expand Down
51 changes: 50 additions & 1 deletion idaes/core/ui/fsvis/static/css/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ input:checked + .slider:before {
}

/* Styling the Variables column in the Stream Table */
.streamtable-variable {
.streamtable-cell {
display: block;
}

Expand All @@ -350,6 +350,55 @@ input:checked + .slider:before {
float: right;
}

.streamtable-variable-value {
float: right;
}

/* Styling visual indicators to identify different Variable types in the Stream Table */
.streamtable-vartype-panel {
height: 1.7em;
display: flex;
gap: 1em;
justify-content: center;
}

.streamtable-vartype-element {
display: inline-flex;
gap: 0.3em;
place-content: center;
}

.streamtable-vartype-text {
float: right;
}

.streamtable-vartype-fixed {
height: 7px;
width: 7px;
margin-top: 0.5em;
background-color: #7526f1;
border-radius: 50%;
float: left;
}

.streamtable-vartype-parameter {
height: 7px;
width: 7px;
margin-top: 0.5em;
background-color: #74AA50;
border-radius: 50%;
float: left;
}

.streamtable-vartype-expression {
height: 7px;
width: 7px;
margin-top: 0.5em;
background-color: #EAAA00;
border-radius: 50%;
float: left;
}

/* Styling the stream table column header that corresponds to the link mouseover event */
.link-streamtable-hover-columnheader {
border-top: 5px solid #0B79BD ;
Expand Down
90 changes: 85 additions & 5 deletions idaes/core/ui/fsvis/static/js/stream_table.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
export class StreamTable {
// Variable Types
UNFIXED = 'unfixed';
FIXED = 'fixed';
PARAMETER = 'parameter';
EXPRESSION = 'expression';


constructor(app, model) {
this._app = app;
this.initTable(model);

// Keeping track of existing variable types. e.g fixed, Parameter, Expression
this.existing_var_types = new Set();
};

initTable(model) {
Expand All @@ -15,6 +25,53 @@ export class StreamTable {
// Clear the table
$("#hide-fields-list").empty();
$("#stream-table-data").empty();
// Clear list of existing variable types
this.existing_var_types = new Set();
}

fillVarTypesPanel() {
/** Create a panel for each variable type that exists in the Stream Table */
const var_types_panel = document.querySelector('#existing-variable-types');
const stream_table_class = 'streamtable-vartype-element';

// Adding header
if (this.existing_var_types.has(this.FIXED) ||
this.existing_var_types.has(this.PARAMETER) ||
this.existing_var_types.has(this.EXPRESSION)) {
const header_vartype = document.createElement('p');
header_vartype.innerHTML = 'Annotated Variable Types:';
header_vartype.className = stream_table_class;
var_types_panel.appendChild(header_vartype);
}

// Adding each type
this.existing_var_types.forEach(var_type => {
switch (var_type) {
case this.UNFIXED:
// This will execute once since this.existing_var_types is a set
console.debug(`Unfixed variables don't have a visual indicator`);
break;
case this.FIXED:
case this.PARAMETER:
case this.EXPRESSION:
const elem_vartype = document.createElement('span'); // Parent node
elem_vartype.className = stream_table_class;

// Create dot with the right color and the right variable type text
const elem_dot = document.createElement('span');
const elem_text = document.createElement('span');
elem_text.className = 'streamtable-vartype-text';
elem_dot.className = `streamtable-vartype-${var_type}`;
elem_dot.title = var_type;
elem_text.innerHTML = var_type;
elem_vartype.appendChild(elem_dot);
elem_vartype.appendChild(elem_text);
var_types_panel.appendChild(elem_vartype);
break;
default:
console.warn(`Couldn't identify Variable type: ${data[col_index]}`);
};
});
}

fillTable(model) {
Expand All @@ -34,7 +91,7 @@ export class StreamTable {
// only add the columns that don't have an empty column header
// Also ignore the "Units" column header
let column_header = columns[col];
if (column_header !== "" && column_header !== "Units") {
if (column_header !== "" && column_header !== "Units" && !column_header.includes("_vartype")) {
// If the column_header is Variable then we don't want the column to be right-aligned and we want the column to be pinned to the left so when the user scrolls the column scrolls with them
if (column_header === "Variable") {
column_defs.push({
Expand All @@ -45,7 +102,7 @@ export class StreamTable {
resizable: true,
pinned: 'left',
cellRenderer: (params) => {
return '<span class="streamtable-variable">' + params.value + '</span>';
return '<span class="streamtable-cell">' + params.value + '</span>';
}
});
}
Expand All @@ -57,7 +114,9 @@ export class StreamTable {
filter: 'agTextColumnFilter',
sortable: true,
resizable: true,
cellStyle: {"text-align": "right"}
cellRenderer: (params) => {
return '<span class="streamtable-cell">' + params.value + '</span>';
}
});
}
let list_item = document.createElement("li");
Expand Down Expand Up @@ -87,13 +146,34 @@ export class StreamTable {
row_object[variable_col] = row_object[variable_col] + '<span class="streamtable-units">&ndash;</span>';
}
}
else {
else if (columns[col_index] === "Variable") {
row_object[columns[col_index]] = data[col_index];
}
else {
var [value, type] = data[col_index];
let cell_style = "";
switch (type) {
case this.UNFIXED:
this.existing_var_types.add(type);
break;
case this.FIXED:
case this.PARAMETER:
case this.EXPRESSION:
this.existing_var_types.add(type);
cell_style = `<span class="streamtable-vartype-${type}" style="margin-top: 7%;" title="${type}"></span>`;
break;
default:
console.warn(`Couldn't identify Variable type: ${type}`);
};
row_object[columns[col_index]] = cell_style + '<span class="streamtable-variable-value">' + value + '</span>';
}
};
row_data.push(row_object);
};

// Fill the Variable Types panel
this.fillVarTypesPanel();

// let the grid know which columns and what data to use
this._gridOptions = {
columnDefs: column_defs,
Expand All @@ -117,7 +197,7 @@ export class StreamTable {
};

setupEvents() {
// This method sets up the event listeners for the table
// This method sets up the event listeners for the table

// Set up the show/hide checkboxes for the Hide Field dropdown in the nav bar
let hide_fields_list = document.querySelector("#hide-fields-list")
Expand Down
Loading

0 comments on commit f2b81bd

Please sign in to comment.