code: def on_initialize(self, event):
      # Build data
      self.data = np.zeros(
          4, [("position", np.float32, 2), ("color", np.float32, 4)]
      )
      self.data["color"] = [
          (1, 0, 0, 1),
          (0, 1, 0, 1),
          (0, 0, 1, 1),
          (1, 1, 0, 1),
      ]
      self.data["position"] = [(-1, -1), (-1, +1), (+1, -1), (+1, +1)]
  
      self.n_instances = 1000
      self.instances = np.empty(
          self.n_instances, [("instance_offset", np.float32, 2)]
      )
      self.instances["instance_offset"] = (
          np.random.rand(self.n_instances, 2) - 0.5
      ) * 2
  
      # Build & activate program
  
      # Request a program and shader slots from GPU
      program = gl.glCreateProgram()
      vertex = gl.glCreateShader(gl.GL_VERTEX_SHADER)
      fragment = gl.glCreateShader(gl.GL_FRAGMENT_SHADER)
  
      # Set shaders source
      gl.glShaderSource(vertex, vertex_code)
      gl.glShaderSource(fragment, fragment_code)
  
      # Compile shaders
      gl.glCompileShader(vertex)
      gl.glCompileShader(fragment)
  
      # Attach shader objects to the program
      gl.glAttachShader(program, vertex)
      gl.glAttachShader(program, fragment)
  
      # Build program
      gl.glLinkProgram(program)
  
      # Get rid of shaders (no more needed)
      gl.glDetachShader(program, vertex)
      gl.glDetachShader(program, fragment)
  
      # Make program the default program
      gl.glUseProgram(program)
  
      # Build buffer
  
      # Request a buffer slot from GPU
      buf = gl.glCreateBuffer()
  
      # Make this buffer the default one
      gl.glBindBuffer(gl.GL_ARRAY_BUFFER, buf)
  
      # Upload data
      gl.glBufferData(gl.GL_ARRAY_BUFFER, self.data, gl.GL_DYNAMIC_DRAW)
  
      # Bind attributes
      stride = self.data.strides[0]
      instance_offset = 0
      loc = gl.glGetAttribLocation(program, "position")
      gl.glEnableVertexAttribArray(loc)
      gl.glBindBuffer(gl.GL_ARRAY_BUFFER, buf)
      gl.glVertexAttribPointer(
          loc, 3, gl.GL_FLOAT, False, stride, instance_offset
      )
  
      instance_offset = self.data.dtype["position"].itemsize
      loc = gl.glGetAttribLocation(program, "color")
      gl.glEnableVertexAttribArray(loc)
      gl.glBindBuffer(gl.GL_ARRAY_BUFFER, buf)
      gl.glVertexAttribPointer(
          loc, 4, gl.GL_FLOAT, False, stride, instance_offset
      )
  
      # instance buffer
      buf = gl.glCreateBuffer()
      gl.glBindBuffer(gl.GL_ARRAY_BUFFER, buf)
      gl.glBufferData(
          gl.GL_ARRAY_BUFFER, self.instances, gl.GL_STATIC_DRAW
      )
      stride = self.instances.strides[0]
      instance_offset = 0
      loc = gl.glGetAttribLocation(program, "instance_offset")
      gl.glEnableVertexAttribArray(loc)
      gl.glBindBuffer(gl.GL_ARRAY_BUFFER, buf)
      gl.glVertexAttribPointer(
          loc, 2, gl.GL_FLOAT, False, stride, instance_offset
      )
      # this is the magic that says "step by 1 every instance"
      gl.glVertexAttribDivisor(loc, 1)
  
      # Bind uniforms
      # --------------------------------------
      loc = gl.glGetUniformLocation(program, "scale")
      gl.glUniform1f(loc, 0.01)
  
file_path: vispy/examples/gloo/gl/quad_instanced.py
imports: import numpy
  from vispy import app, use
  from vispy.gloo import gl
label_desc: Use image node_id 2 for calling the Canvas obj's underlying member method code with example usage: obj.on_initialize(event) without return types