NAME

plotly3D.pl - Adds Graph3D, an object for creating 3D parametric curves and 3D parametric surface plots using the plotly JavaScript library. https://plotly.com/javascript/

DESCRIPTION

Loading this macro adds the Graph3D method which creates a 3D graph object. The graph object can be configured by a list of options of the form "option => value" (see below).

loadMacros('plotly3D.pl');
$graph = Graph3D(options => value);

Use the addCurve method to add a parametric curve to the graph. The following adds a helix to the graph. The first array is the parametric functions x(t), y(t), and z(t), and the second array is the bounds with the optional number of points to plot.

$graph->addCurve(['3*cos(t)', '3*sin(t)', 't'], [0, 6*pi, 150]);

Use the addFunction method to add a two variable function surface to the graph. The following adds the function f(x,y) = x^2 + y^2. The first input is the function in terms of x and y, followed by the x-bounds and y-bounds with the optional number of points to plot. Note the total points computed is the product of the two numbers given.

$graph->addFunction('x^2 + y^2', [-4, 4], [-4, 4]);

Use the addSurface method to add a parametric surface to the graph. The following adds a sphere of radius 3. The first array is the parametric functions x(u,v), y(u,v), and z(u,v), followed by the u-bounds and v-bounds with optional number of points to plot. Note the total points computed is the product of the two numbers given.

$graph->addSurface(
    ['3*sin(v)*cos(u)', '3*sin(v)*sin(u)', '3*cos(v)'],
    [0, 2*pi, 30],
    [0, pi, 30]
);

Output the graph in PGML using the Print method.

[@ $graph->Print @]*

Multiple curves surfaces can be added with the appropriate methods.

PARAMETRIC CURVES

The addCurve method takes two arrays as input followed by a list of options. The first array is three parametric functions, followed by the minimum, maximum, and optional number of points to plot. If the number of points is not given, it defaults to 100.

$graph->addCurve(
    [xFunction, yFunction, zFunction],
    [tMin, tMax, tCount],
    options
);

The additional options are given in a 'option => value' format. The current available options (and defaults) are:

width => 5

The width/thickness of the curve.

colorscale => 'RdBu'

The colorscale for the curve, which is a heatmap based on the z-value of the curve. See "COLORSCALES" below for more information.

opacity => 1

The opacity of a curve between 0 and 1.

funcType => 'jsmd'

How to interpret the parametric functions. See "FUNCTION TYPES" below for more information.

variables => ['t']

The variable to use in the JavaScript function.

PARAMETRIC SURFACES

The addSurface method takes three arrays as input followed by a list of options. The first array is three parametric functions, followed by the minimum, maximum, and optional number of points for each of the two variables. If the number of points is not given, it defaults to 20.

$graph->addSurface(
    [xFunction, yFunction, zFunction],
    [uMin, uMax, uCount],
    [vMin, vMax, vCount],
    options
);

The additional options are given in a 'option => value' format. The current available options (and defaults) are:

colorscale => 'RdBu'

The colorscale for the curve, which is a heatmap based on the z-value of the surface. See "COLORSCALES" below for more information.

opacity => 1

The opacity of a curve between 0 and 1.

funcType => 'jsmd'

How to interpret the parametric functions. See "FUNCTION TYPES" below for more information.

variables => ['u', 'v']

The variables to use in the JavaScript function.

FUNCTIONS

The addFunction method takes a string, which is a function f(x,y), followed by two arrays which give the x-bounds and y-bounds, with optional number of points to plot. This is a wrapper for addSurface in which the variables are x and y. See addSurface for the list of options. funcType => 'data' cannot be used with functions, use addSurface directly to plot data.

$graph->addFunction(
    'zFunction',
    [xMin, xMax, xCount],
    [yMin, yMax, yCount],
    options
);

COLORSCALES

The colorscale colors the points of the curve/surface based on the z-value of the points. The colorscale can be one of the following predefined names:

'BdBu', 'YlOrRd', 'YlGnBu', 'Portland', 'Picnic', 'Jet', 'Hot'
'Greys', 'Greens', 'Electric', 'Earth', 'Bluered', or 'Blackbody'

You can also define a custom colorscale as a list of colors for values ranging from 0 to 1. For example the default RdBu is the following colorscale (note this must be a string since the array is passed to JavaScript):

"[[0, 'rgb(5,10,172)'], [0.35, 'rgb(106,137,247)'],
  [0.5, 'rgb(190,190,190)'], [0.6, 'rgb(220,170,132)'],
  [0.7, 'rgb(230,145,90)'], [1, 'rgb(178,10,28)']]"

