Back to main page
Back to draw contents
This section shows how to combine different graphics objects for drawing more complex scenes.
Basic graphics objects are defined in package draw in order to later design our own more elaborated graphics. In this example, we write a function at Maxima level for pie charts by means of function draw2d and related options. See that this function doesn't calculate frequencies; in such cases, we should load package descriptive and call function piechart (examples here).
random_color():=
block([obase:16],
concat("#",
random(16),random(16), /* red */
random(16),random(16), /* green */
random(16),random(16)) /* blue */ )$
piechart(tit, [pairs]):=
block([n:length(pairs), items, freqs, degrees, sectors, ini, end:0,
conver:float(%pi/180), alpha, hexcolor, numer:true],
items: map('first, pairs),
freqs: map('second, pairs),
degrees: 360.0 * freqs / apply("+", freqs),
header:['title = tit,
'xrange = [-1.5,1.5],
'yrange = [-1.5,1.5],
'xtics = false,
'ytics = false ],
sectors: makelist((ini: end,
end: ini + degrees[i],
alpha: ini+degrees[i]/2.0,
hexcolor: random_color(),
[ color = hexcolor,
label([items[i],1.2*cos(alpha*conver),1.2*sin(alpha*conver)]),
fill_color = hexcolor,
ellipse(0,0,1,1,ini,degrees[i]) ])
,i,1,n),
apply(draw2d,append(header,flatten(sectors))) )$
piechart("Population growth rate (Source: Eurostat - Demographic statistics 1997)",
["Belgium",2.3],
["Denmark",3.7],
["Germany",0.6],
["Spain",1.3],
["France",4.0],
["Ireland",11.4],
["Italy",1.8],
["Luxembourg",12.8],
["Nederlands",5.6],
["Austria",0.9],
["Poland",2.3],
["Finland",2.9],
["Sweden",0.4],
["United Kingdom",3.1] )$
A diagram explaining Omar Khayyam's graphical method to solve cubic equations.
a: 3$
b: 26$
r: b/(2*a^2)$
draw2d(/* General settings */
xrange=[-3,3],
yrange=[-2,4],
axis_top = false,
axis_right = false,
axis_left = false,
axis_bottom = false,
transparent = true,
user_preamble = "unset tics",
title = "Omar Khayyam: solution to the cubic x^3 + a^2 x = b",
eps_width = 10,
eps_height = 10,
terminal = eps_color,
/* draw parabola y=x^2/a */
explicit(x^2/a,x,-3,3),
head_length = 0.1,
vector([-1.626,2],[-0.5,-0.5]),
label(["y=x^2/a",-1.5,2.1]),
/* draw circle: radius r & center (r,0) */
ellipse(r,0,r,r,0,360),
vector([r,0],[0,r]),
label(["r=b/(2*a^2)",r-0.5,r*2/3]),
/* draw axis */
points_joined = true,
color = red,
point_size = 0,
points([[0,3.5],[0,-1.5]]),
points([[-2.5,0],[2.5,0]]),
/* Mark points P e Q*/
color = black,
point_type = 7,
point_size = 1,
points([[2,4/3]]),
label(["P",2.25,1.42]),
points([[2,0]]),
label(["Q",2.25,0.23]),
/* Draw parallel to parabola axis */
point_size = 0,
color = blue,
line_type = dots,
points([[2,2],[2,-0.5]]),
/* Get the solution */
line_width = 4,
color = blue,
line_type = solid,
points([[0,0],[2,0]]),
label(["The length of this blue segment is the solution",1,-0.5]));
The benzene molecule in the wxt terminal. Thanks to Sofía Picos for her assistance.
atomo(x,y,z):=
parametric_surface(x+cos('a)*cos('b),
y+cos('b)*sin('a),
z+sin('b), 'a,0,2*%pi,'b,-%pi/2,%pi/2) $
block([s,v,numer:true],
s: 5*sqrt(3)/2,
v: 5*sqrt(3),
draw3d(
/* Preamble */
title = "Benzene C6H6",
xtics = false,
ytics = false,
ztics = false,
axis_3d = false,
surface_hide = true,
xu_grid = 10,
yv_grid = 5,
user_preamble = "set size ratio 1",
zrange = [-5,5],
terminal = wxt,
/* links */
point_size = 0,
color = black,
points_joined = true,
line_width = 3,
points([[0,10,0],[0,5,0],[s,5/2,0],[v,5,0]]),
points([[v,-5,0],[s,-5/2,0],[0,-5,0],[0,-10,0]]),
points([[-v,5,0],[-s,5/2,0],[-s,-5/2,0],[-v,-5,0]]),
points([[0,5,1/2],[-s,5/2,1/2]]),
points([[0,5,-1/2],[-s,5/2,-1/2]]),
points([[-s,-5/2,1/2],[0,-5,1/2]]),
points([[-s,-5/2,-1/2],[0,-5,-1/2]]),
points([[s,5/2,1/2],[s,-5/2,1/2]]),
points([[s,5/2,-1/2],[s,-5/2,-1/2]]),
/* Hydrogen */
color = green,
atomo(0,10,0),
atomo(0,-10,0),
atomo(v,5,0),
atomo(v,-5,0),
atomo(-v,5,0),
atomo(-v,-5,0),
color = black,
label(["H",0,10,1.5],["H",0,-10,1.5],
["H",v,5,1.5],["H",v,-5,1.5],
["H",-v,5,1.5],["H",-v,-5,1.5]),
/* Carbon */
color = blue,
atomo(0,5,0),
atomo(0,-5,0),
atomo(s,5/2,0),
atomo(s,-5/2,0),
atomo(-s,5/2,0),
atomo(-s,-5/2,0),
color = black,
label(["C",0,5,1.5],["C",0,-5,1.5],
["C",s,5/2,1.5],["C",s,-5/2,1.5],
["C",-s,5/2,1.5],["C",-s,-5/2,1.5]) ))$
It's possible to define new graphics object at Maxima level (requieres draw's cvs version, nov. 2008). Here is a simple example, where we define object shadow_explicit for plotting explicit curves with a very naif special effect. This object can be used alone or with other graphics objects in the same scene. (Thanks to Andrej Vodopivec for this new feature.)
se_transform(expr) :=
if atom(expr)
then [expr]
else if op(expr)=shadow_explicit
then [line_width = 8,
color = grey,
apply(explicit, args(expr)),
line_width = 1,
color = blue,
color = yellow,
apply(explicit, args(expr))]
else [expr]$
put(shadow_explicit, se_transform, draw2d_transform)$
draw2d(shadow_explicit(sin(x),x,0,10))$
draw2d(shadow_explicit(sin(x),x,0,10),
color = black,
explicit(cos(x),x,0,10))$

Here is a more sophisticated example for drawing direction fields; it makes use of Maxima's dynamics package. First thing to do is to download file drawdf.mac and allocate it somewhere reachable from Maxima. (Again, thanks to Andrej for this example.)
load(drawdf)$ draw2d(df(x^2/5,x,-4,4,y,-4,4,[0,0]))$ draw2d(df(exp(-x)+y,x,-2,5,y,-4,4, [4, 1], [4,-1], [2,-2]))$ draw2d(df([w, -19.5*sin(a) - 0.3*w],a,-10,2,w,-14,14, [1.05, -9]))$



Bode diagrams. This code is based on Robert Dodier's bode.mac package. It is an adaptation for package draw. Let's define first the necessary functions:
bode_phase_unwrap : false;
log10 (x) := log (x) / log (10) $
carg_unwrapped (z) :=
block ([a: carg (z)],
charfun (a < 0) * (2*%pi + a) + (1 - charfun (a < 0)) * a) $
bode (H, var, varmin, varmax) :=
block ([L],
L : block ([listdummyvars : false], listofvars (H)),
if length (L) # 1
then throw (oops (msg = "bode: failed to identify a unique variable", expr = H, variables = L))
else s : first (L),
H : subst (%i * var, var, H),
draw(
/* Bode gain plot */
gr2d(
title = concat ("Bode gain plot for ", string (H)),
logx = true,
grid = true,
xlabel = concat("log(", var, ")"),
color = blue,
explicit(10 * log10 (cabs (H * conjugate (H))), var, varmin, varmax)),
/* Bode phase plot */
gr2d(
title = concat ("Bode phase plot for ", string (H)),
logx = true,
grid = true,
xlabel = concat("log(", var, ")"),
color = blue,
if bode_phase_unwrap
then explicit(180/%pi * carg_unwrapped (H), var, varmin, varmax)
else explicit(180/%pi * carg (H), var, varmin, varmax) ) )) $
Plotting diagrams
(%i1) H1 (s) := 100 * (1 + s) / ((s + 10) * (s + 100));
100 (1 + s)
(%o1) H1(s) := ------------------
(s + 10) (s + 100)
(%i2) bode (H1 (s), s, 1/1000, 1000) $
(%i3) bode_phase_unwrap : true $ (%i4) bode (H1 (s), s, 1/1000, 1000) $
Back to main page
Back to draw contents