Skip to content

Commit 4535404

Browse files
committed
Merge branch 'master' of github.com:plotly/plotly.js into custom-server-url
2 parents 3aaf531 + 0af79cc commit 4535404

13 files changed

Lines changed: 438 additions & 119 deletions

File tree

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ but the general idea is to be nice.
1414

1515
## Plotly.js vs Plotly.py and Plotly.R
1616

17-
[Plotly.js](https://plotly.com/javascript) is a standalone Javascript data visualization library, and it also powers the Python and R modules named `plotly` in those respective ecosystems (referred to as [Plotly.py](https://plotly.com/python) and [Plotly.R](http://plotly.com/r), respectively, for clarity). There also exist Plotly.js-powered libraries for other languages such as Julia, Scala, Rust, .NET and even C++!
17+
[Plotly.js](https://plotly.com/javascript) is a standalone Javascript data visualization library, and it also powers the Python and R modules named `plotly` in those respective ecosystems (referred to as [Plotly.py](https://plotly.com/python) and [Plotly.R](https://plotly.com/r), respectively, for clarity). There also exist Plotly.js-powered libraries for other languages such as Julia, Scala, Rust, .NET and even C++!
1818

1919
The basic architecture of Plotly.js is to accept [JSON](https://json.org/) representation of figures that adhere to the [figure schema](https://plotly.com/javascript/reference/index/) and draw interactive graphical representations of these figures in a browser. Libraries in other languages like Python and R provide idiomatic interfaces for users of those languages to create and manipulate these JSON structures, and arrange for them to be rendered in a browser context by Plotly.js. This means that in many cases, when a Python or R user wishes to add a feature to the library they know as `plotly`, the relevant changes must be implemented in Plotly.js, in this repo.
2020

draftlogs/7507_fix.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix `histogram` autobin size for single-point traces in `overlay` mode on data updates via `Plotly.react` [[#7507](https://github.com/plotly/plotly.js/pull/7507)], with thanks to @Lexachoc for the contribution!

draftlogs/7768_fix.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Format tick labels correctly for small numbers in exponential notation [[#7768](https://github.com/plotly/plotly.js/pull/7768)], with thanks to @Hasnaathussain for the contribution!

draftlogs/7901_fix.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Snap cartesian axis tick values to multiple of delta so custom `tickformat` (e.g. `"~r"`) no longer shows floating-point artifacts [[#7901](https://github.com/plotly/plotly.js/pull/7901)], with thanks to @arieleli01212 and @kirthi-b for the contribution!

draftlogs/7905_fix.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Fix `scattermap` box and lasso selection across the antimeridian [[#7905](https://github.com/plotly/plotly.js/pull/7905)], with thanks to @coyaSONG for the contribution!

package-lock.json

Lines changed: 101 additions & 63 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/plots/cartesian/axes.js

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,28 @@ function expandRange(range) {
9090
];
9191
}
9292

93+
/**
94+
* Correct a floating-point roundoff artifact in a linearized tick value.
95+
* When `l` is much closer to its nearest ideal grid position than one `dtick`
96+
* (within `dtick * snapThreshold`), snap it to that ideal. Otherwise return
97+
* `l` unchanged. See https://github.com/plotly/plotly.js/issues/7765.
98+
*
99+
* @param l - linearized tick value from the accumulator in calcTicks
100+
* @param tick0l - the axis' `tick0` in linearized form
101+
* @param dtick - the axis' tick step; must be numeric and nonzero to snap
102+
* @returns the snapped value, or `l` unchanged if no snap applies
103+
*/
104+
function snapToGrid(l, tick0l, dtick) {
105+
if (![dtick, l, tick0l].every(isNumeric) || dtick === 0) return l;
106+
107+
const nTicks = Math.round((l - tick0l) / dtick);
108+
const idealTick = tick0l + nTicks * dtick;
109+
const snapThreshold = 1e-6;
110+
const shouldSnap = l !== idealTick && Math.abs(l - idealTick) < Math.abs(dtick) * snapThreshold;
111+
112+
return shouldSnap ? idealTick : l;
113+
}
114+
93115
/*
94116
* find the list of possible axes to reference with an xref or yref attribute
95117
* and coerce it to that list
@@ -1067,6 +1089,7 @@ axes.calcTicks = function calcTicks(ax, opts) {
10671089
}
10681090

10691091
var dtick = mockAx.dtick;
1092+
var tick0l = (type === 'linear') ? mockAx.r2l(mockAx.tick0) : undefined;
10701093

10711094
if(mockAx.rangebreaks && mockAx._tick0Init !== mockAx.tick0) {
10721095
// adjust tick0
@@ -1110,7 +1133,7 @@ axes.calcTicks = function calcTicks(ax, opts) {
11101133
if(tickVals.length > maxTicks || x === prevX) break;
11111134
prevX = x;
11121135

1113-
var obj = { value: x };
1136+
var obj = { value: snapToGrid(x, tick0l, dtick) };
11141137

11151138
if(major) {
11161139
if(isDLog && (x !== (x | 0))) {
@@ -2191,9 +2214,6 @@ function numFormat(v, ax, fmtoverride, hover) {
21912214

21922215
if(tickformat) return ax._numFormat(tickformat)(v).replace(/-/g, MINUS_SIGN);
21932216

2194-
// 'epsilon' - rounding increment
2195-
var e = Math.pow(10, -tickRound) / 2;
2196-
21972217
// exponentFormat codes:
21982218
// 'e' (1.2e+6, default)
21992219
// 'E' (1.2E+6)
@@ -2208,27 +2228,27 @@ function numFormat(v, ax, fmtoverride, hover) {
22082228
// take the sign out, put it back manually at the end
22092229
// - makes cases easier
22102230
v = Math.abs(v);
2231+
2232+
// 'epsilon' - rounding increment
2233+
const e = Math.pow(10, -tickRound) / 2;
22112234
if(v < e) {
22122235
// 0 is just 0, but may get exponent if it's the last tick
22132236
v = '0';
22142237
isNeg = false;
22152238
} else {
2216-
v += e;
22172239
// take out a common exponent, if any
22182240
if(exponent) {
22192241
v *= Math.pow(10, -exponent);
22202242
tickRound += exponent;
22212243
}
22222244
// round the mantissa
2223-
if(tickRound === 0) v = String(Math.floor(v));
2224-
else if(tickRound < 0) {
2245+
if(tickRound === 0) {
22252246
v = String(Math.round(v));
2226-
v = v.slice(0, Math.max(0, v.length + tickRound));
2227-
for(var i = tickRound; i < 0; i++) v += '0';
2247+
} else if(tickRound < 0) {
2248+
const roundingMagnitude = Math.pow(10, -tickRound);
2249+
v = String(Math.round(v / roundingMagnitude) * roundingMagnitude);
22282250
} else {
2229-
v = String(v);
2230-
var dp = v.indexOf('.') + 1;
2231-
if(dp) v = v.slice(0, dp + tickRound).replace(/\.?0+$/, '');
2251+
v = v.toFixed(Math.min(20, tickRound)).replace(/\.?0+$/, '');
22322252
}
22332253
// insert appropriate decimal point and thousands separator
22342254
v = Lib.numSeparate(v, ax._separators, separatethousands);

0 commit comments

Comments
 (0)