5
$\begingroup$

RegionFunction is normally good at suppressing points in a plot:

ListPlot3D[Flatten[Table[{x, y, RandomReal[]*(x^2 + y^2)}, {x, -5, 5}, {y, -5, 5}], 1], 
RegionFunction -> ((#2 >= #1 && #2 >= -#1) || (#2 <= #1 && #2 <= -#1) &)]

enter image description here

Now consider this data, which is some random numbers over a diamond-shaped domain:

data = {#[[1]], #[[2]], #[[3]]*(#[[1]]^2 + #[[2]]^2)} & /@
   ({(#[[1]] - #[[2]])/2, (#[[1]] + #[[2]])/2, #[[3]]} & /@ 
   Flatten[Table[{x, y, RandomReal[0.1]}, {x, 0, 5}, {y, 0, 5}], 1]);
ListPlot3D[data, PlotRange -> {0, 5}]

enter image description here

Now let's mirror the data over the x-axis, and note that ListPlot3D will automatically plot the connecting regions between the two diamonds:

dataMirrored = DeleteDuplicates@Join[data, {#[[1]], -#[[2]], #[[3]]} & /@ data];
ListPlot3D[dataMirrored, PlotRange -> {All, All, {0, 5}}]

enter image description here

Now, it seems RegionFunction doesn't work - I guess this has something to do with the data taking similar values across the gap:

ListPlot3D[dataMirrored, PlotRange -> {0, 5}, 
   RegionFunction -> ((#2 >= #1 && #2 >= -#1) || (#2 <= #1 && #2 <= -#1) &)]

enter image description here

Even adding a small perturbations to all three coordinates of every point does not completely block this behavior:

ListPlot3D[{#[[1]] + RandomReal[10^-3], #[[2]] + RandomReal[10^-3], 
   #[[3]] + RandomReal[10^-3]} & /@ dataMirrored, PlotRange -> {0, 5},
    RegionFunction -> ((#2 >= #1 && #2 >= -#1) || (#2 <= #1 && #2 <= -#1) &)]

enter image description here

How can I get ListPlot3D to respect RegionFunction?

$\endgroup$
1
$\begingroup$

First of all, since I will be using quite a few ListPlot3D calls, I'd like to keep them all consistent and readable by introducing a wrapper function, myLP3D that sets a manual plot range and labels the axes, but passes any further optional argument through to the underlying ListPlot3D:

Clear[myLP3D]
myLP3D[pts_List, opts : OptionsPattern[ListPlot3D]] :=
  ListPlot3D[
    pts,
    PlotRange -> {{-5, 5}, {-5, 5}, Automatic},
    AxesLabel -> (Style[#, 14, Bold] & /@ {"x", "y", "z"}),
    Evaluate[FilterRules[{opts}, Options[ListPlot3D]]]
  ]

I generated some data on the same domain you were using, but I will not use random $z$ values: I find it irrelevant to your question and confusing because it leads to ugly, poorly readable surfaces. Instead, I will assign a constant $z=1$. I then generated a mirrored set as you specified ($y$ coordinate swapped sign). mirrored is actually a list of the two data sets, the original and the mirrored ones, so they can be readily visualized:

data =
  {(#1 - #2)/2, (#1 + #2)/2, 1} & @@@
   Flatten[Table[{x, y}, {x, 0, 5}, {y, 0, 5}], 1];

mirrored = {data, {#1, -#2, #3} & @@@ data};

GraphicsRow[{myLP3D[data], myLP3D[mirrored]}, ImageSize -> Full]

original and mirrored

I then generate the joined set: all points from the mirrored set, but in a single list:

joined = DeleteDuplicates@Join[Sequence @@ mirrored];

As you showed, ListPlot3D "fills in" the region between the two data sets when drawing the corresponding surface:

myLP3D[joined]

Mathematica graphics

As you showed, attempting to add a RegionFunction that described the domain of the two data sets does not seem to help (note that I rewrote your conditions as $|x|\le|y|$, which is equivalent to your formulation but more compact):

myLP3D[joined, RegionFunction -> (Abs[#1] <= Abs[#2] &)]

region function seems to have no effect

However, region function is not quite ignored: it is simply not checked thoroughly enough with the standard number of plot points. If you increase the MaxPlotPoints setting, the situation improves dramatically:

myLP3D[joined, RegionFunction -> (Abs[#1] <= Abs[#2] &), MaxPlotPoints -> 50]

MaxPlotPoints fixes this behavior

$\endgroup$
3
  • $\begingroup$ It's very troubling to me that the default setting for MaxPlotPoints seems to be All, yet does not plot all points unless changed to Infinity. Any idea on what the All actually means in this context? $\endgroup$ – ninemileskid Feb 22 '16 at 19:19
  • $\begingroup$ @ninemileskid The default setting for MaxPlotPoints is actually Automatic, not All: the system will then try to estimate the minimum number of points to include for a fast yet accurate result. This may lead to dropping some points, mostly with no ill consequences on the results, but with a great gain in speed. However, in some corner cases that guess is spectacularly wrong, so some hand-holding is necessary (e.g. here, this question on ArrayPlot, or this one on ListContourPlot). $\endgroup$ – MarcoB Feb 22 '16 at 19:52
  • $\begingroup$ Right, so I've been fooled twice by MaxPlotPoints....my feeling is that a gain in performance, no matter how convenient, is worthless if the data is being plotted incorrectly. How can we know whether leaving out some points is destroying crucial information in a plot? Should everyone always run MaxPlotPoints->Infinity on every plot just to double-check? $\endgroup$ – ninemileskid Feb 22 '16 at 22:49

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.