Skip to content

Commit ce4afeb

Browse files
Merge pull request #506 from plotly/remove-eval
Remove eval statements, replace string cells with string arrays, rewrite struct2json and cell2json, add m2json test cases, fix convertDate
2 parents 7466f65 + ba57520 commit ce4afeb

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+196
-155
lines changed

plotly/plotly_aux/Test_m2json.m

Lines changed: 61 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,25 +15,29 @@ function test2dArrayInRange0to10(tc)
1515

1616
function testInRange1e6to1e5(tc)
1717
values = 1e-6 * (1 + (1:5) + 0.23456789);
18-
expected = "[2.235e-06,3.235e-06,4.235e-06,5.235e-06,6.235e-06]";
18+
expected = "[2.235e-06,3.235e-06,4.235e-06,5.235e-06," ...
19+
+ "6.235e-06]";
1920
tc.verifyEqual(string(m2json(values)), expected);
2021
end
2122

2223
function testInRange1e14Plus0to1(tc)
2324
values = 1e14 + (1:5) + 0.23456789;
24-
expected = "[100000000000001,100000000000002,100000000000003,100000000000004,100000000000005]";
25+
expected = "[100000000000001,100000000000002,"...
26+
+ "100000000000003,100000000000004,100000000000005]";
2527
tc.verifyEqual(string(m2json(values)), expected);
2628
end
2729

2830
function testInRange1e14Plus1e7Plus0to1(tc)
2931
values = 1e14 + 1e7 + (1:5) + 0.23456789;
30-
expected = "[100000010000001,100000010000002,100000010000003,100000010000004,100000010000005]";
32+
expected = "[100000010000001,100000010000002," ...
33+
+ "100000010000003,100000010000004,100000010000005]";
3134
tc.verifyEqual(string(m2json(values)), expected);
3235
end
3336

3437
function testLogScaledVariables(tc)
3538
values = 1e14 + 10.^(1:5) + 0.23456789;
36-
expected = "[1e+14,1.000000000001e+14,1.00000000001e+14,1.0000000001e+14,1.000000001e+14]";
39+
expected = "[1e+14,1.000000000001e+14,1.00000000001e+14," ...
40+
+ "1.0000000001e+14,1.000000001e+14]";
3741
tc.verifyEqual(string(m2json(values)), expected);
3842
end
3943

@@ -45,14 +49,65 @@ function testInRangeMinus10to0(tc)
4549

4650
function testInRangeMinus1e5toMinus1e6(tc)
4751
values = -1e-6 * (1 + (1:5) + 0.23456789);
48-
expected = "[-2.235e-06,-3.235e-06,-4.235e-06,-5.235e-06,-6.235e-06]";
52+
expected = "[-2.235e-06,-3.235e-06,-4.235e-06,-5.235e-06," ...
53+
+ "-6.235e-06]";
4954
tc.verifyEqual(string(m2json(values)), expected);
5055
end
5156

5257
function testInRangeMinus1e14Plus0to1(tc)
5358
values = -1e14 + (1:5) + 0.23456789;
54-
expected = "[-99999999999998.8,-99999999999997.8,-99999999999996.8,-99999999999995.8,-99999999999994.8]";
59+
expected = "[-99999999999998.8,-99999999999997.8," ...
60+
+ "-99999999999996.8,-99999999999995.8," ...
61+
+ "-99999999999994.8]";
5562
tc.verifyEqual(string(m2json(values)), expected);
5663
end
64+
65+
function testCell(tc)
66+
values = {1, "text", [1,2,3]};
67+
expected = "[1, ""text"", [1,2,3]]";
68+
tc.verifyEqual(string(m2json(values)), expected);
69+
end
70+
71+
function testStruct(tc)
72+
values = struct("a", 1, "b", "text");
73+
expected = "{""a"" : 1, ""b"" : ""text""}";
74+
tc.verifyEqual(string(m2json(values)), expected);
75+
end
76+
77+
function testDatetime(tc)
78+
value = datetime("2023-05-01 12:30:45");
79+
expected = """2023-05-01 12:30:45""";
80+
tc.verifyEqual(string(m2json(value)), expected);
81+
end
82+
83+
function testDate(tc)
84+
value = datetime("2023-05-01");
85+
expected = """2023-05-01""";
86+
tc.verifyEqual(string(m2json(value)), expected);
87+
end
88+
89+
function testLogicalTrue(tc)
90+
value = true;
91+
expected = "true";
92+
tc.verifyEqual(string(m2json(value)), expected);
93+
end
94+
95+
function testLogicalFalse(tc)
96+
value = false;
97+
expected = "false";
98+
tc.verifyEqual(string(m2json(value)), expected);
99+
end
100+
101+
function testCharArray(tc)
102+
value = 'Hello';
103+
expected = """Hello""";
104+
tc.verifyEqual(string(m2json(value)), expected);
105+
end
106+
107+
function testString(tc)
108+
value = "World";
109+
expected = """World""";
110+
tc.verifyEqual(string(m2json(value)), expected);
111+
end
57112
end
58113
end

