Documentation

## Advanced Plotting: Principles and First Examples

MuPAD® notebooks will be removed in a future release. Use MATLAB® live scripts instead.

MATLAB live scripts support most MuPAD functionality, though there are some differences. For more information, see Convert MuPAD Notebooks to MATLAB Live Scripts.

In the previous section, we introduced `plotfunc2d` and `plotfunc3d` that serve for plotting functions in 2D and 3D with simple calls in easy syntax. Although all plot attributes accepted by function graphs (of type `plot::Function2d` or `plot::Function3d`, respectively) are also accepted by `plotfunc2d/3d`, there remains a serious restriction: the attributes are used for all functions simultaneously.

If attributes are to be applied to functions individually, one needs to invoke a (slightly) more elaborate calling syntax to generate the plot:

```plot( plot::Function2d(f1, x1 = a1..b1, attrib11, attrib12, ...), plot::Function2d(f2, x2 = a2..b2, attrib21, attrib22, ...), ... ):```

In this call, each call of `plot::Function2d` creates a separate object that represents the graph of the function passed as the first argument over the plotting range passed as the second argument. An arbitrary number of plot attributes can be associated with each function graph. The objects themselves are not displayed directly. The `plot` command triggers the evaluation of the functions on some suitable numerical mesh and calls the renderer to display these numerical data in the form specified by the given attributes.

In fact, `plotfunc2d` and `plotfunc3d` do precisely the same: Internally, they generate plot objects of type `plot::Function2d` or `plot::Function3d`, respectively, and call the renderer via `plot`.

### General Principles

In general, graphical scenes are collections of “graphical primitives.” There are simple primitives such as points, line segments, polygons, rectangles and boxes, circles and spheres, histogram plots, pie charts etc. An example of a more advanced primitive is `plot::VectorField2d` that represents a collection of arrows attached to a regular mesh visualizing a vector field over a rectangular region in 2. Yet more advanced primitives are function graphs and parametrized curves that come equipped with some internal intelligence, e.g., knowing how to evaluate themselves numerically on adaptive meshes and how to clip themselves in case of singularities. The most advanced primitives in the present `plot` library are `plot::Ode2d`, `plot::Ode3d` and `plot::Implicit2d`, `plot::Implicit3d`. The first automatically solve systems of ordinary differential equations numerically and display the solutions graphically. The latter display the solution curves or surfaces of algebraic equations f(x, y) = 0 or f(x, y, z) = 0, respectively, by solving these equation numerically.

All these primitives are just “objects” representing some graphical entities. They are not rendered directly when they are created, but just serve as data structures encoding the graphical meaning, collecting attributes defining the presentation style and providing numerical routines to convert the input parameters to some numerical data that are to be sent to the renderer.

An arbitrary number of such primitives can be collected to form a graphical scene. Finally, a call to `plot` passing a sequence of all primitives in the scene invokes the renderer to draw the plot. The following example shows the graph of the function f(x) = xsin(x). At the point (x0, f(x0)), a graphical point is inserted and the tangent to the graph through this point is added:

```f := x -> x*sin(x): x0 := 1.2: dx := 1: g := plot::Function2d(f(x), x = 0..2*PI): p := plot::Point2d(x0, f(x0)): t := plot::Line2d([x0 - dx, f(x0) - f'(x0)*dx], [x0 + dx, f(x0) + f'(x0)*dx]):```

The picture is drawn by calling `plot`:

`plot(g, p, t):` Each primitive accepts a variety of plot attributes that may be passed as a sequence of equations `AttributeName = AttributeValue` to the generating call. Most prominently, each primitive allows to set the color explicitly:

`g := plot::Function2d(f(x), x = 0..2*PI, Color = RGB::Blue):`

Alternatively, the generated objects allow to set attributes via slot assignments of the form ```primitive::AttributeName := AttributeValue``` as in

```p::Color := RGB::Black: p::PointSize := 3.0*unit::mm: t::Color := RGB::Red: t::LineWidth := 1.0*unit::mm:```

The help page of each primitive provides a list of all attributes the primitive is reacting to.

Certain attributes such as axes style, the visibility of grid lines in the background etc. are associated with the whole scene rather than with the individual primitives. These attributes may be included in the `plot` call:

`plot(g, p, t, GridVisible = TRUE):` As explained in detail in section The Full Picture: Graphical Trees, the `plot` command automatically embeds the graphical primitives in a coordinate system, which in turn is embedded in a graphical scene, which is drawn inside a canvas. The various attributes associated with the general appearance of the whole picture are associated with these “grouping structures”: a concise list of all such attributes is provided on the help pages of `plot::Canvas`, `plot::Scene2d`, `plot::Scene3d`, `plot::CoordinateSystem2d`, and `plot::CoordinateSystem3d`, respectively.

