Coder Social home page Coder Social logo

jmshea / jupyterquiz Goto Github PK

View Code? Open in Web Editor NEW
120.0 4.0 40.0 1.81 MB

An interactive Quiz generator for Jupyter notebooks and Jupyter Book

License: MIT License

Python 2.58% JavaScript 3.88% CSS 0.43% Jupyter Notebook 93.11%
quiz jupyter-notebook jupyter-notebooks interactive self-assessment

jupyterquiz's Introduction

JupyterQuiz

JupyterQuiz is a tool for displaying interactive self-assessment quizzes in Jupyter notebooks and Jupyter Book. JupyterQuiz was created to enable interactive quizzes for readers of my book Foundations of Data Science with Python [Affiliate Link]

Important Note for JupyterLab 4 Users: Changes to the math rendering system in JupyterLab 4 have broken the LaTeX rendering in JupyterQuiz. There is not currently a simple solution, but I have opened an issue requesting that the necessary methods be made available. Math should still work in Jupyter Book. A very hacky solution is available in version 2.7.0a4, which loads MathJax 3 on top of the JupyterLab MathJax version. Use at your own risk! (It can be installed as pip install jupyterquiz==2.7.0a4. Note that 2.7.0a3 also changed how the precision parameter effects numerical answers. Prior to 2.7.0a3, precision specified a decimal place; from 2.7.0a3 on, it specifies a number of significant digits. )

JupyterQuiz is part of my effort to make open source tools for developing modern, interactive textbooks.

If you would like to see a video that introduces these tools and discusses why I made them, check out my JupyterCon 2023 talk on Tools for Interactive Education Experiences in Jupyter Notebooks and Jupyter Books.

These animated GIFs illustrate the two basic question types in JupyterQuiz:

Many Choice Question

Example many-choice question using JupyterQuiz.


Numerical Answer Question

Example numerical answer question using JupyterQuiz.


Examples using JupyterQuiz

This library was built to create interactive questions for the Foundations of Data Science with Python book by John M. Shea. Example: Chapter 3 Self-Assessment Questions

Some other examples I have seen around the web include:

If you using JupyterQuiz in a Jupyter Book or other way that is useable on the web, please clone this repository, add your information to the bulleted list in the README.md, and make a pull request for me to include a link to your use of this library.

The notebook test.ipynb shows more features but must be run on your own local Jupyter or in nbviewer -- GitHub only renders the static HTML that does not include the interactive quizzes. (If viewing on GitHub, there should be a little circle with a minus sign at the top of the file that offers you the ability to launch the notebook in nbviewer.)

It currently supports two types of quiz questions:

  1. Multiple/ Many Choice Questions: Users are given a predefined set of choices and click on answer(s) they believe are correct.
  2. Numerical: Users are given a text box in which they can submit answers in decimal or fraction form.

Each type of question offers different ways to provide feedback to help users understand what they did wrong (or right).

Quesitons can be loaded from:

  • a Python list of dicts,
  • a JSON local file,
  • via a URL to a JSON file.

New as of version 1.6 (9/26/2021): You can now embed the question source (most importantly, the answers) in Jupyter Notebook so that they will not be directly visibile to users!

Question source data can be stored in any Markdown cell in a hidden HTML element (such as a span with the display style set to "none"). Questions can be stored as either JSON or base64-encoded JSON (to make them non-human readable). Please see the notebook HideQuiz.ipynb for examples of how to use this.

Quiz options

JupyterQuiz supports a few options:

  • num = Number of questions to present. If this option is chosen, the set of questions will be selected at random.
  • shuffle_questions = boolean, whether to shuffle order of questions (default False)
  • shuffle_answers = boolean, whether to shuffle answers for multiple-choice questions (default True)
  • preserve_responses = boolean, whether to output the user responses in a way that is preserved upon reload of the notebook (default False) -- see below

Quiz Formatting