plotly/plotly_aux/cell2json.m

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,4 @@
11
function str = cell2json(s)
2-
str = '';
3-
for i =1:length(s)
4-
val = s{i};
5-
valstr = m2json(val);
6-
str = [str ', ' valstr];
7-
end
8-
str = str(3:end); % snip leading comma
9-
str = ['[' str ']'];
10-
end
2+
strList = string(cellfun(@m2json, s, un=0));
3+
str = sprintf("[%s]", strjoin(strList, ", "));
4+
end

plotly/plotly_aux/m2json.m

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@
55
valstr = cell2json(val);
66
elseif isa(val, "numeric")
77
sz = size(val);
8-
numDigits = 3 + ceil(clip(log10(double(max(abs(val),[],"all"))) ...
9-
- log10(double(range(val,"all"))),0,12));
10-
numDigits(~isfinite(numDigits)) = 7;
8+
numDigits = max(arrayfun(@getPrecision, val));
9+
if isa(val,"single")
10+
numDigits = min(7, numDigits);
11+
else
12+
numDigits = min(15, numDigits);
13+
end
1114
fmt = sprintf("%%.%ig", numDigits);
1215
if sum(sz>1)>1 % 2D or higher array
1316
valsubstr = strings(1, sz(1));
@@ -21,7 +24,11 @@
2124
valstr = arrayfun(@(x) sprintf(fmt, x), val);
2225
valstr = strjoin(valstr, ",");
2326
end
24-
valstr = "[" + valstr + "]";
27+
if length(val)>1
28+
valstr = "[" + valstr + "]";
29+
elseif isempty(val)
30+
valstr = "[]";
31+
end
2532
valstr = strrep(valstr,"-Inf", "null");
2633
valstr = strrep(valstr, "Inf", "null");
2734
valstr = strrep(valstr, "NaN", "null");
@@ -55,7 +62,6 @@
5562
end
5663
end
5764

58-
function x = clip(x,lb,ub)
59-
x(x<lb) = lb;
60-
x(x>ub) = ub;
65+
function numDigits = getPrecision(val)
66+
numDigits = strlength(sprintf("%.15g", val));
6167
end

plotly/plotly_aux/struct2json.m

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,5 @@
11
function str = struct2json(s)
22
f = fieldnames(s);
3-
str = '';
4-
for i = 1:length(fieldnames(s))
5-
val = s.(f{i});
6-
valstr = m2json(val);
7-
str = [str '"' f{i} '"' ': ' valstr ', ' ];
8-
end
9-
str = str(1:(end-2)); % trim trailing comma
10-
str = ['{' str '}'];
3+
strList = cellfun(@(x) sprintf('"%s" : %s', x, m2json(s.(x))), f, un=0);
4+
str = sprintf("{%s}", strjoin(strList, ", "));
115
end

plotly/plotlyfig_aux/core/updateHeatmapAnnotation.m

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,8 @@
8383
if obj.State.Text(anIndex).Title
8484

8585
%-AXIS DATA-%
86-
eval(['xaxis = obj.layout.xaxis' num2str(xsource) ';']);
87-
eval(['yaxis = obj.layout.yaxis' num2str(ysource) ';']);
86+
xaxis = obj.layout.("xaxis" + xsource);
87+
yaxis = obj.layout.("yaxis" + ysource);
8888

8989
%-x position-%
9090
obj.layout.annotations{axIndex}.x = mean(xaxis.domain);

plotly/plotlyfig_aux/core/updateLegendMultipleAxes.m

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@
2626

2727
axIndex = obj.getAxisIndex(obj.State.Plot(traceIndex).AssociatedAxis);
2828
[xSource, ySource] = findSourceAxis(obj, axIndex);
29-
xAxis = eval(sprintf('obj.layout.xaxis%d', xSource));
30-
yAxis = eval(sprintf('obj.layout.yaxis%d', xSource));
29+
xAxis = obj.layout.("xaxis" + xSource);
30+
yAxis = obj.layout.("yaxis" + xSource);
3131

3232
allDomain(traceIndex, 1) = max(xAxis.domain);
3333
allDomain(traceIndex, 2) = max(yAxis.domain);

