Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@ All notable changes to this project will be documented here.

## [unreleased]

## [0.24.0] - July 22nd, 2026
- Add `ConfidenceSlider` toolbox item (`AllowedToolboxItem.ConfidenceSlider`) that deprecates (hides) or shows spatial annotations based on their confidence values. Unlike the now-deprecated `KeypointSlider`, it works with all spatial annotation types that have a confidence payload (`bbox`, `bbox3`, `polygon`, `polyline`, `contour`, `tbar`, and `point`), across every subtask.
- Supports a single global "all" slider and/or per-class sliders, controlled by `class_filter_mode` (`"toggle"`, `"all-only"`, or `"class-only"`).
- Configurable via `confidence_slider_toolbox_item`, including `filter_min`/`filter_max`/`step_value`, per-class `default_values`, `target_spatial_types`, and `target_class_ids`.
- Add `get_confidence_slider_value()` public API method to get the current confidence slider values.
- The default `toolbox_order` (used when none is provided) now includes `ConfidenceSlider` instead of `KeypointSlider`.
- Log a warning when both the `KeypointSlider` and `ConfidenceSlider` toolbox items are enabled at once.
- Deprecate the `KeypointSlider` toolbox item and `get_keypoint_slider_value()` in favor of the `ConfidenceSlider` and `get_confidence_slider_value()`. The `KeypointSlider` is retained for backwards compatibility and continues to filter only `point` annotations. It will be removed in a future release.

## [0.23.7] - July 21st, 2026
- Ship generated `.d.ts` declarations (`dist/types/`) and a generated type entry (`dist/index.d.ts`) instead of pointing consumers' type resolution at the raw `.ts` source. This stops downstream TypeScript projects from compiling ULabel's source under their own (stricter) `tsconfig`.
- Stop publishing the `src/` directory in the npm package (`files` now ships `dist/` only).
Expand Down
47 changes: 47 additions & 0 deletions api_spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,7 @@ enum AllowedToolboxItem {
ImageFilters, // 10
AnnotationList, // 11
Keybinds, // 12
ConfidenceSlider, // 13
}
```
You can access the AllowedToolboxItem enum by calling the static method:
Expand Down Expand Up @@ -434,6 +435,44 @@ The `AnnotationList` toolbox item displays all annotations in the current subtas

This toolbox item requires no configuration and can be added to the `toolbox_order` array using `AllowedToolboxItem.AnnotationList`.

### `confidence_slider_toolbox_item`

The `ConfidenceSlider` toolbox item (added to `toolbox_order` via `AllowedToolboxItem.ConfidenceSlider`) deprecates (hides) or shows spatial annotations based on their confidence values. Unlike the deprecated `KeypointSlider`, it works with **all** spatial annotation types that have a confidence payload (`bbox`, `bbox3`, `polygon`, `polyline`, `contour`, `tbar`, and `point`), across every subtask.

It supports two modes:

- **"all" mode** (default): a single slider applies one confidence threshold to every targeted spatial annotation across all subtasks, using each annotation's highest confidence value.
- **Per-class mode**: one slider is shown per targeted class id. Each slider only filters annotations whose assigned (highest-confidence) class matches that slider, using that class's confidence value.

The `class_filter_mode` config controls whether these modes are user-toggleable:
- `"toggle"` (default): a checkbox lets the user switch between the two modes.
- `"all-only"`: only the single global "all" slider is shown.
- `"class-only"`: only the per-class sliders are shown.

Any annotation with a confidence at or above the threshold is shown; any below is deprecated. Thresholds are expressed as percentages, and the slider's range and increment are configurable via `filter_min`, `filter_max`, and `step_value`.

Configuration object with the following custom definitions:
```javascript
type ConfidenceSliderClasses = {
"all": number, // percentage threshold (0-100) used by the single global slider
[classId: string]?: number // per-class-id thresholds (class id as a string key)
}
Comment thread
TrevorBurgoyne marked this conversation as resolved.

