GUI
The Python syntax for defining a new class that is derived from an existing class uses a class
statement.
This is the statement that defines the RegionBox class:
class RegionBox(pn.Column):
...
pn.Column
is an existing widget class, defined in the Panel library.
That means our new RegionBox objects will be special types of columns that can be inserted into the GUI at some place.
The code that is called to create a new object is a function named __init__
defined inside the class.
The first argument to __init__
is always self
, which is a reference to the object being built.
Here is a simplified version of the __init__
function for the RegionBox class (the actual definition is shown below, in the documentation for RegionBox):
class RegionBox(pn.Column):
def __init__(self, project):
self.boxes = { }
for name in OP.region_names:
box = pn.widgets.Checkbox(name=name, styles=box_styles, stylesheets=[box_style_sheet])
box.param.watch(self.cb, ['value'])
self.boxes[name] = box
When this function is called, it initializes a variable named boxes
to be an empty dictionary. The for
loop iterates over all the region names. It makes a Checkbox widget for each region and adds the box to the dictionary.
The line in the middle of the loop that calls box.param.watch
is where all the "magic" happens. This function call tells the GUI that whenever a checkbox is clicked it should call a function named cb
that is also defined inside the RegionBox class. Here is a simplified version:
def cb(self, event):
r = event.obj.name
if event.new:
self.selected.add(r)
else:
self.selected.remove(r)
The name cb
is short for "callback", a common name for this type of function. The parameter named event
has information about what the user just did. In this case, we want to get the name of the button (which will be one of the region names) and then update the set of selected regions. If the button was turned on we add the region name to the set, otherwise we remove it.
TideGatesApp
Bases: BootstrapTemplate
The web application is based on the Bootstrap template provided by Panel. It displays a map (an instance of the TGMap class) in the sidebar. The main content area has a Tabs widget with five tabs: a welcome message, a help page, the main page (described below) and two tabs for displaying outputs.
The application also displays several small help buttons next to the main widgets. Clicking one of these buttons brings up a floating window with information about the widget.
The main tab (labeled "Start") displays the widgets that allow the user to specify optimization parameters: region names, budget levels, and restoration targets. It also has a Run button. When the user clicks this button the callback function makes sure the necessary parameters have been defined and then uses the template's modal dialog area. Clicking the "OK" button in that dialog invokes another callback, defined here, that runs the optimizer.
Parameters: |
|
---|
Source code in src/gui/app.py
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
|
section_head(s, b=None)
Create an HTML header for one of the sections in the Start tab.
Source code in src/gui/app.py
148 149 150 151 152 153 |
|
validate_settings(_)
Callback function invoked when the user clicks the Run Optimizer button.
Source code in src/gui/app.py
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 |
|
run_cb(_)
Callback function invoked when the user clicks the Continue button after verifying the parameter options.
Wrap the call to the function that runs the optimizer in code that shows the loading icon and opens a message when the function returns.
Source code in src/gui/app.py
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 |
|
run_optimizer()
Use the settings in the widgets to run OptiPass, save the results in the output tab.
Source code in src/gui/app.py
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
|
map_help_cb(_)
Callback function for the help button next to the map in the sidebar.
Source code in src/gui/app.py
217 218 219 220 221 222 223 224 225 226 227 228 229 230 |
|
region_help_cb(_)
Callback function for the help button next to the region box widget in the start tab.
Source code in src/gui/app.py
232 233 234 235 236 237 238 239 240 241 |
|
budget_help_cb(_)
Callback function for the help button next to the budget box widget in the start tab.
Source code in src/gui/app.py
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 |
|
target_help_cb(_)
Callback function for the help button next to the target box widget in the start tab.
Source code in src/gui/app.py
264 265 266 267 268 269 270 271 272 273 |
|
climate_help_cb(_)
Callback function for the help button next to the climate scenario checkbox in the start tab.
Source code in src/gui/app.py
275 276 277 278 279 280 281 282 283 |
|
BudgetBox
Bases: Column
There are three ways users can specify the range of budget values when running OptiPass. A BudgetBox widget has one tab for each option. The widgets displayed inside a tab are defined by their own classes (BasicBudgetBox, AdvancedBudgetBox, and FixedBudgetBox).
Source code in src/gui/budgets.py
19 20 21 22 23 24 25 26 |
|
set_budget_max(n)
When the user selects or deselects a region the budget widgets need to know the new total cost for all the selected regions. This method passes that information to each of the budget widgets.
Parameters: |
|
---|
Source code in src/gui/budgets.py
28 29 30 31 32 33 34 35 36 37 38 |
|
values()
Return the budget settings for the currently selected budget type. Get the widget values from the active budget type, convert them into a tuple of values that will be passed to the optimizer.
Returns: |
|
---|
Source code in src/gui/budgets.py
40 41 42 43 44 45 46 47 48 49 50 51 |
|
defined()
Return True if the user has defined a budget using the current tab
Source code in src/gui/budgets.py
53 54 55 56 57 |
|
set_value(n)
Initialize the GUI by setting an initial budget value
Source code in src/gui/budgets.py
59 60 61 62 63 |
|
BasicBudgetBox
Bases: WidgetBox
The default budget widget displays a slider that ranges from 0 up to a maximum value based on the total cost of all barriers in currently selected regions.
Source code in src/gui/budgets.py
87 88 89 90 91 92 93 94 95 96 97 98 |
|
set_budget_max(n)
Choose a maximum budget by scanning a table of budget levels to find the first one less than the total cost.
Parameters: |
|
---|
Source code in src/gui/budgets.py
100 101 102 103 104 105 106 107 108 109 110 111 112 |
|
values()
The basic budget always has the same number of budgets and always starts with $0. Determine the increment by dividing the max budget in the slider by the number of budgets.
Source code in src/gui/budgets.py
116 117 118 119 120 121 122 123 |
|
defined()
The basic budget is set if the slider is not in the first location.
Source code in src/gui/budgets.py
125 126 127 128 129 |
|
set_value(n)
Set the slider to n
Source code in src/gui/budgets.py
131 132 133 134 135 |
|
FixedBudgetBox
Bases: WidgetBox
This option is for situations where a user knows exactly how much money they have to spend and want to know the optimal set of barriers to replace for that amount of money. OptiPass is run twice -- once to determine the current passabilities, and once to compute the benefit from the specified budget. The widget simply displays a box where the user enters the dollar amount for their budget.
Source code in src/gui/budgets.py
147 148 149 150 |
|
values()
A fixed budget has one value, returned as the starting budget. The the increment is 0 and count is 1.
Source code in src/gui/budgets.py
155 156 157 158 159 160 161 162 163 164 |
|
defined()
The fixed budget is set if the text box is not empty.
Source code in src/gui/budgets.py
166 167 168 169 170 |
|
set_value(n)
Initialize the budget to n
Source code in src/gui/budgets.py
172 173 174 175 176 |
|
parse_dollar_amount(s)
Make sure the string entered by the user has an acceptable format. It can be all digits (e.g. "1500000"), or digits separated by commas (e.g. "1,500,000"), or a number followed by a K or M (e.g. "1.5M"). There can be a dollar sign at the front of the string.
Parameters: |
|
---|
Returns: |
|
---|
Source code in src/gui/budgets.py
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 |
|
AdvancedBudgetBox
Bases: WidgetBox
The "advanced" option gives the user the most control over the budget values processed by OptiPass by letting them specify the number of budget levels (in the basic budget there are always 10 budget levels).
This box has three widgets: a slider to specify the maximum amount, another slider to specify the increment between budgets, and an input box to specify the number of budgets. Adjusting the value of any of these widgets automatically updates the other two. For example, if the maximum is set to $1M and the number of budgets is 10, the increment is $100K. If the user changes the number of budgets to 20, the increment drops to $50K. Or if they change the maximum to $2M, the increment increases to $200K.
Source code in src/gui/budgets.py
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 |
|
values()
In this widget the budget increment and budget count are determined by the values in the corresponding widgets.
Source code in src/gui/budgets.py
281 282 283 284 285 286 |
|
defined()
The advance budget is set if the increment is not 0
Source code in src/gui/budgets.py
288 289 290 291 292 |
|
set_value(n)
Set the budget to n
Source code in src/gui/budgets.py
294 295 296 297 298 |
|
set_budget_max(n)
Called when the user selects or deselects a region. Save the new maximum, and update the value of the increment based on the new maximum.
Parameters: |
|
---|
Source code in src/gui/budgets.py
300 301 302 303 304 305 306 307 308 309 310 311 312 313 |
|
max_updated(e)
Callback function invoked when the user moves the maximum budget slider. Computes a new budget increment.
Source code in src/gui/budgets.py
315 316 317 318 319 320 321 322 323 |
|
inc_updated(e)
Callback function invoked when the user changes the budget increment. Computes a new number of budgets.
Source code in src/gui/budgets.py
325 326 327 328 329 330 331 332 333 334 335 |
|
count_updated(e)
Callback function invoked when the user changes the number of budget levels. Computes a new budget increment.
Source code in src/gui/budgets.py
337 338 339 340 341 342 343 344 345 |
|
DownloadPane
Bases: Column
After OptiPass has completed the last optimization run the GUI creates an instance of this class and saves it in the Download tab of the top level display.
Check the output panel to see which plots were created and to enable the net benefit plot if there is one.
The pane also has a form to allow the user to enter the name of the download file, the format for the figures, and a button to click when they are ready to download the data.
Parameters: |
|
---|
Source code in src/gui/output.py
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 |
|
_make_folder_name()
Use the region names, target names, and budget range to create the default name of the zip file.
Source code in src/gui/output.py
263 264 265 266 267 268 269 270 271 272 273 274 275 |
|
_archive_cb(e)
Function called when the user clicks the Download button. Create the output folder and compress it. When the archive is ready, display a FileDownload widget with a button that starts the download.
Source code in src/gui/output.py
277 278 279 280 281 282 283 284 285 286 287 288 289 290 |
|
_make_archive_dir()
Create an empty directory for the download, using the name in the form.
Source code in src/gui/output.py
292 293 294 295 296 297 298 299 300 301 |
|
_save_files(loc)
Write the tables and figures to the download directory.
Parameters: |
|
---|
Source code in src/gui/output.py
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 |
|
InfoBox
Bases: Column
When the user clicks the Run Optimizer button in the Start panel the GUI displays a message by calling one of the methods in this class. Messages are displayed in the modal dialog area defined by the GUI template.
Parameters: |
|
---|
Source code in src/gui/infobox.py
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
|
_cancel_cb(_)
Close the dialog when the user clicks the "Cancel" button.
Source code in src/gui/infobox.py
60 61 62 63 64 |
|
show_missing(rlist, budget, tlist)
Method called by the OP class when it detects missing parameters (e.g. if the user did not select a region or a target).
Source code in src/gui/infobox.py
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
|
show_invalid_weights(w)
Method called when weighted targets are being used and one of the text boxes does not have a valid entry (must be a number between 1 and 5).
Parameters: |
|
---|
Source code in src/gui/infobox.py
82 83 84 85 86 87 88 89 90 91 92 93 |
|
show_params(regions, budgets, targets, weights, mapping)
Method called to allow the user to review the optimization parameters read from the various widgets. Displays each parameter and two buttons ("Cancel" and "Continue").
Parameters: |
|
---|
Source code in src/gui/infobox.py
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
|
show_success()
Method called after OptiPass has finished running and the results have been parsed successfully.
Source code in src/gui/infobox.py
127 128 129 130 131 132 133 134 |
|
show_fail(reason)
Method called if OptiPass failed.
Parameters: |
|
---|
Source code in src/gui/infobox.py
136 137 138 139 140 141 142 143 144 145 146 147 148 |
|
OutputPane
Bases: Column
After OptiPass has completed the last optimization run the GUI creates an instance of this class and saves it in the Output tab of the top level display.
(displayed in a tab widget showing one figure at a time), the second part has tables showing data about barriers included in solutions.
Parameters: |
|
---|
Source code in src/gui/output.py
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
|
_make_title(op)
The top section of the output pane is a title showing the optimization parameters.
Source code in src/gui/output.py
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
|
_make_figures_tab(op)
Create a Tabs object with one tab for each ROI curve.
Source code in src/gui/output.py
70 71 72 73 74 75 76 77 78 79 80 81 |
|
_make_budget_table(op, tgmap)
Make the table of benefits for each budget. Attach a callback function that is called when the user clicks on a row in the table (the callback updates the map to show gates used in a solution).
Source code in src/gui/output.py
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
|
_make_gate_table(op)
Make a table showing details about gates used in solutions.
Source code in src/gui/output.py
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
|
make_dots(plot, op, tgmap)
Called after the output panel is initialized, make a set of glyphs to display for each budget level.
Source code in src/gui/output.py
150 151 152 153 154 155 156 157 158 159 160 161 |
|
budget_table_cb(e)
The callback function invoked when the user clicks a row in the budget table. Use the event to figure out which row was clicked. Hide any dots that were displayed previously, then make the dots for the selected row visible.
Source code in src/gui/output.py
163 164 165 166 167 168 169 170 171 172 |
|
hide_dots()
Callback function invoked when users click on a region name in the start panel to hide any dots that might be on the map.
Source code in src/gui/output.py
174 175 176 177 178 179 180 181 |
|
RegionBox
Bases: Column
The region box displays the names of each geographic region in the data set, with a checkbox next to the name.
When the user clicks on one of the checkboxes several actions are triggered: the set of selected regions is updated, the budget widget is notified so it can update the maximum budget (based on the total cost of all barriers in the current selection), and the map is updated by zooming in to a level that contains only the barriers in the selected regions.
Parameters: |
|
---|
Source code in src/gui/regionbox.py
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
|
cb(*events)
Callback function invoked when one of the checkboxes is clicked. If the new state of the checkbox is 'selected' the region is added to the set of selected regions, otherwise it is removed. After updating the set notify the map widget and any other widgets that have been registered as external callbacks.
Source code in src/gui/regionbox.py
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
|
check(region)
Initialize the box by addidng region to the selection.
Source code in src/gui/regionbox.py
62 63 64 65 66 |
|
selection()
Return a list of the names of currently selected regions.
Source code in src/gui/regionbox.py
68 69 70 71 72 |
|
add_external_callback(f)
Save a reference to an external function to call when a region box is clicked.
Parameters: |
|
---|
Source code in src/gui/regionbox.py
74 75 76 77 78 79 80 81 |
|
TargetBox
Bases: Column
The restoration targets are shown in a matrix with a selection widget next to each target name. The TargetBox widget has two tabs showing different types of selection widgets, either simple checkboxes (shown by a BasicTargetBox) or text entry widgets (shown by WeightedTargetBox).
Source code in src/gui/targetbox.py
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
|
make_layout(obj)
staticmethod
Read the target layout (size of grid, location of each target in the grid)
Source code in src/gui/targetbox.py
40 41 42 43 44 45 46 47 |
|
selection()
Get a list of IDs of selected targets from the current target widget.
Source code in src/gui/targetbox.py
49 50 51 52 53 |
|
weights()
Get target weights from the current target widget.
Source code in src/gui/targetbox.py
55 56 57 58 59 |
|
mapping()
If the targets have alternative column name mappings return the selected mapping name
Source code in src/gui/targetbox.py
61 62 63 64 65 66 |
|
BasicTargetBox
Bases: Column
The BasicTargetBox widget displays a checkbox next to each target name.
Source code in src/gui/targetbox.py
76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
|
selection()
Return a list of IDs of selected targets.
Source code in src/gui/targetbox.py
91 92 93 94 95 |
|
weights()
There are no weights (all targets considered equally) so return an empty list.
Source code in src/gui/targetbox.py
102 103 104 105 106 |
|
WeightedTargetBox
Bases: Column
A WeightedTargetBox shows a text entry widget next to each target to allow users to enter a numeric weight for the target.
Source code in src/gui/targetbox.py
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
|
selection()
Return a list of IDs of selected targets.
Source code in src/gui/targetbox.py
131 132 133 134 135 |
|
weights()
Return the text content of each non-empty text entry box.
Source code in src/gui/targetbox.py
142 143 144 145 146 |
|
TGMap
A TGMap object manages the display of a map that shows the locations of the barriers in a project.
A static method named init
is a factory that instantiates a new map. It will read
the "mapinfo" file for the project and return a reference to a new
map object belonging to the class specified in the mapinfo file.
Attributes: |
|
---|
map_coords()
Return a frame that has the coordinates and other info needed to display gates on a map
Source code in src/gui/tgmap.py
40 41 42 43 44 45 |
|
graphic()
Return a reference to the map (a Bokeh figure).
Source code in src/gui/tgmap.py
47 48 49 50 51 |
|
display_regions(selection)
Method called when the user clicks the checkbox next to the name of a region. Set the visible attribute of each dot to True or False depending on whether the region it is in is selected.
Parameters: |
|
---|
Source code in src/gui/tgmap.py
53 54 55 56 57 58 59 60 61 62 63 |
|
StaticMap
Bases: TGMap
A static map is simply a PNG file downloaded from the server.
Source code in src/gui/tgmap.py
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
|
TiledMap
Bases: TGMap
A tiled map uses a tile server to fetch the map image. Fetch the main barrier file to get the coordinates and other data for each barrier.
Source code in src/gui/tgmap.py
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
|
_make_info(bf)
Hidden method, makes a dataframe with attributes needed to display gates on a map. Map latitude and longitude columns in the input frame to Mercator coordinates, and copy the ID, region and barrier types so they can be displayed as tooltips.
Source code in src/gui/tgmap.py
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
|
_make_region_list()
Hidden method, make a list of unique region names, sorted by latitude, so regions are displayed in order from north to south. Updates the list of names in the OP object.
Source code in src/gui/tgmap.py
171 172 173 174 175 176 177 178 179 180 181 |
|
_create_ranges()
Hidden method, called by the constructor to create a Pandas Dataframe containing the range of latitudes and longitudes of the barriers in a project.
Source code in src/gui/tgmap.py
183 184 185 186 187 188 189 190 191 192 193 194 195 |
|
display_regions(selection)
Update the map, setting the x and y range based on the currently selected regions.
Parameters: |
|
---|
Source code in src/gui/tgmap.py
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 |
|