Annotation comments
Comment on a single annotation for QA review: list, create, reply, react, edit, resolve and delete. An @username mention notifies that member.
A comment is pinned to one annotation, addressed by its id from
annotations.get; the annotator sees it on that shape in
the editor. Writing a comment needs a key that belongs to a person.
list
Every comment on an image’s annotations, oldest first, open and resolved.
Source: AnnotationComments.list
| Arg | Type | Default | Notes |
|---|---|---|---|
dataset |
str |
required | Dataset name or id |
image |
str |
required | Image path (addressing) |
comments = client.annotation_comments.list(
dataset="road-signs",
image="img-001.jpg",
)
for c in comments:
print(c.id, c.annotation_id, c.resolved, c.body)
pictograph annotation-comments list road-signs 001.jpg --unresolved
curl -s "https://api.pictograph.io/api/v1/developer/annotation-comments?dataset=road-signs&image=img-001.jpg" \
-H "X-API-Key: $PICTOGRAPH_API_KEY"
Returns Sequence[AnnotationComment]
AnnotationComment · 18 fields
class AnnotationComment(BaseModel):
"""One comment on an annotation."""
id: str
annotation_id: str
body: str
resolved: bool = False
parent_comment_id: str | None = None
is_edited: bool = False
is_deleted: bool = False
resolved_by: str | None = None
resolved_by_name: str | None = None
resolved_at: datetime | None = None
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
reactions: list[AnnotationCommentReaction] = []
create
Comment on one annotation. Needs a member key.
Source: AnnotationComments.create
| Arg | Type | Default | Notes |
|---|---|---|---|
dataset |
str |
required | Dataset name or id |
image |
str |
required | Image path (addressing) |
annotation |
str |
required | Annotation id to comment on |
body |
str |
required | Comment text, 1 to 5,000 characters; an @username notifies that member |
parent |
str | None |
None |
Comment id to reply to; a reply to a reply attaches to the top comment |
annotations = client.annotations.get(
dataset="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="road-signs",
image="img-001.jpg",
annotation=ann.id,
body=f"@dana low confidence on this {ann.name} - please re-check.",
)
pictograph annotation-comments add road-signs 001.jpg <annotation-id> "Is this a yield sign? @noah"
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 '{
"dataset": "road-signs",
"image": "img-001.jpg",
"annotation": "b41e7d90-5c62-4a38-8e15-9d3f2a7c6b81",
"body": "@dana low confidence on this stop-sign - please re-check."
}'
Returns AnnotationComment
AnnotationComment · 18 fields
class AnnotationComment(BaseModel):
"""One comment on an annotation."""
id: str
annotation_id: str
body: str
resolved: bool = False
parent_comment_id: str | None = None
is_edited: bool = False
is_deleted: bool = False
resolved_by: str | None = None
resolved_by_name: str | None = None
resolved_at: datetime | None = None
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
reactions: list[AnnotationCommentReaction] = []
reply
Reply to a comment; a reply to a reply attaches to the top comment. A parent on another
annotation is a 404.
Source: AnnotationComments.reply
| Arg | Type | Default | Notes |
|---|---|---|---|
dataset |
str |
required | Dataset name or id |
image |
str |
required | Image path (addressing) |
annotation |
str |
required | Annotation id of the thread |
parent |
str |
required | Comment id to reply to |
body |
str |
required | Reply text, 1 to 5,000 characters; an @username notifies that member |
reply = client.annotation_comments.reply(
dataset="road-signs",
image="img-001.jpg",
annotation="b41e7d90-5c62-4a38-8e15-9d3f2a7c6b81",
parent="7c2a91d5-4e83-4b16-9f27-8a0d6e3b512c",
body="Re-drawn tighter. Good to resolve?",
)
print(reply.parent_comment_id)
pictograph annotation-comments reply road-signs 001.jpg <comment-id> "Yes - relabelled."
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 '{
"dataset": "road-signs",
"image": "img-001.jpg",
"annotation": "b41e7d90-5c62-4a38-8e15-9d3f2a7c6b81",
"parent": "7c2a91d5-4e83-4b16-9f27-8a0d6e3b512c",
"body": "Re-drawn tighter. Good to resolve?"
}'
Returns AnnotationComment
AnnotationComment · 18 fields
class AnnotationComment(BaseModel):
"""One comment on an annotation."""
id: str
annotation_id: str
body: str
resolved: bool = False
parent_comment_id: str | None = None
is_edited: bool = False
is_deleted: bool = False
resolved_by: str | None = None
resolved_by_name: str | None = None
resolved_at: datetime | None = None
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
reactions: list[AnnotationCommentReaction] = []
update
Edit the body, resolve or reopen, or both. Only the author edits the body; anyone in the organization can resolve.
Source: AnnotationComments.update
| Arg | Type | Default | Notes |
|---|---|---|---|
comment |
str |
required | Comment id |
body |
str | None |
None |
New text (author only) |
resolved |
bool | None |
None |
True resolves, False reopens |
comment = client.annotation_comments.update(
comment="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)
pictograph annotation-comments edit <comment-id> "Yield sign, partly hidden."
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 · 18 fields
class AnnotationComment(BaseModel):
"""One comment on an annotation."""
id: str
annotation_id: str
body: str
resolved: bool = False
parent_comment_id: str | None = None
is_edited: bool = False
is_deleted: bool = False
resolved_by: str | None = None
resolved_by_name: str | None = None
resolved_at: datetime | None = None
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
reactions: list[AnnotationCommentReaction] = []
resolve
Resolve a comment, or reopen it.
Source: AnnotationComments.resolve
| Arg | Type | Default | Notes |
|---|---|---|---|
comment |
str |
required | Comment id |
resolved |
bool |
True |
False reopens the comment |
client.annotation_comments.resolve(
comment="7c2a91d5-4e83-4b16-9f27-8a0d6e3b512c",
resolved=True,
)
pictograph annotation-comments resolve <comment-id> # --reopen to open it again
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 · 18 fields
class AnnotationComment(BaseModel):
"""One comment on an annotation."""
id: str
annotation_id: str
body: str
resolved: bool = False
parent_comment_id: str | None = None
is_edited: bool = False
is_deleted: bool = False
resolved_by: str | None = None
resolved_by_name: str | None = None
resolved_at: datetime | None = None
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
reactions: list[AnnotationCommentReaction] = []
react
React to a comment. Any role can; repeating a reaction changes nothing, and an unknown one is
a 400.
Source: AnnotationComments.react
| Arg | Type | Default | Notes |
|---|---|---|---|
comment |
str |
required | Comment id |
reaction |
str |
required | Reaction to add: like, dislike, love, celebrate, exclamation, question or haha |
comment = client.annotation_comments.react(
comment="7c2a91d5-4e83-4b16-9f27-8a0d6e3b512c",
reaction="like",
)
print(comment.reactions)
# Reactions are Python and REST only; list shows them with --json.
pictograph annotation-comments list road-signs 001.jpg --json
curl -s -X PUT "https://api.pictograph.io/api/v1/developer/annotation-comments/7c2a91d5-4e83-4b16-9f27-8a0d6e3b512c/reactions/like" \
-H "X-API-Key: $PICTOGRAPH_API_KEY"
Returns AnnotationComment
AnnotationComment · 18 fields
class AnnotationComment(BaseModel):
"""One comment on an annotation."""
id: str
annotation_id: str
body: str
resolved: bool = False
parent_comment_id: str | None = None
is_edited: bool = False
is_deleted: bool = False
resolved_by: str | None = None
resolved_by_name: str | None = None
resolved_at: datetime | None = None
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
reactions: list[AnnotationCommentReaction] = []
unreact
Remove your reaction; removing one you never left changes nothing.
Source: AnnotationComments.unreact
| Arg | Type | Default | Notes |
|---|---|---|---|
comment |
str |
required | Comment id |
reaction |
str |
required | Reaction to remove |
comment = client.annotation_comments.unreact(
comment="7c2a91d5-4e83-4b16-9f27-8a0d6e3b512c",
reaction="like",
)
print(comment.reactions)
# Reactions are Python and REST only; list shows them with --json.
pictograph annotation-comments list road-signs 001.jpg --json
curl -s -X DELETE "https://api.pictograph.io/api/v1/developer/annotation-comments/7c2a91d5-4e83-4b16-9f27-8a0d6e3b512c/reactions/like" \
-H "X-API-Key: $PICTOGRAPH_API_KEY"
Returns AnnotationComment
AnnotationComment · 18 fields
class AnnotationComment(BaseModel):
"""One comment on an annotation."""
id: str
annotation_id: str
body: str
resolved: bool = False
parent_comment_id: str | None = None
is_edited: bool = False
is_deleted: bool = False
resolved_by: str | None = None
resolved_by_name: str | None = None
resolved_at: datetime | None = None
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
reactions: list[AnnotationCommentReaction] = []
delete
Delete a comment: its author can, and so can an admin key. It keeps its place in the
thread with an empty body, so its replies stay attached.
Source: AnnotationComments.delete
| Arg | Type | Default | Notes |
|---|---|---|---|
comment |
str |
required | Comment id |
client.annotation_comments.delete(comment="7c2a91d5-4e83-4b16-9f27-8a0d6e3b512c")
pictograph annotation-comments delete <comment-id> --yes
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 with neither body nor resolved, or a key with no person to author the comment |
| 403 | ForbiddenError |
A viewer key commenting, a non-author editing a body, or a non-author below admin deleting |
| 404 | NotFoundError |
The image or comment doesn’t exist in your organization |