6

What's the easiest way to produce a figure like this one? The curve is meant to look wiggly and random, and always non-increasing, except for the jumps up. I have tried using decorations with random steps, but that doesn't look right and is sometimes increasing. I have also tried a plot with a lot of individual coordinates that I generated randomly, but that didn't look smooth enough.

I'm happy to use either plain TikZ or pgfplots.

enter image description here

Edit: Here are two attempts.

The first uses random steps decoration, but the plot isn't smooth and it sometimes is increasing. I tried a few different amplitudes.

\documentclass{standalone}

\usepackage{tikz}
\pgfplotsset{compat=1.10}

\begin{document}

    \begin{tikzpicture}

        \draw[->] (0,0) -- (10,0);
        \draw[->] (0,0) -- (0,5);

        \draw [decorate, decoration={random steps,amplitude=2pt}] (0.2,4) -- (3,1);
        \draw (3,1) -- (3,5);
        \draw [decorate, decoration={random steps,amplitude=5pt}] (3,5) -- (5,0.2);
        \draw (5,0.2) -- (5,3);
        \draw [decorate, decoration={random steps,amplitude=8pt}] (5,3) -- (8,1.5);
        \draw (8,1.5) -- (8,4);
        \draw [decorate, decoration={random steps,amplitude=5pt}] (8,4) -- (9,3.5);

        \useasboundingbox (-1,-1) rectangle (11,6);

    \end{tikzpicture}

\end{document}  

enter image description here

The second attempt uses pgfplots with lots of finely spaced coordinates (which I generated randomly in Excel). This one is closer, but too fine-grained and not smooth enough.

\documentclass{standalone}

\usepackage{tikz}
\usepackage{pgfplots}
\pgfplotsset{compat=1.10}

\begin{document}

    \begin{tikzpicture}

        \begin{axis} [
            axis lines=left,
            xtick=\empty,
            ytick=\empty,
        ]

        \addplot [mark size=0]
            coordinates {
                (0.2,4)
                (0.245550438070978,3.9189299356319)
                (0.309894093387146,3.8555584914932)
                (0.374626991695131,3.77679077960278)
                (0.380585874068229,3.74823005668191)
                ... you get the idea ...                
                (11.2737449020538,2.23155401800146)
                (11.2994722948852,2.22522905911657)
                (11.3669785475168,2.17668213475497)
        };

        \end{axis}

    \end{tikzpicture}

\end{document}  

enter image description here

  • 2
    This is actually more of a math problem rather than drawing problem. monotonic random function requires some extra care – percusse Apr 22 '15 at 1:01
  • 2
    Questions about how to draw specific graphics that just post an image of the desired result are really not reasonable questions to ask on the site. Please post a minimal compilable document showing that you've tried to produce the image and then people will be happy to help you with any specific problems you may have. See minimal working example (MWE) for what needs to go into such a document. – cfr Apr 22 '15 at 1:04
  • As @cfr suggested, it would be helpful if you posted your failed attempt of using decorations and random steps. While solving problems can be fun, setting them up is not. Then, those trying to help can simply cut and paste your MWE and get started on solving the problem. – Peter Grill Apr 22 '15 at 1:54
  • Your first graph looks to have a constant discontinuity at random times. As for the rest, start with a random sequence, smooth it (low pass filter) then make it monotonic(several possible approaches). Lastly, add the random discontinuities. – John Kormylo Apr 22 '15 at 4:39
5

First let us look at the decoration random step:

\documentclass[border=9,tikz]{standalone}
\usetikzlibrary{decorations.pathmorphing}
\begin{document}
\makeatletter



\tikzset{
    demo decoration/.style={
        gray,
        postaction={draw=red,decorate,decoration={segment length=6pt,amplitude=3pt,meta-amplitude=12pt,#1}}
    }
}
\begin{tikzpicture}[remember picture]
    \path(0,0)node(A){}(6,0)node(B){};
    \draw[demo decoration=random steps](A)to[bend left](B);
\end{tikzpicture}

I can smoothen it by \pgfsetcornersarced. So I created a decoration called random drift.

\pgfdeclaredecoration{random drift}{start}
{
  \state{start}[width=+0pt,next state=step,persistent precomputation=\pgfdecoratepathhascornerstrue]
  {
    \egroup
    \pgfsetcornersarced{\pgfqpoint{.2\pgfdecorationsegmentlength}{.2\pgfdecorationsegmentlength}}
    \bgroup
  }
  \state{step}[width=+\pgfdecorationsegmentlength]
  {
    \pgfpathlineto{
      \pgfpointadd
      {\pgfqpoint{\pgfdecorationsegmentlength}{0pt}}
      {\pgfpoint{rand*\pgfdecorationsegmentamplitude}{rand*\pgfdecorationsegmentamplitude}}
    }
  }
  \state{final}
  {}
}
\begin{tikzpicture}
    \draw[demo decoration=random drift](A)to[bend left](B);
\end{tikzpicture}

And then I add some jumping-up. Here I use \pgf@randomsaw@y to store the y-coordinate and add negative random length to it so the function is non-increasing.

\pgfdeclaredecoration{random saw}{start}
{
  \state{start}[width=+0pt,next state=step,persistent precomputation=\pgfdecoratepathhascornerstrue]
  {
    \egroup
    \pgfsetcornersarced{\pgfqpoint{.2\pgfdecorationsegmentlength}{.2\pgfdecorationsegmentlength}}
    \bgroup
    \newdimen\pgf@randomsaw@y
  }
  \state{step}[width=+\pgfdecorationsegmentlength]
  {
    \pgfmathsetlength\pgf@ya{-rnd*\pgfmetadecorationsegmentamplitude}
    \pgfmathsetlength\pgf@yb{ rnd*\pgfmetadecorationsegmentamplitude}
    \ifdim\pgf@randomsaw@y<\pgf@ya
      \pgfsetcornersarced{\pgfqpoint{0pt}{0pt}}
      \pgfpathlineto{\pgfpoint{\pgfdecorationsegmentlength}{\pgf@randomsaw@y-4*rnd*\pgfdecorationsegmentamplitude}}
      \pgfpathlineto{\pgfqpoint{\pgfdecorationsegmentlength}{\pgf@yb}}
      \global\pgf@randomsaw@y\pgf@yb
    \else
      \pgfmathsetlength\pgf@xa{\pgfdecorationsegmentlength+rand*\pgfdecorationsegmentamplitude}
      \pgfmathsetlength\pgf@ya{\pgf@randomsaw@y-4*rnd*\pgfdecorationsegmentamplitude}
      \pgfpathlineto{\pgfqpoint{\pgf@xa}{\pgf@ya}}
      \global\pgf@randomsaw@y\pgf@ya
    \fi
  }
  \state{final}
  {}
}
\begin{tikzpicture}
    \draw[demo decoration={random saw,segment length=4pt,amplitude=2pt,meta-amplitude=20pt}](A)to[bend left](B);
\end{tikzpicture}



\end{document}
| improve this answer | |
  • This is terrific, thanks. To be honest I was figuring I'd just add the random "jumps" myself, so your automatic jumps are a bonus. One question -- what's the difference between amplitude and meta-amplitude? – LarrySnyder610 Apr 24 '15 at 21:43
  • 1
    @grendelsdad No difference except names. I mean, seriously, TikZ even gives the same initial value. Take a look at §V.48.1. These variables provide a convenient way to pass our parameters to the decoration engine. What those variables mean depends on how authors use them. In this case, read pgflibrarydecorations.pathmorphing.code.tex for more examples. – Symbol 1 Apr 25 '15 at 0:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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