Custom Tabs¶
The Visualizer framework is extensible, allowing one or more user-defined tabs to be rendered in a given instance of the Visualizer. The Visualizer is built using the statistical programming language R and a package called Shiny. When an instance of the Visualizer is launched, it consumes a config file that specifies both the data and the references to the desired tabs for that instance. Each tab is in turn implementeded as a single Shiny module in a .R file that includes the definition of both the UI and the backend functionality of a tab.
Basic Tab Structure¶
The basic structure of a custom tab is very simple. It must have the following variable and function definitions present to be valid:
title
: This variable should be the desired title of the tab in the UI as a string.footer
: This variable should specify whether or not you want the Visualizer framework footer to be visible when this tab is opened. It will either beTRUE
orFASLE
.ui(id)
: This function should have only theid
parameter and return the output of a Shiny UI function, e.g. fluidPage(), that defines the desired UI.server(input, output, session, data)
: This function is passed the following parameters:input
: This is the Shiny ‘input’ list. You will use this to access inputs generated in the UI.output
: This is the Shiny ‘output’ list. You will use this to assign values to outputs referenced in the UI.session
: This is the Shiny ‘session’ object. It is used to access the ‘ns’ function and is consumed by some of the advanced Shiny functions.data
: This data frame includes the raw data that was passed to the Visualizer by the Results Browser as well as a host of other relevant metadata about the dataset. See below for more infomation.
The ‘data’ Object¶
Upon launch, the Visualizer Framework builds an R data frame that includes the raw data and other useful metadata. The visualizer manages this data frame for the most part, and each of the custom tabs should only enjoy limited write-access to it.
The data object contains all the information that a tab needs to interact with the data and any of the other features that are provided by the Visualizer framework. Below is a mapping of the data structure with an explanation for each of the objects.
data
- contains all the passed objectsColored
- the filtered data that has an added ‘color’ columnFiltered
- the raw data that has been filtered by the different UI elements in the “Filters” sectionFilters
- the state of each of the sliders, selectInputs, etc. in the “Filters” section of the Visualizer UI<variable names>
type
- the “R” data-type of the variable, e.g. ‘factor,’ ‘integer,’ or ‘numeric’selection
- (if type is ‘factor’), list of all selected choicesmin
,max
- (if type is ‘integer’ or ‘numeric’)
meta
coloring
<coloring names>
name
- name of the coloring schemetype
- ‘Max/Min’ or ‘Discrete’var
- the name of the variable that is the basis of the coloringgoal
- (for ‘Max/Min’) ‘Maximize’ or ‘Minimize’palette
- (for ‘Discrete’) ‘Rainbow,’ ‘Heat,’ ‘Terrain,’ ‘Topo,’ or ‘Cm’rainbow_s
- (if ‘Rainbow’ for palette) the saturation for the paletterainbow_v
- (if ‘Rainbow’ for palette) the value/brightness for the palette
current
name
- name of the coloring schemetype
- ‘Max/Min’ or ‘Discrete’var
- the name of the variable that is the basis of the coloringgoal
- (if type is ‘Max/Min’) ‘Maximize’ or ‘Minimize’colors
- (if type is ‘Discrete’, list) the list of the colors used for each variable
comments
[Not yet implemented]<comment ids>
id
- a guid associated with the commentusername
- the username of the user who wrote the commentdate
- the date the comment was addedtext
- a guid associated with the commentobject
- (optional) the object(s) referenced in the comment
pet
- contains information about the PET that generated these resultssampling_method
- (string) ‘Full Factorial,’ ‘Central Composite,’ ‘Opt Latin Hypercube’, or ‘Uniform’num_samples
- (integer) the ‘num_samples’ value from the ‘code’ field in the OpenMETA projectpet_name
- (string) the name of the ‘Parametric Exploration’ in the OpenMETA projectmga_name
- (string) the name of the .mga file within which the PET residesgenerated_configuration_model
- (string) the name of the ‘Generated Configuration Model’ created by the DESERT tool that was selected for the execution of this PETselected_configurations
- (list) the names of each of the configurations that were chosen for this PET executiondesign_variable_names
- (list) the names of all variables that were of type ‘Design Variable’design_variables
- (list) detailed information about the variables that were of type ‘Design Variable’objective_names
- (list) the names of all variables that were of type ‘Objective’pet_config
- (data frame) the parsed pet_config.json file.pet_config_filename
- (string) the filename of the ‘pet_config.json’ file relative to the location of the ‘visualizer_config.json’ file.
sets
[Not yet implemented]<set names>
name
- name of the setusername
- the username of the user who created the setdate
- the date the set was addedobjects
- the different objects in the set, most often design configurations
variables
<variable names>
name
- corresponds to variable indata$raw
dfname_with_units
- unit appended in parenthesestype
- ‘Unknown’, ‘Design Variable’, ‘Objective’, or ‘Classification’username
- the username of the user who wrote the commentdate
- the date the comment was added
pre
- basic preprocessing reactives to simplify interaction with the datavar_names()
- (list) original names of all the variables in the input data setvar_class()
- (list) the class (or type) of each of the variablesvar_facs()
- (list) names of all the variables of class ‘factor’var_ints()
- (list) names of all the variables of class ‘integer’var_nums()
- (list) names of all the variables of class ‘numeric’var_nums_and_ints()
- (list) names of all the variables of class ‘numeric’ or ‘integer’abs_max()
,abs_min()
- (list) the maximum and minimum values for each variable in var_nums_and_intsvar_range_nums_and_ints()
- (list) names of all the variables of class ‘numeric’ or integer’ that vary across some range, i.e. are not constantsvar_range_facs()
- (list) names of all the variables of class ‘factor’ that vary across some range, i.e. are not constantsvar_range()
- (list) names of all variables that vary across some range, i.e. are not constantsvar_range_nums_and_ints_list()
- (list of lists)var_range_nums_and_ints()
sorted into lists by typevar_range_facs_list()
- (list of lists)var_range_facs()
sorted into lists by typevar_range_list()
- (list of lists)var_range()
sorted into lists by typevar_constants()
- (list) names of the variables of any class that don’t vary in the dataset
raw$df
- the raw data with no filtering or coloring applied as a reactive value
E.g. In your server
function, you could find the type of the first
variable by evaluating data$meta$variables[[1]]$type
in either a
reactive context or within an isolate()
call. You could also
find a list of all the variables that are factors, i.e. discrete
choices, in the data$raw$df
data frame by evaluating
data$pre$var_facs()
Histogram Example Tab¶
Below is an example tab definition .R file.
1|title <- "Histogram"
2|footer <- TRUE
3|
4|ui <- function(id) {
5| ns <- NS(id)
6|
7| fluidPage(
8| br(),
9| column(3,
10| selectInput(ns("variable"), "Histogram Variable:", c())
11| ),
12| column(9,
13| plotOutput(ns("plot"))
14| )
15| )
16|
17|}
18|
19|server <- function(input, output, session, data) {
20| ns <- session$ns
21|
22| observe({
23| selected <- isolate(input$variable)
24| if(is.null(selected) || selected == "") {
25| selected <- data$pre$var_range_nums_and_ints()[1]
26| }
27| saved <- si_read(ns("variable"))
28| if (is.empty(saved)) {
29| si_clear(ns("variable"))
30| } else if (saved %in% c(data$pre$var_range_nums_and_ints(), "")) {
30| selected <- si(ns("variable"), NULL)
31| }
32| updateSelectInput(session,
33| "variable",
34| choices = data$pre$var_range_nums_and_ints_list(),
35| selected = selected)
36| })
37|
38| output$plot <- renderPlot({
39| req(input$variable)
40| hist(data$Filtered()[[input$variable]],
41| main = paste("Histogram of" , paste(input$variable)),
42| xlab = paste(input$variable))
43| })
44|
45|}
The title
of the tab is assigned on line 1. On line 2 we specify
that we want to display the Visualizer footer when this tab is open.
The UI for this example tab, defined in ui(id)
on lines 4-17, is
simply a select box for the user to choose which variable to process for
the histogram and a placeholder for the histogram plot itself; the
select box inputId
and plot outputId
are ‘variable’ and ‘plot’,
respectively. The Visualizer framework implements the Shiny ‘Module’
concept to isolate the tabs and avoid input name collisions; this
necessitates the ns <- NS(id)
statement at the beginning of the
function and the wrapping of all the inputId
and outputId
parameters to Shiny UI function calls in a call to ns()
.
The server
function, defined on lines 19-45, is where we describe
the backend processing that produces plots and other outputs for the UI.
The body of this function begins by assigning the local namespace
function (session$ns
) to ns
on line 20. Although you do not need
to call ns()
when accessing variables from input
, e.g. the
input$variable
reference on line 42, you do need to wrap
inputId
s and outputId
s as we did in the UI definition above
when they are being created or updated.
It then implements an observe()
call on lines 22-36 to properly
update the options presented to the user in the “Histogram Variable”
select box. In Shiny, an observe()
provides a mechanism for
re-running a block of code when any of the reactive variables referenced
within that code are initialized or changed. In this case we want to
update the choices presented in the ‘variable’ Select Input anytime the
non-constant, numeric or integer variables in our dataset change. (This
occurs when the data is initialized or classifications are added or
removed.)
This code block is fairly complex, but it provides a lot of
functionality: it specifies a default value, loads a value saved from
a previous session, and updates the ‘variable’ UI element dynamically as
the dataset is altered. The selected
variable is first assigned the
current value of the input. This is done within an isolate()
call
which breaks the reactive dependency on the input value; without the
isolate()
our code block would be executed every time the user
changed the input. Next we assign a default value if it is currently
null or empty, .e.g. when the Visualizer is launched for the first time.
Then we use the si_read()
function to check if there is a saved
value for this input from a previous session of the visualizer. (Note
the use of the ns()
call around our input name.) The is.empty()
function is a custom function that evaluates to true if the value is
either null or an empty list(). To cover the case of it being an empty
list, we clear the saved value as it would prevent saving the value of
this input upon closing the current session. The final if statement
ensures that the saved choice is in the currently available options
before applying the value. Lastly we call updateSelectInput
to
update the input with our new values.
The final section of code on lines 38-43 defines the ‘plot’ output to be a
histogram of the variable selected in the “Histogram Variable” select
box with a title and x-axis label. The req()
function allows us to
break if a needed input is NULL
as is the case with
input$variable
before the dataset is initialized and all the
reactive dependencies are sorted out.
The rendered tab looks like this:
This example can be found at
C:\Program Files (x86)\META\bin\Dig\tabs\Histogram.R
(or wherever
you installed OpenMETA) and used as the basis for creating tabs of your
own.
Adding Your Own Tab¶
Creating the File¶
Navigate to C:\Program Files (x86)\META\bin\Dig\tabs\
to see all the
currently-configured user-defined tabs. Each file here corresponds to a
single tab in the Visualizer. To create a tab of your own, simply make a
copy of the Histogram.R
(or other) file and modify it to suit
your needs. The next time you launch the Visualizer, your tab will be
included in the tabset.
Note
The tabs are added in the order that they appear in this directory, so it may be useful to prepend a number to the filename.
Developing your Application¶
We recommend using RStudio to develop
your custom tabs. It offers syntax highlighting, code completion, and
debugging support. After downloading and installing the software, you
should be able to open the Dig.Rprog
project file at
C:\Program Files (x86)\META\bin\Dig\
and launch the Visualizer
directly from RStudio.
To enable breakpoints in RStudio in your tab file code you will have to
comment (Control-Shift-C
) the debug
call and uncomment the
debugSource
calls towards the top of server.R
file.
170|# Source tab files
171|print("Sourcing Tabs:")
172|tab_environments <- mapply(function(file_name, id) {
173| env <- new.env()
171| if(!is.null(visualizer_config$tab_data)) {
175| env$tab_data <- visualizer_config$tab_data[[id]]
176| } else {
177| env$tab_data <- NULL
178| }
179| # source(file_name, local = env)
180| debugSource(file_name, local = env)
181| print(paste0(env$title, " (", file_name, ")"))
182| env
183| },
184| file_name=tab_files,
185| id=tab_ids,
186| SIMPLIFY = FALSE
187|)
In some cases you may not experience proper breaking behaviour using standard
breakpoints. You can place a browser()
call in your code at the location
you desire to break, and this should result in the execution pausing and an
interactive prompt being shown when the call is reached.