2
$\begingroup$

I have a problem with error bars in a 3d graphics. I wrote the following code to represent a matrix (called in the code "dataX":

xticks = 
  Table[{i, 
    If[Mod[i, 1] == 0.5, IntegerPart[i + 0.5], ""], {0, 0.01}}, {i, 
    0.5, 7.5, 1}];
yticks = 
  Table[{i, 
    If[Mod[i, 1] == 0.5, IntegerPart[i + 0.5], ""], {0, 0.01}}, {i, 
    0.5, 7.5, 1}];
zticks = 
 Table[{N[i/100], If[Mod[i, 2] == 0, NumberForm[i/100, {3, 2}], " "], 
   If[Mod[i, 2] == 0, {0, 0.01}, {0, 0.007}]}, {i, -8, 2, 0.5}]
BarChart3D[dataX, ChartLayout -> "Grid", BarSpacing -> {0, 0}, 
   ColorFunction -> ColorData[{"TemperatureMap", {-0.088, 0.088}}], 
   ColorFunctionScaling -> False, Canvas -> False, 
   ChartBaseStyle -> EdgeForm[{Opacity[1, Black], Thickness[.001]}], 
   FaceGrids -> All][[1]] // 
 Graphics3D[#, Axes -> True, BoxRatios -> {1, 1, 1/GoldenRatio}, 
   FaceGrids -> {{{0, -1, 
       0}, {{0, 2, 4, 6, 8}, {0, -0.02, -0.04, -0.06, -0.08}}}, {{1, 
       0, 0}, {{0, 2, 4, 6, 8}, {0, -0.02, -0.04, -0.06, -0.08}}}}, 
   Boxed -> False, AxesEdge -> {{1, 1}, {-1, 1}, {-1, -1}}, 
   Ticks -> {xticks, yticks, zticks}, PlotRangePadding -> 0, 
   LabelStyle -> {FontSize -> 16, FontFamily -> "Sans-Serif", Black}, 
   ViewPoint -> {-19, 12, -8.5}, ViewVertical -> {0, 0, -1}] &

which gives me the following output:

enter image description here

Now I would like to add error bars. I found the following code may work, if I define the function:

stdErrorData = ConstantArray[0.01, {8, 8}]
chartData = 
 Table[dataX[[i, j]] -> stdErrorData[[i, j]], {i, 1, 8}, {j, 1, 8}]
errorBar3D[b : {{x0_, x1_}, {y0_, y1_}, {z0_, z1_}}, value_, meta_] :=
  Block[{error}, error = Flatten[meta];
  error = 
   If[error === {}, 0, 
    Last[error]]; {ChartElementDataFunction["Cube", "Profile" -> 2][
    b], {Black, Opacity[0.7], 
    Line[{{{(x0 + x1)/2, (y0 + y1)/2, 
        z1 - error}, {(x0 + x1)/2, (y0 + y1)/2, 
        z1 + error}}, {{1/4 (3 x0 + x1), (y0 + y1)/2, 
        z1 + error}, {1/4 (x0 + 3 x1), (y0 + y1)/2, 
        z1 + error}}, {{1/4 (3 x0 + x1), (y0 + y1)/2, 
        z1 - error}, {1/4 (x0 + 3 x1), (y0 + y1)/2, z1 - error}}}]}}]

and if I re-write Barchart3D as:

BarChart3D[chartData, ChartElementFunction -> errorBar3D, 
  ChartLayout -> "Grid", BarSpacing -> {0, 0}, 
  ColorFunction -> ColorData[{"TemperatureMap", {-0.088, 0.088}}], 
  ColorFunctionScaling -> False, Canvas -> False, 
  ChartBaseStyle -> EdgeForm[{Opacity[1, Black], Thickness[.001]}], 
  FaceGrids -> All][[1]]

(so basically replacing "dataX" with "chartData, ChartElementFunction -> errorBar3D".

This is what I get as an output:

enter image description here

Now, I have a problem with this: I don't get why the colors and the style of my bars change, as I left all the parts specifying the color unchanged in the scope of Barchart3D? The problem seems to come from Graphics3D, as if I only plot Barchart3D I get the good colors that I specified.

If you can give me some hints it would be much appreciated. I think I don't undestand very well how the error function works.

EDIT: After adding Neutral to Lightning in Graphics3D I got this result, which is pretty close to the original. I'm satisfied with the result, but it is different from the first one. I wonder why there is this discrepancy and how to recover the small glow and different lighting angle on the bars but I didn't find a solution yet.

enter image description here

$\endgroup$
2
  • 2
    $\begingroup$ add the option Lighting -> "Neutral" to Graphics3D[...]? $\endgroup$
    – kglr
    Jul 21, 2023 at 19:08
  • $\begingroup$ @kglr I did figure it out in the end but thanks a lot for answering! There is stil a small discrepancy between the results (see edit) that I'm trying to fix (if it's even possible) but I'm quite satisfied :) $\endgroup$
    – Luthien
    Jul 21, 2023 at 20:51

1 Answer 1

3
$\begingroup$
SeedRandom[1];

dataX = RandomReal[{-.03, .06}, {8, 8}] + 
   Reverse[ToeplitzMatrix[PadRight[{1, 1}, 8]]] RandomReal[{-.08, 0}, {8, 8}];

chartData = Map[Thread[# -> .01] &] @ dataX;

barchartoptions = {ImageSize -> 400,
   ChartLayout -> "Grid",
   BarSpacing -> {0, 0}, 
   ColorFunction -> ColorData[{"TemperatureMap", {-0.088, 0.088}}], 
   ColorFunctionScaling -> False,
   "Canvas" -> False, FaceGrids -> None, 
   ChartBaseStyle -> EdgeForm[{Opacity[1, Black], Thickness[.001]}],
   ViewPoint -> {-19, 12, -8.5},
   ViewVertical -> {0, 0, -1},
   Boxed -> False, 
   Axes -> False};

We first replicate the issue in OP:

BarChart3D[chartData, barchartoptions, 
 ChartElementFunction -> ToExpression[First@#], 
 PlotLabel -> Style[
    Column[{ChartElementFunction -> First[#], Last@#}, Center], 16]]& /@
    {{"Automatic", ""}, {"errorBar3D", "(\"Cube\")"}} // Row

enter image description here

The issue is caused by the ChartElementDataFunction["Cube",...] used in the definition of errorBar3D. If we replace it with ChartElementDataFunction["FadingCube"] we get the same styling of the bars as in the first chart. (Although I could not find any reference to it in the docs, "FadingCube" seems to be default ChartElementFunction for BarChart3D.)

So define a new function errorBar3Db:

DownValues[errorBar3Db] = DownValues[errorBar3D] /. 
  {errorBar3D -> errorBar3Db, 
  ChartElementDataFunction[__] -> ChartElementDataFunction["FadingCube"]};

Using errorBar3Db gives the same styling of bars as the original chart:

BarChart3D[chartData, barchartoptions, 
 ChartElementFunction -> ToExpression[First@#], 
 PlotLabel -> Style[
   Column[{ChartElementFunction -> First[#], Last@#}, Center], 16]]& /@
    {{"Automatic", ""}, {"errorBar3Db", "(\"FadingCube\")"}} // Row

enter image description here

Update:

A custom ChartElementFunction with customizable error-bars:

errorCube[cubeOpacity_ : Automatic, radius_ : .2, errorColor_ : Red] := 
  {ChartElementData["FadingCube"][##] /. 
   HoldPattern[VertexColors -> vc_] :> 
     Rule[VertexColors, Opacity[cubeOpacity /. Automatic -> .7, #] & /@ vc], 
   Blend[{{3/4, errorColor}, {1/4, Charting`ChartStyleInformation["Color"]}}], 
   FaceForm[Opacity[1]], EdgeForm[], 
   Table[ChartElementData["ErrorCube", "Shape" -> "Circle"][
     {{-radius, radius} + Mean@#, {-radius, radius} + Mean@#2, #3} & @@ #,
     {#2 + e}], {e, {1, -1} #3[[1]]}]} &;

Examples:

SeedRandom[1];
errors = RandomReal[{.005, .015}, {8, 8, 2}];

xDataWerrors = MapThread[Rule, {dataX, errors}, 2];

BarChart3D[xDataWerrors, barchartoptions, ChartElementFunction -> errorCube[]]

enter image description here

Replace errorCube[] with errorCube[Automatic, .1, Black] to get

enter image description here

Use errorCube[Automatic, .3, Charting`ChartStyleInformation["Color"]] to get

enter image description here

$\endgroup$
1
  • $\begingroup$ Wow, thank you so much for the solution and for all the examples! I spent a lot of time trying to fix the issue but I didn't find "fadingcube", I was growing really frustrated. Thank you! $\endgroup$
    – Luthien
    Jul 22, 2023 at 11:55

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.