I have recently started using asymptote for some plotting and drawings for my research. I have however stumbled upon something that I would like to do - but I don't know if it is possible.

I have a figure like this,

enter image description here

That I would like to map to the circumference of a circle, like this

enter image description here

It would be a lot simpler to make this drawing if I could make it like the first figure in a regular cartesian coordinate system $(x,y)$, and then map it onto a polar system (r,\theta), and back to a cartesian system (\tilde x,\tilde y'). The mapping onto the polar coordinates would be,

r = y, \theta = \frac{x}{r} = \frac{x}{y}

and the mapping back to the new cartesian system would be

\tilde x (r,\theta) = r \cos (\theta) = y \cos (\frac{x}{y}),
\tilde y (r,\theta) = r \csin (\theta) = y \sin (\frac{x}{y}).

I have looked at the possible Transformations, but none of them seems to allow this kind of transformation. Is it possible to make my own that allows me to use non-affine transformations?

If this can be done in TikZ I would be very interested in that as well.

Thanks, Christian

Ps. If someone can tell me how to make my math look right, that would be greatly appreciated too.

  • Since this site is about TeX rather than math, it was decided that it is more important to be able to write TeX formulas than to make math look right. Feb 18, 2014 at 19:02
  • Note that doing this in Asymptote will require a custom function, not just a standard transformation. Fortunately, in Asymptote, custom functions are not too hard to generate. Feb 18, 2014 at 19:04
  • Hey Charles, thanks for the answers. I can certainly understand the focus on tex. With regards to my problem I wouldn't mind writing a function myself, I just haven't been able to find an example that tells me how to write a function that will allow me to map a path or an entire picture with a custom function. I'm fairly new to asymptote, so I do not have a good understanding to the framework (yet). Feb 18, 2014 at 19:34

1 Answer 1


Try this:


struct planeTransformation {
  int nInterpolate = 4;
  pair apply(real, real);
  pair apply(pair uv) { return apply(uv.x, uv.y); }
  transform derivative(real, real);
  transform derivative(pair uv) { return derivative(uv.x, uv.y); }
  transform linearization(real u, real v) {
    return shift(apply(u,v)) * derivative(u,v) * shift(-(u,v));
  transform linearization(pair uv) {
    return linearization(uv.x, uv.y);
  /* Apply to a single Bezier spline. */
  guide _apply(pair p1, pair c1, pair c2, pair p2) {
    return apply(p1) .. controls linearization(p1)*c1 and linearization(p2)*c2 .. apply(p2);
  guide _apply(path g) {
    assert((length(g)) == 1);
    return _apply(point(g,0), postcontrol(g,0), precontrol(g,1), point(g,1));
  path apply(path g, int nInterpolate = nInterpolate) {
    guide toreturn;
    for (int i = 0; i < nInterpolate*length(g); ++i) {
      real currentpos = i / nInterpolate;
      real nextpos = (i+1) / nInterpolate;
      toreturn = toreturn & _apply(subpath(g, currentpos, nextpos));
    if (cyclic(g)) toreturn = toreturn & cycle;
    return toreturn;

planeTransformation polar;

polar.apply = new pair(real r, real theta) {
  return r * expi(theta);

polar.derivative = new transform(real r, real theta) {
  transform t = (0, 0, cos(theta), -r*sin(theta), sin(theta), r*cos(theta));
  return t;

path curvedbox = polar.apply(box((1, -pi), (2, pi)));

The result:

Note that this is only an approximate transformation. To make it more precise, call the function e.g. as polar.apply(g, nInterpolate=16); where g is the path to which the transformation should be applied. The default value is nInterpolate = 4; different paths will require different levels of interpolation. The more intricate the path already is, the fewer interpolation points are likely to be required.

Here's the result with

path curvedbox = polar.apply(box((1, -pi), (2, pi)), nInterpolate=16);

Additional note: The code above maps the y-value to the angle, whereas the OP originally requested mapping the y-value to the radius. Here's a function that should switch to the order originally requested:

path switchedPolar(path g) {
    return polar.apply(reflect((0,0),(1,1)) * g);

Alternatively, in the definitions of polar.apply and polar.derivative, the order of r and theta can be switched:

polar.apply = new pair(real theta, real r) {


  • That looks exactly like what I need! Thank you! I have tested it with a few simple figures, and it works really well. Thank you very much! Feb 18, 2014 at 21:07
  • 1
    If anyone else finds this solution of interest, be aware that it maps the y-value to the angle - not the x-value as suggested by my drawing earlier on. If one already has the drawing in a horizontal format one can use the following function guide swapaxis(guide g) {return reflect((0,0),(1,1))*g;} to swap the axis. One can then draw a picture similar to the ones above with the command polar.apply(swapaxis(box((-pi, 1), (pi, 2))); Feb 20, 2014 at 17:06
  • @christianhaargaard: Sorry about that. I think naturally in terms of (r, theta) rather than (theta, r). Feb 20, 2014 at 19:22

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .