Welcome to the LimeSurvey Community Forum

Ask the community, share ideas, and connect with other LimeSurvey users!

Customise item rotation in limesurvey matrix question

  • BBSR-SR5
  • BBSR-SR5's Avatar Topic Author
  • Offline
  • Senior Member
  • Senior Member
More
7 months 3 weeks ago #260062 by BBSR-SR5
Please help us help you and fill where relevant:
Your LimeSurvey version: Version 6.4.12
Own server or LimeSurvey hosting: LimeSurvey Cloud
Survey theme/template: Customised fruity_23 Blueberry
==================

Hi everyone,

sorry if my google-fu has failed me. I have the following problem. I want to rotate items in my matrix question, but I have 1-2 "difficult" items, which should never be shown at first place (or optimally in the top half of the matrix). The reason for this is that we want to avoid priming our respondents with something they might perceive strongly negative. Especially since it isn't the main topic of our survey but needs to be asked anyway.

I want to create a custom rotation where I can make sure certain items only get put into the rotation pool after a certain amount of other items (optimally half of them) has already been placed.

I hope this is possible.

Please Log in to join the conversation.

  • Joffm
  • Joffm's Avatar
  • Offline
  • LimeSurvey Community Team
  • LimeSurvey Community Team
More
7 months 3 weeks ago #260070 by Joffm
Hi,
here I used the script originally thought for mantaining survey wide randomization.
Code:
<script type="text/javascript" data-author="Tony Partner">
  $(document).on('ready pjax:scriptcomplete',function(){
 
function shuffleArray(array) {
    for (var i = array.length - 1; i > 0; i--) {
        var j = Math.floor(Math.random() * (i + 1));
        var temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }
    return array;
}
    
    
    //Identify this question
    var thisQuestion = $('#question{QID}');
    var thisAnswerList = $('tr.answers-list:eq(0)', thisQuestion).parent();
 
    // Special codes appear after
    var afterCode=4;
    
    // Fill the array with "normal" codes
    var array1=[1,3,4,5,7];
    
    // Fill the array with "special" codes
    var array2=[2,6];
    shuffleArray(array1);
    array2=array2.concat(array1.slice(afterCode));
    array1=array1.slice(0,afterCode);
    shuffleArray(array2);
    array1=array1.concat(array2);
 
    // Loop through the answer codes
    $.each(array1, function(i, val) {
      // Move the answer item
      $(thisAnswerList).append($('tr.answers-list[id$="X{QID}'+val+'"]', thisQuestion));
    });
  });
</script>





Joffm

Volunteers are not paid.
Not because they are worthless, but because they are priceless

Please Log in to join the conversation.

  • BBSR-SR5
  • BBSR-SR5's Avatar Topic Author
  • Offline
  • Senior Member
  • Senior Member
More
7 months 3 weeks ago #260165 by BBSR-SR5
Thank you, this works great. I managed to adjust it for our use case to make sure certain items are displayed in a certain order.

There is just one issue I've run into and that's how the matrix has an underlying color pattern which gets distributed in interesting ways:


Is there some way to redraw the coloration after the shuffling/randomisation process is finished?

Please Log in to join the conversation.

  • tpartner
  • tpartner's Avatar
  • Offline
  • LimeSurvey Community Team
  • LimeSurvey Community Team
More
7 months 3 weeks ago #260166 by tpartner
Have a look at "Fix up the row classes" in this script.

- forums.limesurvey.org/forum/can-i-do-thi...sign?start=24#259787

Cheers,
Tony Partner

Solutions, code and workarounds presented in these forums are given without any warranty, implied or otherwise.

Please Log in to join the conversation.

  • BBSR-SR5
  • BBSR-SR5's Avatar Topic Author
  • Offline
  • Senior Member
  • Senior Member
