Skip to content

Commit

Permalink
chore: replace mathjs with mexp (apache#1362)
Browse files Browse the repository at this point in the history
* chore: replace mathjs with mexp

* remove console.log and fix types
  • Loading branch information
villebro authored and zhaoyongjie committed Nov 24, 2021
1 parent 184804b commit 09193ec
Show file tree
Hide file tree
Showing 7 changed files with 118 additions and 102 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
"dompurify": "^2.0.6",
"fast-safe-stringify": "^2.0.6",
"lodash": "^4.17.11",
"mathjs": "^8.0.1",
"math-expression-evaluator": "^1.3.8",
"moment": "^2.20.1",
"nvd3-fork": "^2.0.5",
"prop-types": "^15.6.2",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@
*/
import { kebabCase, throttle } from 'lodash';
import d3 from 'd3';
import nv from 'nvd3-fork';
import { parse as mathjsParse } from 'mathjs';
import moment from 'moment';
import mexp from 'math-expression-evaluator';
import nv from 'nvd3-fork';
import PropTypes from 'prop-types';
import {
t,
Expand Down Expand Up @@ -919,9 +919,9 @@ function nvd3Vis(element, props) {
// The below code should be run AFTER rendering because chart is updated in call()
if (isTimeSeries && activeAnnotationLayers.length > 0) {
// Formula annotations
const formulas = activeAnnotationLayers
.filter(a => a.annotationType === ANNOTATION_TYPES.FORMULA)
.map(a => ({ ...a, formula: mathjsParse(a.value) }));
const formulas = activeAnnotationLayers.filter(
a => a.annotationType === ANNOTATION_TYPES.FORMULA,
);

let xMax;
let xMin;
Expand All @@ -946,6 +946,13 @@ function nvd3Vis(element, props) {
}

if (formulas.length > 0) {
const token = {
type: 3,
token: 'x',
show: 'x',
value: 'x',
};

const xValues = [];
if (vizType === 'bar') {
// For bar-charts we want one data point evaluated for every
Expand Down Expand Up @@ -973,13 +980,21 @@ function nvd3Vis(element, props) {
}
xValues.push(xMax);
}
const formulaData = formulas.map(fo => ({
key: fo.name,
values: xValues.map(x => ({ y: fo.formula.evaluate({ x }), x })),
color: fo.color,
strokeWidth: fo.width,
classed: `${fo.opacity} ${fo.style}`,
}));
const formulaData = formulas.map(fo => {
const { value: expression } = fo;
const subExpressions = String(expression).split('=');

return {
key: fo.name,
values: xValues.map(x => ({
x,
y: mexp.eval(subExpressions[1] ?? subExpressions[0], [token], { x }),
})),
color: fo.color,
strokeWidth: fo.width,
classed: `${fo.opacity} ${fo.style}`,
};
});
data.push(...formulaData);
}
const xAxis = chart.xAxis1 ? chart.xAxis1 : chart.xAxis;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@
"dependencies": {
"@superset-ui/chart-controls": "0.18.4",
"@superset-ui/core": "0.18.4",
"@types/mathjs": "^6.0.7",
"@types/math-expression-evaluator": "^1.2.1",
"d3-array": "^1.2.0",
"echarts": "^5.2.0",
"lodash": "^4.17.15",
"mathjs": "^8.0.1"
"math-expression-evaluator": "^1.3.8"
},
"peerDependencies": {
"react": "^16.13.1"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,6 @@ export function transformFormulaAnnotation(
smooth: true,
data: evalFormula(layer, data),
symbolSize: 0,
z: 0,
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,24 @@ import {
isTimeseriesAnnotationResult,
TimeseriesDataRecord,
} from '@superset-ui/core';
import { parse as mathjsParse } from 'mathjs';
import mexp from 'math-expression-evaluator';

export function evalFormula(
formula: AnnotationLayer,
data: TimeseriesDataRecord[],
): [Date, number][] {
const { value } = formula;
const node = mathjsParse(value as string);
const func = node.compile();
const token = {
type: 3,
token: 'x',
show: 'x',
value: 'x',
};
const { value: expression } = formula;
const subExpressions = String(expression).split('=');

return data.map(row => [
new Date(Number(row.__timestamp)),
func.evaluate({ x: row.__timestamp }) as number,
Number(mexp.eval(subExpressions[1] ?? subExpressions[0], [token], { x: row.__timestamp })),
]);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,18 @@
* specific language governing permissions and limitations
* under the License.
*/
import { AnnotationLayer, AnnotationResult } from '@superset-ui/core';
import {
AnnotationLayer,
AnnotationOpacity,
AnnotationResult,
AnnotationSourceType,
AnnotationStyle,
AnnotationType,
FormulaAnnotationLayer,
TimeseriesDataRecord,
} from '@superset-ui/core';
import {
evalFormula,
extractAnnotationLabels,
formatAnnotationLabel,
parseAnnotationOpacity,
Expand Down Expand Up @@ -53,10 +63,10 @@ describe('formatAnnotationLabel', () => {

describe('extractForecastSeriesContext', () => {
it('should extract the correct series name and type', () => {
expect(parseAnnotationOpacity('opacityLow')).toEqual(0.2);
expect(parseAnnotationOpacity('opacityMedium')).toEqual(0.5);
expect(parseAnnotationOpacity('opacityHigh')).toEqual(0.8);
expect(parseAnnotationOpacity('')).toEqual(1);
expect(parseAnnotationOpacity(AnnotationOpacity.Low)).toEqual(0.2);
expect(parseAnnotationOpacity(AnnotationOpacity.Medium)).toEqual(0.5);
expect(parseAnnotationOpacity(AnnotationOpacity.High)).toEqual(0.8);
expect(parseAnnotationOpacity(AnnotationOpacity.Undefined)).toEqual(1);
expect(parseAnnotationOpacity(undefined)).toEqual(1);
});
});
Expand All @@ -65,41 +75,41 @@ describe('extractAnnotationLabels', () => {
it('should extract all annotations that can be added to the legend', () => {
const layers: AnnotationLayer[] = [
{
annotationType: 'FORMULA',
annotationType: AnnotationType.Formula,
name: 'My Formula',
show: true,
style: 'solid',
style: AnnotationStyle.Solid,
value: 'sin(x)',
},
{
annotationType: 'FORMULA',
annotationType: AnnotationType.Formula,
name: 'My Hidden Formula',
show: false,
style: 'solid',
style: AnnotationStyle.Solid,
value: 'sin(2x)',
},
{
annotationType: 'INTERVAL',
annotationType: AnnotationType.Interval,
name: 'My Interval',
sourceType: 'table',
sourceType: AnnotationSourceType.Table,
show: true,
style: 'solid',
style: AnnotationStyle.Solid,
value: 1,
},
{
annotationType: 'TIME_SERIES',
annotationType: AnnotationType.Timeseries,
name: 'My Line',
show: true,
style: 'dashed',
sourceType: 'line',
style: AnnotationStyle.Dashed,
sourceType: AnnotationSourceType.Line,
value: 1,
},
{
annotationType: 'TIME_SERIES',
annotationType: AnnotationType.Timeseries,
name: 'My Hidden Line',
show: false,
style: 'dashed',
sourceType: 'line',
style: AnnotationStyle.Dashed,
sourceType: AnnotationSourceType.Line,
value: 1,
},
];
Expand All @@ -117,3 +127,30 @@ describe('extractAnnotationLabels', () => {
expect(extractAnnotationLabels(layers, results)).toEqual(['My Formula', 'Line 1', 'Line 2']);
});
});

describe('evalFormula', () => {
const layer: FormulaAnnotationLayer = {
annotationType: AnnotationType.Formula,
name: 'My Formula',
show: true,
style: AnnotationStyle.Solid,
value: 'x+1',
};
it('Should evaluate a regular formula', () => {
const data: TimeseriesDataRecord[] = [{ __timestamp: 0 }, { __timestamp: 10 }];

expect(evalFormula(layer, data)).toEqual([
[new Date(0), 1],
[new Date(10), 11],
]);
});

it('Should evaluate a formula containing redundant characters', () => {
const data: TimeseriesDataRecord[] = [{ __timestamp: 0 }, { __timestamp: 10 }];

expect(evalFormula({ ...layer, value: 'y = x* 2 -1' }, data)).toEqual([
[new Date(0), -1],
[new Date(10), 19],
]);
});
});

0 comments on commit 09193ec

Please sign in to comment.