5

Can something like this be done with pgfplots?

enter image description here

It was generated with whe following gnuplot script:

set view equal xy
set view 72,32
set xyplane relative 0.2
unset key
unset colorbox
set samples 21
set isosamples 21,21

set multiplot

unset border
unset tics
set contour
splot [-1:1][-1:1] sqrt(x**2+y**2) w pm3d at b

set border 4095
set ztics out
unset contour
set palette gray
splot [-1:1][-1:1] x**2+y**2 w pm3d

unset multiplot

The important features are the surface, which I know how to get on its own, and the colour-mapped projection on the bottom, plus contour lines, which I could get in a 2D plane, but as a flat plane in 3D is proving to be difficult.

Bonus features would be the shifted bottom plane, and the z ticks only on the left-most axis (even better if they were horizontal, as in gnuplot)

EDIT: Almost there:

enter image description here

\documentclass{standalone}
\usepackage{pgfplots}
\usepgfplotslibrary{patchplots}
\pgfplotsset{width=10cm,compat=1.10}

\begin{document}
\begin{tikzpicture}
\pgfplotsset{set layers}
\begin{axis}[
  domain=-1:1, y domain=-1:1,
  enlargelimits=false,
  view={32}{22},
  z post scale=1.5,
  3d box=complete,
  3d box foreground style={major tick length=0pt},
  xtick=\empty, ytick=\empty,
  ztick pos=left, ztick align=outside,
  samples=21, samples y=21,
  shader=flat, z buffer=sort,
]
\addplot3[surf,colormap/blackwhite] {x^2+y^2};
\end{axis}

\begin{axis}[
  domain=-1:1, y domain=-1:1,
  xmin=-1, xmax=1,
  ymin=-1, ymax=1,
  zmin=0, zmax=1,
  enlargelimits=false,
  view={32}{22},
  z post scale=1.5,
  axis lines=none,
  samples=21, samples y=21,
  clip=false,
]

% color-mapped plane
\addplot3[surf,
mesh/color input=colormap,
colormap/hot,
point meta={sqrt(x^2+y^2)},
point meta rel=per plot,
point meta min=0, point meta max=1.5,
shader=interp, patch type=bilinear,
update limits=false,
on layer=axis background,
] {-0.2};

% contours (needs --shell-escape)
\addplot3[contour gnuplot={levels={0.01,0,02,0,05,0.1,0.2,0.5,1},labels=false},
contour/draw color=black,
samples=51, samples y=51,
z buffer=default,
z filter/.code={\def\pgfmathresult{-0.2}},
update limits=false,
on layer=axis background,
] {sqrt(x^2+y^2)};

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

I added the bottom plane in a separate axis to be able to shift it a relative distance (relative to the size of the main plot). The ticks in the foreground axis can be disabled, but not those in the back one, they are hidden by the surface (except at the top corner), but would be visible with a different surface. I would also like to remove the bottom lines in the 3D box...

3

You can remove the 3d box entirely, then draw parts of it yourself.

\documentclass[border=5pt]{standalone}
\usepackage{pgfplots}
\usepgfplotslibrary{patchplots}
\pgfplotsset{width=10cm,compat=1.10}

\begin{document}
\begin{tikzpicture}
\pgfplotsset{set layers}
\begin{axis}[
  domain=-1:1, y domain=-1:1,
  enlargelimits=false,
  view={32}{22},
  z post scale=1.5,
  axis lines=right,
  %3d box=complete,
  %3d box foreground style={major tick length=0pt},
  xtick=\empty, ytick=\empty,
  ztick pos=left, ztick align=outside,
  samples=21, samples y=21,
  shader=flat, z buffer=sort,
]
\pgfplotsextra{\draw (rel axis cs: 0,1,1) -- (rel axis cs: 0,1,0);}%hidden
\addplot3[surf,colormap/blackwhite] {x^2+y^2};
\pgfplotsextra{\draw (rel axis cs: 1,1,0) -- (rel axis cs: 1,1,1)
  -- (rel axis cs: 1,0,1) -- (rel axis cs: 0,0,1)
  (rel axis cs: 1,0,1) -- (rel axis cs: 1,0,0);}
\end{axis}

\begin{axis}[
  domain=-1:1, y domain=-1:1,
  xmin=-1, xmax=1,
  ymin=-1, ymax=1,
  zmin=0, zmax=1,
  enlargelimits=false,
  view={32}{22},
  z post scale=1.5,
  axis lines=none,
  samples=21, samples y=21,
  clip=false,
]

% color-mapped plane
\addplot3[surf,
mesh/color input=colormap,
colormap/hot,
point meta={sqrt(x^2+y^2)},
point meta rel=per plot,
point meta min=0, point meta max=1.5,
shader=interp, patch type=bilinear,
update limits=false,
on layer=axis background,
] {-0.2};

% contours (needs --shell-escape)
\addplot3[contour gnuplot={levels={0.01,0,02,0,05,0.1,0.2,0.5,1},labels=false},
contour/draw color=black,
samples=51, samples y=51,
z buffer=default,
z filter/.code={\def\pgfmathresult{-0.2}},
update limits=false,
on layer=axis background,
] {sqrt(x^2+y^2)};

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

removed bottom of 3d box

  • Good idea! The contour is missing in your screenshot. Furthermore, it might benefit from output point meta=rawz inside of contour gnuplot and contour/draw color=mapped color!80!black. Note also that your levels list contains some unexpected fixed point numbers -- I suppose you wanted periods instead of commas – Christian Feuersänger Nov 21 '15 at 23:32
  • @Christian Feuersänger - The contours are from a file I don't have access to. Otherwise I pretty much left the MWE as is. – John Kormylo Nov 22 '15 at 3:10
  • @JohnKormylo I arrived to that solution too (but without arrows ;) ). @ChristianFeuersänger Yes, I had a mistake in the levels, but I prefer the lines black. – Jellby Nov 22 '15 at 8:49
2

I could call this final:

enter image description here

Since I am manually drawing the box, I can manually draw the ticks as well (with some lower-level trick), and avoid the crosses. I think the interior color is a nice touch, and I decided not to use a purely z-based color for the surface, as it looked too "fake" (too horizontal the gradient).

\documentclass{standalone}
\usepackage{pgfplots}
\usepgfplotslibrary{patchplots}
\pgfplotsset{width=10cm,compat=1.10}

\newcommand\dist{0.2}
\newcommand\asym{-0.5}

\begin{document}
\begin{tikzpicture}

\begin{axis}[
  domain=-1:1, y domain=-1:1,
  xmin=-1, xmax=1,
  ymin=-1, ymax=1,
  zmin=0, zmax=1,
  enlargelimits=false,
  view={32}{22},
  z post scale=1.5,
  axis lines=none,
  axis line style=gray,
  samples=21, samples y=21,
  clip=false,
]

% color-mapped plane
\addplot3[surf,
mesh/color input=colormap,
colormap/hot,
point meta={2*sqrt(x^2+y^2+(\asym*(x^2-y^2)))},
point meta rel=per plot,
point meta min=0, point meta max=3,
shader=interp, patch type=bilinear,
update limits=false,
] {-\dist};

% contours (needs --shell-escape)
\addplot3[contour gnuplot={levels={0.1,0.2,0.5,1,2,5},labels=false},
contour/draw color=black,
% high samples for smoother contours
samples=100, samples y=100,
z buffer=default,
z filter/.code={\def\pgfmathresult{-\dist}},
update limits=false,
] {2*sqrt(x^2+y^2+(\asym*(x^2-y^2)))};

\pgfplotsextra{
\draw[/pgfplots/every outer z axis line]
  (axis cs:-1,-1,-\dist)--(axis cs:1,-1,-\dist)--(axis cs:1,1,-\dist)--(axis cs:-1,1,-\dist)--cycle;
}

\end{axis}

\begin{axis}[
  % x is radius, y is angle
  % with -1<x<1 we plot both surfaces at once,
  % with even samples on x we ensure 0 is skipped,
  % and avoid problems with wrongly-oriented triangles
  domain=-1:1, y domain=0:360,
  samples=30, samples y=37,
  enlargelimits=false,
  view={32}{22},
  z post scale=1.5,
  xtick=\empty, ytick=\empty,
  axis x line=none, axis y line=none,
  ztick pos=left, ztick align=outside,
  major tick length=0pt,
  z tick label style={left=0.15cm,/pgf/number format/.cd,fixed,fixed zerofill,precision=2},
  axis z line*=right,
  axis line style=gray,
  z buffer=sort,
  shader=faceted, faceted color=black,
  % patch sampling for nice curved surface lines (slow)
  patch type=biquadratic, patch type sampling,
  point meta={sqrt(x^2+y^2)},
  colormap={graywhite}{color(0cm)=(black!80) color(1cm)=(white)},
  mesh/interior colormap={bluewhite}{color(0cm)=(blue!50!black!70) color(1cm)=(white)},
  line join=round,
  clip=false,
]

% Manual side and back axes
\pgfplotsextra{
\draw[/pgfplots/every outer z axis line]
  (rel axis cs:0,0,0)--(rel axis cs:0,0,1)--(rel axis cs:0,1,1)--(rel axis cs:1,1,1)--(rel axis cs:1,1,0)
  (rel axis cs:0,1,1)--(rel axis cs:0,1,0);
}

\addplot3[surf,fill opacity=0.9] ({x*cos(y)},{x*sin(y)},{x*sqrt(1+(\asym*cos(2*y)))});

% Manual front axes
\pgfplotsextra{
\draw[/pgfplots/every outer z axis line]
  (rel axis cs:0,0,1)--(rel axis cs:1,0,1)--(rel axis cs:1,1,1)
  (rel axis cs:1,0,1)--(rel axis cs:1,0,0);
}

% Manual tick marks
\makeatletter
\pgfplotsextra{
  \pgfplotslistforeach\pgfplots@prepared@tick@positions@major@z\as\pgfplots@curtickpos{
    \expandafter\pgfplots@prepared@tick@pos@unpack\pgfplots@curtickpos
    % \pgfplots@tick is given in absolute units, luckily we want the ticks at (0,0,z)
    \draw[/pgfplots/every outer z axis line] (0,0,\pgfplots@tick) -- +(180:0.15cm);
  }
}
\makeatother

\end{axis}

\end{tikzpicture}
\end{document}

Just a couple of issues:

  • fill opacity doesn't work with shader=faceted interp. I would even try with having different opacities for the exterior and interior colors, if that would be possible.

  • I can't find a way to get smooth contour lines (except by increasing the sampling beyond anything reasonable):

    enter image description here

  • You can play around with contour gnuplot={ ..., handler/.style=smooth}. However, tikz's smoothing is not particularly intelligent. There is even a smooth cycle which should be better, but it is not ... at least not for few samples. – Christian Feuersänger Nov 22 '15 at 17:08
  • @ChristianFeuersänger Thanks, I thought that the samples in the above screenshot (100) would be enough, but indeed both smooth and smooth cycle bring up other problems. – Jellby Nov 22 '15 at 21:05
  • A shame. Perhaps I'll have to implement a good plot handler for smooth interpolation eventually. I know that there is the hobby package which might be useful, it also comes with smooth plot handlers. Perhaps it is better here. – Christian Feuersänger Nov 22 '15 at 21:33

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.