The documentation says
ListPlot3D[array]
requires array
to be a rectangular shape and that by default it assumes that the x
and y
coordinates for each point data point to be successive integers starting at 1.
What it doesn't state is which coordinate, x
or y
, changes fastest?
Looking at the examples it is clear that the x
coordinate is the fastest changing.
So for example:
zVals = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}, {13, 14, 15, 16}};
means that for the first sub-list we would write {x, y, z} by holding the y
value at a constant value of 1 and allowing x
to increment from 1 to 4
{1, 2, 3, 4} -> {1,1,1}, {2,1,2}, {3,1,3}, {4,1,4}
Similarly for the second sublist we hold the y
value at a constant of 2 and allow x
to once again increment from 1 to 4
{5, 6, 7, 8} -> {1,2,5}, {2,2,6}, {3,2,7}, {4,2,8}
and so on.
To convert the zVals
to pts
with {x,y,z}
values use:
pts = Flatten[ Table[{j, i, zVals[[i, j]]}, {i, 4}, {j, 4}], 1]
(* {{1, 1, 1}, {2, 1, 2}, {3, 1, 3}, {4, 1, 4},
{1, 2, 5}, {2, 2, 6}, {3, 2, 7}, {4, 2, 8},
{1, 3, 9}, {2, 3, 10}, {3, 3, 11}, {4, 3, 12},
{1, 4, 13}, {2, 4, 14}, {3, 4, 15}, {4, 4, 16}} *)
and then
ListPlot3D[zVals, Mesh -> All, AxesLabel -> {x, y, z}]

ListPlot3D[pts, Mesh -> All, AxesLabel -> {x, y, z}]

If instead you use
pts = Catenate@MapIndexed[{Sequence @@ #2, #1} &, zVals, {2}]
(* {{1, 1, 1}, {1, 2, 2}, {1, 3, 3}, {1, 4, 4}, {2, 1, 5}, {2,
2, 6}, {2, 3, 7}, {2, 4, 8}, {3, 1, 9}, {3, 2, 10}, {3, 3, 11}, {3,
4, 12}, {4, 1, 13}, {4, 2, 14}, {4, 3, 15}, {4, 4, 16}} *)
which is equivalent to
pts = Flatten[Table[{i, j, zVals[[i, j]]}, {i, 4}, {j, 4}], 1]
(* {{1, 1, 1}, {1, 2, 2}, {1, 3, 3}, {1, 4, 4}, {2, 1, 5}, {2,
2, 6}, {2, 3, 7}, {2, 4, 8}, {3, 1, 9}, {3, 2, 10}, {3, 3, 11}, {3,
4, 12}, {4, 1, 13}, {4, 2, 14}, {4, 3, 15}, {4, 4, 16}} *)
the resulting figure has the wrong relationship between x
, y
and z
.
ListPlot3D[pts, Mesh -> All, AxesLabel -> {x, y, z}]

Update - Triangulation
As pointed out by m_goldberg the proposed solution has a different triangulation compared to the figure using zVals
.
That had escaped my notice.
I dissected the figure and discovered that it used GraphicsComplex
with a list of identical points between the two figures but a different set of polygons (same points, different connection resulting in different polygons).
I have not been able to figure out the rules that Mathematica uses for connecting the points with Mesh -> All
but I was able to discover that one would get different connections if one input a different order for the points.
By trial and error I stumbled upon that if I took the original set of {x, y, z}
points (i.e, pts
with x
changing most rapidly) and ordered them by what I will call the decrement x
and increment y
order, I was able to achieve the same triangulation.
pts = Flatten[Table[{j, i, zVals[[i, j]]}, {i, 4}, {j, 4}], 1]
(* {{1, 1, 1}, {2, 1, 2}, {3, 1, 3}, {4, 1, 4}, {1, 2, 5}, {2,
2, 6}, {3, 2, 7}, {4, 2, 8}, {1, 3, 9}, {2, 3, 10}, {3, 3, 11}, {4,
3, 12}, {1, 4, 13}, {2, 4, 14}, {3, 4, 15}, {4, 4, 16}} *)
ptsDecXandIncY =
pts[[{4, 3, 2, 1, 8, 7, 6, 5, 12, 11, 10, 9, 16, 15, 14, 13}]]
(* {{4, 1, 4}, {3, 1, 3}, {2, 1, 2}, {1, 1, 1}, {4, 2, 8}, {3,
2, 7}, {2, 2, 6}, {1, 2, 5}, {4, 3, 12}, {3, 3, 11}, {2, 3, 10}, {1,
3, 9}, {4, 4, 16}, {3, 4, 15}, {2, 4, 14}, {1, 4, 13}} *)
ListPlot3D[ptsDecXandIncY, Mesh -> All, AxesLabel -> {x, y, z}]

Unfortunately I am unable to determine what the general rule is for connecting the points.
Hope this helps.
ListPlot3D
is generating the first edge of the triangle from the first two sequential points. Permuting the 2nd and 6th point of the catenated list results in precisely 1 re-triangulation.zc = Catenate@MapIndexed[{Sequence @@ #2, #1} &, zVals, {2}]; ex = zc[[{1, 6, 3, 4, 5, 2, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}]]; ListPlot3D[ex,Mesh->All]
No clue yet what orderListPlot3D
is generating its points fromzVals
though. $\endgroup$ – eyorble Jan 3 '18 at 2:27