Choice Modeling - Utilities Plot

From Q
Jump to navigation Jump to search


VizIcon Utilities Plot.svg

Plots the mean utilities of variables in a Choice Model (the mean over all respondents). The mean utilities may be scaled (see scaling options below). Note that the scaled values shown would be different from the means from the utilities produced by scripts such as Choice Modeling - Save_Variable(s) - Utilities (Min 0) as the former are scaled mean utilities whereas the latter are mean scaled utilities.

How to Create

There are two possible ways to create a utilities plot:

  1. Using the menu options with Anything > Advanced Analysis > Choice Modeling > Utilities PlotAutomate > 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.
  2. 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 page with the Utilities plotR 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.

  1. To do so, select Create > R Output.
  2. In the R CODE, paste: item = YourReferenceName
  3. 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.
  4. 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

var allow_control_groups = Q.fileFormatVersion() > 10.9; // Group controls for Displayr and later versions of Q
font_families = !!Q.GetAvailableFontNames ? Q.GetAvailableFontNames() : ["Arial", "Arial Black", "Comic Sans MS",  "Courier New", "Georgia", "Impact", 
                 "Open Sans", "Tahoma", "Times New Roman", "Trebuchet MS", "Verdana"];
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"];

var heading_text = "Utilities Plot";
if (!!form.setObjectInspectorTitle)
    form.setObjectInspectorTitle(heading_text);
else 
    form.setHeading(heading_text);

if (allow_control_groups)
var chartType = form.comboBox({label: "Chart type", name: "formChartType", alternatives: ["Line", "Column", "Bar"], default_value: "Line"}).getValue();

if (allow_control_groups)
    form.group("Inputs")
form.dropBox({label: "Input", name: "formInput", types: ['RItem:FitChoice,list,numeric', 'Variable: Numeric'], 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});
form.textBox({label: "Attributes to exclude", name: "formExcludeAttr", required: false, prompt: "Optional comma-separated list of attributes to exclude from plot"});
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();
form.comboBox({label: "Attributes order", name: "formAttributeOrder", alternatives: ["As is", "Increasing", "Decreasing"], default_value: "As is"}).getValue();
var order = form.comboBox({label: "Levels order", name: "formLevelsOrder", alternatives: ["As is", "Reverse", "Increasing", "Decreasing"], default_value: "Increasing"}).getValue();
if (order != "As is")
    form.textBox({label: "Attributes to exclude from ordering", name: "formExcludeOrder", required: false, prompt: "Comma-separated list of attributes to exclude from ordering"});

if (allow_control_groups)
    form.page("Chart")

if (allow_control_groups)
    form.group("APPEARANCE")
if (chartType == "Line")
    form.numericUpDown({label: "Line thickness", name: "formLineWidth", default_value: 3});

var colOpt = form.comboBox({name: "formPalette", label: "Color palette", alternatives: palettes, default_value: palettes[0], required: true}).getValue();
if (colOpt == "Custom color")
    var qCustomCol = form.colorPicker({name: "formCustomColor", label: allow_control_groups ? "Custom color" : "", default_value: "#5C9AD3"});
if (colOpt == "Custom gradient")
{
    form.colorPicker({name: "formCustomGradientStart", label: !allow_control_groups ? "" : "Gradient start", default_value: "#5C9AD3"});
    form.colorPicker({name: "formCustomGradientEnd", label: !allow_control_groups ? "" : "Gradient end", default_value: "#ED7D31"});
}
if (colOpt == "Custom palette")
    form.textBox({name: "formCustomPalette", label: "Custom palette", default_value: "#5C9AD3, #ED7D31", prompt: "Enter color as a string. Multiple values should be separated by commas."});

if (allow_control_groups)
    form.group("FONT")
var qGlobalFontFamily = form.comboBox({name: "formGlobalFontFamily", label: "Global font family", alternatives: font_families, default_value: "Open Sans", editable: true, prompt: "Select the font to use. You can also type the name of a font directly (including custom fonts)."}).getValue();
var qGlobalFontColor = form.colorPicker({name: "formGlobalFontColor", label: "Global font color", default_value: "#444444"}).getValue();

if (allow_control_groups)
    form.group("ATTRIBUTE LABELS")