type ConfidenceSliderConfig = {
"name"?: string, // Default: "Confidence Filter"
"filter_min"?: number, // Default: 0 (%)
"filter_max"?: number, // Default: 100 (%)
"default_values"?: ConfidenceSliderClasses, // Default: {"all": 0}
"step_value"?: number, // Default: 1 (%)
"class_filter_mode"?: "toggle" | "all-only" | "class-only", // Default: "toggle"
"filter_on_load"?: boolean, // Default: true
// The spatial types to filter. Defaults to all confidence-filterable spatial types.
"target_spatial_types"?: ULabelSpatialType[],
// The class ids to create sliders for in class-only/toggle mode. Defaults to all class ids.
"target_class_ids"?: number[],
}
```

### `reset_zoom_keybind`
Keybind to reset the zoom level to the `initial_crop`. Default is `r`.

Expand All @@ -452,6 +491,8 @@ Keybind to delete a vertex of a polygon or polyline annotation. The vertex must
### `keypoint_slider_default_value`
Default value for the keypoint slider. Must be a number between 0 and 1. Default is `0`.

> **Deprecated:** The `KeypointSlider` toolbox item only filters `point` annotations. Use the `ConfidenceSlider` toolbox item (`confidence_slider_toolbox_item`) instead, which filters all spatial annotation types and supports per-class targeting and multiple sliders.

### `filter_annotations_on_load`
If true, the annotations will be filtered on load based on the `keypoint_slider_default_value`. Default is `true`.

Expand Down Expand Up @@ -563,10 +604,16 @@ Sets the zoom to focus on the provided annotation, and switches to its subtask i

*() => number | null* -- Returns the current keypoint slider value as a number between 0 and 1. Returns `null` if the KeypointSlider toolbox item is not active or the slider element is not found.

> **Deprecated:** Prefer `get_confidence_slider_value()` with the `ConfidenceSlider` toolbox item.

### `get_distance_filter_value()`

*() => object | null* -- Returns an object mapping class identifiers to their distance filter values (in pixels). The object always includes a `closest_row` key for the single-class slider. In multi-class mode, additional keys correspond to each class ID. Returns `null` if the FilterDistance toolbox item is not active or no sliders are found.

### `get_confidence_slider_value()`

*() => object | null* -- Returns an object mapping class identifiers to their confidence threshold values (as percentages, 0–100). The object always includes an `all` key for the single global slider. In per-class mode, additional keys correspond to each class ID. Returns `null` if the ConfidenceSlider toolbox item is not active or no sliders are found.

## Generic Callbacks

Callbacks can be provided by calling `.on(fn, callback)` on a `ULabel` object.
Expand Down
87 changes: 85 additions & 2 deletions demo/live_demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,98 @@
"spatial_type": "bbox",
"spatial_payload": [[871.84, 480.78], [833.71, 396.29]],
"classification_payloads": [
{"class_id": 11, "confidence": 1.0},
{"class_id": 11, "confidence": 0.75},
],
},
{
"id": "dec78d65-9cb4-43ec-8c5a-dcbbae7a3d74",
"spatial_type": "bbox",
"spatial_payload": [[1257.66, 541.35], [1079.71, 411.99]],
"classification_payloads": [
{"class_id": 10, "confidence": 1.0},
{"class_id": 10, "confidence": 0.85},
],
},
// Additional annotations with varied confidences to demo the ConfidenceSlider
{
"id": "71be2a9d-5f1c-4a98-835e-e7826ebec6cf",
"spatial_type": "bbox",
"spatial_payload": [[1381.27, 510.38], [1268.86, 410.89]],
"classification_payloads": [
{"class_id": 10, "confidence": 0.9},
],
},
{
"id": "79c81e3e-0a08-4fa1-a6b0-1e58a498116f",
"spatial_type": "polygon",
"spatial_payload": [
[
[452.24, 540.10], [625.38, 532.35], [642.18, 483.25],
[630.55, 447.07], [591.79, 414.77], [462.58, 413.48],
[445.78, 421.23], [447.07, 469.04], [434.15, 503.92],
[421.23, 510.38], [416.06, 537.52], [452.24, 540.10]
]
],
"spatial_payload_holes": [false],
"spatial_payload_child_indices": [[]],
"classification_payloads": [
{"class_id": 10, "confidence": 0.35},
],
},
{
"id": "c170e38a-eafd-429d-87b1-9a1ee75e25b0",
"spatial_type": "bbox",
"spatial_payload": [[1447.58, 484.52], [1418.42, 397.04]],
"classification_payloads": [
{"class_id": 11, "confidence": 0.55},
],
},
{
"id": "ec96ec1f-2007-4d10-a286-16af43775105",
"spatial_type": "bbox",
"spatial_payload": [[1477.49, 480.78], [1453.56, 401.52]],
"classification_payloads": [
{"class_id": 11, "confidence": 0.2},
],
},
{
"id": "ca9209d9-f787-42e4-8d4b-4408e10ae1ed",
"spatial_type": "bbox",
"spatial_payload": [[1064.00, 468.07], [1031.85, 400.03]],
"classification_payloads": [
{"class_id": 11, "confidence": 0.7},
],
},
{
"id": "39f9f056-383a-4b25-9e31-e71951a1ecaf",
"spatial_type": "bbox",
"spatial_payload": [[1037.67, 477.22], [1013.63, 393.07]],
"classification_payloads": [
{"class_id": 11, "confidence": 0.45},
],
},
{
"id": "9cf8c7ef-814e-48e1-aa1a-e5e74e922938",
"spatial_type": "bbox",
"spatial_payload": [[952.93, 470.00], [898.24, 409.90]],
"classification_payloads": [
{"class_id": 11, "confidence": 0.6},
],
},
{
"id": "84ba0141-fc65-4f89-9057-38eef9d93586",
"spatial_type": "polygon",
"spatial_payload": [
[
[4.78, 791.18], [341.47, 702.03], [358.98, 666.22],
[374.90, 595.38], [369.32, 543.64], [332.71, 497.47],
[305.65, 486.33], [275.40, 484.74], [175.91, 423.45],
[71.64, 410.71], [0, 408.33], [4.78, 791.18]
]
],
"spatial_payload_holes": [false],
"spatial_payload_child_indices": [[]],
"classification_payloads": [
{"class_id": 10, "confidence": 0.65},
],
},
];
Expand Down
6 changes: 5 additions & 1 deletion demo/multi-class.html
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,8 @@
AllowedToolboxItem.AnnotationID,
AllowedToolboxItem.ClassCounter,
AllowedToolboxItem.AnnotationResize,
AllowedToolboxItem.KeypointSlider,
AllowedToolboxItem.KeypointSlider,
AllowedToolboxItem.ConfidenceSlider,
AllowedToolboxItem.FilterDistance,
AllowedToolboxItem.RecolorActive,
],
Expand All @@ -141,6 +142,9 @@
"brightness": 120
},
},
"confidence_slider_toolbox_item": {
"step_value": 5,
},
});
// Wait for ULabel instance to finish initialization
ulabel.init(function () {
Expand Down
24 changes: 17 additions & 7 deletions demo/resume-from.html
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
"spatial_payload": [[300, 300]],
"classification_payloads": [
{"class_id": 12, "confidence": 0.0},
{"class_id": 11, "confidence": 1.0},
{"class_id": 11, "confidence": 0.9},
{"class_id": 10, "confidence": 0.0},
],
},
Expand All @@ -45,15 +45,15 @@
"spatial_type": "point",
"spatial_payload": [[400, 300]],
"classification_payloads": [
{"class_id": 10, "confidence": 1.0},
{"class_id": 10, "confidence": 0.25},
],
},
{
"id": "4a686dc4-0efa-4563-a42b-8eea3dd5b04b",
"spatial_type": "point",
"spatial_payload": [[300, 400]],
"classification_payloads": [
{"class_id": 12, "confidence": 1.0},
{"class_id": 12, "confidence": 0.55},
],
},
{
Expand Down Expand Up @@ -102,7 +102,7 @@
]
],
"classification_payloads": [
{"class_id": 11, "confidence": 1.0},
{"class_id": 11, "confidence": 0.75},
{"class_id": -1, "confidence": 0.0}
],
},
Expand Down Expand Up @@ -175,7 +175,7 @@
"classification_payloads": [
{
"class_id": 10,
"confidence": 1
"confidence": 0.15
},
{
"class_id": 11,
Expand Down Expand Up @@ -209,7 +209,7 @@
"classification_payloads": [
{
"class_id": 10,
"confidence": 1
"confidence": 0.6
},
{
"class_id": 11,
Expand Down Expand Up @@ -275,6 +275,7 @@
};

// Initial ULabel configuration
const AllowedToolboxItem = ULabel.get_allowed_toolbox_item_enum();
let ulabel = new ULabel({
"container_id": "container",
"image_data": "https://ulabel.s3.us-east-2.amazonaws.com/cs-demo-0.png",
Expand All @@ -285,7 +286,16 @@
"allow_annotations_outside_image": false,
"fly_to_next_annotation_keybind": "w",
"fly_to_previous_annotation_keybind": "`",
"fly_to_max_zoom": 6
"fly_to_max_zoom": 6,
"toolbox_order": [
AllowedToolboxItem.ModeSelect,
AllowedToolboxItem.ZoomPan,
AllowedToolboxItem.AnnotationID,
AllowedToolboxItem.ClassCounter,
AllowedToolboxItem.AnnotationResize,
AllowedToolboxItem.ConfidenceSlider,
AllowedToolboxItem.SubmitButtons,
],
});
// Wait for ULabel instance to finish initialization
ulabel.init(function() {
Expand Down
10 changes: 8 additions & 2 deletions demo/row-filtering-example.html
Original file line number Diff line number Diff line change
Expand Up @@ -745,7 +745,7 @@
AllowedToolboxItem.ZoomPan,
AllowedToolboxItem.AnnotationID,
AllowedToolboxItem.ClassCounter,
AllowedToolboxItem.KeypointSlider,
AllowedToolboxItem.ConfidenceSlider,
AllowedToolboxItem.FilterDistance,
AllowedToolboxItem.AnnotationResize,
AllowedToolboxItem.SubmitButtons,
Expand All @@ -761,7 +761,13 @@
// "disable_multi_class_mode": true,
// "filter_during_polyline_move": false,
},
"keypoint_slider_default_value": 0.2,
"confidence_slider_toolbox_item": {
"class_filter_mode": "class-only",
"target_class_ids": [10], // Plant only
"default_values": {
"all": 20, // %
},
},
});
// Wait for ULabel instance to finish initialization
ulabel.init(function () {
Expand Down
43 changes: 42 additions & 1 deletion index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,13 @@ export type Offset = {
/**
* Valid keys for the DeprecatedBy type
*/
export type ValidDeprecatedBy = "human" | "confidence_filter" | "distance_from_row";
export type ValidDeprecatedBy = "human" | "confidence_filter" | "distance_from_row" | "confidence_slider";

export type DeprecatedBy = {
human?: boolean;
confidence_filter?: boolean;
distance_from_row?: boolean;
confidence_slider?: boolean;
};

/**
Expand Down Expand Up @@ -118,6 +119,45 @@ export type FilterDistanceConfig = {
filter_during_polyline_move?: boolean;
};

/**
* Stores the current confidence slider threshold values (percentages, 0-100).
* The key is the class id. "all" is a special key that stores the threshold applied to
* all annotations in single-class mode.
*/
export type ConfidenceSliderClasses = {
all: number;
[key: string]: number;
};

/**
* Controls how the ConfidenceSlider ToolboxItem filters by class:
* - "toggle": a checkbox lets the user switch between the single "all" slider and per-class sliders
* - "all-only": only a single global slider (keyed "all") is shown, filtering every targeted annotation
* - "class-only": only per-class sliders are shown
*/
export type ConfidenceSliderClassFilterMode = "toggle" | "all-only" | "class-only";

/**
* Config object for the ConfidenceSlider ToolboxItem.
*/
export type ConfidenceSliderConfig = {
name?: string;
filter_min?: number;
filter_max?: number;
default_values?: ConfidenceSliderClasses;
step_value?: number;
class_filter_mode?: ConfidenceSliderClassFilterMode;
filter_on_load?: boolean;
// The spatial types to filter. Defaults to all confidence-filterable spatial types.
target_spatial_types?: ULabelSpatialType[];
// The class ids to create sliders for in class-only/toggle mode. Defaults to all class ids.
target_class_ids?: number[];
keybinds?: {
increment: string;
decrement: string;
};
};

export type ULabelSubmitButton = {
name: string;
hook: (submit_data: ULabelSubmitData) => void;
Expand Down Expand Up @@ -367,6 +407,7 @@ export class ULabel {
): void;
public get_keypoint_slider_value(): number | null;
public get_distance_filter_value(): DistanceFromPolylineClasses | null;
public get_confidence_slider_value(): ConfidenceSliderClasses | null;
public fly_to_next_annotation(increment: number, max_zoom?: number): boolean;
public fly_to_annotation_id(annotation_id: string, subtask_key?: string | null, max_zoom?: number): boolean;
public fly_to_annotation(annotation: ULabelAnnotation, subtask_key?: string, max_zoom?: number): boolean;
Expand Down
Loading
Loading