Skip to content

Reading series

Series data comes in several shapes. Pick the cheapest one that answers your question:

You need RPC Returns
A few statistics per series ListSeriesSummaries first, last, min, max, mean, … per series
Every point ListFloatSeries raw steps, values and timestamps
A chart ListFloatSeriesBuckets a fixed number of buckets per series, by step
A chart against wall-clock time ListFloatSeriesTimestampBuckets buckets by timestamp
Histograms ListHistogramSeries bin edges and counts or densities per step
Scatter plots ListScatterSeries the point cloud per step

All of them take workspace, project, a list of runNames, and series queries (or summary queries) selecting series by metric, scale and labels. An empty run or query list returns an empty response.

ListSeriesSummaries returns pre-computed statistics without touching the points — the fastest way to fill a table:

{
"workspace": "my-workspace",
"project": "vision",
"runNames": ["resnet50-lr3e-4", "resnet50-lr1e-4"],
"summaryQueries": ["train/loss():last,min", "eval/accuracy(filter=(split=\"val\")):max"]
}

The response has one entry per run, each listing every matching series with its full definition and a SeriesSummary. A query matching several series returns one row per series — unlike ListRuns, which combines them. limit caps the series per run, and paging uses a resume token.

ListFloatSeries returns points exactly as logged:

{
"workspace": "my-workspace",
"project": "vision",
"runNames": ["resnet50-lr3e-4"],
"seriesQueries": ["train/loss(filter=(gpu=\"0\"))"],
"includeTimestamps": true,
"stepSelection": {"stepRange": {"fromStep": "10000", "toStep": "20000"}}
}

Points are columnar — steps[i], values[i] and, when requested, timestampMillis[i] form one point — in ascending step order, grouped by run and then by series.

Step selection picks which points of each series to return:

Selection Returns
stepRange Steps from fromStep to toStep, inclusive; either end may be left open.
perSeriesFromTheBeginning The first N points of each series.
perSeriesFromTheEnd The last N points of each series — for example 1 for each series’ latest value.

Omit it to get everything.

Paging. maxPointsPerPage caps the points in one response across all series (default 1,000,000, at most 10,000,000; approximate). When more remain, the response carries resumeToken: repeat the identical request with it until it no longer comes back. Pages run depth-first — all of the first run’s series, then the next run’s.

Forks. A forked run inherits its parent’s points up to the fork step. Set includeInherited to get them as part of the child’s series.

Transformations. ListFloatSeries alone accepts | group_by(…) pipelines, which merge series at query time.

A chart cannot show a million points, and the network should not carry them. ListFloatSeriesBuckets divides the common step range of all matched series into bucketsCount buckets (default 1,000, at most 5,000) and returns the mean, count, minimum and maximum of each:

{
"workspace": "my-workspace",
"project": "vision",
"runNames": ["resnet50-lr3e-4", "resnet50-lr1e-4"],
"seriesQueries": ["train/loss()"],
"bucketsCount": "800",
"useColumnarOutput": true
}

Set useColumnarOutput; the non-columnar runPoints layout is kept only for older clients. The columnar runSeries (RunSeriesBuckets) looks like this:

{
"runSeries": {
"firstStep": "0",
"lastStep": "79999",
"stepsPerBucket": 100.0,
"bucketsCount": "800",
"series": [{
"run": "resnet50-lr3e-4",
"definition": {"regular": {"metricName": "train/loss", "scale": "ML_STEP"}},
"bucketIndexes": ["0", "1", "2", "5"],
"yValues": [2.1, 1.8, 1.6, 1.2],
"counts": ["100", "100", "100", "37"],
"minValues": [1.9, 1.7, 1.5, 1.1],
"maxValues": [2.4, 1.9, 1.7, 1.3]
}]
}
}
  • Every series shares the same buckets. Bucket i starts at step firstStep + floor(i × stepsPerBucket).
  • Empty buckets are left out: bucketIndexes lists the buckets that have data, and every other array is aligned with it. Above, buckets 3 and 4 were empty.
  • When each bucket holds a single step (stepsPerBucket is 1), counts, minValues and maxValues are omitted — they would repeat yValues.
  • NaN and infinite points never contribute to the statistics. bucketsWithNans, bucketsWithInfs and bucketsWithNegInfs list the buckets that contained them, so a chart can mark them.
  • If every series is shorter than bucketsCount steps, fewer buckets are returned.

When requesting many series, maxBucketsAcrossSeries caps the total: each series then gets min(bucketsCount, maxBucketsAcrossSeries / seriesCount) buckets (at least one). maxBucketsPerPage caps one response, with paging by resume token as for raw points.

ListFloatSeriesTimestampBuckets buckets by timestamp instead of step, for “loss against wall-clock time” charts. It takes a timestampRange (milliseconds) instead of a step selection, and always answers in the columnar layout, with millisPerBucket in place of stepsPerBucket and each bucket’s lastSteps.

With useRelativeTimestamp, every timestamp — in the request and the response — counts milliseconds since each run’s start, which lines up runs started at different times. Otherwise timestamps are milliseconds since the epoch and all runs share one timeline starting at the earliest run’s start.

ListHistogramSeries returns histogram series, counting and density alike, as HistogramSeriesPoints:

  • steps[i], bins[i] (with either counts or densities) and edgesIdx[i] describe the histogram at one step.
  • Bin edges are pooled: edgesPool[edgesIdx[i]] holds the edges of point i. Most runs use one binning throughout, so the pool usually has a single entry.
  • mins, maxs, sums and sumsOfSquares hold each point’s moments — exact when the logger sent them, approximated from the bins otherwise. For density histograms they are normalized: sums[i] is the mean.

Histogram points are heavy, so pages are smaller: maxPointsPerPage defaults to 1,000 (at most 10,000). Set includeSeriesExtent to also get each series’ first and last step and approximate point count — enough to draw a step slider from a single perSeriesFromTheEnd: 1 request, then fetch the steps the user picks.

To chart a histogram series as a line — its median, say — query it on the float endpoints with value_kind=histogram, value_reducer=quantile(0.5).

ListScatterSeries returns 2D and 3D scatter series as ScatterSeriesPoints: steps[i] and pointSets[i], where each point set holds parallel xs, ys and, for 3D, zs arrays. An empty point set is a logged step with no points. Axis titles are in the series definition’s metadataLabels (xt, yt, zt).

Paging counts individual coordinates: maxDataPointsPerPage defaults to 100,000 (at most 1,000,000). A step’s point set is never split across pages, so one very large step may exceed the budget. includeSeriesExtent works as for histograms.

Series pages can be tens of megabytes. Over gRPC, raise your client’s maximum receive message size (the Python SDK uses 128 MiB) or lower the page size.