|
25 | 25 | {
|
26 | 26 | "cell_type": "code",
|
27 | 27 | "execution_count": null,
|
28 |
| - "metadata": {}, |
| 28 | + "metadata": { |
| 29 | + "tags": [] |
| 30 | + }, |
29 | 31 | "outputs": [],
|
30 | 32 | "source": [
|
31 | 33 | "from ipywidgets import interact, interactive, fixed, interact_manual\n",
|
|
294 | 296 | {
|
295 | 297 | "cell_type": "code",
|
296 | 298 | "execution_count": null,
|
297 |
| - "metadata": {}, |
| 299 | + "metadata": { |
| 300 | + "tags": [] |
| 301 | + }, |
298 | 302 | "outputs": [],
|
299 | 303 | "source": [
|
300 |
| - "# %load solutions/reverse-text.py\n" |
| 304 | + "# %load solutions/reverse-text.py" |
301 | 305 | ]
|
302 | 306 | },
|
303 | 307 | {
|
|
351 | 355 | ]
|
352 | 356 | },
|
353 | 357 | {
|
354 |
| - "cell_type": "markdown", |
| 358 | + "cell_type": "code", |
| 359 | + "execution_count": null, |
355 | 360 | "metadata": {},
|
| 361 | + "outputs": [], |
| 362 | + "source": [] |
| 363 | + }, |
| 364 | + { |
| 365 | + "cell_type": "markdown", |
| 366 | + "metadata": { |
| 367 | + "tags": [] |
| 368 | + }, |
356 | 369 | "source": [
|
357 | 370 | "## Basic interactive plot\n",
|
358 | 371 | "\n",
|
359 |
| - "Though the examples so far in this notebook had very basic output, more interesting possibilities are straightforward. \n", |
360 | 372 | "\n",
|
361 |
| - "The function below plots a straight line whose slope and intercept are given by its arguments." |
| 373 | + "The function below plots a straight line whose slope and intercept are given by its arguments.\n", |
| 374 | + "\n", |
| 375 | + "The interactive below displays a line whose slope and intercept is set by the sliders. Note that if the variable containing the widget, `interactive_plot`, is the last thing in the cell it is displayed." |
362 | 376 | ]
|
363 | 377 | },
|
364 | 378 | {
|
365 | 379 | "cell_type": "code",
|
366 | 380 | "execution_count": null,
|
367 |
| - "metadata": {}, |
| 381 | + "metadata": { |
| 382 | + "tags": [] |
| 383 | + }, |
368 | 384 | "outputs": [],
|
369 | 385 | "source": [
|
370 |
| - "%matplotlib widget\n", |
371 | 386 | "import matplotlib.pyplot as plt\n",
|
372 | 387 | "import numpy as np\n",
|
373 |
| - "\n", |
374 | 388 | "def f(m, b):\n",
|
375 | 389 | " plt.figure(2)\n",
|
376 | 390 | " plt.clf()\n",
|
377 | 391 | " plt.grid()\n",
|
378 | 392 | " x = np.linspace(-10, 10, num=1000)\n",
|
379 | 393 | " plt.plot(x, m * x + b)\n",
|
380 | 394 | " plt.ylim(-5, 5)\n",
|
381 |
| - " plt.show()\n" |
| 395 | + " plt.show()" |
382 | 396 | ]
|
383 | 397 | },
|
384 | 398 | {
|
385 | 399 | "cell_type": "markdown",
|
386 | 400 | "metadata": {},
|
387 | 401 | "source": [
|
388 |
| - "The interactive below displays a line whose slope and intercept is set by the sliders. Note that if the variable containing the widget, `interactive_plot`, is the last thing in the cell it is displayed." |
| 402 | + "The interactive below displays a line whose slope and intercept is set by the sliders." |
389 | 403 | ]
|
390 | 404 | },
|
391 | 405 | {
|
392 | 406 | "cell_type": "code",
|
393 | 407 | "execution_count": null,
|
394 |
| - "metadata": {}, |
| 408 | + "metadata": { |
| 409 | + "tags": [] |
| 410 | + }, |
395 | 411 | "outputs": [],
|
396 | 412 | "source": [
|
397 | 413 | "interact(f, m=(-2.0, 2.0), b=(-3, 3, 0.5))"
|
|
401 | 417 | "cell_type": "markdown",
|
402 | 418 | "metadata": {},
|
403 | 419 | "source": [
|
404 |
| - "### Exercise: Make a plot\n", |
| 420 | + "## Fully interactive plot\n", |
| 421 | + "\n", |
| 422 | + "While the above example works, it has some drawbacks:\n", |
| 423 | + "1. It is inefficient to re-run all the plotting code\n", |
| 424 | + "2. No zooming or panning\n", |
| 425 | + "3. Screen can jump when moving the sliders\n", |
405 | 426 | "\n",
|
406 |
| - "Here is a python function that, given $k$ and $p$, plots $f(x) = \\sin(k x - p)$.\n" |
| 427 | + "A better solution is to use the [ipympl](https://matplotlib.org/ipympl/) Matplotlib backend. You can activate this with the line magic: `%matplotlib ipympl`. Then in your interactive function you update the matplotlib artists." |
407 | 428 | ]
|
408 | 429 | },
|
409 | 430 | {
|
410 | 431 | "cell_type": "code",
|
411 | 432 | "execution_count": null,
|
| 433 | + "metadata": { |
| 434 | + "tags": [] |
| 435 | + }, |
| 436 | + "outputs": [], |
| 437 | + "source": [ |
| 438 | + "# activate the widget based backend.\n", |
| 439 | + "%matplotlib ipympl\n", |
| 440 | + "\n", |
| 441 | + "x = np.linspace(-10, 10, num=1000)\n", |
| 442 | + "m, b = 0, 0\n", |
| 443 | + "\n", |
| 444 | + "fig, ax = plt.subplots()\n", |
| 445 | + "ax.grid()\n", |
| 446 | + "ax.set_ylim(-5, 5)\n", |
| 447 | + "line = ax.plot(x, m * x + b)[0]\n", |
| 448 | + "\n", |
| 449 | + "\n", |
| 450 | + "@interact(m=(-2.0, 2.0), b=(-3, 3, 0.5))\n", |
| 451 | + "def update_line(m, b):\n", |
| 452 | + " # use matplotlib functions to update the canvas\n", |
| 453 | + " line.set_ydata(m * x + b)\n", |
| 454 | + " fig.canvas.draw_idle()\n" |
| 455 | + ] |
| 456 | + }, |
| 457 | + { |
| 458 | + "cell_type": "markdown", |
412 | 459 | "metadata": {},
|
| 460 | + "source": [ |
| 461 | + "## mpl-interactions\n", |
| 462 | + "\n", |
| 463 | + "The [mpl-interactions](https://mpl-interactions.readthedocs.io/en/stable/) library can automate the updating of Matplotlib artists for you. non-matplotlib kwargs to functions like `plot` will be interpted to sliders and widget controls similarly to `interact` and automatically connected with the matplotlib artists." |
| 464 | + ] |
| 465 | + }, |
| 466 | + { |
| 467 | + "cell_type": "code", |
| 468 | + "execution_count": null, |
| 469 | + "metadata": { |
| 470 | + "tags": [] |
| 471 | + }, |
413 | 472 | "outputs": [],
|
414 | 473 | "source": [
|
415 |
| - "def plot_f(k, p):\n", |
416 |
| - " plt.figure(5)\n", |
417 |
| - " plt.clf()\n", |
418 |
| - " plt.grid()\n", |
419 |
| - " x = np.linspace(0, 4 * np.pi)\n", |
420 |
| - " y = np.sin(k*x - p)\n", |
421 |
| - " plt.plot(x, y)\n", |
422 |
| - " plt.show()" |
| 474 | + "from mpl_interactions import ipyplot as iplt\n", |
| 475 | + "\n", |
| 476 | + "fig, ax = plt.subplots()\n", |
| 477 | + "ax.grid()\n", |
| 478 | + "ax.set_ylim(-5,5)\n", |
| 479 | + "\n", |
| 480 | + "# define function in a way you can re-use in calculations\n", |
| 481 | + "def f(x, m, b):\n", |
| 482 | + " return m * x + b\n", |
| 483 | + " \n", |
| 484 | + "ctrls = iplt.plot(x, f, m = (-2,2), b=(-3, 3, 10))\n" |
423 | 485 | ]
|
424 | 486 | },
|
425 | 487 | {
|
426 | 488 | "cell_type": "markdown",
|
427 | 489 | "metadata": {},
|
428 | 490 | "source": [
|
429 |
| - "Copy the above function definition and make it interactive using `interact`, so that there are sliders for the parameters $k$ and $p$, where $0.5\\leq k \\leq 2$ and $0 \\leq p \\leq 2\\pi$ (hint: use `np.pi` for $\\pi$)." |
| 491 | + "### Exercise: Make a plot\n", |
| 492 | + "\n", |
| 493 | + "Here is an example of making a plot of $f(x) = \\sin(k x - p)$.\n" |
430 | 494 | ]
|
431 | 495 | },
|
432 | 496 | {
|
433 | 497 | "cell_type": "code",
|
434 | 498 | "execution_count": null,
|
| 499 | + "metadata": { |
| 500 | + "tags": [] |
| 501 | + }, |
| 502 | + "outputs": [], |
| 503 | + "source": [ |
| 504 | + "x = np.linspace(0, 4 * np.pi, 100)\n", |
| 505 | + "k = 1\n", |
| 506 | + "p = np.pi\n", |
| 507 | + "\n", |
| 508 | + "def f(x, k, p):\n", |
| 509 | + " return np.sin(k*x -p)\n", |
| 510 | + "fig, ax = plt.subplots()\n", |
| 511 | + "ax.grid()\n", |
| 512 | + "ax.plot(x, f(x, k, p))\n" |
| 513 | + ] |
| 514 | + }, |
| 515 | + { |
| 516 | + "cell_type": "markdown", |
435 | 517 | "metadata": {},
|
| 518 | + "source": [ |
| 519 | + "Copy the above function definition and make it interactive using `interact` or `mpl-interactions`, so that there are sliders for the parameters $k$ and $p$, where $0.5\\leq k \\leq 2$ and $0 \\leq p \\leq 2\\pi$ (hint: use `np.pi` for $\\pi$)." |
| 520 | + ] |
| 521 | + }, |
| 522 | + { |
| 523 | + "cell_type": "code", |
| 524 | + "execution_count": null, |
| 525 | + "metadata": { |
| 526 | + "tags": [] |
| 527 | + }, |
| 528 | + "outputs": [], |
| 529 | + "source": [ |
| 530 | + "# %load solutions/plot-function-interact.py" |
| 531 | + ] |
| 532 | + }, |
| 533 | + { |
| 534 | + "cell_type": "code", |
| 535 | + "execution_count": null, |
| 536 | + "metadata": { |
| 537 | + "tags": [] |
| 538 | + }, |
436 | 539 | "outputs": [],
|
437 | 540 | "source": [
|
438 |
| - "# %load solutions/plot-function.py" |
| 541 | + "# %load solutions/plot-function-mpl-inter.py" |
439 | 542 | ]
|
440 | 543 | },
|
441 | 544 | {
|
|
460 | 563 | ],
|
461 | 564 | "metadata": {
|
462 | 565 | "kernelspec": {
|
463 |
| - "display_name": "widgets-tutorial", |
| 566 | + "display_name": "Python 3 (ipykernel)", |
464 | 567 | "language": "python",
|
465 |
| - "name": "widgets-tutorial" |
| 568 | + "name": "python3" |
466 | 569 | },
|
467 | 570 | "language_info": {
|
468 | 571 | "codemirror_mode": {
|
|
474 | 577 | "name": "python",
|
475 | 578 | "nbconvert_exporter": "python",
|
476 | 579 | "pygments_lexer": "ipython3",
|
477 |
| - "version": "3.8.10" |
| 580 | + "version": "3.9.13" |
| 581 | + }, |
| 582 | + "widgets": { |
| 583 | + "application/vnd.jupyter.widget-state+json": { |
| 584 | + "state": {}, |
| 585 | + "version_major": 2, |
| 586 | + "version_minor": 0 |
| 587 | + } |
478 | 588 | }
|
479 | 589 | },
|
480 | 590 | "nbformat": 4,
|
|
0 commit comments