8

Is there a way to get for all tikz-plots in one LaTeX document the same distance between the plot marks, ie the distance between the marks should be independent of sample size. It would be really great if this change wouldn't interfere with the legend like change the position of the marker in the legend etc. Thanks.

Edit: Unfortunately the distance of all data points (not in the mini example but for the real data) is not the same therefore it would be nice if I could define distance between the marks in cm.

\documentclass[tikz,border=1mm]{standalone}
\usepackage{pgfplots}
\usetikzlibrary{decorations.markings}
\pgfplotsset{compat=1.11}
%\tikzset{mark/.style={
%        decoration={
%            markings,
%            mark= between positions 0 and 1 step 5mm with
%                {
%                %\node[circle,inner sep=2pt,fill=blue]{};
%            },
%        },
%        postaction={decorate}
%    }
%}
\begin{document}
\begin{tikzpicture}
\begin{axis}[]
\addplot[
  blue,
  domain=0:3,
  samples=100,
  mark=*
  ]
{exp(x)};
\addlegendentry{exp(x)};

\addplot[
  red,
  domain=0:3,
  samples=20,
  mark=diamond
  ]
{4*x};
\addlegendentry{4x};

\end{axis}
\end{tikzpicture}
\end{document}

edit: Is is possible to pass to tikz such options like mark size or mark options={solid} ?

    \addplot [color=black,loosely dotted,line width=1.5pt, mark=*,mark size=3pt, mark=diamond,mark options={solid}]

edit2: I found out how I can set the marks solid in the legend but how can I do the same in for the plot? Any ideas how to get the plot marks solid in the actual plot?

