TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top


Looking to emulate the following sinusoidal wave having random variations in both its filled and outline thickness:

Wavy Line

The wave has two parts: a variably thick filling and a variably thick outline. The MetaPost function function allows creating paths from function calls, such as sin. The initial curve can be created using something like:

path wave;
wave := curved function( 1, "sin(x)", "x", 1, 10, 1 ) xyscaled( 1cm, 1cm );

This produces a fairly close result:

Example Result


I have tried to make a variably thick pen:

  pen variably_thick;
  variably_thick := pencircle yscaled uniformdeviate( 1mm ) rotated 10;

Yet that sets the initial pen thickness -- there are no callbacks to increase or decrease the pen's thickness as the path is drawn.


A working example:



% Randomize the seed without having to delete the tuc file.
\ctxlua{math.randomseed( os.time() )}

% Draws three waves, somewhat evenly spaced, with two inflection points
% per line.
  color base_colour;
  base_colour := \MPcolor{BaseColour};

  % The wavy shape used for creating the wave and its border.
  path wave;

  % The wave "path"
  path underwave;

  % The wave "fill"
  path overwave;

  % Create the base path
  wave := curved function( 1, "sin(x)", "x", 1, 10, 1 ) xyscaled( 1cm, 1cm );

  % Draw the "path" for the wave (the outside edges)
  underwave := wave rotated 90 xscaled 5 yscaled .45;
  draw underwave withpen pencircle scaled 1.25cm withcolor (.7[base_colour,white]);

  % "Fill" the wave.
  overwave := wave rotated 90 xscaled 5 yscaled .5;
  draw overwave withpen pencircle scaled 1cm withcolor base_colour;


  \input knuth


How would you create a curve in MetaPost that produces a variably thick line?


From the MetaPost examples:

  path p;
  p =
  for i=.1 step .1 until 10:
    hide( pair A; A = (i*u, (sind (i*180/3.14))/i *u);
          draw A withpen pencircle scaled 2pt )
    .. A
  draw p;

It should be possible to use the code above (i.e., loop over a sine wave) to draw the curve while varying the pen's thickness throughout the loop, but I was hoping there was cleaner solution.


share|improve this question
up vote 6 down vote accepted

While not an answer the question of variably thick curves, another approach to emulate the desired outcome is to think of the curves as simply two offset sine waves, connected at each end:

  color base_colour;
  base_colour := \MPcolor{BaseColour};

  deviation_dark := uniformdeviate( .025 );
  def dark_colour = deviation_dark [base_colour, black] enddef;

  wave_height := 1.5mm;

  path top_wave;
  top_wave := (0, 0);

  wave_resolution := 20;

  for x = 0 step (1 / wave_resolution) until 2:
    y := sin( x * pi );
    top_wave := top_wave .. (x, y);

  % Duplicate the top wave, but move it up a random amount.
  path bottom_wave;
  bottom_wave := top_wave shifted( 0, wave_height );

  % Offset the waves.
  top_wave := top_wave xyscaled (5.5cm, 5mm);
  bottom_wave := bottom_wave xyscaled (6.5cm, 4.5mm);

  % Create a path for connecting the waves.
  path wave_right_side;
  wave_right_side :=
    (point length(top_wave) of top_wave) --
    (point length(bottom_wave) of bottom_wave);

  % Connect the waves.
  path wave;
  wave := top_wave & wave_right_side & reverse bottom_wave -- cycle;

  % Stretch the wave to extend beyond the page boundaries.
  wave := wave xscaled( 2.5 );

  draw wave withpen pencircle scaled 3mm withcolor .7[base_colour,white];
  fill wave withcolor dark_colour;

This produces a reasonable facsimile:

Double Sine Wave

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.