Skip to content

Commit

Permalink
pie_chart: Fix per-series radius configuration
Browse files Browse the repository at this point in the history
Prior to this change the last radius in the series was all that was used.
Not it's possible to set a specific series / pie slice to a different radius from the rest. However this does require setting the radius of all slices in the series.

This is considered a bug fix based off what the configuration currently allows. In the future we want to allow a chart radius and a series radius independently.
  • Loading branch information
jentfoo committed Feb 2, 2025
1 parent f508fbb commit 6ee4f78
Show file tree
Hide file tree
Showing 7 changed files with 46 additions and 27 deletions.
2 changes: 1 addition & 1 deletion axis.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ func (a *axisPainter) Render() (Box, error) {
}

formatter := opt.Formatter
if len(formatter) != 0 {
if formatter != "" {
for index, text := range opt.Data {
opt.Data[index] = strings.ReplaceAll(formatter, "{value}", text)
}
Expand Down
36 changes: 18 additions & 18 deletions chart_option.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ type ChartOption struct {
ValueFormatter ValueFormatter
}

// OptionFunc option function
// OptionFunc option function.
type OptionFunc func(opt *ChartOption)

// SVGOutputOptionFunc set svg type of chart's output.
Expand Down Expand Up @@ -92,21 +92,21 @@ func ThemeNameOptionFunc(theme string) OptionFunc {
}
}

// ThemeOptionFunc set them of chart
// ThemeOptionFunc set them of chart.
func ThemeOptionFunc(theme ColorPalette) OptionFunc {
return func(opt *ChartOption) {
opt.Theme = theme
}
}

// TitleOptionFunc set title of chart
// TitleOptionFunc set title of chart.
func TitleOptionFunc(title TitleOption) OptionFunc {
return func(opt *ChartOption) {
opt.Title = title
}
}

// TitleTextOptionFunc set title text of chart
// TitleTextOptionFunc set title text of chart.
func TitleTextOptionFunc(text string, subtext ...string) OptionFunc {
return func(opt *ChartOption) {
opt.Title.Text = text
Expand All @@ -116,14 +116,14 @@ func TitleTextOptionFunc(text string, subtext ...string) OptionFunc {
}
}

// LegendOptionFunc set legend of chart
// LegendOptionFunc set legend of chart.
func LegendOptionFunc(legend LegendOption) OptionFunc {
return func(opt *ChartOption) {
opt.Legend = legend
}
}

// LegendLabelsOptionFunc set legend labels of chart
// LegendLabelsOptionFunc set legend labels of chart.
func LegendLabelsOptionFunc(labels []string) OptionFunc {
return func(opt *ChartOption) {
opt.Legend = LegendOption{
Expand All @@ -132,14 +132,14 @@ func LegendLabelsOptionFunc(labels []string) OptionFunc {
}
}

// XAxisOptionFunc set x-axis of chart
// XAxisOptionFunc set x-axis of chart.
func XAxisOptionFunc(xAxisOption XAxisOption) OptionFunc {
return func(opt *ChartOption) {
opt.XAxis = xAxisOption
}
}

// XAxisDataOptionFunc set x-axis data of chart
// XAxisDataOptionFunc set x-axis data of chart.
func XAxisDataOptionFunc(data []string) OptionFunc {
return func(opt *ChartOption) {
opt.XAxis = XAxisOption{
Expand All @@ -155,7 +155,7 @@ func YAxisOptionFunc(yAxisOption ...YAxisOption) OptionFunc {
}
}

// YAxisDataOptionFunc set y-axis data of chart
// YAxisDataOptionFunc set y-axis data of chart.
func YAxisDataOptionFunc(data []string) OptionFunc {
return func(opt *ChartOption) {
opt.YAxis = []YAxisOption{
Expand All @@ -174,7 +174,7 @@ func DimensionsOptionFunc(width, height int) OptionFunc {
}
}

// PaddingOptionFunc set padding of chart
// PaddingOptionFunc set padding of chart.
func PaddingOptionFunc(padding Box) OptionFunc {
return func(opt *ChartOption) {
opt.Padding = padding
Expand Down Expand Up @@ -207,7 +207,7 @@ func RadarIndicatorOptionFunc(names []string, values []float64) OptionFunc {
}
}

// MarkLineOptionFunc set mark line for series of chart
// MarkLineOptionFunc set mark line for series of chart.
func MarkLineOptionFunc(seriesIndex int, markLineTypes ...string) OptionFunc {
return func(opt *ChartOption) {
if len(opt.SeriesList) <= seriesIndex {
Expand All @@ -217,7 +217,7 @@ func MarkLineOptionFunc(seriesIndex int, markLineTypes ...string) OptionFunc {
}
}

// MarkPointOptionFunc set mark point for series of chart
// MarkPointOptionFunc set mark point for series of chart.
func MarkPointOptionFunc(seriesIndex int, markPointTypes ...string) OptionFunc {
return func(opt *ChartOption) {
if len(opt.SeriesList) <= seriesIndex {
Expand Down Expand Up @@ -267,42 +267,42 @@ func fillThemeDefaults(defaultTheme ColorPalette, title *TitleOption, legend *Le
}
}

// LineRender line chart render
// LineRender line chart render.
func LineRender(values [][]float64, opts ...OptionFunc) (*Painter, error) {
return Render(ChartOption{
SeriesList: NewSeriesListLine(values),
}, opts...)
}

// BarRender bar chart render
// BarRender bar chart render.
func BarRender(values [][]float64, opts ...OptionFunc) (*Painter, error) {
return Render(ChartOption{
SeriesList: NewSeriesListBar(values),
}, opts...)
}

// HorizontalBarRender horizontal bar chart render
// HorizontalBarRender horizontal bar chart render.
func HorizontalBarRender(values [][]float64, opts ...OptionFunc) (*Painter, error) {
return Render(ChartOption{
SeriesList: NewSeriesListHorizontalBar(values),
}, opts...)
}

// PieRender pie chart render
// PieRender pie chart render.
func PieRender(values []float64, opts ...OptionFunc) (*Painter, error) {
return Render(ChartOption{
SeriesList: NewSeriesListPie(values),
}, opts...)
}

// RadarRender radar chart render
// RadarRender radar chart render.
func RadarRender(values [][]float64, opts ...OptionFunc) (*Painter, error) {
return Render(ChartOption{
SeriesList: NewSeriesListRadar(values),
}, opts...)
}

// FunnelRender funnel chart render
// FunnelRender funnel chart render.
func FunnelRender(values []float64, opts ...OptionFunc) (*Painter, error) {
return Render(ChartOption{
SeriesList: NewSeriesListFunnel(values),
Expand Down
10 changes: 7 additions & 3 deletions pie_chart.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,9 +150,9 @@ func (p *pieChart) render(result *defaultRenderResult, seriesList SeriesList) (B
opt := p.opt
values := make([]float64, len(seriesList))
total := float64(0)
radiusValue := ""
var radiusValue string
for index, series := range seriesList {
if len(series.Radius) != 0 {
if series.Radius != "" {
radiusValue = series.Radius
}
value := chartdraw.SumFloat64(series.Data...)
Expand Down Expand Up @@ -185,13 +185,17 @@ func (p *pieChart) render(result *defaultRenderResult, seriesList SeriesList) (B
var quadrant1, quadrant2, quadrant3, quadrant4 []sector
for index, v := range values {
series := seriesList[index]
seriesRadius := radius
if series.Radius != "" {
seriesRadius = getRadius(float64(diameter), series.Radius)
}
color := theme.GetSeriesColor(index)
if index == len(values)-1 {
if color == theme.GetSeriesColor(0) {
color = theme.GetSeriesColor(1)
}
}
s := newSector(cx, cy, radius, labelRadius, v, currentValue, total, labelLineWidth, seriesNames[index], series, color)
s := newSector(cx, cy, seriesRadius, labelRadius, v, currentValue, total, labelLineWidth, seriesNames[index], series, color)
switch quadrant := s.quadrant; quadrant {
case 1:
quadrant1 = append([]sector{s}, quadrant1...)
Expand Down
15 changes: 15 additions & 0 deletions pie_chart_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,21 @@ func TestPieChart(t *testing.T) {
},
result: "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" viewBox=\"0 0 600 400\"><path d=\"M 20 20\nL 580 20\nL 580 380\nL 20 380\nL 20 20\" style=\"stroke:none;fill:white\"/><path d=\"M 429 264\nL 459 264\" style=\"stroke-width:3;stroke:rgb(84,112,198);fill:none\"/><circle cx=\"444\" cy=\"264\" r=\"5\" style=\"stroke-width:3;stroke:rgb(84,112,198);fill:rgb(84,112,198)\"/><text x=\"461\" y=\"270\" style=\"stroke:none;fill:rgb(70,70,70);font-size:15.3px;font-family:'Roboto Medium',sans-serif\">Search Engine</text><path d=\"M 429 284\nL 459 284\" style=\"stroke-width:3;stroke:rgb(145,204,117);fill:none\"/><circle cx=\"444\" cy=\"284\" r=\"5\" style=\"stroke-width:3;stroke:rgb(145,204,117);fill:rgb(145,204,117)\"/><text x=\"461\" y=\"290\" style=\"stroke:none;fill:rgb(70,70,70);font-size:15.3px;font-family:'Roboto Medium',sans-serif\">Direct</text><path d=\"M 429 304\nL 459 304\" style=\"stroke-width:3;stroke:rgb(250,200,88);fill:none\"/><circle cx=\"444\" cy=\"304\" r=\"5\" style=\"stroke-width:3;stroke:rgb(250,200,88);fill:rgb(250,200,88)\"/><text x=\"461\" y=\"310\" style=\"stroke:none;fill:rgb(70,70,70);font-size:15.3px;font-family:'Roboto Medium',sans-serif\">Email</text><path d=\"M 429 324\nL 459 324\" style=\"stroke-width:3;stroke:rgb(238,102,102);fill:none\"/><circle cx=\"444\" cy=\"324\" r=\"5\" style=\"stroke-width:3;stroke:rgb(238,102,102);fill:rgb(238,102,102)\"/><text x=\"461\" y=\"330\" style=\"stroke:none;fill:rgb(70,70,70);font-size:15.3px;font-family:'Roboto Medium',sans-serif\">Union Ads</text><path d=\"M 429 344\nL 459 344\" style=\"stroke-width:3;stroke:rgb(115,192,222);fill:none\"/><circle cx=\"444\" cy=\"344\" r=\"5\" style=\"stroke-width:3;stroke:rgb(115,192,222);fill:rgb(115,192,222)\"/><text x=\"461\" y=\"350\" style=\"stroke:none;fill:rgb(70,70,70);font-size:15.3px;font-family:'Roboto Medium',sans-serif\">Video Ads</text><text x=\"222\" y=\"55\" style=\"stroke:none;fill:rgb(70,70,70);font-size:15.3px;font-family:'Roboto Medium',sans-serif\">Rainfall vs Evaporation</text><text x=\"266\" y=\"70\" style=\"stroke:none;fill:rgb(70,70,70);font-size:15.3px;font-family:'Roboto Medium',sans-serif\">Fake Data</text><path d=\"M 300 207\nL 300 109\nA 98 98 119.89 0 1 384 255\nL 300 207\nZ\" style=\"stroke-width:1;stroke:rgb(84,112,198);fill:rgb(84,112,198)\"/><path d=\"M 384 158\nL 397 151\nM 397 151\nL 412 151\" style=\"stroke-width:1;stroke:rgb(84,112,198);fill:none\"/><text x=\"415\" y=\"156\" style=\"stroke:none;fill:rgb(70,70,70);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">Search Engine: 33.3%</text><path d=\"M 300 207\nL 384 255\nA 98 98 84.08 0 1 261 296\nL 300 207\nZ\" style=\"stroke-width:1;stroke:rgb(145,204,117);fill:rgb(145,204,117)\"/><path d=\"M 330 300\nL 335 314\nM 335 314\nL 350 314\" style=\"stroke-width:1;stroke:rgb(145,204,117);fill:none\"/><text x=\"353\" y=\"319\" style=\"stroke:none;fill:rgb(70,70,70);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">Direct: 23.35%</text><path d=\"M 300 207\nL 261 296\nA 98 98 66.35 0 1 203 207\nL 300 207\nZ\" style=\"stroke-width:1;stroke:rgb(250,200,88);fill:rgb(250,200,88)\"/><path d=\"M 218 260\nL 206 268\nM 206 268\nL 191 268\" style=\"stroke-width:1;stroke:rgb(250,200,88);fill:none\"/><text x=\"107\" y=\"273\" style=\"stroke:none;fill:rgb(70,70,70);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">Email: 18.43%</text><path d=\"M 300 207\nL 203 207\nA 98 98 55.37 0 1 245 127\nL 300 207\nZ\" style=\"stroke-width:1;stroke:rgb(238,102,102);fill:rgb(238,102,102)\"/><path d=\"M 214 161\nL 201 154\nM 201 154\nL 186 154\" style=\"stroke-width:1;stroke:rgb(238,102,102);fill:none\"/><text x=\"75\" y=\"159\" style=\"stroke:none;fill:rgb(70,70,70);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">Union Ads: 15.37%</text><path d=\"M 300 207\nL 245 127\nA 98 98 34.32 0 1 300 109\nL 300 207\nZ\" style=\"stroke-width:1;stroke:rgb(115,192,222);fill:rgb(115,192,222)\"/><path d=\"M 272 114\nL 267 100\nM 267 100\nL 252 100\" style=\"stroke-width:1;stroke:rgb(115,192,222);fill:none\"/><text x=\"149\" y=\"105\" style=\"stroke:none;fill:rgb(70,70,70);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">Video Ads: 9.53%</text></svg>",
},
{
name: "variable_series_radius",
defaultTheme: true,
makeOptions: func() PieChartOption {
opt := makeBasicPieChartOption()
for i := range opt.SeriesList {
opt.SeriesList[i].Radius = strconv.Itoa((i+1)*10) + "%"
}
// disable extras
opt.Title.Show = False()
opt.Legend.Show = False()
return opt
},
result: "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" viewBox=\"0 0 600 400\"><path d=\"M 20 20\nL 580 20\nL 580 380\nL 20 380\nL 20 20\" style=\"stroke:none;fill:white\"/><path d=\"M 300 185\nL 300 156\nA 29 29 119.89 0 1 325 199\nL 300 185\nZ\" style=\"stroke-width:1;stroke:rgb(84,112,198);fill:rgb(84,112,198)\"/><path d=\"M 325 171\nL 438 105\nM 438 105\nL 453 105\" style=\"stroke-width:1;stroke:rgb(84,112,198);fill:none\"/><text x=\"456\" y=\"110\" style=\"stroke:none;fill:rgb(70,70,70);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">Search Engine: 33.3%</text><path d=\"M 300 185\nL 350 213\nA 58 58 84.08 0 1 277 237\nL 300 185\nZ\" style=\"stroke-width:1;stroke:rgb(145,204,117);fill:rgb(145,204,117)\"/><path d=\"M 317 240\nL 349 337\nM 349 337\nL 364 337\" style=\"stroke-width:1;stroke:rgb(145,204,117);fill:none\"/><text x=\"367\" y=\"342\" style=\"stroke:none;fill:rgb(70,70,70);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">Direct: 23.35%</text><path d=\"M 300 185\nL 265 264\nA 87 87 66.35 0 1 214 185\nL 300 185\nZ\" style=\"stroke-width:1;stroke:rgb(250,200,88);fill:rgb(250,200,88)\"/><path d=\"M 227 232\nL 166 271\nM 166 271\nL 151 271\" style=\"stroke-width:1;stroke:rgb(250,200,88);fill:none\"/><text x=\"67\" y=\"276\" style=\"stroke:none;fill:rgb(70,70,70);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">Email: 18.43%</text><path d=\"M 300 185\nL 185 185\nA 116 116 55.37 0 1 235 90\nL 300 185\nZ\" style=\"stroke-width:1;stroke:rgb(238,102,102);fill:rgb(238,102,102)\"/><path d=\"M 198 131\nL 159 110\nM 159 110\nL 144 110\" style=\"stroke-width:1;stroke:rgb(238,102,102);fill:none\"/><text x=\"33\" y=\"115\" style=\"stroke:none;fill:rgb(70,70,70);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">Union Ads: 15.37%</text><path d=\"M 300 185\nL 219 66\nA 145 145 34.32 0 1 300 40\nL 300 185\nZ\" style=\"stroke-width:1;stroke:rgb(115,192,222);fill:rgb(115,192,222)\"/><path d=\"M 258 47\nL 253 33\nM 253 33\nL 238 33\" style=\"stroke-width:1;stroke:rgb(115,192,222);fill:none\"/><text x=\"135\" y=\"38\" style=\"stroke:none;fill:rgb(70,70,70);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">Video Ads: 9.53%</text></svg>",
},
}

for i, tt := range tests {
Expand Down
4 changes: 2 additions & 2 deletions radar_chart.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,9 @@ func (r *radarChart) render(result *defaultRenderResult, seriesList SeriesList)
}
}

radiusValue := ""
var radiusValue string
for _, series := range seriesList {
if len(series.Radius) != 0 {
if series.Radius != "" {
radiusValue = series.Radius
}
}
Expand Down
4 changes: 2 additions & 2 deletions series.go
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ func NewSeriesListPie(values []float64, opts ...PieSeriesOption) SeriesList {
opt = opts[0]
}
for index, v := range values {
name := ""
var name string
if index < len(opt.Names) {
name = opt.Names[index]
}
Expand Down Expand Up @@ -293,7 +293,7 @@ func NewSeriesListFunnel(values []float64, opts ...FunnelSeriesOption) SeriesLis
}
seriesList := make(SeriesList, len(values))
for index, value := range values {
name := ""
var name string
if index < len(opt.Names) {
name = opt.Names[index]
}
Expand Down
2 changes: 1 addition & 1 deletion util.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ const defaultRadiusPercent = 0.4

func getRadius(diameter float64, radiusValue string) float64 {
var radius float64
if len(radiusValue) != 0 {
if radiusValue != "" {
v, _ := convertPercent(radiusValue)
if v != -1 {
radius = diameter * v
Expand Down

0 comments on commit 6ee4f78

Please sign in to comment.