code: def export_image_sequence(
      chrome_driver: webdriver.Chrome,
      notebook: jupytext.jupytext.NotebookNode,
      name,
      actions,
      delay,
      voila_url_base: str = "http://localhost:8866/voila/render/",
  ):
      imgs = []
  
      with tempfile.NamedTemporaryFile(
          mode="wt",
          dir=temp_notebooks_dir,
          suffix=".ipynb",
      ) as f:
          jupytext.write(notebook, f, fmt="ipynb")
          f.file.flush()
  
          temp_file_path = Path(f.name)
  
          # Server file with voila
          url = voila_url_base.rstrip("/") + "/" + temp_file_path.name
  
          # Open url with selenium
          # Get canvas element (the canvas that Vega renders to)
          @retry(
              wait=wait.wait_fixed(0.5), stop=stop.stop_after_delay(10)
          )
          def get_url():
              return chrome_driver.get(url)
  
          get_url()
  
          # Remove padding, margins, and standardize line height.
          css = (
              "body, .jp-Cell, .jp-Notebook, .jupyter-widgets, .jp-RenderedHTMLCommon "
              "{margin: 0 !important; padding: 0 !important; line-height: 1.3 !important;}"
          )
          script = (
              'document.styleSheets[0].insertRule("' + css + '", 0 )'
          )
          chrome_driver.execute_script(script)
  
          # Get canvas element (the canvas that Vega renders to)
          @retry(
              wait=wait.wait_fixed(0.5), stop=stop.stop_after_delay(10)
          )
          def get_canvas():
              return chrome_driver.find_element("xpath", "//canvas")
  
          try:
              canvas = get_canvas()
          except:
              # Write screenshot
              chrome_driver.get_screenshot_as_file(
                  str(failure_output / f"{name}_here.png")
              )
  
              # Write logs
              with open(
                  failure_output / f"{name}_console.log", "wt"
              ) as f:
                  for log in chrome_driver.get_log("browser"):
                      f.write(json.dumps(log) + "\n")
  
              # Write html dump
              root = chrome_driver.find_element("xpath", "//html")
              with open(
                  failure_output / f"{name}_page.html", "wt"
              ) as f:
                  f.write(root.get_attribute("innerHTML"))
  
              raise
          time.sleep(delay)
  
          # Process actions
          chain = ActionChains(chrome_driver)
          for i, action in enumerate(actions):
              action_type = action["type"]
              if action_type in ("snapshot", "screenshot"):
                  time.sleep(0.25)
                  chain.perform()
                  time.sleep(0.25)
  
                  img_path = (
                      temp_screenshots_dir / f"{name}_{i}.png"
                  ).as_posix()
                  print(f"img_path: {img_path}")
                  if action_type == "snapshot":
                      img_bytes = canvas.screenshot_as_png
                      # Write to file for debugging
                      canvas.screenshot(img_path)
                  else:
                      img_bytes = chrome_driver.get_screenshot_as_png()
                      chrome_driver.save_screenshot(img_path)
  
                  # Get png representation in binary (bytes) from driver
                  # convert this into a 3D numpy image
                  img = imread(BytesIO(img_bytes))
                  imgs.append(img)
  
                  # Reset chain
                  chain = ActionChains(chrome_driver)
  
              elif action_type == "move_to":
                  coords = action["coords"]
  
                  # # Origin of top-left corner
                  # chain = chain.move_to_element_with_offset(canvas, coords[0], coords[1])
  
                  # Origin of element center
                  xoffset = canvas.size["width"] / 2
                  yoffset = canvas.size["height"] / 2
                  chain = chain.move_to_element_with_offset(
                      canvas, coords[0] - xoffset, coords[1] - yoffset
                  )
              elif action_type == "move_by":
                  coords = action["coords"]
                  chain = chain.move_by_offset(coords[0], coords[1])
              elif action_type == "click_and_hold":
                  chain = chain.click_and_hold()
              elif action_type == "click":
                  chain = chain.click()
              elif action_type == "double_click":
                  chain = chain.double_click()
              elif action_type == "release":
                  chain = chain.release()
              else:
                  raise ValueError(f"Invalid action type {action_type}")
  
      return imgs
  
imports: from pathlib import Path
  import jupytext
  import io
  import tempfile
  from subprocess import Popen
  import pytest
  from selenium.webdriver import ActionChains
  from selenium import webdriver
  import time
  from io import BytesIO
  from skimage.io import imread
  from skimage.metrics import structural_similarity
  import shutil
  from tenacity import retry, wait, stop
  import os
  from flaky import flaky
  import json
  import platform
label_desc: Use image node_id 4 for calling a global function with example usage: export_image_sequence(chrome_driver, notebook, name, actions, delay, voila_url_base) and returns: imgs, chrome_driver, chrome_driver