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.
Series summaries
Section titled “Series summaries”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.
Raw points
Section titled “Raw points”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.
Buckets for charts
Section titled “Buckets for charts”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
istarts at stepfirstStep + floor(i × stepsPerBucket). - Empty buckets are left out:
bucketIndexeslists 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 (
stepsPerBucketis 1),counts,minValuesandmaxValuesare omitted — they would repeatyValues. - NaN and infinite points never contribute to the statistics.
bucketsWithNans,bucketsWithInfsandbucketsWithNegInfslist the buckets that contained them, so a chart can mark them. - If every series is shorter than
bucketsCountsteps, 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.
Buckets by time
Section titled “Buckets by time”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.
Histograms
Section titled “Histograms”ListHistogramSeries returns histogram series, counting and
density alike, as HistogramSeriesPoints:
steps[i],bins[i](with eithercountsordensities) andedgesIdx[i]describe the histogram at one step.- Bin edges are pooled:
edgesPool[edgesIdx[i]]holds the edges of pointi. Most runs use one binning throughout, so the pool usually has a single entry. mins,maxs,sumsandsumsOfSquareshold 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).
Scatter plots
Section titled “Scatter plots”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.
Response size
Section titled “Response size”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.