8.34 color functions (26.8.99)

8.34.1 Matthias Kawski
8.34.2 Robert Israel (29.8.99)
8.34.3 Helmut Kahovec (30.8.99)
8.34.4 Helmut Kahovec (8.9.99)

8.34.1 Matthias Kawski

Why is it that color functions fail when the domain is not specified in the form x=a..b, y=c..d with a,b,c,d constant, i.e. when e.g. c and d depend on x?

> with(plots):
 

All works fine here:

> plot3d(1,x=0..1,y=0..1,color=x); 
> plot3d(1,x=0..1,y=0..1,color=y); 
> plot3d(1,x=0..1,y=0..1,color=x*y);
 
Things go bad here:
> plot3d(1,x=0..1,y=0..x,color=x); 
> plot3d(1,x=0..1,y=0..x,color=y); 
> plot3d(1,x=0..1,y=0..x,color=x*y);
 
A workaround is to use parametric plots.
> plot3d([x,t*x,1],x=0..1,t=0..1,color=x*(t*x));
 
I ran into this when trying to color the graph of Im(f(z)) by Re(f(z)) and the boundaries in the domain where defined at the branch-cuts – see the images (and animations) of the example w=sqrt(z^2-1), the logo for my fall class.

8.34.2 Robert Israel (29.8.99)

Actually, plot3d(1,x=0..1,y=0..x,color=x); should work all right.

The problem is this: Maple actually converts the plot to the parametric form

plot3d([x,t*x,1],x=0..1,t=0..1,...)

but doesn’t convert the y in the colour specification when it does so.

8.34.3 Helmut Kahovec (30.8.99)

In your examples the color function of a plot3d() command does some scaling based on its HUE color function, which is an expression containing the coordinates. That scaling is done independently of the points to be plotted and does not work (properly) if the range of some coordinate is not specified by constants only and the color function contains that very coordinate.

In such a case you have to employ your clever workaround using parametric plots.

8.34.4 Helmut Kahovec (8.9.99)

Recently Mathias Kawski reported the following behavior of plot3d to the Maple User Group: If the plot ranges do not have constant endpoints, but are specified by some coordinate expressions, and if the (HUE) coloring function contains those coordinates then the coloring is not correctly done.

That behavior of plot3d turned out to be a bug in the procedure ‘plot3d/expression‘. After having looked carefully at that procedure I found many incorrect lines of code in it.

Below you will find my corrected version of ‘plot3d/expression‘. You may test it, for example, by entering the following commands in a fresh (Release 5) session:

> restart; 
> readlib(plot3d): 
> `plot3d/expression`:=proc(parametric,gg,r1,r2) 
.       ... see below ... 
> end: 
> plot3d(1,x=0..1,y=0..x,color=x); 
> plot3d(1,0..1,0..proc(x) x end,color=proc(x,y) x end); 
> plot3d(1,x=0..1,y=0..x,color=y); 
> plot3d(1,0..1,0..proc(x) x end,color=proc(x,y) y end); 
> plot3d(1,x=0..1,y=0..x,color=x*y); 
> plot3d(1,0..1,0..proc(x) x end,color=proc(x,y) x*y end); 
> plot3d(1,x=0..y,y=0..1,color=x); 
> plot3d(1,0..proc(y) y end,0..1,color=proc(x,y) x end); 
> plot3d(1,x=0..y,y=0..1,color=y); 
> plot3d(1,0..proc(y) y end,0..1,color=proc(x,y) y end); 
> plot3d(1,x=0..y,y=0..1,color=x*y); 
> plot3d(1,0..proc(y) y end,0..1,color=proc(x,y) x*y end);
                                                                                  
                                                                                  
 
After having executed those statements, one after the other, you can see that the corrected version of ‘plot3d/expression‘ fully complies with the description of plot3d, plot3d[option], and plot3d[colorfunc] in the online help.

As a comparison you may also try to test the current version of ‘plot3d/expression‘. In doing so you start a fresh Maple session again and leave out (i.e., do not execute) the following two statements:

