Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ SynAnno is a tool designed for interactive guided proofreading and correction of

## Live Demo

A demo is available [here](http://16.170.214.77/reset).
A simplified version of the app, starting directly in the Error Categorization view, is available [here](http://16.170.214.77/demo).

For the full functionality and configuration options of SynAnno, try the complete version [here](http://16.170.214.77/reset).

## Table of Contents

Expand Down
2 changes: 2 additions & 0 deletions synanno/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ def register_routes(app):
from synanno.routes.annotation import blueprint as annotation_blueprint
from synanno.routes.auto_annotate import blueprint as auto_annotate_blueprint
from synanno.routes.categorize import blueprint as categorize_blueprint
from synanno.routes.demo import blueprint as demo_blueprint
from synanno.routes.false_negatives import blueprint as fn_blueprint
from synanno.routes.file_access import blueprint as file_access_blueprint
from synanno.routes.finish import blueprint as finish_blueprint
Expand All @@ -199,6 +200,7 @@ def register_routes(app):
app.register_blueprint(manual_annotate_blueprint)
app.register_blueprint(auto_annotate_blueprint)
app.register_blueprint(fn_blueprint)
app.register_blueprint(demo_blueprint)


def setup_context_processors(app):
Expand Down
2 changes: 1 addition & 1 deletion synanno/backend/ng_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ def setup_ng(
# if a neuron id is already set in the app context, explicitly select it
if getattr(app, "selected_neuron_id", None) is not None:
with app.ng_viewer.txn() as s:
s.layer.layers["neuropil"].segments = frozenset(
s.layers["neuropil"].segments = frozenset(
[getattr(app, "selected_neuron_id", None)]
)

Expand Down
104 changes: 104 additions & 0 deletions synanno/routes/demo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import logging

import pandas as pd
from flask import Blueprint, current_app, render_template, session

import synanno.backend.ng_util as ng_util
from synanno import initialize_global_variables
from synanno.backend.processing import (
calculate_number_of_pages_for_neuron_section_based_loading,
determine_volume_dimensions,
load_cloud_volumes,
)
from synanno.routes.opendata import (
calculate_scale_factor,
handle_neuron_view,
set_coordinate_resolution,
)

logging.basicConfig(level="INFO")
logger = logging.getLogger(__name__)

blueprint = Blueprint("demo", __name__)


@blueprint.route("/demo", methods=["GET"])
def demo():
"""Displays a loading page and resets the session storage.

Returns:
Renders the loading page.
"""

# Reset logic
session.clear()
initialize_global_variables(current_app)

return render_template("demo_setup.html", next_route="/demo_annotation")


@blueprint.route("/demo_annotation", methods=["GET"])
def demo_init():
"""Initializes the demo data and renders the annotation view.

Returns:
Renders the annotation view after initializing the demo data.
"""
# Upload logic
current_app.view_style = "view_style"
current_app.tiles_per_page = 12

current_app.crop_size_x = 256
current_app.crop_size_y = 256
current_app.crop_size_z = 6

current_app.coordinate_order = {"x": (4, 8), "y": (4, 8), "z": (33, 33)}

source_url = "gs://h01-release/data/20210601/4nm_raw"
target_url = "gs://h01-release/data/20210729/c3/synapses/whole_ei_onlyvol"
neuropil_url = "gs://h01-release/data/20210601/proofread_104"

current_app.synapse_data = pd.read_csv("/app/h01/h01_104_materialization.csv")

load_cloud_volumes(source_url, target_url, neuropil_url, "~/.cloudvolume/secrets")

current_app.vol_dim = determine_volume_dimensions()

set_coordinate_resolution()
calculate_scale_factor()

current_app.vol_dim_scaled = tuple(
int(a * b) for a, b in zip(current_app.vol_dim, current_app.scale.values())
)

current_app.selected_neuron_id = 2325998949

handle_neuron_view(neuropil_url)
current_app.neuron_ready = "true"
current_app.n_pages = calculate_number_of_pages_for_neuron_section_based_loading()

if current_app.ng_version is None:
ng_util.setup_ng(
app=current_app._get_current_object(),
source="precomputed://" + source_url,
target="precomputed://" + target_url,
neuropil="precomputed://" + neuropil_url,
)

page = 1
return render_template(
"annotation.html",
page=page,
n_pages=current_app.n_pages,
grid_opacity=current_app.grid_opacity,
neuron_id=current_app.selected_neuron_id,
neuronReady=current_app.neuron_ready,
neuronSections=current_app.sections,
synapsePointCloud=current_app.snapped_point_cloud,
activeNeuronSection=(
current_app.page_section_mapping[page][0]
if page in current_app.page_section_mapping
else 0
),
activeSynapseIDs=current_app.synapse_data.query("page == @page").index.tolist(),
)
36 changes: 31 additions & 5 deletions synanno/static/annotation.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,22 @@ let currentRequestController = new AbortController();
$(document).ready(() => {
const currentPage = $("script[src*='annotation.js']").data("current-page");
reloadImages(currentPage);

// Bind hotkeys for label opacity and toggle-label button
$(document).on("keydown", (event) => {
const hotkey = event.key.toLowerCase();
const $button = $(`[data-hotkey="${hotkey}"]`);

if ($button.length && !$button.prop("disabled")) {
event.preventDefault();
$button.trigger("click");
}
});

window.check_gt = function () {
$imgTarget.toggle();
$toggleLabel.toggleClass("btn-secondary");
};
});

$(document).on("shown.bs.modal", "#drawModalFN", () => {
Expand All @@ -11,7 +27,7 @@ $(document).on("shown.bs.modal", "#drawModalFN", () => {

const handleSaveBboxClick = async () => {
const currentPage = $("script[src*='annotation.js']").data("current-page");
$('#loading-bar').css('display', 'flex');
$("#loading-bar").css("display", "flex");

$(".text-white").text("Saving new instance...");

Expand All @@ -21,15 +37,15 @@ const handleSaveBboxClick = async () => {
z1: $("#d_z1").val(),
z2: $("#d_z2").val(),
my: $("#m_y").val(),
mx: $("#m_x").val()
mx: $("#m_x").val(),
});

$("#drawModalFNSave, #drawModalFN").modal("hide");
location.reload();
} catch (error) {
console.error("Error saving bbox:", error);
}
$('#loading-bar').css('display', 'none');
$("#loading-bar").css("display", "none");
};

const reloadImages = async (currentPage) => {
Expand Down Expand Up @@ -97,6 +113,16 @@ const hideCardGroupLoadingBar = () => {
};

const toggleNavigationButtons = (disable) => {
$("#prev-page, #next-page").toggleClass("disabled", disable)
.find("a").attr("aria-disabled", disable ? "true" : null);
$("#prev-page, #next-page")
.toggleClass("disabled", disable)
.find("a")
.attr("aria-disabled", disable ? "true" : null);
};

window.toggleAllSources = function () {
const $allImgSources = $("[id^='imgTarget-']");
$allImgSources.each((_, img) => {
const $img = $(img);
$img.toggle();
});
};
11 changes: 11 additions & 0 deletions synanno/static/draw.js
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,17 @@ $(document).ready(() => {
}
}

// Bind hotkeys to buttons
$(document).on("keydown", (event) => {
const hotkey = event.key.toLowerCase();
const $button = $(`[data-hotkey="${hotkey}"]`);

if ($button.length && !$button.prop("disabled")) {
event.preventDefault();
$button.trigger("click");
}
});

$("canvas.curveCanvas").mousemove((event) => {
if (split_mask) {
if ((mousePosition.x != event.clientX || mousePosition.y != event.clientY) && event.buttons == 1) {
Expand Down
16 changes: 15 additions & 1 deletion synanno/templates/annotation.html
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,20 @@
<span id="value-opacity-grid" type="button" class="btn btn-light" value="{{grid_opacity or '0.5'}}">{{grid_opacity or '0.5'}}</span>
<button id="inc-opacity-grid" type="button" class="btn btn-secondary" onclick="add_opacity_grid()">+</button>
</div>

<div class="legend-item">
<button
id="toggle-label-opacity"
type="button"
class="btn btn-secondary"
onclick="toggleAllSources();"
data-hotkey="q"
title="Toggle Label Opacity"
hidden
>
Toggle Label Opacity
</button>
</div>
</div>


Expand Down Expand Up @@ -78,7 +92,7 @@

<!-- Error Processing Button -->
<div class="position-absolute" style="bottom: 1.5rem; right: 2.5rem; z-index: 1000;">
<a class="btn btn-secondary" href="{{ url_for('categorize.categorize') }}">Error Processing</a>
<a class="btn btn-secondary" href="{{ url_for('categorize.categorize') }}">Error Categorization</a>
</div>
</div>
</div>
Expand Down
2 changes: 2 additions & 0 deletions synanno/templates/annotation_single.html
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@
id="toggle-label"
class="btn btn-secondary rounded-start"
onclick="check_gt();"
data-hotkey="q"
title="Toggle label"
>
Label
</button>
Expand Down
27 changes: 27 additions & 0 deletions synanno/templates/demo_setup.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{% extends "templatebase.html" %}

{% block help_content %}
<h1 class="mt-5 text-center text-white">Resetting Data and Loading Demo...</h1>
<p class="text-center text-white">Please wait while the demo data is being initialized.</p>
{% endblock %}

{% block content %}
<div class="d-flex justify-content-center align-items-center" style="height: 100vh;">
<div id="loading-bar">
<div>
<p class="text-white">Resetting Data and Loading Demo...</p>
<div class="progress">
<div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" style="width: 100%;"></div>
</div>
</div>
</div>
</div>
<script>
// Clear session storage and redirect to the next route
sessionStorage.clear();
console.log('Session storage cleared.');
setTimeout(() => {
window.location.href = "{{ next_route }}";
}, 2000);
</script>
{% endblock %}
43 changes: 21 additions & 22 deletions synanno/templates/draw_modal.html
Original file line number Diff line number Diff line change
Expand Up @@ -40,28 +40,27 @@
<div class="text-center">
<div class="d-flex justify-content-center px-2">
<div class="btn-group w-100 flex-wrap gap-1 justify-content-between" role="group" aria-label="Canvas Actions">

<button type="button" class="btn btn-secondary" id="canvasButtonPreCRD" title="Pre-Synaptic Marker">🟢</button>
<button type="button" class="btn btn-secondary" id="canvasButtonPostCRD" title="Post-Synaptic Marker">🔵</button>
<button type="button" class="btn btn-secondary" id="canvasButtonDrawMask" title="Draw Mask">
<i class="bi bi-pencil"></i>
</button>
<button type="button" class="btn btn-secondary" id="canvasButtonFill" title="Fill">
<i class="bi bi-paint-bucket"></i>
</button>
<button type="button" class="btn btn-secondary" id="canvasButtonRevise" title="Revise">
<i class="bi bi-eraser"></i>
</button>
<button type="button" class="btn btn-success" id="canvasButtonSave" title="Save">
<i class="bi bi-save"></i>
</button>
<button type="button" class="btn btn-warning" id="canvasButtonAuto" title="Auto Fill">
<i class="bi bi-magic"></i>
</button>
<button class="btn btn-secondary" id="ng-link-draw" type="button" data-bs-target="#drawModalFN" data-bs-toggle="modal" data-bs-dismiss="modal" title="View in Neuroglancer">
<i class="bi bi-diagram-3"></i>
</button>
</div>
<button type="button" class="btn btn-secondary" id="canvasButtonPreCRD" title="Pre-Synaptic Marker" data-hotkey="q">🟢</button>
<button type="button" class="btn btn-secondary" id="canvasButtonPostCRD" title="Post-Synaptic Marker" data-hotkey="w">🔵</button>
<button type="button" class="btn btn-secondary" id="canvasButtonDrawMask" title="Draw Mask" data-hotkey="e">
<i class="bi bi-pencil"></i>
</button>
<button type="button" class="btn btn-secondary" id="canvasButtonFill" title="Fill" data-hotkey="r">
<i class="bi bi-paint-bucket"></i>
</button>
<button type="button" class="btn btn-secondary" id="canvasButtonRevise" title="Revise" data-hotkey="t">
<i class="bi bi-eraser"></i>
</button>
<button type="button" class="btn btn-success" id="canvasButtonSave" title="Save" data-hotkey="y">
<i class="bi bi-save"></i>
</button>
<button type="button" class="btn btn-warning" id="canvasButtonAuto" title="Auto Fill" data-hotkey="u">
<i class="bi bi-magic"></i>
</button>
<button class="btn btn-secondary" id="ng-link-draw" type="button" data-bs-target="#drawModalFN" data-bs-toggle="modal" data-bs-dismiss="modal" title="View in Neuroglancer" data-hotkey="i">
<i class="bi bi-diagram-3"></i>
</button>
</div>
</div>
</div>

Expand Down
8 changes: 8 additions & 0 deletions synanno/templates/loading_bar_demo.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<div id="loading-bar" style="display: none;">
<div>
<p class="text-white">Resetting Data and Loading Demo...</p>
<div class="progress">
<div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" style="width: 100%;"></div>
</div>
</div>
</div>