2

I'm trying to draw a plot which I've been given in a scan: scanned plot

What is the correct way to plot a custom shaped curve --- a freehand tool counterpart. I used quick curve but it's hard to tell extremum from an inflection point.

\begin{figure}
\centering
\bt[xscale=0.03,yscale=0.03]
%\draw (0,0) grid[step=10](200,120);
\coordinate(a) at (0,0);
\coordinate(b) at (20,0);
\coordinate(c1) at (25,2);
\coordinate(c) at (30,10);
\coordinate(d) at (48,50);
\coordinate(ce) at (65,90);
\coordinate(e) at (80,110);
\coordinate(f) at (90,100);
\coordinate(g1) at (89,98);
\coordinate(g) at (93,95);
\coordinate(h) at (100,103);
\coordinate(ci) at (102,103);
\coordinate(i) at (130,100);
\coordinate(cj) at (165,96.6);
\coordinate(j) at (170,95);
\coordinate(ccl) at (172,90);
\coordinate(cl) at (198,5);
\coordinate(l) at (200,0);
\coordinate(m) at (206,-10);
\coordinate(n) at (218,0);
\coordinate(o) at (222,8);
\coordinate(cp) at (232,-3);
\coordinate(p) at (240,0);
\coordinate(r) at (248,0);
\coordinate(z) at (260,0);
\draw[>=latex,->](0,-18)--(0,128)node[left]{$U$};
\draw[>=latex,->](0,0)--(270,0)node[right]{$t$};
\draw[red,semithick] (a)--(b);
\draw[red,semithick] (b) to%
[quick curve through={(c1)(c)(d)(ce)(e)(f)(g)(h)(ci)(i)}] (cj);
\draw[red,semithick] (cj) to%
[quick curve through={(j)(ccl)(cl)(l)(m)(n)(o)(cp)(p)(r)}] (z);
\et
\caption{Charakterystyczne parametry przebiegów impulsowych}
\label{rys:przebiegimpulsowy}
\end{figure}

My plotted image

The result is very prone errors when any of the points is moved even a bit. Is there a better way to do that?

  • Could you please include your preamble as well? – Alenanno Oct 20 '13 at 22:34
  • I understand, that the question is general, but in this case one can probably obtain an expansion into a Fourier series. Which (Polish) book is the source of this picture? I hope that it contains an additional information. – Przemysław Scherwentke Oct 21 '13 at 4:07
3

I would do it using the the to[in=,out=,looseness=] operation, that way you need to specify coordinates and slopes, the looseness is an optional parameter that is 1 if not specifically set. Here's my first try with wildly guessing points. By the way: as it is, your curve is not a function of time as it reverses: \coordinate(f) at (90,100);comes before \coordinate(g1) at (89,98);, I changed that.

Code

\documentclass[tikz,border=2mm]{standalone}
\usetikzlibrary{arrows}

\begin{document}

\newcounter{myc}

