►V Reference
On this page:
58.14.1 Coordinate Curves and Plots
58.14.1.1 Interpolation Modes
curve-interpolation?
58.14.1.2 Sampled Curves and Fields
sample-implicit-path
implicit-curve
vector-field
58.14.2 Function Graphs
sample-function-path
function-graph
58.14.2.1 Adaptive Sampling
sample-adaptive-function-path
adaptive-function-graph
58.14.2.2 Derived Function Graphs
derived-function-graph
58.14.3 Parametric Curves
parameter-range
sample-parametric-path
parametric-curve
58.14.4 Ordered Data Plots
data-series-path
data-plot
9.3

58.14 Function, Parametric, and Data Plots🔗ℹ

Choose a function graph for y = f(x), a parametric curve for an ordered parameter domain, an implicit curve for a scalar-field contour, or a data plot for an already ordered point series. Samplers return local path geometry; styled constructors return ordinary path Visuals. Sampling and the axes transform are construction-time snapshots unless an API explicitly says it is derived.

See also Arrows and Coordinate Axes, Graph Helpers and Traced Paths, ODE Trajectories and Streamlines.

    58.14.1 Coordinate Curves and Plots

      58.14.1.1 Interpolation Modes

      58.14.1.2 Sampled Curves and Fields

    58.14.2 Function Graphs

      58.14.2.1 Adaptive Sampling

      58.14.2.2 Derived Function Graphs

    58.14.3 Parametric Curves

    58.14.4 Ordered Data Plots

58.14.1 Coordinate Curves and Plots🔗ℹ

The procedures in this section convert ordered numeric coordinates to semantic path geometry. They use the local coordinate system of an axes Visual. They do not store a sampling procedure or a caller-owned point list in the result.

58.14.1.1 Interpolation Modes🔗ℹ

procedure

(curve-interpolation? value) → boolean?

  value : any/c
Returns #t when value is one of these symbols:

  • 'linear connects each accepted pair with a line segment.

  • 'smooth creates cubic Bézier segments that pass through all accepted samples in order.

Sampled function and parametric-curve procedures use 'smooth by default. Ordered data-series procedures use 'linear by default. An unsupported symbol or another value returns #f.

Smooth interpolation is applied separately to every accepted run. Suppose one run contains points P0 through Pn. For a segment from Pi to Pi+1, the usual interior control points are:

C1 = Pi + (Pi+1 - Pi-1) / 6

C2 = Pi+1 + (Pi - Pi+2) / 6

At an end of a run, the endpoint is repeated for the missing neighboring point. A run containing exactly two points uses a line-equivalent cubic whose controls are one third and two thirds of the way along the segment. The result therefore follows the same traversal order and reaches every accepted sample.

When clipping is enabled, sample pairs are clipped as line segments before smooth interpolation is calculated. Generated control points are then clamped to the closed axes rectangle. A cubic Bézier curve lies inside the convex hull of its endpoints and controls, so the resulting visible curve stays inside the rectangle. Clamping may reduce smoothness where a run touches a boundary.

58.14.1.2 Sampled Curves and Fields🔗ℹ

procedure

