SVG Function Plotter

NOTE: This page contains MathML elements, which is not well supported by Chrome and Edge on Android devices, but Firefox does quite a good job and renders the equations nicely.

The SVG function plotter shall support one, two and three-dimensional functions, multiple coordinate system axes, and multiple graphs in the same SVG image.

Some examples (TODO):

About Coordinate Systems

The space of an SVG image is inherently two-dimesional. It is defined by the SVG element's viewBox attribute:

<svg viewBox = "-100, -100, 300, 300" ...

These values define the coordinates of the upper left corner xMin and yMin, width and height of the diagram. These values inherently define the location of the origin (0,0) in the image as well as xMax and yMax:

xMin=viewBox.x=−100 xMax=viewBox.width+viewBox.x=300100=200 yMin=viewBox.y=−100 yMax=viewBox.height=viewBox.y=300100=200

Note that the viewbox origin is always at viewbox coordinates (0,0):

Coordinates in SVG space
x y -100 -50 50 100 150 200 -100 -50 50 100 150 200 200

Now let's make things complicated. The figure above suggest that the viewbox axes represent the axes x and y of a function graph. But in fact, they don't. One indicator is that the y axis goes from top to bottom, which is unusual, kind of. Secondly, the viewbox axes are invisible. In the diagrams presented here, I added some SVG code to make them visible. The tickmarks and their lables should give some guidance and orientation in the viewbox space.

Let's create an angled axis named "z":

Angled axis
x y -100 -50 50 100 150 200 -100 -50 50 100 150 200 200 z P2 (−100,100) P1 (−100,100)

Note that the axis can actually be oriented in any direction, and might not even go through the viewbox origin. In the following section, we will go into ways to define an axis and develop the related math equations.

Axis Definition in ViewBox Space

The web page author should have two methods define a diagram axis:

  1. An angle and an optional reference point, which defaults to the viewbox origin (0,0)
  2. Two reference points, the second is optional and defaults to (0,0)

The software should be able to caluclate the intersection points between axis line and viewbox border, as well as axis length in viewbox units and other transformation factors.

Method 1: Angle and Reference Point

The page author supplies an angle and an optional reference point. To keep things simple, we assume the default reference point, the viewbox coordinate system origin O at (0,0)).

The angle is measured counter-clockwise between the viewbox x axis and the graph axis. To draw the axis line, we need to find the coordinates of intersection points (P1, P2) between line and viewbox borders:

Intersection point coordinates
α α x y P1 (xMin, y1) y1 P2 (x2, yMin) x2

They are determined by the angle α and the length of the viewbox axes legs, xMin, xMax, yMin and yMax. We will have to treat each coordinate system quadrant and each axis line leg (P1 O and O P2) separately.

Let's begin with the first quadrant in the upper right corner.

Lines in the first quadrant
yMax y1 xMax x2 P1 P2 α1 α2

The figure above indicates that we have two different situations:

  1. The line intersects with the right viewbox border at P1
  2. The line intersects with the upper viewbox border at P2

The angle α and the viewbox properties xMax, xMin determine which of these alternatives applies.

We will use the trigonometric tangens relation for our calculations:

(1)  tanα=yx  ⇔ y=xtanα  ⇔ x=ytanα 

A visual help:

Relationships in a right-angled triangle
α β γ y x B A C c

So tangens α essentially is the slope of the line AB.

Finding the X Coordinate

If we want to get the x coordinate of the intersection point, we set y in equation (1) to −yMin and solve for x:

(2)  x=−yMintanα 

The negative of yMin must be used in order to obtain a positive x value.

The two situations (O P1 P1A and O P2) are illustrated more detailed in the figure below:

Getting the x coordinate
yMin xMax P2 x1 P1A P1 x2

If the line intersects with the right viewbox border, we get the point P1A with the x-coordinate x1 — which is outside of the viewbox. So we must limit the x-value to find P1:

(2a)  x=min(−yMintanα , xMax)=xMax

In case 2, the line intersects with the upper viewbox border at P2. In this case, the solution is

(2b)  x=min(−yMintanα , xMax)=x2

x2 is less than xMax, so we can accept that.

Finding the Y Coordinate

Now lets find the y coordinate for a line in quadrant 1. Again, we have two situations:

  1. The line intersects with the right viewbox border at P1
  2. The line intersects with the upper viewbox border at P2

In detail:

Quadrant 1, y coordinate
y1 yMin xMax y2 P2A P2 P1 y1 x2 P1 P2 α1 α2

We set x = −xMax in equation (1) and solve for y. We need a negative xMax to obtain a negative y-coordinate in this quadrant.

If the line crosses the right viewbox border at P1, we obtain y1, which is greater than yMin, so we can accept the result:

(3a)  y=max(−xMaxtanα , yMin)=y1

