Ipywidgets: Multiple choice quiz

Created on 8 Jul 2019  路  2Comments  路  Source: jupyter-widgets/ipywidgets

So I have made my own multiple choize quiz in Jupyter with the following code.

import ipywidgets as widgets
import sys
from IPython.display import display
from IPython.display import clear_output

out = widgets.Output()

alternativ = widgets.RadioButtons(
    options=[('Det fysiske laget (Physical layer)', 1), ('Sammenkoblingslaget (Connection layer)', 2), ('Internettlaget (Internet layer)', 3),('Nettverksgrensesnitt-laget (Network layer)', 4)],
    description='',
    disabled=False
)
print('\033[1m','1) Hvilket alternativ er IKKE et lag i TCP/IP-stabelen (stack)?','\033[0m')
check = widgets.Button(description="Sjekk svaret")
display(alternativ)
display(check)


def sjekksvar(b):
        a = int(alternativ.value)
        right_answer = 2
        if(a==right_answer): 
            color = '\x1b[6;30;42m' + "Riktig." + '\x1b[0m' +"\n" #green color
        else:
            color = '\x1b[5;30;41m' + "Feil. " + '\x1b[0m' +"\n" #red color
        svar = ["","","",""] 
        with out:
            clear_output()
        with out:
            print(color+""+svar[a-1])   



display(out)
check.on_click(sjekksvar)

Note that this is code for one question, and I have several cells with almost the same code, only different questions and answers. Now I'm guessing my problems come from the fact that I'm using the Widgets.Output output for all my questions, and that is why answering one question can give an output on the other questions. Does anyone have a more effective way of creating a multiple choice quiz with several questions? This would make a good predefined widget.

Most helpful comment

Widgets.Output is simply a placeholder that you can put everything into it. You can have multiple output widgets but make sure they are named differently, just like how you will name different buttons differently.

A better way is to encapsulate everything and to create a generic function or class that return a multipleChoice widgets. Here is a simple example based on your code:

def create_multipleChoice_widget(description, options, correct_answer):
    if correct_answer not in options:
        options.append(correct_answer)

    correct_answer_index = options.index(correct_answer)

    radio_options = [(words, i) for i, words in enumerate(options)]
    alternativ = widgets.RadioButtons(
        options = radio_options,
        description = '',
        disabled = False
    )

    description_out = widgets.Output()
    with description_out:
        print(description)

    feedback_out = widgets.Output()

    def check_selection(b):
        a = int(alternativ.value)
        if a==correct_answer_index:
            s = '\x1b[6;30;42m' + "Riktig." + '\x1b[0m' +"\n" #green color
        else:
            s = '\x1b[5;30;41m' + "Feil. " + '\x1b[0m' +"\n" #red color
        with feedback_out:
            clear_output()
            print(s)
        return

    check = widgets.Button(description="submit")
    check.on_click(check_selection)


    return widgets.VBox([description_out, alternativ, check, feedback_out])

To create different quiz widgets and display them, simple call

Q1 = create_multipleChoice_widget('blablabla',['apple','banana','pear'],'pear')
Q2 = create_multipleChoice_widget('lalalalal',['cat','dog','mouse'],'dog')
Q3 = create_multipleChoice_widget('jajajajaj',['blue','white','red'],'white')

and then

display(Q1)
display(Q2)
display(Q3)

image

All 2 comments

Widgets.Output is simply a placeholder that you can put everything into it. You can have multiple output widgets but make sure they are named differently, just like how you will name different buttons differently.

A better way is to encapsulate everything and to create a generic function or class that return a multipleChoice widgets. Here is a simple example based on your code:

def create_multipleChoice_widget(description, options, correct_answer):
    if correct_answer not in options:
        options.append(correct_answer)

    correct_answer_index = options.index(correct_answer)

    radio_options = [(words, i) for i, words in enumerate(options)]
    alternativ = widgets.RadioButtons(
        options = radio_options,
        description = '',
        disabled = False
    )

    description_out = widgets.Output()
    with description_out:
        print(description)

    feedback_out = widgets.Output()

    def check_selection(b):
        a = int(alternativ.value)
        if a==correct_answer_index:
            s = '\x1b[6;30;42m' + "Riktig." + '\x1b[0m' +"\n" #green color
        else:
            s = '\x1b[5;30;41m' + "Feil. " + '\x1b[0m' +"\n" #red color
        with feedback_out:
            clear_output()
            print(s)
        return

    check = widgets.Button(description="submit")
    check.on_click(check_selection)


    return widgets.VBox([description_out, alternativ, check, feedback_out])

To create different quiz widgets and display them, simple call

Q1 = create_multipleChoice_widget('blablabla',['apple','banana','pear'],'pear')
Q2 = create_multipleChoice_widget('lalalalal',['cat','dog','mouse'],'dog')
Q3 = create_multipleChoice_widget('jajajajaj',['blue','white','red'],'white')

and then

display(Q1)
display(Q2)
display(Q3)

image

This was very useful, thank you!

I have a follow up question - I am getting text overlapping in the radio button labels if the labels are too long or multi-line. It seems the radio buttons are always only a line apart. Is there a way to correct this?

image

Was this page helpful?
0 / 5 - 0 ratings