plotly/plotlyfig_aux/handlegraphics/updateAnimatedLine.m

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ function updateAnimatedLine(obj,plotIndex)
2020
[xsource, ysource] = findSourceAxis(obj,axIndex);
2121

2222
%-AXIS DATA-%
23-
eval(['xaxis = obj.layout.xaxis' num2str(xsource) ';']);
24-
eval(['yaxis = obj.layout.yaxis' num2str(ysource) ';']);
23+
xaxis = obj.layout.("xaxis" + xsource);
24+
yaxis = obj.layout.("yaxis" + ysource);
2525

2626
%-------------------------------------------------------------------------%
2727

plotly/plotlyfig_aux/handlegraphics/updateBar3.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
axis_data = ancestor(bar_data.Parent,'axes');
1515

1616
%-GET SCENE-%
17-
eval(['scene = obj.layout.scene' num2str(xsource) ';']);
17+
scene = obj.layout.("scene" + xsource);
1818

1919
%-------------------------------------------------------------------------%
2020

plotly/plotlyfig_aux/handlegraphics/updateBar3h.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
axis_data = ancestor(bar_data.Parent,'axes');
1515

1616
%-GET SCENE-%
17-
eval(['scene = obj.layout.scene' num2str(xsource) ';']);
17+
scene = obj.layout.("scene" + xsource);
1818

1919
%-------------------------------------------------------------------------%
2020

plotly/plotlyfig_aux/handlegraphics/updateBarseries.m

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,8 @@
6868
[xsource, ysource] = findSourceAxis(obj,axIndex);
6969

7070
%-AXIS DATA-%
71-
eval(['xaxis = obj.layout.xaxis' num2str(xsource) ';']);
72-
eval(['yaxis = obj.layout.yaxis' num2str(ysource) ';']);
71+
xaxis = obj.layout.("xaxis" + xsource);
72+
yaxis = obj.layout.("yaxis" + ysource);
7373

7474
%-------------------------------------------------------------------------%
7575

plotly/plotlyfig_aux/handlegraphics/updateBoxplot.m

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,8 @@
9595
[xsource, ysource] = findSourceAxis(obj,axIndex);
9696

9797
%-AXIS DATA-%
98-
eval(['xaxis = obj.layout.xaxis' num2str(xsource) ';']);
99-
eval(['yaxis = obj.layout.yaxis' num2str(ysource) ';']);
98+
xaxis = obj.layout.("xaxis" + xsource);
99+
yaxis = obj.layout.("yaxis" + ysource);
100100

101101
%---------------------------------------------------------------------%
102102

plotly/plotlyfig_aux/handlegraphics/updateCategoricalHistogram.m

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@
5858
[xsource, ysource] = findSourceAxis(obj,axIndex);
5959

6060
%-AXIS DATA-%
61-
eval(['xaxis = obj.layout.xaxis' num2str(xsource) ';']);
62-
eval(['yaxis = obj.layout.yaxis' num2str(ysource) ';']);
61+
xaxis = obj.layout.("xaxis" + xsource);
62+
yaxis = obj.layout.("yaxis" + ysource);
6363

6464
%-------------------------------------------------------------------------%
6565

@@ -90,9 +90,9 @@
9090
xmax = (hist_data.NumDisplayBins - 1) + gap;
9191

9292
t = 'category';
93-
eval(['obj.layout.xaxis' num2str(xsource) '.type = t;']);
94-
eval(['obj.layout.xaxis' num2str(xsource) '.autotick = false;']);
95-
eval(['obj.layout.xaxis' num2str(xsource) '.range = {xmin, xmax};']);
93+
obj.layout.("xaxis" + xsource).type = t;
94+
obj.layout.("xaxis" + xsource).autotick = false;
95+
obj.layout.("xaxis" + xsource).range = {xmin, xmax};
9696

9797
%-------------------------------------------------------------------------%
9898

plotly/plotlyfig_aux/handlegraphics/updateComet.m

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,8 @@ function updateComet(obj,plotIndex)
7575
[xsource, ysource] = findSourceAxis(obj,axIndex);
7676

7777
%-AXIS DATA-%
78-
eval(['xaxis = obj.layout.xaxis' num2str(xsource) ';']);
79-
eval(['yaxis = obj.layout.yaxis' num2str(ysource) ';']);
78+
xaxis = obj.layout.("xaxis" + xsource);
79+
yaxis = obj.layout.("yaxis" + ysource);
8080

8181
%-------------------------------------------------------------------------%
8282

plotly/plotlyfig_aux/handlegraphics/updateConeplot.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
[xsource, ysource] = findSourceAxis(obj,axIndex);
1111

