QScript Functions for Raw Data
Jump to navigation
Jump to search
This page is currently under construction, or it refers to features which are under development and not yet available for use.
This page is under construction. Its contents are only visible to developers!
function variableSetRawDataTable() {
let is_displayr = (!!Q.isOnTheWeb && Q.isOnTheWeb());
let variable_set_label = is_displayr ? "variable set" : "question";
let selected_questions = project.report.selectedQuestions();
if (selected_questions.length == 0)
{
if (is_displayr)
log("No data has been selected. Please select data in 'Data Sets' and then click this option again.");
else
log("No data has been selected. Please select data in the 'Variables and Questions' tab and then click this option again.");
return;
}
let group_for_output = groupForOutput();
let valid_questions = selected_questions.filter(hasRawData);
let invalid_questions = selected_questions.filter(q => !hasRawData(q));
addOutputsToDocument(valid_questions, group_for_output)
if (invalid_questions.length == 1)
log("A raw data table could not be created for the following selected " + variable_set_label + ": " +
invalid_questions[0].name +
" as it was either invalid, hidden or an Experiment or Ranking " + variable_set_label + ".");
else if (invalid_questions.length > 1)
log("Raw data tables could not be created for the following selected " + variable_set_label + "s: " +
invalid_questions.map(x => x.name).join(", ") +
" as they were either invalid or hidden.");
}
function groupForOutput() {
let is_displayr = (!!Q.isOnTheWeb && Q.isOnTheWeb());
let page = project.currentPage === undefined ? false : project.currentPage();
if (!page) {
if (is_displayr) {
let page = project.report.appendPage("Blank");
page.name = "Raw data";
}else
page = project.report;
}
return page;
}
function hasRawData(question) {
return !question.isHidden && question.isValid &&
!["Experiment", "Ranking"].includes(question.variableSetStructure);
}
function addRawTable(question, group, top, left, height, width) {
let table = group.appendTable();
table.primary = question;
table.secondary = "RAW DATA";
table.top = top;
table.left = left;
table.height = height;
table.width = width;
return table;
}
function addOutputsToDocument(questions, page) {
const ROW_LABEL_COL_WIDTH = 60;
const VARIABLE_COL_WIDTH = 85;
const max_variables_per_row = Math.floor((page.width - ROW_LABEL_COL_WIDTH)/VARIABLE_COL_WIDTH);
let output_positions = calculateOutputPositions(questions, page,
max_variables_per_row);
let tops, lefts, height, widths, question_order;
if (output_positions == null) {
// too many variable sets for one page, create another
let new_page = page.appendGroup();
new_page.name = "Additional Raw Data Tables";
addOutputsToDocument(questions.slice(0,Math.floor(questions.length/2)),page);
addOutputsToDocument(questions.slice(Math.floor(questions.length/2)),new_page);
return;
}else {
tops = output_positions.top;
lefts = output_positions.left
height = output_positions.height;
widths = output_positions.width;
question_order = output_positions.question_order;
}
let added_outputs = question_order.map(function(question_index, index) {
return addRawTable(questions[question_index], page, tops[index], lefts[index], height, widths[index]);
});
if (added_outputs.length > 0)
project.report.setSelectedRaw([added_outputs[added_outputs.length - 1]]);
return;
}
// Returns a permutation which sorts the input array into descending order
function order(arr) {
let idxs = new Array(arr.length);
for (let i = 0; i < arr.length; i++)
idxs[i] = i;
idxs.sort((a,b) => arr[b] - arr[a]);
return idxs;
}
// Reorder an array, arr, according to the indices in the array, new_order
function reorder(arr,new_order) {
let out = [];
let idxs = new Array(arr.length);
for (let i = 0; i < arr.length; i++)
idxs[i] = i;
for (let i = 0; i < arr.length; i++){
out.push(arr[idxs.indexOf(new_order[i])]);
}
return out;
}
function calculateOutputPositions(questions, page, max_variables_per_output) {
const ROW_LABEL_COL_WIDTH = 60;
const VARIABLE_COL_WIDTH = 85;
const MARGIN_LEFT = 10;
const MARGIN_TOP = 5;
const MIN_OUTPUT_HEIGHT = 140;
const page_height = page.height;
const page_width = page.width;
const has_title = page.subItems.length > 0 && page.subItems[0].type === "Text";
const title_height = has_title ? page.subItems[0].height + page.subItems[0].top : 0;
const max_rows = Math.floor((page_height - title_height)/MIN_OUTPUT_HEIGHT);
let n_vars = questions.map(q => q.variables.length);
let widths_needed = n_vars.map(n => ROW_LABEL_COL_WIDTH + Math.min(n, max_variables_per_output)*VARIABLE_COL_WIDTH + MARGIN_LEFT);
let width_order = order(widths_needed);
widths_needed = reorder(widths_needed,width_order);
n_vars = reorder(n_vars,width_order);
let current_row = 0;
let lefts = [0];
let widths = [widths_needed.shift()];
let question_order = [width_order.shift()];
let rows = [0];
let current_left = widths[0];
for (let i = 1; i < questions.length; i++) {
next_index = widths_needed.findIndex(w => page_width - MARGIN_LEFT - current_left - w > 0);
if (next_index > -1) {
widths.push(widths_needed[next_index]);
lefts.push(current_left);
current_left += widths_needed[next_index];
question_order.push(width_order[next_index]);
widths_needed.splice(next_index,1);
width_order.splice(next_index,1);
}else { // place output with most remaining variables on new row
current_row++;
widths.push(widths_needed.shift());
lefts.push(0);
current_left = widths[widths.length - 1];
question_order.push(width_order.shift());
}
if (current_row >= max_rows) {
// reduce max allowed width of VS with many variables and try again
if (max_variables_per_output === 2)
return;
else
return(calculateOutputPositions(questions,page,max_variables_per_output-1));
}
rows.push(current_row);
}
lefts = distributeOutputsHorizontally(page,rows,lefts,widths);
let tops = [];
let height = (page_height - title_height - current_row*MARGIN_TOP)/(current_row+1);
let current_top = 0;
for (let i = 0; i < questions.length; i++)
tops.push(title_height + rows[i]*(height+MARGIN_TOP));
return {top: tops, left: lefts, height: height, width: widths,question_order: question_order};
}
function distributeOutputsHorizontally(page, rows, lefts, widths) {
const page_width = page.width;
let new_lefts = [];
let row_lefts, last_width_in_row, n_outputs_in_row, idx;
idx = 0;
for (let i = 0; i <= rows[rows.length - 1]; i++) {
row_lefts = lefts.filter((l,idx) => rows[idx] == i);
n_outputs_in_row = row_lefts.length
last_width_in_row = widths[rows.lastIndexOf(i)];
remaining_width = page_width - last_width_in_row - row_lefts[n_outputs_in_row - 1];
for (let j = 1; j <= row_lefts.length; j++) {
new_lefts.push(lefts[idx]+j*remaining_width/(n_outputs_in_row+1));
idx++;
}
}
return new_lefts;
}