Skip to content
Open
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
1 change: 1 addition & 0 deletions docs/_toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ parts:
- caption: User Guide
chapters:
- file: usage/overview
- file: usage/keyboard-shortcuts
- file: usage/rapid-building-assessment
- file: usage/damage-mapping
- file: usage/building-blocks
Expand Down
7 changes: 4 additions & 3 deletions docs/usage/damage-mapping.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ labels, or the arrow next to **Save** to save and start training in one step.

To make damage easier to see while you label, tune the view of the pre-/post-event imagery:
**Opacity**, **Contrast**, **Hue Rotation**, and **Saturation** sliders (with **Reset**).
Toggle between post- and pre-event imagery with the imagery switch or `Ctrl+Alt+C` — if you
didn't upload pre-event imagery, the tool falls back to the Azure Basemap.
Toggle between post- and pre-event imagery with the imagery switch. Press `A` for pre-event
(or the Azure Basemap fallback) and `D` for post-event imagery.

![Labeling imagery properties panel](../_static/usage/labeling/labeling-imagery-properties.png)

Expand Down Expand Up @@ -138,7 +138,8 @@ use the predictions.
control, the predicted damage layer overlaid on both, and an optional **raw predictions**
layer you can toggle on. Imagery sliders (opacity, contrast, hue, saturation) and keyboard
shortcuts — `A` (all pre-event), `S` (split), `D` (all post-event) — help you inspect and
share the result.
share the result. See {doc}`Keyboard shortcuts <keyboard-shortcuts>` for the complete
reference.

![The raw per-pixel predictions layer toggled on](../_static/usage/results/raw-predictions-layer.png)

Expand Down
66 changes: 66 additions & 0 deletions docs/usage/keyboard-shortcuts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Keyboard Shortcuts

HASTE provides keyboard shortcuts for imagery comparison, labeling, and
building validation. Each supported view also includes a collapsible
**Keyboard shortcuts** section.

## Contents

