code: def invalidate(self, proj):
      self.painter = BatchPainter()
      x, y = proj.lonlat_to_screen(self.data["lon"], self.data["lat"])
  
      k_means = KMeans(n_clusters=self.k)
      k_means.fit(np.vstack([x, y]).T)
      labels = k_means.labels_
  
      self.cmap = create_set_cmap(set(labels), "hsv")
      for l in set(labels):
          self.painter.set_color(self.cmap[l])
          self.painter.convexhull(x[labels == l], y[labels == l])
          self.painter.points(x[labels == l], y[labels == l], 2)
  
file_path: geoplotlib/examples/kmeans.py
imports: from geoplotlib.colors import create_set_cmap
  import pyglet
  from sklearn.cluster import KMeans
  import geoplotlib
  from geoplotlib.layers import BaseLayer
  from geoplotlib.core import BatchPainter
  from geoplotlib.utils import BoundingBox
  import numpy
label_desc: Use image node_id 2 for calling the KMeansLayer obj's underlying member method code with example usage: obj.invalidate(proj) without return types