Skip to content

Commit

Permalink
Add new LabelCountAdjustment option as a way to influence the axis …
Browse files Browse the repository at this point in the history
…labels

For implementations which may render a range of graphs, specifying a specific label count can be difficult.  The library already has complex logic to determine how many labels should be rendered.

Specifying an adjustment allows configuration of "Simpler" more spaced out graphs, while still allowing the specific label count to be dynamic based off the data inputs.

This commit serves as a work around to issue #8 (but specifying -1 if you're hitting this bug).
  • Loading branch information
jentfoo committed Feb 15, 2024
1 parent 4f44b37 commit fdf474c
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 29 deletions.
7 changes: 7 additions & 0 deletions axis.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ type AxisOption struct {
Unit float64
// LabelCount is the number of labels to show on the axis. Specify a smaller number to reduce writing collisions. This value takes priority over Unit.
LabelCount int
// LabelCountAdjustment specifies a relative influence on how many labels should be rendered.
// Typically, this is negative to result in cleaner graphs, positive values may result in text collisions.
LabelCountAdjustment int
// LabelSkipCount specifies a number of lines between labels where there will be no label,
// but a horizontal line will still be drawn.
LabelSkipCount int
Expand Down Expand Up @@ -210,6 +213,10 @@ func (a *axisPainter) Render() (Box, error) {
if labelCount > dataCount {
labelCount = dataCount
}
labelCount += opt.LabelCountAdjustment
if labelCount < 2 {
labelCount = 2
}
tickSpaces := dataCount
if !centerLabels {
// there is always one more tick than data sample, and if we are centering labels we use that extra tick to
Expand Down
12 changes: 12 additions & 0 deletions axis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,18 @@ func TestAxis(t *testing.T) {
},
result: "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"600\" height=\"400\">\\n<path d=\"M 0 380\nL 0 375\" style=\"stroke-width:1;stroke:rgba(110,112,121,1.0);fill:none\"/><path d=\"M 85 380\nL 85 375\" style=\"stroke-width:1;stroke:rgba(110,112,121,1.0);fill:none\"/><path d=\"M 171 380\nL 171 375\" style=\"stroke-width:1;stroke:rgba(110,112,121,1.0);fill:none\"/><path d=\"M 257 380\nL 257 375\" style=\"stroke-width:1;stroke:rgba(110,112,121,1.0);fill:none\"/><path d=\"M 342 380\nL 342 375\" style=\"stroke-width:1;stroke:rgba(110,112,121,1.0);fill:none\"/><path d=\"M 428 380\nL 428 375\" style=\"stroke-width:1;stroke:rgba(110,112,121,1.0);fill:none\"/><path d=\"M 514 380\nL 514 375\" style=\"stroke-width:1;stroke:rgba(110,112,121,1.0);fill:none\"/><path d=\"M 600 380\nL 600 375\" style=\"stroke-width:1;stroke:rgba(110,112,121,1.0);fill:none\"/><path d=\"M 0 380\nL 600 380\" style=\"stroke-width:1;stroke:rgba(110,112,121,1.0);fill:none\"/><text x=\"20\" y=\"375\" style=\"stroke-width:0;stroke:none;fill:rgba(70,70,70,1.0);font-size:15.3px;font-family:'Roboto Medium',sans-serif\">Mon --</text><text x=\"108\" y=\"375\" style=\"stroke-width:0;stroke:none;fill:rgba(70,70,70,1.0);font-size:15.3px;font-family:'Roboto Medium',sans-serif\">Tue --</text><text x=\"192\" y=\"375\" style=\"stroke-width:0;stroke:none;fill:rgba(70,70,70,1.0);font-size:15.3px;font-family:'Roboto Medium',sans-serif\">Wed --</text><text x=\"279\" y=\"375\" style=\"stroke-width:0;stroke:none;fill:rgba(70,70,70,1.0);font-size:15.3px;font-family:'Roboto Medium',sans-serif\">Thu --</text><text x=\"369\" y=\"375\" style=\"stroke-width:0;stroke:none;fill:rgba(70,70,70,1.0);font-size:15.3px;font-family:'Roboto Medium',sans-serif\">Fri --</text><text x=\"453\" y=\"375\" style=\"stroke-width:0;stroke:none;fill:rgba(70,70,70,1.0);font-size:15.3px;font-family:'Roboto Medium',sans-serif\">Sat --</text><text x=\"537\" y=\"375\" style=\"stroke-width:0;stroke:none;fill:rgba(70,70,70,1.0);font-size:15.3px;font-family:'Roboto Medium',sans-serif\">Sun --</text></svg>",
},
// label count reduced
{
render: func(p *Painter) ([]byte, error) {
_, _ = NewAxisPainter(p, AxisOption{
Data: []string{"A", "B", "C", "D", "E", "F", "G"},
SplitLineShow: false,
LabelCountAdjustment: -1,
}).Render()
return p.Bytes()
},
result: "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"600\" height=\"400\">\\n<path d=\"M 0 375\nL 0 370\" style=\"stroke-width:1;stroke:rgba(110,112,121,1.0);fill:none\"/><path d=\"M 85 375\nL 85 370\" style=\"stroke-width:1;stroke:rgba(110,112,121,1.0);fill:none\"/><path d=\"M 171 375\nL 171 370\" style=\"stroke-width:1;stroke:rgba(110,112,121,1.0);fill:none\"/><path d=\"M 342 375\nL 342 370\" style=\"stroke-width:1;stroke:rgba(110,112,121,1.0);fill:none\"/><path d=\"M 428 375\nL 428 370\" style=\"stroke-width:1;stroke:rgba(110,112,121,1.0);fill:none\"/><path d=\"M 514 375\nL 514 370\" style=\"stroke-width:1;stroke:rgba(110,112,121,1.0);fill:none\"/><path d=\"M 600 375\nL 600 370\" style=\"stroke-width:1;stroke:rgba(110,112,121,1.0);fill:none\"/><path d=\"M 0 370\nL 600 370\" style=\"stroke-width:1;stroke:rgba(110,112,121,1.0);fill:none\"/><text x=\"-1\" y=\"395\" style=\"stroke-width:0;stroke:none;fill:rgba(70,70,70,1.0);font-size:15.3px;font-family:'Roboto Medium',sans-serif\">A</text><text x=\"123\" y=\"395\" style=\"stroke-width:0;stroke:none;fill:rgba(70,70,70,1.0);font-size:15.3px;font-family:'Roboto Medium',sans-serif\">B</text><text x=\"209\" y=\"395\" style=\"stroke-width:0;stroke:none;fill:rgba(70,70,70,1.0);font-size:15.3px;font-family:'Roboto Medium',sans-serif\">C</text><text x=\"381\" y=\"395\" style=\"stroke-width:0;stroke:none;fill:rgba(70,70,70,1.0);font-size:15.3px;font-family:'Roboto Medium',sans-serif\">E</text><text x=\"467\" y=\"395\" style=\"stroke-width:0;stroke:none;fill:rgba(70,70,70,1.0);font-size:15.3px;font-family:'Roboto Medium',sans-serif\">F</text><text x=\"589\" y=\"395\" style=\"stroke-width:0;stroke:none;fill:rgba(70,70,70,1.0);font-size:15.3px;font-family:'Roboto Medium',sans-serif\">G</text></svg>",
},
}

axisTheme := MakeTheme(ThemeOption{
Expand Down
2 changes: 2 additions & 0 deletions charts.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ func defaultRender(p *Painter, opt defaultRenderOption) (*defaultRenderResult, e
padLabelCount = defaultYAxisLabelCount(max-min, decimalData)
}
}
padLabelCount = chart.MaxInt(padLabelCount+yAxisOption.LabelCountAdjustment, 2)
// we call padRange directly because we need to do this padding before we can calculate the final labelCount for the axisRange
min, max = padRange(padLabelCount, min, max, minPadRange, maxPadRange)
if labelCount <= 0 {
Expand All @@ -222,6 +223,7 @@ func defaultRender(p *Painter, opt defaultRenderOption) (*defaultRenderResult, e
}
yAxisOption.LabelCount = labelCount
}
labelCount = chart.MaxInt(labelCount+yAxisOption.LabelCountAdjustment, 2)
r := axisRange{
p: p,
divideCount: labelCount,
Expand Down
34 changes: 19 additions & 15 deletions xaxis.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,11 @@ type XAxisOption struct {
// Unit is a suggestion for how large the axis step is, this is a recommendation only. Larger numbers result in fewer labels.
Unit float64
// LabelCount is the number of labels to show on the axis. Specify a smaller number to reduce writing collisions.
LabelCount int
isValueAxis bool
LabelCount int
// LabelCountAdjustment specifies a relative influence on how many labels should be rendered.
// Typically, this is negative to result in cleaner graphs, positive values may result in text collisions.
LabelCountAdjustment int
isValueAxis bool
}

const defaultXAxisHeight = 30
Expand All @@ -54,19 +57,20 @@ func (opt *XAxisOption) ToAxisOption() AxisOption {
position = PositionTop
}
axisOpt := AxisOption{
Theme: opt.Theme,
Data: opt.Data,
DataStartIndex: opt.DataStartIndex,
BoundaryGap: opt.BoundaryGap,
Position: position,
FontSize: opt.FontSize,
Font: opt.Font,
FontColor: opt.FontColor,
Show: opt.Show,
Unit: opt.Unit,
LabelCount: opt.LabelCount,
TextRotation: opt.TextRotation,
LabelOffset: opt.LabelOffset,
Theme: opt.Theme,
Data: opt.Data,
DataStartIndex: opt.DataStartIndex,
BoundaryGap: opt.BoundaryGap,
Position: position,
FontSize: opt.FontSize,
Font: opt.Font,
FontColor: opt.FontColor,
Show: opt.Show,
Unit: opt.Unit,
LabelCount: opt.LabelCount,
LabelCountAdjustment: opt.LabelCountAdjustment,
TextRotation: opt.TextRotation,
LabelOffset: opt.LabelOffset,
}
if opt.isValueAxis {
axisOpt.SplitLineShow = true
Expand Down
32 changes: 18 additions & 14 deletions yaxis.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ type YAxisOption struct {
Unit float64
// LabelCount is the number of labels to show on the axis. Specify a smaller number to reduce writing collisions.
LabelCount int
// LabelCountAdjustment specifies a relative influence on how many labels should be rendered.
// Typically, this is negative to result in cleaner graphs, positive values may result in text collisions.
LabelCountAdjustment int
// LabelSkipCount specifies a number of lines between labels where there will be no label and instead just a horizontal line.
LabelSkipCount int
isCategoryAxis bool
Expand Down Expand Up @@ -65,20 +68,21 @@ func (opt *YAxisOption) ToAxisOption(p *Painter) AxisOption {
theme = p.theme
}
axisOpt := AxisOption{
Formatter: opt.Formatter,
Theme: theme,
Data: opt.Data,
Position: position,
FontSize: opt.FontSize,
StrokeWidth: -1,
Font: opt.Font,
FontColor: opt.FontColor,
BoundaryGap: False(),
Unit: opt.Unit,
LabelCount: opt.LabelCount,
LabelSkipCount: opt.LabelSkipCount,
SplitLineShow: true,
Show: opt.Show,
Formatter: opt.Formatter,
Theme: theme,
Data: opt.Data,
Position: position,
FontSize: opt.FontSize,
StrokeWidth: -1,
Font: opt.Font,
FontColor: opt.FontColor,
BoundaryGap: False(),
Unit: opt.Unit,
LabelCount: opt.LabelCount,
LabelCountAdjustment: opt.LabelCountAdjustment,
LabelSkipCount: opt.LabelSkipCount,
SplitLineShow: true,
Show: opt.Show,
}
if !opt.AxisColor.IsZero() {
axisOpt.FontColor = opt.AxisColor
Expand Down

0 comments on commit fdf474c

Please sign in to comment.