# Generate 3d surface plot using black and white heightmap and pgfplots

I am searching for the best way, software or script (latex, python, R, octave), to interactively draw or paint some 3D surface plot for pedagogic usage.

I finally found a way to generate and transform pdf 3D surface plot with svg export using pgfplots latex package. Thus I can redraw/rework initial drawing to render a graphic like this.

But I don't want to use a common mathematic function for input of the 3d drawing, I want to use, if possible, a heightmap to generate the surface.

Is it possible to transform a random black and white heightmap into a 3Dsurface plot with pgfplots ?

I used scipy to transform the heightmap to a data matrix and then wrote the coordinates and the height values to a file.

# Exact height profile

#!/usr/bin/env python

from __future__ import print_function
import numpy as np
from scipy import misc

x,y = matrix.shape

mesh = ""
for i in range(0,x):
for j in range(0,y):
mesh += "%d\t%d\t%d\n" % (i,j,matrix[i,j])
mesh += "\n"

print(mesh)


I ran the script and piped the output to a file called matrix.dat

python extract.py > matrix.dat


Then I used pgfplots to visualise the matrix

\documentclass[tikz]{standalone}
\usepackage{pgfplots}
\begin{document}
\begin{tikzpicture}
\begin{axis}
\end{axis}
\end{tikzpicture}
\end{document}


You need to use lualatex for this as pdflatex will run out of memory. Processing this file takes ca. 1 minute and 52 seconds on my machine.

In the rendered png the colour map turned out darker than in the pdf.

# Averaged height profile

The following script introduces some averaging over all points of the mesh (factor of 5 here). The rest of the procedure stays the same.

#!/usr/bin/env python

from __future__ import print_function
import numpy as np
from scipy import misc

x,y = matrix.shape
matrix = misc.imresize(matrix,(x/5,y/5))
x,y = matrix.shape

mesh = ""
for i in range(0,x):
for j in range(0,y):
mesh += "%d\t%d\t%d\n" % (i,j,matrix[i,j])
mesh += "\n"

print(mesh)


This is now compilable with pdflatex (no more out-of-memory) and takes ca. 3 seconds.

Here an updated Python 3 code:

 #!/usr/bin/python3

import numpy as np

import imageio

matrix = imageio.imread('536ws.jpg', as_gray = True)
x,y=matrix.shape

mesh = ' '
for i in range(0,x):
for j in range(0,y):
mesh += '%d \t %d \t %d \n' % (i,j,matrix[i,j])
mesh += '\n'

print(mesh)


To get the .dat file:

python3 extract.py > matrix.dat


The latex code is

\documentclass[tikz]{standalone}
\usepackage{pgfplots}

\begin{document}

\begin{tikzpicture}
\begin{axis}

lualatex file.tex