\newcommand{\setinitialcoordinates}[3]% x, y, slope in degrees
{   \xdef\lastx{#1}
    \xdef\lasty{#2}
    \xdef\lastslope{#3}
}

\newcommand{\drawpiece}[4][1]%[looseness] target x, target y, target slope
{   \pgfmathsetmacro{\colo}{mod(\value{myc},4)*20+20}
    \stepcounter{myc}

    \pgfmathsetmacro{\inslope}{mod(#4+180,360)}

    \draw (\lastx,\lasty) to[out=\lastslope,in=\inslope,looseness=#1] (#2,#3);
    %\draw[red!\colo!blue] (\lastx,\lasty) to[out=\lastslope,in=\inslope,looseness=#1] (#2,#3);

    \xdef\lastx{#2}
    \xdef\lasty{#3}
    \xdef\lastslope{#4}
}

\begin{tikzpicture}[x={(0:0.03cm)},y={(90:0.03cm)}]
    \draw[step=10,densely dotted, thin,gray] (0,0) grid (260,110);
    \draw[-stealth,thick] (-5,0) -- (265,0) node[right] {$t$};
    \draw[-stealth,thick] (0,-5) -- (0,115) node[left] {$U$};

    \setinitialcoordinates{0}{0}{0}

    \begin{scope}[red,very thick]
        \drawpiece{20}{0}{0}    
        \drawpiece{25}{2}{45}
        \drawpiece{30}{10}{70}
        \drawpiece{48}{50}{80}

        \drawpiece{65}{90}{70}
        \drawpiece{80}{110}{0}
        \drawpiece{89}{100}{-60}
        \drawpiece{90}{98}{-30}

        \drawpiece{93}{95}{0}
        \drawpiece{100}{103}{3}
        \drawpiece{102}{103}{0}
        \drawpiece{130}{100}{-2}

        \drawpiece{165}{96.6}{-10}
        \drawpiece{170}{95}{-30}
        \drawpiece{172}{90}{-70}
        \drawpiece[0.2]{198}{5}{-85}

        \drawpiece{200}{0}{-60}
        \drawpiece{206}{-10}{0}
        \drawpiece{218}{0}{60}
        \drawpiece{222}{8}{0}

        \drawpiece{232}{-3}{0}
        \drawpiece{240}{0}{-5}
        \drawpiece{248}{0}{1}
        \drawpiece{260}{0}{0}
    \end{scope}
\end{tikzpicture}

\end{document}

Output

enter image description here


Edit 1

The first attempt does not look to well, but I think mainly because I used all the points you provided. It looks a lot better if you just use the extrema and the knee:

Code 1

\begin{tikzpicture}[x={(0:0.03cm)},y={(90:0.03cm)}]
    \draw[step=10,densely dotted, thin,gray] (0,0) grid (260,110);
    \draw[-stealth,thick] (-5,0) -- (265,0) node[right] {$t$};
    \draw[-stealth,thick] (0,-5) -- (0,115) node[left] {$U$};

    \setinitialcoordinates{0}{0}{0}

    \begin{scope}[red,very thick]
        \drawpiece{20}{0}{0}    
        \drawpiece[0.5]{80}{110}{0}
        \drawpiece{93}{95}{0}
        \drawpiece{102}{103}{0}

        \drawpiece[0.5]{165}{96.6}{-10}

        \drawpiece[0.3]{206}{-10}{0}
        \drawpiece[0.7]{222}{8}{0}
        \drawpiece{232}{-5}{0}
        \drawpiece{248}{2}{0}
        \drawpiece{260}{0}{0}
    \end{scope}
\end{tikzpicture}

Output 1

enter image description here

As you mentioned that your current solution is very sensitive to small changes, here's the same thing just with different x coordinates and a different knee angle:

Code 2

\begin{tikzpicture}[x={(0:0.03cm)},y={(90:0.03cm)}]
    \draw[step=10,densely dotted, thin,gray] (0,0) grid (260,110);
    \draw[-stealth,thick] (-5,0) -- (265,0) node[right] {$t$};
    \draw[-stealth,thick] (0,-5) -- (0,115) node[left] {$U$};

    \setinitialcoordinates{0}{0}{0}

    \begin{scope}[red,very thick]
        \drawpiece{20}{0}{0}    
        \drawpiece[0.5]{60}{110}{0}
        \drawpiece{110}{95}{0}
        \drawpiece{120}{103}{0}

        \drawpiece[0.5]{140}{96.6}{-40}

        \drawpiece[0.3]{170}{-10}{0}
        \drawpiece[0.7]{200}{8}{0}
        \drawpiece{220}{-5}{0}
        \drawpiece{240}{2}{0}
        \drawpiece{260}{0}{0}
    \end{scope}
\end{tikzpicture}

enter image description here

0

I realize this is not a LaTeX-only solution, and so it may be unsatisfactory, but I had to do this recently with a similar plot and this is what I did.

I used pgfplots to define a piecewise function whose pieces were minimal degree interpolating polynomials satisfying the constraints that I wanted (go through a point, have a certain derivative at a point, etc). Unfortunately, I don't know how to get the interpolating polynomials from within tike/pgfplots . . . you could use an external applet, python, mathematica, etc.

The result looked pretty good:

\documentclass{article}
\usepackage{pgfplots}


\begin{document}

 \pgfmathdeclarefunction{MyF}{1}{% 
  \pgfmathparse{% 
     (and (1 , #1<=5)*(3.-0.5*#1-2.24667*#1^2+2.93766*#1^3-1.55322*#1^4+0.413019*#1^5-0.0534444*#1^6+0.00265741*#1^7))   +%
     (and (5<#1 , #1<7)*(4))     +%
     (and (7<=#1 , #1<12)*(131.4-156.613*#1+54.0096*#1^2-7.99267*#1^3+0.538*#1^4-0.0135556*#1^5))    +%
     (and (12<=#1 , 1)*(1))  %
  }%
}

\begin{center} 
\begin{tikzpicture}
\begin{axis}[axis lines = middle,minor tick num = 1, grid = both, xlabel = $t$, ylabel = $x$, no markers, smooth,xmin=0, xmax=14, ymin=-6, ymax=6, samples = 100, thick]
\addplot +[very thick, domain=0:14] {MyF(x)};
\end{axis}
\end{tikzpicture}
\end{center} 

\end{document}

enter image description here

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.