In the second case, the line intersects with the upper viewbox border, we get P2A with the coordinate y2 — which is outside of the viewbox area. So the result must be limited:

(3b)  y=max(−xMaxtanα , yMin)=yMin

The Second Quadrant

The figure below shows the situation in the second quadrant. Here, both x and y coordinates are negative:

Quadrant 2 coordinates
α β2 β1 yMin x1 x2 xMin y1 y2 P1A P1 P2A P2

To keep things familiar, we will work with the complimentary angle β:

(4)  β=180α

If the line intersects the left viewbox border, we get the x-coordinates xMin and y1:

(5a)  x=max( yMin tanβ, xMin)=xMin
(6a)  y=max(xMintanβ , yMin)=y1

If the line crosses the upper border of the viewbox, we get the following coordinates:

(5b)  x=max( yMin tanβ, xMin)=x2
(6b)  y=max(xMintanβ , yMin)=yMin

The Third Quadrant

This is the situation in the third quadrant:

Quadrant 3 coordinates
α β2 β1 yMax x1 x2 xMin y1 y2 P1A P1 P2A P2

Again, we work with the complimentary angle β:

(7)  β=α180

If the line intersects the left viewbox border, we get the x-coordinates xMin and y1:

(8a)  x=max( −yMax tanβ, xMin)=xMin
(9a)  y=min(−xMintanβ , yMax)=y1

If the line crosses the upper border of the viewbox, we get the following coordinates:

(8b)  x=max( −yMax tanβ, xMin)=x2
(9b)  y=min(−xMintanβ , xMin)=yMax

Similar to quarant 1, we have to use negative values to obtain the correctly signed results.

The Fourth Quadrant

This is the situation in the third quadrant:

Quadrant 4 coordinates
α β2 β1 yMax x1 x2 xMin y1 y2 P1A P1 P2A P2

In this quadrant, all coordinate values are positive.

Again, we work with the complimentary angle β:

(10)  β=360α

If the line intersects the left viewbox border, we get the x-coordinates xMin and y1:

(11a)  x=min( yMax tanβ, xMax)=xMax
(12a)  y=min(xMaxtanβ , yMax)=y1

If the line crosses the upper border of the viewbox, we get the following coordinates:

(11b)  x=min( yMax tanβ, xMax)=x2
(12b)  y=min(xMaxtanβ , xMax)=yMax

Equation Summary

After drowning in the details, it's good to regain an overview. Below are the eight equations used to calculate the coordinates:

The first quadrant:

(2)  x=min(−yMintanα , xMax)
(3)  y=max(−xMaxtanα , yMin)

The second quadrant:

(4)  β=180α
(5)  x=max( yMin tanβ, xMin)
(6)  y=max(xMintanβ , yMin)

The third quadrant:

(7)  β=α180
(8)  x=max( −yMax tanβ, xMin)
(9)  y=min(−xMintanβ , yMax)

The fourth quadrant:

(10)  β=360α
(11)  x=min( yMax tanβ, xMax)
(12)  y=min(xMaxtanβ , yMax)

A closer look at these equations reveals that the combinations are all slightly different for each quadrant. So, we cannot combine them.

Note that an axis lines has two legs at opposite quadrants, and each leg has to be calculated separately!

Angle and Reference Point

The following figure illustrates an axis line with the specified angle α through the reference point R:

Angle and Reference Point
α O P1 (-100, 40) P2 (131, -120) R (30, -50) xMin xMax yMin yMax

If we assume the reference as new origin (0, 0), we get a transformed coordinate system:

Transformed diagram
α O P1 (-100, 40) P2 (131, -120) R (0, 0) xMin−30 xMax−30 yMin+50 yMax+50

The range values for the transformed coordinate system are obtained from these equations:

(13)  xMinT=xMinxR xMaxT=xMaxxR yMinT=xMinyR yMaxT=xMaxyR

With these new values used in equations (2) to (12), we can calculate the axis end point coordinates as before.

Coordinate Calculation Test

20 degree axis intersection points
x y α1 α2 P1 P22




Method 2: Two Reference Points

TO DO

Axis Length

The angled axis is obviously longer than the viewbox x and y axes:

Length of the angled axis
f P1 (200, -80) P2 (-100, 40) P3 (-100, -80)

Pythagoras, a well-respected ancient Greek, says:

P1P2= (x2x1)2 + (y2y1)2 =3002+1202 =323

The JavaScript Math object has a method for this purpose: hypot() computes the root of the sum of squares of arguments.

Axis Projection Parameters

Scaling factors for the projection of a point z onto the viewbox plane:

SFX=zP2P3P1P2 SFY=zP1P3P1P2

Axis