(sample-implicit-path axes    
  field    
  [#:level level    
  #:x-count x-count    
  #:y-count y-count]) → path-geometry?
  axes : axes-visual?
  field : (procedure-arity-includes/c 2)
  level : finite-real? = 0
  x-count : (and/c exact-integer? (>=/c 2)) = 65
  y-count : (and/c exact-integer? (>=/c 2)) = 65
Samples a two-argument scalar field with deterministic marching squares and returns axes-local open contour segments where the field equals level. Adjacent cell segments are stitched into deterministic open or closed subpaths. Non-finite field samples create gaps. The result is immutable path geometry and does not retain the callback.

procedure

(implicit-curve axes    
  field    
  #:id id    
  [#:level level    
  #:x-count x-count    
  #:y-count y-count    
  #:opacity opacity    
  #:stroke stroke    
  #:stroke-width stroke-width]) → path-visual?
  axes : axes-visual?
  field : (procedure-arity-includes/c 2)
  id : symbol?
  level : finite-real? = 0
  x-count : (and/c exact-integer? (>=/c 2)) = 65
  y-count : (and/c exact-integer? (>=/c 2)) = 65
  opacity : opacity? = 1
  stroke : any/c = "darkorange"
  stroke-width : (and/c finite-real? (>=/c 0)) = 2
Constructs a styled path Visual from sample-implicit-path, copying the current axes transform as a semantic snapshot.

procedure

(vector-field axes    
  field    
  #:id id    
  [#:x-count x-count    
  #:y-count y-count    
  #:scale scale    
  #:opacity opacity    
  #:stroke stroke    
  #:stroke-width stroke-width    
  #:tip-length tip-length    
  #:tip-width tip-width]) → group-visual?
  axes : axes-visual?
  field : (procedure-arity-includes/c 2)
  id : symbol?
  x-count : (and/c exact-integer? (>=/c 1)) = 9
  y-count : (and/c exact-integer? (>=/c 1)) = 7
  scale : finite-real? = 1/4
  opacity : opacity? = 1
  stroke : any/c = "seagreen"
  stroke-width : (and/c finite-real? (>=/c 0)) = 2
  tip-length : (and/c finite-real? (>/c 0)) = 3/20
  tip-width : (and/c finite-real? (>/c 0)) = 1/8
Samples field over a closed numeric axes grid. The procedure receives numeric x/y coordinates and must return exactly one vec2 vector. Each nonzero result becomes an arrow; zero vectors are omitted. The returned immutable group has stable child identities and can therefore use nested paths for lookup and animation. Sampling and axes transforms are captured at construction time; the group retains no procedure or renderer state.

58.14.2 Function Graphs🔗ℹ

procedure

(sample-function-path 
  axes 
  function 
  [#:x-min x-min 
  #:x-max x-max 
  #:sample-count sample-count 
  #:clip? clip? 
  #:max-jump max-jump 
  #:detect-discontinuities? detect-discontinuities? 
  #:interpolation interpolation]) 
 → path-geometry?
  axes : axes-visual?
  function : (procedure-arity-includes/c 1)
  x-min : (or/c finite-real? false/c) = #f
  x-max : (or/c finite-real? false/c) = #f
  sample-count : (and/c exact-integer? (>=/c 2)) = 201
  clip? : boolean? = #t
  max-jump : 
(or/c false/c
      (and/c finite-real? (>=/c 0)))
 = #f
  detect-discontinuities? : boolean? = #f
  interpolation : curve-interpolation? = 'smooth
Samples function at sample-count uniformly spaced x values in increasing order. The closed interval includes both endpoints. When x-min or x-max is #f, the corresponding bound comes from (axes-visual-x-range axes). The resolved minimum must be less than the resolved maximum. Their difference must remain a positive finite real.

For a logarithmic x axis, spacing is uniform in the selected base-logarithm display coordinate instead. Thus a base-ten range from one through one thousand samples successive decades evenly. Explicit x-min and x-max bounds follow the same rule and must be strictly positive on a log axis.

All arguments are checked before function is called. When sampling completes without an error, the function is called exactly once for each sample x value. Sampling stops at the first invalid result or exception. Each call must return exactly one value. That value has these meanings:

  • A finite real is one numeric y sample.

  • #f is an explicit gap and breaks the current run.

  • Positive infinity, negative infinity, and NaN also create a gap.

  • Any other result raises an exception that reports the x value and the returned value.

Returning zero values or more than one value raises an exception that reports the x value and result count. An exception raised by function is not converted to a gap. It is reported together with the sample x value and the original exception message. This keeps programming errors separate from explicit discontinuities.

When max-jump is a number, two adjacent finite samples are connected only when the absolute difference between their numeric y values is no greater than that number. The threshold is applied before axes scaling and before clipping. The default #f performs no jump rejection. Use an explicit #f result when the location of a discontinuity is known.

When clip? is true, every accepted sample pair is clipped to the closed rectangle described by the axes x and y ranges. Clipping is performed on segments, so an intersection with a boundary becomes an exact path endpoint when exact arithmetic permits it. When an inexact coordinate difference would overflow, clipping temporarily uses the exact represented input values. When clip? is false, finite out-of-range samples remain in the path. Clipping does not decide whether a segment crossing the rectangle is a true discontinuity.

The interpolation argument controls the path segment kind as described by curve-interpolation?. Linear interpolation stores line segments. Smooth interpolation stores cubic Bézier segments through each accepted run. Breaks from non-finite values, explicit #f results, maximum-jump rejection, or clipping keep the runs separate.

When detect-discontinuities? is true, two adjacent samples that lie beyond opposite sides of the visible numeric y interval are treated as the hidden sides of a vertical asymptote and are not connected. This opt-in rule prevents clipping from drawing a false segment through the plot window while preserving the historical default behavior for steep continuous graphs.

The result contains zero or more open subpaths in sampling order. An isolated finite sample with no accepted adjacent pair does not create a point-only subpath. Every stored point uses the untransformed local coordinate system of axes. Numeric x is multiplied by axes-x-unit-length, and numeric y is multiplied by axes-y-unit-length. The axes translation, rotation, and scale are not applied to the returned geometry.

The sampling grid is deterministic. Exact bounds produce exact rational intermediate x values when ordinary exact arithmetic permits it. The result contains only immutable path geometry. Rendering it later does not call function again.

procedure

(function-graph 
  axes 
  function 
  #:id id 
  [#:x-min x-min 
  #:x-max x-max 
  #:sample-count sample-count 
  #:clip? clip? 
  #:max-jump max-jump 
  #:detect-discontinuities? detect-discontinuities? 
  #:interpolation interpolation 
  #:opacity opacity 
  #:stroke stroke 
  #:stroke-width stroke-width]) 
 → path-visual?
  axes : axes-visual?
  function : (procedure-arity-includes/c 1)
  id : symbol?
  x-min : (or/c finite-real? false/c) = #f
  x-max : (or/c finite-real? false/c) = #f
  sample-count : (and/c exact-integer? (>=/c 2)) = 201
  clip? : boolean? = #t
  max-jump : 
(or/c false/c
      (and/c finite-real? (>=/c 0)))
 = #f
  detect-discontinuities? : boolean? = #f
  interpolation : curve-interpolation? = 'smooth
  opacity : opacity? = 1
  stroke : any/c = "royalblue"
  stroke-width : (and/c finite-real? (>=/c 0)) = 3
Calls sample-function-path with the same axes, function, interval, sample count, clipping, jump, discontinuity detection, and interpolation arguments. It wraps the result in a built-in path Visual.

The graph copies the current translation, rotation, and scale of axes. Its local geometry already uses the axes x and y unit lengths, so the graph and axes coincide at construction time even when the axes are translated, rotated, or non-uniformly scaled. This is a snapshot. Updating either immutable Visual later does not update the other. Put both in a group or apply matching animation requests when they should continue to move together.

The graph has no fill. The identity, opacity, and stroke width are checked before the numeric function is called. stroke and stroke-width are used by the ordinary path renderer. The result works with create, uncreate, path replacement, movement, rotation, non-uniform scaling, fading, groups, layout, and custom path renderers. There is no graph-specific renderer or timeline request.

A constructed function graph is an ordinary path Visual.

Example:
> (path-visual?
   (function-graph (axes #:id 'coordinates)
                   (lambda (x) (* x x))
                   #:id 'parabola #:sample-count 9))

#t

58.14.2.1 Adaptive Sampling🔗ℹ

procedure

(sample-adaptive-function-path 
  axes 
  function 
  [#:x-min x-min 
  #:x-max x-max 
  #:initial-sample-count initial-sample-count 
  #:max-deviation max-deviation 
  #:max-depth max-depth 
  #:clip? clip? 
  #:max-jump max-jump 
  #:detect-discontinuities? detect-discontinuities? 
  #:excluded-intervals excluded-intervals 
  #:interpolation interpolation]) 
 → path-geometry?
  axes : axes-visual?
  function : (procedure-arity-includes/c 1)
  x-min : (or/c finite-real? false/c) = #f
  x-max : (or/c finite-real? false/c) = #f
  initial-sample-count : (and/c exact-integer? (>=/c 2)) = 17
  max-deviation : (and/c finite-real? (>=/c 0)) = 1/100
  max-depth : (and/c exact-integer? (>=/c 0)) = 12
  clip? : boolean? = #t
  max-jump : (or/c false/c (and/c finite-real? (>=/c 0))) = #f
  detect-discontinuities? : boolean? = #t
  excluded-intervals : list? = '()
  interpolation : curve-interpolation? = 'linear
Samples function adaptively. The procedure first evaluates a deterministic, display-uniform grid of initial-sample-count points, then recursively evaluates each interval’s display-space midpoint. An interval is split while its midpoint differs from the chord midpoint by more than max-deviation in untransformed axes-local world units. Refinement stops after max-depth splits per initial interval, so the deviation threshold is a target rather than a guaranteed global bound.

The x-coordinate rule is the same as sample-function-path: linear axes use arithmetic interpolation and log axes use uniform logarithmic display interpolation. Callback values follow the same finite-real/#f/nonfinite rules, except that an exact numeric division-by-zero exception is treated as a gap. Other callback exceptions are reported with their x value.

With detect-discontinuities? true, an interval whose adjacent samples lie beyond opposite visible y boundaries is refined and ultimately broken, rather than clipped through the axes. max-jump adds an independent numeric y-distance break rule. excluded-intervals is a list of either (cons minimum maximum) or (list minimum maximum) values; each finite increasing interval splits the domain and no segment crosses its interior. Overlapping exclusions are merged deterministically.

The result uses the ordinary clipping and linear/smooth path interpolation machinery. It contains immutable axes-local geometry and retains neither the function nor adaptive evaluation cache. No finite initial grid can detect an oscillation that aliases every one of its samples; raise initial-sample-count for that case.

procedure

(adaptive-function-graph 
  axes 
  function 
  #:id id 
  [#:x-min x-min 
  #:x-max x-max 
  #:initial-sample-count initial-sample-count 
  #:max-deviation max-deviation 
  #:max-depth max-depth 
  #:clip? clip? 
  #:max-jump max-jump 
  #:detect-discontinuities? detect-discontinuities? 
  #:excluded-intervals excluded-intervals 
  #:interpolation interpolation 
  #:opacity opacity 
  #:stroke stroke 
  #:stroke-width stroke-width]) 
 → path-visual?
  axes : axes-visual?
  function : (procedure-arity-includes/c 1)
  id : symbol?
  x-min : (or/c finite-real? false/c) = #f
  x-max : (or/c finite-real? false/c) = #f
  initial-sample-count : (and/c exact-integer? (>=/c 2)) = 17
  max-deviation : (and/c finite-real? (>=/c 0)) = 1/100
  max-depth : (and/c exact-integer? (>=/c 0)) = 12
  clip? : boolean? = #t
  max-jump : (or/c false/c (and/c finite-real? (>=/c 0))) = #f
  detect-discontinuities? : boolean? = #t
  excluded-intervals : list? = '()
  interpolation : curve-interpolation? = 'linear
  opacity : opacity? = 1
  stroke : any/c = "royalblue"
  stroke-width : (and/c finite-real? (>=/c 0)) = 3
Calls sample-adaptive-function-path and wraps the result in the same immutable axes-transform snapshot as function-graph. The graph is an ordinary path Visual: it can be created, morphed, faded, moved, or grouped by the existing animation API.

58.14.2.2 Derived Function Graphs🔗ℹ

procedure

(derived-function-graph 
  axes 
  field 
  #:id id 
  [#:x-min x-min 
  #:x-max x-max 
  #:sample-count sample-count 
  #:clip? clip? 
  #:max-jump max-jump 
  #:detect-discontinuities? detect-discontinuities? 
  #:interpolation interpolation 
  #:opacity opacity 
  #:stroke stroke 
  #:stroke-width stroke-width]) 
 → derived-visual?
  axes : axes-visual?
  field : (procedure-arity-includes/c 2)
  id : symbol?
  x-min : (or/c finite-real? false/c) = #f
  x-max : (or/c finite-real? false/c) = #f
  sample-count : (and/c exact-integer? (>=/c 2)) = 201
  clip? : boolean? = #t
  max-jump : 
(or/c false/c
      (and/c finite-real? (>=/c 0)))
 = #f
  detect-discontinuities? : boolean? = #f
  interpolation : curve-interpolation? = 'linear
  opacity : opacity? = 1
  stroke : any/c = "royalblue"
  stroke-width : (and/c finite-real? (>=/c 0)) = 3
Creates a pure derived function graph. field receives the sampled derived-context? first and one numeric x coordinate second. It must return the same one-value result accepted by function-graph. The ordinary graph options have the same meanings as in function-graph.

For each resolved scene state, the field is sampled anew and produces one concrete path Visual with the requested identity, style, and axes transform. This permits an immutable parameter or another resolved Visual to drive a plot without a mutable updater. As with any derived-visual?, animate its source values or dependencies rather than applying a direct Visual animation to the derived graph.

58.14.3 Parametric Curves🔗ℹ

struct

(struct parameter-range (start end)
    #:transparent)
  start : finite-real?
  end : finite-real?
Represents one ordered closed parameter domain. The fields have these meanings:

  • start is the first parameter passed to a sampling procedure.

  • end is the last parameter passed to a sampling procedure.

The values must be distinct finite reals. The computed difference (- end start) must also remain a nonzero finite real. The order is significant. When start is greater than end, sampling proceeds in decreasing order.

The structure is immutable and transparent. Its public bindings include parameter-range, parameter-range?, both field accessors, and struct:parameter-range.

procedure

(sample-parametric-path axes 
  function 
  [#:parameter-range domain 
  #:sample-count sample-count 
  #:clip? clip? 
  #:max-distance max-distance 
  #:interpolation interpolation]) 
 → path-geometry?
  axes : axes-visual?
  function : (procedure-arity-includes/c 1)
  domain : parameter-range? = (parameter-range 0 1)
  sample-count : (and/c exact-integer? (>=/c 2)) = 201
  clip? : boolean? = #t
  max-distance : 
(or/c false/c
      (and/c finite-real? (>=/c 0)))
 = #f
  interpolation : curve-interpolation? = 'smooth
Samples function at sample-count uniformly spaced parameter values from (parameter-range-start domain) through (parameter-range-end domain). Both endpoints are included exactly as stored. Intermediate values follow the same increasing or decreasing order. Exact endpoints produce exact rational intermediate values when ordinary exact arithmetic permits it.

All arguments are checked before function is called. Each sampling call must return exactly one value:

  • A vec2 is one finite numeric coordinate.

  • #f is an explicit gap.

Another value, zero values, or multiple values raise an exception that reports the parameter value. An exception from function is reported with the same parameter and the original exception message. Sampling stops at the first error.

When max-distance is a number, two adjacent coordinates are connected only when their Euclidean distance in numeric-coordinate units is no greater than that number. The distance is measured before independent axes scaling. The default #f applies no distance rejection.

Clipping and interpolation follow the common rules described above. The result contains axes-local open subpaths and does not retain function or domain. Empty runs and isolated finite coordinates produce no drawn segment.

procedure

(parametric-curve axes    
  function    
  #:id id    
  [#:parameter-range domain    
  #:sample-count sample-count    
  #:clip? clip?    
  #:max-distance max-distance    
  #:interpolation interpolation    
  #:opacity opacity    
  #:stroke stroke    
  #:stroke-width stroke-width]) → path-visual?
  axes : axes-visual?
  function : (procedure-arity-includes/c 1)
  id : symbol?
  domain : parameter-range? = (parameter-range 0 1)
  sample-count : (and/c exact-integer? (>=/c 2)) = 201
  clip? : boolean? = #t
  max-distance : 
(or/c false/c
      (and/c finite-real? (>=/c 0)))
 = #f
  interpolation : curve-interpolation? = 'smooth
  opacity : opacity? = 1
  stroke : any/c = "royalblue"
  stroke-width : (and/c finite-real? (>=/c 0)) = 3
Calls sample-parametric-path with the same sampling arguments and wraps the result in an ordinary path Visual. Identity, opacity, and stroke width are checked before the sampling procedure is called.

The returned path has no fill and copies the current axes translation, rotation, and scale. This is a construction-time snapshot, not a live link. The result can use every operation available to an ordinary path Visual, including create, uncreate, morphing, affine animation, opacity, groups, and renderer-aware layout.

58.14.4 Ordered Data Plots🔗ℹ

procedure

(data-series-path axes 
  points 
  [#:clip? clip? 
  #:max-distance max-distance 
  #:interpolation interpolation]) 
 → path-geometry?
  axes : axes-visual?
  points : (listof (or/c vec2? false/c))
  clip? : boolean? = #t
  max-distance : 
(or/c false/c
      (and/c finite-real? (>=/c 0)))
 = #f
  interpolation : curve-interpolation? = 'linear
Converts points to axes-local path geometry. The input must be a proper list containing only vec2 values and #f. A vec2 is one numeric coordinate. #f is an explicit gap.

List order is traversal order. The procedure does not sort by x, infer time order, remove repeated coordinates, or retain the input list. An empty list, a one-point list, or a finite coordinate isolated by gaps produces no drawn segment.

The max-distance, clip?, and interpolation arguments have the same meanings as for sample-parametric-path. Distance is Euclidean in numeric-coordinate units. The result contains only immutable path geometry.

An explicit gap separates two accepted runs.

Examples:
> (define data
    (data-series-path
     (axes #:id 'data-axes)
     (list (vec2 -2 0) (vec2 -1 1) #f (vec2 1 1) (vec2 2 0))))
> (length (path-geometry-subpaths data))

2

procedure

(data-plot axes    
  points    
  #:id id    
  [#:clip? clip?    
  #:max-distance max-distance    
  #:interpolation interpolation    
  #:opacity opacity    
  #:stroke stroke    
  #:stroke-width stroke-width]) → path-visual?
  axes : axes-visual?
  points : (listof (or/c vec2? false/c))
  id : symbol?
  clip? : boolean? = #t
  max-distance : 
(or/c false/c
      (and/c finite-real? (>=/c 0)))
 = #f
  interpolation : curve-interpolation? = 'linear
  opacity : opacity? = 1
  stroke : any/c = "seagreen"
  stroke-width : (and/c finite-real? (>=/c 0)) = 3
Calls data-series-path with the same point, clipping, distance, and interpolation arguments and wraps the result in an ordinary path Visual. Identity, opacity, and stroke width are checked before the point series is converted.

The returned path has no fill and copies the axes translation, rotation, and scale at construction time. It works with ordinary path rendering, creation, removal, morphing, movement, rotation, non-uniform scaling, fading, groups, and relative layout.