* Resolve #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.
This commit is contained in:
parent
49257c5918
commit
42b1c81488
113
chart_test.go
113
chart_test.go
|
@ -253,3 +253,116 @@ func TestDeleteChart(t *testing.T) {
|
||||||
// Test delete chart on no chart worksheet.
|
// Test delete chart on no chart worksheet.
|
||||||
assert.NoError(t, NewFile().DeleteChart("Sheet1", "A1"))
|
assert.NoError(t, NewFile().DeleteChart("Sheet1", "A1"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestChartWithLogarithmicBase(t *testing.T) {
|
||||||
|
// Create test XLSX file with data
|
||||||
|
xlsx := NewFile()
|
||||||
|
sheet1 := xlsx.GetSheetName(0)
|
||||||
|
categories := map[string]float64{
|
||||||
|
"A1": 1,
|
||||||
|
"A2": 2,
|
||||||
|
"A3": 3,
|
||||||
|
"A4": 4,
|
||||||
|
"A5": 5,
|
||||||
|
"A6": 6,
|
||||||
|
"A7": 7,
|
||||||
|
"A8": 8,
|
||||||
|
"A9": 9,
|
||||||
|
"A10": 10,
|
||||||
|
"B1": 0.1,
|
||||||
|
"B2": 1,
|
||||||
|
"B3": 2,
|
||||||
|
"B4": 3,
|
||||||
|
"B5": 20,
|
||||||
|
"B6": 30,
|
||||||
|
"B7": 100,
|
||||||
|
"B8": 500,
|
||||||
|
"B9": 700,
|
||||||
|
"B10": 5000,
|
||||||
|
}
|
||||||
|
for cell, v := range categories {
|
||||||
|
assert.NoError(t, xlsx.SetCellValue(sheet1, cell, v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add two chart, one without and one with log scaling
|
||||||
|
assert.NoError(t, xlsx.AddChart(sheet1, "C1",
|
||||||
|
`{"type":"line","dimension":{"width":640, "height":480},`+
|
||||||
|
`"series":[{"name":"value","categories":"Sheet1!$A$1:$A$19","values":"Sheet1!$B$1:$B$10"}],`+
|
||||||
|
`"title":{"name":"Line chart without log scaling"}}`))
|
||||||
|
assert.NoError(t, xlsx.AddChart(sheet1, "M1",
|
||||||
|
`{"type":"line","dimension":{"width":640, "height":480},`+
|
||||||
|
`"series":[{"name":"value","categories":"Sheet1!$A$1:$A$19","values":"Sheet1!$B$1:$B$10"}],`+
|
||||||
|
`"y_axis":{"logbase":10.5},`+
|
||||||
|
`"title":{"name":"Line chart with log 10 scaling"}}`))
|
||||||
|
assert.NoError(t, xlsx.AddChart(sheet1, "A25",
|
||||||
|
`{"type":"line","dimension":{"width":320, "height":240},`+
|
||||||
|
`"series":[{"name":"value","categories":"Sheet1!$A$1:$A$19","values":"Sheet1!$B$1:$B$10"}],`+
|
||||||
|
`"y_axis":{"logbase":1.9},`+
|
||||||
|
`"title":{"name":"Line chart with log 1.9 scaling"}}`))
|
||||||
|
assert.NoError(t, xlsx.AddChart(sheet1, "F25",
|
||||||
|
`{"type":"line","dimension":{"width":320, "height":240},`+
|
||||||
|
`"series":[{"name":"value","categories":"Sheet1!$A$1:$A$19","values":"Sheet1!$B$1:$B$10"}],`+
|
||||||
|
`"y_axis":{"logbase":2},`+
|
||||||
|
`"title":{"name":"Line chart with log 2 scaling"}}`))
|
||||||
|
assert.NoError(t, xlsx.AddChart(sheet1, "K25",
|
||||||
|
`{"type":"line","dimension":{"width":320, "height":240},`+
|
||||||
|
`"series":[{"name":"value","categories":"Sheet1!$A$1:$A$19","values":"Sheet1!$B$1:$B$10"}],`+
|
||||||
|
`"y_axis":{"logbase":1000.1},`+
|
||||||
|
`"title":{"name":"Line chart with log 1000.1 scaling"}}`))
|
||||||
|
assert.NoError(t, xlsx.AddChart(sheet1, "P25",
|
||||||
|
`{"type":"line","dimension":{"width":320, "height":240},`+
|
||||||
|
`"series":[{"name":"value","categories":"Sheet1!$A$1:$A$19","values":"Sheet1!$B$1:$B$10"}],`+
|
||||||
|
`"y_axis":{"logbase":1000},`+
|
||||||
|
`"title":{"name":"Line chart with log 1000 scaling"}}`))
|
||||||
|
|
||||||
|
// Export XLSX file for human confirmation
|
||||||
|
assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestChartWithLogarithmicBase10.xlsx")))
|
||||||
|
|
||||||
|
// Write the XLSX file to a buffer
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
assert.NoError(t, xlsx.Write(&buffer))
|
||||||
|
|
||||||
|
// Read back the XLSX file from the buffer
|
||||||
|
newFile, err := OpenReader(&buffer)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// Check the number of charts
|
||||||
|
expectedChartsCount := 6
|
||||||
|
chartsNum := newFile.countCharts()
|
||||||
|
if !assert.Equal(t, expectedChartsCount, chartsNum,
|
||||||
|
"Expected %d charts, actual %d", expectedChartsCount, chartsNum) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
chartSpaces := make([]xlsxChartSpace, expectedChartsCount)
|
||||||
|
type xmlChartContent []byte
|
||||||
|
xmlCharts := make([]xmlChartContent, expectedChartsCount)
|
||||||
|
expectedChartsLogBase := []float64{0, 10.5, 0, 2, 0, 1000}
|
||||||
|
var ok bool
|
||||||
|
|
||||||
|
for i := 0; i < expectedChartsCount; i++ {
|
||||||
|
chartPath := fmt.Sprintf("xl/charts/chart%d.xml", i+1)
|
||||||
|
xmlCharts[i], ok = newFile.XLSX[chartPath]
|
||||||
|
assert.True(t, ok, "Can't open the %s", chartPath)
|
||||||
|
|
||||||
|
err = xml.Unmarshal([]byte(xmlCharts[i]), &chartSpaces[i])
|
||||||
|
if !assert.NoError(t, err) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
chartLogBasePtr := chartSpaces[i].Chart.PlotArea.ValAx[0].Scaling.LogBase
|
||||||
|
if expectedChartsLogBase[i] == 0 {
|
||||||
|
if !assert.Nil(t, chartLogBasePtr, "LogBase is not nil") {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if !assert.NotNil(t, chartLogBasePtr, "LogBase is nil") {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
if !assert.Equal(t, expectedChartsLogBase[i], *(chartLogBasePtr.Val),
|
||||||
|
"Expected log base to %f, actual %f", expectedChartsLogBase[i], *(chartLogBasePtr.Val)) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1000,10 +1000,17 @@ func (f *File) drawPlotAreaValAx(formatSet *formatChart) []*cAxs {
|
||||||
if formatSet.YAxis.Maximum == 0 {
|
if formatSet.YAxis.Maximum == 0 {
|
||||||
max = nil
|
max = nil
|
||||||
}
|
}
|
||||||
|
var logBase *attrValFloat
|
||||||
|
// Follow OOXML requirements on
|
||||||
|
// [https://github.com/sc34wg4/OOXMLSchemas/blob/2b074ca2c5df38b18ac118646b329b508b5bdecc/Part1/OfficeOpenXML-XMLSchema-Strict/dml-chart.xsd#L1142-L1147]
|
||||||
|
if formatSet.YAxis.LogBase >= 2 && formatSet.YAxis.LogBase <= 1000 {
|
||||||
|
logBase = &attrValFloat{Val: float64Ptr(formatSet.YAxis.LogBase)}
|
||||||
|
}
|
||||||
axs := []*cAxs{
|
axs := []*cAxs{
|
||||||
{
|
{
|
||||||
AxID: &attrValInt{Val: intPtr(753999904)},
|
AxID: &attrValInt{Val: intPtr(753999904)},
|
||||||
Scaling: &cScaling{
|
Scaling: &cScaling{
|
||||||
|
LogBase: logBase,
|
||||||
Orientation: &attrValString{Val: stringPtr(orientation[formatSet.YAxis.ReverseOrder])},
|
Orientation: &attrValString{Val: stringPtr(orientation[formatSet.YAxis.ReverseOrder])},
|
||||||
Max: max,
|
Max: max,
|
||||||
Min: min,
|
Min: min,
|
||||||
|
|
|
@ -380,6 +380,7 @@ type cChartLines struct {
|
||||||
// cScaling directly maps the scaling element. This element contains
|
// cScaling directly maps the scaling element. This element contains
|
||||||
// additional axis settings.
|
// additional axis settings.
|
||||||
type cScaling struct {
|
type cScaling struct {
|
||||||
|
LogBase *attrValFloat `xml:"logBase"`
|
||||||
Orientation *attrValString `xml:"orientation"`
|
Orientation *attrValString `xml:"orientation"`
|
||||||
Max *attrValFloat `xml:"max"`
|
Max *attrValFloat `xml:"max"`
|
||||||
Min *attrValFloat `xml:"min"`
|
Min *attrValFloat `xml:"min"`
|
||||||
|
@ -544,6 +545,7 @@ type formatChartAxis struct {
|
||||||
Italic bool `json:"italic"`
|
Italic bool `json:"italic"`
|
||||||
Underline bool `json:"underline"`
|
Underline bool `json:"underline"`
|
||||||
} `json:"num_font"`
|
} `json:"num_font"`
|
||||||
|
LogBase float64 `json:"logbase"`
|
||||||
NameLayout formatLayout `json:"name_layout"`
|
NameLayout formatLayout `json:"name_layout"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue