From b2d9627af63ee0b0e5c3ff2cd471b1a05fc1b8ff Mon Sep 17 00:00:00 2001 From: cdfhalle Date: Mon, 18 Nov 2024 10:26:01 +0100 Subject: [PATCH 1/8] added new inputs for model evaluation --- app/controllers/JobController.scala | 14 +++- conf/webknossos.latest.routes | 2 +- frontend/javascripts/admin/api/jobs.ts | 14 ++++ .../view/action-bar/starting_job_modals.tsx | 84 ++++++++++++++++++- 4 files changed, 109 insertions(+), 5 deletions(-) diff --git a/app/controllers/JobController.scala b/app/controllers/JobController.scala index 8d45f63ed0..0b397f1190 100644 --- a/app/controllers/JobController.scala +++ b/app/controllers/JobController.scala @@ -226,7 +226,13 @@ class JobController @Inject()( datasetName: String, layerName: String, bbox: String, - newDatasetName: String): Action[AnyContent] = + newDatasetName: String, + doEvaluation: Boolean, + annotationId: Option[String], + evalUseSparseTracing: Option[Boolean], + evalMaxEdgeLength: Option[String], + evalSparseTubeThresholdNm: Option[String], + evalMinMergerPathLengthNm: Option[String]): Action[AnyContent] = sil.SecuredAction.async { implicit request => log(Some(slackNotificationService.noticeFailedJobRequest)) { for { @@ -246,6 +252,12 @@ class JobController @Inject()( "new_dataset_name" -> newDatasetName, "layer_name" -> layerName, "bbox" -> bbox, + "do_evaluation" -> doEvaluation, + "annotation_id" -> annotationId, + "eval_use_sparse_tracing" -> evalUseSparseTracing, + "eval_max_edge_length" -> evalMaxEdgeLength, + "eval_sparse_tube_threshold_nm" -> evalSparseTubeThresholdNm, + "eval_min_merger_path_length_nm" -> evalMinMergerPathLengthNm, ) job <- jobService.submitJob(command, commandArgs, request.identity, dataset._dataStore) ?~> "job.couldNotRunNeuronInferral" js <- jobService.publicWrites(job) diff --git a/conf/webknossos.latest.routes b/conf/webknossos.latest.routes index 470c28e127..f8089dac9a 100644 --- a/conf/webknossos.latest.routes +++ b/conf/webknossos.latest.routes @@ -264,7 +264,7 @@ POST /jobs/run/computeMeshFile/:organizationId/:datasetName POST /jobs/run/computeSegmentIndexFile/:organizationId/:datasetName controllers.JobController.runComputeSegmentIndexFileJob(organizationId: String, datasetName: String, layerName: String) POST /jobs/run/exportTiff/:organizationId/:datasetName controllers.JobController.runExportTiffJob(organizationId: String, datasetName: String, bbox: String, additionalCoordinates: Option[String], layerName: Option[String], mag: Option[String], annotationLayerName: Option[String], annotationId: Option[String], asOmeTiff: Boolean) POST /jobs/run/inferNuclei/:organizationId/:datasetName controllers.JobController.runInferNucleiJob(organizationId: String, datasetName: String, layerName: String, newDatasetName: String) -POST /jobs/run/inferNeurons/:organizationId/:datasetName controllers.JobController.runInferNeuronsJob(organizationId: String, datasetName: String, layerName: String, bbox: String, newDatasetName: String) +POST /jobs/run/inferNeurons/:organizationId/:datasetName controllers.JobController.runInferNeuronsJob(organizationId: String, datasetName: String, layerName: String, bbox: String, newDatasetName: String, doEvaluation: Boolean, annotationId: Option[String],evalUseSparseTracing: Option[Boolean],evalMaxEdgeLength: Option[String],evalSparseTubeThresholdNm: Option[String],evalMinMergerPathLengthNm: Option[String]) POST /jobs/run/inferMitochondria/:organizationId/:datasetName controllers.JobController.runInferMitochondriaJob(organizationId: String, datasetName: String, layerName: String, bbox: String, newDatasetName: String) POST /jobs/run/alignSections/:organizationId/:datasetName controllers.JobController.runAlignSectionsJob(organizationId: String, datasetName: String, layerName: String, newDatasetName: String, annotationId: Option[String]) POST /jobs/run/materializeVolumeAnnotation/:organizationId/:datasetName controllers.JobController.runMaterializeVolumeAnnotationJob(organizationId: String, datasetName: String, fallbackLayerName: String, annotationId: String, annotationType: String, newDatasetName: String, outputSegmentationLayerName: String, mergeSegments: Boolean, volumeLayerName: Option[String]) diff --git a/frontend/javascripts/admin/api/jobs.ts b/frontend/javascripts/admin/api/jobs.ts index 99d1c6e1bf..7aa6ef177c 100644 --- a/frontend/javascripts/admin/api/jobs.ts +++ b/frontend/javascripts/admin/api/jobs.ts @@ -193,12 +193,26 @@ export function startNeuronInferralJob( layerName: string, bbox: Vector6, newDatasetName: string, + doEvaluation: boolean, + annotationId?: string, + useSparseTracing?: boolean, + evalMaxEdgeLength?: string, + evalSparseTubeThresholdNm?: string, + evalMinMergerPathLengthNm?: string, ): Promise { const urlParams = new URLSearchParams({ layerName, bbox: bbox.join(","), newDatasetName, + doEvaluation: doEvaluation.toString() }); + if (doEvaluation) { + urlParams.append("annotationId", `${annotationId}`) + urlParams.append("evalUseSparseTracing", `${useSparseTracing}`); + urlParams.append("evalMaxEdgeLength", `${evalMaxEdgeLength}`); + urlParams.append("evalSparseTubeThresholdNm", `${evalSparseTubeThresholdNm}`); + urlParams.append("evalMinMergerPathLengthNm", `${evalMinMergerPathLengthNm}`); + } return Request.receiveJSON( `/api/jobs/run/inferNeurons/${organizationId}/${datasetName}?${urlParams.toString()}`, { diff --git a/frontend/javascripts/oxalis/view/action-bar/starting_job_modals.tsx b/frontend/javascripts/oxalis/view/action-bar/starting_job_modals.tsx index a7b75bad1f..894154dfe0 100644 --- a/frontend/javascripts/oxalis/view/action-bar/starting_job_modals.tsx +++ b/frontend/javascripts/oxalis/view/action-bar/starting_job_modals.tsx @@ -15,6 +15,9 @@ import { Switch, type FormInstance, Checkbox, + Collapse, + Col, + InputNumber, } from "antd"; import { startNucleiInferralJob, @@ -59,6 +62,8 @@ import { useGuardedFetch } from "libs/react_helpers"; import _ from "lodash"; import DEFAULT_PREDICT_WORKFLOW from "./default-predict-workflow-template"; import { Slider } from "components/slider"; +import FormItem from "antd/es/form/FormItem"; +import { evaluate } from "@shaderfrog/glsl-parser/dist/ast"; const { ThinSpace } = Unicode; @@ -98,6 +103,7 @@ type StartJobFormProps = Props & { jobApiCall: (arg0: JobApiCallArgsType, form: FormInstance) => Promise; jobName: keyof typeof jobNameToImagePath; description: React.ReactNode; + jobSpecificInputFields?: React.ReactNode | undefined; isBoundingBoxConfigurable?: boolean; chooseSegmentationLayer?: boolean; suggestedDatasetSuffix: string; @@ -521,11 +527,58 @@ function ShouldUseTreesFormItem() { ); } +function CollapsibleEvaluationSettings({ + isActive = false, + setActive, +}: { isActive: boolean; setActive: (active: boolean) => void }) { + return ( + setActive(!isActive)} + expandIcon={() => } + items={[ + { + key: "evaluation", + label: "Evaluation Settings", + children: ( + + + + + + + + + + + + + + + + + + ), + }, + ]} + activeKey={isActive ? "evaluation" : []} + /> + ) +} + function StartJobForm(props: StartJobFormProps) { const isBoundingBoxConfigurable = props.isBoundingBoxConfigurable || false; const isSkeletonSelectable = props.isSkeletonSelectable || false; const chooseSegmentationLayer = props.chooseSegmentationLayer || false; - const { handleClose, jobName, jobApiCall, fixedSelectedLayer, title, description } = props; + const { handleClose, jobName, jobApiCall, fixedSelectedLayer, title, description, jobSpecificInputFields } = props; const [form] = Form.useForm(); const rawUserBoundingBoxes = useSelector((state: OxalisState) => getUserBoundingBoxesFromState(state), @@ -646,6 +699,7 @@ function StartJobForm(props: StartJobFormProps) { onChangeSelectedBoundingBox={(bBoxId) => form.setFieldsValue({ boundingBoxId: bBoxId })} value={form.getFieldValue("boundingBoxId")} /> + {jobSpecificInputFields} {isSkeletonSelectable && } {props.showWorkflowYaml ? ( state.dataset); const dispatch = useDispatch(); + const [useEvaluation, setUseEvaluation] = React.useState(false); return ( dispatch(setAIJobModalStateAction("invisible"))} @@ -711,18 +766,35 @@ export function NeuronSegmentationForm() { title="AI Neuron Segmentation" suggestedDatasetSuffix="with_reconstructed_neurons" isBoundingBoxConfigurable - jobApiCall={async ({ newDatasetName, selectedLayer: colorLayer, selectedBoundingBox }) => { - if (!selectedBoundingBox) { + jobApiCall={async ({ newDatasetName, selectedLayer: colorLayer, selectedBoundingBox, annotationId }, form: FormInstance) => { + const evaluationSettings = form.getFieldValue("evaluationSettings"); + if (!selectedBoundingBox || useEvaluation && evaluationSettings == null) { return; } const bbox = computeArrayFromBoundingBox(selectedBoundingBox.boundingBox); + if(!useEvaluation){ + return startNeuronInferralJob( + dataset.owningOrganization, + dataset.name, + colorLayer.name, + bbox, + newDatasetName, + useEvaluation, + ); + } return startNeuronInferralJob( dataset.owningOrganization, dataset.name, colorLayer.name, bbox, newDatasetName, + useEvaluation, + annotationId, + evaluationSettings.useSparseTracing, + evaluationSettings.maxEdgeLength, + evaluationSettings.sparseTubeThresholdInNm, + evaluationSettings.minimumMergerPathLengthInNm ); }} description={ @@ -738,6 +810,12 @@ export function NeuronSegmentationForm() { } + jobSpecificInputFields={ + + } /> ); } From ac88d7de286ffd8ea4a9110c40299c1214952f69 Mon Sep 17 00:00:00 2001 From: cdfhalle Date: Wed, 20 Nov 2024 14:14:41 +0100 Subject: [PATCH 2/8] run formatter --- frontend/javascripts/admin/api/jobs.ts | 4 +- .../view/action-bar/starting_job_modals.tsx | 76 ++++++++++++------- 2 files changed, 52 insertions(+), 28 deletions(-) diff --git a/frontend/javascripts/admin/api/jobs.ts b/frontend/javascripts/admin/api/jobs.ts index 7aa6ef177c..fe69570e66 100644 --- a/frontend/javascripts/admin/api/jobs.ts +++ b/frontend/javascripts/admin/api/jobs.ts @@ -204,10 +204,10 @@ export function startNeuronInferralJob( layerName, bbox: bbox.join(","), newDatasetName, - doEvaluation: doEvaluation.toString() + doEvaluation: doEvaluation.toString(), }); if (doEvaluation) { - urlParams.append("annotationId", `${annotationId}`) + urlParams.append("annotationId", `${annotationId}`); urlParams.append("evalUseSparseTracing", `${useSparseTracing}`); urlParams.append("evalMaxEdgeLength", `${evalMaxEdgeLength}`); urlParams.append("evalSparseTubeThresholdNm", `${evalSparseTubeThresholdNm}`); diff --git a/frontend/javascripts/oxalis/view/action-bar/starting_job_modals.tsx b/frontend/javascripts/oxalis/view/action-bar/starting_job_modals.tsx index 894154dfe0..e278293c7c 100644 --- a/frontend/javascripts/oxalis/view/action-bar/starting_job_modals.tsx +++ b/frontend/javascripts/oxalis/view/action-bar/starting_job_modals.tsx @@ -62,8 +62,6 @@ import { useGuardedFetch } from "libs/react_helpers"; import _ from "lodash"; import DEFAULT_PREDICT_WORKFLOW from "./default-predict-workflow-template"; import { Slider } from "components/slider"; -import FormItem from "antd/es/form/FormItem"; -import { evaluate } from "@shaderfrog/glsl-parser/dist/ast"; const { ThinSpace } = Unicode; @@ -543,42 +541,68 @@ function CollapsibleEvaluationSettings({ children: ( - - + If not, use the `sparse` mode." + > + - - + However, this can also introduce wrong nodes in curved processes." + > + - - + + - - + estimation makes sure no relevant mergers are ignored." + > + - + ), }, ]} activeKey={isActive ? "evaluation" : []} - /> - ) + /> + ); } function StartJobForm(props: StartJobFormProps) { const isBoundingBoxConfigurable = props.isBoundingBoxConfigurable || false; const isSkeletonSelectable = props.isSkeletonSelectable || false; const chooseSegmentationLayer = props.chooseSegmentationLayer || false; - const { handleClose, jobName, jobApiCall, fixedSelectedLayer, title, description, jobSpecificInputFields } = props; + const { + handleClose, + jobName, + jobApiCall, + fixedSelectedLayer, + title, + description, + jobSpecificInputFields, + } = props; const [form] = Form.useForm(); const rawUserBoundingBoxes = useSelector((state: OxalisState) => getUserBoundingBoxesFromState(state), @@ -766,14 +790,17 @@ export function NeuronSegmentationForm() { title="AI Neuron Segmentation" suggestedDatasetSuffix="with_reconstructed_neurons" isBoundingBoxConfigurable - jobApiCall={async ({ newDatasetName, selectedLayer: colorLayer, selectedBoundingBox, annotationId }, form: FormInstance) => { + jobApiCall={async ( + { newDatasetName, selectedLayer: colorLayer, selectedBoundingBox, annotationId }, + form: FormInstance, + ) => { const evaluationSettings = form.getFieldValue("evaluationSettings"); - if (!selectedBoundingBox || useEvaluation && evaluationSettings == null) { + if (!selectedBoundingBox || (useEvaluation && evaluationSettings == null)) { return; } const bbox = computeArrayFromBoundingBox(selectedBoundingBox.boundingBox); - if(!useEvaluation){ + if (!useEvaluation) { return startNeuronInferralJob( dataset.owningOrganization, dataset.name, @@ -794,7 +821,7 @@ export function NeuronSegmentationForm() { evaluationSettings.useSparseTracing, evaluationSettings.maxEdgeLength, evaluationSettings.sparseTubeThresholdInNm, - evaluationSettings.minimumMergerPathLengthInNm + evaluationSettings.minimumMergerPathLengthInNm, ); }} description={ @@ -811,10 +838,7 @@ export function NeuronSegmentationForm() { } jobSpecificInputFields={ - + } /> ); From 3258794d637c776862b5d31199576638269f3d12 Mon Sep 17 00:00:00 2001 From: cdfhalle Date: Wed, 20 Nov 2024 15:18:28 +0100 Subject: [PATCH 3/8] updated changelog --- CHANGELOG.unreleased.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.unreleased.md b/CHANGELOG.unreleased.md index 4e0cb15ae5..d633573be4 100644 --- a/CHANGELOG.unreleased.md +++ b/CHANGELOG.unreleased.md @@ -11,6 +11,7 @@ For upgrade instructions, please check the [migration guide](MIGRATIONS.released [Commits](https://github.com/scalableminds/webknossos/compare/24.10.0...HEAD) ### Added +- It is now possible to start a split-merger evaluation when starting a neuron inferrence. [#8221](https://github.com/scalableminds/webknossos/pull/8221) - It is now possible to add metadata in annotations to Trees and Segments. [#7875](https://github.com/scalableminds/webknossos/pull/7875) - Added a summary row to the time tracking overview, where times and annotations/tasks are summed. [#8092](https://github.com/scalableminds/webknossos/pull/8092) - Most sliders have been improved: Wheeling above a slider now changes its value and double-clicking its knob resets it to its default value. [#8095](https://github.com/scalableminds/webknossos/pull/8095) From 92b61697abc97242d1c56921947cb7d7a36fc035 Mon Sep 17 00:00:00 2001 From: cdfhalle Date: Tue, 26 Nov 2024 12:25:08 +0100 Subject: [PATCH 4/8] add support for displaying annotation links instead of datasets --- app/models/job/Job.scala | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/models/job/Job.scala b/app/models/job/Job.scala index 4fe3fe6ac3..9f58461fb4 100644 --- a/app/models/job/Job.scala +++ b/app/models/job/Job.scala @@ -52,6 +52,7 @@ case class Job( def datasetName: Option[String] = argAsStringOpt("dataset_name") private def argAsStringOpt(key: String) = (commandArgs \ key).toOption.flatMap(_.asOpt[String]) + private def argAsBooleanOpt(key: String) = (commandArgs \ key).toOption.flatMap(_.asOpt[Boolean]) def resultLink(organizationId: String): Option[String] = if (effectiveState != JobState.SUCCESS) None @@ -63,6 +64,8 @@ case class Job( } case JobCommand.export_tiff | JobCommand.render_animation => Some(s"/api/jobs/${this._id}/export") + case JobCommand.infer_neurons if this.argAsBooleanOpt("do_evaluation").getOrElse(false) => + returnValue.map { resultAnnotationLink => resultAnnotationLink} case JobCommand.infer_nuclei | JobCommand.infer_neurons | JobCommand.materialize_volume_annotation | JobCommand.infer_with_model | JobCommand.infer_mitochondria | JobCommand.align_sections => returnValue.map { resultDatasetName => From 67a55ffdc6cbfac4f267bdeedfa2ebb459be73ec Mon Sep 17 00:00:00 2001 From: cdfhalle <82583544+cdfhalle@users.noreply.github.com> Date: Tue, 26 Nov 2024 12:34:39 +0100 Subject: [PATCH 5/8] Update CHANGELOG.unreleased.md Co-authored-by: MichaelBuessemeyer <39529669+MichaelBuessemeyer@users.noreply.github.com> --- CHANGELOG.unreleased.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.unreleased.md b/CHANGELOG.unreleased.md index 826397b0d3..ef938f51a7 100644 --- a/CHANGELOG.unreleased.md +++ b/CHANGELOG.unreleased.md @@ -11,7 +11,7 @@ For upgrade instructions, please check the [migration guide](MIGRATIONS.released [Commits](https://github.com/scalableminds/webknossos/compare/24.11.1...HEAD) ### Added -- It is now possible to start a split-merger evaluation when starting a neuron inferrence. [#8221](https://github.com/scalableminds/webknossos/pull/8221) +- It is now possible to start a split-merger evaluation when starting a neuron inference. [#8221](https://github.com/scalableminds/webknossos/pull/8221) - When exploring remote URIs pasted from Neuroglancer, the format prefixes like `precomputed://` are now ignored, so users don’t have to remove them. [#8195](https://github.com/scalableminds/webknossos/pull/8195) ### Changed From 63bade2d5e9068d848615d1e2fcbb1c855f9ed43 Mon Sep 17 00:00:00 2001 From: cdfhalle Date: Tue, 26 Nov 2024 13:24:49 +0100 Subject: [PATCH 6/8] adapt to feedback --- app/controllers/JobController.scala | 4 +- conf/application.conf | 4 +- conf/webknossos.latest.routes | 2 +- frontend/javascripts/admin/api/jobs.ts | 25 ++++++++--- .../view/action-bar/starting_job_modals.tsx | 45 +++++++++++-------- 5 files changed, 50 insertions(+), 30 deletions(-) diff --git a/app/controllers/JobController.scala b/app/controllers/JobController.scala index d4f343b14a..23aad7c8a0 100644 --- a/app/controllers/JobController.scala +++ b/app/controllers/JobController.scala @@ -227,7 +227,7 @@ class JobController @Inject()( layerName: String, bbox: String, newDatasetName: String, - doEvaluation: Boolean, + doSplitMergerEvaluation: Boolean, annotationId: Option[String], evalUseSparseTracing: Option[Boolean], evalMaxEdgeLength: Option[String], @@ -254,7 +254,7 @@ class JobController @Inject()( "new_dataset_name" -> newDatasetName, "layer_name" -> layerName, "bbox" -> bbox, - "do_evaluation" -> doEvaluation, + "do_split_merger_evaluation" -> doSplitMergerEvaluation, "annotation_id" -> annotationId, "eval_use_sparse_tracing" -> evalUseSparseTracing, "eval_max_edge_length" -> evalMaxEdgeLength, diff --git a/conf/application.conf b/conf/application.conf index 2cfdcccb0c..19ba8cd008 100644 --- a/conf/application.conf +++ b/conf/application.conf @@ -151,8 +151,8 @@ features { taskReopenAllowedInSeconds = 30 allowDeleteDatasets = true # to enable jobs for local development, use "yarn enable-jobs" to also activate it in the database - jobsEnabled = false - voxelyticsEnabled = false + jobsEnabled = true + voxelyticsEnabled = true # For new users, the dashboard will show a banner which encourages the user to check out the following dataset. # If isWkorgInstance == true, `/createExplorative/hybrid/true` is appended to the URL so that a new tracing is opened. # If isWkorgInstance == false, `/view` is appended to the URL so that it's opened in view mode (since the user might not diff --git a/conf/webknossos.latest.routes b/conf/webknossos.latest.routes index 310e384257..7fdbffc16c 100644 --- a/conf/webknossos.latest.routes +++ b/conf/webknossos.latest.routes @@ -264,7 +264,7 @@ POST /jobs/run/computeMeshFile/:organizationId/:datasetName POST /jobs/run/computeSegmentIndexFile/:organizationId/:datasetName controllers.JobController.runComputeSegmentIndexFileJob(organizationId: String, datasetName: String, layerName: String) POST /jobs/run/exportTiff/:organizationId/:datasetName controllers.JobController.runExportTiffJob(organizationId: String, datasetName: String, bbox: String, additionalCoordinates: Option[String], layerName: Option[String], mag: Option[String], annotationLayerName: Option[String], annotationId: Option[String], asOmeTiff: Boolean) POST /jobs/run/inferNuclei/:organizationId/:datasetName controllers.JobController.runInferNucleiJob(organizationId: String, datasetName: String, layerName: String, newDatasetName: String) -POST /jobs/run/inferNeurons/:organizationId/:datasetName controllers.JobController.runInferNeuronsJob(organizationId: String, datasetName: String, layerName: String, bbox: String, newDatasetName: String, doEvaluation: Boolean, annotationId: Option[String],evalUseSparseTracing: Option[Boolean],evalMaxEdgeLength: Option[String],evalSparseTubeThresholdNm: Option[String],evalMinMergerPathLengthNm: Option[String]) +POST /jobs/run/inferNeurons/:organizationId/:datasetName controllers.JobController.runInferNeuronsJob(organizationId: String, datasetName: String, layerName: String, bbox: String, newDatasetName: String, doSplitMergerEvaluation: Boolean, annotationId: Option[String], evalUseSparseTracing: Option[Boolean], evalMaxEdgeLength: Option[String], evalSparseTubeThresholdNm: Option[String], evalMinMergerPathLengthNm: Option[String]) POST /jobs/run/inferMitochondria/:organizationId/:datasetName controllers.JobController.runInferMitochondriaJob(organizationId: String, datasetName: String, layerName: String, bbox: String, newDatasetName: String) POST /jobs/run/alignSections/:organizationId/:datasetName controllers.JobController.runAlignSectionsJob(organizationId: String, datasetName: String, layerName: String, newDatasetName: String, annotationId: Option[String]) POST /jobs/run/materializeVolumeAnnotation/:organizationId/:datasetName controllers.JobController.runMaterializeVolumeAnnotationJob(organizationId: String, datasetName: String, fallbackLayerName: String, annotationId: String, annotationType: String, newDatasetName: String, outputSegmentationLayerName: String, mergeSegments: Boolean, volumeLayerName: Option[String]) diff --git a/frontend/javascripts/admin/api/jobs.ts b/frontend/javascripts/admin/api/jobs.ts index f1a4b6fb93..d2f9e0af4a 100644 --- a/frontend/javascripts/admin/api/jobs.ts +++ b/frontend/javascripts/admin/api/jobs.ts @@ -193,7 +193,7 @@ export function startNeuronInferralJob( layerName: string, bbox: Vector6, newDatasetName: string, - doEvaluation: boolean, + doSplitMergerEvaluation: boolean, annotationId?: string, useSparseTracing?: boolean, evalMaxEdgeLength?: string, @@ -204,14 +204,25 @@ export function startNeuronInferralJob( layerName, bbox: bbox.join(","), newDatasetName, - doEvaluation: doEvaluation.toString(), + doSplitMergerEvaluation: doSplitMergerEvaluation.toString(), }); - if (doEvaluation) { + if (doSplitMergerEvaluation) { + if (!annotationId) { + throw new Error("annotationId is required when doEvaluation is true"); + } urlParams.append("annotationId", `${annotationId}`); - urlParams.append("evalUseSparseTracing", `${useSparseTracing}`); - urlParams.append("evalMaxEdgeLength", `${evalMaxEdgeLength}`); - urlParams.append("evalSparseTubeThresholdNm", `${evalSparseTubeThresholdNm}`); - urlParams.append("evalMinMergerPathLengthNm", `${evalMinMergerPathLengthNm}`); + if (useSparseTracing != null) { + urlParams.append("evalUseSparseTracing", `${useSparseTracing}`); + } + if (evalMaxEdgeLength != null) { + urlParams.append("evalMaxEdgeLength", `${evalMaxEdgeLength}`); + } + if (evalSparseTubeThresholdNm != null) { + urlParams.append("evalSparseTubeThresholdNm", `${evalSparseTubeThresholdNm}`); + } + if (evalMinMergerPathLengthNm != null) { + urlParams.append("evalMinMergerPathLengthNm", `${evalMinMergerPathLengthNm}`); + } } return Request.receiveJSON( `/api/jobs/run/inferNeurons/${organizationId}/${datasetName}?${urlParams.toString()}`, diff --git a/frontend/javascripts/oxalis/view/action-bar/starting_job_modals.tsx b/frontend/javascripts/oxalis/view/action-bar/starting_job_modals.tsx index fc4cea4610..817d425f7c 100644 --- a/frontend/javascripts/oxalis/view/action-bar/starting_job_modals.tsx +++ b/frontend/javascripts/oxalis/view/action-bar/starting_job_modals.tsx @@ -527,7 +527,7 @@ function ShouldUseTreesFormItem() { ); } -function CollapsibleEvaluationSettings({ +function CollapsibleSplitMergersplitMergerEvaluationSettings({ isActive = false, setActive, }: { isActive: boolean; setActive: (active: boolean) => void }) { @@ -545,9 +545,9 @@ function CollapsibleEvaluationSettings({ @@ -573,7 +573,7 @@ function CollapsibleEvaluationSettings({ - +