More
7 months 3 weeks ago #260190 by BBSR-SR5
Hm I tried adding that to my code, but it doesn't seem to do anything.
Code:
<script type="text/javascript" data-author="Tony Partner">
  $(document).on('ready pjax:scriptcomplete',function(){
 
 
    function shuffleArray(array) {
    for (var i = array.length - 1; i > 0; i--) {
        var j = Math.floor(Math.random() * (i + 1));
        var temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }
    return array;
}
 
    // Merge function
        function mergeArrays(array1, array2) {
            var mergedArray = [];
            var maxLength = Math.max(array1.length, array2.length);
 
            for (var i = 0; i < maxLength; i++) {
                if (i < array2.length) {
                    mergedArray.push(array2[i]);
                }
                if (i < array1.length) {
                    mergedArray.push(array1[i]);
                }
            }
 
            return mergedArray;
        }
 
    //Identify this question
    var thisQuestion = $('#question{QID}');
    var thisAnswerList = $('tr.answers-list:eq(0)', thisQuestion).parent();
    var thisTable = $('table.subquestion-list:eq(0)', thisQuestion);
 
    // Special codes appear after
        var afterCode = 4;
 
        //Array for K Codes
        var array_k = ["b","d","g","h","i","j","l"];
 
        //Array for N Codes
        var array_n = ["c","e","f","k","m","n"];
 
        //Array for Special K Codes
        var array_sk = [];
 
        //Array for Special N codes
        var array_sn = ["a"];
 
        //Array for super special codes
        var array_ss = ["p"];
 
    // Shuffle order of "normal" arrays
        shuffleArray(array_k);
        shuffleArray(array_n);
 
        // Slice "normal" arrays and merge second part to special codes
        array_sk = array_sk.concat(array_k.slice(afterCode));
        array_sn = array_sn.concat(array_n.slice(afterCode));
 
        // Save only first part of "normal" arrays
        array_k = array_k.slice(0, afterCode);
        array_n = array_n.slice(0, afterCode);
 
        // Shuffle special arrays
        shuffleArray(array_sk);
        shuffleArray(array_sn);
        shuffleArray(array_ss);
 
        // Combine normal and special arrays
        array_k = array_k.concat(array_sk);
        array_n = array_n.concat(array_sn);
 
        // Merge arrays in order n,k,n,k...
        var array_res = mergeArrays(array_k, array_n);
 
        //Add super special array to end of result array
        array_res = array_res.concat(array_ss);
 
 
 
 
    // Loop through the answer codes
    $.each(array_res, function(i, val) {
      // Move the answer item
      $(thisAnswerList).append($('tr.answers-list[id$="X{QID}'+val+'"]', thisQuestion));
    });
 
 
 
 
    // Fix up the row classes
        var rowClass = 1;
        $('tr.answers-list', thisTable).each(function(i) {
            $(this).addClass('array'+(2-(i%2)));
        });
 
 
    });
 
 
 
</script>

Do I need to adjust something I've missed?

Please Log in to join the conversation.

  • tpartner
  • tpartner's Avatar
  • Offline
  • LimeSurvey Community Team
  • LimeSurvey Community Team
More
7 months 3 weeks ago #260211 by tpartner
Sample survey?

Cheers,
Tony Partner

Solutions, code and workarounds presented in these forums are given without any warranty, implied or otherwise.

Please Log in to join the conversation.

  • BBSR-SR5
  • BBSR-SR5's Avatar Topic Author
  • Offline
  • Senior Member
  • Senior Member
More
7 months 3 weeks ago - 7 months 3 weeks ago #260232 by BBSR-SR5

Sample survey?
Sure:
 

File Attachment:

File Name: limesurvey...1318.lss
File Size:36 KB
Last edit: 7 months 3 weeks ago by BBSR-SR5. Reason: File didn't attach

Please Log in to join the conversation.

  • tpartner
  • tpartner's Avatar
  • Offline
  • LimeSurvey Community Team
  • LimeSurvey Community Team
More
7 months 3 weeks ago #260244 by tpartner
This should do it:

