vdobler/chart

BarChart wrong formatted bars

Opened this issue · 1 comments

The following snippet will generate the attached wrong formatted bar chart. If more bars are used the formatting looks okay, so somehow the bar width and pos calculation for one or two datapoints is wrong.
chart_issue

func IssueChart() error {
    wuc := chart.BarChart{Title: "Weekly Data Usage"}
    wuc.XRange.Category = []string{"W1", "W2"}
    wuc.XRange.Label, wuc.YRange.Label = "Calendar Week", "Data Transfer (MB)"
    wuc.Key.Pos, wuc.Key.Cols, wuc.Key.Border = "otc", 2, -1
    wuc.YRange.ShowZero = true
    wuc.ShowVal = 0
    pos := []float64{0, 1}
    rx := []float64{100.0, 150.0}
    tx := []float64{50.0, 200.0}
    wuc.AddDataPair("RX (Download)", pos, rx,
        chart.Style{Symbol: 'o', LineColor: color.NRGBA{69, 117, 179, 0xff}, LineWidth: 2, FillColor: color.NRGBA{79, 127, 189, 0xff}})
    wuc.AddDataPair("TX (Upload)", pos, tx,
        chart.Style{Symbol: 'o', LineColor: color.NRGBA{182, 70, 67, 0xff}, LineWidth: 2, FillColor: color.NRGBA{192, 80, 77, 0xff}})
    // Save image
    igr := imgg.New(1024, 640, color.RGBA{0xff, 0xff, 0xff, 0xff}, nil, nil)
    wuc.Plot(igr)
    fh, err := os.Create("chart_issue.jpg")
    if err != nil {
        return err
    }
    err = jpeg.Encode(fh, igr.Image, nil)
    return err
}

This is unfortunate. It is the result of default autoscaling a categorical axis with bar charts. As a workaround you may fix the Min and Max of the x-axis manually like this:

wuc.XRange.Fixed(-0.5, 1.5, 1)

Of course you could fix it to the actual range covered by pos +- 0.5

Probably there is no sensible way to fix this automatically because:

  • dropping full or constrained autoscaling for bar charts or categorical bar charts is not an option
  • expanding the range to ExpandNextTics expands to much for categorical axes and bars at integer values
  • the bar width is not fixed, not even for categorical axes

Any automatic solution would have to be an ugly special case, probably with a heuristic when to trigger. Like: "For bar charts autoexpand range to cover full bar modulo Fixed and Constrained autoscaling and ignore Expansion in the RangeMode." This would work, I'll try it out but I'm afraid this new heuristic might break other existing code.