How to calculate outcome of quiz


#1

In my app, i want to add a short quiz/test. There are six questions and each one can be answered by clicking 1-5 on a scale (from ‘completely disagree’ to ‘completely agree’). I made five circular buttons to represent the scale. The outcome score can be calculated as follows:

'Add the responses varying from 1-5 for all six items giving a range from 6-30. Divide the total
sum by the total number of questions answered. ’

How do I add this formula to my quiz so that afterwards the correct score is shown?


How to create a user story in Axure?
#2

There are (at least) a few different ways you can do this …in general, regardless of Axure version.

  • Use global variables. I’ll use some example global variable names here:
    • varItems : stores an identifier (ID) for each answered item, such as a number, letter, or label.
    • varCount : stores number of answered items.
    • varSum : stores total of answered item values.
    • varAverage : stores varSum / varCount. (optional; can be calculated as needed, e.g., upon a button press.)
    • Details:
      • It is best to store the ID and a “delimiter” --some char that separates each ID, like a comma, period, semicolon, etc., especially if your ID is numbers–to differentiate between “1”, “10”, “21” etc. Let’s say your question item ID is a letter, so when user answers the first item, the value of varItems would be “A,” and then after they answer the second item, varItems would be “A,B,” and so forth. (But with letters and fewer than 26 items (for English alphabet) delimiters not required.)
      • I recommend naming each radio button with its value, e.g., “1” , “2” , “3” etc. so you can refer to it when calculating the sum.
      • Because you have 5 radio buttons per item, and only one can be selected at a time, you’ll want to assign a unique Selection Group or Radio Group for each item’s set of radio buttons, to automatically enforce this rule.
      • You’ll need to keep track of answered items and not individual radio button clicks. For example, if a user first selects ‘4’ for item A, then varItems can be updated to include “A,”. But if the user then changes their mind and selects ‘3’ for item A, varItems does not need to be updated. (Likewise, the sum would not update to 7 but rather change from 4 to 3.)
      • So, if you are using a true Radio Button widget, when it gets clicked it gets selected (and the way to unselect it is to select another radio button in its Radio Group, or have another widget/action specifically set it to unselected.) If you’ve manually created a kind of custom radio button–e.g., with an Ellipse widget–you’ll want to assign the Click or Tap event with "Set selected of This to “true”. Each radio button’s Selected event should test if its item ID exists in varItems–meaning, “has this item been answered already?” and update varItems if needed, and always add its value–using its name–to varSum. When unselected always decrement its value from varSum. …Something like,

Selected
If value of varItems does not contain “A,”
Set value of varItems to “[[varItems]]A,”
Set value of varCount to [[varCount + 1]]
If true
Set value of varSum to [[varSum + This.name]]
Unselected
Set value of varSum to [[varSum - This.name]]

  • If you want a running average to be calculated, you can also add an action to update varAverage using the expression, [[varSum / varCount]]
  • If you don’t need a running average, you can assign this expression to a button’s Click or Tap event.

  • Or, you can use text values of widgets (shown or hidden) in place of global variables. This creates a set of “page local variables”.
    • You can have one hidden widget for the count of answered items, one hidden widget for the sum of answered question values, and one widget (hidden or not) for the average.
    • Each question item can be a group or dynamic panel (dp) containing the question label, 5 radio buttons, and a hidden “score” widget used for that item’s score. (I recommend keeping it unhidden while you are coding/testing/debugging your prototype, then hiding once everything works correctly.)
      • By default the item Score widget’s text value is blank or 0.
      • When a radio button is selected, it
        • Sets the Score widget’s text value to the value of this radio button.
        • Sets the text value of the item’s Count widget to 1.
        • Adds the Score widget’s value to the Sum widget.
        • Sets the text of the Average widget to the value of Sum divided by the value of Count.
      • When a radio button is unselected, it
        • Subtracts this radio button’s value from the Sum widget.

  • Or, you can use a repeater for the list of question items and calculate the sum and average using conditional cases in the repeater’s Item Loaded event.
    • The repeater’s datasheet can have columns for (at least)
      • Question
      • Answer
    • When a radio button is clicked it can update “This” row in the repeater (or Edit Row Data action for RP10), setting the Answer column to the radio button’s value. For example,
      Update Rows
      (Repeater) set Answer to “[[This.name]]” for This
    • In the repeater’s Item Loaded event, include these conditional cases:
      • If true
        Set Text
        QuestionLabel to “[[Item.Question]]”
      • If [[Item.isFirst]] equals “true”
        Set value of varCount to 0
        Set value of varSum to 0
      • If value of [[Item.Answer]] is greater than 0
        Set value of varCount to [[varCount + 1]]
        Set value of varSum to [[VarSum + Item.Answer]]
      • If [[Item.isLast]] equals “true”
        Set value of varAverage to [[(varSum / varCount).toFixed(1)]]
        (…for 1-digit precision, which is appropriate for max of 6 items; e.g. “4.2”)
      • If value of [[Item.Answer]] equals “1”
        Set selected of 1 to “true”
        (…where the first radio button is named “1”)
      • Else If value of [[Item.Answer]] equals “2”
        Set selected of 2 to “true”
      • Else If value of [[Item.Answer]] equals “3”
        Set selected of 3 to “true”
      • Else If value of [[Item.Answer]] equals “4”
        Set selected of 4 to “true”
      • Else If value of [[Item.Answer]] equals “5”
        Set selected of 5 to “true”

