├── .gitignore ├── LICENSE ├── README.md ├── big-buck-bunny_trailer.webm ├── environment.yml ├── ipyvolume-presentation.ipynb ├── johan-hidding.jpg ├── postBuild └── scipy-2018-3d-viz-jupyter.pdf /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Maarten Breddels 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # talk-ipyvolume-scipy2018 2 | Talk at scipy 2018: Interactive 3d Visualization in Jupyter 3 | 4 | [Slides](https://github.com/maartenbreddels/talk-ipyvolume-scipy2018/blob/master/scipy-2018-3d-viz-jupyter.pdf) and 5 | [![Binder](https://mybinder.org/badge.svg)](https://mybinder.org/v2/gh/maartenbreddels/talk-ipyvolume-scipy2018/master?filepath=ipyvolume-presentation.ipynb) 6 | -------------------------------------------------------------------------------- /big-buck-bunny_trailer.webm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maartenbreddels/talk-ipyvolume-scipy2018/2872f26fd218c7f02306da15985e7cd6806bc705/big-buck-bunny_trailer.webm -------------------------------------------------------------------------------- /environment.yml: -------------------------------------------------------------------------------- 1 | name: scipy2018-ipyvolume 2 | channels: 3 | - conda-forge 4 | dependencies: 5 | - jupyterlab >=0.32 6 | - ipywidgets 7 | - bqplot 8 | - vaex-core 9 | - vaex-hdf5 10 | - vaex-jupyter 11 | - cython 12 | -------------------------------------------------------------------------------- /ipyvolume-presentation.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "# lets pretend all is fine ;-)\n", 10 | "import warnings; warnings.simplefilter('ignore')\n", 11 | "import logging\n", 12 | "logging.disable(logging.CRITICAL)" 13 | ] 14 | }, 15 | { 16 | "cell_type": "markdown", 17 | "metadata": { 18 | "slideshow": { 19 | "slide_type": "slide" 20 | } 21 | }, 22 | "source": [ 23 | "# Interactive 3d Visualization in Jupyter\n", 24 | " * Maarten Breddels (freelance/independent)\n", 25 | " * SciPy - 2018" 26 | ] 27 | }, 28 | { 29 | "cell_type": "code", 30 | "execution_count": null, 31 | "metadata": {}, 32 | "outputs": [], 33 | "source": [ 34 | "# get the dataset from https://docs.vaex.io/en/latest/datasets.html\n", 35 | "# import vaex\n", 36 | "# ds = vaex.open('/Users/maartenbreddels/datasets/nytaxi/nyc_taxi2015.hdf5')\n", 37 | "# ds.plot_widget(ds.pickup_longitude, ds.pickup_latitude, f='log')" 38 | ] 39 | }, 40 | { 41 | "cell_type": "code", 42 | "execution_count": null, 43 | "metadata": {}, 44 | "outputs": [], 45 | "source": [ 46 | "import vaex\n", 47 | "# ds = vaex.datasets.helmi_de_zeeuw.fetch()\n", 48 | "ds = vaex.example()" 49 | ] 50 | }, 51 | { 52 | "cell_type": "code", 53 | "execution_count": null, 54 | "metadata": {}, 55 | "outputs": [], 56 | "source": [ 57 | "ds.plot_widget('x', 'y', f='log', controls_selection=True)" 58 | ] 59 | }, 60 | { 61 | "cell_type": "code", 62 | "execution_count": null, 63 | "metadata": {}, 64 | "outputs": [], 65 | "source": [ 66 | "ds.plot_widget('Lz', 'E', f='log', controls_selection=True)" 67 | ] 68 | }, 69 | { 70 | "cell_type": "code", 71 | "execution_count": null, 72 | "metadata": {}, 73 | "outputs": [], 74 | "source": [] 75 | }, 76 | { 77 | "cell_type": "markdown", 78 | "metadata": { 79 | "slideshow": { 80 | "slide_type": "slide" 81 | } 82 | }, 83 | "source": [ 84 | "# Intro: simple expected API" 85 | ] 86 | }, 87 | { 88 | "cell_type": "code", 89 | "execution_count": null, 90 | "metadata": { 91 | "slideshow": { 92 | "slide_type": "fragment" 93 | } 94 | }, 95 | "outputs": [], 96 | "source": [ 97 | "import ipyvolume as ipv\n", 98 | "import numpy as np" 99 | ] 100 | }, 101 | { 102 | "cell_type": "code", 103 | "execution_count": null, 104 | "metadata": { 105 | "slideshow": { 106 | "slide_type": "fragment" 107 | } 108 | }, 109 | "outputs": [], 110 | "source": [ 111 | "N = 1000\n", 112 | "x, y, z = np.random.normal(0, 1, (3, N))" 113 | ] 114 | }, 115 | { 116 | "cell_type": "code", 117 | "execution_count": null, 118 | "metadata": { 119 | "slideshow": { 120 | "slide_type": "fragment" 121 | } 122 | }, 123 | "outputs": [], 124 | "source": [ 125 | "fig = ipv.figure()\n", 126 | "scatter = ipv.scatter(x, y, z, marker='sphere')\n", 127 | "ipv.show()" 128 | ] 129 | }, 130 | { 131 | "cell_type": "code", 132 | "execution_count": null, 133 | "metadata": { 134 | "slideshow": { 135 | "slide_type": "fragment" 136 | } 137 | }, 138 | "outputs": [], 139 | "source": [ 140 | "scatter.geo = 'box'" 141 | ] 142 | }, 143 | { 144 | "cell_type": "code", 145 | "execution_count": null, 146 | "metadata": {}, 147 | "outputs": [], 148 | "source": [ 149 | "scatter.x = x + 2" 150 | ] 151 | }, 152 | { 153 | "cell_type": "code", 154 | "execution_count": null, 155 | "metadata": {}, 156 | "outputs": [], 157 | "source": [ 158 | "ipv.save('example.html')" 159 | ] 160 | }, 161 | { 162 | "cell_type": "markdown", 163 | "metadata": {}, 164 | "source": [ 165 | "[example.html](example.html)" 166 | ] 167 | }, 168 | { 169 | "cell_type": "markdown", 170 | "metadata": { 171 | "slideshow": { 172 | "slide_type": "slide" 173 | } 174 | }, 175 | "source": [ 176 | "# Built on ipywidgets" 177 | ] 178 | }, 179 | { 180 | "cell_type": "code", 181 | "execution_count": null, 182 | "metadata": { 183 | "scrolled": false, 184 | "slideshow": { 185 | "slide_type": "-" 186 | } 187 | }, 188 | "outputs": [], 189 | "source": [ 190 | "import ipywidgets as widgets\n", 191 | "fig" 192 | ] 193 | }, 194 | { 195 | "cell_type": "code", 196 | "execution_count": null, 197 | "metadata": {}, 198 | "outputs": [], 199 | "source": [ 200 | "scatter.geo = 'diamond'" 201 | ] 202 | }, 203 | { 204 | "cell_type": "code", 205 | "execution_count": null, 206 | "metadata": { 207 | "slideshow": { 208 | "slide_type": "fragment" 209 | } 210 | }, 211 | "outputs": [], 212 | "source": [ 213 | "w = widgets.ToggleButtons(options=['sphere', 'box', 'diamond', 'circle_2d', 'point_2d', 'arrow'])\n", 214 | "widgets.link((scatter, 'geo'), (w, 'value'))\n", 215 | "w" 216 | ] 217 | }, 218 | { 219 | "cell_type": "code", 220 | "execution_count": null, 221 | "metadata": {}, 222 | "outputs": [], 223 | "source": [ 224 | "scatter.size = 10" 225 | ] 226 | }, 227 | { 228 | "cell_type": "code", 229 | "execution_count": null, 230 | "metadata": {}, 231 | "outputs": [], 232 | "source": [ 233 | "slider = widgets.FloatSlider(min=0.0, max=10, step=0.1)\n", 234 | "widgets.jslink((scatter, 'size'), (slider, 'value'))\n", 235 | "slider" 236 | ] 237 | }, 238 | { 239 | "cell_type": "markdown", 240 | "metadata": { 241 | "slideshow": { 242 | "slide_type": "slide" 243 | } 244 | }, 245 | "source": [ 246 | "# Features\n", 247 | " * scatter/quiver\n", 248 | " * quiver\n", 249 | " * mesh\n", 250 | " * lines\n", 251 | " * volumes ('3d imshow')\n", 252 | " * isosurfaces" 253 | ] 254 | }, 255 | { 256 | "cell_type": "markdown", 257 | "metadata": { 258 | "slideshow": { 259 | "slide_type": "slide" 260 | } 261 | }, 262 | "source": [ 263 | "# Quiver plot" 264 | ] 265 | }, 266 | { 267 | "cell_type": "code", 268 | "execution_count": null, 269 | "metadata": {}, 270 | "outputs": [], 271 | "source": [ 272 | "fig = ipv.figure()\n", 273 | "quiver = ipv.quiver(x, y, z, x, y, z, size=4)\n", 274 | "ipv.show()" 275 | ] 276 | }, 277 | { 278 | "cell_type": "code", 279 | "execution_count": null, 280 | "metadata": {}, 281 | "outputs": [], 282 | "source": [ 283 | "quiver.vx = -quiver.vx\n", 284 | "quiver.vy = quiver.vy\n", 285 | "quiver.vz = -quiver.vz" 286 | ] 287 | }, 288 | { 289 | "cell_type": "code", 290 | "execution_count": null, 291 | "metadata": {}, 292 | "outputs": [], 293 | "source": [ 294 | "quiver.color = 'green'" 295 | ] 296 | }, 297 | { 298 | "cell_type": "code", 299 | "execution_count": null, 300 | "metadata": {}, 301 | "outputs": [], 302 | "source": [ 303 | "cp = widgets.ColorPicker(value='pink')\n", 304 | "widgets.jsdlink((cp, 'value'), (quiver, 'color'))\n", 305 | "cp" 306 | ] 307 | }, 308 | { 309 | "cell_type": "code", 310 | "execution_count": null, 311 | "metadata": {}, 312 | "outputs": [], 313 | "source": [ 314 | "quiver.color = np.random.random((N,3))" 315 | ] 316 | }, 317 | { 318 | "cell_type": "code", 319 | "execution_count": null, 320 | "metadata": {}, 321 | "outputs": [], 322 | "source": [] 323 | }, 324 | { 325 | "cell_type": "markdown", 326 | "metadata": { 327 | "slideshow": { 328 | "slide_type": "slide" 329 | } 330 | }, 331 | "source": [ 332 | "# Mesh" 333 | ] 334 | }, 335 | { 336 | "cell_type": "code", 337 | "execution_count": null, 338 | "metadata": { 339 | "slideshow": { 340 | "slide_type": "fragment" 341 | } 342 | }, 343 | "outputs": [], 344 | "source": [ 345 | "s = 1/2**0.5\n", 346 | "# 4 vertices for the tetrahedron\n", 347 | "x = np.array([1., -1, 0, 0])\n", 348 | "y = np.array([0, 0, 1., -1])\n", 349 | "z = np.array([-s, -s, s, s])\n", 350 | "# and 4 surfaces (triangles), where the number refer to the vertex index\n", 351 | "triangles = [(0, 1, 2), (0, 1, 3), (0, 2, 3), (1,3,2)]" 352 | ] 353 | }, 354 | { 355 | "cell_type": "code", 356 | "execution_count": null, 357 | "metadata": {}, 358 | "outputs": [], 359 | "source": [ 360 | "ipv.figure()\n", 361 | "ipv.plot_trisurf(x, y, z, triangles=triangles, color='orange')\n", 362 | "ipv.scatter(x, y, z, marker='sphere', color='blue')\n", 363 | "ipv.xyzlim(-2, 2)\n", 364 | "ipv.show()" 365 | ] 366 | }, 367 | { 368 | "cell_type": "code", 369 | "execution_count": null, 370 | "metadata": {}, 371 | "outputs": [], 372 | "source": [ 373 | "a = np.linspace(-5, 5, 30)\n", 374 | "U, V = np.meshgrid(a, a)\n", 375 | "\n", 376 | "X = U\n", 377 | "Y = V\n", 378 | "Z = X*Y**2" 379 | ] 380 | }, 381 | { 382 | "cell_type": "code", 383 | "execution_count": null, 384 | "metadata": {}, 385 | "outputs": [], 386 | "source": [ 387 | "ipv.figure()\n", 388 | "mesh = ipv.plot_surface(X, Z, Y, color=\"orange\")\n", 389 | "ipv.show()" 390 | ] 391 | }, 392 | { 393 | "cell_type": "code", 394 | "execution_count": null, 395 | "metadata": {}, 396 | "outputs": [], 397 | "source": [ 398 | "mesh.y = -mesh.y\n", 399 | "mesh.x = mesh.x * 1.4\n", 400 | "mesh.color = 'green'" 401 | ] 402 | }, 403 | { 404 | "cell_type": "markdown", 405 | "metadata": { 406 | "slideshow": { 407 | "slide_type": "slide" 408 | } 409 | }, 410 | "source": [ 411 | "# Mesh + texture mapping" 412 | ] 413 | }, 414 | { 415 | "cell_type": "code", 416 | "execution_count": null, 417 | "metadata": {}, 418 | "outputs": [], 419 | "source": [ 420 | "ipv.figure()\n", 421 | "brain = ipv.examples.brain();" 422 | ] 423 | }, 424 | { 425 | "cell_type": "code", 426 | "execution_count": null, 427 | "metadata": {}, 428 | "outputs": [], 429 | "source": [ 430 | "import PIL.Image\n", 431 | "brain.texture = PIL.Image.open('./johan-hidding.jpg')" 432 | ] 433 | }, 434 | { 435 | "cell_type": "code", 436 | "execution_count": null, 437 | "metadata": {}, 438 | "outputs": [], 439 | "source": [ 440 | "brain.material.wireframe = True" 441 | ] 442 | }, 443 | { 444 | "cell_type": "markdown", 445 | "metadata": { 446 | "slideshow": { 447 | "slide_type": "slide" 448 | } 449 | }, 450 | "source": [ 451 | "# Lines" 452 | ] 453 | }, 454 | { 455 | "cell_type": "code", 456 | "execution_count": null, 457 | "metadata": {}, 458 | "outputs": [], 459 | "source": [ 460 | "import ipyvolume as ipv\n", 461 | "import numpy as np" 462 | ] 463 | }, 464 | { 465 | "cell_type": "code", 466 | "execution_count": null, 467 | "metadata": {}, 468 | "outputs": [], 469 | "source": [ 470 | "fig = ipv.figure()\n", 471 | "u = np.linspace(0, 1, 4000)\n", 472 | "r = 1 + 0.3 * np.sin(u*np.pi*4)\n", 473 | "x = np.sin(u*2*np.pi*40) * r\n", 474 | "y = np.cos(u*2*np.pi*40) * r\n", 475 | "z = u\n", 476 | "line = ipv.plot(x, y, z)\n", 477 | "fig.camera.rotateY(1)\n", 478 | "ipv.show()" 479 | ] 480 | }, 481 | { 482 | "cell_type": "code", 483 | "execution_count": null, 484 | "metadata": {}, 485 | "outputs": [], 486 | "source": [ 487 | "r = 1 + 0.3 * np.sin(u*np.pi*3)\n", 488 | "line.x = np.sin(u*2*np.pi*40) * r\n", 489 | "line.y = np.cos(u*2*np.pi*40) * r\n", 490 | "line.color = np.stack([u*0, u, u*0], 1)" 491 | ] 492 | }, 493 | { 494 | "cell_type": "markdown", 495 | "metadata": { 496 | "slideshow": { 497 | "slide_type": "slide" 498 | } 499 | }, 500 | "source": [ 501 | "# Volumetric data\n", 502 | "## Volume rendering" 503 | ] 504 | }, 505 | { 506 | "cell_type": "code", 507 | "execution_count": null, 508 | "metadata": {}, 509 | "outputs": [], 510 | "source": [ 511 | "I = ipv.example_ylm(draw=False, show=False, shape=64)\n", 512 | "I.shape, type(I)" 513 | ] 514 | }, 515 | { 516 | "cell_type": "code", 517 | "execution_count": null, 518 | "metadata": {}, 519 | "outputs": [], 520 | "source": [ 521 | "ipv.figure()\n", 522 | "ipv.volshow(I)\n", 523 | "ipv.show()" 524 | ] 525 | }, 526 | { 527 | "cell_type": "markdown", 528 | "metadata": { 529 | "slideshow": { 530 | "slide_type": "slide" 531 | } 532 | }, 533 | "source": [ 534 | "# Isosurfaces" 535 | ] 536 | }, 537 | { 538 | "cell_type": "code", 539 | "execution_count": null, 540 | "metadata": {}, 541 | "outputs": [], 542 | "source": [ 543 | "fig = ipv.figure()\n", 544 | "mesh = ipv.plot_isosurface(I, level=0.08)\n", 545 | "ipv.xyzlim(0, 64)\n", 546 | "ipv.show()" 547 | ] 548 | }, 549 | { 550 | "cell_type": "code", 551 | "execution_count": null, 552 | "metadata": {}, 553 | "outputs": [], 554 | "source": [ 555 | "mesh.z = (64-mesh.z) " 556 | ] 557 | }, 558 | { 559 | "cell_type": "code", 560 | "execution_count": null, 561 | "metadata": {}, 562 | "outputs": [], 563 | "source": [ 564 | "fig.animation = 0" 565 | ] 566 | }, 567 | { 568 | "cell_type": "markdown", 569 | "metadata": { 570 | "slideshow": { 571 | "slide_type": "slide" 572 | } 573 | }, 574 | "source": [ 575 | "# Animations: Performance" 576 | ] 577 | }, 578 | { 579 | "cell_type": "code", 580 | "execution_count": null, 581 | "metadata": {}, 582 | "outputs": [], 583 | "source": [ 584 | "M = 1000*1000\n", 585 | "xm, ym, zm = np.random.normal(0, 1, (3, M))\n", 586 | "fig = ipv.figure()\n", 587 | "scatterm = ipv.scatter(xm, ym, zm, marker='diamond')\n", 588 | "ipv.show()" 589 | ] 590 | }, 591 | { 592 | "cell_type": "code", 593 | "execution_count": null, 594 | "metadata": {}, 595 | "outputs": [], 596 | "source": [ 597 | "scatterm.size = 0.1" 598 | ] 599 | }, 600 | { 601 | "cell_type": "code", 602 | "execution_count": null, 603 | "metadata": {}, 604 | "outputs": [], 605 | "source": [ 606 | "scatterm.x = xm * 3" 607 | ] 608 | }, 609 | { 610 | "cell_type": "markdown", 611 | "metadata": {}, 612 | "source": [ 613 | "# Back to our galaxy" 614 | ] 615 | }, 616 | { 617 | "cell_type": "code", 618 | "execution_count": null, 619 | "metadata": {}, 620 | "outputs": [], 621 | "source": [ 622 | "plot3d = ds.plot_widget(\"x\", \"y\", \"z\", vx=\"vx\", vy=\"vy\", vz=\"vz\",\n", 623 | " backend=\"ipyvolume\", f=\"log1p\", shape=100, smooth_pre=0.5)#, vcount_limits = [50, 100000])" 624 | ] 625 | }, 626 | { 627 | "cell_type": "code", 628 | "execution_count": null, 629 | "metadata": {}, 630 | "outputs": [], 631 | "source": [ 632 | "plot3d.vcount_limits = [50, 100000]" 633 | ] 634 | }, 635 | { 636 | "cell_type": "markdown", 637 | "metadata": {}, 638 | "source": [ 639 | "# Large datasets" 640 | ] 641 | }, 642 | { 643 | "cell_type": "code", 644 | "execution_count": null, 645 | "metadata": { 646 | "slideshow": { 647 | "slide_type": "slide" 648 | } 649 | }, 650 | "outputs": [], 651 | "source": [ 652 | "# import vaex\n", 653 | "# ds = vaex.open('/Users/maartenbreddels/datasets/aquarius/Aq-A-2-999-shuffled.hdf5')\n", 654 | "# ds.set_active_fraction(0.5)\n", 655 | "# print(f'{len(ds):,}')\n", 656 | "# ds.plot_widget('x', 'y', 'z', f='log', extent=[[40, 60]]*3, backend='ipyvolume', shape=100)" 657 | ] 658 | }, 659 | { 660 | "cell_type": "markdown", 661 | "metadata": { 662 | "slideshow": { 663 | "slide_type": "slide" 664 | } 665 | }, 666 | "source": [ 667 | "# Large data cubes\n", 668 | "using glue-jupyter (http://glueviz.org/)" 669 | ] 670 | }, 671 | { 672 | "cell_type": "code", 673 | "execution_count": null, 674 | "metadata": {}, 675 | "outputs": [], 676 | "source": [ 677 | "# import glue_jupyter as gj\n", 678 | "# app = gj.jglue(volume='/Users/maartenbreddels/datasets/glue/Filament_5/Data/GRS/fil5_grs_large.fits')\n", 679 | "# app.volshow()" 680 | ] 681 | }, 682 | { 683 | "cell_type": "markdown", 684 | "metadata": {}, 685 | "source": [ 686 | "# Selections" 687 | ] 688 | }, 689 | { 690 | "cell_type": "code", 691 | "execution_count": null, 692 | "metadata": {}, 693 | "outputs": [], 694 | "source": [ 695 | "N = 1000\n", 696 | "x, y, z = np.random.normal(0, 1, (3, N))" 697 | ] 698 | }, 699 | { 700 | "cell_type": "code", 701 | "execution_count": null, 702 | "metadata": {}, 703 | "outputs": [], 704 | "source": [ 705 | "fig = ipv.figure()\n", 706 | "scatter = ipv.scatter(x, y, z, marker='sphere', color='green')\n", 707 | "ipv.selector_default()\n", 708 | "ipv.show()\n", 709 | "def print_info(*_):\n", 710 | " indices = scatter.selected[0]\n", 711 | " meanx = np.mean(scatter.x[indices])\n", 712 | " print('mean x', meanx)\n", 713 | "scatter.observe(print_info, 'selected')" 714 | ] 715 | }, 716 | { 717 | "cell_type": "markdown", 718 | "metadata": { 719 | "slideshow": { 720 | "slide_type": "slide" 721 | } 722 | }, 723 | "source": [ 724 | "# Time / Keyframes" 725 | ] 726 | }, 727 | { 728 | "cell_type": "code", 729 | "execution_count": null, 730 | "metadata": {}, 731 | "outputs": [], 732 | "source": [ 733 | "import ipywidgets as widgets\n", 734 | "data = ipv.datasets.animated_stream.fetch().data[...,::4]\n", 735 | "x, y, z, vx, vy, vz = data\n", 736 | "x.shape" 737 | ] 738 | }, 739 | { 740 | "cell_type": "code", 741 | "execution_count": null, 742 | "metadata": {}, 743 | "outputs": [], 744 | "source": [ 745 | "v = np.sqrt(x**2 + y**2 + z**2)\n", 746 | "v -= v.min(); v /= v.max();\n", 747 | "import matplotlib.cm as cm\n", 748 | "colors = np.array([cm.Reds(k) for k in v])" 749 | ] 750 | }, 751 | { 752 | "cell_type": "code", 753 | "execution_count": null, 754 | "metadata": {}, 755 | "outputs": [], 756 | "source": [ 757 | "fig = ipv.figure()\n", 758 | "ipv.style.use('dark')\n", 759 | "# use just rgb colors, not rgba\n", 760 | "quiver = ipv.quiver(x, y, z, vx, vy, vz, size=5, color=colors[:,:,:3])\n", 761 | "ipv.show()" 762 | ] 763 | }, 764 | { 765 | "cell_type": "code", 766 | "execution_count": null, 767 | "metadata": {}, 768 | "outputs": [], 769 | "source": [ 770 | "ipv.style.use('light')" 771 | ] 772 | }, 773 | { 774 | "cell_type": "code", 775 | "execution_count": null, 776 | "metadata": {}, 777 | "outputs": [], 778 | "source": [ 779 | "quiver.sequence_index = 3" 780 | ] 781 | }, 782 | { 783 | "cell_type": "code", 784 | "execution_count": null, 785 | "metadata": {}, 786 | "outputs": [], 787 | "source": [ 788 | "ipv.animation_control(quiver, interval=400)" 789 | ] 790 | }, 791 | { 792 | "cell_type": "code", 793 | "execution_count": null, 794 | "metadata": {}, 795 | "outputs": [], 796 | "source": [ 797 | "w = widgets.ToggleButtons(options=['arrow', 'sphere', 'cat'])\n", 798 | "widgets.link((quiver, 'geo'), (w, 'value'))\n", 799 | "w" 800 | ] 801 | }, 802 | { 803 | "cell_type": "code", 804 | "execution_count": null, 805 | "metadata": {}, 806 | "outputs": [], 807 | "source": [] 808 | }, 809 | { 810 | "cell_type": "code", 811 | "execution_count": null, 812 | "metadata": {}, 813 | "outputs": [], 814 | "source": [ 815 | "from ipyvolume.moviemaker import MovieMaker\n", 816 | "mm = MovieMaker(stream=fig, camera=fig.camera)\n", 817 | "mm.widget_main" 818 | ] 819 | }, 820 | { 821 | "cell_type": "code", 822 | "execution_count": null, 823 | "metadata": {}, 824 | "outputs": [], 825 | "source": [ 826 | "fig" 827 | ] 828 | }, 829 | { 830 | "cell_type": "code", 831 | "execution_count": null, 832 | "metadata": {}, 833 | "outputs": [], 834 | "source": [ 835 | "import ipywebrtc as webrtc" 836 | ] 837 | }, 838 | { 839 | "cell_type": "code", 840 | "execution_count": null, 841 | "metadata": {}, 842 | "outputs": [], 843 | "source": [ 844 | "webrtc.MediaRecorder(stream=fig, filename='scipy2018')" 845 | ] 846 | }, 847 | { 848 | "cell_type": "code", 849 | "execution_count": null, 850 | "metadata": {}, 851 | "outputs": [], 852 | "source": [ 853 | "_.data[:100]" 854 | ] 855 | }, 856 | { 857 | "cell_type": "code", 858 | "execution_count": null, 859 | "metadata": {}, 860 | "outputs": [], 861 | "source": [ 862 | "from IPython.display import YouTubeVideo\n", 863 | "YouTubeVideo('ZOnV5vAVwR4')" 864 | ] 865 | }, 866 | { 867 | "cell_type": "markdown", 868 | "metadata": {}, 869 | "source": [ 870 | "# WebRTC Fun" 871 | ] 872 | }, 873 | { 874 | "cell_type": "code", 875 | "execution_count": null, 876 | "metadata": {}, 877 | "outputs": [], 878 | "source": [ 879 | "import ipywidgets as widgets\n", 880 | "widgets.Widget.close_all()" 881 | ] 882 | }, 883 | { 884 | "cell_type": "code", 885 | "execution_count": null, 886 | "metadata": {}, 887 | "outputs": [], 888 | "source": [ 889 | "video = webrtc.VideoStream.from_file('big-buck-bunny_trailer.webm')\n", 890 | "video" 891 | ] 892 | }, 893 | { 894 | "cell_type": "code", 895 | "execution_count": null, 896 | "metadata": {}, 897 | "outputs": [], 898 | "source": [ 899 | "camera = webrtc.CameraStream()\n", 900 | "camera" 901 | ] 902 | }, 903 | { 904 | "cell_type": "code", 905 | "execution_count": null, 906 | "metadata": {}, 907 | "outputs": [], 908 | "source": [ 909 | "fig = ipv.figure(render_continuous=True)\n", 910 | "back = ipv.plot_plane(\"back\", texture=video)\n", 911 | "right = ipv.plot_plane(\"right\", texture=camera)\n", 912 | "ipv.show()" 913 | ] 914 | }, 915 | { 916 | "cell_type": "code", 917 | "execution_count": null, 918 | "metadata": {}, 919 | "outputs": [], 920 | "source": [ 921 | "right.texture = fig" 922 | ] 923 | }, 924 | { 925 | "cell_type": "code", 926 | "execution_count": null, 927 | "metadata": {}, 928 | "outputs": [], 929 | "source": [ 930 | "chatroom = webrtc.chat(room='scipy2018a', stream=fig)" 931 | ] 932 | }, 933 | { 934 | "cell_type": "code", 935 | "execution_count": null, 936 | "metadata": {}, 937 | "outputs": [], 938 | "source": [ 939 | "right.texture = chatroom.streams[1]" 940 | ] 941 | }, 942 | { 943 | "cell_type": "code", 944 | "execution_count": null, 945 | "metadata": {}, 946 | "outputs": [], 947 | "source": [ 948 | "widgets.Widget.close_all()" 949 | ] 950 | }, 951 | { 952 | "cell_type": "code", 953 | "execution_count": null, 954 | "metadata": {}, 955 | "outputs": [], 956 | "source": [] 957 | } 958 | ], 959 | "metadata": { 960 | "kernelspec": { 961 | "display_name": "Python 3", 962 | "language": "python", 963 | "name": "python3" 964 | }, 965 | "language_info": { 966 | "codemirror_mode": { 967 | "name": "ipython", 968 | "version": 3 969 | }, 970 | "file_extension": ".py", 971 | "mimetype": "text/x-python", 972 | "name": "python", 973 | "nbconvert_exporter": "python", 974 | "pygments_lexer": "ipython3", 975 | "version": "3.6.4" 976 | }, 977 | "livereveal": { 978 | "center": false, 979 | "scroll": true 980 | } 981 | }, 982 | "nbformat": 4, 983 | "nbformat_minor": 2 984 | } 985 | -------------------------------------------------------------------------------- /johan-hidding.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maartenbreddels/talk-ipyvolume-scipy2018/2872f26fd218c7f02306da15985e7cd6806bc705/johan-hidding.jpg -------------------------------------------------------------------------------- /postBuild: -------------------------------------------------------------------------------- 1 | pip install 'git+https://github.com/maartenbreddels/ipyvolume.git@d8c3e17abd12b3fc0c5169eac84466761117ce90' 2 | pip install 'git+https://github.com/maartenbreddels/ipywebrtc.git@7b364018501957fb9c778c0ee3d850b88e52f83f' 3 | pip install 'git+https://github.com/gallantlab/pycortex.git@13054a2dc1a773b436b0cbfdd562a8f25154f20b' 4 | -------------------------------------------------------------------------------- /scipy-2018-3d-viz-jupyter.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maartenbreddels/talk-ipyvolume-scipy2018/2872f26fd218c7f02306da15985e7cd6806bc705/scipy-2018-3d-viz-jupyter.pdf --------------------------------------------------------------------------------