How Annotation Heat Map calculated in Roboflow platform?

Hey everyone, hope you guys are doing great. I would like to know how this graph and quartile results are calculated in the Roboflow Analytics section. I am trying to reproduce these (with Codex CLI) but couldn’t obtain the exact numbers.

I attached the code below:

def _increment_heatmap(grid: List[List[int]], x: float, y: float) -> None:
    """Increment one heatmap cell from normalized [0, 1] coordinates."""
    if not grid or not grid[0]:
        return
    if x < 0 or y < 0:
        return

    h = len(grid)
    w = len(grid[0])
    gx = min(w - 1, max(0, int(x * w)))
    gy = min(h - 1, max(0, int(y * h)))
    grid[gy][gx] += 1


def _increment_heatmap_box(
    grid: List[List[int]],
    x1: float,
    y1: float,
    x2: float,
    y2: float,
) -> None:
    """Increment grid cells whose centers lie inside a normalized [0, 1] rectangle."""
    if not grid or not grid[0]:
        return

    h = len(grid)
    w = len(grid[0])

    nx1 = max(0.0, min(1.0, min(x1, x2)))
    ny1 = max(0.0, min(1.0, min(y1, y2)))
    nx2 = max(0.0, min(1.0, max(x1, x2)))
    ny2 = max(0.0, min(1.0, max(y1, y2)))

    if nx2 <= nx1 or ny2 <= ny1:
        return

    gx0 = min(w - 1, max(0, int(math.floor(nx1 * w))))
    gy0 = min(h - 1, max(0, int(math.floor(ny1 * h))))
    gx1 = min(w - 1, max(0, int(math.ceil(nx2 * w) - 1)))
    gy1 = min(h - 1, max(0, int(math.ceil(ny2 * h) - 1)))

    hit = False
    for gy in range(gy0, gy1 + 1):
        cy = (gy + 0.5) / float(h)
        if cy < ny1 or cy > ny2:
            continue
        row = grid[gy]
        for gx in range(gx0, gx1 + 1):
            cx = (gx + 0.5) / float(w)
            if nx1 <= cx <= nx2:
                row[gx] += 1
                hit = True

    # Keep tiny/very thin boxes visible at this grid resolution.
    if not hit:
        cx = (nx1 + nx2) * 0.5
        cy = (ny1 + ny2) * 0.5
        _increment_heatmap(grid, cx, cy)


def _point_in_polygon(x: float, y: float, polygon: List[Tuple[float, float]]) -> bool:
    """Ray-casting point-in-polygon test in normalized coordinates."""
    n = len(polygon)
    if n < 3:
        return False

    inside = False
    j = n - 1
    for i in range(n):
        xi, yi = polygon[i]
        xj, yj = polygon[j]

        if (yi > y) != (yj > y):
            denom = yj - yi
            if abs(denom) < 1e-12:
                denom = 1e-12
            x_cross = (xj - xi) * (y - yi) / denom + xi
            if x < x_cross:
                inside = not inside
        j = i

    return inside


def _increment_heatmap_polygon(
    grid: List[List[int]],
    polygon: List[Tuple[float, float]],
) -> None:
    """Increment grid cells whose centers fall inside a normalized polygon."""
    if not grid or not grid[0] or len(polygon) < 3:
        return

    h = len(grid)
    w = len(grid[0])

    xs = [p[0] for p in polygon]
    ys = [p[1] for p in polygon]

    min_x = max(0.0, min(1.0, min(xs)))
    min_y = max(0.0, min(1.0, min(ys)))
    max_x = max(0.0, min(1.0, max(xs)))
    max_y = max(0.0, min(1.0, max(ys)))

    if max_x <= min_x or max_y <= min_y:
        return

    gx0 = min(w - 1, max(0, int(math.floor(min_x * w))))
    gy0 = min(h - 1, max(0, int(math.floor(min_y * h))))
    gx1 = min(w - 1, max(0, int(math.ceil(max_x * w) - 1)))
    gy1 = min(h - 1, max(0, int(math.ceil(max_y * h) - 1)))

    hit = False
    for gy in range(gy0, gy1 + 1):
        cy = (gy + 0.5) / float(h)
        row = grid[gy]
        for gx in range(gx0, gx1 + 1):
            cx = (gx + 0.5) / float(w)
            if _point_in_polygon(cx, cy, polygon):
                row[gx] += 1
                hit = True

    # Keep very small polygons visible at this grid resolution.
    if not hit:
        cx = sum(xs) / float(len(xs))
        cy = sum(ys) / float(len(ys))
        _increment_heatmap(grid, cx, cy)

def _point_in_polygon(x: float, y: float, polygon: List[Tuple[float, float]]) -> bool:
    """Ray-casting point-in-polygon test in normalized coordinates."""
    n = len(polygon)
    if n < 3:
        return False

    inside = False
    j = n - 1
    for i in range(n):
        xi, yi = polygon[i]
        xj, yj = polygon[j]

        if (yi > y) != (yj > y):
            denom = yj - yi
            if abs(denom) < 1e-12:
                denom = 1e-12
            x_cross = (xj - xi) * (y - yi) / denom + xi
            if x < x_cross:
                inside = not inside
        j = i

    return inside

