{"record":{"id":"deee1b2962f5ef9c","repo":"roboflow/supervision","slug":"all-values-in-custom-values-must-be-between-0-and","errorCode":null,"errorMessage":"All values in custom_values must be between 0 and 1.","messagePattern":"All values in custom_values must be between 0 and 1\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/supervision/annotators/core.py","lineNumber":2994,"sourceCode":"                raise ValueError(\n                    \"The provided detections do not contain confidence values. \"\n                    \"Please provide `custom_values` or ensure that the detections \"\n                    \"contain confidence values (e.g. by using a different model).\"\n                )\n\n        else:\n            if not isinstance(custom_values, (np.ndarray, list)):\n                raise TypeError(\n                    \"custom_values must be either a numpy array or a list of floats.\"\n                )\n\n            if len(custom_values) != len(detections):\n                raise ValueError(\n                    \"The length of custom_values must match the number of detections.\"\n                )\n\n            if not all(0 <= value <= 1 for value in custom_values):\n                raise ValueError(\"All values in custom_values must be between 0 and 1.\")\n\n    @staticmethod\n    @deprecated(  # type: ignore[untyped-decorator]\n        target=_validate_custom_values.__func__,  # type: ignore[attr-defined]\n        deprecated_in=\"0.29.0\",\n        remove_in=\"0.32.0\",\n    )\n    def validate_custom_values(\n        custom_values: npt.NDArray[np.float64] | list[float] | None,\n        detections: Detections,\n    ) -> None:\n        void(custom_values, detections)\n\n\nclass CropAnnotator(BaseAnnotator):\n    \"\"\"\n    A class for drawing scaled up crops of detections on the scene.\n    \"\"\"","sourceCodeStart":2976,"sourceCodeEnd":3012,"githubUrl":"https://github.com/roboflow/supervision/blob/7f254d9784d4c37e0f03cd89ddee164c8db099c0/src/supervision/annotators/core.py#L2976-L3012","documentation":"ColorAnnotator (and related annotators using per-detection color scaling) accepts an optional `custom_values` array that replaces per-detection statistics (e.g. tracking time) as the color-mapping input. Those values must be normalized to [0, 1] so they can be mapped onto the color gradient. The error is raised by `_validate_custom_values` in src/supervision/annotators/core.py:2994 when any value falls outside [0, 1].","triggerScenarios":"Calling `ColorAnnotator.annotate(scene, detections, custom_values=[...])` (or the constructor) with raw, un-normalized values such as pixel counts, seconds, or class ids; or with values computed on a different scale than the annotator expects. Also raised if a list is passed containing NaN/inf, since NaN fails the `0 <= value <= 1` comparison.","commonSituations":"Passing raw detection ages, track durations, or confidence sums directly instead of min-max normalizing them first; reusing values normalized against a stale min/max after new data arrives; NaN produced by division-by-zero during normalization.","solutions":["Min-max normalize the values to [0, 1] before passing: `(vals - vmin) / (vmax - vmin)` with a guard for `vmax == vmin`","Clip values into range if slight overshoot is acceptable: `np.clip(vals, 0.0, 1.0)`","Replace NaN/inf with 0 before passing: `np.nan_to_num(vals, nan=0.0, posinf=1.0, neginf=0.0)`","Leave `custom_values=None` to let the annotator derive values from `detections.data` automatically"],"exampleFix":"// before\nannotator.annotate(scene=frame, detections=detections, custom_values=[120, 300, 45])\n\n// after\nimport numpy as np\nvals = np.array([120, 300, 45], dtype=np.float64)\nvmin, vmax = vals.min(), vals.max()\nnorm = (vals - vmin) / (vmax - vmin) if vmax > vmin else np.zeros_like(vals)\nannotator.annotate(scene=frame, detections=detections, custom_values=norm)","handlingStrategy":"validation","validationCode":"import numpy as np\n\ndef normalize_custom_values(values, detections) -> np.ndarray | None:\n    \"\"\"Return custom_values normalized to [0, 1] and length-matched, or None.\"\"\"\n    if values is None:\n        return None\n    arr = np.nan_to_num(np.asarray(values, dtype=np.float64), nan=0.0, posinf=1.0, neginf=0.0)\n    if arr.shape != (len(detections),):\n        raise ValueError(f\"expected {len(detections)} values, got {arr.shape}\")\n    vmin, vmax = arr.min(), arr.max()\n    if vmax > vmin:\n        arr = (arr - vmin) / (vmax - vmin)\n    else:\n        arr = np.zeros_like(arr)\n    return np.clip(arr, 0.0, 1.0)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always normalize before passing custom_values; treat the API as expecting [0, 1] floats","Check len(custom_values) == len(detections) to fail before the annotator does","Run np.isfinite(values).all() to catch NaN/inf introduced by upstream math"],"tags":["annotators","validation","color-mapping","numpy"],"backgroundTag":null,"analyzedSha":"7f254d9784d4c37e0f03cd89ddee164c8db099c0","analyzedAt":"2026-08-15T05:13:01.950Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}