supervisely 6.73.376__py3-none-any.whl → 6.73.378__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- supervisely/__init__.py +1 -0
- supervisely/_utils.py +11 -0
- supervisely/api/entity_annotation/tag_api.py +223 -20
- supervisely/api/image_api.py +81 -1
- supervisely/app/fastapi/index.html +20 -0
- supervisely/app/widgets/__init__.py +1 -0
- supervisely/app/widgets/flexbox/flexbox.py +4 -2
- supervisely/app/widgets/flexbox/template.html +5 -9
- supervisely/app/widgets/input_number/input_number.py +2 -0
- supervisely/app/widgets/input_number/template.html +3 -0
- supervisely/app/widgets/sampling/__init__.py +0 -0
- supervisely/app/widgets/sampling/sampling.py +550 -0
- supervisely/app/widgets/select_dataset/select_dataset.py +15 -5
- supervisely/app/widgets/sly_tqdm/sly_tqdm.py +9 -0
- supervisely/convert/image/sly/sly_image_converter.py +10 -7
- supervisely/video/sampling.py +550 -0
- {supervisely-6.73.376.dist-info → supervisely-6.73.378.dist-info}/METADATA +1 -1
- {supervisely-6.73.376.dist-info → supervisely-6.73.378.dist-info}/RECORD +22 -19
- {supervisely-6.73.376.dist-info → supervisely-6.73.378.dist-info}/LICENSE +0 -0
- {supervisely-6.73.376.dist-info → supervisely-6.73.378.dist-info}/WHEEL +0 -0
- {supervisely-6.73.376.dist-info → supervisely-6.73.378.dist-info}/entry_points.txt +0 -0
- {supervisely-6.73.376.dist-info → supervisely-6.73.378.dist-info}/top_level.txt +0 -0
supervisely/__init__.py
CHANGED
supervisely/_utils.py
CHANGED
|
@@ -98,6 +98,17 @@ def batched(seq, batch_size=50):
|
|
|
98
98
|
yield seq[i : i + batch_size]
|
|
99
99
|
|
|
100
100
|
|
|
101
|
+
def batched_iter(iterable, batch_size=50):
|
|
102
|
+
batch = []
|
|
103
|
+
for item in iterable:
|
|
104
|
+
batch.append(item)
|
|
105
|
+
if len(batch) == batch_size:
|
|
106
|
+
yield batch
|
|
107
|
+
batch = []
|
|
108
|
+
if batch:
|
|
109
|
+
yield batch
|
|
110
|
+
|
|
111
|
+
|
|
101
112
|
def get_bytes_hash(bytes):
|
|
102
113
|
return base64.b64encode(hashlib.sha256(bytes).digest()).decode("utf-8")
|
|
103
114
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# coding: utf-8
|
|
2
2
|
|
|
3
|
-
from typing import List, Optional
|
|
3
|
+
from typing import Any, Dict, List, Optional, Union
|
|
4
4
|
|
|
5
5
|
from supervisely._utils import batched
|
|
6
6
|
from supervisely.api.module_api import ApiField, ModuleApi
|
|
@@ -210,11 +210,13 @@ class TagApi(ModuleApi):
|
|
|
210
210
|
raise RuntimeError("SDK error: len(tags_keys) != len(tags_to_add)")
|
|
211
211
|
if len(tags_keys) == 0:
|
|
212
212
|
return
|
|
213
|
-
ids = self.append_to_objects_json(entity_id, tags_to_add)
|
|
213
|
+
ids = self.append_to_objects_json(entity_id, tags_to_add, project_id)
|
|
214
214
|
KeyIdMap.add_tags_to(key_id_map, tags_keys, ids)
|
|
215
215
|
return ids
|
|
216
216
|
|
|
217
|
-
def append_to_objects_json(
|
|
217
|
+
def append_to_objects_json(
|
|
218
|
+
self, entity_id: int, tags_json: List[Dict], project_id: Optional[int] = None
|
|
219
|
+
) -> List[int]:
|
|
218
220
|
"""
|
|
219
221
|
Add Tags to Annotation Objects for specific entity (image etc.).
|
|
220
222
|
|
|
@@ -224,14 +226,50 @@ class TagApi(ModuleApi):
|
|
|
224
226
|
:type tags_json: dict
|
|
225
227
|
:return: List of tags IDs
|
|
226
228
|
:rtype: list
|
|
229
|
+
|
|
230
|
+
:Usage example:
|
|
231
|
+
|
|
232
|
+
.. code-block:: python
|
|
233
|
+
|
|
234
|
+
import supervisely as sly
|
|
235
|
+
|
|
236
|
+
api = sly.Api(server_address, token)
|
|
237
|
+
|
|
238
|
+
tags_list = [
|
|
239
|
+
{
|
|
240
|
+
"tagId": 25926,
|
|
241
|
+
"objectId": 652959,
|
|
242
|
+
"value": None
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
"tagId": 25927,
|
|
246
|
+
"objectId": 652959,
|
|
247
|
+
"value": "v1"
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
"tagId": 25927,
|
|
251
|
+
"objectId": 652958,
|
|
252
|
+
"value": "v2"
|
|
253
|
+
}
|
|
254
|
+
]
|
|
255
|
+
response = api.video.tag.append_to_objects_json(12345, tags_list)
|
|
256
|
+
|
|
257
|
+
print(response)
|
|
258
|
+
# Output:
|
|
259
|
+
# [
|
|
260
|
+
# 80421101,
|
|
261
|
+
# 80421102,
|
|
262
|
+
# 80421103
|
|
263
|
+
# ]
|
|
227
264
|
"""
|
|
228
265
|
|
|
229
266
|
if len(tags_json) == 0:
|
|
230
267
|
return []
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
268
|
+
if project_id is not None:
|
|
269
|
+
json_data = {ApiField.PROJECT_ID: project_id, ApiField.TAGS: tags_json}
|
|
270
|
+
else:
|
|
271
|
+
json_data = {ApiField.ENTITY_ID: entity_id, ApiField.TAGS: tags_json}
|
|
272
|
+
response = self._api.post("annotation-objects.tags.bulk.add", json_data)
|
|
235
273
|
ids = [obj[ApiField.ID] for obj in response.json()]
|
|
236
274
|
return ids
|
|
237
275
|
|
|
@@ -242,11 +280,21 @@ class TagApi(ModuleApi):
|
|
|
242
280
|
batch_size: int = 100,
|
|
243
281
|
log_progress: bool = False,
|
|
244
282
|
progress: Optional[tqdm_sly] = None,
|
|
245
|
-
) -> List[
|
|
283
|
+
) -> List[Dict[str, Union[str, int, None]]]:
|
|
246
284
|
"""
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
285
|
+
For images project:
|
|
286
|
+
Add Tags to existing Annotation Figures (labels).
|
|
287
|
+
The `tags_list` example:
|
|
288
|
+
[{"tagId": 12345, "figureId": 54321, "value": "tag_value"}, ...].
|
|
289
|
+
For video, pointcloud, volume and pointcloud episodes projects:
|
|
290
|
+
Add Tags to existing Annotation Objects.
|
|
291
|
+
The `frameRange` field is optional and is supported only for video and pointcloud episodes projects.
|
|
292
|
+
The `tags_list`` example:
|
|
293
|
+
[{"tagId": 12345, "objectId": 54321, "value": "tag_value"}, ...].
|
|
294
|
+
or with frameRange:
|
|
295
|
+
[{"tagId": 12345, "objectId": 54321, "value": "tag_value", "frameRange": [1, 10]}, ...].
|
|
296
|
+
|
|
297
|
+
All objects must belong to entities of the same project.
|
|
250
298
|
|
|
251
299
|
:param project_id: Project ID in Supervisely.
|
|
252
300
|
:type project_id: int
|
|
@@ -259,7 +307,7 @@ class TagApi(ModuleApi):
|
|
|
259
307
|
:param progress: Progress bar object to display progress.
|
|
260
308
|
:type progress: Optional[tqdm_sly]
|
|
261
309
|
:return: List of tags infos as dictionaries.
|
|
262
|
-
:rtype: List[
|
|
310
|
+
:rtype: List[Dict[str, Union[str, int, None]]]
|
|
263
311
|
|
|
264
312
|
Usage example:
|
|
265
313
|
.. code-block:: python
|
|
@@ -272,7 +320,8 @@ class TagApi(ModuleApi):
|
|
|
272
320
|
{
|
|
273
321
|
"tagId": 25926,
|
|
274
322
|
"figureId": 652959,
|
|
275
|
-
"value": None #
|
|
323
|
+
"value": None # optional for tag with type 'None'
|
|
324
|
+
"frameRange": [1, 10] # optional (supported only for video and pointcloud episodes projects)
|
|
276
325
|
},
|
|
277
326
|
{
|
|
278
327
|
"tagId": 25927,
|
|
@@ -282,7 +331,7 @@ class TagApi(ModuleApi):
|
|
|
282
331
|
{
|
|
283
332
|
"tagId": 25927,
|
|
284
333
|
"figureId": 652958,
|
|
285
|
-
"value": "v2"
|
|
334
|
+
"value": "v2",
|
|
286
335
|
}
|
|
287
336
|
]
|
|
288
337
|
response = api.image.tag.add_to_figures(12345, tag_list)
|
|
@@ -310,16 +359,14 @@ class TagApi(ModuleApi):
|
|
|
310
359
|
# }
|
|
311
360
|
# ]
|
|
312
361
|
"""
|
|
313
|
-
if type(self) is not TagApi:
|
|
314
|
-
raise NotImplementedError("This method is not available for classes except TagApi")
|
|
315
|
-
|
|
316
|
-
if len(tags_list) == 0:
|
|
317
|
-
return []
|
|
318
362
|
|
|
319
363
|
if progress is not None:
|
|
320
364
|
log_progress = False
|
|
321
365
|
|
|
322
366
|
result = []
|
|
367
|
+
|
|
368
|
+
if len(tags_list) == 0:
|
|
369
|
+
return result
|
|
323
370
|
if log_progress:
|
|
324
371
|
progress = tqdm_sly(
|
|
325
372
|
desc="Adding tags to figures",
|
|
@@ -327,8 +374,164 @@ class TagApi(ModuleApi):
|
|
|
327
374
|
)
|
|
328
375
|
for batch in batched(tags_list, batch_size):
|
|
329
376
|
data = {ApiField.PROJECT_ID: project_id, ApiField.TAGS: batch}
|
|
330
|
-
|
|
377
|
+
if type(self) is TagApi:
|
|
378
|
+
response = self._api.post("figures.tags.bulk.add", data)
|
|
379
|
+
else:
|
|
380
|
+
response = self._api.post("annotation-objects.tags.bulk.add", data)
|
|
331
381
|
result.extend(response.json())
|
|
332
382
|
if progress is not None:
|
|
333
383
|
progress.update(len(batch))
|
|
334
384
|
return result
|
|
385
|
+
|
|
386
|
+
def add_to_entities_json(
|
|
387
|
+
self,
|
|
388
|
+
project_id: int,
|
|
389
|
+
tags_list: List[Dict[str, Union[str, int, None]]],
|
|
390
|
+
batch_size: int = 100,
|
|
391
|
+
log_progress: bool = False,
|
|
392
|
+
) -> List[int]:
|
|
393
|
+
"""
|
|
394
|
+
Bulk add tags to entities (images, videos, pointclouds, volumes) in a project.
|
|
395
|
+
Not supported for pointcloud episodes projects.
|
|
396
|
+
All entities must belong to the same project.
|
|
397
|
+
The `frameRange` field in a tag object within the tags list is optional and is supported only for video projects.
|
|
398
|
+
|
|
399
|
+
The `tags_list` example:
|
|
400
|
+
[{"tagId": 12345, "entityId": 54321, "value": "tag_value"}, ...].
|
|
401
|
+
or with frameRange:
|
|
402
|
+
[{"tagId": 12345, "entityId": 54321, "value": "tag_value", "frameRange": [1, 10]}, ...].
|
|
403
|
+
|
|
404
|
+
:param project_id: Project ID in Supervisely.
|
|
405
|
+
:type project_id: int
|
|
406
|
+
:param tags_list: List of tag object infos as dictionaries
|
|
407
|
+
(e.g. {"tagId": 12345, "entityId": 54321, "value": "tag_value"}).
|
|
408
|
+
:param batch_size: Number of tags to add in one request.
|
|
409
|
+
:type batch_size: int
|
|
410
|
+
:param log_progress: If True, will display a progress bar.
|
|
411
|
+
:type log_progress: bool
|
|
412
|
+
:return: List of tags IDs.
|
|
413
|
+
:rtype: List[int]
|
|
414
|
+
|
|
415
|
+
Usage example:
|
|
416
|
+
.. code-block:: python
|
|
417
|
+
|
|
418
|
+
import supervisely as sly
|
|
419
|
+
|
|
420
|
+
api = sly.Api(server_address, token)
|
|
421
|
+
|
|
422
|
+
tag_list = [
|
|
423
|
+
{
|
|
424
|
+
"tagId": 25926,
|
|
425
|
+
"entityId": 652959,
|
|
426
|
+
"value": None # optional for tag with type 'None'
|
|
427
|
+
"frameRange": [1, 10] # optional (supported only for video projects)
|
|
428
|
+
},
|
|
429
|
+
{
|
|
430
|
+
"tagId": 25927,
|
|
431
|
+
"entityId": 652959,
|
|
432
|
+
"value": "v1"
|
|
433
|
+
},
|
|
434
|
+
{
|
|
435
|
+
"tagId": 25927,
|
|
436
|
+
"entityId": 652958,
|
|
437
|
+
"value": "v2"
|
|
438
|
+
}
|
|
439
|
+
]
|
|
440
|
+
api.image.tag.add_to_entities_json(project_id=12345, tag_list=tag_list)
|
|
441
|
+
"""
|
|
442
|
+
|
|
443
|
+
result = []
|
|
444
|
+
|
|
445
|
+
if len(tags_list) == 0:
|
|
446
|
+
return result
|
|
447
|
+
|
|
448
|
+
if log_progress:
|
|
449
|
+
ds_progress = tqdm_sly(desc="Adding tags to entities", total=len(tags_list))
|
|
450
|
+
|
|
451
|
+
for batch in batched(tags_list, batch_size):
|
|
452
|
+
data = {ApiField.PROJECT_ID: project_id, ApiField.TAGS: batch}
|
|
453
|
+
response = self._api.post("tags.entities.bulk.add", data)
|
|
454
|
+
result.extend([obj[ApiField.ID] for obj in response.json()])
|
|
455
|
+
if log_progress:
|
|
456
|
+
ds_progress.update(len(batch))
|
|
457
|
+
|
|
458
|
+
return result
|
|
459
|
+
|
|
460
|
+
def add_tags_collection_to_objects(
|
|
461
|
+
self,
|
|
462
|
+
project_id: int,
|
|
463
|
+
tags_map: Dict[int, Any],
|
|
464
|
+
batch_size: int = 100,
|
|
465
|
+
log_progress: bool = False,
|
|
466
|
+
) -> List[Dict[str, Union[str, int, None]]]:
|
|
467
|
+
"""
|
|
468
|
+
For images project:
|
|
469
|
+
Add Tags to existing Annotation Figures (labels).
|
|
470
|
+
The `tags_map` example: {figure_id_1: TagCollection, ...}.
|
|
471
|
+
For video, pointcloud, volume and pointcloud episodes projects:
|
|
472
|
+
Add Tags to existing Annotation Objects.
|
|
473
|
+
The `frameRange` field is optional and is supported only for video and pointcloud episodes projects.
|
|
474
|
+
The `tags_map` example: {object_id_1: TagCollection, ...}.
|
|
475
|
+
|
|
476
|
+
All objects must belong to entities of the same project.
|
|
477
|
+
|
|
478
|
+
:param project_id: Project ID in Supervisely.
|
|
479
|
+
:type project_id: int
|
|
480
|
+
:param tags_map: Dictionary with mapping figure/object ID to tags collection.
|
|
481
|
+
:type tags_map: Dict[int, Any]
|
|
482
|
+
:param batch_size: Number of tags to add in one request.
|
|
483
|
+
:type batch_size: int
|
|
484
|
+
:param log_progress: If True, will display a progress bar.
|
|
485
|
+
:type log_progress: bool
|
|
486
|
+
:return: List of tags infos as dictionaries.
|
|
487
|
+
:rtype: List[Dit[str, Union[str, int, None]]]
|
|
488
|
+
|
|
489
|
+
Usage example:
|
|
490
|
+
.. code-block:: python
|
|
491
|
+
|
|
492
|
+
import supervisely as sly
|
|
493
|
+
|
|
494
|
+
api = sly.Api(server_address, token)
|
|
495
|
+
|
|
496
|
+
project_id = 12345
|
|
497
|
+
|
|
498
|
+
tag_meta = sly.TagMeta("tag_name", sly.TagValueType.ANY_STRING)
|
|
499
|
+
meta = sly.ProjectMeta(tag_metas=[tag_meta])
|
|
500
|
+
meta = sly.ProjectMeta.from_json(api.project.update_meta(project_id, meta))
|
|
501
|
+
tag_meta = meta.get_tag_meta("tag_name")
|
|
502
|
+
|
|
503
|
+
# for images project:
|
|
504
|
+
tag_map = {
|
|
505
|
+
652959: sly.TagCollection([sly.Tag(tag_meta, value="v1"), sly.Tag(tag_meta, value="v2"), ...]),
|
|
506
|
+
652958: sly.TagCollection([sly.Tag(tag_meta, value="v3"), sly.Tag(tag_meta, value="v4"), ...]),
|
|
507
|
+
...
|
|
508
|
+
}
|
|
509
|
+
api.image.tag.add_tags_to_objects(project_id, tag_map)
|
|
510
|
+
|
|
511
|
+
# for videos projects (frameRange is optional):
|
|
512
|
+
tag_map = {
|
|
513
|
+
652959: sly.VideoTagCollection([sly.VideoTag(tag_meta, value="v1", frameRange=[1, 10]), ...]),
|
|
514
|
+
652958: sly.VideoTagCollection([sly.VideoTag(tag_meta, value="v2", frameRange=[4, 12]), ...]),
|
|
515
|
+
...
|
|
516
|
+
}
|
|
517
|
+
api.video.tag.add_to_objects_json_batch(project_id, tag_map)
|
|
518
|
+
"""
|
|
519
|
+
|
|
520
|
+
OBJ_ID_FIELD = ApiField.FIGURE_ID if type(self) is TagApi else ApiField.OBJECT_ID
|
|
521
|
+
|
|
522
|
+
data = []
|
|
523
|
+
for obj_id, tags in tags_map.items():
|
|
524
|
+
for tag in tags:
|
|
525
|
+
|
|
526
|
+
if tag.meta.sly_id is None:
|
|
527
|
+
raise ValueError(f"Tag {tag.name} meta has no sly_id")
|
|
528
|
+
|
|
529
|
+
data.append(
|
|
530
|
+
{
|
|
531
|
+
ApiField.TAG_ID: tag.meta.sly_id,
|
|
532
|
+
OBJ_ID_FIELD: obj_id,
|
|
533
|
+
**tag.to_json()
|
|
534
|
+
}
|
|
535
|
+
)
|
|
536
|
+
|
|
537
|
+
return self.add_to_objects(project_id, data, batch_size, log_progress)
|
supervisely/api/image_api.py
CHANGED
|
@@ -3601,7 +3601,87 @@ class ImageApi(RemoveableBulkModuleApi):
|
|
|
3601
3601
|
if progress_cb is not None:
|
|
3602
3602
|
progress_cb(len(batch_ids))
|
|
3603
3603
|
|
|
3604
|
-
def
|
|
3604
|
+
def add_tags_batch(
|
|
3605
|
+
self,
|
|
3606
|
+
image_ids: List[int],
|
|
3607
|
+
tag_ids: Union[int, List[int]],
|
|
3608
|
+
values: Optional[Union[str, int, List[Union[str, int, None]]]] = None,
|
|
3609
|
+
log_progress: bool = False,
|
|
3610
|
+
batch_size: Optional[int] = 100,
|
|
3611
|
+
tag_metas: Optional[Union[TagMeta, List[TagMeta]]] = None,
|
|
3612
|
+
) -> List[int]:
|
|
3613
|
+
"""
|
|
3614
|
+
Add tag with given ID to Images by IDs with different values.
|
|
3615
|
+
|
|
3616
|
+
:param image_ids: List of Images IDs in Supervisely.
|
|
3617
|
+
:type image_ids: List[int]
|
|
3618
|
+
:param tag_ids: Tag IDs in Supervisely.
|
|
3619
|
+
:type tag_ids: int or List[int]
|
|
3620
|
+
:param values: List of tag values for each image or single value for all images.
|
|
3621
|
+
:type values: List[str] or List[int] or str or int, optional
|
|
3622
|
+
:param log_progress: If True, will log progress.
|
|
3623
|
+
:type log_progress: bool, optional
|
|
3624
|
+
:param batch_size: Batch size
|
|
3625
|
+
:type batch_size: int, optional
|
|
3626
|
+
:param tag_metas: Tag Metas. Needed for values validation, omit to skip validation
|
|
3627
|
+
:type tag_metas: TagMeta or List[TagMeta], optional
|
|
3628
|
+
:return: List of tags IDs.
|
|
3629
|
+
:rtype: List[int]
|
|
3630
|
+
:Usage example:
|
|
3631
|
+
|
|
3632
|
+
.. code-block:: python
|
|
3633
|
+
|
|
3634
|
+
import supervisely as sly
|
|
3635
|
+
|
|
3636
|
+
os.environ['SERVER_ADDRESS'] = 'https://app.supervisely.com'
|
|
3637
|
+
os.environ['API_TOKEN'] = 'Your Supervisely API Token'
|
|
3638
|
+
api = sly.Api.from_env()
|
|
3639
|
+
image_ids = [2389126, 2389127]
|
|
3640
|
+
tag_ids = 277083
|
|
3641
|
+
values = ['value1', 'value2']
|
|
3642
|
+
api.image.add_tags_batch(image_ids, tag_ids, values)
|
|
3643
|
+
"""
|
|
3644
|
+
if len(image_ids) == 0:
|
|
3645
|
+
return []
|
|
3646
|
+
|
|
3647
|
+
if isinstance(tag_ids, int):
|
|
3648
|
+
tag_ids = [tag_ids] * len(image_ids)
|
|
3649
|
+
|
|
3650
|
+
if isinstance(tag_metas, TagMeta):
|
|
3651
|
+
tag_metas = [tag_metas] * len(image_ids)
|
|
3652
|
+
|
|
3653
|
+
if values is None:
|
|
3654
|
+
values = [None] * len(image_ids)
|
|
3655
|
+
elif isinstance(values, (str, int)):
|
|
3656
|
+
values = [values] * len(image_ids)
|
|
3657
|
+
|
|
3658
|
+
if len(values) != len(image_ids):
|
|
3659
|
+
raise ValueError("Length of image_ids and values should be the same")
|
|
3660
|
+
|
|
3661
|
+
if len(tag_ids) != len(image_ids):
|
|
3662
|
+
raise ValueError("Length of image_ids and tag_ids should be the same")
|
|
3663
|
+
|
|
3664
|
+
if tag_metas and len(tag_metas) != len(image_ids):
|
|
3665
|
+
raise ValueError("Length of image_ids and tag_metas should be the same")
|
|
3666
|
+
|
|
3667
|
+
if tag_metas:
|
|
3668
|
+
for tag_meta, tag_id, value in zip(tag_metas, tag_ids, values):
|
|
3669
|
+
if not (tag_meta.sly_id == tag_id):
|
|
3670
|
+
raise ValueError(f"{tag_meta.name = } and {tag_id = } should be same")
|
|
3671
|
+
if not tag_meta.is_valid_value(value):
|
|
3672
|
+
raise ValueError(f"{tag_meta.name = } can not have value {value = }")
|
|
3673
|
+
|
|
3674
|
+
project_id = self.get_project_id(image_ids[0])
|
|
3675
|
+
data = [
|
|
3676
|
+
{ApiField.ENTITY_ID: image_id, ApiField.TAG_ID: tag_id, ApiField.VALUE: value}
|
|
3677
|
+
for image_id, tag_id, value in zip(image_ids, tag_ids, values)
|
|
3678
|
+
]
|
|
3679
|
+
|
|
3680
|
+
return self.tag.add_to_entities_json(project_id, data, batch_size, log_progress)
|
|
3681
|
+
|
|
3682
|
+
def update_tag_value(
|
|
3683
|
+
self, tag_id: int, value: Union[str, float]
|
|
3684
|
+
) -> Dict:
|
|
3605
3685
|
"""
|
|
3606
3686
|
Update tag value with given ID.
|
|
3607
3687
|
|
|
@@ -57,6 +57,26 @@
|
|
|
57
57
|
border-bottom: 1px solid #dfe2e8;
|
|
58
58
|
position: relative;
|
|
59
59
|
}
|
|
60
|
+
|
|
61
|
+
.el-input-number--mini .el-input-number__decrease,
|
|
62
|
+
.el-input-number--mini .el-input-number__increase {
|
|
63
|
+
height: 20px !important;
|
|
64
|
+
width: 20px !important;
|
|
65
|
+
line-height: 18px !important;
|
|
66
|
+
font-size: 12px !important;
|
|
67
|
+
min-width: 20px !important;
|
|
68
|
+
padding: 0 !important;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.el-input-number--mini .el-input-number__decrease {
|
|
72
|
+
right: 20px !important;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.el-input-number--mini .el-input-number__decrease i,
|
|
76
|
+
.el-input-number--mini .el-input-number__increase i {
|
|
77
|
+
font-size: 10px !important;
|
|
78
|
+
line-height: 18px !important;
|
|
79
|
+
}
|
|
60
80
|
</style>
|
|
61
81
|
<title>{{{app_name}}}</title>
|
|
62
82
|
</head>
|
|
@@ -151,3 +151,4 @@ from supervisely.app.widgets.experiment_selector.experiment_selector import Expe
|
|
|
151
151
|
from supervisely.app.widgets.bokeh.bokeh import Bokeh
|
|
152
152
|
from supervisely.app.widgets.run_app_button.run_app_button import RunAppButton
|
|
153
153
|
from supervisely.app.widgets.select_collection.select_collection import SelectCollection
|
|
154
|
+
from supervisely.app.widgets.sampling.sampling import Sampling
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
from
|
|
2
|
-
from typing import Dict, List
|
|
1
|
+
from typing import Dict, List, Literal
|
|
3
2
|
|
|
3
|
+
from supervisely.app.widgets import Widget
|
|
4
4
|
|
|
5
5
|
"""
|
|
6
6
|
<div
|
|
@@ -21,10 +21,12 @@ class Flexbox(Widget):
|
|
|
21
21
|
gap: int = 10,
|
|
22
22
|
center_content: bool = False,
|
|
23
23
|
widget_id: str = None,
|
|
24
|
+
vertical_alignment: Literal["start", "end", "center", "stretch", "baseline"] = None,
|
|
24
25
|
):
|
|
25
26
|
self._widgets = widgets
|
|
26
27
|
self._gap = gap
|
|
27
28
|
self._center_content = center_content
|
|
29
|
+
self._vertical_alignment = vertical_alignment
|
|
28
30
|
super().__init__(widget_id=widget_id, file_path=__file__)
|
|
29
31
|
|
|
30
32
|
def get_json_data(self) -> Dict:
|
|
@@ -1,11 +1,7 @@
|
|
|
1
|
-
<div
|
|
2
|
-
{
|
|
3
|
-
style="display: flex; gap: {{{widget._gap}}}px;
|
|
4
|
-
{% else %}
|
|
5
|
-
style="display: flex; gap: {{{widget._gap}}}px;"
|
|
6
|
-
{% endif %}
|
|
7
|
-
>
|
|
1
|
+
<div {% if widget._center_content==true %}
|
|
2
|
+
style="display: flex; gap: {{{widget._gap}}}px; align-items: {{{widget._vertical_alignment}}}; justify-content: center;"
|
|
3
|
+
{% else %} style="display: flex; gap: {{{widget._gap}}}px; align-items: {{{widget._vertical_alignment}}};" {% endif%}>
|
|
8
4
|
{% for w in widget._widgets %}
|
|
9
|
-
|
|
5
|
+
{{{w}}}
|
|
10
6
|
{% endfor %}
|
|
11
|
-
</div>
|
|
7
|
+
</div>
|
|
@@ -20,6 +20,7 @@ class InputNumber(Widget):
|
|
|
20
20
|
debounce: int = 300,
|
|
21
21
|
precision: int = 0,
|
|
22
22
|
widget_id: str = None,
|
|
23
|
+
width: int = None,
|
|
23
24
|
):
|
|
24
25
|
self._value = value
|
|
25
26
|
self._min = min
|
|
@@ -29,6 +30,7 @@ class InputNumber(Widget):
|
|
|
29
30
|
self._controls = controls
|
|
30
31
|
self._debounce = debounce
|
|
31
32
|
self._precision = precision
|
|
33
|
+
self._width = width
|
|
32
34
|
self._changes_handled = False
|
|
33
35
|
|
|
34
36
|
super().__init__(widget_id=widget_id, file_path=__file__)
|
|
@@ -16,5 +16,8 @@
|
|
|
16
16
|
:controls="data.{{{widget.widget_id}}}.controls"
|
|
17
17
|
:debounce="data.{{{widget.widget_id}}}.debounce"
|
|
18
18
|
:precision="data.{{{widget.widget_id}}}.precision"
|
|
19
|
+
{% if widget._width %}
|
|
20
|
+
:style="{ width: '{{{widget._width}}}px' }"
|
|
21
|
+
{% endif %}
|
|
19
22
|
>
|
|
20
23
|
</el-input-number>
|
|
File without changes
|