def _increment_heatmap_polygon(
    grid: List[List[int]],
    polygon: List[Tuple[float, float]],
) -> None:
    """Increment grid cells whose centers fall inside a normalized polygon."""
    if not grid or not grid[0] or len(polygon) < 3:
        return

    h = len(grid)
    w = len(grid[0])

    # Find bounding box of polygon
    xs = [p[0] for p in polygon]
    ys = [p[1] for p in polygon]

    min_x = max(0.0, min(1.0, min(xs)))
    min_y = max(0.0, min(1.0, min(ys)))
    max_x = max(0.0, min(1.0, max(xs)))
    max_y = max(0.0, min(1.0, max(ys)))

    if max_x <= min_x or max_y <= min_y:
        return

    # Calculate grid cells within bounding box
    gx0 = min(w - 1, max(0, int(math.floor(min_x * w))))
    gy0 = min(h - 1, max(0, int(math.floor(min_y * h))))
    gx1 = min(w - 1, max(0, int(math.ceil(max_x * w) - 1)))
    gy1 = min(h - 1, max(0, int(math.ceil(max_y * h) - 1)))

    # Test each cell's center against polygon
    hit = False
    for gy in range(gy0, gy1 + 1):
        cy = (gy + 0.5) / float(h)
        row = grid[gy]
        for gx in range(gx0, gx1 + 1):
            cx = (gx + 0.5) / float(w)
            if _point_in_polygon(cx, cy, polygon):
                row[gx] += 1
                hit = True

    # Fallback for very small polygons: use centroid
    if not hit:
        cx = sum(xs) / float(len(xs))
        cy = sum(ys) / float(len(ys))
        _increment_heatmap(grid, cx, cy)

# then in the main analyses block I use
HEATMAP_LARGE_REGION_AREA_RATIO = 0.50
box_area_ratio = (bw * bh) / image_area
if box_area_ratio > HEATMAP_LARGE_REGION_AREA_RATIO:
    # Use center point only (avoid flooding entire grid)
    cx = ((bx1 + bx2) * 0.5) / width_f
    cy = ((by1 + by2) * 0.5) / height_f
    _increment_heatmap(heat_grid, cx, cy)
else:
    # Use full cell-center-in-shape logic
    _increment_heatmap_box(heat_grid, bx1/width_f, by1/height_f, bx2/width_f, by2/height_f)

# these are for polygons
HEATMAP_POLYGON_BLUR_SIGMA_RATIO = 0.115
HEATMAP_POLYGON_GAMMA = 2.3
HEATMAP_POLYGON_LOW_CUTOFF = 0.04
HEATMAP_POLYGON_DENSITY_SCALE = 0.2555

def _postprocess_polygon_only_heatmap(
    grid: List[List[int]],
    grid_size: int,
    box_hits: int,
    polygon_hits: int,
) -> List[List[int]]:
    """
    Improve polygon-only heatmap comparability by smoothing and contrast remapping.
    Leaves mixed/box datasets untouched.
    """
    if polygon_hits <= 0 or box_hits > 0:
        return grid
    
    # Gaussian blur 
    sigma = max(0.0, float(grid_size) * HEATMAP_POLYGON_BLUR_SIGMA_RATIO)
    arr = _gaussian_blur_grid(arr, sigma=sigma)
    
    # Gamma correction (2.3) for contrast
    arr = np.power(arr, HEATMAP_POLYGON_GAMMA)
    
    # Low cutoff filtering: zero out values below 0.04
    if HEATMAP_POLYGON_LOW_CUTOFF > 0.0:
        arr = (arr - HEATMAP_POLYGON_LOW_CUTOFF) / (1.0 - HEATMAP_POLYGON_LOW_CUTOFF)
        arr = np.clip(arr, 0.0, 1.0)
    
    # Rescale to target density
    target_max = max(1, int(round(float(polygon_hits) * HEATMAP_POLYGON_DENSITY_SCALE)))
    arr = np.rint(arr * float(target_max))
    arr = np.clip(arr, 0.0, float(target_max))
    
    return arr.astype(int).tolist()

def _percentile(values: List[int], p: float) -> float:
    """Linear percentile interpolation for p in [0, 1]."""
    if not values:
        return 0.0
    ordered = sorted(values)
    idx = (len(ordered) - 1) * p
    lo = int(math.floor(idx))
    hi = int(math.ceil(idx))
    if lo == hi:
        return float(ordered[lo])
    frac = idx - lo
    return float(ordered[lo] * (1.0 - frac) + ordered[hi] * frac)

flat_heat = [v for row in heat_grid for v in row]
heat_stats = {
    "min": int(min(flat_heat) if flat_heat else 0),
    "q1": int(round(_percentile(flat_heat, 0.25))),      # 25th percentile
    "median": int(round(_percentile(flat_heat, 0.50))),  # 50th percentile
    "q3": int(round(_percentile(flat_heat, 0.75))),      # 75th percentile
    "max": int(max(flat_heat) if flat_heat else 0),
}

Hi @rauffatali ,

I can’t directly share the code with you, but these are the steps that are taken to create such visualization:

1. Collect all annotation bounding boxes across every image in the dataset
2. Normalize their coordinates to a common [0,1] space
3. Overlay a grid (e.g. 10x10) on that space
4. Count how many annotations fall into each grid cell
5. Color each cell on a gradient (white → blue → orange → red) based on density