From 53b213603b7c3e49898b1cec68594256e5931267 Mon Sep 17 00:00:00 2001 From: robertoffmoura Date: Sun, 4 Aug 2024 17:51:18 +0100 Subject: [PATCH] Improve calculation of number of significant digits needed when converting floats to JSON --- plotly/plotly_aux/Test_m2json.m | 58 +++++++++++++++++++++++++++++++++ plotly/plotly_aux/m2json.m | 37 ++++++++++----------- 2 files changed, 76 insertions(+), 19 deletions(-) create mode 100644 plotly/plotly_aux/Test_m2json.m diff --git a/plotly/plotly_aux/Test_m2json.m b/plotly/plotly_aux/Test_m2json.m new file mode 100644 index 00000000..8cb2d0d2 --- /dev/null +++ b/plotly/plotly_aux/Test_m2json.m @@ -0,0 +1,58 @@ +classdef Test_m2json < matlab.unittest.TestCase + methods (Test) + function testInRange0to10(tc) + values = 1 + (1:5) + 0.23456789; + expected = "[2.235,3.235,4.235,5.235,6.235]"; + tc.verifyEqual(string(m2json(values)), expected); + end + + function test2dArrayInRange0to10(tc) + values = 1 + (1:5) + (0:1)' + 0.23456789; + expected = "[[2.235,3.235,4.235,5.235,6.235]," ... + + "[3.235,4.235,5.235,6.235,7.235]]"; + tc.verifyEqual(string(m2json(values)), expected); + end + + function testInRange1e6to1e5(tc) + values = 1e-6 * (1 + (1:5) + 0.23456789); + expected = "[2.235e-06,3.235e-06,4.235e-06,5.235e-06,6.235e-06]"; + tc.verifyEqual(string(m2json(values)), expected); + end + + function testInRange1e14Plus0to1(tc) + values = 1e14 + (1:5) + 0.23456789; + expected = "[100000000000001,100000000000002,100000000000003,100000000000004,100000000000005]"; + tc.verifyEqual(string(m2json(values)), expected); + end + + function testInRange1e14Plus1e7Plus0to1(tc) + values = 1e14 + 1e7 + (1:5) + 0.23456789; + expected = "[100000010000001,100000010000002,100000010000003,100000010000004,100000010000005]"; + tc.verifyEqual(string(m2json(values)), expected); + end + + function testLogScaledVariables(tc) + values = 1e14 + 10.^(1:5) + 0.23456789; + expected = "[1e+14,1.000000000001e+14,1.00000000001e+14,1.0000000001e+14,1.000000001e+14]"; + tc.verifyEqual(string(m2json(values)), expected); + end + + function testInRangeMinus10to0(tc) + values = -(1 + (1:5) + 0.23456789); + expected = "[-2.235,-3.235,-4.235,-5.235,-6.235]"; + tc.verifyEqual(string(m2json(values)), expected); + end + + function testInRangeMinus1e5toMinus1e6(tc) + values = -1e-6 * (1 + (1:5) + 0.23456789); + expected = "[-2.235e-06,-3.235e-06,-4.235e-06,-5.235e-06,-6.235e-06]"; + tc.verifyEqual(string(m2json(values)), expected); + end + + function testInRangeMinus1e14Plus0to1(tc) + values = -1e14 + (1:5) + 0.23456789; + expected = "[-99999999999998.8,-99999999999997.8,-99999999999996.8,-99999999999995.8,-99999999999994.8]"; + tc.verifyEqual(string(m2json(values)), expected); + end + end +end diff --git a/plotly/plotly_aux/m2json.m b/plotly/plotly_aux/m2json.m index d17eb2e1..f9f9b309 100644 --- a/plotly/plotly_aux/m2json.m +++ b/plotly/plotly_aux/m2json.m @@ -5,29 +5,23 @@ valstr = cell2json(val); elseif isa(val, "numeric") sz = size(val); - if isa(val,"single") - precision = "7"; - else - precision = "15"; - end - fmt = "%." + precision + "g,"; - if length(find(sz>1))>1 % 2D or higher array - valstr = ""; + numDigits = 3 + ceil(clip(log10(double(max(abs(val),[],"all"))) ... + - log10(double(range(val,"all"))),0,12)); + numDigits(~isfinite(numDigits)) = 7; + fmt = sprintf("%%.%ig", numDigits); + if sum(sz>1)>1 % 2D or higher array + valsubstr = strings(1, sz(1)); for i = 1:sz(1) - valsubstr = sprintf(fmt, val(i,:)); - valsubstr = valsubstr(1:(end-1)); - valstr = valstr + ", [" + valsubstr + "]"; + formattedRowVal = arrayfun(@(x) sprintf(fmt, x), val(i,:)); + valsubstr(i) = strjoin(formattedRowVal, ","); + valsubstr(i) = "[" + valsubstr(i) + "]"; end - valstr = valstr(3:end); % trail leading commas + valstr = strjoin(valsubstr, ","); else - valstr = [sprintf(fmt, val)]; - valstr = valstr(1:(end-1)); - end - if length(val)>1 - valstr = "[" + valstr + "]"; - elseif isempty(val) - valstr = "[]"; + valstr = arrayfun(@(x) sprintf(fmt, x), val); + valstr = strjoin(valstr, ","); end + valstr = "[" + valstr + "]"; valstr = strrep(valstr,"-Inf", "null"); valstr = strrep(valstr, "Inf", "null"); valstr = strrep(valstr, "NaN", "null"); @@ -60,3 +54,8 @@ warning("Failed to m2json encode class of type: %s", class(val)); end end + +function x = clip(x,lb,ub) + x(xub) = ub; +end