Skip to content

Commit b311086

Browse files
authored
Merge pull request #261 from fieldsoftheworld/threshold-scaling
Scale confidence values differently (0-100 instead of 0-58)
2 parents 7ea0e0a + 4a9aae7 commit b311086

7 files changed

Lines changed: 59 additions & 23 deletions

File tree

src/components/GlobalDataPanel.vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,12 @@ const handleLocationSelected = (place: PlaceResult) => {
5757
<v-radio label="2024" :value="2024"></v-radio>
5858
<v-radio label="2025" :value="2025"></v-radio>
5959
</v-radio-group>
60-
<h3 class="group">Confidence Threshold: {{ (settings.threshold * 100).toFixed(0) }}%</h3>
60+
<h3 class="group">Confidence Threshold: {{ settings.threshold }}%</h3>
6161
<v-slider
6262
v-model.number="settings.threshold"
6363
:min="0"
64-
:max="1"
65-
:step="0.01"
64+
:max="100"
65+
:step="1"
6666
color="teal"
6767
track-color="grey-darken-2"
6868
thumb-color="teal"

src/components/MapLegend.vue

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,11 @@ const legendThresholdPct = computed(() => {
4545
const s = legendStops.value
4646
const threshold = settings.value.threshold
4747
const n = s.length - 1
48+
const labelValues = s.map((stop) => Number(stop.label))
4849
for (let i = 0; i < n; i++) {
49-
if (threshold <= s[i].value) return (i / n) * 100
50-
if (threshold <= s[i + 1].value) {
51-
const frac = (threshold - s[i].value) / (s[i + 1].value - s[i].value)
50+
if (threshold <= labelValues[i]) return (i / n) * 100
51+
if (threshold <= labelValues[i + 1]) {
52+
const frac = (threshold - labelValues[i]) / (labelValues[i + 1] - labelValues[i])
5253
return ((i + frac) / n) * 100
5354
}
5455
}
@@ -94,7 +95,20 @@ const legendThresholdPct = computed(() => {
9495
></div>
9596
</div>
9697
<div class="legend-labels">
97-
<span v-for="(stop, i) in legendStops" :key="i">{{ stop.label }}</span>
98+
<span
99+
v-for="(stop, i) in legendStops"
100+
:key="i"
101+
:style="{
102+
left: (i / (legendStops.length - 1)) * 100 + '%',
103+
transform:
104+
i === 0
105+
? 'none'
106+
: i === legendStops.length - 1
107+
? 'translateX(-100%)'
108+
: 'translateX(-50%)',
109+
}"
110+
>{{ stop.label }}</span
111+
>
98112
</div>
99113
</div>
100114
</template>
@@ -146,13 +160,17 @@ const legendThresholdPct = computed(() => {
146160
}
147161
148162
.legend-labels {
149-
display: flex;
150-
justify-content: space-between;
163+
position: relative;
164+
height: 1.2em;
151165
margin-top: 0.2em;
152166
font-size: 0.7rem;
153167
opacity: 0.85;
154168
}
155169
170+
.legend-labels span {
171+
position: absolute;
172+
}
173+
156174
.legend-item {
157175
display: flex;
158176
align-items: center;

src/composables/usePermalink.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type Map from 'ol/Map'
33
import useAreaOfInterest from './useAreaOfInterest'
44
import useMap from './useMap'
55
import useSearch from './useSearch'
6-
import useSettings from './useSettings'
6+
import useSettings, { defaultThreshold } from './useSettings'
77
import { fromLonLat, toLonLat, transformExtent } from 'ol/proj'
88
import { type Extent } from 'ol/extent'
99
import { type Coordinate } from 'ol/coordinate'
@@ -58,7 +58,7 @@ export default function usePermalink() {
5858
zoom: 2,
5959
center: [0, 0],
6060
year: 2025,
61-
threshold: 0.4,
61+
threshold: defaultThreshold,
6262
fieldBoundariesOpacity: 90,
6363
}
6464

@@ -180,8 +180,10 @@ export default function usePermalink() {
180180

181181
for (const part of keyValueParts) {
182182
if (part.startsWith('threshold:')) {
183-
const val = parseFloat(part.substring(10))
184-
if (!isNaN(val)) result.threshold = val
183+
const val = parseInt(part.substring(10), 10)
184+
if (!isNaN(val)) {
185+
result.threshold = val
186+
}
185187
} else if (part.startsWith('year:')) {
186188
const year = parseInt(part.substring(5), 10)
187189
if (!isNaN(year)) result.year = year
@@ -286,7 +288,7 @@ export default function usePermalink() {
286288
}
287289
} else {
288290
// Global mode
289-
hashParts.push(`threshold:${settings.value.threshold}`)
291+
hashParts.push(`threshold:${Math.round(settings.value.threshold)}`)
290292
if (settings.value.year) {
291293
hashParts.push(`year:${settings.value.year}`)
292294
}

src/composables/useSettings.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ const availableModes: { id: string; label: string }[] = [
4545

4646
const availableModels = shallowRef<ModelInfo[]>([])
4747

48+
export const defaultThreshold = 70
49+
4850
// Default settings
4951
const defaultSettings: Settings = {
5052
autoSceneSelection: true,
@@ -57,7 +59,7 @@ const defaultSettings: Settings = {
5759
model: '',
5860
expertMode: false,
5961
mode: defaultMode,
60-
threshold: 0.4,
62+
threshold: defaultThreshold,
6163
fieldBoundariesOpacity: 90,
6264
}
6365

@@ -86,6 +88,9 @@ const loadSettingsFromStorage = (): Settings => {
8688
const stored = localStorage.getItem('ftw-search-settings')
8789
if (stored) {
8890
const parsed = JSON.parse(stored)
91+
if (parsed.threshold !== undefined) {
92+
parsed.threshold = Math.round(parsed.threshold)
93+
}
8994
return Object.assign(structuredClone(defaultSettings), parsed) as Settings
9095
}
9196

src/layers/Global-Overview-Layers.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
GLOBAL_DATA_MAP_FIELD_START_ZOOM_LEVEL,
77
type Settings,
88
} from '../composables/useSettings'
9-
import { areaColorScale, type ColorStop } from './color-scales'
9+
import { areaColorScale, thresholdToRaw, type ColorStop } from './color-scales'
1010

1111
const ALPHA = 'aa'
1212

@@ -24,7 +24,7 @@ const overviewStyle = (settings: Settings) => {
2424
'case',
2525
['<=', ['band', 1], 0],
2626
'#00000000', // no area data
27-
['<=', ['band', 2], settings.threshold],
27+
['<=', ['band', 2], thresholdToRaw(settings.threshold)],
2828
'#00000000', // confidence below threshold
2929
buildAreaInterpolation(areaColorScale), // show area colors
3030
],

src/layers/Global-Predictions-Layer.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
get_global_pmtiles_url,
77
type Settings,
88
} from '../composables/useSettings'
9+
import { thresholdToRaw } from './color-scales'
910

1011
export interface GlobalPredictionsController {
1112
layer: TileLayer<ImageTileSource>
@@ -21,7 +22,7 @@ export function createGlobalPredictionsLayer(settings: Settings): GlobalPredicti
2122
worker.postMessage({
2223
action: 'init',
2324
url: get_global_pmtiles_url(settings.year),
24-
threshold: settings.threshold,
25+
threshold: thresholdToRaw(settings.threshold),
2526
})
2627

2728
let revision = 0
@@ -101,7 +102,10 @@ export function createGlobalPredictionsLayer(settings: Settings): GlobalPredicti
101102
return {
102103
layer,
103104
update(newSettings: Settings) {
104-
worker.postMessage({ action: 'updateThreshold', threshold: newSettings.threshold })
105+
worker.postMessage({
106+
action: 'updateThreshold',
107+
threshold: thresholdToRaw(newSettings.threshold),
108+
})
105109
revision++
106110
;(source as any).setKey(`${GLOBAL_DATA_PMTILES_THRESHOLD_METRIC}-${revision}`)
107111
},

src/layers/color-scales.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,19 @@ export const areaColorScale: ColorStop[] = [
2121
{ value: 1, color: '#00ff00', label: '100' },
2222
]
2323

24+
const CONFIDENCE_MAX = 0.578178 // before scaling, ratio [0-1]
25+
26+
/** Convert a UI percentage threshold (0–100) to the raw internal confidence value. */
27+
export function thresholdToRaw(pct: number): number {
28+
return (pct / 100) * CONFIDENCE_MAX
29+
}
30+
2431
export const confidenceColorScale: ColorStop[] = [
2532
{ value: 0, color: '#d7191c', label: '0' },
26-
{ value: 0.4, color: '#fec379', label: '40' },
27-
{ value: 0.45, color: '#f3fabb', label: '45' },
28-
{ value: 0.5, color: '#cfecb0', label: '50' },
29-
{ value: 0.58, color: '#33a02c', label: '58' },
33+
{ value: thresholdToRaw(70), color: '#fec379', label: '70' },
34+
{ value: thresholdToRaw(80), color: '#f3fabb', label: '80' },
35+
{ value: thresholdToRaw(90), color: '#cfecb0', label: '90' },
36+
{ value: CONFIDENCE_MAX, color: '#33a02c', label: '100' },
3037
]
3138

3239
const LUT_SIZE = 256

0 commit comments

Comments
 (0)