In addtion, it supports additional options for controlling the formatting of the quiz options.

  • border_radius = boolean, border radius of question boxes
  • question_alignment = string, alignment of question text (e.g., "left", "right)
  • max_width = int, max width of question boxes

For more fine-grained formatting control of the question text, leaving the question field the empty string ("") will result in only the answers being displayed. This allows for custom question formatting such as including images, tables, more complex code examples, etc. Note that this feature works better for a single question quiz and may not work as well with shuffled quizzes or quiz questions selected at random.

Colors can be changed by passing the colors keyword argument. Pass in a dictionary of colors that you would like to change. Here is the default dictionary for reference:

color_dict = {
        '--jq-multiple-choice-bg': '#6f78ffff',   # Background for the question part of multiple-choice questions
        '--jq-mc-button-bg': '#fafafa',           # Background for the buttons when not pressed
        '--jq-mc-button-border': '#e0e0e0e0',     # Border of the buttons
        '--jq-mc-button-inset-shadow': '#555555', # Color of inset shadow for pressed buttons
        '--jq-many-choice-bg': '#f75c03ff',       # Background for question part of many-choice questions
        '--jq-numeric-bg': '#392061ff',           # Background for question part of numeric questions
        '--jq-numeric-input-bg': '#c0c0c0',       # Background for input area of numeric questions
        '--jq-numeric-input-label': '#101010',    # Color for input of numeric questions
        '--jq-numeric-input-shadow': '#999999',   # Color for shadow of input area of numeric questions when selected
        '--jq-incorrect-color': '#c80202',        # Color for incorrect answers 
        '--jq-correct-color': '#009113',          # Color for correct answers
        '--jq-text-color': '#fafafa'              # Color for question text
    }

There is one included alternative set of colors to the default colors, which be selected by passing colors='fdsp'.

Preserving student responses

New as of version 2.0 (7/26/2022): There is now code to enable preserving student responses (for instance, for checking/grading their quizzes). If you want to use this functionality, please read this carefully!

To enable this behavior, set preserve_responses=True in display_quiz()

This option produces a text ouptut that consists of a question number (based on the question order) along with the chosen answer. Instructions are given at the end of the quiz on how to copy the text output and paste it into a pre-prepared Markdown cell. See preserve-responses.ipynb for an example.

The requirement that the student copy and paste the text output to preserve it is because of limitations in the exchange of information from the JavaScript side to the Python side. As far as I know, the only way around this requires a plug-in, and I do not want to require that. I will continue to investigate solutions to this in the future.

This option is not compatible with shuffle_questions = True or setting num because these result in the order of the questions being random, which makes no sense when reporting answers vs question number.

Tool for making Multiple/Many Choice Questions

Dr. WJB Mattingly (@wjbmattingly) has made a Streamlit App for creating JupyterQuiz question files in an interactive way without having to edit a JSON file. It currently supports multiple/many choice questions.

Installation

JupyterQuiz is available via pip:

pip install jupyterquiz

Multiple/Many Choice Questions

Multiple/Many Choice questions are defined by a Question, an optional Code block, and a list of possible Answers. Answers include a text component and/or a code block, details on whether the Answer is correct, and Feedback to be displayed for that Answer. The schema for Multiple/Many Choice Questions is shown below: Schema for Multiple/Many Choice Questions in JupyterQuiz

* = Required parameter, (+) = At least one of these parameters is required

Example JSON for a many-choice question is below:

  {
        "question": "Choose all of the following that can be included in Jupyter notebooks?",
        "type": "many_choice",
        "answers": [
            {
                "answer": "Text and graphics output from Python",
                "correct": true,
                "feedback": "Correct."
            },
            {
                "answer": "Typeset mathematics",
                "correct": true,
                "feedback": "Correct."
            },
            {
                "answer": "Python executable code",
                "correct": true,
                "feedback": "Correct."
            },
            {
                "answer": "Formatted text",
                "correct": true,
                "feedback": "Correct."
            },
            {
                "answer": "Live snakes via Python",
                "correct": false,
                "feedback": "I hope not."
            }
        ]
    }

Numerical Questions

Numerical questions consist of a Question, an optional Precision, and one or more Answers. Each Answer can be a Value, a Range, or the Default, and each of these can include Feedback text. Values and Ranges can be marked as correct or incorrect. Ranges are in the form [A,B), where endpoint A is included in the range and endpoint B is not included in the range. When Precision is specified, numerical inputs are rounded to the specified precision before comparing to the Answers. The schema for Numerical questions is shown below:

Schema for Numerical Questions in JupyterQuiz

* = Required parameter

Example JSON for a numerical question is below:

  {
        "question": "Enter the value of pi (will be checked to 2 decimal places):",
        "type": "numeric",
        "precision": 2,
        "answers": [
            {
                "type": "value",
                "value": 3.14,
                "correct": true,
                "feedback": "Correct."
            },
            {
                "type": "range",
                "range": [ 3.142857, 3.142858], 
                "correct": true,
                "feedback": "True to 2 decimal places, but you know pi is not really 22/7, right?"
            },
            {
                "type": "range",
                "range": [ -100000000, 0], 
                "correct": false,
                "feedback": "pi is the AREA of a circle of radius 1. Try again."
            },
            {
                "type": "default",
                "feedback": "pi is the area of a circle of radius 1. Try again."
            }
        ]
    }

Working with JupyterLite

This should work with JupyterLite as of version 2.1.2. Here is an example that should work on JupyterLite:

import micropip
await micropip.install('jupyterquiz')

from jupyterquiz import display_quiz
git_url='https://raw.githubusercontent.com/jmshea/Foundations-of-Data-Science-with-Python/main/questions/'

display_quiz(git_url+'ch1.json')

As an Amazon Associate I earn from qualifying purchases.

jupyterquiz's People

Contributors

chquix avatar jmshea avatar norepercussions avatar ogiorgis avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

jupyterquiz's Issues

Preserve_Quizzes_with_Student_Answers

For some homework assignments, I ask multiple choice questions (without any feedback and I set all answers as true) inside a Jupyter Notebook with the intent of grading the students' response when they submit their notebooks. However, when I open a notebook, the quiz resets and I can't see the output like I would from any other code cell.

Decouple Python from JavaScript

I would like to implement my own UI in React.js. Looking at the source I see that the python code is generating the javascript

<script type="text/Javascript">
{{
mydiv={div_id}
nB_cell = mydiv.closest(".jp-Notebook-cell");
//prev_cell = nb_cell.previousElementSibling.previousElementSibling;
//prev_cell = document.getElementById({prev_div_id});
prev_cell = {prev_div_id};
console.log(prev_cell);
responses = prev_cell.querySelector(".JCResponses");
//console.log(responses);
if (responses) {{
//console.log(responses);
mydiv.setAttribute("data-responses", responses.dataset.responses);
//printResponses(mydiv);
var iDiv = document.createElement('div');
iDiv.id = 'responses' + mydiv.id;
iDiv.innerText=responses.dataset.responses;
mydiv.appendChild(iDiv);
}} else {{
mydiv.setAttribute("data-responses", "[]");
mydiv.innerText = 'No Responses Found';
}}
}}
</script>
"""
.

Is there a way to decouple more Python from JavaScript so that 3rd party UI can be implemented on top of this library?

Jupyter polls?

Have you considered having polls? Something that, when you click on it, shows the distribution. Like Twitter or LinkedIn polls. I think having polls is a great way to hook students on a topic they are hesitant to learn. For example, if they see that the majority of people are thinking wrong about something after seeing the distribution, then they'd be psyched to want to learn to become the minority :)
I'd be very happy to help with this since we are planning to use it in our newly funded educational project at https://c4r.io/about-us/

Test with MathJax 3

This code has not yet been tested with MathJax 3, but I have tried to call the appropriate function to re-typeset the page when feedback is added.

Javascript Error: MathJax.typeset is not a function

Getting the error Javascript Error: MathJax.typeset is not a function when making a quiz in a notebook.
The quiz seems to work fine, but the error is displayed below the quiz display:
Screenshot at 2023-08-24 10-12-22

I'm using JupyterLab, in case that helps?

requirements.txt not defined!

It is not correct to assume that everyone is running the same version of all the libraries in their virtual environments. For example I tried running test.ipynb and got the following error. I am pretty sure either I have a later version of the importlib library that depreciated the files method or an earlier version that does not have it defined.

File ~/Documents/workspace/jupyterquiz/jupyterquiz/dynamic.py:126, in display_quiz(ref, num, shuffle_questions, shuffle_answers, preserve_responses, border_radius, question_alignment, max_width, colors)
124 styles+= "}\n\n"
125 #print(styles)
--> 126 f = importlib.resources.files(package).joinpath('styles.css')
127 css = f.read_bytes()
128 styles += css.decode("utf-8")

AttributeError: module 'importlib.resources' has no attribute 'files'

Please include requiremnts.txt so we know which library versions work with this framework. BTW I am macbook M1 Pro running Ventura 13.5.1

Thanks!

the default answer

First, I would like to thank you for such a great tool.

Since you randomize answers and this is always welcome, I think there is no need to set a number to correct answer. You can always set it to the first one.

Also, I wonder how can I include an image in my question or its answers

Thanks in advance
Mohamed Ali

Jupterquiz in Jupyterlite notebook

I'm running a workshop in which students run JupyterLite inside their browser on their own laptops, which is much more convenient than having to sort out a running JupyterLab environment for them. Doe anyone have any experience of getting jupyterquiz to run within this enviroment? Is it even possible, given that things like urllib.request don't work in the jupyterlite sandbox?

import error in jupyterlite

when I run the sample code on jupyterlab, I get the following error:

File /lib/python3.11/site-packages/jupyterquiz/dynamic.py:158, in display_quiz(ref, num, shuffle_questions, shuffle_answers, preserve_responses, border_radius, question_alignment, max_width, colors)
    156 url = ref
    157 if sys.platform == 'emscripten':
--> 158     from pyodide import open_url
    159     text = open_url(url).read()
    160     script+=text

ImportError: cannot import name 'open_url' from 'pyodide' (/lib/python311.zip/pyodide/__init__.py)

import pyodide

jupyterlite==0.1.0
jupyterquiz==2.5.2
pyodide==0.23.0

Parse question and answer from cell metadata

When authoring a self-contained notebook for rendering as a Jupyter Book, it's presumably easy enough to put question and answer definitions into a removed code cell in the final book output.

However, if the notebook is used as a notebook, the answers are evident in the code cell.

In such a case, it might be useful to pop the question and answer dictionary into the cell metadata as a JSON object and then render that into the multiple choice widget?

It's a bit of a faff for the notebook author having to edit the metadata cell, but it would keep the notebook self-contained and the answer source hidden to some extent.

How to Layout answers horizontally?

Hii. Thanks for the awesome package.
Is it possible to change the layout of the answers?
I need to provide a wide range of answers (about ten options), so it would be great if they were spread horizontally instead.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.