Tables - Crosstabs
Jump to navigation
Jump to search
Displayr - Anything Menu
Displayr - New Page Menu
Displayr - Table Menu
Q Technical Reference
Q Technical Reference
Q Technical Reference
Q Technical Reference
Q Technical Reference > Setting Up Data > Creating New Variables
Q Technical Reference > Setting Up Data > Creating New Variables
Q Technical Reference > Updating and Automation > Automation Online Library
Q Technical Reference > Updating and Automation > JavaScript > QScript > QScript Examples Library
Q Technical Reference > Updating and Automation > JavaScript > QScript > QScript Examples Library > QScript Online Library
R Online Library
User Interface > Create Tables
Related Videos | |
---|---|
Part 4 of Creating Tables in Q (Video) |
Generate multiple crosstabs at the same time This QScript generates multiple crosstabs at the same time (also, see Tables - Banner Tables). This is an alternative to using the Basic Tables feature, which automatically flattens any two-dimensional (grid) questions.
Technical detail
You will be asked to select:
- The questions use in the rows of the tables (these will be placed in the Blue Drop-down Menu).
- The questions use in the columns of the tables (these will be placed in the Brown Drop-down Menu).
- Whether you would like to sort the tables based on their significance (p-values) and whether you would like to only show tables with p-values below the selected threshold.
- The statistic(s) to be shown on the generated tables. Statistics will only be shown where they make sense for the data selected in the rows and columns of the tables.
- (In Displayr only) An (optional) variable to use as a filter and an (optional) variable to use as a weight.
Any Pick One - Multi, Pick Any - Grid and Number - Grid questions will be copied and flattened before using them in a crosstab. The flattened copy will contain all of the cells from the original question in a single column or row.
How to apply this QScript
- Start typing the name of the QScript into the Search features and data box in the top right of the Q window.
- Click on the QScript when it appears in the QScripts and Rules section of the search results.
OR
- Select Automate > Browse Online Library.
- Select this QScript from the list.
Customizing the QScript
This QScript is written in JavaScript and can be customized by copying and modifying the JavaScript.
Customizing QScripts in Q4.11 and more recent versions
- Start typing the name of the QScript into the Search features and data box in the top right of the Q window.
- Hover your mouse over the QScript when it appears in the QScripts and Rules section of the search results.
- Press Edit a Copy (bottom-left corner of the preview).
- Modify the JavaScript (see QScripts for more detail on this).
- Either:
- Run the QScript, by pressing the blue triangle button.
- Save the QScript and run it at a later time, using Automate > Run QScript (Macro) from File.
Customizing QScripts in older versions
JavaScript
includeWeb("QScript Functions to Generate Outputs");
includeWeb('QScript Selection Functions');
includeWeb('QScript Table Functions');
includeWeb('QScript Utility Functions');
if (!main())
log("QScript cancelled.");
else
conditionallyEmptyLog("QScript finished.");
function main() {
// first condition makes sure Q.isOnTheWeb is defined
var web_mode = (!!Q.isOnTheWeb && Q.isOnTheWeb());
var ALLOWED_STATS_Q = ["%", "Column %", "Row %", "Total %", "Average",
"Median", "Index", "n", "Column n", "Row n", "Base n"];
var allowed_stats;
if (web_mode)
allowed_stats = ALLOWED_STATS_Q.map(function(s){ return project.translations.get(s); });
else
allowed_stats = ALLOWED_STATS_Q;
if (!requireDataFile()) {
return false;
}
var column_q_choices = [];
var row_q_choices = [];
if (project.dataFiles.length > 1)
var data_file = selectOneDataFile('There is more than one data file in your project. ' +
'Please select the data file to use:', project.dataFiles)
else
var data_file = project.dataFiles[0];
var row_q_choices = data_file.questions.filter(function (q) { return q.isValid && !q.isHidden && q.questionType.indexOf("Text") == -1 && !questionHasOnlyMissingValues(q)});
var column_q_choices = row_q_choices.filter(function (q) { return q.questionType != 'Ranking' && q.questionType != 'Experiment'});
if (row_q_choices.length == 0 || column_q_choices.length == 0) {
log("Not enough questions available to make crosstabs.")
return false;
}
var row_questions, column_questions;
while (!row_questions || !oneOrMoreQuestions(row_questions))
row_questions = selectManyQuestions('Please select data to place in the rows:', row_q_choices).questions;
while (!column_questions || !oneOrMoreQuestions(column_questions))
column_questions = selectManyQuestions('Please select data to place in the columns:', column_q_choices).questions;
// Sorting happens within each row by column variables, so if only one column variable, nothing to sort
if (column_questions.length === 1)
var show_opts = ["All tables", "Delete tables not significant at the 0.1 level",
"Delete tables not significant at the 0.05 level", "Delete tables not significant at the 0.01 level",
"Delete tables not significant at the 0.001 level", "Delete tables not significant at the 0.0001 level"];
else
var show_opts = ["All tables", "Sort tables by statistical significance of column data", "Delete tables not significant at the 0.1 level",
"Delete tables not significant at the 0.05 level", "Delete tables not significant at the 0.01 level",
"Delete tables not significant at the 0.001 level", "Delete tables not significant at the 0.0001 level",
"Sort and delete tables not significant at 0.1", "Sort and delete tables not significant at 0.05",
"Sort and delete tables not significant at 0.01", "Sort and delete tables not significant at 0.001",
"Sort and delete tables not significant at 0.0001"];
var show_opt_idx = selectOne("Show", show_opts, null, 0);
var selected_opt = show_opts[show_opt_idx];
var sort_tables = selected_opt.match("^Sort|^All tables sorted") !== null;
var delete_tables = selected_opt.match("[Dd]elete") !== null;
if (delete_tables)
var p_value_cutoff = selected_opt.match("0[.][0]{0,3}[15]")[0];
var stat_selection_text = "Which statistic would you like to show on the table? " +
"(Statistics will only be shown where they make sense " +
"for the data selected in the rows and columns of the tables.)";
var selected_stats_idx = selectMany(stat_selection_text, allowed_stats);
allowed_stats = ALLOWED_STATS_Q.filter(function(s,i){ return selected_stats_idx.includes(i);});
flattenSelectedQuestions(column_questions);
flattenSelectedQuestions(row_questions);
// Ask user for filter and weight variables
if (web_mode) {
var filter_questions = data_file.questions.filter(function isFilter(v){ return v.isFilter;});
if (filter_questions.length > 0) {
var filter_variables = filter_questions[0].variables
for (i = 1; i < filter_questions.length; i++)
filter_variables = filter_variables.concat(filter_questions[i].variables);
var filter_opts = ["Total Sample"];
filter_opts = filter_opts.concat(filter_variables.map(function getNames(v){ return v.label}));
var selected_filters = selectMany("Please select filter(s) to apply to each crosstab.", filter_opts, null, [0]);
if (selected_filters == 0)
selected_filters = "Total Sample";
else {
selected_filters = selected_filters.filter(function gt0(x){ return x > 0; });
selected_filters = selected_filters.map(function idx(x){return filter_variables[x-1];});
}
}else
var selected_filters = "Total Sample";
var weight_questions = data_file.questions.filter(function isWeight(v){ return v.isWeight;});
if (weight_questions.length > 0) {
var weight_variables = weight_questions[0].variables
for (i = 1; i < weight_questions.length; i++)
weight_variables = weight_variables.concat(weight_questions[i].variables);
var weight_opts = ["None"];
weight_opts = weight_opts.concat(weight_variables.map(function getNames(v){ return v.label}));
var selected_weight = selectOne("Please select a weight to apply to each crosstab.", weight_opts, null, 0);
if (selected_weight == 0)
selected_weight = "None"
else
selected_weight = weight_variables[selected_weight-1];
}else
var selected_weight = "None";
}
// check for large crosstabs
var q_pairs_large = [];
for (var i = 0; i < row_questions.length; i++) {
for (var j = 0; j < column_questions.length; j++) {
var row_q = row_questions[i];
var column_q = column_questions[j];
if (row_q.isValid && column_q.isValid && questionsYieldLargeCrosstab(row_q, column_q)) {
q_pairs_large.push('"' + row_q.name + ' and ' + column_q.name + '"');
}
}
}
// warn about large crosstabs
if (q_pairs_large.length == 1) {
var cancelled = !confirm('The question pair ' + q_pairs_large[0] +
' will result in a very large table.\n\n' +
'Very large tables are not likely to be interesting, will be slow to calculate ' +
'and will generate a warning message when viewed.\n\n' +
'Do you wish to continue?');
if (cancelled)
return false;
} else if (q_pairs_large.length > 1) {
var q_pairs_large_examples = '';
for (var i = 0; i < Math.min(3, q_pairs_large.length); i++) {
q_pairs_large_examples = q_pairs_large_examples + q_pairs_large[i] + '\n';
}
var cancelled = !confirm('There are ' + q_pairs_large.length + ' very large tables that will be created.\n\n' +
'Very large tables are not likely to be interesting, will be slow to calculate ' +
'and will generate a warning message when viewed.\n\n ' +
'Question pairs that will result in very large tables include:\n' + q_pairs_large_examples + '\n' +
'Do you wish to continue?');
if (cancelled)
return false;
}
var crosstabs = project.report.appendGroup();
crosstabs.name = 'Crosstabs';
var nr = row_questions.length;
var nc = column_questions.length;
var min_p_values = new Array(nr);
for (var i = 0; i < nr; i++) {
min_p_values[i] = new Array(nc);
}
for (var i = 0; i < nr; i++) {
// First compute corrected p-values to get sort order then add to do
for (var j = 0; j < nc; j++) {
if (web_mode) {
var page = crosstabs.appendPage("Item");
var table = page.appendTable();
}else
var table = crosstabs.appendTable();
table.primary = row_questions[i];
table.secondary = column_questions[j];
var default_stat = table.cellStatistics;
if (!addStat(table, 'Row %') * !addStat(table, 'n')) // non short-circuiting &&
if (!addStat(table, 'Column n'))
addStat(table, 'Row n');
var cell_stats = table.cellStatistics;
if (allowed_stats.length > 0)
cell_stats = allowed_stats;
else
cell_stats = default_stat;
addStat(table, 'Corrected p');
var p_values = getStatisticsFromTable(table, ['Corrected p']);
if (p_values === null) {
min_p_values[i][j] = 1;
}else {
p_values = p_values['Corrected p'];
min_p_values[i][j] = minWithReplacedNaN(p_values, Number.POSITIVE_INFINITY);
}
table.cellStatistics = cell_stats; // reset stats back to user selected values or the default statistic
if (web_mode) {
page.name = table.primary.name + ' by ' + table.secondary.name;
var title_text = page.subItems[0];
title_text.text = page.name;
if (selected_filters !== "Total Sample")
table.filters = selected_filters;
if (selected_weight !== "None")
table.weight = selected_weight;
}
}
}
// delete all the tables and recreate them in the sorted order only adding those with p-value below p_value_cutoff
if (sort_tables || delete_tables) {
crosstabs.deleteItem();
var crosstabs = project.report.appendGroup();
crosstabs.name = 'Crosstabs';
for (var i = 0; i < nr; i++) {
if (sort_tables) {
var table_order = order(min_p_values[i]);
}else {
var table_order = new Array(nc);
for (var j = 0; j < nc; j++)
table_order[j] = j;
}
for (var j = 0; j < nc; j++) {
var idx = table_order[j];
if (!delete_tables || min_p_values[i][idx] < p_value_cutoff) {
if (web_mode) {
var page = crosstabs.appendPage("Item");
var table = page.appendTable();
}else
var table = crosstabs.appendTable();
table.primary = row_questions[i];
table.secondary = column_questions[idx];
if (allowed_stats.length > 0)
table.cellStatistics = allowed_stats;
if (web_mode) {
page.name = table.primary.name + ' by ' + table.secondary.name;
var title_text = page.subItems[0];
title_text.text = page.name;
if (selected_filters !== "Total Sample")
table.filters = selected_filters;
if (selected_weight !== "None")
table.weight = selected_weight;
}
}
}
}
if (crosstabs.subItems.length == 0) {
crosstabs.deleteItem();
log("No tables are significant at p-value " + p_value_cutoff + ".");
return true;
}
}
if (fileFormatVersion() > 8.65)
project.report.setSelectedRaw([crosstabs.subItems[0]]);
conditionallyEmptyLog('Crosstabs have been added to the "' + crosstabs.name + '" group.');
return true;
}
// replicate R's order() function
// e.g. sortWithIndices(['b','c','a']) = [2,1,0]
function order(arr) {
var arr_with_index = [];
for (var i in arr) {
arr_with_index.push([arr[i], i]);
}
arr_with_index.sort(function(left, right) {
return left[0] - right[0];
});
var idxs = [];
for (var j in arr_with_index) {
// arr.push(arr_with_index[j][0]);
idxs.push(arr_with_index[j][1]);
}
return idxs;
}
function addStat(table, stat) {
cell_stats = table.cellStatistics;
cell_stats.push(stat);
table.cellStatistics = cell_stats;
return table.cellStatistics.indexOf(stat) > -1;
}
function oneOrMoreQuestions(questions) {
if (questions.length == 0) {
alert('Select one or more questions.');
return false;
} else
return true;
}
function questionHasOnlyMissingValues(q) {
var v = q.variables[0];
try {
var raw = v.rawValues;
}
catch(e) {
return true;
}
var all_missing = true;
for (var i = 0; i < raw.length; i++) {
if (!v.valueAttributes.getIsMissingData(raw[i])) {
all_missing = false;
break;
}
}
return all_missing;
}
See also
- QScript for more general information about QScripts.
- QScript Examples Library for other examples.
- Online JavaScript Libraries for the libraries of functions that can be used when writing QScripts.
- QScript Reference for information about how QScript can manipulate the different elements of a project.
- JavaScript for information about the JavaScript programming language.
- Table JavaScript and Plot JavaScript for tools for using JavaScript to modify the appearance of tables and charts.
Displayr - Anything Menu
Displayr - New Page Menu
Displayr - Table Menu
Q Technical Reference
Q Technical Reference
Q Technical Reference
Q Technical Reference
Q Technical Reference > Setting Up Data > Creating New Variables
Q Technical Reference > Setting Up Data > Creating New Variables
Q Technical Reference > Updating and Automation > Automation Online Library
Q Technical Reference > Updating and Automation > JavaScript > QScript > QScript Examples Library
Q Technical Reference > Updating and Automation > JavaScript > QScript > QScript Examples Library > QScript Online Library
R Online Library
User Interface > Create Tables