{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "import subprocess\nimport sys\n\nif \"google.colab\" in sys.modules:\n subprocess.run(\"apt-get update\", shell=True, check=True)\n subprocess.run(\"apt-get install -qq xvfb libgl1-mesa-glx\", shell=True, check=True)\n subprocess.run(\"pip install pyvista[all] -qq\", shell=True, check=True)\n\n import pyvista as pv\n\n # Seems that only static plotting is supported by colab at the moment\n pv.global_theme.jupyter_backend = \"static\"\n pv.global_theme.notebook = True\n pv.start_xvfb()\nelse:\n %matplotlib inline\n from pyvista import set_plot_theme\n\n set_plot_theme(\"document\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Create Point Cloud {#create_point_cloud_exercise}\n==================\n\nCreate a `pyvista.PolyData`{.interpreted-text role=\"class\"} object from\na point cloud of vertices and scalar arrays for those points.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "import numpy as np\nimport pyvista as pv\nfrom pyvista import examples" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Point clouds are generally constructed using\n`pyvista.PolyData`{.interpreted-text role=\"class\"} and can easily have\nscalar or vector data arrays associated with the individual points. In\nthis example, we\\'ll start by working backwards using a point cloud that\nis available from our `examples` module. This however is no different\nthan creating a PyVista mesh with your own NumPy arrays of vertice\nlocations.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# Define some helpers - ignore these and use your own data if you like!\ndef generate_points(subset=0.02):\n \"\"\"A helper to make a 3D NumPy array of points (n_points by 3).\"\"\"\n dataset = examples.download_lidar()\n ids = np.random.randint(low=0, high=dataset.n_points - 1, size=int(dataset.n_points * subset))\n return dataset.points[ids]\n\n\npoints = generate_points()\n# Output the first 5 rows to prove it's a numpy array (n_points by 3)\n# Columns are (X, Y, Z)\npoints[0:5, :]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now that you have a NumPy array of points/vertices either from our\nsample data or your own project, create a PyVista mesh using those\npoints.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# insert your code here\npoint_cloud = ..." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, perform a sanity check to show that the points have been loaded\ncorrectly.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "np.allclose(points, point_cloud.points)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now that we have a PyVista mesh, we can plot it. Note that we add an\noption to use eye dome lighting - this is a shading technique to improve\ndepth perception with point clouds (learn more about\n[EDL](https://docs.pyvista.org/examples/02-plot/edl.html)).\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "point_cloud.plot(eye_dome_lighting=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now what if you have data attributes (scalar or vector arrays) that\nyou\\'d like to associate with every point of your mesh? You can easily\nadd NumPy data arrays that have a length equal to the number of points\nin the mesh along the first axis. For example, lets add a few arrays to\nthis new `point_cloud` mesh.\n\nMake an array of scalar values with the same length as the points array.\nEach element in this array will correspond to points at the same index:\n\n::: {.note}\n::: {.title}\nNote\n:::\n\nYou can use a component of the `points` array or use the `n_points`\nproperty of the mesh to make an array of that length.\n:::\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "data = ... # your code here" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Add that data to the mesh with the name \\\"elevation\\\".\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# your code here" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And now we can plot the point cloud with that elevation data. PyVista is\nsmart enough to plot the scalar array you added by default. This time,\nlet\\'s render every point as its own sphere using\n`render_points_as_spheres`.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "point_cloud.plot(render_points_as_spheres=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "That data is kind of boring, right? You can also add data arrays with\nmore than one scalar value - perhaps a vector with three elements?\nLet\\'s make a little function that will compute vectors for every point\nin the point cloud and add those vectors to the mesh.\n\nThis time, we\\'re going to create a totally new, random point cloud\ncontaining 100 points using `numpy.random.random`{.interpreted-text\nrole=\"func\"}.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# Create a random point cloud with Cartesian coordinates\npoints = np.random.rand(100, 3)\n# Construct PolyData from those points\npoint_cloud = pv.PolyData(points)\n\n\ndef compute_vectors(mesh):\n \"\"\"Create normalized vectors pointing outward from the center of the cloud.\"\"\"\n origin = mesh.center\n vectors = mesh.points - origin\n vectors = vectors / np.linalg.norm(vectors, axis=1)[:, None]\n return vectors\n\n\nvectors = compute_vectors(point_cloud)\nvectors[0:5, :]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Add the vector array as point data to the new mesh:\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we can make arrows using those vectors using the glyph filter (see\nthe [Glyph\nExample](https://docs.pyvista.org/examples/01-filter/glyphs.html) for\nmore details).\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "arrows = point_cloud.glyph(\n orient='vectors',\n scale=False,\n factor=0.15,\n)\n\n# Display the arrows\nplotter = pv.Plotter()\nplotter.add_mesh(point_cloud, color='maroon', point_size=10.0, render_points_as_spheres=True)\nplotter.add_mesh(arrows, color='lightblue')\n# plotter.add_point_labels([point_cloud.center,], ['Center',],\n# point_color='yellow', point_size=20)\nplotter.show_grid()\nplotter.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```{=html}\n