Skip to content

Commit 42b1c81

Browse files
authored
Resolve qax-os#661 Add Logarithmic scale option support on Y axis (qax-os#662)
* Resolve qax-os#661 Add Logarithmic scale option support on Y axis Example usage: Add the following option into the format string when using AddChart: "y_axis":{"scaling":{"logbase":"10"}} * Change type of LogBase from attrValString to attrVarFloat * Add test case for testing Logarithmic Option in Y axis of charts * Move field `LogBase` in the format string up one level (remove `Scaling`) as suggested the owner Test cases are updated accordingly.
1 parent 49257c5 commit 42b1c81

File tree

3 files changed

+122
-0
lines changed

3 files changed

+122
-0
lines changed

chart_test.go

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,3 +253,116 @@ func TestDeleteChart(t *testing.T) {
253253
// Test delete chart on no chart worksheet.
254254
assert.NoError(t, NewFile().DeleteChart("Sheet1", "A1"))
255255
}
256+
257+
func TestChartWithLogarithmicBase(t *testing.T) {
258+
// Create test XLSX file with data
259+
xlsx := NewFile()
260+
sheet1 := xlsx.GetSheetName(0)
261+
categories := map[string]float64{
262+
"A1": 1,
263+
"A2": 2,
264+
"A3": 3,
265+
"A4": 4,
266+
"A5": 5,
267+
"A6": 6,
268+
"A7": 7,
269+
"A8": 8,
270+
"A9": 9,
271+
"A10": 10,
272+
"B1": 0.1,
273+
"B2": 1,
274+
"B3": 2,
275+
"B4": 3,
276+
"B5": 20,
277+
"B6": 30,
278+
"B7": 100,
279+
"B8": 500,
280+
"B9": 700,
281+
"B10": 5000,
282+
}
283+
for cell, v := range categories {
284+
assert.NoError(t, xlsx.SetCellValue(sheet1, cell, v))
285+
}
286+
287+
// Add two chart, one without and one with log scaling
288+
assert.NoError(t, xlsx.AddChart(sheet1, "C1",
289+
`{"type":"line","dimension":{"width":640, "height":480},`+
290+
`"series":[{"name":"value","categories":"Sheet1!$A$1:$A$19","values":"Sheet1!$B$1:$B$10"}],`+
291+
`"title":{"name":"Line chart without log scaling"}}`))
292+
assert.NoError(t, xlsx.AddChart(sheet1, "M1",
293+
`{"type":"line","dimension":{"width":640, "height":480},`+
294+
`"series":[{"name":"value","categories":"Sheet1!$A$1:$A$19","values":"Sheet1!$B$1:$B$10"}],`+
295+
`"y_axis":{"logbase":10.5},`+
296+
`"title":{"name":"Line chart with log 10 scaling"}}`))
297+
assert.NoError(t, xlsx.AddChart(sheet1, "A25",
298+
`{"type":"line","dimension":{"width":320, "height":240},`+
299+
`"series":[{"name":"value","categories":"Sheet1!$A$1:$A$19","values":"Sheet1!$B$1:$B$10"}],`+
300+
`"y_axis":{"logbase":1.9},`+
301+
`"title":{"name":"Line chart with log 1.9 scaling"}}`))
302+
assert.NoError(t, xlsx.AddChart(sheet1, "F25",
303+
`{"type":"line","dimension":{"width":320, "height":240},`+
304+
`"series":[{"name":"value","categories":"Sheet1!$A$1:$A$19","values":"Sheet1!$B$1:$B$10"}],`+
305+
`"y_axis":{"logbase":2},`+
306+
`"title":{"name":"Line chart with log 2 scaling"}}`))
307+
assert.NoError(t, xlsx.AddChart(sheet1, "K25",
308+
`{"type":"line","dimension":{"width":320, "height":240},`+
309+
`"series":[{"name":"value","categories":"Sheet1!$A$1:$A$19","values":"Sheet1!$B$1:$B$10"}],`+
310+
`"y_axis":{"logbase":1000.1},`+
311+
`"title":{"name":"Line chart with log 1000.1 scaling"}}`))
312+
assert.NoError(t, xlsx.AddChart(sheet1, "P25",
313+
`{"type":"line","dimension":{"width":320, "height":240},`+
314+
`"series":[{"name":"value","categories":"Sheet1!$A$1:$A$19","values":"Sheet1!$B$1:$B$10"}],`+
315+
`"y_axis":{"logbase":1000},`+
316+
`"title":{"name":"Line chart with log 1000 scaling"}}`))
317+
318+
// Export XLSX file for human confirmation
319+
assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestChartWithLogarithmicBase10.xlsx")))
320+
321+
// Write the XLSX file to a buffer
322+
var buffer bytes.Buffer
323+
assert.NoError(t, xlsx.Write(&buffer))
324+
325+
// Read back the XLSX file from the buffer
326+
newFile, err := OpenReader(&buffer)
327+
assert.NoError(t, err)
328+
329+
// Check the number of charts
330+
expectedChartsCount := 6
331+
chartsNum := newFile.countCharts()
332+
if !assert.Equal(t, expectedChartsCount, chartsNum,
333+
"Expected %d charts, actual %d", expectedChartsCount, chartsNum) {
334+
t.FailNow()
335+
}
336+
337+
chartSpaces := make([]xlsxChartSpace, expectedChartsCount)
338+
type xmlChartContent []byte
339+
xmlCharts := make([]xmlChartContent, expectedChartsCount)
340+
expectedChartsLogBase := []float64{0, 10.5, 0, 2, 0, 1000}
341+
var ok bool
342+
343+
for i := 0; i < expectedChartsCount; i++ {
344+
chartPath := fmt.Sprintf("xl/charts/chart%d.xml", i+1)
345+
xmlCharts[i], ok = newFile.XLSX[chartPath]
346+
assert.True(t, ok, "Can't open the %s", chartPath)
347+
348+
err = xml.Unmarshal([]byte(xmlCharts[i]), &chartSpaces[i])
349+
if !assert.NoError(t, err) {
350+
t.FailNow()
351+
}
352+
353+
chartLogBasePtr := chartSpaces[i].Chart.PlotArea.ValAx[0].Scaling.LogBase
354+
if expectedChartsLogBase[i] == 0 {
355+
if !assert.Nil(t, chartLogBasePtr, "LogBase is not nil") {
356+
t.FailNow()
357+
}
358+
} else {
359+
if !assert.NotNil(t, chartLogBasePtr, "LogBase is nil") {
360+
t.FailNow()
361+
}
362+
if !assert.Equal(t, expectedChartsLogBase[i], *(chartLogBasePtr.Val),
363+
"Expected log base to %f, actual %f", expectedChartsLogBase[i], *(chartLogBasePtr.Val)) {
364+
t.FailNow()
365+
}
366+
}
367+
}
368+
}

