This page contains copies of JavaScript Rule code that either existed as examples in the Q Wiki or is the code that the functions in Displayr and Q run on. It reflects the state of the code as of August 2023, and will not be updated after that date, although the in-app functions may change.
The code is given here for example purposes only, to learn from.
Abbreviate Month Labels for a Date/Time Question
Displayr - How to Abbreviate Month Labels in Tables
Q - How to Abbreviate Month Labels in Tables
// Abbreviate month labels in rows and columns of table
// All labels must be months for any replacements to be made
var row_labels = table.rowLabels;
var col_labels = table.columnLabels;
var months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
// Check row labels and update
var split_labels = row_labels.map(function (str) { return str.split(" ")[0]; });
if (split_labels.every( function (str) { return months.indexOf(str) > -1; })) {
split_labels = split_labels.map(function (str) { return str.substring(0, 3); });
table.rowLabels = split_labels;
}
// Check column labels and update
var split_labels = col_labels.map(function (str) { return str.split(" ")[0]; });
if (split_labels.every( function (str) { return months.indexOf(str) > -1; })) {
split_labels = split_labels.map(function (str) { return str.substring(0, 3); });
table.columnLabels = split_labels;
}
Adding Sample Size to the Column Labels
var do_java; // Prevent an error when no below_table exists
try {
do_java = below_table.availableStatistics.indexOf('Column n') != -1;
} catch (e) {
do_java = false;
}
if (table.numberColumns > 1 && do_java) {// If this table has the 'Column n' statistic
var column_ns = below_table.get('Column n');// Get the column n values
if (column_ns.length == 1)
column_ns = column_ns[0];
var column_labels = table.columnLabels;// Get the standard column labels.
for (var column = 0; column < table.numberColumns; column++) {// For each column...
// Adjust the label to include the column name and column n, on new lines.
column_labels[column] = column_labels[column] + '\r\n' + 'n = ' + column_ns[column];
}
// Set the adjusted column labels.
table.columnLabels = column_labels;
}How to Add Sample Size to Column Labels in a Table
Displayr - How to Add Sample Size to Column Labels in a Table
Q - How to Add Sample Size to Column Labels in a Table
var do_java; // Prevent an error when no below_table exists
try {
do_java = below_table.availableStatistics.indexOf('Column n') != -1;
} catch (e) {
do_java = false;
}
if (table.numberColumns > 1 && do_java) {// If this table has the 'Column n' statistic
var column_ns = below_table.get('Column n');// Get the column n values
if (column_ns.length == 1)
column_ns = column_ns[0];
var column_labels = table.columnLabels;// Get the standard column labels.
for (var column = 0; column < table.numberColumns; column++) {// For each column...
// Adjust the label to include the column name and column n, on new lines.
column_labels[column] = column_labels[column] + '\r\n' + 'n = ' + column_ns[column];
}
// Set the adjusted column labels.
table.columnLabels = column_labels;
}How to Add a Column Header Footnote Indicating Small Sample Sizes
Displayr - How to Add a Column Header Footnote Indicating Small Sample Sizes
Q - How to Add a Column Header Footnote Indicating Small Sample Sizes
var column_ns = table.get('Column n');// Get the Column N statistics.
var column_labels = table.columnLabels;// Get the column labels.
var footnotes = table.extraFooters;// Make a list of extra footnotes.
for (var column = 0; column < table.numberColumns; column++) {// For each column...
var column_n = column_ns[0][column];// Get the column n statistic (from the cell in the first row).
if (column_n < 30) {
footnotes.push('* column "' + column_labels[column] + '" has less than 30 respondents.');// Add an extra footnote.
column_labels[column] += '*';// Put a marker on this column's label.
}
}
table.columnLabels = column_labels;// Store the adjusted column labels and footnotes.
table.extraFooters = footnotes;How to Add a Footnote for Cells with Small Sample Sizes
Displayr - How to Add a Footnote for Cells with Small Sample Sizes
Q - How to Add a Footnote for Cells with Small Sample Sizes
if (table.availableStatistics.indexOf('Column n') != -1)
table.addFootNoteForCellsLessThan('Column n', 20, '*', '* sample size < 20');
else
table.addFootNoteForCellsLessThan('Base n', 20, '*', '* sample size < 20');How to Automatically Remove NETs From Tables
Displayr - How to Automatically Remove NETs from Tables
Q - How to Automatically Remove NETs from Tables
includeWeb("Table JavaScript Utility Functions");
// Delete any NET columns
var n_deleted_cols = 0;
table.netColumns.forEach(function (net_col) {
deleteColumnComplete(net_col - n_deleted_cols);
n_deleted_cols++;
});
// Delete any NET rows
var n_deleted_rows = 0;
table.netRows.forEach(function (net_row) {
deleteRowComplete(net_row - n_deleted_rows);
n_deleted_rows++;
});Modify Cell Content - Blank Cells with Small Sample Sizes
Displayr - How to Blank Table Cells with Small Sample Sizes
Q - How to Blank Table Cells with Small Sample Sizes
This rule script exists in two versions, one that is very simple and one that includes a user interface. The latter is published in-app.
Simple Code
var min_sample_size = 10
var column_ns = table.get('Column n');// Get column sample sizes.
var extra_footers = table.extraFooters;// Store the extra footnotes we generate for each blank column.
for (var column = 0; column < table.numberColumns; column++) {// loop through the columns
for (var row = 0; row < table.numberRows; row++) {
// Get the sample size for this cell
var column_n = column_ns[row][column];
// If the column's sample size is less than min_sample_size, make each cell in the column blank.
if (column_n < min_sample_size) {
table.blankCell(row, column);
// Also, add a footnote that explains why some columns are missing.
extra_footers.push('Column "' + table.columnLabels[column]
+ " is blank because less than " + min_sample_size + " people were asked the question.");
}
}
}
// Set the extra footnotes.
table.extraFooters = extra_footers;Code with User Interface
let stat_name = table.getTranslation('Column n');
let grid_stat_name = table.getTranslation('Base n');
let stat_to_use = 'Column n';
if (table.availableStatistics.indexOf('Column n') == -1 && table.availableStatistics.indexOf('Base n') == -1)
form.ruleNotApplicable('this format only applies to tables with the ' +
stat_name + ' or ' + grid_stat_name + ' statistics');
if (table.availableStatistics.indexOf('Column n') == -1){
stat_name = grid_stat_name;
stat_to_use = 'Base n';
}
// Set up controls for user input.
form.setHeading('Blank Cells With Small Sample Sizes:');
let description = form.newLabel("Prevent results from being shown when the column sample size falls below a specified value.");
description.lineBreakAfter = true;
let label = form.newLabel('Minimum ' + stat_name + ':');
let numeric_up_down = form.newNumericUpDown('threshold');
numeric_up_down.setDefault(30);
numeric_up_down.setIncrement(1);
numeric_up_down.setMaximum(999999999);
numeric_up_down.lineBreakAfter = true;
let nan_checkbox = form.newCheckBox("cbnan", "Also set values of first table statistic to NaN");
nan_checkbox.setDefault(true);
form.setInputControls([description, label, numeric_up_down, nan_checkbox]);
let min_column_n = numeric_up_down.requireValue();
form.setSummary('Blank cells where ' + stat_name + ' < ' + min_column_n);
let primary_statistic = table.get(table.statistics[0]);
let blank_flag = false; // Keep track of whether any cells have been blanked.
let column_ns = table.get(stat_to_use);// Get column sample sizes.
for (let column = 0; column < table.numberColumns; column++) {// loop through the columns
for (let row = 0; row < table.numberRows; row++) {
// Get the sample size for this cell
let column_n = column_ns[row][column];
// If the column's sample size is less than min_column_n, make each cell in the column blank.
if (column_n < min_column_n) {
table.blankCell(row, column);
primary_statistic[row][column] = NaN;
blank_flag = true;
}
}
}
if (nan_checkbox.getValue())
table.set(table.statistics[0], primary_statistic);
if (blank_flag) {
let extra_footers = table.extraFooters;// Store the extra footnotes we generate for each blank column.
extra_footers.push('Blank cells have a sample size that is smaller than ' + min_column_n + '.');
// Set the extra footnotes.
table.extraFooters = extra_footers;
}Modify Cell Content - Blank Cells with Small Values
Q - Modify Cell Content - Blank Cells with Small Values
includeWeb('JavaScript Utilities');
includeWeb('Table JavaScript Utility Functions');
let stats = difference(_GLOBAL_STAT_LIST, _COLUMN_COMPARISON_STATS);
let translated_stats = translateStats(stats);
// Set up controls for user input.
form.setHeading('Blank Cells with Small Values');
let description = form.newLabel("Prevents results from being shown within cells when they fall below a specified value.");
description.lineBreakAfter = true;
let label_stats = form.newLabel('Choose a cell statistic:');
let combobox_stats = form.newComboBox('stats', translated_stats);
combobox_stats.setDefault(translated_stats[0]);
combobox_stats.lineBreakAfter = true;
let label = form.newLabel('Minimum Value:');
let numeric_up_down = form.newNumericUpDown('threshold');
numeric_up_down.setDefault(30);
numeric_up_down.setIncrement(1);
numeric_up_down.lineBreakAfter = true;
let nan_checkbox = form.newCheckBox("cbnan", "Also set values of statistic to NaN");
nan_checkbox.setDefault(true);
form.setInputControls([description, label_stats,combobox_stats,label, numeric_up_down, nan_checkbox]);
//form.setOutputControls([]);
let selected_stat_translated = combobox_stats.requireValue();
let selected_statistic = stats[translated_stats.indexOf(selected_stat_translated)];
let min_value = numeric_up_down.requireValue();
form.setSummary('Blank cells where ' + selected_stat_translated + ' < ' + min_value);
if (table.availableStatistics.indexOf(selected_statistic) == -1)
form.ruleNotApplicable(selected_stat_translated + " is not available on this table");
let blank_flag = false; // Keep track of whether any cells have been blanked.
let values = table.get(selected_statistic);// Get statistic values in all the cells
for (let column = 0; column < table.numberColumns; column++) {// loop through the columns
for (let row = 0; row < table.numberRows; row++) {
let stat_value = values[row][column];
// If the cells selected statistics is less than min_value, make each cell blank.
if (stat_value < min_value) {
table.blankCell(row, column);
values[row][column] = NaN;
blank_flag = true;
}
}
}
if (nan_checkbox.getValue())
table.set(selected_statistic, values);
// Store the extra footnotes we generate for each blank cell.
if (blank_flag) {
let extra_footers = table.extraFooters;
extra_footers.push('Blank cells have ' + selected_stat_translated +
' that is smaller than ' + min_value + '.');
table.extraFooters = extra_footers;
}Modify Cell Content - Change Color of Cells with Small Sample Sizes
Displayr - How to Change the Color of Table Cells with Small Sample Sizes
Q - How to Change the Color of Table Cells with Small Sample Sizes
let stat_name = table.getTranslation('Column n');
if (table.availableStatistics.indexOf('Column n') == -1)
form.ruleNotApplicable('this format only applies to tables with the ' +
stat_name + ' statistic');
// Set up controls for user input.
form.setHeading('Change the Color of Cells With Small Sample Sizes');
let description = form.newLabel('Choose a color to apply to cells when the ' + stat_name + ' is smaller than a specified value');
description.lineBreakAfter = true;
let label = form.newLabel('Minimum ' + stat_name + ':');
let numeric_up_down = form.newNumericUpDown('threshold');
numeric_up_down.setDefault(30);
numeric_up_down.setIncrement(1);
numeric_up_down.setMaximum(999999999);
numeric_up_down.lineBreakAfter = true;
let color_label = form.newLabel("Color:");
let color_picker = form.newColorPicker('color');
color_picker.setDefault('Pink');
form.setInputControls([description, label, numeric_up_down, color_label, color_picker]);
let min_column_n = numeric_up_down.requireValue();
form.setSummary('Change color of cells where ' + stat_name + ' < ' + min_column_n);
let color_to_use = color_picker.getValue();
// Figure out which cells need to be highlighted
let column_ns = table.get('Column n');// Get column sample sizes.
let colors = table.cellColors; // Obtain the current cell colors.
let color_flag = false; // Keep track of whether any cells have been highlighted.
let extra_footers = table.extraFooters;// Store the extra footnotes we generate for each blank column.
for (let column = 0; column < table.numberColumns; column++) {// loop through the columns
for (let row = 0; row < table.numberRows; row++) {
// Get the sample size for this cell
let column_n = column_ns[row][column];
// If the column's sample size is less than min_sample_size, make each cell in the column blank.
if (column_n < min_column_n) {
colors[row][column] = color_to_use;
color_flag = true;
}
}
}
// Apply changes to the table
if (color_flag) {
table.cellColors = colors; // Set the new table colors
extra_footers.push('Shaded cells have a sample size that is smaller than ' + min_column_n + '.');
// Set the extra footnotes.
table.extraFooters = extra_footers;
}Modify Cell Content - Change Missing Data (NaN) Symbol
Displayr - Modify Cell Content - Change Missing Data (NaN) Symbol
Q - Modify Cell Content - Change Missing Data (NaN) Symbol
table.requireNumericTable();
// Set up controls for user input.
form.setHeading('Changing the Missing Data (NaN) Symbol');
let description = form.newLabel("Choose a symbol or text to use in table cells instead of showing 'NaN'");
description.lineBreakAfter = true;
let label_text = form.newLabel('Replace with:');
let text_box = form.newTextBox('text');
text_box.setDefault('-');
form.setInputControls([description, label_text, text_box]);
let text = text_box.getValue();
form.setSummary('Replace missing data (NaN) with "' + text + '"');
table.showMissingAs(text);Modify Cell Content - Add Text to Cells with Large Numbers
Displayr - Add Text to Cells with Large Numbers
Q - Add Text to Cells with Large Numbers
This rule script exists in two versions, one which is very simple and one which includes a user interface. The latter is published in-app.
Simple Code
// Display an exclamation point next to the first statistic in each cell, if it is over 80.
let cutoff = 80;
// Get the values for the first statistic shown on the table.
var values = table.get(table.statistics[0]);
// Get the default text in each cell in the table.
var cell_texts = table.cellText;
// Loop through each cell...
for (var row = 0; row < table.numberRows; row++)
for (var column = 0; column < table.numberColumns; column++) {
var value = values[row][column];
if (value > cutoff) {
// Put an exclamation point next to the first statistic.
cell_texts[row][column] = ['!'];
}
}
// Now store the new cell texts.
table.cellText = cell_texts;Code with User Interface
includeWeb('Table JavaScript Utility Functions');
table.requireNumericTable();
// Set up controls for user input.
form.setHeading('Adding Text to Cells with Large Numbers:');
let description = form.newLabel("Add symbols or text to cells with large values");
description.lineBreakAfter = true;
let label_statistic = form.newLabel('Statistic to use:');
let translated_statistics = translateStats(table.statistics);
let combo_box = form.newComboBox('statistic', translated_statistics);
combo_box.setDefault(translated_statistics[0]);
combo_box.lineBreakAfter = true;
let label_threshold = form.newLabel('Threshold:');
let numeric_up_down = form.newNumericUpDown('threshold');
numeric_up_down.setDefault(20);
numeric_up_down.setIncrement(1);
numeric_up_down.setMaximum(999999999);
numeric_up_down.lineBreakAfter = true;
let label_text = form.newLabel('Text to append:');
let text_box = form.newTextBox('text');
text_box.setDefault('!');
form.setInputControls([description, label_statistic, combo_box, label_threshold, numeric_up_down, label_text, text_box]);
let statistic_translated = combo_box.getValue();
let statistic = table.statistics[translated_statistics.indexOf(statistic_translated)];
let threshold = numeric_up_down.getValue();
let text = text_box.getValue();
form.setSummary('Append "' + text + '" to cells with ' + statistic_translated + ' larger than ' + threshold);
// Move chosen statistic to top
let stats = table.statistics;
stats.splice(stats.indexOf(statistic), 1);
stats.splice(0, 0, statistic);
table.statistics = stats;
// Get the values for statistic
let values = table.get(statistic);
// Get the default text in each cell in the table.
let cell_texts = table.cellText;
// Loop through each cell...
for (let row = 0; row < table.numberRows; row++)
for (let column = 0; column < table.numberColumns; column++) {
let value = values[row][column];
if (value > threshold) {
// Append text next to the first statistic.
cell_texts[row][column] = [text];
}
}
// Now store the new cell texts.
table.cellText = cell_texts;Modify Cell Content - Color Selected Rows or Columns
Displayr - How to Color Selected Rows or Columns in a Table
Q - How to Color Selected Rows or Columns in a Table
// Color selected rows or columns
includeWeb('JavaScript Array Functions');
form.setHeading('Color Selected Rows or Columns');
let description = form.newLabel('Choose colors for rows or columns in the table');
description.lineBreakAfter = true;
const no_selection_string = '(none)';
// Color rows or columns?
let color_label = form.newLabel("Color:")
let color_options = ["Rows", "Columns"];
let color_rows_or_columns_box = form.newComboBox('columnOrRow', color_options);
color_rows_or_columns_box.setDefault(color_options[0]);
color_rows_or_columns_box.lineBreakAfter = true;
let color_columns = color_rows_or_columns_box.getValue() == color_options[1];
let controls = [description, color_label, color_rows_or_columns_box];
form.setSummary('Color selected ' + color_rows_or_columns_box.getValue().toLowerCase());
// If coloring columns, table must be two-dimensional.
if (color_columns && table.columnLabels == null)
form.ruleNotApplicable('the columns in this table are statistics');
// Trim column/row labels and change column/row labels that collide with no_selection_string
let col_row_combobox_alternatives = (color_columns ? table.columnLabels : table.rowLabels).map(function (label) {
return label.trim();
}).map(function (label) {
if (label == no_selection_string)
return label + (color_columns ? ' (column)' : ' (row)');
else
return label;
});
col_row_combobox_alternatives = [no_selection_string].concat(enumerateDuplicatesInStringArray(col_row_combobox_alternatives, '(', ')'));
let selected_cols_rows = [];
let selected_colors = [];
let default_color = "AliceBlue";
let last_index = 0;
let current_index = 0;
let col_row_label = color_columns ? 'Column:' : 'Row:';
while (true) {
let col_row_combobox = form.newComboBox((color_columns ? 'column' : 'row') + current_index, col_row_combobox_alternatives);
col_row_combobox.setDefault(no_selection_string);
let selected_col_row = col_row_combobox.getValue();
controls.push(form.newLabel(col_row_label));
controls.push(col_row_combobox);
if (selected_col_row == no_selection_string) // stop adding when the combobox selection is null
break;
else { // only add comboboxes with a column/row selected
controls.push(form.newLabel('Color:'));
let color_picker = form.newColorPicker('color' + current_index)
color_picker.setDefault(default_color);
color_picker.lineBreakAfter = true;
let selected_color = color_picker.getValue();
controls.push(color_picker);
selected_cols_rows.push(selected_col_row);
selected_colors.push(selected_color);
last_index = current_index + 1;
}
current_index++;
}
form.setInputControls(controls);
// Do the coloring
let cell_colors = table.cellColors;
let indices_to_color = selected_cols_rows.map(function (label) { return col_row_combobox_alternatives.indexOf(label) - 1; });
indices_to_color.forEach(function (x, ind) {
let current_color = selected_colors[ind];
if (color_columns) {
for (let row = 0; row < table.numberRows; row++)
cell_colors[row][x] = current_color;
} else {
for (let col = 0; col < table.numberColumns; col++)
cell_colors[x][col] = current_color;
}
});
table.cellColors = cell_colors;Modify Cell Content - Highlight Cells Above and Below NET
Displayr - How to Highlight Table Cells Above and Below the NET
Q - How to Highlight Table Cells Above and Below the NET
includeWeb('QScript Utility Functions');
includeWeb('Table JavaScript Utility Functions');
table.requireNumericTable();
// Set up controls for user input.
form.setHeading('Highlighting Cells Above and Below NET');
let description = form.newLabel('Add color to cells whose value is greater or lower than the value in the NET column');
description.lineBreakAfter = true;
let label_statistic = form.newLabel('Statistic to use:');
let translated_statistics = translateStats(table.statistics);
let combo_box = form.newComboBox('statistic', translated_statistics);
combo_box.setDefault(translated_statistics[0]);
combo_box.lineBreakAfter = true;
let label_threshold = form.newLabel('Threshold (%):');
let numeric_up_down = form.newNumericUpDown('threshold');
numeric_up_down.setDefault(20);
numeric_up_down.setIncrement(1);
numeric_up_down.lineBreakAfter = true;
let color_picker_1 = form.newColorPicker('color1');
let color_picker_2 = form.newColorPicker('color2');
color_picker_1.setDefault('PaleGreen');
color_picker_1.lineBreakAfter = true;
color_picker_2.setDefault('Pink');
let color_label_1 = form.newLabel('Higher values:');
let color_lable_2 = form.newLabel('Lower values:');
let statistic_translated = combo_box.getValue();
let statistic = table.statistics[translated_statistics.indexOf(statistic_translated)];
let percent = numeric_up_down.getValue();
form.setInputControls([label_statistic, combo_box, label_threshold, numeric_up_down, color_label_1, color_picker_1, color_lable_2, color_picker_2])
form.setOutputColors([color_picker_1.getValue(), color_picker_2.getValue()]);
form.setSummary('Highlight cells with ' + statistic_translated +
' that is ' + percent + '% above and below NET');
// Get the statistic's values.
let values = table.get(statistic);
if (table.brownQuestion.isBanner && table.netColumns.length == 0) {
let banner_message = 'the banner does not have an overall NET column. '
+ 'To add an overall NET, '
+ (inDisplayr() ? 'select the table and then select "Add overall NET" on the right'
: 'edit the banner and select "Add overall NET"');
form.ruleNotApplicable(banner_message);
}
if (!table.columnLabels)
form.ruleNotApplicable('this table does not have a suitable NET');
// Work out the orientation of the table.
let by_columns;
let net_row;
let net_column;
let net_rows = table.netRows;
if (net_rows.length > 0 && values[net_rows[0]][0] != 100.0) {
net_row = net_rows[0];
by_columns = true;
} else {
let net_columns = table.netColumns;
if (net_columns.length > 0 && values[0][net_columns[0]] != 100.0) {
net_column = net_columns[0];
by_columns = false;
} else
form.ruleNotApplicable('this table does not have a suitable NET');
}
// Get the array of cell colors (currently blank, or white).
let cell_colors = table.cellColors;
let upper_threshold = 1 + percent / 100;
let lower_threshold = 1 - percent / 100;
for (let row = 0; row < table.numberRows; row++)
for (let column = 0; column < table.numberColumns; column++) {
let value = values[row][column];
let NET_value = by_columns ? values[net_row][column] : values[row][net_column];
let ratio = value / NET_value;
if (ratio >= upper_threshold)
cell_colors[row][column] = color_picker_1.getValue();
else if (ratio <= lower_threshold)
cell_colors[row][column] = color_picker_2.getValue();
}
// Set the array of cell colors we just modified.
table.cellColors = cell_colors;