fieldbox.eda
site field_site_01 / box box_0002computed in browser, no backend

A field sensor box went quiet three times in one day.This page finds it, live.

The fieldbox-sensor-edapipeline runs quality checks, IQR anomaly detection, correlation analysis, and a plain English narrator over raw IoT telemetry. Every number below is recomputed in your browser from the repo's real 42,712 readings. Move any control and the analysis, and its prose, change with it.

Sensors

5

Readings

42,712

Span

24.00h

Avg quality

85.0/100

Anomalies

53

Uptime

99.41%

All five sensors, full 24 hours

each trace scaled to its own range

Accel X
Accel Y
Gas
Pressure
Temperature

Replay200x

--:--:--UTC

start with the sensors

01 / the fleet

Five sensors, one box, one day

Every card is recomputed from the raw readings as you change any control on this page. Select one to drive the anomaly lab and the narrator below. The distribution strip is a real histogram of that sensor's values, which is where the quantisation becomes visible: the accelerometers resolve to a handful of discrete levels, while pressure and gas move continuously.

Fleet roll-up

85.0/100

mean quality across sensors

readings
42,712
anomalies
53
flagged sensors
2 of 5
downtime
507s
uptime
99.413%

02 / detector

Anomaly lab

IQR flags a reading when it falls outside q1 - k*iqr or q3 + k*iqr. Z-score compares distance from the mean in population standard deviations, which is the convention the repo's numpy call uses. Drag k and watch the fences and the counts move across all 42,712 readings.

Temperature/IQR k=3.0

fence [65.294, 73.736]

20.00030.00040.00050.00060.00070.00000:0004:0007:5911:5915:5919:5923:59
hover the chart to inspect a readinggreen band = accepted, dashed = fence
config.json default

method

quartiles from 8,543 sorted values

q168.912
q370.118
iqr1.206
mean69.448
std1.991

flagged per sensor

At the default k=3.0 the detector flags 53readings. Temperature's are all the identical value 21.50, a stuck reading rather than a real excursion.

03 / scoring

What a quality score actually measures

The pipeline starts every sensor at 100 and subtracts: 10 if any value is missing, 10 if any timestamp repeats, and 5 for each data gap. This dataset has zero missing values and zero duplicate timestamps, so the entire deduction comes from gaps, which means the score is really a function of where you set the gap threshold. Push it past the longest outage and every sensor is suddenly perfect.
config.json default

fleet average

85.0/100

Deducting for 3 gap(s) per sensor above 30s.

Accel X

85/100

100 base-15 3 data gaps above 30s

Accel Y

85/100

100 base-15 3 data gaps above 30s

Gas

85/100

100 base-15 3 data gaps above 30s

Pressure

85/100

100 base-15 3 data gaps above 30s

Temperature

85/100

100 base-15 3 data gaps above 30s

missing

0

duplicates

0

gaps found

15

downtime

507s

04 / uptime

Three blackouts, all five sensors, same second

Each ribbon is one sensor across the full capture. Amber marks where the interval between consecutive readings exceeded 30s. Select an outage to zoom into the raw samples on either side of it.
Accel X
3 gaps
Accel Y
3 gaps
Gas
3 gaps
Pressure
3 gaps
Temperature
3 gaps
00040812162024

06:19:27 to 06:20:55 UTC

88s dark5 of 5 sensors

Accel X
Accel Y
Gas
Pressure
Temperature
06:17:57outage06:22:25

Each dot is one real reading. The hole appears in every row at the same instant, which is the signature of the box dropping off, not of a single failing sensor.

fleet uptime

99.413%

507s dark out of 86386s observed

outages (3)

05 / coupling

Which sensors move together

Pearson correlation over 12,349 aligned timestamps. The strongest relationship in this box is Accel Y vs Pressure at -0.768, which is real physical coupling rather than noise.
Accel XAccel YGasPressureTemperature
Accel X
Accel Y
Gas
Pressure
Temperature
-1 inverse+1 directclick any cell for its scatter

PressurevsAccel Y

r = -0.768

Pressure (psi)Accel Y (g)
Pressure range
14.355 to 14.425
Accel Y range
0.1874 to 0.1915
points plotted
2,600 of 12,349

r uses every aligned row. The scatter is evenly subsampled so the plot stays light.

06 / prose

The narrator, regenerating live

narrator.py turns the JSON report into plain English through a cascade of thresholds: coefficient of variation picks the stability wording, jitter picks the sampling wording, the score picks the quality wording, and anomaly percentage picks the closing sentence. Every paragraph below is generated by that same cascade, right now, from your current settings.
generated withmethod=iqr k=3.0 gap=30smatches config.json defaults (iqr, k=3.0, 30s)

Acceleration_X

cv < 1jitter highscore >= 80none

