A lightweight framework for making interactive mathematical graphics with a focus on refinement, stability, and performance of finalized presentation.
Plots are composed as a container marked with the Plot class and holding multiple layers of various types. Example structure:
<div class="Plot" PlotRange="[0, 7]">
The layers are rendered in reverse order: the first one is placed at the bottom of the final illustration with each next layer getting stacked on top of the previous one. To draw the axes underneath everything else in the code above, for example, the first two layers should be swapped.
<svg class="Layer" id="plotCanvas"></svg>
<div class="Layer" Axes Arrowheads Ticks=1></div>
<svg class="Layer" id="epilog"></svg>
<div class="Label">Example</div>
</div>
Graphical content can be added using the provided plotting methods and combined with static elements hardcoded directly into the respective layers:
<svg class="Layer" id="plotCanvas">
<circle r=0.5 cx=2 cy=1 ></circle>
</svg>
Overall plot properties are set up via html attributes, while the appearance of any component is customized with CSS rules written for the provided classes. Interactive controls can be made from standard HTML inputs and connected to responsive graphical components using simple update queue.
The code for importing the framework:
<script defer src="https://cdn.jsdelivr.net/gh/Eltaurus-Lt/SquirrelsAndSpace/pLTlib/pLTlib.js"></script>
Should be appended to the
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/Eltaurus-Lt/SquirrelsAndSpace/pLTlib/pLTlib.css">
<script defer src="https://cdn.jsdelivr.net/npm/mathjax@4/tex-mml-chtml.js"></script>
<head> of an .html file. The last line is for importing MathJax and can be ommited if LaTeX fonts and formatting are not used.
Scripts relying on pLTlib methods should be wrapped in a DOMContentLoaded callback to make sure the dependencies are loaded before being used:
<script>
(scripts outside of the
… // non-plt scripts
document.addEventListener("DOMContentLoaded", () => {
… // scripts creating plt objects
plt.dynamic.push((dynamic_vars) => {
… // scripts fot dynamic plt content
});
});
</script>
DOMContentLoaded can predefine framework's input parameters programmatically ahead of its initialization).
Independent illustrations are intended to be coded in individual .html files (each can contain multiple .Plot objects), which then could be embedded into a collective article using the following tag:
<iframe src="plot.html" width="600px" onload="window.addEventListener('message', e=>{if(e.source===this.contentWindow && e.data && e.data.type==='embed-height'){this.style.height=e.data.height+'px';}});"></iframe>
Replace plot.html with the actual path to the plot file being embedded. The width attribute can be modified as needed and additional attributes, like classes and styling, can be appended as usual.
The included onload function ensures the height of the embedded plot is fit to the proper aspect ratio of the referenced plot html and accurately reacts to page resizing.
Types of layers to be used in plot composition. A plot can contain any number of layers of any kind.
Layers for adding various plot lines and elements of vector graphics to the overall illustration.
<svg class="Layer"></svg>
Coordinates and their units are matched with the plot space. In particular, vertical axis is directed upward, as expected from a mathematical plot, instead of going down, as is the default for svg (and 2D images in general). Note, that if a plot has different scales on horizontal and vertical axes, graphical elements will appear accordingly stretched or squashed. Line stroke thickness is an exception from this rule and is set in pixels of the screen space, remaining fixed independently of the plot's display size. When plotting points, to ensure circular appearance at arbitrary ScaleRatio, a markup layer with markers should be used instead of a vector layer with <circle> tags.
Layers for adding elements, that should be positioned in the plot space, but sized in the screen space. This includes construction elements, such as axes, grids, ticks, etc., plot markers, labels, as well as any kind of custom insets.
<div class="Layer"></div>
The plot-space coordinates of a markup-layer element can be set via left and bottom CSS properties for the x and y respectively (note that top and right cannot be used for this purpose). For the respective values, the % unit is getting repurposed as the universal plot-space length unit (and, consequently, loses its standard CSS meaning). For example, the following CSS rules put an element exactly at the point with coordinates (1.4, 2):
left: 1.4%; /* x = 1.4 */
By default, all elements are aligned to the specified position with their centers. To change the location of an anchor point,
bottom: 2%; /* y = 2 */
translate CSS property should be set to
translate: Ah Av;
with Ah being the anchor point's relative horizontal position (0 = left side, -100% = right side, -50% = horizontal middle) and Av being the relative vertical position (0 = bottom side, -100% = top side, -50% = vertical middle). For example:
translate: 0 -100%; /* sets the top left corner as the anchor point */
Layers for drawing with canvas methods.
<canvas class="Layer"></canvas>
Resolution is defined using layer attributes and stays fixed independently of the actual displayed plot size. Useful for ArrayPlot's, in particular.
Layers for producing raster assets rendered at screen resolution, regardless of the overall displaying size of the plot.
<canvas class="Layer glsl"></canvas>
Serve as attachment points for GLSL fragment shaders. Plot-space coordinates are accessible from within a shader as
vec2 xy = (gl_FragCoord.xy - plotOrigin) / plotResolution;
Any element inside a .Plot container, if not marked with the Layer class, keeps its access to the default page space and can be positioned and sized as ordinary HTML, using px, % (which, in this case, would measure fractions of the width and height of the .Plot itself), or any other HTML length units. This, in particular, can be used to add plot legends, buttons, and other overlays. PlotLabels are also generated as non-layer elements.
Basic controls can be build using native html <input> elements. To make a slider, for example, the following should be put anywhere inside the body of the plot html file (outside of the .Plot container itself):
<input pltvar="k" type="range" min=0 max=1 step="any" value=0.5>
The attributes here are standard html slider parameters, which can be used to configure the inputs. The only part essential for the plt framework is the pltvar property that indicate a text name for the JavaScript variable to be controlled by the slider. No other setup for the input element itself, regardless of the type, is required to make it fully functional.
For components of the plot to dynamically respond to changing inputs, their parameters should be updated on each interaction. To automate the associated setup, plt provides the dynamic object, which can be used to push individual update functions into a unified queue:
plt.dynamic.push(({k, t}) => {
In this example, the radius of the circle will get updated in accordance with the provided function each time the value of either
circleL.setAttribute("r", 1 + k * Math.sin(t) );
});
k or t is modified. Note that, in general, the arguments referenced in the curly braces can be listed in any order, as long as their names correspond to pltvar values of <input> elements present in the document (a function can use only the necessary subset of pltvar variables, not every <input> has to be referenced in each instance).
The functions from plt.dynamic are automatically connected to the input elements they depend upon and get called back in real time when the associated inputs are being interacted with. The callback execution follows the order in which the functions were originally pushed in. This, in particular, can be leveraged to avoid excessive reevaluations by calculating all reusable values at the head of the queue and saving them as global variables to be accessable from successive functions. Such optimisation is especially important for demanding computations, like ODE integration.
To manually trigger an update, the .update method can be called, specifying the the pltvar variables to be refreshed as names in string format:
plt.update("t", "ω"); (WiP)
Calling update() without arguments performs a global update, refreshing all variables and the whole dynamic queue. In particular, update() is useful for initiating the state of the plot at the end of the script, after all dynamic functions were pushed to the queue.
Extra interactivity, such as plot reacting to keyboard events or mouse clicks on its canvas, can be developed by adding a suitable event listener. The values of auxiliary dynamic variables not represented by any explicit <input> controls are to be stored in dummy html elements, which can be placed anywhere inside the document (by default, they are not being displayed in any way):
<var pltvar="ω" value=42 ></var>
Code for modifying the value of the respective variable from the event listener:
document.querySelector('var[pltvar="ω"]').value = ...;
Followed by the manual plot state update described in the previous section.
Attributes are used to define structural parameters of the plots and are included inside the opening tag of the respective element:
<div class="Plot" PlotRange=5 AspectRatio=1 ... >
Can be listed in arbitrary order. The only mandatory attribute is PlotRange – any other can be ommited, if the respective setting is not needed.
Attributes attached to the div.Plot object itself (control overall sizing):
PlotRange="[Xmin, Xmax]" sets horizontal range of the plot. Providing a number A instead of an interval is interpreted as [-A, A].AspectRatio=X defines the width-to-height ratio of the plot in screen space. If not explicitly set, defaults to the golden ratio ≈1.618.ScaleRatio=X defines the 1Y:1X ratio of unit lengths along vertical and horizontal axes. Equals 1 by default, asserting uniform scaling of the plot space to the screen space mapping.RangePivot="[X0, Y0]" (WiP) .
Note that vertical range cannot be set directly, because it depends on the properties above, which are more important for final presentation of the illustration than exact Ymin and Ymax values (aspect ratio is typically expected to be standardized across an entire article, while scale ratio is required for plotting data without distortion).
Attributes attached to a div.Layer element:
<div class="Layer" Frame Grid Ticks=1 TicksRight="[[.5, '$\\frac{1}{2}$'], 1, [1.618, '$\\varphi$']]" ... >
Primarily control overlayed details, such as ticks and text labels. The details do not have any default values – plots display what have been explicitly declared. Attributes that appear without values practically serve as toggles, with the result depending only on whether their name is attached to the <div> at all:
Axes toggles axes on the HTML layer. Individually, horizontal and vertical axes can be toggled by AxisX and AxisY respectively. Arrowheads toggles arrowheads on the ends of axes (have no effect on layers without any of the Axes attributes). ArrowheadRight, ArrowheadTop (as well as ArrowheadLeft and ArrowheadBottom) control individual ends of each axis. Frame toggles frame around the HTML layer. Ticks=X puts equidistant tick marks with interval "X" (in plot units) on Axes or Frame of the layer. When both attributes are present, Ticks applies the same setting to both of them. If that is not the desired effect, a separate HTML layer should be created so that either Axes or Frame could be moved over to it. This way, two independent Ticks setups could be made.
Arrowheads and Axes, Ticks can be split into two separate attributes – TicksX and TicksY – for horizontal and vertical directions respectively. For the frame ticks, TicksX can be further split into TicksTop and TicksBottom and TicksY can be split into TicksLeft and TicksRight. All variants of the attribute can be used in combination, with the more specialized one always taking priority. Note that empty specialized setting, like TicksRight="", overwrites more general ones, effectively removing any ticks from the provided side or direction.Ticks="[X1, X2, X3, ...]" is an alternative form for the Tick attribute value to put the ticks at the explicitly set positions X1, X2, etc. Same specialized attributes for each individual side and direction are supported.
Xi themselves can be either numbers, or a pair of a number and a string, like in the example above. The latter labels the respective tick with the text from the provided string, instead of the number itself. The string should be enclosed in single quotes. Xi do not have to all be of the same type, the two formats can be freely mixed. Subticks=N uniformily subdivides interval between consecutive ticks into N parts. Works only with the equidistant format of Ticks. Similar to the Ticks attribute itself, SubticksX, …Y, …Bottom, …Left, …Top, …Bottom are available for axes and the frame. Grid toggles a coordinate grid on the back of the HTML layer. Relies on the Tick attribute (TicksX / TicksY) to control the spacing of the grid lines. Labeling attributes:
TickLabels toggles automatic labeling of all the ticks on the layer (manual labels provided in the Tick arrays do not require this attribute to be displayed).SubtickLabels (WiP) similarly toggles automatic labeling of subticks on the layer.MergeZero toggle displaying a single unified label at the axes' intersection instead of showing two separate zeroes.AxesLabels="['labelX', 'labelY']" provides text labels to mark the ends of the axes. Requires Axes (or AxisX / AxisY) attribute. Either of the labels can be an empty string to be omitted. Individual attributes AxisLabelX and AxisLabelY are also supported. FrameLabels="['labelBottom', 'labelLeft']" provides text labels to mark the sides of the frame. Can be supplied with an array of four strings instead of two to mark all the sides (starting from the bottom an proceeding in the clockwise direction). Either of the strings can be an empty string to be omitted. All six specialized variants are supported for labeling individual sides or both sides in a certain direction: FrameLabelX, FrameLabelY, FrameLabelBottom, FrameLabelLeft, FrameLabelTop, FrameLabelRight. All text labels (including manual tick labels) support MathJax for LaTeX expressions.
Appearance of any plot component is controlled directly, using standard CSS. Styling code can be put in a <style>...</style> tag (or referenced from a separate file) inside the <head> of the document after pltlib import tags.
Inherited. --Color, --Thickness, --PointSize, --TickLength, --Dashing, --DashingPeriod.
To reset bounding to plot origin for a specific object (e.g., plot legend):
translate: 0;
Classes .Axis, .Arrowhead, .Frame, .Gridline, .Tick, as well as general .Label class, are provided for targeting certain kinds of elements generated from attributes. Example uses:
.Frame {
All generated components are
--Thickness: 5px; /* inherited by the frame ticks */
}
.Axis, .Gridline {
--Color: green; /* inherited by the axes' ticks and arrowheads */
--Dashing: 0.5;
--DashingPeriod: calc(4 * var(--Thickness));
}
.Tick {
--TickLength: 15px;
--Thickness: 2px; /* overrides inherited value */
}
.Axis {
justify-content: 0; /* tick alignment */
}
<div> elements. Axes, frames, and gridlines are direct children of HTML layers they are set up for. Frame ticks are attached to edges of a frame, while arrowheads and axes ticks are parented to respective axes. Labels of all kinds are direct descendants of the elements they are labeling.
Children elements are set up to inherit basic properties from their parents by default. In particular, ticks inherit thickness and color from their axes and frame (which can be overriden by a css rule targeting ticks).
For selecting subsets of the components within a certain kind, supplementary classes can be appended to selectors. Classes .X and .Y target any element (axis, arrowhead, gridline, tick, ...) associated with respective direction:
.Axis.X,
Additionally, classes
.Frame .Tick.Y {
border-color: #bada55;
}
.Arrowhead.X {
background-color: gold;
}
.Bottom, .Left, .Top, and .Right are available for arrowheads, frame labels, frame edges, and frame ticks. Subticks do not have a dedicated class, instead they are marked with an auxiliary .Sub class on top of the general .Tick and can be targeted with .Sub.Tick selector.
Similarly, different kinds of labels do not have distinguishing classes of their own. Instead, they can be selected using the class of its parent element and the child combinator:
.Plot > .Label {
font-size: 20px;
}
.Tick > .Label {
font-size: small;
}
transform: translate(-100%, 100%);
. To align the element to the coordinates with its center, transform values (-50%, 50%) can be used. This, in particular, is the method for adding plot Markers.
For controlling tick alignment relative to its parent axis (or frame edge), the translate property can be used:
translate: 0 0; centers a tick on the line,translate: 0 -50%; (default) moves it entirely inside the plot,translate: 0 50%; moves the tick outside.labels (WiP)
For styling elements created in the plot scripts, custom classes can be assigned in the .add() method. Some extra class names have predefined appearance settings associated with them:
.PlotLine for plotted functions automatically assigns them appropriate thickness and different colors depending on the ordinal number of the vector layers the lines are added into (in accordance with the default Wolfram Mathematica color scheme)..PlotMarker (WiP)Arrowheads (WiP)
Normal and tucked.
The framework puts no restrictions on the number and positions of plot elements and inputs. They can be arranged freely, using any means available in HTML. In particular, CSS Grid is useful for making multi-panel layouts and complex interfaces.
It should be noted, that, by default, height of a .Plot element is connected to its width through the AspectRatio. If a different CSS rule is manually set for the height, it might be practical to change AspectRatio to a sufficiently small value and add overflow-y: hidden; to the .Plot styles.
Provided implementations of common numerical methods covering basic needs of plotting functions and solving algebraic and differential equations. Because finalized illustrations imply predefined well-posed conditions, the provided routines perform no data checks and rely on the incoming arguments always having appropriate formats. To further cut on overhead and avoid jittering typically associated with real-time auto-tuning, all parameter values are taken in explicitly.
Methods called from the plt object that return path data in the d-string format expected by a <path> element of a vector layer:
const vectorLayer = document.querySelector("svg.Layer");
Here
vectorLayer.add("path", "PlotLine").setAttribute("d", path_string);
.add is the provided utility method for creating and attaching plot elements, white the path_string is a result returned by either of the path methods listed below (for static plots, each has a simplified Plot counterpart):
LinePath(f, xs)
Path for an analytical single-valued function f(x) drawn as a polyline over an array of argument values xs:
path_string = plt.LinePath(x => Math.cos(x), plt.Subdivide([0, 10], 25));
Here x => Math.cos(x) is a JS arrow function expression for f(x)=cos(x), and plt.Subdivide(...) is an array of x values, obtained by applying the respective utility method to the [0, 10] interval.
BezierPath(f, df, xs)
Method similar to the LinePath above, which returns a cubic Bezier spline instead of straight-line segments to produce a completely smooth result with fewer points. Requires additionally providing explicit analytical expression for the derivative df(x) of the f(x) function:
plt.BezierPath(x => Math.cos(x), x => -Math.sin(x), xs)
ParametricLinePath(f, ts)
Variation of the LinePath for hodographs of 2D vector functions, such as
t => [Math.cos(x - 0.3), Math.sin(2 * x)]
ParametricBezierPath(f, df, ts)
2D vector version of the BezierPath and the smooth alternative to the ParametricLinePath. Requires providing the derivative df, which itself should also be a 2D vector function.
ListLinePath(xys)
Returns a polyline constructed from the xys array of 2D points [x, y]. Suited for plotting table functions. In particular, the ones obtained as numerical solitions of differential equations.
ListBezierPath(xys)
Bezier equivalent of the ListLinePath. Works similarly to Adobe Illuatrator Curvature tool. Autocloses curve if the first point coincides with the last (WiP).
Note that multiple paths constructed using different methods can be stitched together with the .merge() utility function.
Methods abstracting the creation of required elements with all required data attributes assigned internally. Take in optional classList argument to mark the created elements for selective styling.
Plot(path, classList = "")
Called from a vector layer, assigns the path as the d attribute, and returns the created <path> element. Better suited for static plots – dynamically modified paths should rely on setting path explicitly, as Plot will create a new element each time it is called instead of updating existing layout.
Specialized versions for each of the path methods are available. For example, LinePlot(f, xs, classList) is equivalent to
vectorLayer.Plot(plt.LinePath(f, xs), classList);
Full list of specialized methods consists of LinePlot, BezierPlot, ParametricLinePlot, ParametricBezierPlot, ListLinePlot, ListBezierPlot. Each of the methods takes in the arguments equivalent to their …Path counterpart plus an optional classList.
ListPlot(xys, classList = "")
A method for plotting a table function as a collection of points instead of a continuous line. Called from a markup layer, returns an array of marker elements:
markupLayer.ListPlot(plt.ListPlot(xys));
Provided methods for solving algebraic and differential equations. Called from the plt object.
LocateRoot(f, [xa, xb], Imax = Infinity)
Calculates a root located in the interval [xa, xb] of an algebraic equation f(x)=0 using the Brent–Dekker method up to the precision set by $Precision. Returns undefined if f(xa) and f(xb) do not have opposite signs. Imax is an optional parameter that allows placing a hard limit on the number of iterations performed, although even with the infinite value (default) the method is guaranteed to take no more than Log₂(|xb-xa|/$Precision) steps (if the hard limit is reached, the error of the returned value will be greater than $Precision).
xroot = plt.LocateRoot(x => (Math.tan(x) - x/5), [2, 5]);
FindRoot(f, df, x0, Imax, damp = 1)
Searches for a root of an algebraic equation f(x)=0 using Newton–Raphson method starting from the point x0. Executes until precision $Precision is achieved or the maximum number of iterations Imax is reached. In the latter case, returns undefined. The argumet Imax should be set explicitly to a finite value, because unlike LocateRoot the method is not guaranteed to converge. Requires providing analytical derivative df(x) of the function f(x) (both should be single-valued functions).
For sufficiently well-behaved functions with simple derivatives converges faster than LocateRoot and does not require a pre‑estimated interval, but does not guarantee that the returned root will be close to x0 or that any root will be found at all.
Allows specifying an optional damping factor, which serves as a step multiplier (when the function is called with 4 arguments, damp defaults to 1). Values less than 1 improve stability, but require more steps to converge. Values greater than 1 can be useful for improving convergence near roots with multiplicity > 1.
NSolve(f, x0s, Imax)
Searches for multiple roots of the f(x)=0 equation using LocateRoot for each interval between the consecutive values from the x0s array. Returns either an array of the found roots (filtering out undefined results) or an empty array (if no roots were detected). Does not search for more than one root per interval.
Recommended for most cases. Use example:
sol = plt.NSolve(x => (Math.sin(1/x) - x*x), plt.Subdivide([.05, 1], 100));
NRSolve(f, df, x0s, Imax, damp = 1)
Searches for multiple roots of the f(x)=0 equation using FindRoot for each of the x0 values from the array x0s. Returns the roots sorted in ascending order, filters out repeated values based on $Precision.
NDSolve(f, x0, ts)
Integrates differential equation x'(t)=f(t, x) with initial conditions x(ts[0])=x0 over the array ts of t values using Runge–Kutta method (rk4). The method supports x being either a real number or a vector (array) of arbitrary length. In the vector case, f(t, x) must expect its x argument to be an array and return the result as an array of the same length.
Example use:
function f(t, [x, y, z]) {
Returns the result as an array of value pairs
return [
2 * (y - x),
x * (15 - z) - y,
x * y - 0.2 * z
];
};
sol = plt.NDSolve(f, [1, 1, 10], plt.Subdivide([0, 100], 1000));
[ti, xi]. Plotting example:
svgLayer.ListLinePlot( sol.map( ([t, [x, y, z]]) => [x, z] ));
Quality-of-life features automating certain frequently repeated patterns.
Subdivide([x0, x1], N)
Uniformly subdivides the specified interval into N subintervals. Returns a single array of values with the first and the last one coinciding with x0 and x1. Called from the plt object:
plt.Subdivide( [0, Math.PI / 2], 50 ) // returns [0, 0.01 π, 0.02 π, ..., 0.5 π]
.add(elementType, classList = "")
Main method for creating svg and html elements and attaching them to vector and html layers respectivelly. Called from a layer object, returns a reference to the created element. Allows additionally specifying a list of classes (as a single string, separated by spaces) as an optional second argument to mark the element and be used for styling. Example uses:
const svgLayer = document.getElementById("plotCanvas");
const lineL = svgLayer.add("line");
lineL.setAttribute("x1", 1);
lineL.setAttribute("y1", 2);
const divLayer = document.querySelector("div.Layer");
const textL = divLayer.add("span", "label large");
textL.innerText = "Plot Label";
Additionally can be called from a div.Plot container to dynamicaly make new layers (WiP). The elementType in such case should be one of the following: "svg", "html", "canvas", "glsl".
WiP: .addN(), .addBefore(), .addAfter(), as well as .addNBefore() and .addNAfter().
.setAttributes(a1, a2, … ) (WIP)
Method for setting values of multiple attributes at once. Can only be called from objects created using the .add() method. Works for circle, line, rect, general path for vector layer object, as well as standard divs from markup layers.
.merge(path_string1, path_string2, … )
Method for merging path-strings (returned by the path methods, in particular). Can be used to assemble piecewise contours from individual segments:
path_string1 = plt.LinePath(x => Math.pow(x, 3), plt.Subdivide([0, 1], 3));
path_string2 = plt.ParametricBezierPath(t => [1 + Math.cos(t), 1 + Math.sin(t)], t => [-Math.sin(t), Math.cos(t)], plt.Subdivide([0, 1], 2));
path_string3 = "M 2,0 C 4,0 3,2 3,1";
joined_line = plt.merge(path_string1, path_string2, path_string3);
.unwrap(obj)
Unwraps methods contained in the obj object into the global scope. Useful for Math to simplify writing long mathematical expressions. Can also be used on the plt itself.
$Precision
Some of the numerical methods internally use floating-point comparison, which requires specifying an error margin. The utilized value is stored as a global variable $Precision, which can be modified to control the coarseness of the dependent operations:
$Precision = 1e-9;
Layers additionally marked with the .3D class present their inner elements as located in 3D space of the plot with the positions and sizes automatically adjusted with camera movements. Elements added to these layers must have the required 3D data attribute attached (all positions are specified in global plot space). In general, all the same types of layers as in regular 2D plots can be used for 3D, but each type has its own set of features and differences associated with the extended functionality.
Layers for adding vector lines, wireframes (of 3D plots, in particular), arrows, curves, and other elements that can be drawn with purely vector means.
<svg class="Layer 3D"></svg>
Similarly to 2D, markup layers can display axes, ticks, boxes, as well as markers and text labels placed in the 3D space. Elements can be scaled with the distance, or rendered with a constant screen-space size.
<div class="Layer 3D"></div>
Layers for drawing fully-shaded 3D objects and surfaces. Requires additionally importing three.js library. Can be used for displaying imported 3D models or for procedurally generated 3D plots and sets of primitives.
<canvas class="Layer 3D"></canvas>
Shaders do not require any additional attributes for the layers.
<canvas class="Layer glsl"></canvas>
Any shader layer within a 3D plot will automatically get access to 3D camera parameters cameraOrigin (vec3), cameraRotation (mat3), fov (float). In combination with the plotResolution they can be used to calculate the direction of a cast ray for the pixel:
vec3 d = normalize( cameraRotation * ( vec3(0, 0, -1) + fov * vec3(gl_FragCoord.xy - .5 * plotResolution, 0) / plotResolution ) );