Code:
<script type="text/javascript">
    $(document).on('ready pjax:scriptcomplete',function(){
 
        function shuffleArray(array) {
            for (var i = array.length - 1; i > 0; i--) {
                var j = Math.floor(Math.random() * (i + 1));
                var temp = array[i];
                array[i] = array[j];
                array[j] = temp;
            }
            return array;
        }
 
        // Merge function
        function mergeArrays(array1, array2) {
            var mergedArray = [];
            var maxLength = Math.max(array1.length, array2.length);
 
            for (var i = 0; i < maxLength; i++) {
                if (i < array2.length) {
                    mergedArray.push(array2[i]);
                }
                if (i < array1.length) {
                    mergedArray.push(array1[i]);
                }
            }
 
            return mergedArray;
        }
 
        //Identify this question
        var thisQuestion = $('#question{QID}');
        var thisAnswerList = $('tr.answers-list:eq(0)', thisQuestion).parent();
        var thisTable = $('table.subquestion-list:eq(0)', thisQuestion);
 
        // Special codes appear after
        var afterCode = 4;
 
        //Array for K Codes
        var array_k = ["b","d","g","h","i","j","l"];
 
        //Array for N Codes
        var array_n = ["c","e","f","k","m","n"];
 
        //Array for Special K Codes
        var array_sk = [];
 
        //Array for Special N codes
        var array_sn = ["a"];
 
        //Array for super special codes
        var array_ss = ["p"];
 
        // Shuffle order of "normal" arrays
        shuffleArray(array_k);
        shuffleArray(array_n);
 
        // Slice "normal" arrays and merge second part to special codes
        array_sk = array_sk.concat(array_k.slice(afterCode));
        array_sn = array_sn.concat(array_n.slice(afterCode));
 
        // Save only first part of "normal" arrays
        array_k = array_k.slice(0, afterCode);
        array_n = array_n.slice(0, afterCode);
 
        // Shuffle special arrays
        shuffleArray(array_sk);
        shuffleArray(array_sn);
        shuffleArray(array_ss);
 
        // Combine normal and special arrays
        array_k = array_k.concat(array_sk);
        array_n = array_n.concat(array_sn);
 
        // Merge arrays in order n,k,n,k...
        var array_res = mergeArrays(array_k, array_n);
 
        //Add super special array to end of result array
        array_res = array_res.concat(array_ss);
 
        // Loop through the answer codes
        $.each(array_res, function(i, val) {
            // Move the answer item
            $(thisAnswerList).append($('tr.answers-list[id$="X{QID}'+val+'"]', thisQuestion));
        });
 
        // Fix up the row background colours
        $('tr.answers-list', thisQuestion). each (function(i){
            $(this).removeClass('ls-even ls-odd');
            if(i % 2 == 0) {
                $(this).addClass('ls-even');
            }
            else {
                $(this).addClass('ls-odd');
            }
        });
 
    });  
 
</script>

Sample survey: 

File Attachment:

File Name: limesurvey...3181.lss
File Size:41 KB

Cheers,
Tony Partner

Solutions, code and workarounds presented in these forums are given without any warranty, implied or otherwise.

Please Log in to join the conversation.

  • BBSR-SR5
  • BBSR-SR5's Avatar Topic Author
  • Offline
  • Senior Member
  • Senior Member
More
7 months 2 weeks ago #260525 by BBSR-SR5
Thank you very much, it works great now.

I have one last question though. If I turn the question soft mandatory and people trigger the warning window:

The questions reshuffle every time the continue button is pressed. I suspect that would be rather irritating for people answering the survey. Can I prevent this, so the questions are only reshuffled on page load? (I don't think it's possible to only reshuffle them once per participant/browser, right?)

Please Log in to join the conversation.

  • Joffm
  • Joffm's Avatar
  • Offline
  • LimeSurvey Community Team
  • LimeSurvey Community Team
More
7 months 2 weeks ago #260526 by Joffm
Should be possible.
There is a script to maintain a once created order survey wide.

So you may store the created order in a question of type "short text" at the start of the survey and then use this to display the array.
​​​​​

Volunteers are not paid.
Not because they are worthless, but because they are priceless

Please Log in to join the conversation.

  • BBSR-SR5
  • BBSR-SR5's Avatar Topic Author
  • Offline
  • Senior Member
  • Senior Member
