Documentation
¶
Overview ¶
Package plot reads sequences of numbers and draws them as line graphs.
It is a Go port of https://github.com/annacrombie/plot (MIT, Stone Tickle). This file is the data-processing half: the transformations that run over the numbers before anything is drawn, which is what separates plot from a plain graph renderer. A monotonic counter — bytes on an interface, say — is a ramp until Rate turns it into a rate.
The processors are streaming by construction. Each one is handed whatever samples have arrived so far, emits what it can, and reports how many it consumed; the rest stays buffered for the next read. That is what lets the same code serve a file read once and a counter polled forever.
Index ¶
Constants ¶
const BufferSize = 128
BufferSize bounds a processor's window, matching PLOT_DBUF_SIZE in the original. It is not a limit on how much data can be plotted — samples stream through — only on how far back a single processor may look.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Block ¶
type Block struct {
// contains filtered or unexported fields
}
Block averages every n samples into one, which is the plain decimation used to make a long series fit a short plot.
Mid-stream it emits a block only once a sample beyond that block has arrived, as the original does — its loop runs while i+n < len rather than <=. At the end of the stream the samples still held are emitted by Flush, so nothing is lost; in the original they are dropped, which costs a series of ten with avg:5 half its output.
type Cumulative ¶
type Cumulative struct {
// contains filtered or unexported fields
}
Cumulative is the running average of everything seen so far. Unlike Simple it never forgets, so it settles rather than tracks.
func NewCumulative ¶
func NewCumulative() *Cumulative
NewCumulative returns a Cumulative moving average.
type Flusher ¶
Flusher is a Proc that may still be holding samples it would only emit once more arrived. Flush is called when the stream has ended and no more will: whatever is held is all there will ever be, so it is emitted rather than dropped. in is the samples the processor left unconsumed.
type Pipeline ¶
type Pipeline struct {
// contains filtered or unexported fields
}
Pipeline is a chain of processors. The output of each is the input of the next, so "avg:5|roc:5" first averages every five samples into one and then reports the rate of change of those averages.
A Pipeline holds the buffered tail of every stage, so like the processors in it, one belongs to a single stream.
func NewPipeline ¶
NewPipeline chains the given processors.
func ParsePipeline ¶
ParsePipeline reads the pipeline syntax used on the command line: processors separated by "|", each optionally taking an argument after ":".
avg:5|roc:5
The names are those of the original, so a command line written for C plot means the same thing here.
func (*Pipeline) Flush ¶
Flush drains every stage, for when the stream has ended. A stage holding a window that will never fill emits what it has rather than losing it, and each stage's last output still passes through the ones after it.
Call it once, at the end. A pipeline that has been flushed can still be given more samples, but the stages that held a partial window have started over.
type Proc ¶
Proc transforms a stream of samples.
Process appends its output to dst and returns the extended slice along with the number of samples it consumed from the front of in. Samples left unconsumed are offered again, with more appended, on the next call — so a processor that needs a longer window than it has been given may consume nothing and emit nothing, and that is not an error.
Implementations hold their own state, so a Proc belongs to one stream and cannot be shared between two.
type Rate ¶
type Rate struct {
// contains filtered or unexported fields
}
Rate reports how fast a value is changing rather than what it is: each sample becomes (value - previous) / interval.
This is the one that makes a counter readable. Interface byte counts, uptime, anything monotonic, plotted raw, is a line going up and to the right and says nothing about the traffic; through Rate it is throughput.
The first sample has nothing to compare against, so it comes out as zero rather than as a spike from nowhere.
type Simple ¶
type Simple struct {
// contains filtered or unexported fields
}
Simple is a simple moving average over n samples — a boxcar filter, for taking the noise out of a signal without moving its features along the axis.
n must be odd, so that the window has a middle sample to be centered on.
While the window is still filling it emits the average of what it has, but only once it holds more than half a window. Before that the average would say more about how recently the stream started than about the signal.
This differs from the original deliberately. C plot divides the warm-up sum by one less than the number of samples in it, so a constant signal comes out as a spike that decays into the true value — feeding it a flat series of 10 with a window of 5 gives 15, 13.33, 12.5, 10. Here the divisor is the count, so a flat signal is flat. The emission schedule is unchanged: output still begins once the window is more than half full.
func (*Simple) Process ¶
Process consumes everything it is given, keeping the window in its own state rather than in the caller's buffer.
The original keeps a running sum but leaves the samples for the caller to re-offer, which double-counts them if a window spans more than one read. It does not show up there because a read usually fills the whole buffer, so the window fills in one go — but it makes the result depend on how the input happened to be chopped up, which is exactly what a stream cannot promise.
type Source ¶
type Source struct {
// Name is what the source was opened as, for error messages.
Name string
// Rewind makes the source start over when it reaches the end, instead of
// stopping there.
//
// This is what makes polling a counter work. A file under /sys holds one
// number that changes; it does not grow. Reading to the end and waiting
// for more, which is what following a log means, would wait forever — the
// value has to be read again from the top each time.
Rewind bool
// Infinite keeps the source open when it reaches the end, so that data
// appended later is picked up — following a log, as tail -f does.
//
// It is separate from Rewind because the two answer different questions. A
// log grows, so following it means waiting at the end; a counter changes in
// place, so following it means going back to the start. The original has
// both for the same reason: -f sets this, and :r sets Rewind.
Infinite bool
// contains filtered or unexported fields
}
Source is one stream of numbers: somewhere to read from, the flags that say how, and the pipeline the numbers go through on the way out.
func OpenSource ¶
OpenSource opens spec, which is a filename optionally followed by flags:
/sys/class/net/eno1/statistics/rx_bytes:r
The filename "-" is standard input. The only flag is "r" for rewind; the original also has "n" for a nonblocking open, which is not needed here because a poll that finds nothing simply reads nothing.
The pipeline may be nil, in which case numbers pass through untouched.
func (*Source) Done ¶
Done reports whether the source has ended and will produce nothing more. A rewinding source is never done.
func (*Source) Pipeline ¶
Pipeline is the processing the numbers go through on their way out. It is never nil: a source with no pipeline has an empty one.
type Splitter ¶
type Splitter struct {
// contains filtered or unexported fields
}
Splitter turns a byte stream into numbers, one chunk at a time.
The original's parser is deliberately lenient: it scans for something that could start a number, tries to read one from there, and skips the byte if that fails. That is what lets plot be pointed at a log line, a CSV or /proc/loadavg without anything in between — the numbers are picked out of whatever the text happens to be.
A number split across two reads is the reason this is a type rather than a function. The tail of a chunk may be half of a number whose other half has not arrived, so it is held until the next Write says how it ends.
func (*Splitter) Flush ¶
Flush emits a number left at the end of the stream. Call it at EOF, and only then: a file often ends without a trailing newline, and that last number is as real as any other.
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
plot-go
command
Command plot-go reads numbers and draws them as a line graph.
|
Command plot-go reads numbers and draws them as a line graph. |
|
Command serve is a static file server for the demo page, so the wasm can be loaded over http rather than file:// (which blocks instantiateStreaming).
|
Command serve is a static file server for the demo page, so the wasm can be loaded over http rather than file:// (which blocks instantiateStreaming). |
|
Command web is the plot-go demo: live counters, plotted as they arrive.
|
Command web is the plot-go demo: live counters, plotted as they arrive. |
