# Color Histogram3D by Bin Location

I am using a Histogram3D plot to view the correlation of the R & G of an RGB image. Naturally, I want the bins to have a color corresponding to their $x$, $y$ (R,G) position on the chart.

Unfortunately, ColorFunction for Histogram3D only supplies one argument, height, not $x$ or $y$ position.

Is there a way to color each bin based on its $x$ and $y$ position within the histogram? (i.e. RGBColor[x,y,0])

Here is how I am generating my (uncolored) histogram:

    Histogram3D[Transpose[{
Flatten[ImageData[jpeg][[All,All,1]]]
,Flatten[ImageData[jpeg][[All,All,2]]]
}]]

-
Yes, exactly. I also want to make two other plots: R,B: RGBColor[x,0,y] and B,Y: RGBColor[0,x,y] –  Perfect Tommy Sep 16 '13 at 23:01
I'm not sure what that should show. For example RGBColor[1, 1, 0] is Yellow, but it doesn't mean it was Yellow in the image since you are not counting Blue. –  Kuba Sep 16 '13 at 23:04
Yes, I am aware. I would like to display the color value without the Blue Counted. –  Perfect Tommy Sep 16 '13 at 23:06
You may be interested in my edit. I've also made your code more compact. –  Kuba Sep 17 '13 at 6:13

Thanks to ybeltukov I realised that post-processing way is not so bulletproof. Let's write a little bit longer solution to take control.

ChartElementFunction, is a handy way to deal with this (only a little bit adapted example for documentation):

f[{{xmin_, xmax_}, {ymin_, ymax_}, {zmin_, zmax_}}, ___] := {
RGBColor[Mean[{xmin, xmax}], Mean[{ymin, ymax}], 0],
Cuboid[{xmin, ymin, zmin}, {xmax, ymax, zmax}]}


And it works for small images too:

jpeg = ImageResize[ExampleData[{"TestImage", "Mandrill"}], 5]

hist = Histogram3D[
Flatten[ImageData[jpeg][[;; , ;; , {1, 2}]], 1],
ChartElementFunction -> f]


(I have changed a little bit your code to make it more compact).

Edit All of the graphs you asked for. I had to modify f to make it more useful:

f[{x_, y_, z_}, ___, OptionsPattern[Irrelevant -> 1]] := {
RGBColor @@ Insert[{Mean@x, Mean@y}, 0, OptionValue[Irrelevant]],
Cuboid @@ Transpose[{x, y, z}]}

jpeg = ImageResize[ExampleData[{"TestImage", "Mandrill"}], 100]

Histogram3D[Flatten[ImageData[jpeg][[;; , ;; , #]], 1], PlotLabel -> #2,
ChartElementFunction -> (f[##, Irrelevant -> "x"] & /. "x" -> #3)
] & @@@ {{{1, 2}, "R - G", 3},
{{1, 3}, "R - B", 2},
{{2, 3}, "G - B", 1}} // GraphicsRow[#, ImageSize -> 1000] &


"Post-processing" way, works automatically only for larger images, for small, take a look @ybeltukov solution.

ChartElements are Cuboid s. r1 and r2 are coordinates of oposite vertices. Just reffer the color to them as you like. r2 = {x2, y2, z2} so you can involve height too.

To achieve what you've described in comments:

hist /. Cuboid[r1_, r2_] :> {RGBColor[##, 0] & @@ Most@(Mean /@ Transpose[{r1, r2}])
, Cuboid[r1, r2]}


-
@PerfectTommy does my edit fits your needs? –  Kuba Sep 16 '13 at 23:10
If you want this to work on small images add the option PerformanceGoal -> "Speed" to Histogram3D. –  Mr.Wizard Sep 17 '13 at 0:29
@Mr.Wizard Thank's for the remark. ChartElementFunction has this advantage that it still creates tooltips for small images :) –  Kuba Sep 17 '13 at 6:59
@Kuba I ended up using the "post-processing" method and it worked wonderfully. Thanks! –  Perfect Tommy Sep 20 '13 at 19:17
@PerfectTommy I'm glad it helps :) good luck! –  Kuba Sep 20 '13 at 19:19

Solution of Kuba works fine only for large images when bars on Histogram3D are not dynamic objects with tooltips. I provide more general solution

hist /. (h_ /; h === CuboidBox || h === Cuboid)[r1_, r2_] :>
With[{col = Append[Most[r1 + r2]/2, 0]}, {RGBColor[col], h[r1, r2]} /; True])


For small data set there is CuboidBox instead of Cuboid. Moreover CuboidBox is in held expression so I use Trott-Strzebonski in-place evaluation technique.

Examples

1. Small image

jpeg = Image[RandomReal[1, {8, 12, 3}]]
hist = Histogram3D[
Transpose[{Flatten[ImageData[jpeg][[All, All, 1]]],
Flatten[ImageData[jpeg][[All, All, 2]]]}]];
hist /. (h_ /; h === CuboidBox || h === Cuboid)[r1_, r2_] :>
With[{col = Append[Most[r1 + r2]/2, 0]}, {RGBColor[col],
h[r1, r2]} /; True]


2. Large image

jpeg = Import["ExampleData/lena.tif"]
hist = Histogram3D[
Transpose[{Flatten[ImageData[jpeg][[All, All, 1]]],
Flatten[ImageData[jpeg][[All, All, 2]]]}]];
hist /. (h_ /; h === CuboidBox || h === Cuboid)[r1_, r2_] :>
With[{col = Append[Most[r1 + r2]/2, 0]}, {RGBColor[col],
h[r1, r2]} /; True]


-
One can add the option PerformanceGoal -> "Speed" to Histogram3D to get the "large image" behavior on small data as well. –  Mr.Wizard Sep 17 '13 at 0:30
@Mr.Wizard Thanks! I searched this option to no avail. –  ybeltukov Sep 17 '13 at 0:32
Without help from others (this site) or an almost pathological inclination for experimentation I don't know how one is to learn of such things. I'm glad I could pass this information along. –  Mr.Wizard Sep 17 '13 at 0:50
@ybeltukov Good catch. I must admint I have not thought about this. Could you pleaste tell me why haven't you started to participate earlier in answering on this site? Looking on your answers I feel like we 'lost' a lot :) –  Kuba Sep 17 '13 at 5:08
p.s. Ok, I edited my post so it works with small images too :) –  Kuba Sep 17 '13 at 6:14