Acceleration_X recorded 8,542 data points over 24.0 hours. The signal is extremely stable with near-zero variance, ranging from -0.9148 to -0.9111 (mean -0.9131, std 0.0006). Sampling is irregular, mean interval 10.1s but jitter is high (3.3s std), which may indicate connectivity or buffering issues. Data quality is good (85/100) with minor issues: 3 data gap(s). The longest data gap spans 4.2 minutes (from 2026-01-18T18:03:59 to 2026-01-18T18:08:10). No anomalies were detected in this sensor.

Acceleration_Y

cv < 1jitter highscore >= 80none

Acceleration_Y recorded 8,542 data points over 24.0 hours. The signal is extremely stable with near-zero variance, ranging from 0.1874 to 0.1915 (mean 0.1895, std 0.0008). Sampling is irregular, mean interval 10.1s but jitter is high (3.3s std), which may indicate connectivity or buffering issues. Data quality is good (85/100) with minor issues: 3 data gap(s). The longest data gap spans 4.2 minutes (from 2026-01-18T18:04:00 to 2026-01-18T18:08:10). No anomalies were detected in this sensor.

Gas

cv < 5jitter highscore >= 80< 1%

Gas recorded 8,542 data points over 24.0 hours. The signal is relatively stable with minor fluctuations, ranging from 0.1510 to 0.2320 (mean 0.1580, std 0.0026). Sampling is irregular, mean interval 10.1s but jitter is high (3.3s std), which may indicate connectivity or buffering issues. Data quality is good (85/100) with minor issues: 3 data gap(s). The longest data gap spans 4.2 minutes (from 2026-01-18T18:03:59 to 2026-01-18T18:08:10). 40 anomalies flagged (0.47% of readings), a small number that likely represents isolated spikes rather than a systemic issue.

Pressure

cv < 1jitter highscore >= 80none

Pressure recorded 8,543 data points over 24.0 hours. The signal is extremely stable with near-zero variance, ranging from 14.3549 to 14.4249 (mean 14.3999, std 0.0228). Sampling is irregular, mean interval 10.1s but jitter is high (3.3s std), which may indicate connectivity or buffering issues. Data quality is good (85/100) with minor issues: 3 data gap(s). The longest data gap spans 4.2 minutes (from 2026-01-18T18:03:59 to 2026-01-18T18:08:10). No anomalies were detected in this sensor.

Temperature

cv < 5jitter highscore >= 80< 1%

Temperature recorded 8,543 data points over 24.0 hours. The signal is relatively stable with minor fluctuations, ranging from 21.5000 to 70.4600 (mean 69.4483, std 1.9905). Sampling is irregular, mean interval 10.1s but jitter is high (3.3s std), which may indicate connectivity or buffering issues. Data quality is good (85/100) with minor issues: 3 data gap(s). The longest data gap spans 4.2 minutes (from 2026-01-18T18:03:59 to 2026-01-18T18:08:10). 13 anomalies flagged (0.15% of readings), a small number that likely represents isolated spikes rather than a systemic issue.

Overall assessment

Most sensors are healthy. A total of 53 anomalies were flagged, review the anomaly plots to determine if intervention is needed.

The committed README shows a sample narrative where Temperature ranges 70.0625 to 70.3125 with no anomalies and a perfect score. Recomputed from the dataset in this repo, Temperature actually dips to 21.50 thirteen times and scores 85/100. The sample in the README is stale relative to its own data, and the figures on this page come from the data.

07 / provenance

Everything here is a port, not a mock

The repo is a Python pipeline driven by shell scripts: ./scripts/run_analysis.sh chains four modules over the CSVs in data/. This page reimplements the analytical stages in TypeScript and runs them against the same committed dataset, in the browser, with no server involved.
01

Formatter

data_formatter.py

Explodes ISO timestamps into date, time, hour and weekday columns.

Timestamps are decoded to 1ms precision for every chart on this page.

02

Analyzer

eda_template.py

SensorAnalyzer: quality checks, IQR or z-score anomalies, correlation matrix.

Powers the anomaly lab, the quality scorer, and the correlation matrix.

03

Reporter

report_converter.py

Turns the JSON report into Markdown and per topic CSV tables.

The stat blocks and score breakdowns mirror those tables.

04

Narrator

narrator.py

Threshold cascade that writes one plain English paragraph per sensor.

Ported branch for branch into the narrator section.

how the data gets here

The five raw CSVs total 2.1MB, which is too much to ship as text. Across all 42,712 readings there are only 558 distinct values, because the hardware quantises heavily: Acceleration X resolves to just 16 discrete levels over the whole day. So each sensor ships a dictionary of its unique values at full float precision plus a compact index string, which is about 99KB gzipped for the entire dataset and keeps every recomputed statistic bit identical to the pipeline's pandas output.

raw CSVs

2.1 MB

shipped, gzipped

99 KB

distinct values

558

aligned rows

12,349