58.11 Arrows and Coordinate Axes
Arrow endpoints and axes reference points are semantic coordinates. Numeric axis ranges are distinct from their displayed world lengths: axes-coordinates->point applies the axis scales and placement, while axes-point->coordinates performs the inverse conversion.
See also Live Endpoints and Mathematical Annotations, Function, Parametric, and Data Plots.
58.11.1 Arrow and Cartesian Axes Visuals
Arrow and axes values are semantic affine Visuals. They implement gen:visual, gen:affine-visual, and gen:opacity-visual. Their raw structure constructors and internal local geometry fields are not public.
58.11.1.1 Arrows
procedure
(arrow start end #:id id [ #:rotation rotation #:scale scale #:opacity opacity #:stroke stroke #:stroke-width stroke-width #:tip-length tip-length #:tip-width tip-width #:start-tip? start-tip? #:end-tip? end-tip?]) → arrow-visual? start : vec2? end : vec2? id : symbol? rotation : finite-real? = 0 scale : scale-factor? = 1 opacity : opacity? = 1 stroke : any/c = "black" stroke-width : (and/c finite-real? (>=/c 0)) = 2 tip-length : (and/c finite-real? positive?) = 3/10 tip-width : (and/c finite-real? positive?) = 1/4 start-tip? : boolean? = #f end-tip? : boolean? = #t
The points must be distinct and their distance must be finite. The constructor uses their midpoint as the Visual’s reference position and stores the two endpoints relative to that midpoint. The optional rotation and scale therefore act around the midpoint.
start-tip? and end-tip? independently select closed triangular tips. The default is one tip at the end. Both flags may be false, or both may be true. tip-length measures the distance from an apex to the center of its base. tip-width measures the full base width. Both are local world-unit geometry and are affected by semantic scale. A tip is allowed to be longer than the shaft.
stroke is adapter-specific style data. The built-in Pict renderer uses it for the shaft, tip fill, and tip outline. stroke-width is a cosmetic output width and is not multiplied by semantic scale. opacity is applied to the complete rendered arrow after renderer dispatch.
procedure
(arrow-visual? value) → boolean?
value : any/c
procedure
(arrow-visual-length arrow) → (and/c finite-real? positive?)
arrow : arrow-visual?
procedure
(arrow-visual-stroke arrow) → any/c
arrow : arrow-visual?
procedure
(arrow-visual-stroke-width arrow)
→ (and/c finite-real? (>=/c 0)) arrow : arrow-visual?
procedure
(arrow-visual-tip-length arrow)
→ (and/c finite-real? positive?) arrow : arrow-visual?
procedure
(arrow-visual-tip-width arrow) → (and/c finite-real? positive?)
arrow : arrow-visual?
procedure
(arrow-visual-start-tip? arrow) → boolean?
arrow : arrow-visual?
procedure
(arrow-visual-end-tip? arrow) → boolean?
arrow : arrow-visual?
procedure
(arrow-visual-start arrow) → vec2?
arrow : arrow-visual?
procedure
(arrow-visual-end arrow) → vec2?
arrow : arrow-visual?
procedure
(arrow-visual-point-at arrow progress) → vec2?
arrow : arrow-visual? progress : (real-in 0 1)
58.11.1.2 Axis Ranges
struct
(struct axis-range (minimum maximum tick-step) #:transparent) minimum : finite-real? maximum : finite-real? tick-step : (and/c finite-real? positive?)
minimum is the smallest represented coordinate.
maximum is the largest represented coordinate.
tick-step is the positive distance between regular tick coordinates.
minimum must be less than maximum. The computed difference (- maximum minimum) must also remain a positive finite real; this rejects an inexact endpoint pair whose subtraction overflows. The structure is immutable and transparent. Linear axes require their ranges to contain zero; logarithmic axes require strictly-positive ranges. Its public bindings include axis-range, axis-range?, the three field accessors, and struct:axis-range.
procedure
(axis-range-contains? range value) → boolean?
range : axis-range? value : any/c
procedure
(axis-range-tick-values range) → (listof finite-real?)
range : axis-range?
For example:
(axis-range-tick-values (axis-range -3 5 2))
returns '(-2 2 4). The procedure does not choose ticks from camera pixels or available label space.
Exact endpoint quotients are handled exactly. For inexact quotients, the procedure uses a fixed relative tolerance of 1e-12 when choosing the first and last integer indexes. This prevents ordinary decimal input such as -0.3, 0.3, and 0.1 from losing endpoint ticks because of binary floating-point rounding. It raises an exception when dividing a range endpoint by the step produces an infinite or NaN index.
The zero tick is omitted; nonzero multiples stay in increasing order.
> (axis-range-tick-values (axis-range -3 5 2)) '(-2 2 4)
procedure
(axis-scale? value) → boolean?
value : any/c
58.11.1.3 Cartesian Axes
procedure
(axes #:id id [ #:center center #:rotation rotation #:scale scale #:opacity opacity #:x-range x-range #:y-range y-range #:x-scale x-scale #:y-scale y-scale #:x-log-base x-log-base #:y-log-base y-log-base #:x-length x-length #:y-length y-length #:stroke stroke #:stroke-width stroke-width #:tick-size tick-size #:tip-length tip-length #:tip-width tip-width #:x-tip? x-tip? #:y-tip? y-tip?]) → axes-visual? id : symbol? center : vec2? = origin rotation : finite-real? = 0 scale : scale-factor? = 1 opacity : opacity? = 1 x-range : axis-range? = (axis-range -6 6 1) y-range : axis-range? = (axis-range -3 3 1) x-scale : axis-scale? = 'linear y-scale : axis-scale? = 'linear x-log-base : (and/c finite-real? (>/c 1)) = 10 y-log-base : (and/c finite-real? (>/c 1)) = 10 x-length : (and/c finite-real? positive?) = 12 y-length : (and/c finite-real? positive?) = 6 stroke : any/c = "black" stroke-width : (and/c finite-real? (>=/c 0)) = 2 tick-size : (and/c finite-real? (>=/c 0)) = 3/20 tip-length : (and/c finite-real? positive?) = 3/10 tip-width : (and/c finite-real? positive?) = 1/4 x-tip? : boolean? = #t y-tip? : boolean? = #t
The full interval from (axis-range-minimum x-range) to (axis-range-maximum x-range) is mapped to x-length local world units. The y interval is mapped independently to y-length. The x and y unit lengths can therefore differ. Each resulting length-per-display-unit must remain a positive finite real.
With 'log for x-scale or y-scale, that axis accepts only a strictly-positive axis-range. Numeric coordinates are converted through (log value) in the configured base before they are placed. A log axis uses numeric one as its shaft reference when it is visible (otherwise the minimum range value); coordinate zero is invalid. x-log-base and y-log-base must be finite and greater than one. The tick-step of a log range is a step in base-logarithm exponent space, so the usual value of one produces ticks at successive powers of the base.
The x shaft is drawn at numeric y coordinate zero on a linear y axis, and at numeric one (or the visible minimum) on a log y axis; the y shaft follows the same rule for its x coordinate. Regular ticks come from axis-range-tick-values on linear axes and powers of the configured base on log axes. tick-size is the full local length of each tick. A value of zero hides all ticks while preserving the ranges and coordinate conversion.
x-tip? and y-tip? select triangular tips at the maximum-x and maximum-y endpoints, respectively. tip-length and tip-width are local world-unit geometry. stroke-width is cosmetic. The built-in renderer uses stroke for shafts, ticks, tip fill, and tip outlines.
The constructor does not create numeric labels, axis-name labels, grid lines, or sampled plots. They can be added as separate Visuals. Renderer-aware layout can place labels around the complete axes render box.
procedure
(axes-visual? value) → boolean?
value : any/c
procedure
(axes-visual-x-range axes) → axis-range?
axes : axes-visual?
procedure
(axes-visual-y-range axes) → axis-range?
axes : axes-visual?
procedure
(axes-visual-x-scale axes) → axis-scale?
axes : axes-visual?
procedure
(axes-visual-y-scale axes) → axis-scale?
axes : axes-visual?
procedure
(axes-visual-x-log-base axes) → (and/c finite-real? (>/c 1))
axes : axes-visual?
procedure
(axes-visual-y-log-base axes) → (and/c finite-real? (>/c 1))
axes : axes-visual?
procedure
(axes-visual-x-length axes) → (and/c finite-real? positive?)
axes : axes-visual?
procedure
(axes-visual-y-length axes) → (and/c finite-real? positive?)
axes : axes-visual?
procedure
(axes-visual-stroke axes) → any/c
axes : axes-visual?
procedure
(axes-visual-stroke-width axes) → (and/c finite-real? (>=/c 0))
axes : axes-visual?
procedure
(axes-visual-tick-size axes) → (and/c finite-real? (>=/c 0))
axes : axes-visual?
procedure
(axes-visual-tip-length axes) → (and/c finite-real? positive?)
axes : axes-visual?
procedure
(axes-visual-tip-width axes) → (and/c finite-real? positive?)
axes : axes-visual?
procedure
(axes-visual-x-tip? axes) → boolean?
axes : axes-visual?
procedure
(axes-visual-y-tip? axes) → boolean?
axes : axes-visual?
procedure
(axes-x-unit-length axes) → (and/c finite-real? positive?)
axes : axes-visual?
procedure
(axes-y-unit-length axes) → (and/c finite-real? positive?)
axes : axes-visual?
procedure
(axes-coordinates->point axes x y) → vec2?
axes : axes-visual? x : finite-real? y : finite-real?
The numeric coordinates are not required to lie inside the displayed ranges. This permits extrapolation and placement just outside the visible axes. A value on a logarithmic axis must nevertheless be a positive finite real.
procedure
(axes-point->coordinates axes point) → vec2?
axes : axes-visual? point : vec2?
For finite inputs this is the inverse of axes-coordinates->point up to ordinary numeric precision. A nonzero rotation normally introduces inexact trigonometric results.
Equal display lengths and numeric spans give one world unit per coordinate unit.
> (define grid (axes #:id 'grid #:x-range (axis-range -3 3 1) #:x-length 6 #:y-range (axis-range -2 2 1) #:y-length 4)) > (define point (axes-coordinates->point grid 2 1)) > (list (vec2-x point) (vec2-y point)) '(2 1)