TURF - Incrementality Plot
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:
- 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.
- 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