Annotation comments
Review comments pinned to a single annotation - list, create, edit, resolve, delete. The programmatic side of annotation QA.
A comment is attached to one annotation inside one image, not to the image and not to the dataset. That is what makes it useful for review: a QA pass can flag the specific box it disagrees with, and the annotator sees the note on that box in the editor.
An @username mention in the body notifies that member of your organization. See
Notifications for reading the resulting feed.
Images are addressed the way you read them off the grid, by dataset name and
filename. The annotation itself stays an id: an annotation carries a class name,
not a unique one, so a hundred boxes on an image can all be called car and no name
identifies one of them. Take the id from
client.annotations.get.
There is no pictograph CLI group for annotation comments; use the Python SDK or
raw REST.
list
Every comment on the given image’s annotations, oldest first, resolved and open alike.
Source: AnnotationComments.list
| Arg | Type | Default | Notes |
|---|---|---|---|
dataset_name |
str |
required | Dataset name. |
image |
str |
required | Image filename, or an image id |
comments = client.annotation_comments.list(
dataset_name="road-signs",
image="img-001.jpg",
)
for c in comments:
print(c.id, c.annotation_id, c.resolved, c.body)
curl -s "https://api.pictograph.io/api/v1/developer/annotation-comments?image_id=3f1c8e42-6b90-4a71-9d0e-2b5c7a11e004" \
-H "X-API-Key: $PICTOGRAPH_API_KEY"
Returns Sequence[AnnotationComment]
AnnotationComment · 11 fields
class AnnotationComment(BaseModel):
"""One comment on an annotation."""
id: str
annotation_id: str
body: str
resolved: bool = False
created_at: datetime | None = None
updated_at: datetime | None = None
user_id: str | None = None
author_name: str | None = None
author_username: str | None = None
author_avatar_url: str | None = None
is_mine: bool = False
REST takes the image id rather than the filename; resolve one with GET /api/v1/developer/images/?dataset=road-signs&filename=img-001.jpg.
create
Post a comment on one annotation. Requires member+ role, and the API key must
belong to a user, since a comment has an author.
Source: AnnotationComments.create
| Arg | Type | Default | Notes |
|---|---|---|---|
dataset_name |
str |
required | Dataset name. |
image |
str |
required | Image filename, or an image id |
annotation_id |
str |
required | The annotation to pin the comment to |
body |
str |
required | Comment text, 1 to 5000 characters. @username mentions notify org members |
annotations = client.annotations.get(
dataset_name="road-signs",
image="img-001.jpg",
)
low = [a for a in annotations if (a.confidence or 1.0) < 0.4]
for ann in low:
client.annotation_comments.create(
dataset_name="road-signs",
image="img-001.jpg",
annotation_id=ann.id,
body=f"@dana low confidence on this {ann.name} - please re-check.",
)
curl -s -X POST "https://api.pictograph.io/api/v1/developer/annotation-comments" \
-H "X-API-Key: $PICTOGRAPH_API_KEY" -H "Content-Type: application/json" \
-d '{
"image_id": "3f1c8e42-6b90-4a71-9d0e-2b5c7a11e004",
"annotation_id": "b41e7d90-5c62-4a38-8e15-9d3f2a7c6b81",
"body": "@dana low confidence on this stop-sign - please re-check."
}'
Returns AnnotationComment
AnnotationComment · 11 fields
class AnnotationComment(BaseModel):
"""One comment on an annotation."""
id: str
annotation_id: str
body: str
resolved: bool = False
created_at: datetime | None = None
updated_at: datetime | None = None
user_id: str | None = None
author_name: str | None = None
author_username: str | None = None
author_avatar_url: str | None = None
is_mine: bool = False
update
Edit the body, change the resolved flag, or both in one call. Editing the body is restricted to the comment’s author; changing the resolved flag is open to anyone in the organization. Sending neither field is a 400.
Source: AnnotationComments.update
| Arg | Type | Default | Notes |
|---|---|---|---|
comment_id |
str |
required | Comment id, from list or create |
body |
str | None |
None |
New text. Author only |
resolved |
bool | None |
None |
Mark resolved or reopen |
comment = client.annotation_comments.update(
comment_id="7c2a91d5-4e83-4b16-9f27-8a0d6e3b512c",
body="Re-checked against the raw frame - the box is correct after all.",
resolved=True,
)
print(comment.resolved, comment.updated_at)
curl -s -X PATCH "https://api.pictograph.io/api/v1/developer/annotation-comments/7c2a91d5-4e83-4b16-9f27-8a0d6e3b512c" \
-H "X-API-Key: $PICTOGRAPH_API_KEY" -H "Content-Type: application/json" \
-d '{"body": "Re-checked against the raw frame - the box is correct after all.", "resolved": true}'
Returns AnnotationComment
AnnotationComment · 11 fields
class AnnotationComment(BaseModel):
"""One comment on an annotation."""
id: str
annotation_id: str
body: str
resolved: bool = False
created_at: datetime | None = None
updated_at: datetime | None = None
user_id: str | None = None
author_name: str | None = None
author_username: str | None = None
author_avatar_url: str | None = None
is_mine: bool = False
resolve
The one-argument form of update for the common case: close a comment, or reopen
it with resolved=False. It issues the same request.
Source: AnnotationComments.resolve
| Arg | Type | Default | Notes |
|---|---|---|---|
comment_id |
str |
required | Comment id |
resolved |
bool |
True |
False reopens the comment |
client.annotation_comments.resolve(
comment_id="7c2a91d5-4e83-4b16-9f27-8a0d6e3b512c",
resolved=True,
)
curl -s -X PATCH "https://api.pictograph.io/api/v1/developer/annotation-comments/7c2a91d5-4e83-4b16-9f27-8a0d6e3b512c" \
-H "X-API-Key: $PICTOGRAPH_API_KEY" -H "Content-Type: application/json" \
-d '{"resolved": true}'
Returns AnnotationComment
AnnotationComment · 11 fields
class AnnotationComment(BaseModel):
"""One comment on an annotation."""
id: str
annotation_id: str
body: str
resolved: bool = False
created_at: datetime | None = None
updated_at: datetime | None = None
user_id: str | None = None
author_name: str | None = None
author_username: str | None = None
author_avatar_url: str | None = None
is_mine: bool = False
delete
Remove a comment permanently. Allowed to the author, or to an admin / owner key
moderating the thread.
Source: AnnotationComments.delete
| Arg | Type | Default | Notes |
|---|---|---|---|
comment_id |
str |
required | Comment id |
client.annotation_comments.delete(
comment_id="7c2a91d5-4e83-4b16-9f27-8a0d6e3b512c",
)
curl -s -X DELETE "https://api.pictograph.io/api/v1/developer/annotation-comments/7c2a91d5-4e83-4b16-9f27-8a0d6e3b512c" \
-H "X-API-Key: $PICTOGRAPH_API_KEY"
Returns None
Common errors
| Status | Exception | Cause |
|---|---|---|
| 400 | ValidationError |
update sent neither a new body nor a resolved flag, or the API key has no associated user to author a comment |
| 403 | ForbiddenError |
A viewer key tried to comment, a non-author tried to edit a body, or a non-author without admin+ tried to delete |
| 404 | NotFoundError |
The image or the comment does not exist in your organization |