> readlib(plot3d): 
> `plot3d/expression`:=proc(parametric,gg,r1,r2) 
.       ... see below ... 
> end: 
> `plot3d/expression`:=proc(parametric,gg,r1,r2) 
> local x,y,t,a,b,c,d,g,f,Dummy1,Dummy2,O1,O2; 
> option `copyright (c) 1994 by George Labahn. All rights reserved.`; 
>   g:=gg; 
>   if type(r1,name=constant..constant) and type(r2,name=range) then 
>     x:=op(1,r1); 
>     t:=op(2,r1); 
>     a:=op(1,t); 
>     b:=op(2,t); 
>     y:=op(1,r2); 
>     t:=op(2,r2); 
>     c:=op(1,t); 
>     d:=op(2,t); 
>     if type(c,algebraic) and type(d,algebraic) then 
>       if not parametric then 
>         g:=seq( 
>           [x,(1-_tt)*c+_tt*d,subs(y=(1-_tt)*c+_tt*d,f)], 
>           f=g 
>         ); 
>         RETURN( 
>           plot3d( 
>             {g}, 
>             r1, 
>             _tt=0..1, 
>             labels=[x,y,'``'], 
>             op(subs(y=(1-_tt)*c+_tt*d,[args[5..nargs]])) 
>           ) 
>         ) 
>       else 
>         g:=seq( 
>           subs(y=(1-_tt)*c+_tt*d,f), 
>           f=g 
>         ); 
>         RETURN( 
>           plot3d( 
>             {g}, 
>             r1, 
>             _tt=0..1, 
>             labels=[x,y,'``'], 
>             op(subs(y=(1-_tt)*c+_tt*d,[args[5..nargs]])) 
>           ) 
>         ) 
>       fi 
>     else ERROR(`bad range arguments`,r1,r2) 
>     fi 
>   elif type(r1,name=range) and type(r2,name=constant..constant) then 
>     x:=op(1,r1); 
>     t:=op(2,r1); 
>     a:=op(1,t); 
>     b:=op(2,t); 
>     y:=op(1,r2); 
>     t:=op(2,r2); 
>     c:=op(1,t); 
>     d:=op(2,t); 
>     if type(a,algebraic) and type(b,algebraic) then 
>       if not parametric then 
>         g:=seq( 
>           [(1-_tt)*a+_tt*b,y,subs(x=(1-_tt)*a+_tt*b,f)], 
>           f=g 
>         ); 
>         RETURN( 
>           plot3d( 
>             {g}, 
>             _tt=0..1, 
>             r2, 
>             labels=[x,y,'``'], 
>             op(subs(x=(1-_tt)*a+_tt*b,[args[5..nargs]])) 
>           ) 
>         ) 
>       else 
>         g:=seq( 
>           subs(x=(1-_tt)*a+_tt*b,f), 
>           f=g 
>         ); 
>         RETURN( 
>           plot3d( 
>             {g}, 
>             _tt=0..1, 
>             r2, 
>             labels=[x,y,'``'], 
>             op(subs(x=(1-_tt)*a+_tt*b,[args[5..nargs]])) 
>           ) 
>         ) 
>       fi 
>     else ERROR(`bad range arguments`,r1,r2) 
>     fi 
>   elif type(r1,constant..constant) and type(r2,range) then 
>     a:=op(1,r1); 
>     b:=op(2,r1); 
>     c:=op(1,r2); 
>     d:=op(2,r2); 
>     if 
>       type(c,{algebraic,procedure}) and type(d,{algebraic,procedure}) 
>     then 
>       if type(c,constant) and not parametric then 
>         Dummy1:=proc(x,y) (1-y)*_c+y*_d(x) end; 
>         Dummy2:=proc(x,y) _f(x,(1-y)*_c+y*_d(x)) end 
>       elif type(d,constant) and not parametric then 
>         Dummy1:=proc(x,y) (1-y)*_c(x)+y*_d end; 
>         Dummy2:=proc(x,y) _f(x,(1-y)*_c(x)+y*_d) end 
>       elif not parametric then 
>         Dummy1:=proc(x,y) (1-y)*_c(x)+y*_d(x) end; 
>         Dummy2:=proc(x,y) _f(x,(1-y)*_c(x)+y*_d(x)) end 
>       else ERROR(`bad range arguments`,r1,r2) 
>       fi; 
>       g:=seq( 
>         [ 
>           proc(x) x end, 
>           subs([_c=c,_d=d],eval(Dummy1)), 
>           subs([_f=f,_c=c,_d=d],eval(Dummy2)) 
>         ], 
>         f=g 
>       ); 
>       O1:=op(select(has,[args[5..nargs]],{color,colour})); 
>       O2:=op(remove(has,[args[5..nargs]],{color,colour})); 
>       if type(O1,name=procedure) then 
>         RETURN( 
>           plot3d( 
>             {g}, 
>             r1, 
>             0..1, 
>             lhs(O1)=subs( 
>               _body=subs(_yy=_xx*_yy,eval(rhs(O1)(_xx,_yy))), 
>               proc(_xx,_yy) _body end 
>             ), 
>             O2 
>           ) 
>         ) 
>       else 
>         RETURN(plot3d({g},r1,0..1,O1,O2)) 
>       fi 
>     else ERROR(`bad range arguments`,r1,r2) 
>     fi 
>   elif type(r1,range) and type(r2,constant..constant) then 
>     a:=op(1,r1); 
>     b:=op(2,r1); 
>     c:=op(1,r2); 
>     d:=op(2,r2); 
>     if 
>       type(a,{algebraic,procedure}) and type(b,{algebraic,procedure}) 
>     then 
>       if type(a,constant) and not parametric then 
>         Dummy1:=proc(y,x) (1-y)*_a+y*_b(x) end; 
>         Dummy2:=proc(y,x) _f((1-y)*_a+y*_b(x),x) end 
>       elif type(b,constant) and not parametric then 
>         Dummy1:=proc(y,x) (1-y)*_a(x)+y*_b end; 
>         Dummy2:=proc(y,x) _f((1-y)*_a(x)+y*_b,x) end 
>       elif not parametric then 
>         Dummy1:=proc(y,x) (1-y)*_a(x)+y*_b(x) end; 
>         Dummy2:=proc(y,x) _f((1-y)*_a(x)+y*_b(x),x) end 
>       else ERROR(`bad range arguments`,r1,r2) 
>       fi; 
>       g:=seq( 
>         [ 
>           subs([_a=a,_b=b],eval(Dummy1)), 
>           proc(y) y end, 
>           subs([_f=f,_a=a,_b=b],eval(Dummy2)) 
>         ], 
>         f=g 
>       ); 
>       O1:=op(select(has,[args[5..nargs]],{color,colour})); 
>       O2:=op(remove(has,[args[5..nargs]],{color,colour})); 
>       if type(O1,name=procedure) then 
>         RETURN( 
>           plot3d( 
>             {g}, 
>             0..1, 
>             r2, 
>             lhs(O1)=subs( 
>               _body=subs(_xx=_xx*_yy,eval(rhs(O1)(_xx,_yy))), 
>               proc(_yy,_xx) _body end 
>             ), 
>             O2 
>           ) 
>         ) 
>       else 
>         RETURN(plot3d({g},0..1,r2,O1,O2)) 
>       fi 
>     else ERROR(`bad range arguments`,r1,r2) 
>     fi 
>   else ERROR(`bad range arguments`,r1,r2) 
>   fi 
> end: