Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tickmode "proportional" #6827

Open
wants to merge 38 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
e7a2ffa
Add/calc tickmode "proportional" in `cartesian/`
ayjayt Dec 26, 2023
6d48a3b
Fix bug by which tickvals forever expands
ayjayt Dec 26, 2023
00e884a
Make tickmode proportional calculate reversed axes
ayjayt Dec 26, 2023
931199e
Use lib.simpleMap(); Refactor var names.
ayjayt Dec 26, 2023
fced9ce
Add log math to tickmode proportional
ayjayt Dec 26, 2023
b2abf08
Remove console debug messages
ayjayt Dec 26, 2023
910163e
Add description in layout_attributes.js
ayjayt Dec 26, 2023
e21af96
Fix linter errors
ayjayt Dec 26, 2023
ddfaad7
update plot-scheme diff
ayjayt Dec 26, 2023
d42dd73
Restore proportional array later in loop:
ayjayt Dec 27, 2023
5d7b1b9
Remove _isSet flag from tickVals before resetting
ayjayt Dec 28, 2023
db1f82e
Add parameterized tests:
ayjayt Dec 28, 2023
a2ac023
Fix tests to pass if #6828 is addressed
ayjayt Dec 28, 2023
1fedfc7
Clean up commenting/address lint errors.
ayjayt Dec 28, 2023
e8f2052
Fix a bit more lint
ayjayt Dec 28, 2023
c3f590d
Merge branch 'master' into pikul-proportional-ticks
ayjayt Jan 2, 2024
7e93370
Change tickmode 'proportional' to 'domain array'
ayjayt Jan 3, 2024
afba178
Add tickmode 'full domain'
ayjayt Jan 3, 2024
aca7a92
Set default so `full domain` doesn't set to `auto`
ayjayt Jan 3, 2024
195dfa5
Fix various errata/typos
ayjayt Jan 3, 2024
a788ccc
Add test for full-domain
ayjayt Jan 3, 2024
ecffc49
Merge branch 'master' into pikul-proportional-ticks
ayjayt Jan 4, 2024
3089c4a
Restructure parameterization and fix linting
ayjayt Jan 9, 2024
99d336a
Intermediate commit w/ partial work- new strat:
ayjayt Jan 12, 2024
4476d38
Merge branch 'master' into pikul-proportional-ticks
ayjayt Jan 12, 2024
3502d49
Revert branch to equal master
ayjayt Jan 12, 2024
09ebcfc
Lint and refactor
ayjayt Jan 12, 2024
3fe254b
Merge branch 'pikul-proportional-ticks-old' into pikul-proportional-t…
ayjayt Jan 12, 2024
eb82723
Revert completely to old tick algo
ayjayt Jan 12, 2024
fe6f8d0
update git-scheme diff
ayjayt Jan 12, 2024
b3956a0
Merge branch 'master' into pikul-proportional-ticks
ayjayt Jan 24, 2024
7176049
Remove category test in prep for disallowing
ayjayt Jan 25, 2024
15387ed
Refactor as to not override ax.tickvals:
ayjayt Jan 25, 2024
2ab0b41
Rework some if-then to golf mode (?:)
ayjayt Jan 25, 2024
f1a4db8
Lint
ayjayt Jan 25, 2024
ee17af2
Make 'auto' to function as 'array' when [] present
ayjayt Jan 25, 2024
93e4bb8
Refix incorrect patch ee17af22f393c
ayjayt Jan 25, 2024
61efdef
Merge branch 'master' into pikul-proportional-ticks
ayjayt Feb 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/plot_api/plot_api.js
Original file line number Diff line number Diff line change
Expand Up @@ -2945,7 +2945,11 @@ function getDiffFlags(oldContainer, newContainer, outerparts, opts) {
// so newContainer won't have them.
if((key === 'tick0' || key === 'dtick') && outerparts[0] !== 'geo') {
var tickMode = newContainer.tickmode;
if(tickMode === 'auto' || tickMode === 'array' || !tickMode) continue;
if(tickMode === 'auto' ||
tickMode === 'array' ||
tickMode === 'domain array' ||
tickMode === 'full domain' ||
!tickMode) continue;
}
// FIXME: Similarly for axis ranges for 3D
// contourcarpet doesn't HAVE zmin/zmax, they're just auto-added. It needs them.
Expand Down
74 changes: 62 additions & 12 deletions src/plots/cartesian/axes.js
Original file line number Diff line number Diff line change
Expand Up @@ -682,10 +682,13 @@ axes.prepTicks = function(ax, opts) {
if(ax._name === 'radialaxis') nt *= 2;
}

if(!(ax.minor && ax.minor.tickmode !== 'array')) {
if(!(ax.minor &&
(ax.minor.tickmode !== 'array' &&
ax.minor.tickmode !== 'domain array' &&
ax.minor.tickmode !== 'full domain'))) {
// add a couple of extra digits for filling in ticks when we
// have explicit tickvals without tick text
if(ax.tickmode === 'array') nt *= 100;
if(ax.tickmode === 'array' || ax.tickmode === 'domain array' || ax.tickmode === 'full domain') nt *= 100;
}

ax._roughDTick = Math.abs(rng[1] - rng[0]) / nt;
Expand Down Expand Up @@ -915,7 +918,6 @@ axes.calcTicks = function calcTicks(ax, opts) {
var maxRange = Math.max(rng[0], rng[1]);

var maxTicks = Math.max(1000, ax._length || 0);

var ticksOut = [];
var minorTicks = [];

Expand Down Expand Up @@ -944,15 +946,54 @@ axes.calcTicks = function calcTicks(ax, opts) {
axes.prepTicks(mockAx, opts);
}

// now that we've figured out the auto values for formatting
// in case we're missing some ticktext, we can break out for array ticks
if(mockAx.tickmode === 'array') {

if(mockAx.tickmode === 'array' || mockAx.tickmode === 'domain array' || mockAx.tickmode === 'full domain') {
var fractionalTickvals = [];
if(mockAx.tickmode === 'full domain') { // TODO: Change for minor, note: if minor we already have major
var nt = mockAx.nticks;
if(nt === undefined) nt = 0;
if(nt === 0) {
// pass
} else if(nt === 1) {
fractionalTickvals = [0.5];
} else if(nt === 2) {
fractionalTickvals = [0, 1];
} else {
var increment = 1 / (nt - 1); // (nt-2) + 1
fractionalTickvals = [0];
for(var tickIndex = 0; tickIndex < nt - 2; tickIndex++) {
fractionalTickvals.push((tickIndex + 1) * increment);
}
fractionalTickvals.push(1);
}
}
if(mockAx.tickmode === 'domain array') {
fractionalTickvals = (major ? ax : ax.minor).tickvals;
}

if(mockAx.tickmode !== 'array') {
var width = (maxRange - minRange); // TODO: inspect this value for log, it shouldn't work!
if(axrev) width *= -1;
var offset = !axrev ? minRange : maxRange; // TODO: inspect this value for log
var mappedVals = Lib.simpleMap(fractionalTickvals,
function(fraction, offset, width, type) {
var mapped = offset + (width * fraction);
return (type === 'log') ? Math.pow(10, mapped) : mapped;
}, offset, width, type);
// reminder: ranges w/ type log use the exponent whereas ticks use the absolute value
// TODO: do some inspection here: it freaks me out doin arithmetic on possible exponents
(major ? ax : ax.minor)._mappedTickvals = mappedVals;
}
// now that we've figured out the auto values for formatting
// in case we're missing some ticktext, we can break out for array ticks

// Original 'array' only code
if(major) {
tickVals = [];
ticksOut = arrayTicks(ax, !isMinor);
ticksOut = arrayTicks(ax, !isMinor); // ie arrayTicks(ax, majorOnly = !False)
} else {
minorTickVals = [];
minorTicks = arrayTicks(ax, !isMinor);
minorTicks = arrayTicks(ax, !isMinor); // ie arrayTicks(ax, majorOnly = !True)
}
continue;
}
Expand Down Expand Up @@ -1204,6 +1245,7 @@ axes.calcTicks = function calcTicks(ax, opts) {
ticksOut.push(t);
}
}

ticksOut = ticksOut.concat(minorTicks);

ax._inCalcTicks = false;
Expand Down Expand Up @@ -1281,7 +1323,10 @@ function arrayTicks(ax, majorOnly) {
for(var isMinor = 0; isMinor <= 1; isMinor++) {
if((majorOnly !== undefined) && ((majorOnly && isMinor) || (majorOnly === false && !isMinor))) continue;
if(isMinor && !ax.minor) continue;
var vals = !isMinor ? ax.tickvals : ax.minor.tickvals;

var targetAxis = (!isMinor ? ax : ax.minor);
var vals = (targetAxis.tickmode === 'array') ? targetAxis.tickvals : targetAxis._mappedTickvals;

var text = !isMinor ? ax.ticktext : [];
if(!vals) continue;

Expand Down Expand Up @@ -1618,18 +1663,23 @@ axes.tickFirst = function(ax, opts) {
axes.tickText = function(ax, x, hover, noSuffixPrefix) {
var out = tickTextObj(ax, x);
var arrayMode = ax.tickmode === 'array';
var fractionalMode = (ax.tickmode === 'domain array' || ax.tickmode === 'full domain');
var extraPrecision = hover || arrayMode;
var axType = ax.type;
// TODO multicategory, if we allow ticktext / tickvals
var tickVal2l = axType === 'category' ? ax.d2l_noadd : ax.d2l;
var i;

if(arrayMode && Lib.isArrayOrTypedArray(ax.ticktext)) {
if((arrayMode || fractionalMode) && Lib.isArrayOrTypedArray(ax.ticktext)) {
var rng = Lib.simpleMap(ax.range, ax.r2l);
var minDiff = (Math.abs(rng[1] - rng[0]) - (ax._lBreaks || 0)) / 10000;

for(i = 0; i < ax.ticktext.length; i++) {
if(Math.abs(x - tickVal2l(ax.tickvals[i])) < minDiff) break;
if(arrayMode) {
if(Math.abs(x - tickVal2l(ax.tickvals[i])) < minDiff) break;
} else {
if(Math.abs(x - tickVal2l(ax._mappedTickvals[i])) < minDiff) break;
}
}
if(i < ax.ticktext.length) {
out.text = String(ax.ticktext[i]);
Expand Down Expand Up @@ -3333,7 +3383,7 @@ axes.drawGrid = function(gd, ax, opts) {

var counterAx = opts.counterAxis;
if(counterAx && axes.shouldShowZeroLine(gd, ax, counterAx)) {
var isArrayMode = ax.tickmode === 'array';
var isArrayMode = (ax.tickmode === 'array' || ax.tickmode === 'domain array' || ax.tickmode === 'full domain');
for(var i = 0; i < majorVals.length; i++) {
var xi = majorVals[i].x;
if(isArrayMode ? !xi : (Math.abs(xi) < ax.dtick / 100)) {
Expand Down
15 changes: 11 additions & 4 deletions src/plots/cartesian/layout_attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ var DAY_OF_WEEK = constants.WEEKDAY_PATTERN;

var minorTickmode = {
valType: 'enumerated',
values: ['auto', 'linear', 'array'],
values: ['auto', 'linear', 'array', 'domain array', 'full domain'],
editType: 'ticks',
impliedEdits: {tick0: undefined, dtick: undefined},
description: [
Expand All @@ -23,9 +23,16 @@ var minorTickmode = {
'If *linear*, the placement of the ticks is determined by',
'a starting position `tick0` and a tick step `dtick`',
'(*linear* is the default value if `tick0` and `dtick` are provided).',
'If *array*, the placement of the ticks is set via `tickvals`',
'and the tick text is `ticktext`.',
'(*array* is the default value if `tickvals` is provided).'
'If *array*, the placement of the ticks is set via `tickvals`,',
'which are actual values, and the tick text is `ticktext`.',
'(*array* is the default value if `tickvals` is provided).',
'If *full domain*, the number of ticks is set bia `nticks` but ticks',
'are placed first at both axis ends and then at equal proportions',
'between the axis. So `nticks=5` would put ticks at both ends and',
'every quarter.',
'If *domain array*, the placement is similiar to *array* except that',
'`tickvals` are fractions between 0 and 1 representing distance on',
'the corresponding axis.'
].join(' ')
};

Expand Down
3 changes: 1 addition & 2 deletions src/plots/cartesian/tick_value_defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@ module.exports = function handleTickValueDefaults(containerIn, containerOut, coe
_dtick ? 'linear' :
'auto';
var tickmode = coerce(prefix + 'tickmode', tickmodeDefault);

if(tickmode === 'auto' || tickmode === 'sync') {
if(tickmode === 'auto' || tickmode === 'sync' || tickmode === 'full domain') {
coerce(prefix + 'nticks');
} else if(tickmode === 'linear') {
// dtick is usually a positive number, but there are some
Expand Down
Loading