A colorscale can have any number of color points between 0 and 1. To make the plot a single color, set the color for 0 and 1 to be the same:

"[[0, 'rgb(0,200,0)'], [1, 'rgb(0,200,0)']]"

FUNCTION TYPES

The functions to generate the plot can be either mathematical, JavaScript, Perl, or raw data, and this can be controlled using the funcType => type option in addCurve or addSurface methods. The valid types are:

jsmd

This is the default type, in which the functions are converted from math formulas into JavaScript functions to generate the plot. This should accept standard mathematical notation with some exceptions: Multiplication must be an explicit "*": "ucos(v)" is not accepted, but "u*cos(v)" is. JavaScript considers "-u^2" not well defined, instead use "-(u^2)".

js

The functions are interpreted as raw JavaScript functions. The functions will be passed the defined variables and return a single value. This function type is useful to plot more complicated functions, such as piecewise functions with if/then statements. For example, this graphs the surface of the plane in the first octant that passes through the points ($a,0,0), (0,$b,0), (0,0,$c):

($a, $b, $c) = (5, 3, 7);
$graph->addSurface(
    [
        "return ($b*u < $a*v ? 0.5*u : u - 0.5*$a/$b*v);",
        "return ($b*u > $a*v ? 0.5*v : v - 0.5*$b/$a*u);",
        "const x = ($b*u < $a*v ? 0.5*u : u - 0.5*$a/$b*v);"
            . "const y = ($b*u > $a*v ? 0.5*v : v - 0.5*$b/$a*u);"
            . "return $c - $c/$a*x - $c/$b*y;",
    ],
    [0, $a],
    [0, $b],
    funcType => 'js',
);
perl

The functions are interpreted as Perl subroutines. The functions will be passed the appropriate number of inputs, and return a single value. This uses the WeBWorK server to generate the points for the plot, and can slow down the rendering of the problem. Using the JavaScript methods are preferred for this reason. Here is an example of plotting a sphere of radius $R.

$R = 5;
$graph->addSurface(
    [
        sub { return $R*cos($_[0])*sin($_[1]); },
        sub { return $R*sin($_[0])*sin($_[1]); },
        sub { return $R*cos($_[1]); }
    ],
    [0, 2*pi],
    [0, pi],
    funcType => 'perl',
);
data

The functions are interpreted as a nested array of data points to be sent directly to plotly to plot. The nested array needs to be a string, since it is passed to JavaScript to plot. This array lists all of the points which are used to create the surface. For example to plot a surface with 9 points, use something like:

$graph->addSurface(
    [
        "[[x1, x2, x3], [x4, x5, x6], [x7, x8, x9]]",
        "[[y1, y2, y3], [y4, y5, y6], [y7, y8, y9]]",
        "[[z1, z2, z3], [z4, z5, z6], [z7, z8, z9]]"
    ],
    [0,0],
    [0,0],
    funcType => 'data'
);

This plots a surfacing using the points (x1,y1,z1), (x2,y2,z2), ..., and (x9,y9,z9). The addSurface method requires bounds, but they are not used, so [0,0] needs to be included, but is ignored. Using the perl method to first generate the arrays, then copying the result and using the data method can be useful to speed up rendering of nonrandomized plots.

Graph3D OPTIONS

Create a graph object: $graph = Graph3D(option => value) The valid options are:

height

The height of the div containing the graph.

width

The width of the div containing the graph.

title

Graph title to print above the graph.

style

CSS style to style the div containing the graph.

bgcolor

The background color of the graph.

image

Image filename to be used in hardcopy TeX output. If no image is provided, the hardcopy TeX output has a message that image must be viewed online.

tex_size

Size of image in hardcopy TeX output as scale factor from 0 to 1000. 1000 is 100%, 500 is 50%, etc.

tex_border

Put (1) or don't put (0) a border around image in TeX output.

scene

Add a JavaScript scene configuration dictionary to the plotly layout. This can be used to configure various aspects of the plot, such as the aspect ratio, and view range of the 3D axes. The scene is a string which contains a JavaScript dictonary to pass to plotly. Example:

scene => 'aspectmode: "manual",'
       . 'aspectratio: {x: 1, y: 1, z: 1},'
       . 'xaxis: { range: [0,2] },'
       . 'yaxis: { range: [0,3] },'
       . 'zaxis: { range: [1,4] }'

See https://plotly.com/javascript/3d-axes/ for more examples or https://plotly.com/javascript/reference/layout/scene/#layout-scene for the API reference.