{
  "slug": "linear-interpolate-gaps",
  "name": "gizza-ai/linear-interpolate-gaps",
  "version": "0.1.0",
  "title": "Linear Interpolate Gaps — Fill Missing Values in a Number Series — gizza.ai",
  "description": "Paste readings with blanks or NA markers and fill gaps by linear interpolation. Cap run length, choose direction, and control edge gaps.",
  "tags": [
    "interpolation",
    "missing data",
    "fill gaps",
    "time series",
    "linear",
    "data cleaning",
    "csv",
    "spreadsheet"
  ],
  "category": "data",
  "urls": {
    "page": "https://gizza.ai/tools/linear-interpolate-gaps/",
    "markdown": "https://gizza.ai/tools/linear-interpolate-gaps/index.md",
    "descriptor": "https://gizza.ai/tools/linear-interpolate-gaps/tool.json",
    "deep_link_example": "https://gizza.ai/tools/linear-interpolate-gaps/?input=10%0A%0A%0A%0A20&layout=auto&max_gap=0&direction=both&edges=leave&na_tokens=missing%2C-999&decimals=6&output=values"
  },
  "cli": "gizza tool linear-interpolate-gaps \"10\n\n\n\n20\"",
  "tool": {
    "description": "Fill the missing values in an ordered numeric series by drawing a straight line between the two nearest known neighbours, the way a spreadsheet's fill-series or a dataframe's interpolate() does. Paste a column of readings with blanks or NA markers in it and get the same column back with the gaps filled and everything you typed echoed verbatim. Two-column rows are read as 'x,y' pairs, so a sensor that logged at 0, 5 and 20 minutes is interpolated against the real spacing rather than against row numbers — the difference between a right answer and a plausible one. layout picks that reading ('auto' (default), 'values', 'xy'); max_gap caps how many consecutive blanks may be filled, so a two-month hole is left honest instead of invented (0 = no limit); direction ('both' (default), 'forward', 'backward') decides which side a clipped run is filled from and whether the edge gaps are eligible; edges says what happens outside the known range, where there is no second anchor — 'leave' (default) keeps those blank, 'hold' repeats the nearest known value, 'extrapolate' extends the end slope; na_tokens adds your own missing markers such as '-999' or 'missing'; decimals rounds only the computed values (0-12, default 6, trailing zeros trimmed); output returns the plain series, a CSV with a known/filled/missing status per row, or JSON with counts plus a per-gap report of every run it filled or refused. Errors are specific: a non-numeric value names the position, out-of-order x values name the row. Runs entirely in the sandbox; nothing is uploaded.",
    "parameters": {
      "additionalProperties": false,
      "properties": {
        "decimals": {
          "default": 6,
          "description": "Maximum decimal places for the values this tool COMPUTES, 0-12 (default 6). Trailing zeros are trimmed, so a computed 2.50 prints as 2.5 and 17.500000 as 17.5. Set 0 for whole-number series like counts. Known values you typed are echoed back verbatim and are never reformatted or rounded.",
          "maximum": 12,
          "minimum": 0,
          "type": "integer"
        },
        "direction": {
          "default": "both",
          "description": "Which side(s) a gap may be filled from: 'both' (default), 'forward' only after a known value (the ffill direction), 'backward' only before one. On interior gaps with no max_gap all three give the same straight line — direction starts to matter once max_gap clips a run, and it also decides whether the leading gap (needs backward) and the trailing gap (needs forward) are eligible at all.",
          "enum": [
            "both",
            "forward",
            "backward"
          ],
          "type": "string"
        },
        "edges": {
          "default": "leave",
          "description": "What to do with the gaps OUTSIDE the known range — the blanks before the first known value and after the last, where there is no second anchor to draw a line to: 'leave' (default) keeps them empty, because strict interpolation never invents data past the anchors; 'hold' repeats the nearest known value (the classic ffill/bfill); 'extrapolate' extends the straight line through the two nearest known points, which can go negative. With a single known value 'extrapolate' degrades to 'hold' — one point has no slope.",
          "enum": [
            "leave",
            "hold",
            "extrapolate"
          ],
          "type": "string"
        },
        "input": {
          "description": "The series to fill, as text. One value per line, or separated by commas, semicolons, tabs or spaces. A blank field or an NA marker (empty, na, n/a, nan, null, none, nil, -, --, ?) is a gap; everything else must be a number. Rows of exactly two fields are read as 'x,y' pairs so uneven spacing is respected. A leading header row or label is skipped automatically. Max 100,000 values.",
          "type": "string"
        },
        "layout": {
          "default": "auto",
          "description": "How the input is read: 'auto' (default) treats the data as x,y pairs when there are 2+ rows and EVERY row has exactly two fields, otherwise as a plain list of y values; 'values' forces the plain list, where the positions 1,2,3… act as the x axis and every step is equal; 'xy' forces x,y pairs and errors on any row that has not got exactly two fields. In x,y layout the x column must be numeric and strictly increasing — only y may be missing.",
          "enum": [
            "auto",
            "values",
            "xy"
          ],
          "type": "string"
        },
        "max_gap": {
          "default": 0,
          "description": "Longest run of consecutive missing values that may be filled: 3 fills runs of 1-3 blanks and leaves a run of 4 alone, which is how you avoid inventing a week of data from two months apart. 0 (default) means no limit. A run longer than the limit is not skipped entirely under direction 'both' — it is filled max_gap values in from EACH side and left blank in the middle; use 'forward' or 'backward' to fill from one side only.",
          "maximum": 100000,
          "minimum": 0,
          "type": "integer"
        },
        "na_tokens": {
          "default": "",
          "description": "Extra tokens that also count as missing, comma-separated and case-insensitive, e.g. 'missing,unknown,-999,#N/A'. The built-in markers (empty, na, n/a, nan, null, none, nil, -, --, ?) are always recognised; this list adds to them rather than replacing them. Use it for sentinel values a logger writes, so they become gaps instead of failing the parse as non-numbers.",
          "type": "string"
        },
        "output": {
          "default": "values",
          "description": "Result shape: 'values' (default) prints the filled series one value per line — or 'x,y' per line in x,y layout — ready to paste straight back into a spreadsheet column; 'csv' adds a header row and a per-row status column of known/filled/missing so you can see which numbers are yours; 'json' returns the counts, the numeric array (an unfilled gap is null) and a per-gap report giving each run's start, end, length, kind (leading/interior/trailing), how many cells were filled and why the rest were not.",
          "enum": [
            "values",
            "csv",
            "json"
          ],
          "type": "string"
        }
      },
      "required": [
        "input"
      ],
      "type": "object"
    }
  }
}