forked from p30928647/excelize
ref #65, new formula functions: SKEW.P and SLOPE, remove no-required format default
This commit is contained in:
parent
5a279321bb
commit
6fa950a4f8
74
calc.go
74
calc.go
|
@ -640,7 +640,9 @@ type formulaFuncs struct {
|
||||||
// SIN
|
// SIN
|
||||||
// SINH
|
// SINH
|
||||||
// SKEW
|
// SKEW
|
||||||
|
// SKEW.P
|
||||||
// SLN
|
// SLN
|
||||||
|
// SLOPE
|
||||||
// SMALL
|
// SMALL
|
||||||
// SQRT
|
// SQRT
|
||||||
// SQRTPI
|
// SQRTPI
|
||||||
|
@ -8860,14 +8862,20 @@ func (fn *formulaFuncs) min(mina bool, argsList *list.List) formulaArg {
|
||||||
return newNumberFormulaArg(min)
|
return newNumberFormulaArg(min)
|
||||||
}
|
}
|
||||||
|
|
||||||
// pearsonProduct is an implementation of the formula functions PEARSON and
|
// pearsonProduct is an implementation of the formula functions PEARSON, RSQ
|
||||||
// RSQ.
|
// and SLOPE.
|
||||||
func (fn *formulaFuncs) pearsonProduct(name string, argsList *list.List) formulaArg {
|
func (fn *formulaFuncs) pearsonProduct(name string, argsList *list.List) formulaArg {
|
||||||
if argsList.Len() != 2 {
|
if argsList.Len() != 2 {
|
||||||
return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires 2 arguments", name))
|
return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires 2 arguments", name))
|
||||||
}
|
}
|
||||||
array1 := argsList.Front().Value.(formulaArg).ToList()
|
var array1, array2 []formulaArg
|
||||||
array2 := argsList.Back().Value.(formulaArg).ToList()
|
if name == "SLOPE" {
|
||||||
|
array1 = argsList.Back().Value.(formulaArg).ToList()
|
||||||
|
array2 = argsList.Front().Value.(formulaArg).ToList()
|
||||||
|
} else {
|
||||||
|
array1 = argsList.Front().Value.(formulaArg).ToList()
|
||||||
|
array2 = argsList.Back().Value.(formulaArg).ToList()
|
||||||
|
}
|
||||||
if len(array1) != len(array2) {
|
if len(array1) != len(array2) {
|
||||||
return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
|
return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
|
||||||
}
|
}
|
||||||
|
@ -8898,7 +8906,10 @@ func (fn *formulaFuncs) pearsonProduct(name string, argsList *list.List) formula
|
||||||
if name == "RSQ" {
|
if name == "RSQ" {
|
||||||
return newNumberFormulaArg(math.Pow(sum/math.Sqrt(deltaX*deltaY), 2))
|
return newNumberFormulaArg(math.Pow(sum/math.Sqrt(deltaX*deltaY), 2))
|
||||||
}
|
}
|
||||||
return newNumberFormulaArg(sum / math.Sqrt(deltaX*deltaY))
|
if name == "PEARSON" {
|
||||||
|
return newNumberFormulaArg(sum / math.Sqrt(deltaX*deltaY))
|
||||||
|
}
|
||||||
|
return newNumberFormulaArg(sum / deltaX)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PEARSON function calculates the Pearson Product-Moment Correlation
|
// PEARSON function calculates the Pearson Product-Moment Correlation
|
||||||
|
@ -9268,16 +9279,19 @@ func (fn *formulaFuncs) RSQ(argsList *list.List) formulaArg {
|
||||||
return fn.pearsonProduct("RSQ", argsList)
|
return fn.pearsonProduct("RSQ", argsList)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SKEW function calculates the skewness of the distribution of a supplied set
|
// skew is an implementation of the formula functions SKEW and SKEW.P.
|
||||||
// of values. The syntax of the function is:
|
func (fn *formulaFuncs) skew(name string, argsList *list.List) formulaArg {
|
||||||
//
|
|
||||||
// SKEW(number1,[number2],...)
|
|
||||||
//
|
|
||||||
func (fn *formulaFuncs) SKEW(argsList *list.List) formulaArg {
|
|
||||||
if argsList.Len() < 1 {
|
if argsList.Len() < 1 {
|
||||||
return newErrorFormulaArg(formulaErrorVALUE, "SKEW requires at least 1 argument")
|
return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires at least 1 argument", name))
|
||||||
|
}
|
||||||
|
mean := fn.AVERAGE(argsList)
|
||||||
|
var stdDev formulaArg
|
||||||
|
var count, summer float64
|
||||||
|
if name == "SKEW" {
|
||||||
|
stdDev = fn.STDEV(argsList)
|
||||||
|
} else {
|
||||||
|
stdDev = fn.STDEVP(argsList)
|
||||||
}
|
}
|
||||||
mean, stdDev, count, summer := fn.AVERAGE(argsList), fn.STDEV(argsList), 0.0, 0.0
|
|
||||||
for arg := argsList.Front(); arg != nil; arg = arg.Next() {
|
for arg := argsList.Front(); arg != nil; arg = arg.Next() {
|
||||||
token := arg.Value.(formulaArg)
|
token := arg.Value.(formulaArg)
|
||||||
switch token.Type {
|
switch token.Type {
|
||||||
|
@ -9300,11 +9314,43 @@ func (fn *formulaFuncs) SKEW(argsList *list.List) formulaArg {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if count > 2 {
|
if count > 2 {
|
||||||
return newNumberFormulaArg(summer * (count / ((count - 1) * (count - 2))))
|
if name == "SKEW" {
|
||||||
|
return newNumberFormulaArg(summer * (count / ((count - 1) * (count - 2))))
|
||||||
|
}
|
||||||
|
return newNumberFormulaArg(summer / count)
|
||||||
}
|
}
|
||||||
return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
|
return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SKEW function calculates the skewness of the distribution of a supplied set
|
||||||
|
// of values. The syntax of the function is:
|
||||||
|
//
|
||||||
|
// SKEW(number1,[number2],...)
|
||||||
|
//
|
||||||
|
func (fn *formulaFuncs) SKEW(argsList *list.List) formulaArg {
|
||||||
|
return fn.skew("SKEW", argsList)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SKEWdotP function calculates the skewness of the distribution of a supplied
|
||||||
|
// set of values. The syntax of the function is:
|
||||||
|
//
|
||||||
|
// SKEW.P(number1,[number2],...)
|
||||||
|
//
|
||||||
|
func (fn *formulaFuncs) SKEWdotP(argsList *list.List) formulaArg {
|
||||||
|
return fn.skew("SKEW.P", argsList)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SLOPE returns the slope of the linear regression line through data points in
|
||||||
|
// known_y's and known_x's. The slope is the vertical distance divided by the
|
||||||
|
// horizontal distance between any two points on the line, which is the rate
|
||||||
|
// of change along the regression line. The syntax of the function is:
|
||||||
|
//
|
||||||
|
// SLOPE(known_y's,known_x's)
|
||||||
|
//
|
||||||
|
func (fn *formulaFuncs) SLOPE(argsList *list.List) formulaArg {
|
||||||
|
return fn.pearsonProduct("SLOPE", argsList)
|
||||||
|
}
|
||||||
|
|
||||||
// SMALL function returns the k'th smallest value from an array of numeric
|
// SMALL function returns the k'th smallest value from an array of numeric
|
||||||
// values. The syntax of the function is:
|
// values. The syntax of the function is:
|
||||||
//
|
//
|
||||||
|
|
97
calc_test.go
97
calc_test.go
|
@ -1157,6 +1157,12 @@ func TestCalcCellValue(t *testing.T) {
|
||||||
"=SKEW(1,2,3,4,3)": "-0.404796008910937",
|
"=SKEW(1,2,3,4,3)": "-0.404796008910937",
|
||||||
"=SKEW(A1:B2)": "0",
|
"=SKEW(A1:B2)": "0",
|
||||||
"=SKEW(A1:D3)": "0",
|
"=SKEW(A1:D3)": "0",
|
||||||
|
// SKEW.P
|
||||||
|
"=SKEW.P(1,2,3,4,3)": "-0.27154541788364",
|
||||||
|
"=SKEW.P(A1:B2)": "0",
|
||||||
|
"=SKEW.P(A1:D3)": "0",
|
||||||
|
// SLOPE
|
||||||
|
"=SLOPE(A1:A4,B1:B4)": "1",
|
||||||
// SMALL
|
// SMALL
|
||||||
"=SMALL(A1:A5,1)": "0",
|
"=SMALL(A1:A5,1)": "0",
|
||||||
"=SMALL(A1:B5,2)": "1",
|
"=SMALL(A1:B5,2)": "1",
|
||||||
|
@ -3063,6 +3069,14 @@ func TestCalcCellValue(t *testing.T) {
|
||||||
"=SKEW()": "SKEW requires at least 1 argument",
|
"=SKEW()": "SKEW requires at least 1 argument",
|
||||||
"=SKEW(\"\")": "strconv.ParseFloat: parsing \"\": invalid syntax",
|
"=SKEW(\"\")": "strconv.ParseFloat: parsing \"\": invalid syntax",
|
||||||
"=SKEW(0)": "#DIV/0!",
|
"=SKEW(0)": "#DIV/0!",
|
||||||
|
// SKEW.P
|
||||||
|
"=SKEW.P()": "SKEW.P requires at least 1 argument",
|
||||||
|
"=SKEW.P(\"\")": "strconv.ParseFloat: parsing \"\": invalid syntax",
|
||||||
|
"=SKEW.P(0)": "#DIV/0!",
|
||||||
|
// SLOPE
|
||||||
|
"=SLOPE()": "SLOPE requires 2 arguments",
|
||||||
|
"=SLOPE(A1:A2,B1:B1)": "#N/A",
|
||||||
|
"=SLOPE(A4,A4)": "#DIV/0!",
|
||||||
// SMALL
|
// SMALL
|
||||||
"=SMALL()": "SMALL requires 2 arguments",
|
"=SMALL()": "SMALL requires 2 arguments",
|
||||||
"=SMALL(A1:A5,0)": "k should be > 0",
|
"=SMALL(A1:A5,0)": "k should be > 0",
|
||||||
|
@ -4968,6 +4982,89 @@ func TestCalcMODE(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCalcPEARSON(t *testing.T) {
|
||||||
|
cellData := [][]interface{}{
|
||||||
|
{"x", "y"},
|
||||||
|
{1, 10.11},
|
||||||
|
{2, 22.9},
|
||||||
|
{2, 27.61},
|
||||||
|
{3, 27.61},
|
||||||
|
{4, 11.15},
|
||||||
|
{5, 31.08},
|
||||||
|
{6, 37.9},
|
||||||
|
{7, 33.49},
|
||||||
|
{8, 21.05},
|
||||||
|
{9, 27.01},
|
||||||
|
{10, 45.78},
|
||||||
|
{11, 31.32},
|
||||||
|
{12, 50.57},
|
||||||
|
{13, 45.48},
|
||||||
|
{14, 40.94},
|
||||||
|
{15, 53.76},
|
||||||
|
{16, 36.18},
|
||||||
|
{17, 49.77},
|
||||||
|
{18, 55.66},
|
||||||
|
{19, 63.83},
|
||||||
|
{20, 63.6},
|
||||||
|
}
|
||||||
|
f := prepareCalcData(cellData)
|
||||||
|
formulaList := map[string]string{
|
||||||
|
"=PEARSON(A2:A22,B2:B22)": "0.864129542184994",
|
||||||
|
}
|
||||||
|
for formula, expected := range formulaList {
|
||||||
|
assert.NoError(t, f.SetCellFormula("Sheet1", "C1", formula))
|
||||||
|
result, err := f.CalcCellValue("Sheet1", "C1")
|
||||||
|
assert.NoError(t, err, formula)
|
||||||
|
assert.Equal(t, expected, result, formula)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCalcRSQ(t *testing.T) {
|
||||||
|
cellData := [][]interface{}{
|
||||||
|
{"known_y's", "known_x's"},
|
||||||
|
{2, 22.9},
|
||||||
|
{7, 33.49},
|
||||||
|
{8, 34.5},
|
||||||
|
{3, 27.61},
|
||||||
|
{4, 19.5},
|
||||||
|
{1, 10.11},
|
||||||
|
{6, 37.9},
|
||||||
|
{5, 31.08},
|
||||||
|
}
|
||||||
|
f := prepareCalcData(cellData)
|
||||||
|
formulaList := map[string]string{
|
||||||
|
"=RSQ(A2:A9,B2:B9)": "0.711666290486784",
|
||||||
|
}
|
||||||
|
for formula, expected := range formulaList {
|
||||||
|
assert.NoError(t, f.SetCellFormula("Sheet1", "C1", formula))
|
||||||
|
result, err := f.CalcCellValue("Sheet1", "C1")
|
||||||
|
assert.NoError(t, err, formula)
|
||||||
|
assert.Equal(t, expected, result, formula)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCalcSLOP(t *testing.T) {
|
||||||
|
cellData := [][]interface{}{
|
||||||
|
{"known_x's", "known_y's"},
|
||||||
|
{1, 3},
|
||||||
|
{2, 7},
|
||||||
|
{3, 17},
|
||||||
|
{4, 20},
|
||||||
|
{5, 20},
|
||||||
|
{6, 27},
|
||||||
|
}
|
||||||
|
f := prepareCalcData(cellData)
|
||||||
|
formulaList := map[string]string{
|
||||||
|
"=SLOPE(A2:A7,B2:B7)": "0.200826446280992",
|
||||||
|
}
|
||||||
|
for formula, expected := range formulaList {
|
||||||
|
assert.NoError(t, f.SetCellFormula("Sheet1", "C1", formula))
|
||||||
|
result, err := f.CalcCellValue("Sheet1", "C1")
|
||||||
|
assert.NoError(t, err, formula)
|
||||||
|
assert.Equal(t, expected, result, formula)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestCalcSHEET(t *testing.T) {
|
func TestCalcSHEET(t *testing.T) {
|
||||||
f := NewFile()
|
f := NewFile()
|
||||||
f.NewSheet("Sheet2")
|
f.NewSheet("Sheet2")
|
||||||
|
|
7
chart.go
7
chart.go
|
@ -479,16 +479,11 @@ func parseFormatChartSet(formatSet string) (*formatChart, error) {
|
||||||
},
|
},
|
||||||
Format: formatPicture{
|
Format: formatPicture{
|
||||||
FPrintsWithSheet: true,
|
FPrintsWithSheet: true,
|
||||||
FLocksWithSheet: false,
|
|
||||||
NoChangeAspect: false,
|
|
||||||
OffsetX: 0,
|
|
||||||
OffsetY: 0,
|
|
||||||
XScale: 1.0,
|
XScale: 1.0,
|
||||||
YScale: 1.0,
|
YScale: 1.0,
|
||||||
},
|
},
|
||||||
Legend: formatChartLegend{
|
Legend: formatChartLegend{
|
||||||
Position: "bottom",
|
Position: "bottom",
|
||||||
ShowLegendKey: false,
|
|
||||||
},
|
},
|
||||||
Title: formatChartTitle{
|
Title: formatChartTitle{
|
||||||
Name: " ",
|
Name: " ",
|
||||||
|
|
|
@ -31,11 +31,6 @@ import (
|
||||||
func parseFormatPictureSet(formatSet string) (*formatPicture, error) {
|
func parseFormatPictureSet(formatSet string) (*formatPicture, error) {
|
||||||
format := formatPicture{
|
format := formatPicture{
|
||||||
FPrintsWithSheet: true,
|
FPrintsWithSheet: true,
|
||||||
FLocksWithSheet: false,
|
|
||||||
NoChangeAspect: false,
|
|
||||||
Autofit: false,
|
|
||||||
OffsetX: 0,
|
|
||||||
OffsetY: 0,
|
|
||||||
XScale: 1.0,
|
XScale: 1.0,
|
||||||
YScale: 1.0,
|
YScale: 1.0,
|
||||||
}
|
}
|
||||||
|
|
7
shape.go
7
shape.go
|
@ -25,15 +25,10 @@ func parseFormatShapeSet(formatSet string) (*formatShape, error) {
|
||||||
Height: 160,
|
Height: 160,
|
||||||
Format: formatPicture{
|
Format: formatPicture{
|
||||||
FPrintsWithSheet: true,
|
FPrintsWithSheet: true,
|
||||||
FLocksWithSheet: false,
|
|
||||||
NoChangeAspect: false,
|
|
||||||
OffsetX: 0,
|
|
||||||
OffsetY: 0,
|
|
||||||
XScale: 1.0,
|
XScale: 1.0,
|
||||||
YScale: 1.0,
|
YScale: 1.0,
|
||||||
},
|
},
|
||||||
Line: formatLine{Width: 1},
|
Line: formatLine{Width: 1},
|
||||||
Macro: "",
|
|
||||||
}
|
}
|
||||||
err := json.Unmarshal([]byte(formatSet), &format)
|
err := json.Unmarshal([]byte(formatSet), &format)
|
||||||
return &format, err
|
return &format, err
|
||||||
|
|
5
table.go
5
table.go
|
@ -23,10 +23,7 @@ import (
|
||||||
// parseFormatTableSet provides a function to parse the format settings of the
|
// parseFormatTableSet provides a function to parse the format settings of the
|
||||||
// table with default value.
|
// table with default value.
|
||||||
func parseFormatTableSet(formatSet string) (*formatTable, error) {
|
func parseFormatTableSet(formatSet string) (*formatTable, error) {
|
||||||
format := formatTable{
|
format := formatTable{ShowRowStripes: true}
|
||||||
TableStyle: "",
|
|
||||||
ShowRowStripes: true,
|
|
||||||
}
|
|
||||||
err := json.Unmarshal(parseFormatSet(formatSet), &format)
|
err := json.Unmarshal(parseFormatSet(formatSet), &format)
|
||||||
return &format, err
|
return &format, err
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue