Skip to content

Analyse a first recording

Question

What does this recording support before I choose a specialised analysis?

What you need

A ClockLab AWD file, timestamped CSV/TSV, BioDare2 elapsed-time table, wide multi-series table, or supported Excel equivalent.

Click path

  1. Choose Load activity data and select one file.
  2. Check the source name, samples, interval, missing percentage, and timestamp gaps.
  3. Set the analysis interval and exclusions.
  4. In Temporal Structure, switch between Actogram and Time series as two views of the same recording. Inspect the activity profile, daily timing, and periodograms too.
  5. Open Workbench for a question-specific analysis.

For a file with several traces, choose Measurement to analyse in the sidebar to name the column used by detailed plots and daily tables. Tick columns in Statistics by trace above the tabs to compare their metrics in each view; the same ticks control the periodogram overlay. Actogram and time-series layer visibility is separate. Both Temporal Structure views have an appearance editor and PNG, SVG, transparent SVG, and individual-layer ZIP downloads; the browser chooses the save location. For category counts such as correct and incorrect runs, set Sum for each column during manual import. In the actogram layout selector, choose Parts of total, then tick those columns in the editor. Their combined bar height is the number of runs; each colour shows its percentage. Separate lanes puts only its ticked traces in distinct vertical lanes.

What success looks like

The top status reads Analysis current, figures agree with the selected interval, and warnings are attached to the result they qualify.

What it does not prove

A clean import does not establish rhythmicity, entrainment, or biological validity.

What gets saved

Use Save project for replay instructions or Export reproducibility bundle for figures and numerical tables.

Analysis explained ยท Importer troubleshooting

File to figure in Python

Run in the directory containing mouse.awd. No server or account is needed.

import circadian_workbench as workbench

recording = workbench.open("mouse.awd")
result = recording.detrend(window_hours=24).compare_periods()
result.plot().save("periods.svg")

The output is .circadian-agent/periods.svg, with companion data/statistics CSVs, JSON evidence and a standalone replay producer. The source remains unchanged. The comparison uses the processed values and its figure states the preceding detrending. result.tables["estimates"] gives the estimates and their units; result.warnings retains failed/refused methods and their reasons. These are software outputs, not proof of a biological rhythm.

Complete numeric-trace example

If hours and values already exist in your measurement workflow, use:

import circadian_workbench as workbench

recording = workbench.trace(
    hours,
    values,
    settings={"period_min_hours": 20, "period_max_hours": 28},
)
result = recording.compare_periods()
result.plot(theme="classic").save("periods.svg")

Motion's analysis.circadian.trace and Auto-Organotypic's auto_organotypic.rhythm.trace expose that same constructor. The scientific settings and figure options therefore have the same meanings at all three entrances. Their older measurement wrappers retain their documented legacy settings; they do not supply defaults for this call.

This synthetic seven-day signal has a 23.5-hour rhythm, a slow baseline and one missing sample. Elapsed hours are not a real calendar clock.

import math
import circadian_workbench as workbench

hours = list(range(168))
values = [20 + 0.02 * hour + 4 * math.cos(2 * math.pi * hour / 23.5)
          for hour in hours]
values[50] = None
trace = workbench.trace(
    hours, values, name="Synthetic cell", value_label="Luminescence",
    value_unit="photons/s",
    settings={"period_min_hours": 21, "period_max_hours": 27,
              "period_hours": 24, "bin_minutes": 60},
)
processed = trace.detrend(window_hours=24)
result = processed.compare_periods(["lomb", "mesa"],
                                  settings={"period_max_hours": 26})
print(result.tables["estimates"])
figure = result.plot(theme="classic", show_grid=False)
saved = figure.save("numeric-periods.svg", root="my-figures")
print(saved.path)

# This fit overrides the per-call 24-hour cycle; it does not change the search.
fixed_fit = processed.cosinor(period_hours=23.5, settings={"period_hours": 24})
print(fixed_fit.measurements["amplitude"].value)

The comparison inherits the 21-hour lower search bound and overrides its upper bound to 26 hours. The cosinor uses the explicitly requested 23.5-hour cycle. Missing samples stay missing and baseline-subtracted negative values are valid. Raw activity files still reject negative activity; those checks are not bypassed.

result.run_record retains the completed settings, processing, inputs and environment. The saved producer verifies those sources and software before recomputing, then checks the scientific result and complete figure definition. Keep the original inputs and recorded environment. Changing an input or upgrading a package is a mismatch, not a request to find a historical result or silently install an older engine.

Complete channel example

Channels are measurements from the same subject, not independent replicates. Here two synthetic reporters share one time grid and differ in phase.

import math
import circadian_workbench as workbench

hours = list(range(168))
reporters = {
    "PER2": [10 + math.cos(2 * math.pi * hour / 24) for hour in hours],
    "BMAL1": [10 + math.cos(2 * math.pi * (hour - 6) / 24) for hour in hours],
}
recording = workbench.channels(hours, reporters, name="Synthetic dual reporter",
                              settings={"period_min_hours": 22, "period_max_hours": 26})
result = recording.compare()
print(result.tables["channels"])
result.plot().save("reporter-comparison.svg")

For genuinely separate oscillators, use workbench.population(hours, traces) instead. Calendar-dependent questions need a file/recording with a real origin; the numeric constructors do not invent one. The command-line question entrance accepts files or the demo, not a numeric-array expression. Python and the registered machine interface accept numeric specifications directly.