|
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 | {
|
|
352 | 356 | },
|
353 | 357 | {
|
354 | 358 | "cell_type": "markdown",
|
355 |
| - "metadata": {}, |
| 359 | + "metadata": { |
| 360 | + "tags": [] |
| 361 | + }, |
356 | 362 | "source": [
|
357 | 363 | "## Basic interactive plot\n",
|
358 | 364 | "\n",
|
359 |
| - "Though the examples so far in this notebook had very basic output, more interesting possibilities are straightforward. \n", |
360 | 365 | "\n",
|
361 | 366 | "The function below plots a straight line whose slope and intercept are given by its arguments."
|
362 | 367 | ]
|
363 | 368 | },
|
364 | 369 | {
|
365 | 370 | "cell_type": "code",
|
366 | 371 | "execution_count": null,
|
367 |
| - "metadata": {}, |
| 372 | + "metadata": { |
| 373 | + "tags": [] |
| 374 | + }, |
368 | 375 | "outputs": [],
|
369 | 376 | "source": [
|
370 |
| - "%matplotlib widget\n", |
371 | 377 | "import matplotlib.pyplot as plt\n",
|
372 | 378 | "import numpy as np\n",
|
373 | 379 | "\n",
|
374 | 380 | "def f(m, b):\n",
|
375 |
| - " plt.figure(2)\n", |
| 381 | + " fig = plt.figure()\n", |
376 | 382 | " plt.clf()\n",
|
377 | 383 | " plt.grid()\n",
|
378 | 384 | " x = np.linspace(-10, 10, num=1000)\n",
|
379 | 385 | " plt.plot(x, m * x + b)\n",
|
380 | 386 | " plt.ylim(-5, 5)\n",
|
381 |
| - " plt.show()\n" |
| 387 | + " plt.show()\n", |
| 388 | + "\n", |
| 389 | + "interact(f, m=(-2.0, 2.0), b=(-3, 3, 0.5))" |
382 | 390 | ]
|
383 | 391 | },
|
384 | 392 | {
|
385 | 393 | "cell_type": "markdown",
|
386 | 394 | "metadata": {},
|
387 | 395 | "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." |
| 396 | + "## Fully interactive plot\n", |
| 397 | + "\n", |
| 398 | + "While the above example works, it has some drawbacks:\n", |
| 399 | + "1. It is inefficient to re-run all the plotting code (the whole plot gets re-created every time -- to see this, run the code above again after running the cell below and see how the figure numbers get incremented)\n", |
| 400 | + "2. No zooming or panning\n", |
| 401 | + "3. Screen can jump when moving the sliders\n", |
| 402 | + "\n", |
| 403 | + "A better solution is to use the [ipympl](https://matplotlib.org/ipympl/) Matplotlib backend. You can activate this with the line magic: `%matplotlib ipympl`." |
389 | 404 | ]
|
390 | 405 | },
|
391 | 406 | {
|
392 | 407 | "cell_type": "code",
|
393 | 408 | "execution_count": null,
|
| 409 | + "metadata": { |
| 410 | + "tags": [] |
| 411 | + }, |
| 412 | + "outputs": [], |
| 413 | + "source": [ |
| 414 | + "# Activate the widget based backend.\n", |
| 415 | + "%matplotlib ipympl\n", |
| 416 | + "\n", |
| 417 | + "x = np.linspace(-10, 10, num=1000)\n", |
| 418 | + "fig, ax = plt.subplots()\n", |
| 419 | + "ax.grid()\n", |
| 420 | + "ax.set_ylim(-5, 5)\n", |
| 421 | + "# Initialize a plot object with y = x. We'll be modifying y below.\n", |
| 422 | + "# This returns a list of `.Line2D` representing the plotted data. We grab the first one -- we only have 1 series.\n", |
| 423 | + "line = ax.plot(x, x)[0]\n", |
| 424 | + "\n", |
| 425 | + "@interact(m=(-2.0, 2.0), b=(-3, 3, 0.5))\n", |
| 426 | + "def update_line(m=1, b=0.5):\n", |
| 427 | + " line.set_ydata(m * x + b)\n", |
| 428 | + " # Request a widget redraw.\n", |
| 429 | + " fig.canvas.draw_idle()" |
| 430 | + ] |
| 431 | + }, |
| 432 | + { |
| 433 | + "cell_type": "markdown", |
394 | 434 | "metadata": {},
|
| 435 | + "source": [ |
| 436 | + "## mpl-interactions\n", |
| 437 | + "\n", |
| 438 | + "The [mpl-interactions](https://mpl-interactions.readthedocs.io/en/stable/) library can automate the updating of Matplotlib plots for you. Non-matplotlib keyword arguments passed to functions like `plot` will be interpreted to sliders and widget controls, similarly to `interact`, and automatically connected with the matplotlib plots." |
| 439 | + ] |
| 440 | + }, |
| 441 | + { |
| 442 | + "cell_type": "code", |
| 443 | + "execution_count": null, |
| 444 | + "metadata": { |
| 445 | + "tags": [] |
| 446 | + }, |
395 | 447 | "outputs": [],
|
396 | 448 | "source": [
|
397 |
| - "interact(f, m=(-2.0, 2.0), b=(-3, 3, 0.5))" |
| 449 | + "from mpl_interactions import ipyplot as iplt\n", |
| 450 | + "\n", |
| 451 | + "fig, ax = plt.subplots()\n", |
| 452 | + "ax.grid()\n", |
| 453 | + "ax.set_ylim(-5,5)\n", |
| 454 | + "\n", |
| 455 | + "# Define function in a way you can re-use in calculations\n", |
| 456 | + "def f(x, m, b):\n", |
| 457 | + " return m * x + b\n", |
| 458 | + " \n", |
| 459 | + "ctrls = iplt.plot(x, f, m=(-2,2), b=(-3, 3, 10))" |
398 | 460 | ]
|
399 | 461 | },
|
400 | 462 | {
|
|
403 | 465 | "source": [
|
404 | 466 | "### Exercise: Make a plot\n",
|
405 | 467 | "\n",
|
406 |
| - "Here is a python function that, given $k$ and $p$, plots $f(x) = \\sin(k x - p)$.\n" |
| 468 | + "Here is an example of making a plot of $f(x) = \\sin(k x - p)$.\n" |
407 | 469 | ]
|
408 | 470 | },
|
409 | 471 | {
|
410 | 472 | "cell_type": "code",
|
411 | 473 | "execution_count": null,
|
412 |
| - "metadata": {}, |
| 474 | + "metadata": { |
| 475 | + "tags": [] |
| 476 | + }, |
413 | 477 | "outputs": [],
|
414 | 478 | "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()" |
| 479 | + "x = np.linspace(0, 4 * np.pi, 100)\n", |
| 480 | + "k = 1\n", |
| 481 | + "p = np.pi\n", |
| 482 | + "\n", |
| 483 | + "def f(x, k, p):\n", |
| 484 | + " return np.sin(k*x -p)\n", |
| 485 | + "fig, ax = plt.subplots()\n", |
| 486 | + "ax.grid()\n", |
| 487 | + "ax.plot(x, f(x, k, p))" |
423 | 488 | ]
|
424 | 489 | },
|
425 | 490 | {
|
426 | 491 | "cell_type": "markdown",
|
427 | 492 | "metadata": {},
|
428 | 493 | "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$)." |
| 494 | + "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$)." |
430 | 495 | ]
|
431 | 496 | },
|
432 | 497 | {
|
433 | 498 | "cell_type": "code",
|
434 | 499 | "execution_count": null,
|
435 |
| - "metadata": {}, |
| 500 | + "metadata": { |
| 501 | + "tags": [] |
| 502 | + }, |
| 503 | + "outputs": [], |
| 504 | + "source": [ |
| 505 | + "# %load solutions/plot-function-interact.py" |
| 506 | + ] |
| 507 | + }, |
| 508 | + { |
| 509 | + "cell_type": "code", |
| 510 | + "execution_count": null, |
| 511 | + "metadata": { |
| 512 | + "tags": [] |
| 513 | + }, |
436 | 514 | "outputs": [],
|
437 | 515 | "source": [
|
438 |
| - "# %load solutions/plot-function.py" |
| 516 | + "# %load solutions/plot-function-mpl-inter.py" |
439 | 517 | ]
|
440 | 518 | },
|
441 | 519 | {
|
|
460 | 538 | ],
|
461 | 539 | "metadata": {
|
462 | 540 | "kernelspec": {
|
463 |
| - "display_name": "widgets-tutorial", |
| 541 | + "display_name": "Python 3 (ipykernel)", |
464 | 542 | "language": "python",
|
465 |
| - "name": "widgets-tutorial" |
| 543 | + "name": "python3" |
466 | 544 | },
|
467 | 545 | "language_info": {
|
468 | 546 | "codemirror_mode": {
|
|
474 | 552 | "name": "python",
|
475 | 553 | "nbconvert_exporter": "python",
|
476 | 554 | "pygments_lexer": "ipython3",
|
477 |
| - "version": "3.8.10" |
| 555 | + "version": "3.9.13" |
| 556 | + }, |
| 557 | + "widgets": { |
| 558 | + "application/vnd.jupyter.widget-state+json": { |
| 559 | + "state": {}, |
| 560 | + "version_major": 2, |
| 561 | + "version_minor": 0 |
| 562 | + } |
478 | 563 | }
|
479 | 564 | },
|
480 | 565 | "nbformat": 4,
|
|
0 commit comments