More
7 months 2 weeks ago #260528 by BBSR-SR5
Hm actually, I figured it might be easier to replace the Math.random() function with a seeded random function and then use the survey number as a seed. That way it should stay constant for a user.

Though how would I access that? Right now I've plugged in Date.now()
Code:
<script type="text/javascript" data-author="BBSR-SR5 &amp; Tony Partner">
  $(document).on('ready pjax:scriptcomplete',function(){
 
 
//Define Seeded Random function
   function splitmix32(a) {
  return function() {
    a |= 0;
    a = a + 0x9e3779b9 | 0;
    let t = a ^ a >>> 16;
    t = Math.imul(t, 0x21f0aaad);
    t = t ^ t >>> 15;
    t = Math.imul(t, 0x735a2d97);
    return ((t = t ^ t >>> 15) >>> 0) / 4294967296;
  };
}
 
function shuffleArray(array) {
  const seed = Date.now();
  const random = splitmix32(seed);
  for (let i = array.length - 1; i > 0; i--) {
    const j = Math.floor(random() * (i + 1));
    [array[i], array[j]] = [array[j], array[i]];
  }
  return array;
}
 
    // Merge function
        function mergeArrays(array1, array2) {
            var mergedArray = [];
            var maxLength = Math.max(array1.length, array2.length);
 
            for (var i = 0; i < maxLength; i++) {
                if (i < array2.length) {
                    mergedArray.push(array2[i]);
                }
                if (i < array1.length) {
                    mergedArray.push(array1[i]);
                }
            }
 
            return mergedArray;
        }
 
    //Identify this question
    var thisQuestion = $('#question{QID}');
    var thisAnswerList = $('tr.answers-list:eq(0)', thisQuestion).parent();
    var thisTable = $('table.subquestion-list:eq(0)', thisQuestion);
 
    // Special codes appear after
        var afterCode = 4;
 
        //Array for K Codes
        var array_k = ["b","d","g","h","i","j","l"];
 
        //Array for N Codes
        var array_n = ["c","e","f","k","m","n"];
 
        //Array for Special K Codes
        var array_sk = [];
 
        //Array for Special N codes
        var array_sn = ["a"];
 
        //Array for super special codes
        var array_ss = ["o"];
 
    // Shuffle order of "normal" arrays
        shuffleArray(array_k);
        shuffleArray(array_n);
 
 
        // Slice "normal" arrays and merge second part to special codes
        array_sk = array_sk.concat(array_k.slice(afterCode));
        array_sn = array_sn.concat(array_n.slice(afterCode));
 
        // Save only first part of "normal" arrays
        array_k = array_k.slice(0, afterCode);
        array_n = array_n.slice(0, afterCode);
 
        // Shuffle special arrays
        shuffleArray(array_sk);
        shuffleArray(array_sn);
        shuffleArray(array_ss);
 
        // Combine normal and special arrays
        array_k = array_k.concat(array_sk);
        array_n = array_n.concat(array_sn);
 
        // Merge arrays in order n,k,n,k...
        var array_res = mergeArrays(array_k, array_n);
 
        //Add super special array to end of result array
        array_res = array_res.concat(array_ss);
 
 
 
 
    // Loop through the answer codes
    $.each(array_res, function(i, val) {
      // Move the answer item
      $(thisAnswerList).append($('tr.answers-list[id$="X{QID}'+val+'"]', thisQuestion));
    });
 
 
 
 
    // Fix up the row background colours
        $('tr.answers-list', thisQuestion). each (function(i){
            $(this).removeClass('ls-even ls-odd');
            if(i % 2 == 0) {
                $(this).addClass('ls-even');
            }
            else {
                $(this).addClass('ls-odd');
            }
        });
 
      //alert(array_res);
    //console.log(array_res);
    });
 
 
 
</script>

How would I access the participant number from the code?

Please Log in to join the conversation.

  • tpartner
  • tpartner's Avatar
  • Offline
  • LimeSurvey Community Team
  • LimeSurvey Community Team