form.comboBox({name: "formAttrFontFamily", label: "Attribute label font family", alternatives: font_families, default_value: qGlobalFontFamily, editable: true, prompt: "Select the font to use. You can also type the name of a font directly (including custom fonts)."});
form.colorPicker({name: "formAttrFontColor", label: "Attribute label font color", default_value: qGlobalFontColor});
    form.numericUpDown({name: "formAttrFontSize", label: "Attribute label font size", default_value: 9, increment: 0.5, prompt: "Font size in points"});

if (allow_control_groups)
    form.group("LEVEL LABELS")
var qLevelWrap = form.checkBox({name: "formLabelWrap", label: "Wrap level labels", default_value: chartType == "Bar" ? false : true}).getValue();
if (qLevelWrap)
    form.numericUpDown({name: "formLabelWrapNchar", label: "Label level width (in characters)", default_value: 20});     
form.comboBox({name: "formLevelFontFamily", label: "Level label font family", alternatives: font_families, default_value: qGlobalFontFamily, editable: true, prompt: "Select the font to use. You can also type the name of a font directly (including custom fonts)."});
form.colorPicker({name: "formLevelFontColor", label: "Level label font color", default_value: qGlobalFontColor});
    form.numericUpDown({name: "formLevelFontSize", label: "Level label font size", default_value: 9, increment: 0.5, prompt: "Font size in points"});

if (allow_control_groups)
    form.group("VALUES AXIS")
form.textBox({name: "formValuesMin", label: "Minimum value", type: "number", required: false, prompt: "Leave blank to determine automatically from data."});
form.textBox({name: "formValuesMax", label: "Maximum value", type: "number", required: false, prompt: "Leave blank to determine automatically from data."});
var qValuesTitle = form.textBox({name: "formValuesTitle", label: "Value axis title", required: false, default_value: "Utility"}).getValue();
if (qValuesTitle != "")
{
    form.comboBox({name: "formValuesTitleFontFamily", label: "Axis title font family", alternatives: font_families, default_value: qGlobalFontFamily, editable: true, prompt: "Select the font to use. You can also type the name of a font directly (including custom fonts)."});
    form.colorPicker({name: "formValuesTitleFontColor", label: "Axis title font color", default_value: qGlobalFontColor});
        form.numericUpDown({name: "formValuesTitleFontSize", label: "Axis title font size", default_value: 10, increment: 0.5, prompt: "Font size in points"});
}
form.comboBox({name: "formValuesTickFontFamily", label: "Axis tick font family", alternatives: font_families, default_value: qGlobalFontFamily, editable: true, prompt: "Select the font to use. You can also type the name of a font directly (including custom fonts)."});
form.colorPicker({name: "formValuesTickFontColor", label: "Axis tick font color", default_value: qGlobalFontColor});
    form.numericUpDown({name: "formValuesTickFontSize", label: "Axis tick font size", default_value: 9, increment: 0.5, prompt: "Font size in points"});

if (allow_control_groups)
    form.group("HOVERTEXT")
form.numericUpDown({name: "formHoverDecimals", label: "Decimal places", default_value: 3});

if (allow_control_groups)
    form.group("GRID LINES")
var gridWidth = form.numericUpDown({name: "formGridWidth", label: "Grid line width", default_value: 0.5, increment: 0.5}).getValue();
if (gridWidth > 0)
    form.colorPicker({name: "formGridColor", label: "Grid line color", default_value: "#D2D8E1"});
var zeroWidth = form.numericUpDown({name: "formZeroLineWidth", label: "Zero line width", default_value: 1, prompt: "Control width of line showing 'Utility = 0' place on top of the grid'"}).getValue();
if (zeroWidth > 0)
    form.colorPicker({name: "formZeroLineColor", label: "Zero line color", default_value: "#1C283B"});

if (allow_control_groups)
    form.group("MARGINS")
form.numericUpDown({name: "formMarginTop", label: "Top", default_value: 20, increment: 1, minimum: 0, maximum: 1000});
form.numericUpDown({name: "formMarginLeft", label: "Left", default_value: 80, increment: 1, minimum: 0, maximum: 1000});
form.numericUpDown({name: "formMarginBottom", label: "Bottom", default_value: 50, increment: 1, minimum: 0, maximum: 1000});
form.numericUpDown({name: "formMarginRight", label: "Right", default_value: 60, increment: 1, minimum: 0, maximum: 1000});
library(flipChoice)

