Choice Modeling - Utilities Plot Extension
Plots the utility of variables in a Choice Model.
Plots the utility of variables in a Choice Model.
How to Create
There are two possible ways to create a utilities plot:
- Using the menu options with Automate > Browse Online Library > Choice Modeling > Utilities Plot and populate the plot with the desired input type (see possible input types in the Options section below). To do this, in the newly created Utilities plot, view the Inputs tab of the Object Inspector and select the desired choice model from the dropbox labeled Input in the INPUTS subsection.
- In the Object Inspector of a Choice Model output, click the Utilities plot extension button. This extension button can be found under Inputs > DIAGNOSTICS > Utilities plot. The extension button will create a new R output with the Utilities plot in the same group (folder) where the choice model is contained.
Example
Output Example:
Input Example:
A choice model. The following LCA model creates the output above:
Options
Chart type The chart type that is used for the output. It can be one of Line, Column or Bar.
Input One of
- A choice model such as Choice Modeling - Latent Class Analysis or Choice Modeling - Hierarchical Bayes .
- Multiple numeric variables that each contain respondent utilities for an attribute level. For example variables created using Choice Modeling - Save Variable(s) - Utilities (Min 0) .
- A vector or list containing summary values for each attribute level. e.g c(`Feed: Grain` = 0.2, `Feed: Vegetables` = 0.1, `Weight: 55g` = 0.4, `Weight: 60g` = 0.5, `Weight: 75g` = 0.6) or list(Feed = c(Grain = 0.2, Vegetables = 0.1), Weight = c(`55g` = 0.4, `60g` = 0.5, `75g` = 0.6))
Attributes to exclude Attributes in the model to omit from the chart.
Scaling Whether the mean utility of each variable should be scaled or plotted as is. Options are
- As is
- Mean 0
- Mean 0, Max range 100
- Mean 0, Mean range 100
- Min 0 (default)
- Min 0, Max range 100
- Min 0, Mean range 100
Order levels Whether the levels of each attribute should be order or plotted as is.
Attributes to exclude from ordering If levels are ordered, individual attributes can be omitted from sorting.
Zero line width Line width of the axis line at Utility = 0. Often you want to emphasize this line but it can also hidden by setting the width to zero.
Additional Properties
When using this feature you can obtain additional information that is stored by the R code which produces the output.
- To do so, select Create > R Output.
- In the R CODE, paste: item = YourReferenceName
- Replace YourReferenceName with the reference name of your item. Find this in the Report tree or by selecting the item and then going to Properties > General > Name from the object inspector on the right.
- Below the first line of code, you can paste in snippets from below or type in str(item) to see a list of available information.
For a more in depth discussion on extracting information from objects in R, checkout our blog post here.
Code
includeWeb("QScript R Output Functions");
if (Q.fileFormatVersion() <= 17.09) {
alert("This Utilities plot button is not functional in this version of Q. " +
"You can create the same plot via the menus at Automate > Browse Online Library > Choice Modelling > Utilities Plot");
} else {
var is_displayr = (!!Q.isOnTheWeb && Q.isOnTheWeb());
// Separate selected item from the group/page
var selected_items = project.report.selectedRaw();
var selected_item = selected_items[0];
var selected_group = selected_item.type == "ReportGroup" ? selected_item : selected_item.group;
var output_name = generateUniqueRObjectName("utilities.plot");
var r_expr = 'library(flipChoice)\n' +
'\n' +
'# Read input\n' +
'if (inherits(formInput[[1]], "FitChoice"))\n' +
'{\n' +
' x <- formInput[[1]]\n' +
' if (length(formInput) > 1)\n' +
' warning("Only the first choice model was used for utilities plot")\n' +
' attributes <- names(x$attribute.levels)\n' +
'\n' +
'} else if (is.numeric(formInput[[1]]) && length(formInput) == 1)\n' +
'{ \n' +
' x <- formInput[[1]]\n' +
' if (is.null(names(x)))\n' +
' stop("Input vector must have names in the format \x27<attribute>:<level>\x27")\n' +
' ind <- which(!grepl(":", names(x)))\n' +
' if (length(ind) > 0)\n' +
' stop("Names \x27", paste(colnames(x)[ind], collapse="\x27, \x27"),\n' +
' "\x27 do not have the expected format \'<attribute>:<level>\x27")\n' +
' attributes <- names(flipChoice:::makeAttributeList(names(x)))\n' +
'\n' +
'} else if (!is.null(names(formInput[[1]])) && !is.null(names(formInput[[1]][[1]])))\n' +
'{\n' +
' x <- formInput[[1]]\n' +
' if (length(formInput) > 1)\n' +
' warning("Only the first R output was used for utilities plot")\n' +
' attributes <- names(x)\n' +
'\n' +
'} else\n' +
'{\n' +
' x <- as.data.frame(formInput, check.names = FALSE)\n' +
' colnames(x) <- sapply(x, function(i) attr(i, "label"))\n' +
' ind <- which(!grepl(":", colnames(x)))\n' +
' if (length(ind) > 0)\n' +
' stop("Variables \x27", paste(colnames(x)[ind], collapse="\x27, \x27"),\n' +
' "\x27 do not have label names with the expected format \x27<attribute>:<level>\x27")\n' +
' attributes <- names(flipChoice:::makeAttributeList(colnames(x)))\n' +
'\n' +
'}\n' +
' \n' +
'# Set color palette\n' +
'attributes <- setdiff(attributes, flipTransformations::TextAsVector(formExcludeAttr))\n' +
'colors = flipChartBasics::ChartColors(length(attributes), formPalette,\n' +
' custom.color = get0("formCustomColor"), custom.gradient.start = get0("formCustomGradientStart"), \n' +
' custom.gradient.end = get0("formCustomGradientEnd"), custom.palette = get0("formCustomPalette"),\n' +
' silent = TRUE, silent.single.color = TRUE)\n' +
'\n' +
'# Create plot\n' +
output_name + ' <- Utilities(x, subset = QFilter, weights = QPopulationWeight,\n' +
' scaling = formScaling,\n' +
' levels.order = formLevelsOrder,\n' +
' attr.order = formAttributeOrder, \n' +
' exclude.attributes = formExcludeAttr,\n' +
' attr.levels.not.ordered = get0("formExcludeOrder", ifnotfound = ""),\n' +
' output = formChartType,\n' +
' colors = colors,\n' +
' line.width = get0("formLineWidth", ifnotfound = 0),\n' +
' global.font.family = formGlobalFontFamily,\n' +
' global.font.color = formGlobalFontColor,\n' +
' grid.width = formGridWidth,\n' +
' grid.color = get0("formGridColor", ifnotfound = 0),\n' +
' level.label.font.family = formLevelFontFamily,\n' +
' level.label.font.color = formLevelFontColor,\n' +
' level.label.font.size = formLevelFontSize,\n' +
' level.label.wrap = formLabelWrap,\n' +
' level.label.wrap.nchar = get0("formLabelWrapNchar"),\n' +
' values.minimum = if (sum(nchar(get0("formValuesMin"))) == 0) NULL else as.numeric(formValuesMin),\n' +
' values.maximum = if (sum(nchar(get0("formValuesMax"))) == 0) NULL else as.numeric(formValuesMax),\n' +
' values.title = formValuesTitle,\n' +
' values.title.font.family = get0("formValuesTitleFontFamily"),\n' +
' values.title.font.color = get0("formValuesTitleFontColor"),\n' +
' values.title.font.size = get0("formValuesTitleFontSize"),\n' +
' values.tick.font.family = get0("formValuesTickFontFamily"),\n' +
' values.tick.font.color = get0("formValuesTickFontColor"),\n' +
' values.tick.font.size = get0("formValuesTickFontSize"),\n' +
' values.zero.line.width = formZeroLineWidth,\n' +
' values.zero.line.color = get0("formZeroLineColor"),\n' +
' attr.tick.font.family = get0("formAttrFontFamily"),\n' +
' attr.tick.font.color = get0("formAttrFontColor"),\n' +
' attr.tick.font.size = get0("formAttrFontSize"),\n' +
' hovertext.decimals = formHoverDecimals,\n' +
' margin.top = formMarginTop,\n' +
' margin.bottom = formMarginBottom,\n' +
' margin.left = formMarginLeft,\n' +
' margin.right = formMarginRight,\n' +
' font.units = "pt")';
if (is_displayr) {
try {
var new_output = selected_group.group.appendPage("Title and Content");
} catch(e) {
var new_output = selected_group.group.appendPage("TitleOnly");
}
new_output.subItems[0].text = "Utilities Plot";
new_output.name = "Utilities Plot";
var component_plot = new_output.appendR(r_expr);
selected_group.group.moveAfter(new_output, selected_group);
project.report.setSelectedRaw([new_output]);
} else {
var component_plot = selected_group.appendR(r_expr);
selected_group.moveAfter(component_plot, selected_item);
project.report.setSelectedRaw([component_plot]);
}
// Create GUI controls
var javascript_inputs_expr = 'var allow_control_groups = Q.fileFormatVersion() > 10.9; // Group controls for Displayr and later versions of Q\n' +
'font_families = ["Arial", "Arial Black", "Century Gothic", "Comic Sans MS",\n' +
' "Courier New", "Georgia", "Impact", "Open Sans", "Tahoma", "Times New Roman", "Trebuchet MS", "Verdana"];\n' +
'palettes = ["Default colors", "Colorblind safe colors", "Rainbow", "Light pastels", "Strong colors", "Spectral colors (red, yellow, blue)", "Spectral colors (blue, yellow, red)", "Reds, dark to light", "Reds, light to dark", "Greens, dark to light", "Greens, light to dark", "Blues, dark to light", "Blues, light to dark", "Greys, dark to light", "Greys, light to dark", "Heat colors (yellow, red)", "Terrain colors (green, beige, grey)", "Custom color", "Custom gradient", "Custom palette"];\n' +
'\n' +
'form.setHeading("Utilities Plot");\n' +
'if (allow_control_groups)\n' +
' var chartType = form.comboBox({label: "Chart type", name: "formChartType", alternatives: ["Line", "Column", "Bar"], default_value: "Line"}).getValue();\n' +
'\n' +
'if (allow_control_groups)\n' +
' form.group("Inputs")\n' +
'form.dropBox({label: "Input", name: "formInput", types: [\x27RItem:FitChoice,list,numeric\x27, \x27Variable: Numeric\x27], required: true, prompt: "Select either 1) a choice model; 2) a vector or list containing summary values for each attribute level; or 3) a set of numeric variables that each contain respondent utilities for an attribute level", multi: true});\n' +
'form.textBox({label: "Attributes to exclude", name: "formExcludeAttr", required: false, prompt: "Optional comma-separated list of attributes to exclude from plot"});\n' +
'form.comboBox({label: "Scaling", name: "formScaling", alternatives: ["As is", "Mean 0", "Mean 0, Max range 100", "Mean 0, Mean range 100", "Min 0", "Min 0, Max range 100", "Min 0, Mean range 100"], default_value: "Min 0"}).getValue();\n' +
'form.comboBox({label: "Attributes order", name: "formAttributeOrder", alternatives: ["As is", "Increasing", "Decreasing"], default_value: "As is"}).getValue();\n' +
'var order = form.comboBox({label: "Levels order", name: "formLevelsOrder", alternatives: ["As is", "Reverse", "Increasing", "Decreasing"], default_value: "Increasing"}).getValue();\n' +
'if (order != "As is")\n' +
' form.textBox({label: "Attributes to exclude from ordering", name: "formExcludeOrder", required: false, prompt: "Comma-separated list of attributes to exclude from ordering"});\n' +
'\n' +
'if (allow_control_groups)\n' +
' form.page("Chart")\n' +
'\n' +
'if (allow_control_groups)\n' +
' form.group("APPEARANCE")\n' +
'if (chartType == "Line")\n' +
' form.numericUpDown({label: "Line thickness", name: "formLineWidth", default_value: 3});\n' +
'\n' +
'var colOpt = form.comboBox({name: "formPalette", label: "Color palette", alternatives: palettes, default_value: palettes[0], required: true}).getValue();\n' +
'if (colOpt == "Custom color")\n' +
' var qCustomCol = form.colorPicker({name: "formCustomColor", label: allow_control_groups ? "Custom color" : "", default_value: "#5C9AD3"});\n' +
'if (colOpt == "Custom gradient")\n' +
'{\n' +
' form.colorPicker({name: "formCustomGradientStart", label: !allow_control_groups ? "" : "Gradient start", default_value: "#5C9AD3"});\n' +
' form.colorPicker({name: "formCustomGradientEnd", label: !allow_control_groups ? "" : "Gradient end", default_value: "#ED7D31"});\n' +
'}\n' +
'if (colOpt == "Custom palette")\n' +
' form.textBox({name: "formCustomPalette", label: "Custom palette", default_value: "#5C9AD3, #ED7D31", prompt: "Enter color as a string. Multiple values should be separated by commas."});\n' +
'\n' +
'if (allow_control_groups)\n' +
' form.group("FONT")\n' +
'var qGlobalFontFamily = form.comboBox({name: "formGlobalFontFamily", label: "Global font family", alternatives: font_families, default_value: "Arial"}).getValue();\n' +
'var qGlobalFontColor = form.colorPicker({name: "formGlobalFontColor", label: "Global font color", default_value: "#2C2C2C"}).getValue();\n' +
'\n' +
'if (allow_control_groups)\n' +
' form.group("ATTRIBUTE LABELS")\n' +
'form.comboBox({name: "formAttrFontFamily", label: "Attribute label font family", alternatives: font_families, default_value: qGlobalFontFamily});\n' +
'form.colorPicker({name: "formAttrFontColor", label: "Attribute label font color", default_value: qGlobalFontColor});\n' +
'form.numericUpDown({name: "formAttrFontSize", label: "Attribute label font size", default_value: 9, increment: 0.5, prompt: "Font size in points"});\n' +
'\n' +
'if (allow_control_groups)\n' +
' form.group("LEVEL LABELS")\n' +
'var qLevelWrap = form.checkBox({name: "formLabelWrap", label: "Wrap level labels", default_value: chartType == "Bar" ? false : true}).getValue();\n' +
'if (qLevelWrap)\n' +
' form.numericUpDown({name: "formLabelWrapNchar", label: "Label level width (in characters)", default_value: 20}); \n' +
'form.comboBox({name: "formLevelFontFamily", label: "Level label font family", alternatives: font_families, default_value: qGlobalFontFamily});\n' +
'form.colorPicker({name: "formLevelFontColor", label: "Level label font color", default_value: qGlobalFontColor});\n' +
'form.numericUpDown({name: "formLevelFontSize", label: "Level label font size", default_value: 7.5, increment: 0.5, prompt: "Font size in points"});\n' +
'\n' +
'if (allow_control_groups)\n' +
' form.group("VALUES AXIS")\n' +
'form.textBox({name: "formValuesMin", label: "Minimum value", type: "number", required: false, prompt: "Leave blank to determine automatically from data."});\n' +
'form.textBox({name: "formValuesMax", label: "Maximum value", type: "number", required: false, prompt: "Leave blank to determine automatically from data."});\n' +
'var qValuesTitle = form.textBox({name: "formValuesTitle", label: "Value axis title", required: false, default_value: "Utility"}).getValue();\n' +
'if (qValuesTitle != "")\n' +
'{\n' +
' form.comboBox({name: "formValuesTitleFontFamily", label: "Axis title font family", alternatives: font_families, default_value: qGlobalFontFamily});\n' +
' form.colorPicker({name: "formValuesTitleFontColor", label: "Axis title font color", default_value: qGlobalFontColor});\n' +
' form.numericUpDown({name: "formValuesTitleFontSize", label: "Axis title font size", default_value: 12, increment: 0.5, prompt: "Font size in points"});\n' +
'}\n' +
'form.comboBox({name: "formValuesTickFontFamily", label: "Axis tick font family", alternatives: font_families, default_value: qGlobalFontFamily});\n' +
'form.colorPicker({name: "formValuesTickFontColor", label: "Axis tick font color", default_value: qGlobalFontColor});\n' +
'form.numericUpDown({name: "formValuesTickFontSize", label: "Axis tick font size", default_value: 7.5, increment: 0.5, prompt: "Font size in points"});\n' +
'\n' +
'if (allow_control_groups)\n' +
' form.group("HOVERTEXT")\n' +
'form.numericUpDown({name: "formHoverDecimals", label: "Decimal places", default_value: 3});\n' +
'\n' +
'if (allow_control_groups)\n' +
' form.group("GRID LINES")\n' +
'var gridWidth = form.numericUpDown({name: "formGridWidth", label: "Grid line width", default_value: 1}).getValue();\n' +
'if (gridWidth > 0)\n' +
' form.colorPicker({name: "formGridColor", label: "Grid line color", default_value: "#E1E1E1"});\n' +
'var zeroWidth = form.numericUpDown({name: "formZeroLineWidth", label: "Zero line width", default_value: 1, prompt: "Control width of line showing \x27Utility = 0\x27 place on top of the grid\x27"}).getValue();\n' +
'if (zeroWidth > 0)\n' +
' form.colorPicker({name: "formZeroLineColor", label: "Zero line color", default_value: "#E1E1E1"});\n' +
'\n' +
'if (allow_control_groups)\n' +
' form.group("MARGINS")\n' +
'form.numericUpDown({name: "formMarginTop", label: "Top", default_value: 20, increment: 1, minimum: 0, maximum: 1000});\n' +
'form.numericUpDown({name: "formMarginLeft", label: "Left", default_value: 80, increment: 1, minimum: 0, maximum: 1000});\n' +
'form.numericUpDown({name: "formMarginBottom", label: "Bottom", default_value: 50, increment: 1, minimum: 0, maximum: 1000});\n' +
'form.numericUpDown({name: "formMarginRight", label: "Right", default_value: 60, increment: 1, minimum: 0, maximum: 1000});'
component_plot.setCodeForGuiControls(javascript_inputs_expr);
// Place selected item as default plot input.
component_plot.setGuiControlInputRaw("formInput", selected_item.guid);
}