#4

thanks a lot! i still find it really difficult to understand. is it possible for you to make an example file?


#5

Here is a demo showing different methods for presenting and calculating a Likert scale quiz like this.
Likert Scale Quiz.rp (234.0 KB)

The Basic Quiz page shows how global variables can be used to keep track of which questions have been answered, how many, the total score, and the average score. The total sum and average are retrieved manually by clicking their respective buttons.

The Quiz with Running Totals page shows how this can work without global variables, instead using text values of widgets on the page.

  • A hidden widget, named “Items” keeps a list of which question items have been answered, just as the global variable “varItems” did on the first page. You can show it by default to see how it gets updated as you answer questions.
  • It also calculates the total and average on the fly as questions are answered.
    • This running calculation approach doesn’t have to be used here, it is just an extra demonstration of how this would work. You could certainly use the “manual button” approach if you don’t want the total and average scores to be shown all the time. You could hide the “Total” and “Average” widgets by default and then have a button click show them.
    • You could also have a scheme where the total and average scores are hidden by default then automatically shown when all questions have been answered. To do this, you could have a “secret function” assigned to the “Items” widget, then trigger that function every time the “Items” value is updated.

The Quiz with Repeater page shows how your quiz items can be in a repeater. The code for this is a little different but overall, much less code is needed. The big advantage is that you can edit your questions and add more easily in the repeater’s datasheet. You could also easily add or remove/hide scale items, maybe getting rid of Neutral, or making it a 7-point or 10-point scale fairly easy, and without having to make the changes separately on every question item.

  • You can use this approach with global variables as well. Just change all the Set Text actions to Set Variable Value actions, and the local variable references in the expressions to point to the appropriate global variable. For example,
    • Set Text Total to "[[Target.text + Item.Answer]]" would become
      Set Variable Value varSum to [[varSum + Item.Answer]]
    • Set Text Average to "[[ (T / C).toFixed(1) ]]" would become
      Set Variable Value varAverage to "[[ (varSum / varCount).toFixed(1) ]]"
  • Of course, you can also use a manual calculation method as well to get/show the total and average values.

#6

thanks!! I am basing this on an existing test and read that the items 2, 4 and 6 are supposed to be reverse coded, do you know how to do this?


#7

Ah, right, like a Standard Usability Score (SUS) survey.

Here is an updated demo file:
Likert Scale Quiz.rp (486.2 KB)

The most straightforward approach would be to rename the answer dots for the reverse-coded items, where “1” becomes “5”, “2” becomes “4”, etc. See the Basic Quiz (with reverse coding) page for this approach.

That could be a bit of a pain though. Also would be too easy to make mistakes, and hard to see at a glance if everything is set correctly for a given quiz item–is it normal or reverse? It would be nice if you could click a toggle switch to reverse-code any quiz item and quickly scan the questionnaire form in the editor to see which questions have been toggled to reverse-coding. For that, we need an algorithm to swap the scores.

I Googled likert scale reverse scoring algorithm to find this simple transform equation:
Reverse Score = Max + 1 - Score

See the Quiz Running Totals (with reverse) page for an algorithm-driven approach.

  • To each quiz item group, I added a toggle image that I already had (made with Axure, btw) and set its selected style to load an image showing the toggle “on”.
  • When the toggle is selected/on, a conditional case in each dot applies the reverse-coding expression when updating the Total value.
  • To set an item as reverse-coded in the RP editor, click that item’s toggle, then on the Interactions pane, check the “Selected” checkbox. It will then show in the editor as “on”.
  • All the toggles have a Loaded event to hide themselves automatically.

( I just thought of another few approaches, but I didn’t make examples of these. They work on the same logical principle as the toggle…

  • You could use a global variable to store the item numbers that are reverse-coded, and then test if OnLoadVariable contains the current quiz item number, in the same way I test for the selection state of the toggle.
    • Either set its default value in the Project > Global Variables dialog, e.g, set OnLoadVariable to “2,4,6”
    • Or, you could use the Page Loaded event to set the global variable value.
  • You could set it up so every other question is always reverse-coded, e.g., all the even-numbered questions. The conditional case for the dot click would be If "[[ (LVAR1.Name.substring(1))%2 ]]" equals "0" where LVAR1 is a local variable pointing to the group, e.g., named “Q1”, “Q2”, etc.
    )

The reverse coding algorithm is also needed for a repeater-based quiz. The “toggle” can be done with a datasheet column and a conditional case testing the value of that column. See the Quiz Repeater (supporting reverse) page.

  • I added a sixth row and made the question items in rows 2, 4, 6 sound “negative”. Quick and easy.
  • I added a column named, “Reverse” and set the value to “true” for rows 2, 4 6.
  • I added an additional case for calculating the total value which applies the reverse coding expression if the Reverse column equals “true”.
  • In the “Case Last” (row) case, I also added a Wait 100 ms action before calculating the average to ensure everything gets set on the Count and Total widgets before trying to divide them.
    • Also note that it only tries to calculate an average if the count is greater than 0, otherwise a math error would occur and the value would get set to “NaN” (for Not a Number).