\tikzset{
  nomorepostactions/.code={\let\tikz@postactions=\pgfutil@empty},
  mymark/.style={decoration={markings,
    mark= between positions 0 and 1 step (1/11)*\pgfdecoratedpathlength with{%
        \pgfuseplotmark{#1},%
      },  
    },
    postaction={decorate},
    /pgfplots/legend image post style={mark=#1,every path/.append style={nomorepostactions}},
  },
  every mark/.append style={solid,mark size=3},
}

enter image description here

11

Similar to Harish's answer but removes the need to plot twice. You basically need to stop the postaction reaching to the legend pictures because that is what is causing the funky mark placement. And that you can do with our good ol' answer to Applying a postaction to every path in TikZ

\documentclass[]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.11}
\usetikzlibrary{decorations.markings}
\makeatletter
\tikzset{
  nomorepostactions/.code={\let\tikz@postactions=\pgfutil@empty},
  mymark/.style 2 args={decoration={markings,
    mark= between positions 0 and 1 step (1/11)*\pgfdecoratedpathlength with{%
        \tikzset{#2,every mark}\tikz@options
        \pgfuseplotmark{#1}%
      },  
    },
    postaction={decorate},
    /pgfplots/legend image post style={
        mark=#1,mark options={#2},every path/.append style={nomorepostactions}
    },
  },
}
\makeatother

\begin{document}
\begin{tikzpicture}
\begin{axis}[legend style={at={(0.5,0.95)}, anchor=north},
  legend entries={$\exp(x)$,$10\sin(5x)$},
]
\addplot[blue,dashed, domain=0:3,samples=15,mymark={o}{solid}]{exp(x)};
\addplot[red,domain=0:3, dashdotted,samples=200,
           mymark={diamond*}{draw=black,fill=yellow,solid}]{10*sin(deg(5*x))};
\end{axis}
\end{tikzpicture}
\end{document}

You can also add yet another parameter for how many marker you want to have by dividing the total path length to a fixed number. Here I went with 11. (replacing it with a distance is what you wish probably but I put here as an alternative)

enter image description here

with 1 cm mark distance

enter image description here

EDIT For the added style question, the code now gives

enter image description here

|improve this answer|||||
  • Thanks you very much, I'm using 'densely dashed' -- is there a way to set options like 'mark options={solid} or 'mark size=2.5pt'? – jlk Mar 8 '15 at 15:25
  • This is a really neat solution. However, if I use dashed as line type, I would also like to have the line in the legend dashed. This however is not the case for your latest example. Is there a possibility to preserve the original line style in the legend? – raedma Jun 5 '16 at 21:14
  • A simple \pgftransformresetnontranslations before \pgfuseplotmark{#1} improves this beautiful solution by keeping the orientation of the markers fixed, as in the legend. – DennisH Dec 30 '16 at 11:24
6

Done with MetaPost, with the actual sinus curve. (The legend box is still to be done.) For the markers, is it something like that you wish to obtain?

Note that it is only an adaptation of my answer to a very similar question here: Pgfplot, show mark when distance along the path is reached

Edit The cartouche is here now, with some other (minor) changes.

\documentclass[border=2bp]{standalone}
\usepackage{luamplib}
    \mplibsetformat{metafun}
    \mplibtextextlabel{enable}
    \mplibnumbersystem{double}
\begin{document}
\begin{mplibcode}
% Reimplementation of the `point .. of ..` binary operator
% somewhat bugged in the current metafun format: 
% http://tug.org/pipermail/metapost/2015-March/003065.html
primarydef len on pat = % no outer ( ) .. somehow fails
     (arctime if len>=0 : len else : (arclength(pat)+len) fi of pat) of pat
enddef;

% Parameters
u = 2cm; v = .3cm; pen bigdot; bigdot = pencircle scaled 3bp;
xmin = -.25; xmax = 3.25; ymin = -1; ymax = 22.5;
len = 4bp; nmarks = 20; % length and number of marks

% Function curve
vardef function(expr xmin, xmax, xstep)(text f_x) =
    save x; x := xmin;
    (x, f_x)
    forever:
        hide(x := x + xstep)
        exitunless x <= xmax;
        .. (x, f_x)
    endfor
    if x - xstep < xmax: hide(x := xmax) .. (x, f_x) fi
enddef;

% Exponential and sinusoide curve
path expcurve; expcurve = function(ceiling(xmin), floor(xmax), .1)(exp x) xyscaled (u, v);
path sincurve; sincurve = function(ceiling(xmin), floor(xmax), .1)(10sin x) xyscaled (u, v);

% Space between marks
exp_marksep = arclength expcurve / (nmarks-1);
sin_marksep = arclength sincurve / (nmarks-1);

% Cartouche management
def define_cartouche(text cartouche)(expr pos) = 
    picture cartouche; cartouche = nullpicture;
    numeric _cnt; _cnt = 0;
    def addto_cartouche (suffix cartouche)(expr wd, str) =
        addto cartouche also (image(draw pos - (wd,0) -- pos; 
            drawdot pos - (.5wd, 0) withpen bigdot;
            label.rt(str, pos) withcolor black)
                yshifted -_cnt*\mpdim{\baselineskip});
        _cnt := _cnt + 1;
    enddef;
enddef;

beginfig(1);
    define_cartouche(box)((2u, 20v));

    % Curves and marks
    drawoptions(withcolor blue); draw expcurve;
    for i = 0 upto nmarks-1:
        %drawdot point (arctime (i*exp_marksep) of expcurve) of expcurve withpen bigdot; 
        draw point (i*exp_marksep) on expcurve withpen bigdot;      
    endfor
    addto_cartouche(box, .5cm, "$\exp x$");

    drawoptions(withcolor red); draw sincurve;
    for i = 0 upto nmarks-1:
        %draw point (arctime (i*sin_marksep) of sincurve) of sincurve withpen bigdot; 
        draw point (i*sin_marksep) on sincurve withpen bigdot;
    endfor
    addto_cartouche(box, .5cm, "$10\sin x$");

    % Axes and labels
    drawoptions();
    draw ((xmin, ymin) -- (xmax, ymin) -- (xmax, ymax) -- (xmin, ymax) -- cycle) xyscaled (u, v);  
    for i = 0 upto 3:
        draw (u*i, ymin*v) -- (u*i, ymin*v+len);
        draw (u*i, ymax*v) -- (u*i, ymax*v-len);
        label.bot(decimal i, (i*u, ymin*v));
    endfor;  
    for j = 0 step 5 until 20:
        draw (xmin*u, j*v) -- (xmin*u + len, j*v);
        draw (xmax*u, j*v) -- (xmax*u - len, j*v) ;
        label.lft(decimal j, (xmin*u, j*v));
    endfor;

    draw bbox box enlarged 2bp; draw box;

endfig;
\end{mplibcode}
\end{document}

enter image description here

|improve this answer|||||
5

If a manual solution is sufficient for your usage, you can use the mark repeat=<n> key to draw only every n th mark. Here, I've added 1 to each of your samples settings so that things work out in nice integers:

\documentclass[tikz,border=1mm]{standalone}
\usepackage{pgfplots}
\usetikzlibrary{decorations.markings}
\pgfplotsset{compat=1.11}

\begin{document}
\begin{tikzpicture}
\begin{axis}[]
\addplot[
  blue,
  domain=0:3,
  samples=101,
  mark=*,
  mark repeat=5, % calculated using (101-1)/(21-1) = 5
  ]
{exp(x)};
\addlegendentry{exp(x)};

\addplot[
  red,
  domain=0:3,
  samples=21,
  mark=diamond
  ]
{4*x};
\addlegendentry{10 sin(x)};

\end{axis}
\end{tikzpicture}
\end{document}

enter image description here

|improve this answer|||||
  • Thanks you very much for your suggestion -- unfortunately the distance of all data points is not the same therefore it would be nice if I could define distance between the marks in cm. – jlk Mar 8 '15 at 8:24
  • @harryhaller Then what's wrong with the decoration stuff you posted in your question? Note that, pgfplots uses markers to mark the data points. TikZ markings decoration is different. – percusse Mar 8 '15 at 10:29
  • @percusse: it influences the legend, eg there are two markers in on the same legend entry and the marker is not centered, ie the marker position in the legend is a fuction of the distance. Furthermore, it's not really universal, ie I need to define a decoration for every maker type. I'm fine with the second point but it's awkward that the marker in the legend moves as a function of the distance. – jlk Mar 8 '15 at 11:08
5

Hee is a way that uses legend image post style and tikz decorations. We define a decoration first and then plot the same curve two times, once only with decorated marks, and then without markers.

\documentclass[tikz,border=1mm]{standalone}
\usepackage{pgfplots}
\usetikzlibrary{decorations.markings}
\usetikzlibrary{plotmarks}
\pgfplotsset{compat=1.11}
\tikzset{mymark/.style={
        decoration={
            markings,
            mark= between positions 0 and 1 step 5mm with
                {
                \pgfuseplotmark{#1};
            },
        },
        postaction={decorate}
    }
}



\begin{document}
\begin{tikzpicture}
\begin{axis}[legend style={at={(0.5,0.95)}, anchor=north}]
\addplot[
  blue,
  domain=0:3,
  samples=100,
  mymark={o},
  draw=none,
  forget plot,     %% don't consider this plot for legends
  ]
{exp(x)};
\addplot[
  blue,
  domain=0:3,
  samples=100,
  mark=none,smooth,
  legend image post style={mark=o}  %% <-----
  ]
{exp(x)};
\addlegendentry{exp(x)};

\addplot[
  red,
  domain=0:3,
  samples=20,
  mymark={diamond},
  draw=none,
  forget plot,
  ]
{4*x};
\addplot[
  red,
  domain=0:3,
  samples=20,
  mark=none,smooth,
  legend image post style={mark=diamond}
  ]
{4*x};
\addlegendentry{10 sin(x)};

\end{axis}
\end{tikzpicture}
\end{document}

enter image description here

|improve this answer|||||
  • Thanks you very much, I'm using 'densely dotted' -- is there a way to set options like 'mark options={solid} or 'mark size=2.5pt' for the plot? – jlk Mar 9 '15 at 13:06
  • @harryhaller densely dotted for what, the line or the mark? – user11232 Mar 9 '15 at 13:20

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.