More
7 months 2 weeks ago #260529 by tpartner
My solution would be to do as Joffm suggests - load the sub-question order in a hidden (via CSS class) short-text question. On page load, if that question is found to be populated, that order is used, otherwise your randomization alogorithm kick in.

Code:
<script type="text/javascript">
    $(document).on('ready pjax:scriptcomplete',function(){
 
        function shuffleArray(array) {
            for (var i = array.length - 1; i > 0; i--) {
                var j = Math.floor(Math.random() * (i + 1));
                var temp = array[i];
                array[i] = array[j];
                array[j] = temp;
            }
            return array;
        }
 
        // Merge function
        function mergeArrays(array1, array2) {
            var mergedArray = [];
            var maxLength = Math.max(array1.length, array2.length);
 
            for (var i = 0; i < maxLength; i++) {
                if (i < array2.length) {
                    mergedArray.push(array2[i]);
                }
                if (i < array1.length) {
                    mergedArray.push(array1[i]);
                }
            }
 
            return mergedArray;
        }
 
        // Identify some elements and define variables
        var thisQuestion = $('#question{QID}');
        var thisAnswerList = $('tr.answers-list:eq(0)', thisQuestion).parent();
        var thisTable = $('table.subquestion-list:eq(0)', thisQuestion);
        var orderQuestion = $(thisQuestion).nextAll('.text-short:eq(0)');
        var orderInput = $(':text.form-control:eq(0)', orderQuestion);
        var array_res;
        var aOrder = [];
 
        // Previously set order
        if($.trim($(orderInput).val()) != '') {
            array_res = $.trim($(orderInput).val()).split(',');
        }
        // No previous order set
        else {    
            // Special codes appear after
            var afterCode = 4;
 
            //Array for K Codes
            var array_k = ["b","d","g","h","i","j","l"];
 
            //Array for N Codes
            var array_n = ["c","e","f","k","m","n"];
 
            //Array for Special K Codes
            var array_sk = [];
 
            //Array for Special N codes
            var array_sn = ["a"];
 
            //Array for super special codes
            var array_ss = ["p"];
 
            // Shuffle order of "normal" arrays
            shuffleArray(array_k);
            shuffleArray(array_n);
 
            // Slice "normal" arrays and merge second part to special codes
            array_sk = array_sk.concat(array_k.slice(afterCode));
            array_sn = array_sn.concat(array_n.slice(afterCode));
 
            // Save only first part of "normal" arrays
            array_k = array_k.slice(0, afterCode);
            array_n = array_n.slice(0, afterCode);
 
            // Shuffle special arrays
            shuffleArray(array_sk);
            shuffleArray(array_sn);
            shuffleArray(array_ss);
 
            // Combine normal and special arrays
            array_k = array_k.concat(array_sk);
            array_n = array_n.concat(array_sn);
 
            // Merge arrays in order n,k,n,k...
            array_res = mergeArrays(array_k, array_n);
 
            //Add super special array to end of result array
            array_res = array_res.concat(array_ss);
 
            // Load the hidden order input
            $(orderInput).val(array_res);
        }
 
        // Loop through the answer codes
        $.each(array_res, function(i, val) {
            // Move the answer item
            $(thisAnswerList).append($('tr.answers-list[id$="X{QID}'+val+'"]', thisQuestion));
        });
 
        // Fix up the row background colours
        $('tr.answers-list', thisQuestion). each (function(i){
            $(this).removeClass('ls-even ls-odd');
            if(i % 2 == 0) {
                $(this).addClass('ls-even');
            }
            else {
                $(this).addClass('ls-odd');
            }
        });
    });   
 
</script>

Sample survey:  

File Attachment:

File Name: limesurvey...3182.lss
File Size:56 KB

Cheers,
Tony Partner

Solutions, code and workarounds presented in these forums are given without any warranty, implied or otherwise.

Please Log in to join the conversation.

Moderators: tpartnerholch

Lime-years ahead

Online-surveys for every purse and purpose