#8

Thanks a lot. I tried the basic quiz for my app, but when i fill in the test, the result is not right. do you know how to fix this? Here is my file:Interactivetest.rp (197.6 KB)


#9

Do you know how to fix the above mentioned issue?


#10

Probably. I’ll take a look at your file when I get some time. Busy now…


#11

In my file, I had a group for each question item which included the radio buttons and the Question text item. These groups were named “Q1”, “Q2”, “Q3”, etc. The name of the group is used to keep track of which question items have been answered, using the global variable, varItems, to build and store a list. When an answer is chosen, it does two key things:

  • A conditional case tests varItems to see if it contains the question item identifier
    • If not found (this question not yet answered) it adds the last char of its group name (e.g., “Q1” is stored as “1”) and a comma as a list delimiter, to mark this question as answered, and increments varCount (the number of answered questions).
  • It also adds its point value to varSum.

When you ungrouped the radios and question text, you inadvertently killed the method of keeping track of which questions have been answered and ability to properly calculate the total and average.

  • This is because the Set Variable Value varItems action uses a local variable (named “LVAR1”) which points to the group widget, and refers to that widget’s name property, as in, [[ LVAR1.Name ]]. Without the group, there is no widget to point to and no way to keep track of which questions have been answered.
  • Also, the conditional case for the Click or Tap event of each radio tests if varItems contains the question identifier, and its local variable also now points to nothing.

I fixed this for the first two questions in your file. Here is the updated file:
Interactivetest.rp (357.7 KB)

  • I named the widget with “Q1: positive” in State 2, as “Q1”.
  • I edited the Click or Tap for the first radio button so that:
    • The local variable, LVAR1, in the conditional case points to the “Q1” widget.
      • I’ve found that in RP 10 not all widgets show up in the widget droplist… (maybe if they don’t have interactions?) so I had to search for this widget …just type in “Q1” and it shows up.
    • The local variable, LVAR1, in the Set Variable Value varItems action, points to the “Q1” widget.
  • To make it easier to do this for all radios, I copied the Selected event of this first radio, then deleted the Selected event for the remaining four radios, then pasted to all radios.
  • …I did the same process for the next question.
  • …You can now (hopefully) fix the rest.

#12

I am so sorry, i still dont understand it… i dont know how to make sure the LVAR1 variable points to the text widget, i dont see an option anywhere to change where it points to.
I could also group the items again if that makes it easier?

In the example file i sent i added a sixth question. i found that the ‘get total’ option works for all questions except for the sixth. The ‘get average’ question does not seem to work whatsoever…


#13

Here is Axure documentation for this:

Not directly easier, no, because you’ll still need to edit the LVAR1 pointers in the expressions. I suppose you could try copying in my original groups (e.g., “Q1”, “Q2”, etc., keep them intact but change the location, styling ad text as you need. That should work, but you’ll likely need to verify it.


Here are the steps for changing one radio, using your file as an example:

  • Select the widget on the canvas, look at the Interactions panel, find the event, and click on the action.
    image

  • Next to the VALUE field, click the little fx button.
    image

  • In the Edit Text dialog that shows, create, edit, and/or verify the local variable details.

    • (If necessary, click “Add Local Variable” …of course one already exists here, with the default “LVAR1” name.

    • (If desired, you can rename this, e.g., “Q” or “qItem” , etc. Best to avoid common or reserved terms typically used for something else, like “Item” or “text”.)

    • Be sure to verify what the variable is pointing to in the middle field. The default is usually “text on widget” but in this situation you want to point to
      widget" --the widget itself, because we refer to a property of that widget.

    • The third field is where you specify what widget to point to. Click on it to show its droplist:

    • This is where I don’t understand the current behavior of Axure RP 10, because clearly not all the widgets are shown in this list …where is the “Q1” widget in State 2 of testpanel?

    • Just start typing the name of the widget you need in order to find it.

      • (Note the Search field is focused by default, so as soon as you click into this droplist you can start typing.) In this situation, I just needed to enter “q” to see every widget with a ‘q’ in it (text value, name, or type of widget).
      • (Also note that hovering over a widget in the list shows it’s contents just to the left, which can really help in identifying the correct widget.)
  • If you need to change the expression (in the white field) or just discover what is possible, click “Insert Variable or Function…” to see a list of all available system variables and functions. You can chose any of them to insert it into your expression.

Should work once your expressions and local variables are set up correctly.


#14

Thanks! In this file i have implemented your tips. Still, the get total doesnt work for the sixth question. The sixth question is also not ‘seen’ by the ‘get average’ function.
Interactivetest (1).rp (365.9 KB)


#15

In testpanel State 7, for the sixth question, you need to update the local variable in the conditional case. It looks like you updated it correctly in the Set Variable Value action, though, so set it to the same Q6 widget. That should fix both issues.