3
$\begingroup$

I'd like to make a 3d plot of a list of {x, y, z} points, where the height of the plot scales with the density (as in histogram) of the xy-values and the color scales with the z values.

I think the following is close but the colors don't appear to scale with the z values. I think i'm either not using ColorFunction properly, or I'm not scaling the ColorData values properly (or both, or maybe something completely different!).

I found a few related questions, but none quite the same as this one. An important difference is that I interpolate the data to get the colour function because the z-values in my actual data set are noisy.

Is there a simple fix?

data = RandomReal[1, {100, 3}];
f = Interpolation[data]/Max[data[[;; , 3]]];
SmoothHistogram3D[data[[;; , 1 ;; 2]], 
  ColorFunction -> Function[{x, y, z}, ColorData["FallColors"][f[x, y]]]]

Following on from the excellent solution by @m_goldberg , I tried adding a BarLegend, using a second function to get the colors to match the raw data rather than data normalized to 1. I first fixed the z range to two values: 0.1 or 0.2 (which for this example simply depends on whether the x value is > or < 0.5) to make it clear if the legend was working. The BarLegend numbers scale to the raw data values as intended, but the colors in BarLegend do not (I get just a very narrow colour band or maybe just one colour?):

SeedRandom[42];
data = RandomReal[1, {100, 3}];
lt05 = Flatten@Position[data[[;; , 1]], _?(# < 0.5 &)];
data[[;; , 3]] = 0.1;
data[[lt05, 3]] = 0.2;
Clear@f
f[x_, y_] = Quiet@Interpolation[data][x, y]/Max[data[[All, 3]]]; 
f2[x_, y_] = Quiet@Interpolation[data][x, y]; Quiet@
SmoothHistogram3D[data[[All, ;; 2]], 
ColorFunction -> 
Function[{x, y, z}, ColorData["SolarColors"][f[x, y]]], 
ColorFunctionScaling -> False, 
PlotLegends -> 
BarLegend[{Function[{x, y, z}, 
  ColorData["SolarColors"][f2[x, y]]], {Min[data[[;; , 3]]], 
  Max[data[[;; , 3]]]}}]]

How do I make the BarLegend numbers match the raw data range? Using f2 as the argument to ColorFunction, rather than f, results in one colour throughout the plot (with or without ColorFunctionScaling->True).

$\endgroup$
2
  • 1
    $\begingroup$ why not ColorFunction -> "FallColors"? $\endgroup$ Commented Dec 24, 2015 at 4:08
  • $\begingroup$ Thanks Mike, the colour should scale with the z values of the original 3d {x,y,z} data. The histogram is only using the {x,y} values, so histogram height represents the density of the x,y points ignoring the z values. I want the colour to vary with the interpolated z values rather than the height of the histogram. f is supposed to be a function giving colour "z" as a function of x and y, whilst the histogram height shows the density of the points in x and y. The z values aren't necessarily greatest where the x y points are densest. (I hope that is a bit clearer, sorry!) $\endgroup$
    – DrBubbles
    Commented Dec 24, 2015 at 6:13

1 Answer 1

5
$\begingroup$

Some reproducible data.

SeedRandom[42];
data = RandomReal[1, {100, 3}];

Your problem is with the way in which you define f. As you define it

f = Interpolation[data]/Max[data[[All, 3]]];

This f is not a function and does not act like one.

f @@ data[[1, ;; 2]]

bad-f

However, if f is redefined with

Clear @ f
f[x_, y_] = Interpolation[data][x, y]/Max[data[[All, 3]]];

it is a function and behaves well

f @@ data[[1, ;; 2]]

0.350213

Using this 2nd definition of f, the smooth 3D histogram looks like

Quiet @ 
  SmoothHistogram3D[data[[All , ;; 2]], 
    ColorFunction -> Function[{x, y, z}, ColorData["FallColors"][f[x, y]]]]

plot

$\endgroup$
1
  • $\begingroup$ Thanks @m_goldberg this works. I need to read up on the meaning of how [...] can follow [...] in the definition of f. $\endgroup$
    – DrBubbles
    Commented Dec 24, 2015 at 8:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.