{ "cells": [ { "cell_type": "markdown", "id": "0", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "source": [ "# Getting started\n", "\n", "scicode-widgets can be installed with:\n", "\n", "```bash\n", " pip install scwidgets\n", "```" ] }, { "cell_type": "raw", "id": "1", "metadata": { "editable": true, "raw_mimetype": "text/restructuredtext", "slideshow": { "slide_type": "" }, "tags": [], "vscode": { "languageId": "raw" } }, "source": [ ".. important::\n", " Jupyter widgets cannot be run within the documentation. To interact with the widget, you must run a mybinder instance. To run a mybinder instance of this notebook, please use this link https://mybinder.org/v2/gh/osscar-org/scicode-widgets/HEAD?labpath=docs%2Fsrc%2Fgetting_started.ipynb. Note that also the LaTeX rendering is resolved when running the notebook." ] }, { "cell_type": "markdown", "id": "2", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "source": [ "## Creating a code exercise\n", "This is how a simple coding exercise can look like." ] }, { "cell_type": "code", "execution_count": null, "id": "3", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "outputs": [], "source": [ "from scwidgets import CodeExercise\n", "\n", "import matplotlib.pyplot as plt\n", "import numpy as np\n", "\n", "# This is what the students sees and can adapt\n", "def sin(x, omega):\n", " import numpy as np\n", " # We already provide the solution for the demo\n", " return np.sin(x*omega)\n", "\n", "\n", "x = np.linspace(-2*np.pi, 2*np.pi, 100)\n", "def update_func(code_ex):\n", " y = code_ex.code(x, code_ex.parameters[\"omega\"])\n", " ax = code_ex.figure.gca()\n", " ax.plot(x, y)\n", "\n", "code_ex = CodeExercise(\n", " code=sin,\n", " outputs=plt.figure(),\n", " parameters={\"omega\": (0.5, 3.14, 0.1)},\n", " update=update_func,\n", " update_mode=\"continuous\",\n", " title=\"Sine function\",\n", " description=\"Implements $\\\\sin(x\\\\omega)$\",\n", ")\n", "\n", "code_ex.run_update() # For the demonstration we run the widget one time\n", "display(code_ex)" ] }, { "cell_type": "markdown", "id": "4", "metadata": {}, "source": [ "Please look at __[exercises section](./exercises.html)__ for more information about the exercises that can be created and their customization options." ] }, { "cell_type": "markdown", "id": "5", "metadata": {}, "source": [ "## Check student's solution\n", "\n", "You can create checks (like unit tests) to help students verify their solutions:" ] }, { "cell_type": "code", "execution_count": null, "id": "6", "metadata": { "lines_to_next_cell": 2, "tags": [] }, "outputs": [], "source": [ "from scwidgets import (\n", " CheckRegistry,\n", " assert_numpy_allclose,\n", " assert_shape,\n", " assert_type,\n", ")\n", "\n", "\n", "check_registry = CheckRegistry()\n", "\n", "def sine(arr):\n", " import numpy as np\n", " return np.cos(arr) # oops! wrong solution\n", "\n", "check_code_ex = CodeExercise(\n", " code=sine,\n", " update=lambda code_ex: print(code_ex.code(np.pi)),\n", " check_registry=check_registry,\n", ")\n", "\n", "def assert_2pi_periodic() -> str:\n", " out = check_code_ex.code([0, 2*np.pi])\n", " if not np.allclose(out[0], out[1]):\n", " return \"Function is not periodic.\"\n", " return \"\" # empty strings means it passes\n", "\n", "check_registry.add_check(\n", " check_code_ex,\n", " asserts=[\n", " assert_2pi_periodic,\n", " ]\n", ")\n", "\n", "check_registry.add_check(\n", " check_code_ex,\n", " asserts=[\n", " assert_type, # checks if same type as reference values \n", " assert_shape, # checks if same shape as reference values\n", " assert_numpy_allclose, # checks if allclose to reference values\n", " ],\n", " inputs_parameters=[{\"arr\": np.asarray([0., 0.78539816, 1.57079633, 2.35619449, 3.14159265])}],\n", " outputs_references=[(np.asarray([0., 7.07106781e-01, 1.00000000e+00, 7.07106781e-01, 0.]),)]\n", ")\n", "\n", "check_code_ex.run_check()\n", "check_code_ex" ] }, { "cell_type": "markdown", "id": "7", "metadata": { "lines_to_next_cell": 2 }, "source": [ "Please look at the __[section on how to add checks](check.html)__ for all options to create them." ] }, { "cell_type": "markdown", "id": "8", "metadata": { "lines_to_next_cell": 2 }, "source": [ "## `nbgrader` integration \n", "\n", "One can use `nbgrader` by using their macros.\n", "\n", "```python\n", "def sin(arr: np.ndarray):\n", " \"\"\"\n", " :param arr: array of arbitrary shape\n", " :return: returns the sine\n", " \"\"\"\n", " import numpy as np\n", " ### BEGIN SOLUTION\n", " sin_arr = np.sin(arr)\n", " ### END SOLUTION\n", " return sin_arr\n", "```\n", "\n", "Then, `nbgrader` will convert this to" ] }, { "cell_type": "code", "execution_count": null, "id": "9", "metadata": { "tags": [] }, "outputs": [], "source": [ "def sin(arr: np.ndarray):\n", " \"\"\"\n", " :param arr: array of arbitrary shape\n", " :return: returns the sine\n", " \"\"\"\n", " import numpy as np\n", " # YOUR CODE HERE\n", " raise NotImplementedError()\n", " return sin_arr\n", "\n", "code_ex = CodeExercise(\n", " code=sin\n", ")\n", "\n", "display(code_ex)" ] }, { "cell_type": "markdown", "id": "10", "metadata": { "tags": [] }, "source": [ "It requires to add a hook in the config to copy over the student's answers to the grading subfolder. A step-by-step tutorial how to make an `nbgrader` project compatible with `scwidget` can be seen in the repo." ] } ], "metadata": { "kernelspec": { "display_name": "scicode", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.11" }, "tags": [] }, "nbformat": 4, "nbformat_minor": 5 }