An SVG plotter axis represents a section of a dimension of the real-world space of a function to be plotted. It governs two transformations:

  1. from a dimension of the function "real-world" function space to the one-dimensional axis space
  2. from the axis space to the two-dimensional SVG viewbox space

The visual representation of an axis is a line with an arrow-head and label and a series of tickmarks with labels, representing real-world coordinates. The SVG viewbox space is shared between all axes.

Before diving into the properties, let's visually inspect the transformation from a real-world space to the SVG viewbox space of an axis.

Coordinate System Transformations

The SVG image projects a real-world data range (rwMin to rwMax) on the SVG viewbox range (vbMin to vbMax).

Simple projection from real-world
to viewbox coordinates
rwMin O rwMax -0.4 0 0.8 -75 0 150 vbMin O vbMax

This is a simple projection without offset between origins, due to the fact that the ratio OrwMinrwMaxO is equal to OvbMinvbMaxO .

A more general projection is shown below, with real-world space above the axis line, and the SVG viewbox space below:

Complex projection from real-world
to viewbox coordinates
rwMin rwOffset O rwMax −0.7 −0.2 0 0.8 −100 0 40 200 vbMin O vbOffset vbMax

The real-world origin (0) is not projected on the viewbox origin (0) but at some offset (40). This shift is a consequence of the projection of the real-world data range on the viewbox data range.

The formula for the transformation from real-word to viewbox coordinates uses a scaling factor (SF) and an offset (vbOff):

xvb =(xrwrwOff)SF =xrwSF+ vbOff

Similarly, the transformation from SVG viewbox coordinates to real-world coordinates is done by

xrw =xvbvbOFFSF = xvb/SF+ rwOff

The second tranformation project the 1D axis space on the 2D viewbox space.

The orientation of an axis can be arbitrary and is defined by the angle (α), measured counterclockwise, value range is from 0 to 360 degrees. Zero degree corresponds to a horizontal axis, pointing to the right.

An axis at 225 degree angle
x y α x1 x2 y2 y1 −len / 2 cos α −len / 2 sin α len / 2 cos α len / 2 sin α

The black axes represent the viewbox axes of the SVG image. A circle at their intersection indicates the viewbox coordinate system origin (0,0). Note that the orientation of the y axis is down, not up as you might expect.

The green arrow, the z axis, represents a section of a function space dimension, with its origin (0) somewhat offset from the viewbox origin. Start and end points of this axis are projected on the viewbox axes, their viewbox coordinates are defined by the length of the axis (len) and the axis orientation angle (α).

Normally, the axis should extend to the image border, but for clarity, the z axis has been shortened a little bit.

SVG ViewBox Calculations

The viewbox coordinate system defines some fundamental values for the entire SVG image:

vbXMin
X axis minimum (left) value. Defined in the SVG element's viewBox x attribute.
vbYLen
X axis length. Defined in the SVG element's viewBox w attribute.
vbXMax
Length of the x axis. Computed.
vbXLen=vbXMax+vbXMin
vbYMin
Y axis minimum (top) value. Defined in the SVG element's viewBox y attribute.
vbYLen
Y axis length. Defined in the SVG element's viewBox h attribute.
vbYMax
Length of the y axis. Computed.
vbYLen=vbYMax+vbYMin

The viewbox coordinate system origin is always at (0,0).

Axis Properties Calculations

An axis line intersects the viewbox borders at two points. We need to find their coordinates in order to calculate their properties. Depending on which of the four viewbox sides an intersection point is located, one of four different formula sets has to be applied to find its coordinates.

But we are not yet there. Currently, we only know the axis orientation angle α1, supplied by the caller, and the viewbox properties, xMin, xMax, yMin and yMax:

To use the axis angle as selection criterium, we divide the viewbox into four areas, defined by the corners and the viewbox origin:

SVG viewbox areas
x y φ1 φ2 φ3 φ4 Area 1 Area 2 Area 3 Area 4

Then we can calculate the four angles φ1 to φ4:

φ1=atan−yMinxMax
φ2=atanxMinyMin+90
φ3=atanyMax−xMin+180
φ4=atanxMaxyMax+270

Now we have the criteria to locate the intersection points in one of the four areas and calculate their coordinates:

Intersection point coordinate calculation
function calculateIntersectionPoint( α ) {
	let x, y;
	α = α % 360 ;
	if ( α between φ1 and φ2 ) {
		y = yMin;
		x = −yMin tan α ;
		}
	else if ( α between φ2 and φ3 ) {
		x = xMin;
		y = −xMin tan α ;
		}
	else if ( α between φ3 and φ4 ) {
		y = yMax;
		x = −yMax tan α ;
		}
	else {
		x = xMax;
		y = −xMax tan α ;
		}
	return { x : x , y : y };
	}

	// Calculate the intersection points