The object browser provided by the MuPAD® graphics tool allows to select each primitive in the plot. After selection, the attributes of the primitive can be changed interactively in the property inspector (see section Viewer, Browser, and Inspector: Interactive Manipulation).

Next, we wish to demonstrate a animation. It is remarkably simple to generate an animated picture. We want to let the point x0 at which the tangent is added move along the graph of the function. In MuPAD, you do not need to create an animation frame by frame. Instead, each primitive can be told to animate itself by simply defining it with a symbolic animation parameter and adding an animation range for this parameter. Static and animated objects can be mixed and rendered together. The static function graph of f(x) used in the previous plot is recycled for the animation. The graphical point at (x0, f(x0)) and the tangent through this point shall be animated using the coordinate `x0` as the animation parameter. Deleting its value set above, we can use the same definitions as before, now with a symbolic `x0`. We just have to add the range specification `x0 = 0..2*PI` for this parameter:

```delete x0: dx := 2/sqrt(1 + f'(x0)^2): p := plot::Point2d(x0, f(x0), x0 = 0..2*PI, Color = RGB::Black, PointSize = 2.0*unit::mm): t := plot::Line2d([x0 - dx, f(x0) - f'(x0)*dx], [x0 + dx, f(x0) + f'(x0)*dx], x0 = 0..2*PI, Color = RGB::Red, LineWidth = 1.0*unit::mm): plot(g, p, t, GridVisible = TRUE):``` Details on animations and further examples are provided in section Graphics and Animations.

We summarize the construction principles for graphics with the MuPAD `plot` library:

### Note

Graphical scenes are built from graphical primitives. Section Graphics and Animations provides a survey of the primitives that are available in the `plot` library.

### Note

Primitives generated by the `plot` library are symbolic objects that are not rendered directly. The call ```plot(Primitive1, Primitive2, ...)``` generates the pictures.

### Note

Graphical attributes are specified as equations ```AttributeName = AttributeValue```. Attributes for a graphical primitive may be passed in the call that generates the primitive. The help page of each primitive provides a complete list of all attributes the primitive reacts to.

### Note

Attributes determining the general appearance of the picture may be passed in the `plot` call. The help pages of `plot::Canvas`, `plot::Scene2d`, `plot::Scene3d`, `plot::CoordinateSystem2d`, and `plot::CoordinateSystem3d`, respectively, provide a complete list of all attributes determining the general appearance.

### Note

All attributes can be changed interactively in the viewer.

### Note

Presently, 2D and 3D plots are strictly separated. Objects of different dimension cannot be rendered in the same plot.

### Note

Animations are not created frame by frame but objectwise (also see section Frame by Frame Animations). An object is animated by generating it with a symbolic animation parameter and providing a range for this parameter in the generating call. Section Graphics and Animations provides for further details on animations.

Presently, it is not possible to add objects to an existing plot. However, using animations, it is possible to let primitives appear one after another in the animated picture. See Graphics and Animations.

### Some Examples

#### Example 1

We wish to visualize the interpolation of a discrete data sample by cubic splines. First, we define the data sample, consisting of a list of points [[x1, y1], [x2, y2], …]. Suppose they are equidistant sample points from the graph of the function :

```f := x -> x*exp(-x)*sin(5*x): data := [[i/3, f(i/3)] \$ i = 0..9]:```

We use `numeric::cubicSpline` to define the cubic spline interpolant through these data:

`S := numeric::cubicSpline(op(data)):`

The plot shall consist of the function f(x) that provides the data of the sample points and of the spline interpolant S(x). The graphs of f(x) and S(x) are generated via `plot::Function2d`. The data points are plotted as a `plot::PointList2d`:

```plot( plot::Function2d(f(x), x = 0..3, Color = RGB::Red, LegendText = expr2text(f(x))), plot::PointList2d(data, Color = RGB::Black), plot::Function2d(S(x), x = 0..3, Color = RGB::Blue, LegendText = "spline interpolant"), GridVisible = TRUE, SubgridVisible = TRUE, LegendVisible = TRUE ):``` #### Example 2

A cycloid is the curve that you get when following a point fixed to a wheel rolling along a straight line. We visualize this construction by an animation in which we use the x coordinate of the hub as the animation parameter. The wheel is realized as a circle. There are 3 points fixed to the wheel: a green point on the rim, a red point inside the wheel and a blue point outside the wheel:

```WheelRadius := 1: WheelCenter := [x, WheelRadius]: WheelRim := plot::Circle2d(WheelRadius, WheelCenter, x = 0..4*PI, LineColor = RGB::Black): WheelHub := plot::Point2d(WheelCenter, x = 0..4*PI, PointColor = RGB::Black): WheelSpoke := plot::Line2d(WheelCenter, [WheelCenter + 1.5*WheelRadius*sin(x), WheelCenter + 1.5*WheelRadius*cos(x)], x = 0..4*PI, LineColor = RGB::Black): color:= [RGB::Red, RGB::Green, RGB::Blue]: r := [1.5*WheelRadius, 1.0*WheelRadius, 0.5*WheelRadius]: for i from 1 to 3 do Point[i] := plot::Point2d([WheelCenter + r[i]*sin(x), WheelCenter + r[i]*cos(x)], x = 0..4*PI, PointColor = color[i], PointSize = 2.0*unit::mm): Cycloid[i] := plot::Curve2d([y + r[i]*sin(y), WheelRadius + r[i]*cos(y)], y = 0..x, x = 0..4*PI, LineColor = color[i]): end_for: plot(WheelRim, WheelHub, WheelSpoke, Point[i] \$ i = 1..3, Cycloid[i] \$ i = 1..3, Scaling = Constrained, Width = 120*unit::mm, Height = 60*unit::mm):``` #### Example 3

We wish to visualize the solution of the ordinary differential equation (ODE) with the initial condition y(0) = 0. The solution shall be drawn together with the vector field associated with this ODE (along the solution curve, the vectors of this field are tangents of the curve). We use `numeric::odesolve2` to generate the solution as a function plot. Since the numerical integrator returns the result as a list of one floating-point value, one has to pass the single list entry as `Y(x)` to `plot::Function2d`. The vector field is generated via `plot::VectorField2d`:

```f := (x, y) -> -y^3 + cos(x): Y := numeric::odesolve2( numeric::ode2vectorfield({y'(x) = f(x, y), y(0) = 0}, [y(x)])): plot( plot::Function2d(Y(x), x = 0..6, Color = RGB::Red, LineWidth = 0.7*unit::mm), plot::VectorField2d([1, f(x, y)], x = 0..6, y = -1..1, Color = RGB::Blue, Mesh = [25, 25]), GridVisible = TRUE, SubgridVisible = TRUE, Axes = Frame ):``` #### Example 4

The radius r of an object with rotational symmetry around the x-axis is measured at various x positions:

 x 0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 0.95 1 r(x) 0.6 0.58 0.55 0.51 0.46 0.4 0.3 0.15 0.23 0.24 0.2 0

A spline interpolation is used to define a smooth function r(x) from the measurements:

```samplepoints := [0.00, 0.60], [0.10, 0.58], [0.20, 0.55], [0.30, 0.51], [0.40, 0.46], [0.50, 0.40], [0.60, 0.30], [0.70, 0.15], [0.80, 0.23], [0.90, 0.24], [0.95, 0.20], [1.00, 0.00]: r := numeric::cubicSpline(samplepoints):```

We reconstruct the object as a surface of revolution via `plot::XRotate`. The rotation angle is restricted to a range that leaves a gap in the surface. The spline curve and the sample points are added as a `plot::Curve3d` and a `plot::PointList3d`, respectively, and displayed in this gap:

```plot( plot::XRotate(r(x), x = 0..1, AngleRange = 0.6*PI..2.4*PI, Color = RGB::MuPADGold), plot::Curve3d([x, 0, r(x)], x = 0..1, LineWidth = 0.5*unit::mm, Color = RGB::Black), plot::PointList3d([[p, 0, p] \$ p in samplepoints], PointSize = 2.0*unit::mm, Color = RGB::Red), CameraDirection = [70, -70, 40] ):``` #### Example 5

The following sum is a Fourier representation of a periodic step function: We wish to show the convergence of the partial sums for some small values of n. To this end, we assign the value of fn(x) to the MuPAD `identifier` `f_n`. For our second and third example, we will need to accept fractional values of n, so the code uses `floor` to get a “proper” integer value for the sum:

`f_n := sum(sin((2*k-1)*x)/(2*k-1), k = 1..floor(n))`
` `

First, we use `plotfunc2d` and the sequence operator `\$` to plot the first 5 partial sums into the same coordinate system (and switch off the legend, which is not useful for this application).

`plotfunc2d(f_n \$ n = 1..5, LegendVisible = FALSE)` This plot clearly shows what is known as Gibbs' phenomenon: At the discontinuities of the step function, the approximation “overshoots.” Plotting more approximations simultaneously is going to create a too crowded plot to be of use, so to show that using more terms in the sum does not help against Gibbs' phenomenon, we revert to animations to show the first 30 partial sums – this is one of the reasons we used `floor(n)` above:

`plotfunc2d(f_n, x = -5..5, n = 1..30, Frames = 15)` Another possibility of showing the convergence behavior is to create a 3D plot with the second ordinate being the number of terms used in the approximation:

```plotfunc3d(f_n, x = -5..5, n = 1..30, Submesh = [5,1], FillColorType = Rainbow)``` #### Mathematical Modeling with Symbolic Math Toolbox

Get examples and videos