1212
%-SCENE DATA-%
13-
eval(['scene = obj.layout.scene' num2str(xsource) ';']);
13+
scene = obj.layout.("scene" + xsource);
1414

1515
%-------------------------------------------------------------------------%
1616

plotly/plotlyfig_aux/handlegraphics/updateContour3.m

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717
[xsource, ysource] = findSourceAxis(obj,axIndex);
1818

1919
%-AXIS DATA-%
20-
eval(['xaxis = obj.layout.xaxis' num2str(xsource) ';']);
21-
eval(['yaxis = obj.layout.yaxis' num2str(ysource) ';']);
20+
xaxis = obj.layout.("xaxis" + xsource);
21+
yaxis = obj.layout.("yaxis" + ysource);
2222

2323
%-------------------------------------------------------------------------%
2424

plotly/plotlyfig_aux/handlegraphics/updateContourProjection.m

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
[xsource, ysource] = findSourceAxis(obj,axIndex);
1717

1818
%-AXIS DATA-%
19-
eval(['xaxis = obj.layout.xaxis' num2str(xsource) ';']);
20-
eval(['yaxis = obj.layout.yaxis' num2str(ysource) ';']);
19+
xaxis = obj.layout.("xaxis" + xsource);
20+
yaxis = obj.layout.("yaxis" + ysource);
2121

2222
%-------------------------------------------------------------------------%
2323

plotly/plotlyfig_aux/handlegraphics/updateFmesh.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
axisData = ancestor(meshData.Parent,'axes');
1515

1616
%-SCENE DATA-%
17-
eval( sprintf('scene = obj.layout.scene%d;', xsource) );
17+
scene = obj.layout.("scene" + xsource);
1818

1919
%-GET CONTOUR INDEX-%
2020
obj.PlotOptions.nPlots = obj.PlotOptions.nPlots + 1;

plotly/plotlyfig_aux/handlegraphics/updateFunctionContour.m

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
[xsource, ysource] = findSourceAxis(obj,axIndex);
1717

1818
%-AXIS DATA-%
19-
eval(['xaxis = obj.layout.xaxis' num2str(xsource) ';']);
20-
eval(['yaxis = obj.layout.yaxis' num2str(ysource) ';']);
19+
xaxis = obj.layout.("xaxis" + xsource);
20+
yaxis = obj.layout.("yaxis" + ysource);
2121

2222
%-------------------------------------------------------------------------%
2323

@@ -214,15 +214,15 @@
214214

215215
%-axis layout-%
216216
t = 'linear';
217-
eval(['obj.layout.xaxis' num2str(xsource) '.type=t;']);
218-
eval(['obj.layout.xaxis' num2str(xsource) '.autorange=true;']);
219-
eval(['obj.layout.xaxis' num2str(xsource) '.ticktext=axis_data.XTickLabel;']);
220-
eval(['obj.layout.xaxis' num2str(xsource) '.tickvals=axis_data.XTick;']);
221-
222-
eval(['obj.layout.yaxis' num2str(xsource) '.type=t;']);
223-
eval(['obj.layout.yaxis' num2str(xsource) '.autorange=true;']);
224-
eval(['obj.layout.yaxis' num2str(xsource) '.ticktext=axis_data.YTickLabel;']);
225-
eval(['obj.layout.yaxis' num2str(xsource) '.tickvals=axis_data.YTick;']);
217+
obj.layout.("xaxis" + xsource).type=t;
218+
obj.layout.("xaxis" + xsource).autorange=true;
219+
obj.layout.("xaxis" + xsource).ticktext=axis_data.XTickLabel;
220+
obj.layout.("xaxis" + xsource).tickvals=axis_data.XTick;
221+
222+
obj.layout.("yaxis" + xsource).type=t;
223+
obj.layout.("yaxis" + xsource).autorange=true;
224+
obj.layout.("yaxis" + xsource).ticktext=axis_data.YTickLabel;
225+
obj.layout.("yaxis" + xsource).tickvals=axis_data.YTick;
226226

227227
%-------------------------------------------------------------------------%
228228

plotly/plotlyfig_aux/handlegraphics/updateFunctionSurface.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
axisData = ancestor(meshData.Parent,'axes');
1515

1616
%-SCENE DATA-%
17-
eval( sprintf('scene = obj.layout.scene%d;', xsource) );
17+
scene = obj.layout.("scene" + xsource);
1818

1919
%-GET CONTOUR INDEX-%
2020
obj.PlotOptions.nPlots = obj.PlotOptions.nPlots + 1;

0 commit comments

Comments
 (0)