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?
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);
> 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);
w=sqrt(z^2-1), the logo for my fall class.
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.
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.
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);
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: