We can use the built-in (but undocumented) chart element function "ArrowRectangle"
to create desired graphics primitives:
ClearAll[arrowBar]
arrowBar[arrowwidth_: .5, boxwidth_: 1, arrowangle_: 120][
colors_: ColorData[97, "ColorList"], dr_: 5] :=
{colors[[#]], Opacity[.7],
ChartElementData["ArrowRectangle", {"ArrowheadAngle" -> arrowangle,
"ArrowWidth" -> arrowwidth}][{{-boxwidth, boxwidth}/2 + #2, #3}],
Opacity[1], EdgeForm[Gray], Disk[{#2, #3[[1]]}, Offset[dr]]} &;
Examples:
Column[{
Graphics[arrowBar[][{RandomColor[]}][1, #,
RandomSample @ {2, -2}] & /@ {1, 3, 5}],
Graphics[arrowBar[1, .9 , 120][{RandomColor[]}, 7][1, #,
RandomSample @ {2, -2}] & /@ {1, 3, 5}],
Graphics[arrowBar[.1, .9, 90][{RandomColor[]}, 10][1, #,
RandomSample @ {2, -2}] & /@ {1, 3, 5}]}]
legend = Graphics[{arrowBar[][{Gray}][1, -1/4, {1, -1}/2] /.
EdgeForm[_] -> EdgeForm[White],
GrayLevel[.2],
Text[Style["actual", FontSize -> 11], Offset[{5, 0}, {1/8, 1/2}], Left],
Text[Style["projected", FontSize -> 11], Offset[{5, 5}, {1/8, -1/2}], Left]},
ImageSize -> 1 -> 40]
Using a modification of data in OP:
countries = CountryData["G7"];
data = {{2, 1, 1.5, 3, 3, 2.5, 4}, {-2, -1, -1.5, -3, -3, -2.5, -2}};
SeedRandom[1]
data2 = Transpose[{#, # + RandomInteger[{-5, 5}, Length @ data[[1]]]} & @ data[[1]]];
options = Join[{ImageSize -> Large, Axes -> {True, False},
AxesStyle -> Dashed, AspectRatio -> 1/2},
FilterRules[Charting`ResolvePlotTheme["Business", Plot], Options[Graphics]]];
Legended[Graphics[arrowBar[][] @@@ MapIndexed[{1, #2[[1]], #} &, data2],
FrameTicks -> {{Automatic, Automatic},
{Thread[{Range@Length@data2, Rotate[#, 90 Degree] & /@ countries}], Automatic}},
options],
legend]
Use arrowBar[][] @@@ MapIndexed[{#2[[1]], #2[[1]] , #} &, data2]
to get
To deal with grouped data, we need to pre-process input data into a form that can be used with arrowBar
:
ClearAll[preProcess]
preProcess[groupsizes_List, groupspacing_: 1] := Join[Join @@
MapIndexed[Thread @ {#2[[1]], (#2[[1]] - 1) groupspacing + # - 1} &,
TakeList[Range[Length@#], groupsizes]], List /@ #, 2] &;
Partition data2
into two groups with sizes 3 and 4:
dt = preProcess[{3, 4}] @ data2;
Legended[Graphics[arrowBar[][ColorData[97] /@ {1, 2}] @@@ dt,
FrameTicks -> {{Automatic, Automatic},
{Thread[{dt[[All, 2]], Rotate[#, 90 Degree] & /@ countries}], Automatic}},
options],
Column[{SwatchLegend[Opacity[.7, #] & /@ ColorData[97] /@ {1, 2}, {"group1",
"group2"}], legend}]]
Partition data2
into three groups with sizes 3,2 and 2:
dt = preProcess[{3, 2, 2}] @ data2;
colors = ColorData[97] /@ {1, 2, 3};
Legended[Graphics[arrowBar[][colors] @@@ dt,
FrameTicks -> {{Automatic, Automatic},
{Thread[{dt[[All, 2]], Rotate[#, 90 Degree] & /@ countries}], Automatic}},
options],
Column[{SwatchLegend[Opacity[.7, #] & /@ colors,
{"group1", "group2", "group3"}], legend}]]
Use arrowBar[1, .9 , 120][colors, 15] @@@ dt
to get
Use arrowBar[.1, 1/4 , 120][colors, 7] @@@ dt
to get