Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

There are two ways to consider a two-dimensional torus. One way is to take a parallelogram (let's say the square $[0, 1]^2$) and topologically glue the opposite edges. Another way is to look at the surface of a doughnut with one hole.

I would like to draw the zero set of a doubly-periodic function as a contour on a torus. Here is how I do it when viewing the torus as a square:

Contour on torus

However, I'd really like to see a contour on the surface of a doughnut. How can this be done? (Generally, I'd like to transplant the square $[0, 1]^2$ of any graphic onto the surface of a doughnut.)

share|improve this question

4 Answers 4

up vote 26 down vote accepted

You could also use MeshFunctions option to map the $[0,1]^2$ region:

yourFunc = Function[{u, v},
                    Re[2 Exp[2 π I (u + 2 v)] + 3 Exp[2 π I (u - 2 v)]]

                  (2 + Cos[2 π v]) Sin[2 π u],
                  (2 + Cos[2 π v]) Cos[2 π u],
                  Sin[2 π v]},
                 {u, 0, 1}, {v, 0, 1},
       MeshFunctions -> Function[{x, y, z, u, v}, yourFunc[u, v]],
       Mesh -> {{0}}, (* Because you state yourFunc[u,v] = 0 *)
       MeshStyle -> Directive[Blue, Thick],
       PlotPoints -> 50


Another fancy example:

                  (3 + Cos[2 π v]) Sin[2 π u],
                  (3 + Cos[2 π v]) Cos[2 π u],
                  Sin[2 π v]},
                 {u, 0, 1}, {v, 0, 1},
          MeshFunctions -> Function[{x, y, z, u, v}, yourFunc[v, u]],
          Mesh -> {Range[-1, 1, .1]},
          MeshStyle -> None,
          MeshShading -> Join[{None},
            ColorData["Rainbow"] /@ Rescale[Most@Range[-1, 1, .1]],
          PlotPoints -> 100,
          PlotStyle -> None,
          Lighting -> "Neutral"


share|improve this answer

One easy way is to use the Line's from your parametric curves and map them onto a torus mathematically. What basically happens here is that we interpret the points of your plot no longer as Cartesian coordinates but as angles $\phi$ and $\theta$ of the torus parametrisation. Here the function for this parametrisation:

With[{rr = 3, r = 1},
 torus[{u_, v_}] := {(rr + r*Cos[2 Pi u])*Cos[2 Pi v], 
   (rr + r*Cos[2 Pi u])*Sin[2 Pi v], r*Sin[2 Pi u]}

rr is the inner radius and r the radius of the tube. Now lets take your plot and do the transformation. In the following code all the magic happens at the and where I extract the lines of gr using Cases and then transform them into Tube's using our torus function.

gr = ContourPlot[Re[2 Exp[2 Pi I (x + 2 y)] + 3 Exp[2 Pi I (x - 2 y)]] == 0, 
  {x, 0, 1}, {y, 0, 1}];
 ParametricPlot3D[torus[{u, v}], {u, 0, 1}, {v, 0, 1}, 
  PlotStyle -> Directive[Opacity[.3], Red], Mesh -> None],
   Cases[Normal[gr], Line[__], Infinity] /. 
    Line[pts_] :> Tube[torus /@ pts]}]

enter image description here

share|improve this answer
How do you extend your code to introduce double helix inside the torus? Please see demonstrations.wolfram.com/DoubleHelix –  thils Sep 4 at 6:34

For some applications, it might be useful not to use the conventional parametrization of the torus. In particular, if one wants a conformal (angle-preserving) map from a rectangular domain to a torus, one can use the parametric equations (see e.g. Sullivan's paper):

$$\mathbf r(u,v)=\frac1{\sqrt{s^2+t^2}-t\cos\tfrac{2\pi v}{t}}\begin{pmatrix}s\cos\tfrac{2\pi u}{s}\\s\sin\tfrac{2\pi u}{s}\\t\sin\tfrac{2\pi v}{t}\end{pmatrix}$$

with parameter ranges $0\leq u\leq s,\; 0\leq v\leq t$ to conformally map an $s\times t$ rectangle onto a torus.

In particular, for your curve of interest, we can do something similar to Silvia's proposal, but using this parametrization instead. If you want to see the curve only, without the torus backdrop, you can do this:

With[{s = 1, t = 1}, 
     ParametricPlot3D[{s Cos[2 π u/s], s Sin[2 π u/s], t Sin[2 π v/t]}/
                       (Sqrt[s^2 + t^2] - t Cos[2 π v/t]),
                      {u, 0, s}, {v, 0, t}, Mesh -> {{0}},
                      MeshFunctions -> Function[{x, y, z, u, v},
                                      Re[2 Exp[2 π I (u + 2 v)] + 3 Exp[2 π I (u - 2 v)]]],
                      MeshStyle -> Directive[Thick, Blue],
                      PlotPoints -> 55, PlotStyle -> None]]

curve living on a torus

(Change s and t if you want a plot over a wider rectangle.)

If you want to see the torus as well, you can have it be translucent, so that you can still see the structure of the curve. For instance, here's the resulting picture with the setting PlotStyle -> Opacity[3/5, ColorData["Legacy", "PowderBlue"]]:

curve on a glassy torus

share|improve this answer
+1 for the math teaching and the reference. –  Silvia Jun 10 '13 at 14:04
(As a tiny note: a lot of my previous Gravatars that were based on mapping parallelogram domains to tori used this parametrization. For instance, here is a conformal hexagonal tiling of a torus. Note that the 120° angles of the hexagons are preserved.) –  J. M. Jun 10 '13 at 14:05
What previous gravatars of 0x4A4D? This chap's new here... –  rm -rf Jun 10 '13 at 14:16
(whistles innocently) Uh... right. –  J. M. Jun 10 '13 at 14:41

One way to do this is to map the image of the function onto the surface of the torus. First, let's make your plot of the function into an image:

img = Erosion[Image[
  ContourPlot[3 Cos[2 \[Pi] (u - 2 v)] + 2 Cos[2 \[Pi] (u + 2 v)] == 0,   
  {u, 0, 1}, {v, 0, 1}, Frame -> None]], 1]

enter image description here

and map it onto the surface of a torus:

colorfun = BSplineFunction[ImageData[img], SplineDegree -> 1];
    {(2 + Cos[2 Pi v]) Cos[2 Pi u], (2 + Cos[2 Pi v]) Sin[2 Pi u], Sin[2 Pi v]}, 
    {u, 0, 1}, {v, 0, 1}, ColorFunction -> {colorfun[1 - #5, #4] &}, 
    ViewPoint -> {Pi/2, Pi, 1}, PlotPoints -> 200,  Mesh -> None, Axes -> None]

enter image description here

It's a little easier using the new (version 9) Texture command:

ParametricPlot3D[{(2 + Cos[2 Pi v]) Cos[2 Pi u], 
      (2 + Cos[2 Pi v]) Sin[2 Pi u], Sin[2 Pi v]}, 
      {u, 0, 1}, {v, 0, 1}, PlotStyle -> {Opacity[1], Texture[img]}, 
      PlotPoints -> 100, Mesh -> None, Axes -> None]

enter image description here

Add the option Lighting->"Neutral" to remove the colored shading and get back to the pure white.

share|improve this answer

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.