- [General behavior](#general-behavior)
- [Results viewer](#results-viewer)
- [Interactive Labeler](#interactive-labeler)
- [Labeling Tool](#labeling-tool)
- [Building Validation](#building-validation)

## General Behavior

Letter shortcuts are not case-sensitive. HASTE ignores global shortcuts while
you type in a field or interact with a button, link, dropdown, or switch.

The imagery comparison keys use the same direction across views:

- `A` shows pre-event imagery or moves a swipe divider left.
- `S` centers a swipe divider when the view supports split comparison.
- `D` shows post-event imagery or moves a swipe divider right.

## Results Viewer

| Shortcut | Action |
|---|---|
| `A` | Move the swipe divider left to show pre-event imagery. |
| `S` | Center the swipe divider for an even comparison. |
| `D` | Move the swipe divider right to show post-event imagery. |

## Interactive Labeler

| Shortcut | Action |
|---|---|
| `1` | Select **Intact**. |
| `2` | Select **Damaged**. |
| `3` | Select **Cloudy**. |
| `T` | Cycle through the available classes. |
| `P` | Toggle between labeled and predicted views when the model can train. |
| `Space` | Show or hide building footprints. |
| `Ctrl` + drag | Box-label buildings. |
| `A` | Move the enabled swipe divider left. |
| `S` | Center the enabled swipe divider. |
| `D` | Move the enabled swipe divider right. |

## Labeling Tool

| Shortcut | Action |
|---|---|
| `A` | Show pre-event imagery, or the basemap when pre-event imagery is unavailable. |
| `D` | Show post-event imagery. |

## Building Validation

| Shortcut | Action |
|---|---|
| `1` | Label the selected building **Damaged**. |
| `2` | Label the selected building **Not Damaged**. |
| `3` | Label the selected building **Unknown**. |
| `Left Arrow` | Select the previous building in the current filter. |
| `Right Arrow` | Select the next building in the current filter. |
| `A` | Show pre-event imagery, or the basemap when pre-event imagery is unavailable. |
| `D` | Show post-event imagery. |
2 changes: 2 additions & 0 deletions docs/usage/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,5 @@ continuous, pixel-level damage raster.
Both workflows start the same way — create a project and add an image layer — then diverge.
Those shared building blocks have their own pages: {doc}`Projects <projects>`,
{doc}`Image layers <image-layers>`, and the {doc}`Model catalog <model-catalog>`.
See {doc}`Keyboard shortcuts <keyboard-shortcuts>` for the controls available
across map and labeling views.
14 changes: 11 additions & 3 deletions docs/usage/rapid-building-assessment.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,16 +83,23 @@ panel with the class selector, counts, a view toggle, and quality metrics.
- **Classes:** **Intact** (green), **Damaged** (red), **Cloudy** (purple) for obscured
buildings; unlabeled buildings are gray.
- **Shortcuts:** `1`/`2`/`3` pick a class, `T` cycles, `P` toggles Labeled/Predicted view,
`Space` shows/hides footprints.
`Space` shows/hides footprints, and `Ctrl+drag` box-labels buildings. Swipe comparison is
on by default; `A`/`S`/`D` move its divider left/to an even split/right.
See {doc}`Keyboard shortcuts <keyboard-shortcuts>` for the complete reference.

Once you've labeled at least **3 buildings across 2+ classes**, an in-browser model
Once you've labeled at least **3 buildings in each of 2+ classes**, an in-browser model
(logistic regression, WebGPU-accelerated when available) trains automatically and predicts
damage for every building in view. Toggle **View: Labeled ↔ Predicted** to compare. The
panel shows holdout **precision / recall / F1 for the Damaged class** so you can watch
quality improve as you label diverse examples.

![The Interactive Labeler in Predicted view, with holdout metrics](../_static/usage/interactive/labeler-predicted.png)

Under **Advanced**, **Show misclassified buildings** trains or reuses the current in-browser
model and highlights only human-labeled buildings whose current prediction differs. Correctly
classified and unlabeled buildings are not highlighted. This view is mutually exclusive with
Predicted and Uncertainty views and turns off if labels fall below the training threshold.

## Step 3 — Predict all buildings

- **Save labels** persists your manual labels so you can resume later (no full prediction).
Expand All @@ -115,7 +122,8 @@ sample of footprints (~200 by default) with the pre-/post-event imagery.

- Select a building and label it **Damaged**, **Not Damaged**, or **Unknown**.
- **Shortcuts:** `1`/`2`/`3` to label; arrow keys to move Prev/Next (auto-advances to the
next unlabeled). Filter by label status; a progress bar tracks your coverage.
next unlabeled); `A` shows pre-event imagery (or basemap) and `D` shows post-event imagery.
Filter by label status; a progress bar tracks your coverage.
- **Save Labels** to persist, or **Download GeoJSON** to export the labeled sample.

These human labels are the **ground truth** the reports compare predictions against
Expand Down
2 changes: 1 addition & 1 deletion ui/src/AppContext.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ export const AppProvider = ({ children }) => {
target: `#postEventImagery`,
title: "Imagery toggle",
content:
"Click on the toggle to switch between post event and pre event imagery. If you did not upload pre event imagery, the tool will default to Azure Basemap. You can also use the keyboard shortcut - Ctrl+Alt+c",
"Click the toggle to switch imagery. Press A for pre event (or Azure Basemap) and D for post event.",
},
{
type: "teachingBubble",
Expand Down
17 changes: 13 additions & 4 deletions ui/src/Components/BuildingValidation/BuildingValidation.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -311,9 +311,11 @@ const BuildingValidation = () => {
}
}, [showFill, isMapReady]);

// Toggle post-event imagery layer so the user can compare the
// post-event view against the basemap satellite underneath.
// A single-map comparison: post-event on, or pre-event/basemap when off.
useEffect(() => {
if (preImageryRef.current) {
preImageryRef.current.setOptions({ visible: !showPostImagery });
}
if (postImageryRef.current) {
postImageryRef.current.setOptions({ visible: showPostImagery });
}
Expand Down Expand Up @@ -487,12 +489,14 @@ const BuildingValidation = () => {
// Keyboard shortcuts:
// 1 / 2 / 3 — assign Damaged / NotDamaged / Unknown
// ArrowLeft / ArrowRight — move through the filtered list
// A / D — show pre (or basemap) / post imagery
// The right-panel toggles and dropdown remain focusable; the
// INPUT/TEXTAREA/SELECT guard keeps shortcuts from hijacking typing.
// editable-target guard keeps shortcuts from hijacking typing.
useEffect(() => {
const keyMap = { "1": "Damaged", "2": "NotDamaged", "3": "Unknown" };
function onKeyDown(e) {
if (["INPUT", "TEXTAREA", "SELECT"].includes(e.target.tagName)) return;
if (shouldIgnoreShortcut(e)) return;
if (e.ctrlKey || e.altKey || e.metaKey) return;
const labelValue = keyMap[e.key];
if (labelValue) {
handleLabel(labelValue);
Expand All @@ -504,6 +508,10 @@ const BuildingValidation = () => {
} else if (e.key === "ArrowRight") {
e.preventDefault();
navigateInFilter(1);
} else {
const key = e.key.toLowerCase();
if (key === "a") setShowPostImagery(false);
else if (key === "d") setShowPostImagery(true);
}
}
window.addEventListener("keydown", onKeyDown);
Expand Down Expand Up @@ -596,6 +604,7 @@ const BuildingValidation = () => {
setShowFill={setShowFill}
showPostImagery={showPostImagery}
setShowPostImagery={setShowPostImagery}
hasPreImagery={!!preImageryRef.current}
hasPostImagery={!!postImageryRef.current}
/>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import {
makeStyles,
tokens,
} from "@fluentui/react-components";
import KeyboardShortcutHelp from "../KeyboardShortcutHelp";
import { BUILDING_VALIDATION_SHORTCUTS } from "../keyboardShortcuts";

const LABEL_OPTIONS = [
{ value: "Damaged", label: "Damaged (1)", color: "#C50F1F" },
Expand Down Expand Up @@ -143,6 +145,7 @@ const BuildingValidationRightPanel = ({
setShowFill,
showPostImagery,
setShowPostImagery,
hasPreImagery,
hasPostImagery,
}) => {
const styles = useStyles();
Expand Down Expand Up @@ -202,7 +205,13 @@ const BuildingValidationRightPanel = ({
onChange={(_e, data) => setShowFill(!!data.checked)}
/>
<Switch
label="Show post-event imagery"
label={
showPostImagery
? "Imagery: Post event"
: hasPreImagery
? "Imagery: Pre event"
: "Imagery: Basemap"
}
checked={showPostImagery}
onChange={(_e, data) => setShowPostImagery(!!data.checked)}
disabled={!hasPostImagery}
Expand Down Expand Up @@ -287,13 +296,15 @@ const BuildingValidationRightPanel = ({

{/* Legend */}
<div className={styles.legend}>
<div className={styles.legendTitle}>Legend · Hotkeys: 1 / 2 / 3 · ← →</div>
<div className={styles.legendTitle}>Legend</div>
<div><span style={{ color: "#BDBDBD" }}>■</span> Unlabeled</div>
<div><span style={{ color: "#C50F1F" }}>■</span> Damaged</div>
<div><span style={{ color: "#107C10" }}>■</span> Not Damaged</div>
<div><span style={{ color: "#4D4D4D" }}>■</span> Unknown</div>
</div>

<KeyboardShortcutHelp shortcuts={BUILDING_VALIDATION_SHORTCUTS} />

{/* Actions */}
<div className={styles.actions} style={{ display: "flex", flexDirection: "column", gap: 8 }}>
<Button
Expand Down Expand Up @@ -335,6 +346,7 @@ BuildingValidationRightPanel.propTypes = {
setShowFill: PropTypes.func.isRequired,
showPostImagery: PropTypes.bool.isRequired,
setShowPostImagery: PropTypes.func.isRequired,
hasPreImagery: PropTypes.bool,
hasPostImagery: PropTypes.bool,
};

Expand Down
2 changes: 1 addition & 1 deletion ui/src/Components/HelpDocs/HelpDocsLabeling.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ const HelpDocsLabeling = ({ anchor }) => {
<li><b>Reset Controls:</b> Resets all sliders to their default values.</li>
</ul>
<p className='mt-4 mt-lg-0'>
<b>Imagery toggle:</b> Click on the toggle to switch between post event and pre event imagery. If you did not upload pre event imagery, the tool will default to Azure Basemap. You can also use the keyboard shortcut - Ctrl+Alt+c
<b>Imagery toggle:</b> Click the toggle to switch between post-event and pre-event imagery. If you did not upload pre-event imagery, the tool uses Azure Basemap. Press <kbd>A</kbd> for pre-event/basemap or <kbd>D</kbd> for post-event imagery.
<br /><br />
Use these controls to optimize the map view for your labeling tasks or analysis needs.
</p>
Expand Down
4 changes: 4 additions & 0 deletions ui/src/Components/HelpDocs/HelpDocsResults.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ const HelpDocsModelTraining = ({ anchor }) => {
<h2 className=''>Built-in Visualizer</h2>

<p>This opens a damage visualizer tool within HASTE. This is useful for quickly visualizing damage predictions, comparing them with pre-event imagery and for sharing these results via screenshots </p>
<p>
Use <kbd>A</kbd>, <kbd>S</kbd>, and <kbd>D</kbd> to move the imagery
swipe divider left, to an even split, or right.
</p>

<img src={resultsVisualizerImage} alt="Visualizer" className="img-fluid pe-5 pt-4 pb-4" />

Expand Down
Loading
Loading