drawing.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1000,10 +1000,17 @@ func (f *File) drawPlotAreaValAx(formatSet *formatChart) []*cAxs {
10001000
if formatSet.YAxis.Maximum == 0 {
10011001
max = nil
10021002
}
1003+
var logBase *attrValFloat
1004+
// Follow OOXML requirements on
1005+
// [https://github.com/sc34wg4/OOXMLSchemas/blob/2b074ca2c5df38b18ac118646b329b508b5bdecc/Part1/OfficeOpenXML-XMLSchema-Strict/dml-chart.xsd#L1142-L1147]
1006+
if formatSet.YAxis.LogBase >= 2 && formatSet.YAxis.LogBase <= 1000 {
1007+
logBase = &attrValFloat{Val: float64Ptr(formatSet.YAxis.LogBase)}
1008+
}
10031009
axs := []*cAxs{
10041010
{
10051011
AxID: &attrValInt{Val: intPtr(753999904)},
10061012
Scaling: &cScaling{
1013+
LogBase: logBase,
10071014
Orientation: &attrValString{Val: stringPtr(orientation[formatSet.YAxis.ReverseOrder])},
10081015
Max: max,
10091016
Min: min,

xmlChart.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,7 @@ type cChartLines struct {
380380
// cScaling directly maps the scaling element. This element contains
381381
// additional axis settings.
382382
type cScaling struct {
383+
LogBase *attrValFloat `xml:"logBase"`
383384
Orientation *attrValString `xml:"orientation"`
384385
Max *attrValFloat `xml:"max"`
385386
Min *attrValFloat `xml:"min"`
@@ -544,6 +545,7 @@ type formatChartAxis struct {
544545
Italic bool `json:"italic"`
545546
Underline bool `json:"underline"`
546547
} `json:"num_font"`
548+
LogBase float64 `json:"logbase"`
547549
NameLayout formatLayout `json:"name_layout"`
548550
}
549551

0 commit comments

Comments
 (0)