Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How is the BarSpacing option really implemented in Mathematica?

I'm trying to implement a DateListBarChart function that takes dated data and outputs a bar chart with the same placements as DateListPlot. It's essential that they plot data in the same horizontal position if given the same data, so they can be combined using Show. I am finding it difficult to get the settings for BarSpacing right so that the horizontal range of the plot doesn't change, and the bars stay in essentially the same place.

I have been unable to infer the correct scaling so that BarSpacing->{0.2,0.3} results in 20% of the x-axis length available for that group of bars is taken up with spacing between bars in that group, and 30% as spacing between groups of bars. For technical reasons I am doing this by passing things to RectangleChart. According to the documentation, BarSpacing is treated as absolute units in RectangleChart. Obviously the absolute sizes of the gaps need to be smaller if there are more series, and the bars need to be narrower.

Some examples:

arList = FoldList[0.9 #1 + #2 &, 0.01, RandomReal[NormalDistribution[0, 1], 24]]

{0.01, 0.334557, 2.02709, 1.1878, 1.9009, 3.08604, 2.36652, 3.04111, 
3.32364, 3.22662, 3.12626, 2.59118, 1.69334, 1.21069, 0.23171, 
0.689415, -0.852649, -0.124624, 0.58604, -0.481886, 0.221074, 
-0.300329, 2.36137, 0.427789, -1.47747}

dists = RandomChoice[{3, 4}, Length[arList]]
{4, 4, 4, 3, 4, 3, 4, 3, 4, 4, 3, 4, 4, 3, 4, 4, 4, 4, 3, 4, 3, 3, 3, 3, 3}

Results in:

RectangleChart[Transpose[{dists - 0 - 0/2, arList}], 
 PlotRange -> {{0, 100}, {-2, 4}}, ChartStyle -> EdgeForm[None], 
 Frame -> True, GridLines -> Automatic, BarSpacing -> {0, 0}]

enter image description here

RectangleChart[Transpose[{dists - 0.7 - 0.5/2, arList}], 
 PlotRange -> {{0, 100}, {-2, 4}}, ChartStyle -> EdgeForm[None], 
 Frame -> True, GridLines -> Automatic, BarSpacing -> {0.7, 0.5}]

enter image description here

Notice how the data aren't spanning the same distance along the x-axis as the previous example.

It gets even messier when trying to chart multiple series (the same in this example, for illustration).

RectangleChart[
 Transpose[{{dists - i/2 - j/2, arList}, {dists - i/2 - j/2, 
  arList}}, {2, 3, 1}], PlotRange -> {{0, 180}, {-2, 4}}, 
 ChartStyle -> EdgeForm[None], Frame -> True, Ticks -> None, 
  GridLines -> Automatic, BarSpacing -> {i, j}]

enter image description here

I've been futzing for ages trying to find the right formula so that BarSpacing settings for the custom function (not seen here) induce the correct spacings and bar widths so that the horizontal plot range doesn't change as the BarSpacing does.

What am I missing?

EDIT: In response to belisarius, this is an example of where I am heading. It works, kind of (the bars aren't quite in alignment with the line, but this is probably the dates I am using) but the cases with stacked bars fail to plot with the bars where they should be, as do any kind of bar graph on its own where there are multiple series. (I'm quite proud of the date label placement algorithm: the powers that be at work don't want to give up that look.)

enter image description here

And here is one that just isn't working. The data should fill the horizontal range. (The different width bars are deliberate - it's a combination of annual and quarterly data.)

enter image description here

EDIT 2

I remember why I didn't use Filling in a DateListPlot to draw the bars as in Mike Honeychurch's package - if you have anything other than very skinny bars, they end up having the top edge in the wrong place.

DateListPlot[{dateARList}, 
 PlotStyle -> {AbsolutePointSize[6], Yellow}, Filling -> {1 -> 0}, 
 FillingStyle -> {1 -> {{AbsoluteThickness[12], Darker[Red, 0.25]}}}, 
 PlotRange -> All]

enter image description here

like image 297
Verbeia Avatar asked Sep 03 '11 13:09

Verbeia


2 Answers

Maybe using the ChartElementFunction option instead of BarSpacing helps. For example barplot in the code would plot a bar chart such that each bar has margins of gapl on the left and gapr on the right where gapl and gapr are fractions of the total width of the bar

scale[{{xmin_, xmax_}, {ymin_, ymax_}}, {gapl_, gapr_}] :=
 {{xmin (1 - gapl) + xmax gapl, ymin}, {xmax (1 - gapr) + xmin gapr, ymax}}

barplot[dists_, arList_, {gapl_, gapr_}, opts___] := 
 RectangleChart[Transpose[{dists, arList }], opts, 
  Frame -> True, 
  GridLines -> Automatic, BarSpacing -> 0,
  ChartElementFunction -> (Rectangle @@ scale[#, {gapl, gapr}] &)]

Usage:

To plot the original bar chart with no gaps

barplot[dists, arList, {0, 0}]

rectangle chart with no gaps

This would plot a bar chart with a margin of 0.2 on both sides which results in a bar chart with gaps of 0.4 times the total width of the bars. Note that the positions of the bars matches with those in the first figure.

barplot[dists, arList, {0.2, 0.2}]

barchart with gaps

You can plot multiple series by doing something like

Show[barplot[dists, arList 0.9, {0, 0.5}],
 barplot[dists, arList 0.8, {0.5, 0}, ChartStyle -> LightGreen]] 

two series in one plot

like image 53
Heike Avatar answered Jan 01 '23 22:01

Heike


You may relieve your complaint about FillingStyle by using CapForm["Butt"].

list = {0.01, -0.81, 0.12, 0.81, 1.79, 1.1, 0.41, 1., 1.33, 1.08, 
  2.16, 1.13, 1.92, 1.64, 1.31, 1.94, 1.71, 0.91, 2.32, 0.95, 1.29, 
  1.28, 2.97, 4.45, 5.11}

DateListPlot[list, {2000, 8}, 
 PlotStyle -> {AbsolutePointSize[6], Yellow}, Filling -> {1 -> 0}, 
 FillingStyle -> {1 -> {{CapForm["Butt"], AbsoluteThickness[14], 
      Darker[Red, 0.25]}}}, PlotRange -> {0, 6}, ImageSize -> 400]

enter image description here

like image 26
Mr.Wizard Avatar answered Jan 01 '23 23:01

Mr.Wizard