Functional line coloring
|plot::Conformal, plot::Curve2d, plot::Curve3d, plot::Cylindrical, plot::Density, plot::Dodecahedron, plot::Function2d, plot::Function3d, plot::Hexahedron, plot::Icosahedron, plot::Implicit2d, plot::Implicit3d, plot::Integral, plot::Listplot, plot::Matrixplot, plot::Octahedron, plot::Polar, plot::Polygon2d, plot::Polygon3d, plot::Prism, plot::Pyramid, plot::Rootlocus, plot::Sequence, plot::Spherical, plot::Streamlines2d, plot::Sum, plot::Surface, plot::SurfaceSet, plot::SurfaceSTL, plot::Sweep, plot::Tetrahedron, plot::Tube, plot::VectorField2d, plot::VectorField3d, plot::Waterman, plot::XRotate, plot::ZRotate|
These options accept functions that define the color of a plot at arbitrary points.
Using FillColorType and LineColorType, the user can control the color of many graphical objects. The setting providing the most detailed (and most complicated) control is Functional. In this case, a color function must be provided using one of LineColorFunction, FillColorFunction.
A color function can be a list of three or four expressions.
If three expressions are given, they specify RGB colors. If four expressions are given, they specify RGBA colors. See the introduction for more details on color specifications.
The expressions may contain the identifiers bound in the corresponding object. For example, in a plot::Function2d(sin(x), x=0..PI), the color function may refer to x. More formally, the expressions may contain the identifiers found in the attributes XName, YName, ZName, UName, VName, and ParameterName of the plot object they are found in.
All of these expressions must, for values in the given ranges, evaluate to real numbers in the range . Real values outside this range do not yield errors, they are simply clipped.
See also Example 1.
Alternatively, a color function can be a procedure or function environment.
A procedure (or a function environment) used as a color function must return lists of three or four real numbers in the range . Real values outside this range are clipped. (If this function ever returns a list of four numbers, it must always do so.) A list of three numbers is interpreted as an RGB color, while a list of four values is interpreted as an RGBA color. See the introduction for more details on color specifications.
The number and meaning of arguments a color function is called with depends on the object type. Informally, we have:
|Conformal(f(z))||z, Re(f((z)), Im(f((z)), flag (with flag = 1 or flag = 2)|
|Curve2d(x(u),y(u))||u, x(u), y(u)|
|Curve3d(x(u),y(u),z(u))||u, x(u), y(u), z(u)|
|Cylindrical(r(u,v),phi(u,v),z(u,v))||u, v, r(u,v), phi(u,v), z(u,v), x(u), y(u), z(u)|
|Density(f(x,y))||x, y, f(x,y)|
|Function3d(f(x,y))||x, y, f(x,y)|
|Implicit2d(f(x,y), Contours=[c])||x, y, D(,f)(x,y), D(,f)(x,y), c|
|Implicit3d(f(x,y,z), Contours=[c])||x, y, z, D(,f)(x,y,z), D(,f)(x,y,z), D(,f)(x,y,z), c|
|Matrixplot||x, y, z|
|Polar([r(t),phi(t)])||t, r(t), phi(t), x(t), y(t)|
|Polygon2d([..,[xi,yi],..])||xi, yi, i|
|xi, yi, zi, i|
|u, Re(z), Im(z)|
|Spherical(r(u,v),phi(u,v),thet(u,v))||u, v, r(u,v), phi(u,v), thet(u,v), x, y, z|
|Streamlines2d(v(x,y), w(x, y))||x, y, v(x,y), w(x,y), t, l, n|
|Surface(x(u,v),y(u,v),z(u,v))||u, v, x(u,v), y(u,v), z(u,v)|
|VectorField2d(v(x,y),w(x,y))||x, y, v(x,y), w(x,y)|
|XRotate(f(x))||x, phi, x, y(x,phi), z(x,phi)|
|ZRotate(f(t))||t, phi, x(t,phi), y(t,phi), f(t)(=z(t,phi))|
Additionally, for animated objects, the current value of the animation parameter is provided.
Dodecahedron, Hexahedron, Icosahedron, SurfaceSTL, SurfaceSet, and Tetrahedron are built from triangles; the color functions are called once for each vertex of these triangles and are passed the number of the triangle (an integer count starting at 1), the coordinates of the vertex and the animation parameter, if that is used.
For plot::Tube, the color functions are given the coordinates of the currently visited point on the central curve, followed by the coordinates of the point on the surface, followed by the animation parameter, if any. (That makes seven arguments altogether.)
The examples below show different usage environments of color functions for some of the object types listed above.
By default, most 3D-objects in MuPAD® get "height coloring":
To change the direction of this color, you can use FillColorFunction:
xmin := -5: xmax := 5: color := zip(RGB::Red, RGB::CornflowerBlue, (a, b) -> (x-xmin)/(xmax-xmin)*a +(xmax-x)/(xmax-xmin)*b)
plot(plot::Function3d(sin(x)*y^3, FillColorFunction = color))
Animated color functions can be combined with static objects:
plot( plot::Curve2d([sin(3*x), sin(4*x + 1)], x = 0..2*PI, LineColorFunction = ((u, x, y, a) -> [(u-a)/5, (u-a)/5, 1]), a = -5..6) )
cf := (i, x, y, z, a) -> [RGB::Red, RGB::Green, RGB::Blue][(floor(a*i) mod 3) + 1]: plot(plot::Icosahedron(FillColorFunction = cf, a = 0..9))
rgb := (u, v, x, y, z) -> [x, y, z]: plot(plot::Surface(formula, u = 0..1, v = 0..1, FillColorFunction = rgb) $ formula in [[0, u, v], [1, u, v], [u, 0, v], [u, 1, v], [u, v, 0], [u, v, 1]], plot::Box(0..1, 0..1, 0..1, Filled = FALSE, LineColor = RGB::Black.[0.25]), Scaling = Constrained, Axes = None, ULinesVisible = FALSE, VLinesVisible = FALSE, Lighting = None, CameraDirection = [4, 7, 3])
RGB colors are a very technical way of defining a color. The HSV color space is more popular with designers, since there the "hue" (i.e., the perceived color type) is not a combination of three numbers but rather one of the numbers making up a color:
hsv := (u, v, r, phi, z) -> RGB::fromHSV([180/PI*phi, r, z]): plot(plot::Cylindrical([z, phi, z], z = 0..1, phi = 0..2*PI, FillColorFunction = hsv), plot::Cylindrical([r, phi, 1], r = 0..1, phi = 0..2*PI, FillColorFunction = hsv), plot::Circle3d(1, [0, 0, 1], [0, 0, 1], Color = RGB::Black.[0.25]), ZXRatio = 1.5, Scaling = Unconstrained, Axes = None, Lighting = None, ULinesVisible = FALSE, VLinesVisible = FALSE, CameraDirection = [-17, -12, 3])
hsv := (u, v, r, phi,thet) -> RGB::fromHSV([180/PI*(phi+(thet+2)^3/PI^2), 3/4+sin(u)/4, 1]): plot(plot::Spherical([1, u, v], u = 0..2*PI, v = 0..PI, FillColorFunction = hsv))
There are other examples, where the cyclic nature comes in handy, too:
hsv := (x, y, z) -> RGB::fromHSV([150*z, 1, 1]): plot(plot::Function3d(sin(x*y)*(x-y), x = -3..3, y = -3..3, Submesh = [2, 2], FillColorFunction = hsv))
The following example takes a long time to compute. Reducing the values set for Mesh results in a shorter computation, while higher values lead to an image with finer details:
c := 0.377+0.2*I: julia := proc(x, y) local i, z; begin i := 0; z := float(x + I*y); while i < 1000 and abs(z) < 4 do z := z^2 + c; i := i + 1; end_while; i; end_proc: Jcol := (x, y, i) -> if i >= 1000 then RGB::Black else RGB::fromHSV([i, 1, 3/4+i/2000]) end: plot(plot::Density(julia, x = 0..0.5, y=0.25..0.75, FillColorFunction = Jcol, Mesh = [100,75]))
Another way of getting a smooth color transition is to use a periodic function in between, for example trigonometric ones (note the (1+sin(a))/2: we need values between 0 and 1):
plot( plot::Polar([r*surd(r, 3), r], r = -4*PI..4*PI, AdaptiveMesh = 2, LineColorFunction = [(sin(r) + 1)/2, (cos(r/2) + 1)/2, 1/3], LineWidth = 1*unit::mm) )
This also applies for cyclic colors in terms of time:
plot(plot::Function3d(sin(x)+sin(y), x = -5..5, y = -5..5, FillColorFunction = [(x+5)/10, (y+5)/10, abs(x+y+5*cos(a))/15, (1+cos(x+y^2-a))/2], a = 0..2*PI), CameraDirection = [-1, -3, 3], Scaling = Constrained)
Animation is handled by the general framework, not the individual objects. Therefore, the framework also supplies the animation parameter to the color functions.