6
$\begingroup$

Is there a way to reproduce the following behavior in BarChart?

enter image description here

I have seen this in ListPlot, but I am not sure how it can be modified for a bar chart:

Generating a broken or snipped axis in ListPlot

$\endgroup$

1 Answer 1

4
$\begingroup$

System`BarFunctionDump`ScaleBreakRectangle

For the looks we can use the undocumented function System`BarFunctionDump`ScaleBreakRectangle as the setting for the option ChartElementFunction:

SeedRandom[777]
BarChart[RandomInteger[1000, {4, 3}], ImageSize -> Large, 
 ChartStyle -> "Rainbow",  ChartLabels -> {Range[4], {"A", "B", "C"}},
 ChartElementFunction ->(System`BarFunctionDump`ScaleBreakRectangle[##, 
     Charting`ChartStyleInformation["ScaleBreaker"] = {300},
      "Frequency" -> 3, "Amplitude" -> 10, "BreakWidth" -> 10] &)]

enter image description here

Change {300} to, say, {150, 300, 600} to get multiple breaks:

enter image description here

We can also combine it with other built-in functions. For example, using

ChartElementFunction -> ({ChartElementData["GlassRectangle"][##], 
     EdgeForm[{AbsoluteThickness[2], White}], FaceForm[], 
     System`BarFunctionDump`ScaleBreakRectangle[##, 
      Charting`ChartStyleInformation["ScaleBreaker"] = {150, 300, 600},
      "Frequency" -> 3, "Amplitude" -> 10, "BreakWidth" -> 10]} &)

we get

enter image description here

NEXT: (1) Using different scales for the upper and lower portions of rectangles, (2) adjusting the vertical ticks accordingly, and (2) modifying the vertical axis to add a snip glyph.

ClearAll[scF, iscF, cEF, snip, inset]
scF[t_, sc_: 1/2] := If[# <= t, #, t + sc (# - t)] &;

iscF[t_, sc_: 1/2] := InverseFunction[scF[t, sc]];

cEF[t_, sc_: 1/2] := System`BarFunctionDump`ScaleBreakRectangle[
  {#[[1]], {#[[2, 1]], scF[t, sc]@#[[2, 2]]}}, #2, 
    Charting`ChartStyleInformation["ScaleBreaker"] = {t}, 
    "Frequency" -> 2, "Amplitude" -> 3., "BreakWidth" -> 2] &;

snip = Graphics[{Antialiasing -> True, EdgeForm[None], FaceForm[White], 
    Polygon[{{-1, -1/6}, {1, 5/6}, {1, 1/6}, {-1, -5/6}}], 
    Black, CapForm["Butt"], AbsoluteThickness[1], 
    Line[{{{-1, -5/6}, {1, 1/6}}, {{-1, -1/6}, {1, 5/6}}}]}];

inset[pos_: ImageScaled[{.2, .1}], size_: Scaled[{.04, .04}]] := 
 Inset[snip, pos, Automatic, size]

Examples:

SeedRandom[1]
data = RandomReal[{0, 300}, 10];

yticks = Join @@ (#[Quiet @ 
 Charting`ScaledTicks[{scF[100], iscF[100]}][##2, {10, 5}]] & @@@ 
  {{Most, 0, 100}, {Rest, 100, Max @ data}});

Row[{BarChart[data, ImageSize -> 500, ChartStyle -> "Rainbow", 
    ChartLabels -> Range[10], AxesOrigin -> {-1/5, 0}, 
    ImagePadding -> Scaled[.03]], 
  BarChart[data, ImageSize -> 500, ChartStyle -> "Rainbow",  
    ChartLabels -> Range[10], AxesOrigin -> {-1/5, 0},
    Ticks -> {Automatic, yticks}, ChartElementFunction -> cEF[100], 
    PlotRangeClipping -> False, ImagePadding -> Scaled[.03], 
    Epilog -> {inset[{-1/5, 100}], 
      Text[100, Offset[{-15, 0}, {-1/5, 100}]]}]}]

enter image description here

Use ChartElementFunction -> cEF[100, 1/4] and change yticks to

yticks = Join @@ (#[Quiet @ 
  Charting`ScaledTicks[{scF[100, 1/4], iscF[100, 1/4]}][##2, {10, 5}]] & @@@ 
    {{Most, 0, 100}, {Rest, 100, Max@data}});

to get

![enter image description here

$\endgroup$
2
  • $\begingroup$ This is a very interesting function. Wonder why it is undocumented. $\endgroup$ Commented May 9, 2020 at 19:03
  • $\begingroup$ Is is possible to define different types of 'breaks'? Something else than that seesaw curve? $\endgroup$ Commented May 9, 2020 at 19:05

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.