Functional Weave
Code in TypeScript

charts.axis@1.0.1

vectors.json

27,260 bytes · view raw

[
  {"fn": "axisFromTicks", "name": "a bottom axis: marks point down, labels hang below them", "args": [[0, 50, 100], ["0", "5", "10"], [0, 100], "bottom", 200, 6], "expect": {"orient": "bottom", "position": 200, "line": {"x1": 0, "y1": 200, "x2": 100, "y2": 200}, "ticks": [{"position": 0, "label": "0", "tick": {"x1": 0, "y1": 200, "x2": 0, "y2": 206}, "labelX": 0, "labelY": 209, "anchor": "middle", "baseline": "hanging"}, {"position": 50, "label": "5", "tick": {"x1": 50, "y1": 200, "x2": 50, "y2": 206}, "labelX": 50, "labelY": 209, "anchor": "middle", "baseline": "hanging"}, {"position": 100, "label": "10", "tick": {"x1": 100, "y1": 200, "x2": 100, "y2": 206}, "labelX": 100, "labelY": 209, "anchor": "middle", "baseline": "hanging"}]}},
  {"fn": "axisFromTicks", "name": "a top axis: marks point up, labels sit on their baseline above", "args": [[10, 90], ["a", "b"], [0, 100], "top", 20, 6], "expect": {"orient": "top", "position": 20, "line": {"x1": 0, "y1": 20, "x2": 100, "y2": 20}, "ticks": [{"position": 10, "label": "a", "tick": {"x1": 10, "y1": 20, "x2": 10, "y2": 14}, "labelX": 10, "labelY": 11, "anchor": "middle", "baseline": "alphabetic"}, {"position": 90, "label": "b", "tick": {"x1": 90, "y1": 20, "x2": 90, "y2": 14}, "labelX": 90, "labelY": 11, "anchor": "middle", "baseline": "alphabetic"}]}},
  {"fn": "axisFromTicks", "name": "a left axis: marks point left, labels right-aligned beside them", "args": [[300, 150, 0], ["0", "50", "100"], [300, 0], "left", 40, 6], "expect": {"orient": "left", "position": 40, "line": {"x1": 40, "y1": 300, "x2": 40, "y2": 0}, "ticks": [{"position": 300, "label": "0", "tick": {"x1": 40, "y1": 300, "x2": 34, "y2": 300}, "labelX": 31, "labelY": 300, "anchor": "end", "baseline": "middle"}, {"position": 150, "label": "50", "tick": {"x1": 40, "y1": 150, "x2": 34, "y2": 150}, "labelX": 31, "labelY": 150, "anchor": "end", "baseline": "middle"}, {"position": 0, "label": "100", "tick": {"x1": 40, "y1": 0, "x2": 34, "y2": 0}, "labelX": 31, "labelY": 0, "anchor": "end", "baseline": "middle"}]}},
  {"fn": "axisFromTicks", "name": "a right axis: labels start after the marks", "args": [[0, 100], ["low", "high"], [0, 100], "right", 500, 4], "expect": {"orient": "right", "position": 500, "line": {"x1": 500, "y1": 0, "x2": 500, "y2": 100}, "ticks": [{"position": 0, "label": "low", "tick": {"x1": 500, "y1": 0, "x2": 504, "y2": 0}, "labelX": 507, "labelY": 0, "anchor": "start", "baseline": "middle"}, {"position": 100, "label": "high", "tick": {"x1": 500, "y1": 100, "x2": 504, "y2": 100}, "labelX": 507, "labelY": 100, "anchor": "start", "baseline": "middle"}]}},
  {"fn": "axisFromTicks", "name": "pixels are rounded to 2 places, half away from zero", "args": [[12.345, 12.3449], ["x", "y"], [0.004, 99.996], "bottom", 100.125, 6], "expect": {"orient": "bottom", "position": 100.13, "line": {"x1": 0, "y1": 100.13, "x2": 100, "y2": 100.13}, "ticks": [{"position": 12.35, "label": "x", "tick": {"x1": 12.35, "y1": 100.13, "x2": 12.35, "y2": 106.13}, "labelX": 12.35, "labelY": 109.13, "anchor": "middle", "baseline": "hanging"}, {"position": 12.34, "label": "y", "tick": {"x1": 12.34, "y1": 100.13, "x2": 12.34, "y2": 106.13}, "labelX": 12.34, "labelY": 109.13, "anchor": "middle", "baseline": "hanging"}]}},
  {"fn": "axisFromTicks", "name": "zero-length marks put labels 3 pixels from the line", "args": [[5], ["5"], [0, 10], "left", 0, 0], "expect": {"orient": "left", "position": 0, "line": {"x1": 0, "y1": 0, "x2": 0, "y2": 10}, "ticks": [{"position": 5, "label": "5", "tick": {"x1": 0, "y1": 5, "x2": 0, "y2": 5}, "labelX": -3, "labelY": 5, "anchor": "end", "baseline": "middle"}]}},
  {"fn": "axisFromTicks", "name": "an axis with no ticks is just its line", "args": [[], [], [0, 300], "bottom", 150, 6], "expect": {"orient": "bottom", "position": 150, "line": {"x1": 0, "y1": 150, "x2": 300, "y2": 150}, "ticks": []}},
  {"fn": "axisFromTicks", "name": "a label per position is required", "args": [[0, 1], ["0"], [0, 1], "bottom", 0, 6], "expectError": "positions and labels must be the same length"},
  {"fn": "axisFromTicks", "name": "an unknown orient is an error, not a left axis", "args": [[0], ["0"], [0, 1], "middle", 0, 6], "expectError": "orient must be bottom, top, left or right"},
  {"fn": "axisFromTicks", "name": "a range needs two ends", "args": [[0], ["0"], [0], "bottom", 0, 6], "expectError": "range must have exactly 2 values"},
  {"fn": "gridLines", "name": "from a bottom axis the lines run up across the plot", "args": [{"orient": "bottom", "position": 200, "line": {"x1": 0, "y1": 200, "x2": 100, "y2": 200}, "ticks": [{"position": 0, "label": "0", "tick": {"x1": 0, "y1": 200, "x2": 0, "y2": 206}, "labelX": 0, "labelY": 209, "anchor": "middle", "baseline": "hanging"}, {"position": 50, "label": "5", "tick": {"x1": 50, "y1": 200, "x2": 50, "y2": 206}, "labelX": 50, "labelY": 209, "anchor": "middle", "baseline": "hanging"}, {"position": 100, "label": "10", "tick": {"x1": 100, "y1": 200, "x2": 100, "y2": 206}, "labelX": 100, "labelY": 209, "anchor": "middle", "baseline": "hanging"}]}, 180], "expect": [{"x1": 0, "y1": 200, "x2": 0, "y2": 20}, {"x1": 50, "y1": 200, "x2": 50, "y2": 20}, {"x1": 100, "y1": 200, "x2": 100, "y2": 20}]},
  {"fn": "gridLines", "name": "from a top axis they run down", "args": [{"orient": "top", "position": 20, "line": {"x1": 0, "y1": 20, "x2": 100, "y2": 20}, "ticks": [{"position": 25, "label": "x", "tick": {"x1": 25, "y1": 20, "x2": 25, "y2": 14}, "labelX": 25, "labelY": 11, "anchor": "middle", "baseline": "alphabetic"}]}, 100], "expect": [{"x1": 25, "y1": 20, "x2": 25, "y2": 120}]},
  {"fn": "gridLines", "name": "from a left axis they run right", "args": [{"orient": "left", "position": 40, "line": {"x1": 40, "y1": 300, "x2": 40, "y2": 0}, "ticks": [{"position": 300, "label": "0", "tick": {"x1": 40, "y1": 300, "x2": 34, "y2": 300}, "labelX": 31, "labelY": 300, "anchor": "end", "baseline": "middle"}, {"position": 150, "label": "50", "tick": {"x1": 40, "y1": 150, "x2": 34, "y2": 150}, "labelX": 31, "labelY": 150, "anchor": "end", "baseline": "middle"}, {"position": 0, "label": "100", "tick": {"x1": 40, "y1": 0, "x2": 34, "y2": 0}, "labelX": 31, "labelY": 0, "anchor": "end", "baseline": "middle"}]}, 460], "expect": [{"x1": 40, "y1": 300, "x2": 500, "y2": 300}, {"x1": 40, "y1": 150, "x2": 500, "y2": 150}, {"x1": 40, "y1": 0, "x2": 500, "y2": 0}]},
  {"fn": "gridLines", "name": "from a right axis they run left", "args": [{"orient": "right", "position": 500, "line": {"x1": 500, "y1": 0, "x2": 500, "y2": 100}, "ticks": [{"position": 10, "label": "a", "tick": {"x1": 500, "y1": 10, "x2": 506, "y2": 10}, "labelX": 509, "labelY": 10, "anchor": "start", "baseline": "middle"}]}, 460.004], "expect": [{"x1": 500, "y1": 10, "x2": 40, "y2": 10}]},
  {"fn": "gridLines", "name": "no ticks, no gridlines", "args": [{"orient": "bottom", "position": 0, "line": {"x1": 0, "y1": 0, "x2": 1, "y2": 0}, "ticks": []}, 50], "expect": []},
  {"fn": "gridLines", "name": "a negative length is an error", "args": [{"orient": "bottom", "position": 200, "line": {"x1": 0, "y1": 200, "x2": 100, "y2": 200}, "ticks": [{"position": 0, "label": "0", "tick": {"x1": 0, "y1": 200, "x2": 0, "y2": 206}, "labelX": 0, "labelY": 209, "anchor": "middle", "baseline": "hanging"}, {"position": 50, "label": "5", "tick": {"x1": 50, "y1": 200, "x2": 50, "y2": 206}, "labelX": 50, "labelY": 209, "anchor": "middle", "baseline": "hanging"}, {"position": 100, "label": "10", "tick": {"x1": 100, "y1": 200, "x2": 100, "y2": 206}, "labelX": 100, "labelY": 209, "anchor": "middle", "baseline": "hanging"}]}, -1], "expectError": "length must be a finite number of zero or more"},
  {"fn": "numberAxis", "name": "0 to 100 in steps of 20 along 500 pixels", "args": [[0, 100], [0, 500], 5, "bottom", 300, 6], "expect": {"orient": "bottom", "position": 300, "line": {"x1": 0, "y1": 300, "x2": 500, "y2": 300}, "ticks": [{"position": 0, "label": "0", "tick": {"x1": 0, "y1": 300, "x2": 0, "y2": 306}, "labelX": 0, "labelY": 309, "anchor": "middle", "baseline": "hanging"}, {"position": 100, "label": "20", "tick": {"x1": 100, "y1": 300, "x2": 100, "y2": 306}, "labelX": 100, "labelY": 309, "anchor": "middle", "baseline": "hanging"}, {"position": 200, "label": "40", "tick": {"x1": 200, "y1": 300, "x2": 200, "y2": 306}, "labelX": 200, "labelY": 309, "anchor": "middle", "baseline": "hanging"}, {"position": 300, "label": "60", "tick": {"x1": 300, "y1": 300, "x2": 300, "y2": 306}, "labelX": 300, "labelY": 309, "anchor": "middle", "baseline": "hanging"}, {"position": 400, "label": "80", "tick": {"x1": 400, "y1": 300, "x2": 400, "y2": 306}, "labelX": 400, "labelY": 309, "anchor": "middle", "baseline": "hanging"}, {"position": 500, "label": "100", "tick": {"x1": 500, "y1": 300, "x2": 500, "y2": 306}, "labelX": 500, "labelY": 309, "anchor": "middle", "baseline": "hanging"}]}},
  {"fn": "numberAxis", "name": "a y axis drawn upwards, labelled to one place because the step is 0.2", "args": [[0, 1], [300, 0], 5, "left", 40, 6], "expect": {"orient": "left", "position": 40, "line": {"x1": 40, "y1": 300, "x2": 40, "y2": 0}, "ticks": [{"position": 300, "label": "0.0", "tick": {"x1": 40, "y1": 300, "x2": 34, "y2": 300}, "labelX": 31, "labelY": 300, "anchor": "end", "baseline": "middle"}, {"position": 240, "label": "0.2", "tick": {"x1": 40, "y1": 240, "x2": 34, "y2": 240}, "labelX": 31, "labelY": 240, "anchor": "end", "baseline": "middle"}, {"position": 180, "label": "0.4", "tick": {"x1": 40, "y1": 180, "x2": 34, "y2": 180}, "labelX": 31, "labelY": 180, "anchor": "end", "baseline": "middle"}, {"position": 120, "label": "0.6", "tick": {"x1": 40, "y1": 120, "x2": 34, "y2": 120}, "labelX": 31, "labelY": 120, "anchor": "end", "baseline": "middle"}, {"position": 60, "label": "0.8", "tick": {"x1": 40, "y1": 60, "x2": 34, "y2": 60}, "labelX": 31, "labelY": 60, "anchor": "end", "baseline": "middle"}, {"position": 0, "label": "1.0", "tick": {"x1": 40, "y1": 0, "x2": 34, "y2": 0}, "labelX": 31, "labelY": 0, "anchor": "end", "baseline": "middle"}]}},
  {"fn": "numberAxis", "name": "thousands are grouped", "args": [[0, 5000], [0, 100], 2, "bottom", 0, 6], "expect": {"orient": "bottom", "position": 0, "line": {"x1": 0, "y1": 0, "x2": 100, "y2": 0}, "ticks": [{"position": 0, "label": "0", "tick": {"x1": 0, "y1": 0, "x2": 0, "y2": 6}, "labelX": 0, "labelY": 9, "anchor": "middle", "baseline": "hanging"}, {"position": 40, "label": "2,000", "tick": {"x1": 40, "y1": 0, "x2": 40, "y2": 6}, "labelX": 40, "labelY": 9, "anchor": "middle", "baseline": "hanging"}, {"position": 80, "label": "4,000", "tick": {"x1": 80, "y1": 0, "x2": 80, "y2": 6}, "labelX": 80, "labelY": 9, "anchor": "middle", "baseline": "hanging"}]}},
  {"fn": "numberAxis", "name": "a domain that is not nice only gets the ticks inside it", "args": [[3, 97], [0, 94], 4, "bottom", 0, 6], "expect": {"orient": "bottom", "position": 0, "line": {"x1": 0, "y1": 0, "x2": 94, "y2": 0}, "ticks": [{"position": 17, "label": "20", "tick": {"x1": 17, "y1": 0, "x2": 17, "y2": 6}, "labelX": 17, "labelY": 9, "anchor": "middle", "baseline": "hanging"}, {"position": 37, "label": "40", "tick": {"x1": 37, "y1": 0, "x2": 37, "y2": 6}, "labelX": 37, "labelY": 9, "anchor": "middle", "baseline": "hanging"}, {"position": 57, "label": "60", "tick": {"x1": 57, "y1": 0, "x2": 57, "y2": 6}, "labelX": 57, "labelY": 9, "anchor": "middle", "baseline": "hanging"}, {"position": 77, "label": "80", "tick": {"x1": 77, "y1": 0, "x2": 77, "y2": 6}, "labelX": 77, "labelY": 9, "anchor": "middle", "baseline": "hanging"}]}},
  {"fn": "numberAxis", "name": "negative to positive", "args": [[-10, 10], [0, 200], 4, "top", 0, 6], "expect": {"orient": "top", "position": 0, "line": {"x1": 0, "y1": 0, "x2": 200, "y2": 0}, "ticks": [{"position": 0, "label": "-10", "tick": {"x1": 0, "y1": 0, "x2": 0, "y2": -6}, "labelX": 0, "labelY": -9, "anchor": "middle", "baseline": "alphabetic"}, {"position": 50, "label": "-5", "tick": {"x1": 50, "y1": 0, "x2": 50, "y2": -6}, "labelX": 50, "labelY": -9, "anchor": "middle", "baseline": "alphabetic"}, {"position": 100, "label": "0", "tick": {"x1": 100, "y1": 0, "x2": 100, "y2": -6}, "labelX": 100, "labelY": -9, "anchor": "middle", "baseline": "alphabetic"}, {"position": 150, "label": "5", "tick": {"x1": 150, "y1": 0, "x2": 150, "y2": -6}, "labelX": 150, "labelY": -9, "anchor": "middle", "baseline": "alphabetic"}, {"position": 200, "label": "10", "tick": {"x1": 200, "y1": 0, "x2": 200, "y2": -6}, "labelX": 200, "labelY": -9, "anchor": "middle", "baseline": "alphabetic"}]}},
  {"fn": "numberAxis", "name": "count below 1 is an error", "args": [[0, 1], [0, 1], 0, "bottom", 0, 6], "expectError": "count must be a whole number of at least 1"},
  {"fn": "numberAxis", "name": "a domain needs two ends", "args": [[0], [0, 1], 5, "bottom", 0, 6], "expectError": "domain must have exactly 2 values"},
  {"fn": "timeAxis", "name": "a year in quarters", "args": [["2026-01-01", "2026-12-31"], [0, 364], 4, "bottom", 200, 6], "expect": {"orient": "bottom", "position": 200, "line": {"x1": 0, "y1": 200, "x2": 364, "y2": 200}, "ticks": [{"position": 0, "label": "Q1 2026", "tick": {"x1": 0, "y1": 200, "x2": 0, "y2": 206}, "labelX": 0, "labelY": 209, "anchor": "middle", "baseline": "hanging"}, {"position": 90, "label": "Q2 2026", "tick": {"x1": 90, "y1": 200, "x2": 90, "y2": 206}, "labelX": 90, "labelY": 209, "anchor": "middle", "baseline": "hanging"}, {"position": 181, "label": "Q3 2026", "tick": {"x1": 181, "y1": 200, "x2": 181, "y2": 206}, "labelX": 181, "labelY": 209, "anchor": "middle", "baseline": "hanging"}, {"position": 273, "label": "Q4 2026", "tick": {"x1": 273, "y1": 200, "x2": 273, "y2": 206}, "labelX": 273, "labelY": 209, "anchor": "middle", "baseline": "hanging"}]}},
  {"fn": "timeAxis", "name": "a fortnight in days every 2 days, starting on the 1st of the month's odd days", "args": [["2026-09-01", "2026-09-15"], [0, 140], 7, "bottom", 0, 6], "expect": {"orient": "bottom", "position": 0, "line": {"x1": 0, "y1": 0, "x2": 140, "y2": 0}, "ticks": [{"position": 0, "label": "1 Sep", "tick": {"x1": 0, "y1": 0, "x2": 0, "y2": 6}, "labelX": 0, "labelY": 9, "anchor": "middle", "baseline": "hanging"}, {"position": 20, "label": "3 Sep", "tick": {"x1": 20, "y1": 0, "x2": 20, "y2": 6}, "labelX": 20, "labelY": 9, "anchor": "middle", "baseline": "hanging"}, {"position": 40, "label": "5 Sep", "tick": {"x1": 40, "y1": 0, "x2": 40, "y2": 6}, "labelX": 40, "labelY": 9, "anchor": "middle", "baseline": "hanging"}, {"position": 60, "label": "7 Sep", "tick": {"x1": 60, "y1": 0, "x2": 60, "y2": 6}, "labelX": 60, "labelY": 9, "anchor": "middle", "baseline": "hanging"}, {"position": 80, "label": "9 Sep", "tick": {"x1": 80, "y1": 0, "x2": 80, "y2": 6}, "labelX": 80, "labelY": 9, "anchor": "middle", "baseline": "hanging"}, {"position": 100, "label": "11 Sep", "tick": {"x1": 100, "y1": 0, "x2": 100, "y2": 6}, "labelX": 100, "labelY": 9, "anchor": "middle", "baseline": "hanging"}, {"position": 120, "label": "13 Sep", "tick": {"x1": 120, "y1": 0, "x2": 120, "y2": 6}, "labelX": 120, "labelY": 9, "anchor": "middle", "baseline": "hanging"}, {"position": 140, "label": "15 Sep", "tick": {"x1": 140, "y1": 0, "x2": 140, "y2": 6}, "labelX": 140, "labelY": 9, "anchor": "middle", "baseline": "hanging"}]}},
  {"fn": "timeAxis", "name": "a date domain given backwards is placed backwards", "args": [["2026-12-31", "2026-01-01"], [0, 364], 4, "bottom", 0, 6], "expect": {"orient": "bottom", "position": 0, "line": {"x1": 0, "y1": 0, "x2": 364, "y2": 0}, "ticks": [{"position": 364, "label": "Q1 2026", "tick": {"x1": 364, "y1": 0, "x2": 364, "y2": 6}, "labelX": 364, "labelY": 9, "anchor": "middle", "baseline": "hanging"}, {"position": 274, "label": "Q2 2026", "tick": {"x1": 274, "y1": 0, "x2": 274, "y2": 6}, "labelX": 274, "labelY": 9, "anchor": "middle", "baseline": "hanging"}, {"position": 183, "label": "Q3 2026", "tick": {"x1": 183, "y1": 0, "x2": 183, "y2": 6}, "labelX": 183, "labelY": 9, "anchor": "middle", "baseline": "hanging"}, {"position": 91, "label": "Q4 2026", "tick": {"x1": 91, "y1": 0, "x2": 91, "y2": 6}, "labelX": 91, "labelY": 9, "anchor": "middle", "baseline": "hanging"}]}},
  {"fn": "timeAxis", "name": "an impossible date is an error", "args": [["2026-02-30", "2026-12-31"], [0, 1], 4, "bottom", 0, 6], "expectError": "is not a real calendar date"},
  {"fn": "bandAxis", "name": "three categories, ticks at band centres", "args": [["a", "b", "c"], [0, 300], 0.2, 0.1, "bottom", 100, 6], "expect": {"orient": "bottom", "position": 100, "line": {"x1": 0, "y1": 100, "x2": 300, "y2": 100}, "ticks": [{"position": 50, "label": "a", "tick": {"x1": 50, "y1": 100, "x2": 50, "y2": 106}, "labelX": 50, "labelY": 109, "anchor": "middle", "baseline": "hanging"}, {"position": 150, "label": "b", "tick": {"x1": 150, "y1": 100, "x2": 150, "y2": 106}, "labelX": 150, "labelY": 109, "anchor": "middle", "baseline": "hanging"}, {"position": 250, "label": "c", "tick": {"x1": 250, "y1": 100, "x2": 250, "y2": 106}, "labelX": 250, "labelY": 109, "anchor": "middle", "baseline": "hanging"}]}},
  {"fn": "bandAxis", "name": "centres are rounded to 2 places", "args": [["x", "y"], [0, 100], 0.5, 0, "bottom", 0, 6], "expect": {"orient": "bottom", "position": 0, "line": {"x1": 0, "y1": 0, "x2": 100, "y2": 0}, "ticks": [{"position": 16.67, "label": "x", "tick": {"x1": 16.67, "y1": 0, "x2": 16.67, "y2": 6}, "labelX": 16.67, "labelY": 9, "anchor": "middle", "baseline": "hanging"}, {"position": 83.33, "label": "y", "tick": {"x1": 83.33, "y1": 0, "x2": 83.33, "y2": 6}, "labelX": 83.33, "labelY": 9, "anchor": "middle", "baseline": "hanging"}]}},
  {"fn": "bandAxis", "name": "a category axis on the left", "args": [["north", "south"], [200, 0], 0, 0, "left", 50, 6], "expect": {"orient": "left", "position": 50, "line": {"x1": 50, "y1": 200, "x2": 50, "y2": 0}, "ticks": [{"position": 150, "label": "north", "tick": {"x1": 50, "y1": 150, "x2": 44, "y2": 150}, "labelX": 41, "labelY": 150, "anchor": "end", "baseline": "middle"}, {"position": 50, "label": "south", "tick": {"x1": 50, "y1": 50, "x2": 44, "y2": 50}, "labelX": 41, "labelY": 50, "anchor": "end", "baseline": "middle"}]}},
  {"fn": "bandAxis", "name": "a repeated category is an error", "args": [["a", "a"], [0, 100], 0, 0, "bottom", 0, 6], "expectError": "domain has a repeated value"},
  {"fn": "numberAxis", "name": "a right axis: labels start 3 pixels past the marks", "args": [[0, 10], [0, 100], 2, "right", 0, 6], "expect": {"orient": "right", "position": 0, "line": {"x1": 0, "y1": 0, "x2": 0, "y2": 100}, "ticks": [{"position": 0, "label": "0", "tick": {"x1": 0, "y1": 0, "x2": 6, "y2": 0}, "labelX": 9, "labelY": 0, "anchor": "start", "baseline": "middle"}, {"position": 50, "label": "5", "tick": {"x1": 0, "y1": 50, "x2": 6, "y2": 50}, "labelX": 9, "labelY": 50, "anchor": "start", "baseline": "middle"}, {"position": 100, "label": "10", "tick": {"x1": 0, "y1": 100, "x2": 6, "y2": 100}, "labelX": 9, "labelY": 100, "anchor": "start", "baseline": "middle"}]}},
  {"fn": "numberAxis", "name": "a domain given backwards puts its ticks backwards", "args": [[10, 0], [0, 100], 2, "bottom", 0, 6], "expect": {"orient": "bottom", "position": 0, "line": {"x1": 0, "y1": 0, "x2": 100, "y2": 0}, "ticks": [{"position": 0, "label": "10", "tick": {"x1": 0, "y1": 0, "x2": 0, "y2": 6}, "labelX": 0, "labelY": 9, "anchor": "middle", "baseline": "hanging"}, {"position": 50, "label": "5", "tick": {"x1": 50, "y1": 0, "x2": 50, "y2": 6}, "labelX": 50, "labelY": 9, "anchor": "middle", "baseline": "hanging"}, {"position": 100, "label": "0", "tick": {"x1": 100, "y1": 0, "x2": 100, "y2": 6}, "labelX": 100, "labelY": 9, "anchor": "middle", "baseline": "hanging"}]}},
  {"fn": "numberAxis", "name": "a step of 0.05 labels every tick with two places", "args": [[0, 0.1], [0, 100], 2, "bottom", 0, 6], "expect": {"orient": "bottom", "position": 0, "line": {"x1": 0, "y1": 0, "x2": 100, "y2": 0}, "ticks": [{"position": 0, "label": "0.00", "tick": {"x1": 0, "y1": 0, "x2": 0, "y2": 6}, "labelX": 0, "labelY": 9, "anchor": "middle", "baseline": "hanging"}, {"position": 50, "label": "0.05", "tick": {"x1": 50, "y1": 0, "x2": 50, "y2": 6}, "labelX": 50, "labelY": 9, "anchor": "middle", "baseline": "hanging"}, {"position": 100, "label": "0.10", "tick": {"x1": 100, "y1": 0, "x2": 100, "y2": 6}, "labelX": 100, "labelY": 9, "anchor": "middle", "baseline": "hanging"}]}},
  {"fn": "numberAxis", "name": "an unknown orient is an error", "args": [[0, 10], [0, 100], 5, "centre", 0, 6], "expectError": "orient must be bottom, top, left or right"},
  {"fn": "timeAxis", "name": "leap years make yearly ticks uneven: 2021 is 366 days along, not 365", "args": [["2020-01-01", "2025-01-01"], [0, 500], 5, "bottom", 0, 6], "expect": {"orient": "bottom", "position": 0, "line": {"x1": 0, "y1": 0, "x2": 500, "y2": 0}, "ticks": [{"position": 0, "label": "2020", "tick": {"x1": 0, "y1": 0, "x2": 0, "y2": 6}, "labelX": 0, "labelY": 9, "anchor": "middle", "baseline": "hanging"}, {"position": 100.16, "label": "2021", "tick": {"x1": 100.16, "y1": 0, "x2": 100.16, "y2": 6}, "labelX": 100.16, "labelY": 9, "anchor": "middle", "baseline": "hanging"}, {"position": 200.05, "label": "2022", "tick": {"x1": 200.05, "y1": 0, "x2": 200.05, "y2": 6}, "labelX": 200.05, "labelY": 9, "anchor": "middle", "baseline": "hanging"}, {"position": 299.95, "label": "2023", "tick": {"x1": 299.95, "y1": 0, "x2": 299.95, "y2": 6}, "labelX": 299.95, "labelY": 9, "anchor": "middle", "baseline": "hanging"}, {"position": 399.84, "label": "2024", "tick": {"x1": 399.84, "y1": 0, "x2": 399.84, "y2": 6}, "labelX": 399.84, "labelY": 9, "anchor": "middle", "baseline": "hanging"}, {"position": 500, "label": "2025", "tick": {"x1": 500, "y1": 0, "x2": 500, "y2": 6}, "labelX": 500, "labelY": 9, "anchor": "middle", "baseline": "hanging"}]}},
  {"fn": "timeAxis", "name": "in a leap year March starts on day 60", "args": [["2024-01-01", "2024-04-01"], [0, 91], 3, "bottom", 0, 6], "expect": {"orient": "bottom", "position": 0, "line": {"x1": 0, "y1": 0, "x2": 91, "y2": 0}, "ticks": [{"position": 0, "label": "Jan 2024", "tick": {"x1": 0, "y1": 0, "x2": 0, "y2": 6}, "labelX": 0, "labelY": 9, "anchor": "middle", "baseline": "hanging"}, {"position": 31, "label": "Feb 2024", "tick": {"x1": 31, "y1": 0, "x2": 31, "y2": 6}, "labelX": 31, "labelY": 9, "anchor": "middle", "baseline": "hanging"}, {"position": 60, "label": "Mar 2024", "tick": {"x1": 60, "y1": 0, "x2": 60, "y2": 6}, "labelX": 60, "labelY": 9, "anchor": "middle", "baseline": "hanging"}, {"position": 91, "label": "Apr 2024", "tick": {"x1": 91, "y1": 0, "x2": 91, "y2": 6}, "labelX": 91, "labelY": 9, "anchor": "middle", "baseline": "hanging"}]}},
  {"fn": "timeAxis", "name": "weekly ticks fall on Mondays, not on the first date", "args": [["2026-09-01", "2026-09-29"], [0, 280], 4, "left", 50, 6], "expect": {"orient": "left", "position": 50, "line": {"x1": 50, "y1": 0, "x2": 50, "y2": 280}, "ticks": [{"position": 60, "label": "7 Sep", "tick": {"x1": 50, "y1": 60, "x2": 44, "y2": 60}, "labelX": 41, "labelY": 60, "anchor": "end", "baseline": "middle"}, {"position": 130, "label": "14 Sep", "tick": {"x1": 50, "y1": 130, "x2": 44, "y2": 130}, "labelX": 41, "labelY": 130, "anchor": "end", "baseline": "middle"}, {"position": 200, "label": "21 Sep", "tick": {"x1": 50, "y1": 200, "x2": 44, "y2": 200}, "labelX": 41, "labelY": 200, "anchor": "end", "baseline": "middle"}, {"position": 270, "label": "28 Sep", "tick": {"x1": 50, "y1": 270, "x2": 44, "y2": 270}, "labelX": 41, "labelY": 270, "anchor": "end", "baseline": "middle"}]}},
  {"fn": "timeAxis", "name": "a domain needs two ends", "args": [["2026-01-01"], [0, 100], 4, "bottom", 0, 6], "expectError": "domain must have exactly 2 values"},
  {"fn": "timeAxis", "name": "count below 1 is an error", "args": [["2026-01-01", "2026-12-31"], [0, 364], 0, "bottom", 0, 6], "expectError": "count must be a whole number of at least 1"},
  {"fn": "timeAxis", "name": "an unknown orient is an error", "args": [["2026-01-01", "2026-12-31"], [0, 364], 4, "middle", 0, 6], "expectError": "orient must be bottom, top, left or right"},
  {"fn": "bandAxis", "name": "one category fills the range and sits in the middle", "args": [["only"], [0, 100], 0, 0, "bottom", 0, 6], "expect": {"orient": "bottom", "position": 0, "line": {"x1": 0, "y1": 0, "x2": 100, "y2": 0}, "ticks": [{"position": 50, "label": "only", "tick": {"x1": 50, "y1": 0, "x2": 50, "y2": 6}, "labelX": 50, "labelY": 9, "anchor": "middle", "baseline": "hanging"}]}},
  {"fn": "bandAxis", "name": "outer padding on a top axis: a third of a step each side", "args": [["a", "b"], [0, 100], 0, 0.5, "top", 10, 6], "expect": {"orient": "top", "position": 10, "line": {"x1": 0, "y1": 10, "x2": 100, "y2": 10}, "ticks": [{"position": 33.33, "label": "a", "tick": {"x1": 33.33, "y1": 10, "x2": 33.33, "y2": 4}, "labelX": 33.33, "labelY": 1, "anchor": "middle", "baseline": "alphabetic"}, {"position": 66.67, "label": "b", "tick": {"x1": 66.67, "y1": 10, "x2": 66.67, "y2": 4}, "labelX": 66.67, "labelY": 1, "anchor": "middle", "baseline": "alphabetic"}]}},
  {"fn": "bandAxis", "name": "a reversed range puts the first category at the far end", "args": [["a", "b", "c"], [300, 0], 0, 0, "bottom", 0, 6], "expect": {"orient": "bottom", "position": 0, "line": {"x1": 300, "y1": 0, "x2": 0, "y2": 0}, "ticks": [{"position": 250, "label": "a", "tick": {"x1": 250, "y1": 0, "x2": 250, "y2": 6}, "labelX": 250, "labelY": 9, "anchor": "middle", "baseline": "hanging"}, {"position": 150, "label": "b", "tick": {"x1": 150, "y1": 0, "x2": 150, "y2": 6}, "labelX": 150, "labelY": 9, "anchor": "middle", "baseline": "hanging"}, {"position": 50, "label": "c", "tick": {"x1": 50, "y1": 0, "x2": 50, "y2": 6}, "labelX": 50, "labelY": 9, "anchor": "middle", "baseline": "hanging"}]}},
  {"fn": "bandAxis", "name": "no categories is just the axis line", "args": [[], [0, 100], 0.1, 0.1, "bottom", 0, 6], "expect": {"orient": "bottom", "position": 0, "line": {"x1": 0, "y1": 0, "x2": 100, "y2": 0}, "ticks": []}},
  {"fn": "bandAxis", "name": "inner padding above 1 is an error", "args": [["a", "b"], [0, 100], 1.5, 0, "bottom", 0, 6], "expectError": "paddingInner must be between 0 and 1"},
  {"fn": "bandAxis", "name": "an unknown orient is an error", "args": [["a", "b"], [0, 100], 0, 0, "centre", 0, 6], "expectError": "orient must be bottom, top, left or right"},
  {"fn": "gridLines", "name": "a zero length draws each line as a point on the axis", "args": [{"orient": "bottom", "position": 200, "line": {"x1": 0, "y1": 200, "x2": 100, "y2": 200}, "ticks": [{"position": 30, "label": "30", "tick": {"x1": 30, "y1": 200, "x2": 30, "y2": 206}, "labelX": 30, "labelY": 209, "anchor": "middle", "baseline": "hanging"}]}, 0], "expect": [{"x1": 30, "y1": 200, "x2": 30, "y2": 200}]},
  {"fn": "gridLines", "name": "any negative length is refused, however small", "args": [{"orient": "bottom", "position": 200, "line": {"x1": 0, "y1": 200, "x2": 100, "y2": 200}, "ticks": [{"position": 30, "label": "30", "tick": {"x1": 30, "y1": 200, "x2": 30, "y2": 206}, "labelX": 30, "labelY": 209, "anchor": "middle", "baseline": "hanging"}]}, -0.01], "expectError": "length must be a finite number of zero or more"}
]