8

I would like to diagonally hatch the bars in BarChart and to have three different background colors for the different bars, like this:

enter image description here

Any ideas how to reproduce this image? The closest post I found is here.

Zlatko-Minev
  • 677
  • 4
  • 14

2 Answers2

15

With a bit of manual parameters:

barFilled[gap_, h_, seg_][{{xmin_, xmax_}, {ymin_, ymax_}}, ___] := 
 Module[{width, line, yt, yb, lend},
  {yb, yt} = Sort[{ymin, ymax}];
  width = xmax - xmin;
  line = Table[{{xmin, i}, {xmax, i + width}}, {i, yb, yt - width, h/seg}];
  lend = line[[-1, 1, 2]];
  line = {Line[line],
     Line[Table[{{xmin + i, yb}, {xmax, yb + width - i}}, {i, h/seg, width, h/seg}]], 
     Line[Table[{{xmin, lend + i}, {xmax - (lend + width - yt) - i,yt}}, {i, h/seg, width + h/seg, h/seg}]]};
   {{Opacity[.2], EdgeForm[], Rectangle[{xmin, -h}, {xmax + gap, h}]},
    {CapForm["Butt"], line}, {FaceForm[], Rectangle[{xmin, ymin}, {xmax, ymax}]}}]

BarChart[{2, -1, 1.5, -3, 3, 2.5}, BarSpacing -> 2, 
 ChartElementFunction -> barFilled[.65, 3, 35], ChartStyle -> 61, 
 GridLines -> {None, Automatic}]

enter image description here

Like AimForClarity mentioned, to avoid empty strip, we could replace 0 with some dummy value + meta and define barFilled for that value. For example:

barFilled[gap_, h_, seg_][{{xmin_, xmax_}, {ymin_, ymax_}}, _, {None}] :=
 {{Opacity[.2], EdgeForm[], Rectangle[{xmin, -h}, {xmax + gap, h}]}}

BarChart[{2, -1, 0, -2, 1, 2} /. {0 -> (1 -> None)}, BarSpacing -> 2,  ChartElementFunction -> barFilled[.65, 2, 35], 
ChartStyle -> 61, GridLines -> {None, Automatic}]

enter image description here

halmir
  • 15,082
  • 37
  • 53
  • Does the grid lines have to be on top of the charts and axes ticks labels? – mmal Oct 15 '13 at 08:45
  • @mmal grid lines are behind bars. It's a side effect of setting FaceForm[]. If you don't want that, you can insert one more rectangle before drawing lines. For example, .., {FaceForm[White], Rectangle[{xmin, ymin}, {xmax, ymax}]}, {CapForm["Butt"], line}, ... – halmir Oct 15 '13 at 12:14
  • 2
    @mmal To have grid lines on top of the charts and axes ticks labels one can use Method -> {"GridLinesInFront" -> True} option. – Alexey Popkov Oct 15 '13 at 21:12
  • Thanks, the halmir's method does exactly what I was thinking about. Using Frame->True clips the grid lines to frame region. – mmal Oct 16 '13 at 05:52
  • I hav not been able to get around this silly problem, that if one of the elements is 0 in the array, the barFilled function does not seem to be called and so there is an empty strip, any ideas how to fix this? – Zlatko-Minev Oct 19 '13 at 04:31
  • @AimForClarity when data is 0, ChartElementFunction seem not to send anything. What is your expectation when data is 0? – halmir Oct 19 '13 at 06:35
  • @halmir, I was expecting that the background would stay the same. – Zlatko-Minev Oct 21 '13 at 14:35
4

We can use ChartBaseStyle -> HatchFilling[] (HatchFilling is introduced in version 12.1) to get rectangles with hatched filling. Using the (undocumented) option "BarStartingValue" -> 0 the horizontal coordinates of bars become successive integers starting with 0 (independent of the BarSpacing option value). Then, it becomes an easy task to get the coordinates of the background rectangles using Scaled to construct epilog primitives:

epilog[col_] := MapIndexed[{Opacity[.2], #, 
     Rectangle[Scaled[{0, -1}, {#2[[1]] - 1, 0}], Scaled[{0, 1}, {#2[[1]], 0}]]} &, 
   col]

Examples:

data = {2, -1, 1.5, -3, 3, 2.5};
colors = ColorData[61] /@ Range[Length @ data];

BarChart[data, ChartBaseStyle -> HatchFilling[], BarSpacing -> 2, ChartStyle -> 61, Axes -> {False, True}, GridLines -> {None, Automatic}, PlotRange -> {{0, Length @ data}, All}, "BarStartingValue" -> 0, Epilog -> {Line[{{0, 0}, {Length @ data, 0}}], epilog[PadRight[colors, Length @ data,colors]]}]

enter image description here

Use BarSpacing -> 1 to get

enter image description here

With data = {2, -1, 0, -3, 3, 2.5}; we get

enter image description here

kglr
  • 394,356
  • 18
  • 477
  • 896