Review entities
The pre-annotated notes now need a human check. In this tutorial, you write a view, a short Python function telling Metanno how to show the notes and their entities. Annotators then read each note with its entities highlighted, fix the wrong ones, add the missing ones and tick those they checked.
Before you start
Follow Pre-annotate first: this tutorial shows the entities it added to oncology.pret.
Write the view
Metanno looks for the Python files of views, called recipes, in the metanno-home/recipes folder, next to the metanno-home/annotations folder of your annotation files, at the root of the file browser. Create it:
from pathlib import Path
Path("~/metanno-home/recipes").expanduser().mkdir(parents=True, exist_ok=True)
then write the view in it:
%%writefile ~/metanno-home/recipes/review_entities.py
from pret_joy import Stack
from metanno import DataRelation, DataWidgetFactory
# Name and color of each entity label, in the text and on the toolbar buttons
LABELS = {
"tumeur": {"name": "Tumeur", "color": "rgb(255,200,206)"},
"tnm": {"name": "TNM", "color": "rgb(210,236,247)"},
}
def main(store):
"""
Show each note with its entities highlighted, and a table to check them
"""
# The factory builds widgets that edit the same Store and share
# their selected rows. The relation limits the entities to those
# of the selected note
factory = DataWidgetFactory(
store,
relations=[DataRelation("notes", "entities", on="note_id")],
)
# One row per note, selecting a note chooses the text shown below.
# store_key is the table of the Store to show, primary_key the column
# identifying its rows, and fields the columns to show
notes = factory.create_table_widget(
store_key="notes",
primary_key="note_id",
fields=[
{"key": "note_id", "kind": "text"},
{"key": "department", "kind": "text", "filterable": True},
{"key": "text", "kind": "text"},
],
style={"height": "150px"},
)
# Text of the selected note with its entities highlighted, and a
# toolbar of labels: select some text then click a label to add an
# entity, or click an entity to edit it. The texts come from notes,
# the entities and their begin and end columns from entities
text, toolbar = factory.create_text_widget(
store_text_key="notes",
store_spans_key="entities",
text_key="text",
text_primary_key="note_id",
spans_primary_key="entity_id",
fields=[{"key": "label", "kind": "select", "editable": True, "options": list(LABELS)}],
labels=LABELS,
)
# Entities of the selected note, label, negated and checked are
# editable
entities = factory.create_table_widget(
store_key="entities",
primary_key="entity_id",
fields=[
{"key": "text", "kind": "text"},
{"key": "label", "kind": "select", "editable": True, "options": list(LABELS)},
{"key": "negated", "kind": "boolean", "editable": True},
{"key": "checked", "kind": "boolean", "editable": True},
],
style={"height": "200px"},
)
# Widgets stacked from top to bottom
return Stack(notes, toolbar, text, entities, spacing=1)
main receives the Store of the annotation file and returns what the tab shows. Metanno calls it each time the file is opened with this view.
Meet DataWidgetFactory
DataWidgetFactory is the helper behind every Metanno view, including the table view you used so far. Its create_*_widget methods build tables, texts and forms connected to the Store: an edit in any widget is saved to the file, and selecting a row in one widget updates the others. fields lists the columns each widget shows and which ones can be edited. Design your view goes through its other widgets and options.
Open the notes with it
from pret import load_store
from metanno import view_opener
store = load_store("~/metanno-home/annotations/oncology.pret")
view_opener(store, view="review_entities")
The menu of the opener now shows review_entities: it lists the recipes of metanno-home/recipes that can display this file, the way the opener of Annotate a table showed note_tnm. Click , then review the notes:
- select note 4 in the top table: its text shows
Tumeur,cT3N1M0andmétastasehighlighted, and the entities table lists them, withmétastasenegated - tick
checkedfor each entity you agree with, and change the label of the ones that are wrong - select note 5: the pipeline missed
lésion, since it is not in its terms. Select the word in the text and click in the toolbar to add it, then tick itsnegatedbox
As before, each change is saved to oncology.pret at once.
Reopen it from the sidebar
The file now remembers its view. Click oncology.pret under Annotations in the sidebar: it reopens with review_entities, without any notebook, which is how annotators usually work.
The tab toolbar
| Button | What it does |
|---|---|
| Kernel name | Runs the view in another kernel, any kernel with Metanno installed can open a saved file |
| View menu | Shows the file with another of your views |
| Reload | Opens the file and runs the view again, after you changed the view |
| Open notebook | Opens the notebook cell that opened the tab |
| Fullscreen | Fills the browser tab with the view |
JupyterLab reopens Metanno tabs after a page refresh. The URL of a fullscreen tab opens the same file again, for instance ?metanno-fullscreen=annotation:/home/you/metanno-home/annotations/oncology.pret, for anyone with access to your Jupyter server and the file.
Changing the view
Edit review_entities.py, then click the reload button of the tab toolbar: Metanno runs the view again on the same file, keeping all annotations.
Next
Your annotators can now work on this project. Design your view goes further, with panels, forms and keyboard shortcuts.