code: def plot_wave(fps=30, frequency=1, wavetime=3, notebook=None):
      """Plot a 3D moving wave in a render window.
  
      Parameters
      ----------
      fps : int, default: 30
          Maximum frames per second to display.
  
      frequency : float, default: 1.0
          Wave cycles per second (Hz).
  
      wavetime : float, default: 3.0
          The desired total display time in seconds.
  
      notebook : bool, optional
          When ``True``, the resulting plot is placed inline a jupyter
          notebook.  Assumes a jupyter console is active.
  
      Returns
      -------
      numpy.ndarray
          Position of points at last frame.
  
      Examples
      --------
      >>> from pyvista import demos
      >>> out = demos.plot_wave()
  
      """
      # camera position
      cpos = [
          (6.879481857604187, -32.143727535933195, 23.05622921691103),
          (
              -0.2336056403734026,
              -0.6960083534590372,
              -0.7226721553894022,
          ),
          (
              -0.008900669873416645,
              0.6018246347860926,
              0.7985786667826725,
          ),
      ]
  
      # Make data
      X = np.arange(-10, 10, 0.25)
      Y = np.arange(-10, 10, 0.25)
      X, Y = np.meshgrid(X, Y)
      R = np.sqrt(X**2 + Y**2)
      Z = np.sin(R)
  
      # Create and plot structured grid
      sgrid = pyvista.StructuredGrid(X, Y, Z)
  
      mesh = sgrid.extract_surface()
      mesh["Height"] = Z.ravel()
  
      # Start a plotter object and set the scalars to the Z height
      plotter = pyvista.Plotter(notebook=notebook)
      plotter.add_mesh(
          mesh,
          scalars="Height",
          show_scalar_bar=False,
          smooth_shading=True,
      )
      plotter.camera_position = cpos
      plotter.show(
          title="Wave Example",
          window_size=[800, 600],
          auto_close=False,
          interactive_update=True,
      )
  
      # Update Z and display a frame for each updated position
      tdelay = 1.0 / fps
      tlast = time.time()
      tstart = time.time()
      while time.time() - tstart < wavetime:
          # get phase from start
          telap = time.time() - tstart
          phase = telap * 2 * np.pi * frequency
          Z = np.sin(R + phase)
          mesh.points[:, -1] = Z.ravel()
          mesh["Height"] = Z.ravel()
  
          mesh.compute_normals(inplace=True)
  
          # Render and get time to render
          plotter.update()
  
          # time delay
          tpast = time.time() - tlast
          if tpast < tdelay and tpast >= 0 and not plotter.off_screen:
              time.sleep(tdelay - tpast)
  
          # store when rendering complete
          tlast = time.time()
  
      # Close movie and delete object
      plotter.close()
      return mesh.points
  
file_path: pyvista/pyvista/demos/demos.py
imports: import time
  import numpy
  import pyvista
  from pyvista import examples
  from .logo import text_3d
label_desc: Use image node_id 5 for calling a global function with example usage: plot_wave(fps, frequency, wavetime, notebook) and returns: mesh