const p1 = calculateIntersectionPoint( α1 + 180 );
const p2 = calculateIntersectionPoint( α1 );

NOTE that α2 can be calculated as α1 + 180 deg.

With the axis line coodinates at hand, we can calculate the axis length in viewbox units:

len=()

An axis has the following properties to support tranformations:

axAngle α
Axis orientation angle relative to the viewbox x axis, measured counter-clockwise. Range: 0 … 360 degree
Input, discarded after computations.
axMin
Minimum axis coordinate value. Computed.
If axAngle between 90 and 180 degree then
axMin=vbYMaxsinα
Len
Axis length, computed.
SFX
Scaling factor for the projection of axis values on the viewbox x axis. vbFTX = cos α
SFY
Scaling factor for the projection of axis values on the viewbox y axis. vbFTY = sin α
vbMin
viewbox range minimum (left) value
Input
vbLen
viewbox range length, vbMax - vbLen
Input
vbMax
viewbox range maxium (right) value
Computed
vbOff
viewbox value for real-word zero
Computed
rwMin
real-word range minimum (left) value
Input or computed
rwMax
real-word range maximum (right) value
Input or computed
rwOff
real-world offset value for viewbox zero.
Input or computed
SF
Scaling factor, used to scale real-world coordinates to viewbox coordinates
Computed

Depending on the two variables supplied by the user, one of the following calculation methods is used:

  1. rwMax and Offsrw given,
    SF and Offsvb are calculated, rwMin is defined implicitly
  2. rwMin and Offsrwgiven,
    SF and Offsvb are calculated, rwMax is defined implicitly
  3. rwMin and rwMaxgiven,
    SF, Offsrw and Offsvb are calculated. Offsrw will most probably not be a non-integer number.

Method 1 has the disadvantage that the viewbox origin might not map to a "clean" rwOffset, which is required if tickmarks should have "regular" values like 0.1, 0.2, 0.3 etc. Methods 2 and 3 avoid that, because the rwOffset can be chosen freely.

The scaling factor can be computed in three ways, which are equivalent:

SF = Maxvb Maxrw = Minvb Minrw = MaxvbMinvb MaxrwMinrw

Depending on what's available, a suitable variant can be chosen.

Computation Examples

We will use the following projection for the calculation examples:

Example 1 Overview
rwMin rwOffset O rwMax −0.7 −0.2 0 0.8 −100 0 40 200 vbMin O vbOffset vbMax

The following table outlines example 1 with input option 1:

Example 1 a
Input
vbMin −100
vbLen 300
rwMin −0.7
rwMax 0.8
Calculations
vbMax = vbLen + vbMin
= 300 − 100
= 200
rwLen = rwMax − rwMin
= 0.8 + 0.7
= 1.5
SF = vbLen / rwLen
= 300 / 1.5
= 200
rwOff = rwMin − vbMin / SF
= −0.7 + 100 / 200
= −0.7 + 0.5
= −0.2
vbOff = −rwOff ⋅ SF
= −0.2 ⋅ 200
= 40

The following table outlines example 1 with input option 2:

Example 1 b
Input
vbMin −100
vbLen 300
rwOff −0.2
rwMax 0.8
Computations
vbMax = vbLen + vbMin
= 300 − 100
= 200
SF = vbMax / (rwMax − rwOff)
= 200 / (0.8 + 0.2)
= 200
rwMin = vbMin / SF + rwOff
= −100 / 200 − 0.2
= −0.5 − 0.2
= −0.7
rwLen = rwMax − rwMin
= 0.8 + 0.7
= 1.5
vbOff = −rwOff ⋅ SF
= 0.2 ⋅ 200
= 40

The following table outlines example 1 with input option 3:

Example 1 c
Input
vbMin −100
vbLen 300
rwOff −0.2
rwMin −0.7
Computations
vbMax = vbLen + vbMin
= 300 − 100
= 200
SF = vbMin / (rwMin − rwOff)
= −100 / (−0.7 + 0.2)
= −100 / −0.5
= 200
rwMax = vbMax / SF + rwOff
= 200 / 200 − 0.2
= 1 − 0.2
= 0.8
rwLen = rwMax − rwMin
= 0.8 + 0.7
= 1.5
vbOff = −rwOff ⋅ SF
= 0.2 ⋅ 200
= 40

Tickmarks

Tickmarks on the axes should visualize the data range. They should be space equidistantly. To avoid rounding/dithering effect, the tickmark distance should be an integer value.

The tickmark distance is usually defined in value units. To continume the example, let's consider a tickmark distance of 0.1. We need to translate this value to viewbox coordinate:

vbTD=rwTDSF=0.1500=50

So, we have a tickmark every 50 viewbox units, but the first and last tickmarks should not interfere with the axis ends.


Code