# Read input
if (inherits(formInput[[1]], "FitChoice"))
{
    x <- formInput[[1]]
    if (length(formInput) > 1)
        warning("Only the first choice model was used for utilities plot")
    attributes <- names(x$attribute.levels)

} else if (is.numeric(formInput[[1]]) && length(formInput) == 1)
{ 
    x <- formInput[[1]]
    if (is.null(names(x)))
        stop("Input vector must have names in the format '<attribute>:<level>'")
    ind <- which(!grepl(":", names(x)))
    if (length(ind) > 0)
        stop("Names '", paste(colnames(x)[ind], collapse="', '"),
        "' do not have the expected format '<attribute>:<level>'")
    attributes <- names(flipChoice:::makeAttributeList(names(x)))

}  else if (!is.null(names(formInput[[1]])) && !is.null(names(formInput[[1]][[1]])))
{
    x <- formInput[[1]]
    if (length(formInput) > 1)
        warning("Only the first R output was used for utilities plot")
    attributes <- names(x)

} else
{
    x <- as.data.frame(formInput, check.names = FALSE)
    colnames(x) <- sapply(x, function(i) attr(i, "label"))
    ind <- which(!grepl(":", colnames(x)))
    if (length(ind) > 0)
        stop("Variables '", paste(colnames(x)[ind], collapse="', '"),
        "' do not have label names with the expected format '<attribute>:<level>'")
    attributes <- names(flipChoice:::makeAttributeList(colnames(x)))

}
    
# Set color palette
attributes <- setdiff(attributes, flipTransformations::TextAsVector(formExcludeAttr))
colors = flipChartBasics::ChartColors(length(attributes), formPalette,
    custom.color = get0("formCustomColor"), custom.gradient.start = get0("formCustomGradientStart"), 
    custom.gradient.end = get0("formCustomGradientEnd"), custom.palette = get0("formCustomPalette"),
    silent = TRUE, silent.single.color = TRUE)

# Create plot
utilities.plot <- Utilities(x, subset = QFilter, weights = QPopulationWeight,
    scaling = formScaling,
    levels.order = formLevelsOrder,
    attr.order = formAttributeOrder,                          
    exclude.attributes = formExcludeAttr,
    attr.levels.not.ordered = get0("formExcludeOrder", ifnotfound = ""),
    output = formChartType,
    colors = colors,
    line.width = get0("formLineWidth", ifnotfound = 0),
    global.font.family = formGlobalFontFamily,
    global.font.color = formGlobalFontColor,
    grid.width = formGridWidth,
    grid.color = get0("formGridColor", ifnotfound = 0),
    level.label.font.family = formLevelFontFamily,
    level.label.font.color = formLevelFontColor,
    level.label.font.size = formLevelFontSize,
    level.label.wrap = formLabelWrap,
    level.label.wrap.nchar = get0("formLabelWrapNchar"),
    values.minimum = if (sum(nchar(get0("formValuesMin"))) == 0) NULL else as.numeric(formValuesMin),
    values.maximum = if (sum(nchar(get0("formValuesMax"))) == 0) NULL else as.numeric(formValuesMax),
    values.title = formValuesTitle,
    values.title.font.family = get0("formValuesTitleFontFamily"),
    values.title.font.color = get0("formValuesTitleFontColor"),
    values.title.font.size = get0("formValuesTitleFontSize"),
    values.tick.font.family = get0("formValuesTickFontFamily"),
    values.tick.font.color = get0("formValuesTickFontColor"),
    values.tick.font.size = get0("formValuesTickFontSize"),
    values.zero.line.width = formZeroLineWidth,
    values.zero.line.color = get0("formZeroLineColor"),
    attr.tick.font.family = get0("formAttrFontFamily"),
    attr.tick.font.color = get0("formAttrFontColor"),
    attr.tick.font.size = get0("formAttrFontSize"),
    hovertext.decimals = formHoverDecimals,
    margin.top = formMarginTop,
    margin.bottom = formMarginBottom,
    margin.left = formMarginLeft,
    margin.right = formMarginRight,
    font.units = "pt")