4
$\begingroup$

By default, when using the "Count" density specification, DensityHistogram does not plot empty bins. And thus the legend starts at 1.

So, is there a way to force DensityHistogram to draw bins containing no data and to ensure the zero value appears as part of the legend?

$\endgroup$
2
  • 2
    $\begingroup$ Have you tried the GridLines and the PlotRange options? $\endgroup$
    – LouisB
    Commented Dec 21, 2019 at 23:48
  • $\begingroup$ No, @Louis, I haven't. But I will ASAP ;) $\endgroup$ Commented Dec 22, 2019 at 0:32

1 Answer 1

5
$\begingroup$

Update: To make colors corresponding to a given value the same across legends with the same color function use a second argument that specifies the range of values:

ClearAll[legendF2]
legendF2[values_, range_, zerocolor_: White, cf_: "M10DefaultDensityGradient"] := 
 SwatchLegend[Prepend[ColorData[cf] /@ Rescale[Rest@values, range], zerocolor], 
  values, LegendMarkerSize -> Large, LegendLayout -> {"ReversedColumn", 1}]

Examples:

Row[{legendF2[{0, 2, 3, 5, 6, 7, 10}, {1, 10}], 
  legendF2[Range[0, 7], {1, 10}], 
  legendF2[{0, 3, 5, 6, 7}, {1, 10}, White, "Rainbow"], 
  legendF2[Range[0, 9], {1, 10}, Cyan, "Rainbow"]}, Spacer[10]]

enter image description here

Original answer:

We can use a custom SwatchLegend that adds the 0 counts with a specified color to the colors for non-zero counts:

ClearAll[legendF]
legendF[values_, zerocolor_: White, cf_: "M10DefaultDensityGradient"] := 
 SwatchLegend[Prepend[ColorData[cf] /@ Rescale[Rest @ values], zerocolor], values, 
  LegendMarkerSize -> Large, LegendLayout -> {"ReversedColumn", 1}]

Examples:

Row[{legendF[{0, 2, 3, 5, 6, 10}], legendF[Range[0, 7]], 
  legendF[{0, 2, 3, 5, 6, 10}, White, "Rainbow"], 
  legendF[Range[0, 7], Cyan, "Rainbow"]}, Spacer[10]]

enter image description here

To use this with DensityHistogram we need to pass to legendF the bin counts used by DensityHistogram. We can get the bin counts using HistogramList with the same bin specs:

ClearAll[heightF]
heightF[binspecs_: Automatic][dt_] :=  HistogramList[dt, binspecs, "Count"][[2]]

Examples:

SeedRandom[1]
data = RandomVariate[BinormalDistribution[.5], 100];

Row[{DensityHistogram[data, Automatic, "Count", ImageSize -> 300, 
   ChartLegends -> legendF[Union @@ heightF[][data]]], 
  DensityHistogram[data, Automatic, "Count", ImageSize -> 300, 
   ColorFunction -> "Rainbow", ChartLegends -> legendF[Union @@ heightF[][data], White, 
    "Rainbow"]]}, Spacer[10]]

enter image description here

Using a different bin specification:

Row[{DensityHistogram[data, {{-3, -1, 0, 1, 3}}, "Count", 
   ImageSize -> 300, 
   ChartLegends -> legendF[Union @@ heightF[{{-3, -1, 0, 1, 3}}][data]]], 
  DensityHistogram[data, {{-3, -1, 0, 1, 3}}, "Count", 
   ImageSize -> 300, ColorFunction -> "Rainbow", 
   ChartLegends -> legendF[Union @@ heightF[{{-3, -1, 0, 1, 3}}][data], White, 
     "Rainbow"]]}, Spacer[10]]

enter image description here

Showing empty bins:

DensityHistogram does not render bins with zero counts. To show the bins with zero-counts with specified colors and tooltips, we can shift the counts by 1 so that all bins have positive count and use a custom color function and a custom chart element function:

ClearAll[colorF, cEF]
colorF[max_, zerocolor_: White, cf_: "M10DefaultDensityGradient"] := 
  If[# == 1, zerocolor, ColorData[cf] @ Rescale[#, {2, 1 + max}]] &;

cEF[zerocolor_: White] := {If[#2 == {}, zerocolor], 
   Tooltip[ChartElementData["Rectangle"][##], Length@#2]} &

Examples:

Row[DensityHistogram[data, Automatic, heightF[][data] + 1 &, 
    ImageSize -> 300, 
    ChartLegends -> legendF[Union @@ heightF[][data], White, #], 
    ChartElementFunction -> cEF[], 
    ColorFunction -> colorF[Max@heightF[][data], White, #], 
    ColorFunctionScaling -> False] & /@ 
  {"M10DefaultDensityGradient", "Rainbow"}, Spacer[10]]

enter image description here

Row[DensityHistogram[data, Automatic, heightF[][data] + 1 &, 
    ImageSize -> 300, 
    ChartLegends -> legendF[Union @@ heightF[][data], Cyan, #], 
    ChartElementFunction -> cEF[Cyan], 
    ColorFunction -> colorF[Max@heightF[][data], Cyan, #], 
    ColorFunctionScaling -> False] & /@ 
{"M10DefaultDensityGradient", "Rainbow"}, Spacer[10]]

enter image description here

$\endgroup$
4
  • $\begingroup$ This is really clever, @kglr! I can't test that right now, but that sounds promising. $\endgroup$ Commented Dec 22, 2019 at 19:00
  • $\begingroup$ @SylvainLeroux, have you had chance to test this? $\endgroup$
    – kglr
    Commented Feb 23, 2020 at 15:03
  • $\begingroup$ I completely forgot :o $\endgroup$ Commented Feb 24, 2020 at 4:24
  • $\begingroup$ OK, @kglr, I checked that this morning. Your solution does work. I hope I will not forget the trick of using a custom hspec parameter. Thank you very much for the great answer!!! $\endgroup$ Commented Feb 24, 2020 at 11:41

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.