TURF - Incrementality Plot

From Q
Jump to navigation Jump to search

Creates a waterfall chart showing the incremental effect of additional alternatives across TURF portfolios. Our TURF eBook contains more information on how to interpret and use this visualization.

Example

Usage

In order to create this chart you first need to create two or more TURF analysis outputs. See TURF - TURF Analysis.

In Displayr, go to Insert > More > TURF > Incrementality Plot

In Q, go to Automate > Browse Online Library > TURF > Incrementality Plot

In the object inspector on the right of the screen, select the turf outputs that you have already created, making sure that they're selected in order such that the first item selected has the fewest alternatives in the top portfolio, and the second item selected has the next fewest alternatives, and so on.

Technical details

If the error message of This plot only makes sense when each additional portfolio includes the alternatives in the previous smaller portfolios appears, check that:

  1. You have selected the TURFs in order, with the TURF with the smallest portfolio size first, followed by the TURF with one more alternative second, etc.
  2. Each top portfolio in each of the TURFs includes all the alternatives from the winning smaller portfolios.

More information

See our webinar here: Making TURF for New Product Development Awesome in Less than 20 Mins.

See also our detailed eBook: How to Use TURF to Optimize Product Portfolios

Options

TURFs The results of TURF analyses, in order (smallest first).

Chart > COLOR > Increment The color of incremental contributions.

Chart > COLOR > Connector The color of connectors joining the incremental contributions.

Chart > COLOR > Total The color of the total column.

Chart > FONT Global settings for the font family, color, and size.

Chart > DATA LABELS Settings for the font family, color, and size of the data labels.

Chart > CATEGORIES (X) AXIS Settings for the font family, color, and size of the horizontal axis .

Chart > VALUES (Y) AXIS Settings for the font family, color, and size of the vertical axis .

Acknowledgements

Uses plotly.

Code

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

var allow_control_groups = Q.fileFormatVersion() > 10.9;
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"];

form.dropBox({name: "formTURFs",
              label: "TURFs",
              types:["RItem:TURF"],
              multi: true,
              min_inputs: 2,
              required: true})
form.page("Chart")
form.group("COLOR")
form.colorPicker({name: "formIncrementColor", 
                  label: "Increment",
                  default_value: "#B1CBEB"})
form.colorPicker({name: "formConnectorColor", 
                  label: "Connector",
                  default_value: "#B1CBEB"})
form.colorPicker({name: "formTotalColor", 
                  label: "Total",
                  default_value: "#3E7DCC"})
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();
var qGlobalFontUnit = form.comboBox({name: "formFontUnits", label: "Font units", default_value: "pt", alternatives: ["px", "pt"], prompt: "Specify font sizes in pt or px"}).getValue();

if (allow_control_groups)
    form.group("DATA LABELS");
if (true)
{
    form.comboBox({name: "formDataLabelFontFamily", label: "Data 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: "formDataLabelFontColor", label: "Data label font color", default_value: qGlobalFontColor});
    form.numericUpDown({name: "formDataLabelFontSize", label: "Data label font size", default_value: 8, increment: 0.5});
    form.numericUpDown({name: "formDataLabelBgOpacity", label: "Data label background opacity", default_value: 0.5, minimum_value: 0.0, maximum_value: 1.0, increment: 0.05});
}
if (allow_control_groups)
    form.group("CATEGORIES (X) AXIS")
form.comboBox({name: "formXAxisTickFontFamily", label: "X axis 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: "formXAxisTickFontColor", label: "X axis label font color", default_value: qGlobalFontColor});
form.numericUpDown({name:"formXAxisTickFontSize", label: "X axis label font size", default_value: 9, increment: 0.5});

if (allow_control_groups)
    form.group("VALUES (Y) AXIS")
form.comboBox({name: "formYAxisTitleFontFamily", label: "Y title 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: "formYAxisTitleFontColor", label: "Y title label font color", default_value: qGlobalFontColor});
form.numericUpDown({name:"formYAxisTitleFontSize", label:"Y title label font size", default_value: 10, increment: 0.5});
# Exracting the data
tables = lapply(formTURFs, function(x) attr(x, "ChartData")[1,, drop = FALSE])
reach = sapply(tables, function(x) x[1, 1]) * 100
portfolios = sapply(tables, function(x) rownames(x)[1])
alts = lapply(formTURFs, function (x) { x$alternative.names[x$portfolios[1,]]})            
n = length(reach)
x =  reach - c(0, reach[-n]) # Incremental reach
# Identifing the incremental alternatives 
names(x)[1] = portfolios[1]
for (i in 2:length(reach)) {
    extra = alts[[i]][! alts[[i]] %in% alts[[i - 1]]]
    if (length(extra) != 1)
        stop("This plot only makes sense when each additional portfolio includes the alternatives in the previous smaller portfolios.")
    names(x)[i] = extra}
# Creating the plot 
library(plotly)
font.scale <- if (formFontUnits == "pt") 1.3333 else 1.0
measure = c(rep("relative", n), "total")
text = c(paste0("+", round(x, 1), "%"), paste0(round(reach[n], 1), "%"))
y = c(x / 100, 0)
x = c(names(x), "Total")
global.font <- list(family = "Impact", color = "red", size = 8)
incrementality.plot = plot_ly(data = data.frame(x = factor(x, levels = x), measure, text, y),
             type = "waterfall", 
             increasing = list(marker = list(color = formIncrementColor)),
             connector = list(line = list(color= formConnectorColor)),
             totals = list(marker = list(color = formTotalColor)),
             measure = ~measure,
             x = ~x, textposition = "outside", y= ~y, 
             text =~text, textfont = list(family=formDataLabelFontFamily, color=formDataLabelFontColor, size = formDataLabelFontSize * font.scale), 
             cliponaxis = FALSE) %>% 
        config(displayModeBar = FALSE)  %>% 
        layout(title = "",
                    xaxis = list(title = "", tickfont = list(family=formXAxisTickFontFamily, color=formXAxisTickFontColor, size = formXAxisTickFontSize * font.scale)),
                    yaxis = list(title = "Reach", titlefont = list(family=formYAxisTitleFontFamily, color=formYAxisTitleFontColor, size = formYAxisTitleFontSize * font.scale),
                                 zeroline = FALSE,
                                 showline = FALSE,
                                 showticklabels = FALSE,
                                 showgrid = TRUE,
                                 hoverformat = "%", font = global.font),
                    autosize = TRUE,
                    showlegend = FALSE)
incrementality.plot$sizingPolicy$browser$padding <- 0
incrementality.plot