<b>Saving and export</b>

Export writes the <i>visible range</i> of every plotted trace to a file: NumPy <tt>.npy</tt>,
<tt>.csv</tt>, or <b>MDF 3.30</b> (<tt>.mf3</tt> or <tt>.mdf</tt>), chosen by the extension you
type.

<b>How to reach it</b>

<b>Export visible range…</b> in the overflow menu, or <tt>Ctrl+E</tt>. A file chooser asks where;
the format follows the path's extension.

<b>Worth knowing</b>

• The table is collected at the moment you click, not when the chooser returns. A live view keeps
  scrolling while a dialog is up, so a late collection would write a window you never saw.
• The rows are the <b>stored samples</b>, never the LOD buckets the plot draws from. A row count
  far below the span times the stored rate means something cut the table from the pyramid.
• The stored rate is not always the wire rate. A window long enough to need decimation is stored
  averaged at a lower rate, and the export carries <i>that</i> — read the status bar's ⓘ popover
  for the figure before trusting a sample count.
• Two time columns. <tt>time</tt> is the display timeline — negative ages ending at 0 while
  streaming, offsets from the trigger edge while an event is held — so it is the x you read a
  value at on screen. <tt>abs_seconds</tt> is the source's own clock for the same sample, which
  is what lets two exports taken in different modes line up. Both are strictly increasing and
  evenly spaced; duplicate or backwards stamps would mean the file held two clocks.
• An export taken <i>mid-capture</i> writes the partly filled window that is on screen, which is
  shorter than the event span. Export outside a capture if you want the whole event.
• <b>MDF</b> exists for handing a window to another tool, and its shape follows the contract that
  reader uses: one channel group, every channel record-interleaved, the master channel as the x
  axis and the unit in the channel metadata. So there the <b>master is <tt>abs_seconds</tt></b>,
  named <tt>time</tt> — the clock that is the same in every display mode — and the display axis
  goes out beside it as an ordinary channel, <tt>time_relative</tt>. Both are seconds; each signal
  carries the source's own unit. That is also what <b>ScryLab</b> reads: channel name → signal
  name, master → x axis, unit → the signal's unit.

<b>Example</b>

A 2 s window at 10 kS/s over 3 traces writes 20001 rows and 5 columns
(<tt>time</tt>, <tt>abs_seconds</tt>, three signals). The <tt>.npy</tt> is
<tt>64·⌈(10+len(header)+1)/64⌉ + rows·(16 + 4·cols)</tt> bytes. Read it back with
<tt>pd.DataFrame(np.load(path))</tt>. The <tt>.mf3</tt> is bigger — a block per channel plus a
comment — <tt>272 + comment + rows·record + 28 + channels·274 + 30</tt> bytes, with
<tt>record = 16 + 4·cols</tt> and <tt>channels = cols + 2</tt> for the master and the relative
axis. Read that one back with <tt>asammdf.MDF(path)</tt> or in ScryLab.
