Home | Math Display Experiments | svgPHPGrapher Syntax Examples
Page by Murray Bourne, IntMath.com. Last updated: 07 Jul 2019svgPHPGrapher Syntax Examples
svgPHPGrapher is a PHP-based mathematical grapher that produces svg images. It's a highly-modified PHP port of ASCIIsvg.js by Peter Jipsen.
The advantages of producing stand-alone svg output (as opposed to creating the graph with javascript, which is the case in ASCIIsvg and JSXGraph) is that it's quicker, because there is less for the browser to download (no javascript), and there is no javascript processing required during page load to produce the graph. It's also quicker on mobile devices, because the server does the processing work, rather than the device and its browser.
Download
Requirements You need a PHP-based server (on your local machine, or a real server).
You can download a working copy of svgPHPGrapher here:
svgPHPGrapher Example Chapters
Apart from the examples below, you can see example graph output from svgPHPGrapher in these IntMath chapters:
- Inequalities
- Polynomial Equations (Equations of Higher Degree
- Exponential and Logarithmic Functions
- Functions and Graphs
- Quadratic Equations
- Systems of Equations
On this page...
- Board Requirements
- Drawing a board with axes
- Plotting Mathematical Functions
- Lines
- Segments and inequalities
- Log-log & Semi-log Graphs
- Polar Graphs
- Parametric Curves
- Cardinal Splines
- Geometric Shapes (circle, square, etc)
Board Requirements
Somewhere at the top of your page, add the following (this grabs the latest version of svgPHPGrapher.php).
<?php include('../includes/getLatestsvgPHPGrapher.php'); $brdNum=0; // For svg id's ?>
Drawing a Board with Axes
The board, grid and axes above were produced using the following code:
<?php // Create the board $boardID = "svgphp-$brdNum"; $brdNum++; $width = 310; $height = 200; $xMin=-4; $xMax=6; $yMin=-3; $yMax=''; $padding = 15; list($svgArr, $htmlArr, $brdParams) = initBoard($boardID, $width, $height, $xMin, $xMax, $yMin, $yMax, $axesType, $res1, $res2, $res3, $padding); // Create the axes $xAxisTicks = 1; $yAxisTicks = 2; $axisNumbering = "labels"; $verticalGridGap = 2; $horizontalGridGap = 2; $gridAttrs = 'stroke:#777; stroke-width:0.5'; $axesAttrs = 'stroke:#444; stroke-width:1'; $xAxisVbl = "x"; $yAxisVbl = "y"; $arrows = 1; $svgArr[] = axes($xAxisTicks,$yAxisTicks, $axisNumbering, $verticalGridGap,$horizontalGridGap, $xAxisVbl,$yAxisVbl, $gridAttrs,$axesAttrs, $arrows, $brdParams); // Echo out the results doOutput($svgArr,$htmlArr); ?>
Explanation
Each board on the page automatically gets a sequential ID:
$boardID = "svgphp-$brdNum"; $brdNum++;
This is your graph size (in pixels):
$width = 310; $height = 200;
This is the range of possible values in the horizontal and vertical axes.
$xMin=-4; $xMax=6; $yMin=-3; $yMax='';
Leaving $yMax
as an empty string means the board will have equal-scaled axes.
This next one gives some space around the edge so you can see all of the axes numbers (a good default size is 15):
$padding = 15;
This is the first function call where you initialize the board. Nothing to do here, as you have defined all that's needed above.
list($svgArr, $htmlArr, $brdParams) = initBoard($boardID, $width, $height, $xMin, $xMax, $yMin, $yMax, $axesType, $res1, $res2, $res3, $padding);
Next is the function that echoes out the final output:
doOutput($svgArr,$htmlArr);
Adding the axes
The gaps between ticks on your axes:
$xAxisTicks = 1; $yAxisTicks = 2;
If you want the numbers on your axes to show, put "labels" if so, or an empty string if not: "":
$axisNumbering = "labels";
The gaps between grids (x-direction, then y-direction):
$verticalGridGap = 2; $horizontalGridGap = 2;
The $gridAttrs
and $axesAttrs
have defaults (see the top of the svgPHPGrapher function), but you can override colors and thickness if you want.
Here's where you state what axis variables you want. Leaving them blank (like $xAxisVbl = ''
) will mean no axis label will appear.
$xAxisVbl = "x"; $yAxisVbl = "y";
This is if you want arrows on your axes (value 1) or not (value 0).
$arrows = 1;
Now for the axes function. (If you put $yAxisTicks = ''
it means no y-axis.)
$svgArr[] = axes($xAxisTicks,$yAxisTicks, $axisNumbering, $verticalGridGap,$horizontalGridGap, $xAxisVbl,$yAxisVbl, $gridAttrs,$axesAttrs, $arrows, $brdParams);
This closes the svg tag and prints out the resulting graph to the screen:
$svgArr[] = '</svg>'; doOutput($svgArr,$htmlArr);
Multiples of `pi` on axes
The above axes use the following call to the axes
function:
$svgArr[] = axes(pi(),1,"pi,numbers",pi(),2, $xAxisVbl, $yAxisVbl, $gridAttrs, $axesAttrs, $arrows, $brdParams);
Plotting Mathematical Functions
The above polynomial was plotted as follows.
The function is declared like this:
$fun = "x^4 + 0.4x^3 - 6.49x^2 + 7.244x - 2.112";
You indicate the start and end x-values for the curve as follows (leaving $xStart
blank means the curve will start from the far left side of the graph, and leaving $xEnd
blank means the domain extends all the way to the right):
$xStart = 0.5; $xEnd = '';
You can set the number of points for the curve (lower numbers means a "chunkier" graph, higher means a smoother graph but larger file size):
$numPts = 80;
These are the attributes for the curve:
$attrs = 'stroke:#165a71; stroke-width:1.5; fill:none';
The syntax for the plot
function is:
$svgArr[] = plot($fun, $xStart,$xEnd, $numPts, $attrs,$brdParams);
The following syntax produces the dots at the x-axis intersections:
$attrs = 'stroke:none; fill:#f0f';
$svgArr[] = dot([1.2,0], 3, $attrs,$brdParams);
$svgArr[] = dot([0.5,0], 3, $attrs,$brdParams);
$svgArr[] = dot([1.1,0], 3, $attrs,$brdParams);
The parameters for the dot function are:
$center, $radius, $attrs, $brdParams
NOTE: Possible independent variables are `x` and `t`.
Vertical Graph Cases
Here's a common problem when constructing graphs using a computer-based grapher. If the graph becomes very steep, the only way to ensure all of it is included is to have a very large number of sample points. But this is not a good idea as:
- It results in a large file size
- It's not necessary to have a large number of points for the graph in parts where it is not so steep.
Let's illustrate the problem with an example. Here I'm trying to draw the graph of `x=y^2+2`. This is a relation (not a function) and I need to draw it in 2 halves:
- The top half, `y=sqrt(x-2)`; and
- The bottom half, `y=-sqrt(x-2)`.
As you can see, there is a gap near `x=2` where the top and bottom half should meet.
Here's the syntax I've used:
$svgArr[] = plot("sqrt(x-2)",'','',60, $attrs,$brdParams); $svgArr[] = plot("-sqrt(x-2)",'','',60, $attrs,$brdParams);
In svgPHPGrapher, there is a built-in attempt to solve this. When the graph is steep, the number of points sampled increases by a factor of 10. But even with this enhancement, you can see there still is a gap.
If I increase the number of points for each of the arms of the graph from 60 to 400 (giving a total of 800 points for the 2 arms plus the extra ones generated near the gap, I still get a gap.
Here's one way to solve this issue. We graph the inverse instead.
Graph the Inverse
It's possible in svgPHPGrapher to plot an inverse. In this example, the inverse of `y=+-sqrt(x-2)` is `x=y^2+2`. Here's what the graph looks like.
This is the syntax used this time:
$svgArr[] = plot("y^2+2",'','',40, $attrs,$brdParams);
Notice the use of the `y` variable. Internally, the grapher takes `y`-values from the minimum `y`-value to the maximum `y`-value. You'll notice that with only 40 sample points, the curve is smooth and connected, and there is no trouble when the graph is vertical at `x=2`.
Graphs with Discontinuities
Similar problems occur when we try to draw periodic graphs with vertical asymptotes, for example, `y=tan x`.
You can see that the grapher has connected the top of each positive arm of the curve to the bottom of the negative (supposedly infinite) negative next arm. You can also see the graph doesn't go down all the way to the minimum negative value.
Using the inverse function, we can get a better looking tan curve, with no joins and a small number of points.
What I've done here is to graph the inverse tan curve using the `y` variable: `"atan"(y)` (which means `arctan (y)`). I then replicate that single curve as many times as needed to cover the board.
Here's the syntax for the loop:
for($k=-pi(); $k<=2*pi(); $k+=pi()) {
$attrs = 'stroke:#165a71; stroke-width:1.5;fill:none';
$svgArr[] = plot("atan(y)+$k", $yMin,$yMax, 60, $attrs,$brdParams);
$attrs = 'stroke:#165a71; stroke-width:1; stroke-dasharray:5,5';
$svgArr[] = line([$k+pi()/2, $yMin], [$k+pi()/2, $yMax], $attrs,$brdParams);
}
The first 2 lines in the loop are responsible for repeating the single `"atan"(y)` curve, and the last 2 lines produce the dashed vertical asymptotes.
Here are the cuves `y="atan"x` (in magenta) and `x="atan"y` (in green) drawn on the one set of axes. Since they are inverses, they are reflections in the line `y=x`, which is also shown.
Here's another example where I've plotted a curve `y=sin x` and its inverse `x= sin y` on the one set of axes, and shown the reflection line `y=x`.
Here's another place where I needed to use the inverse function idea.
The 2 arms of the green hyperbola would have proved difficult using ordinary `f(x)` approach. This is the syntax used:
$attrs = 'stroke:#165a71; stroke-width:1.5; fill:none'; $svgArr[] = plot("sqrt((y^2 + 4)/3)",$yMin,$yMax,40, $attrs,$brdParams); $svgArr[] = plot("-sqrt((y^2 + 4)/3)",$yMin,$yMax,40, $attrs,$brdParams);
Finally, some graphs have both a steep part and a gently rising part. For example, the graph of `y=log_10 x`. Here I've drawn it in 2 parts.
The green part (quite shallow, above `y=-1`) is:
$attrs = 'stroke:#165a71; stroke-width:1.5; fill:none'; $svgArr[] = plot("(ln(x))/(ln(10))",0.1,'',40, $attrs,$brdParams);
The magenta part (almost vertical to start with, below `y=-1`) is:
$attrs = 'stroke:#f0f; stroke-width:1.5; fill:none'; $svgArr[] = plot("10^y",$yMin,-1,40, $attrs,$brdParams);
Line through 2 points
A line extends across the whole board. Here is the syntax for the above line, which passes through `(-2,-1)` and `(2,2)`:
$attrs = 'stroke:#165a71; stroke-width:1.5'; $svgArr[] = line([-2,-1], [2,2], $attrs,$brdParams);
Segments
Simple segment
Here is the syntax for the segment joining `(-3,2)` and `(3,-3)`:
$p = [-3,2]; $q = [3,-3]; $attrs = 'stroke:#165a71; stroke-width:2;'; $svgArr[] = segment($p, $q, $attrs,$brdParams);
Segments can be embellished with various markers (dots or arrows).
Segment-Arrow
This one is useful for drawing vectors. You can change the color and size of the arrow head.
Here is the syntax used for the first segment, pointing down:
$p = [1,-1]; $q = [1,-2]; $segAttrs = 'stroke:#f0f; stroke-width:2;'; $arrAttrs = 'triWidth:8; triHeight:12; stroke:#165a71; stroke-width:1; fill:#3df;'; $svgArr[] = segArrow($p, $q, $segAttrs, $arrAttrs,$brdParams);
Here is the second grey segment, with green arrow head:
$p = [2,-2.5]; $q = [5,-1]; $segAttrs = 'stroke:#888; stroke-width:2;'; $arrAttrs = 'triWidth:15; triHeight:20; stroke:#165a71; stroke-width:1; fill:#4f4;'; $svgArr[] = segArrow($p, $q, $segAttrs, $arrAttrs,$brdParams);
Dot-Segment-Dot
You can have different-size (and colored) dots on the end of your segments, as follows:
Here is the syntax used for the first "dot-segment-dot" segment. Note the 2 dots ("dot0" and "dot1" have their own attributes.)
$p = [-3,0]; $q = [4,2]; $dot0Attrs = 'radius:5; stroke:#165a71; stroke-width:2; fill:none'; $segAttrs = 'stroke:#165a71; stroke-width:2'; $dot1Attrs = 'radius:5; stroke:#165a71; stroke-width:2; fill:none'; $svgArr[] = dotSegDot($p, $q, $dot0Attrs,$segAttrs,$dot1Attrs, $brdParams);
Here is the second multi-colored and multi-sized one:
$p = [-3,-3]; $q = [4,-1]; $dot0Attrs = 'radius:10; stroke:#165a71; stroke-width:2; fill:#f0f; fill-opacity:0.4'; $segAttrs = 'stroke:#888; stroke-width:2;; $dot1Attrs = 'radius:3; stroke:none; fill:#f55'; $svgArr[] = dotSegDot($p, $q, $dot0Attrs,$segAttrs,$dot1Attrs, $brdParams);
Dot-Segment-Arrow
You can have your segment starting with a dot, and ending with an arrow, as follows:
The first 2 segments (on the left) share the same attributes:
$dotAttrs = 'radius:5; stroke:#165a71; stroke-width:2; fill:none'; $segAttrs = 'stroke:#165a71; stroke-width:2;'; $arrAttrs = 'triWidth:10; triHeight:15; stroke:#165a71; stroke-width:1; fill:none'; $svgArr[] = dotSegArrow([-2,-2], [2,-3], $dotAttrs, $segAttrs, $arrAttrs,$brdParams); $svgArr[] = dotSegArrow([-2,-1], [0,0], $dotAttrs, $segAttrs, $arrAttrs,$brdParams);
This is the segment with larger features at top right (I've toned it down by reducing the opacity):
$dotAttrs = 'radius:15; stroke:#165a71; stroke-width:2; fill:#165a71;opacity:0.5'; $segAttrs = 'stroke:#165a71; stroke-width:4;opacity:0.5'; $arrAttrs = 'triWidth:20; triHeight:20; stroke:#165a71; stroke-width:1; fill:#165a71;opacity:0.5'; $svgArr[] = dotSegArrow([5,1], [3,-1], $dotAttrs, $segAttrs, $arrAttrs,$brdParams);
This is the more subtle segment at bottom right:
$dotAttrs = 'radius:3; stroke:#165a71; stroke-width:2; fill:#165a71'; $segAttrs = 'stroke:#165a71; stroke-width:1'; $arrAttrs = 'triWidth:10; triHeight:15; stroke:#165a71; stroke-width:1; fill:#165a71'; $svgArr[] = dotSegArrow([5,-2.5], [2,-3], $dotAttrs, $segAttrs, $arrAttrs,$brdParams);
Drawing Inequalities Graphs
The above segments can be used to draw inequalities, as follows.
No y-axis, no grids, no y-axis variable name
We can "turn off" the y-axis like this:
Here is the syntax used:
$xAxisTicks = 1; $yAxisTicks = ''; $axisNumbering = "labels"; $verticalGridGap = 0; $horizontalGridGap = 0; $gridAttrs = ''; $axesAttrs = 'stroke:#444; stroke-width:1'; $xAxisVbl = "x"; $yAxisVbl = ""; $arrows = 0;
The above configuration is useful for presenting inequality solutions, as follows.
Open one end, closed the other:
The above example uses the "dot-segment-dot" type, like this:
$p = [-2,0]; $q = [4,0]; $dot0Attrs= 'radius:5; stroke:#165a71; fill:none; stroke-width:1.5'; $segAttrs = 'stroke:#165a71; stroke-width:3'; $dot1Attrs = 'radius:5; stroke:#165a71; fill:#165a71; stroke-width:1.5'; $svgArr[] = dotSegDot($p, $q, $dot0Attrs,$segAttrs,$dot1Attrs, $brdParams);
Open dot with pointing arrow:
The line segment, opening circle and final arrow in the above graph are achieved with:
$p = [2,0]; $q = [-2,0]; $dot0Attrs= 'radius:5; stroke:#165a71; fill:none; stroke-width:1.5'; $segAttrs = 'stroke:#165a71; stroke-width:3'; $arrAttrs = 'triWidth:10; triHeight:15; stroke:#165a71; stroke-width:1; fill:#165a71'; $svgArr[] = dotSegArrow($p, $q, $dot0Attrs,$segAttrs,$arrAttrs, $brdParams);
NOTE: dots are always circles, whether the axes are equal scaled or not.
Log-log and Semi-log Graphs
For log-log and semi-logarithmic graphs, we need to call the logAxes
function, instead of the ordinary axes
function.
Log-log graphs
Here is the syntax for the log-log graph type:
$xMin=0.1; $xMax=100; $yMin=1; $yMax=100; $padding = 28; $axesType = "loglog"; // log vertical, log horizontal list($svgArr, $htmlArr, $brdParams) = initBoard($boardID, $width, $height, $xMin, $xMax, $yMin, $yMax, $axesType, $res1, $res2, $res3, $padding); $gridAttrs = 'stroke:#ccc; stroke-width:1; shape-rendering:crispEdges'; $axesAttrs = 'stroke:#444; stroke-width:1; shape-rendering:crispEdges'; $xAxisVbl = "T"; $yAxisVbl = "P"; $arrows = 1; $svgArr[] = logaxes(1,1,"labels",1,2, $xAxisVbl, $yAxisVbl, $gridAttrs, $axesAttrs, $arrows, $brdParams); $attrs = 'stroke:#165a71; stroke-width:1.5; fill:none'; $svgArr[] = plot("40+30sin(x/5)",'',$xMax,300, $attrs,$brdParams);
Log-linear graphs
This is the syntax for the vertical logarithm and horizontal linear graph type:
Here's what you need to do for the log-linear graph type.
$xMin=-4; $xMax=10; $yMin=1; $yMax=100; $padding = 20; $axesType = "loglin"; // log vertical, linear horizontal list($svgArr, $htmlArr, $brdParams) = initBoard($boardID, $width, $height, $xMin, $xMax, $yMin, $yMax, $axesType, $res1, $res2, $res3, $padding); $gridAttrs = 'stroke:#ccc; stroke-width:1; shape-rendering:crispEdges'; $axesAttrs = 'type:log-linear; stroke:#444; stroke-width:1; shape-rendering:crispEdges'; $xAxisVbl = "T"; $yAxisVbl = "P"; $arrows = 1; $svgArr[] = logaxes(1,1,"labels",1,2, $xAxisVbl, $yAxisVbl, $gridAttrs, $axesAttrs, $arrows, $brdParams); //$dx,$dy,$labels,$gdx,$gdy, $xAxisVbl, $yAxisVbl, $attrs,$brdParams $attrs = 'stroke:#165a71; stroke-width:1.5; fill:none'; $svgArr[] = plot("40+30sin(x)",'',$xMax,300, $attrs,$brdParams);
Polar Graphs
For polar graphs, we need to call the polarAxes
function, instead of the ordinary axes
function.
Here is the syntax:
$rGap = 1; $degRad = "deg"; $qGap = 15; $angLabelGap = 30; $gridAttrs = 'stroke:#ccc; stroke-width:1; fill:none; shape-rendering:crispEdges'; $axesAttrs = 'stroke:#ccc; stroke-width:1; fill:none;'; $svgArr[] = polarAxes($rGap,"labels",$degRad,$qGap,$angLabelGap, $gridAttrs, $axesAttrs, $brdParams);
Here's the graph:
The gap between each angular axis (circle) in the grid (and the gap between numbers along the axis):
$rGap = 1;
Whether you want radians or degrees for your angle measure:
$degRad = "deg";
The gap between the radial axes (the lines) as an angle (in this case 15°):
$qGap = 15;
The gap between angle labels (the numbers around the outer circle, in this case 30°):
$angLabelGap = 30;
The next part is the standard grid and axes attributes:
$gridAttrs = 'stroke:#ccc; stroke-width:1; fill:none; shape-rendering:crispEdges'; $axesAttrs = 'stroke:#ccc; stroke-width:1; fill:none;'; $svgArr[] = polarAxes($rGap,"labels",$degRad,$qGap,$angLabelGap, $gridAttrs, $axesAttrs, $brdParams);
Now for the polar curve. Notice we use polarPlot
function.
We use "q" for the angle variable (q is commonly used for θ).
$attrs = 'stroke:#165a71; stroke-width:1.5; fill:none'; $svgArr[] = polarplot("3sin(2q)",0,2*pi(),100, $attrs,$brdParams);
The function paramaters are:
$fun,$x_min,$x_max,$points, $attrs,$brdParams
Parametric Curve
Here's a curve traced out by functions in the form `x = x(t)`, and `y=y(t)`. We need to empty the $plist array first, since it may contain values from an example above.
Here's the syntax used:
$plist = []; $attrs = 'stroke:#165a71; stroke-width:1.5; fill:none'; for ($t = -7*pi()/2; $t < 7*pi()/2+0.08; $t += 0.08) { $plist[] = [$t*cos($t), $t*sin($t)]; } $svgArr[] = path($plist,'','', $attrs,$brdParams);
Cardinal Splines
A cardinal spline is a smooth curve that passes through a set of points. This is different from a regression curve which is an "average" curve, and doesn't necessarily pass through any of the points.
You need to provide a list of points and some attributes, then generate the $plist
array. Finally, provide the $plist
array to the path
function.
The $numSegs
changes how smooth the curve is (its the number of points between each supplied point).
Here's the syntax:
$ptsArr = [ [2,2], [5,-2], [1,-1], [-3,-2], [-3,1] ]; $tension = 0.7; $isClosed = true; $numSegs = 20; $plist = getCurvePoints($ptsArr, $tension, $isClosed, $numSegs); $attrs = 'stroke:#165a71; stroke-width:1.5; fill:#165a71;fill-opacity:0.15'; $svgArr[] = path($plist,'','', $attrs,$brdParams); $attrs = 'stroke:none; fill:#165a71'; foreach($ptsArr as $pt) { $svgArr[] = dot($pt,3,$attrs, $brdParams); }
Geometric Shapes
Ellipses and Circles
Here we've drawn both an ellipse and a circle, using this syntax:
$attrs = 'stroke:#165a71; stroke-width:3; fill:#5a9fb5; opacity:0.5';
$svgArr[] = ellipse([-2,-3],1,4,"myEllipse", $attrs, $brdParams); //ellipse($center,$rx,$ry,$id, $attrs, $brdParams)
$attrs = 'stroke:#165a71; stroke-width:3; fill:#ff8; opacity:0.5'; $svgArr[] = circle([3,3],2,"myCirc", $attrs, $brdParams);
However, the circle isn't right because we haven't used equal-scaled axes. Second try:
This time, I set $yMax='';
so the axes would have equal scaling.
Arcs
For an arc, we need to set the beginning and end points, then the radius of the arc. We can also have our arc filled, or not.
This is the first one, which is filled:
$attrs = 'stroke:#165a71; stroke-width:3; fill:#5a9fb5; opacity:0.5'; $svgArr[] = arc([-2,2],[3,-2],4, $attrs, $brdParams);
Now for the second one, without fill:
$attrs = 'stroke:#165a71; stroke-width:3; fill:none; opacity:0.5'; $svgArr[] = arc([2,0],[0,2],2, $attrs, $brdParams);
Angle arcs
These are simply an arc with an arrow at the end, using the angleArcArrow function.
Function parameters:
angleArcArrow($p, $radius, $startAngle, $endAngle, $arcAttrs, $arrAttrs,$brdParams); { // pixels and degrees
This is the third angle arc shown (the one in the second quadrant:
$p = [0,0]; $q = [-1,2]; $svgArr[] = segArrow($p, $q, $segAttrs, $arrAttrs,$brdParams); $svgArr[] = angleArcArrow([0,0], 60, 0, 180 + 180*atan( $q[1]/$q[0])/PI(), $attrs, $brdParams);
Rectangles and Squares
Here's the syntax for the rectangle. The points are the bottom left, then top right of the rectangle.
$attrs = 'stroke:#165a71; stroke-width:3; fill:#5a9fb5; fill-opacity:0.1'; $svgArr[] = rect([-3.5,-1],[-1,3], $attrs,$brdParams);
Now for the square. We specify the bottom-left of the square, and the next parameter is its width.
$attrs = 'stroke:#165a71; fill:#ff8; stroke-width:1.5; rx:8; opacity:0.7'; $svgArr[] = square([1, -2], 2.5, $attrs,$brdParams);
Rounded corners are achieved using rx:8
Triangles
For triangles, we specify the 3 vertices. Here's the first one:
$p = [-4,-2]; $q = [-1,2]; $r = [-2,-2]; $attrs = 'stroke:#165a71; stroke-width:3; fill:#5a9fb5; fill-opacity:0.1'; $svgArr[] = triangle($p,$q,$r, $attrs,$brdParams);
Now for the second one:
$p = [-1,0]; $q = [4,0]; $r = [2,1]; $attrs = 'stroke:#165a71; fill:#ff8; stroke-width:1.5; opacity:0.7'; $svgArr[] = triangle($p,$q,$r, $attrs,$brdParams);
Current grapher version = svgPHPGrapher2018-12-18.php