code: def prep_data(dataset):
      df = dataset.copy()
  
      latlon = list(zip(df.lat, df.lon))
      dist = np.array(
          [
              distance(latlon[i + 1], latlon[i])
              for i in range(len(latlon[:-1]))
          ]
      )
  
      df["dist"] = np.concatenate(([0], np.cumsum(dist)))
  
      slope = np.abs(100 * np.diff(df.alt) / (1000 * dist))
      slope[np.where(slope < 4)] = 0  # "green"
      slope[np.where((slope >= 4) & (slope < 6))] = 1  # "yellow"
      slope[np.where((slope >= 6) & (slope < 10))] = 2  # "pink"
      slope[np.where((slope >= 10) & (slope < 15))] = 3  # "orange"
      slope[np.where(slope >= 15)] = 4  # "red"
      slope = im.median_filter(slope, 6)
  
      colors = np.empty_like(slope, dtype=object)
      colors[np.where(slope == 0)] = "green"
      colors[np.where(slope == 1)] = "yellow"
      colors[np.where(slope == 2)] = "pink"
      colors[np.where(slope == 3)] = "orange"
      colors[np.where(slope == 4)] = "red"
      df["colors"] = [
          *colors,
          None,
      ]  # NOTE: add None just make pandas happy
  
      return df
  
file_path: bokeh/examples/models/trail.py
imports: from math import atan2, cos, radians, sin, sqrt
  import numpy
  import scipy.ndimage
  from bokeh.document import Document
  from bokeh.embed import file_html
  from bokeh.models import Column, ColumnDataSource, GMapOptions, GMapPlot, Grid, Label, Line, LinearAxis, PanTool, Patches, Plot, Range1d, ResetTool, WheelZoomTool
  from bokeh.sampledata.mtb import obiszow_mtb_xcm
  from bokeh.util.browser import view
label_desc: Use image node_id 3 for calling a global function with example usage: prep_data(dataset) and returns: df