Skip to content

Adjust tick0 for weekly time periods #5180

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

Merged
merged 3 commits into from
Sep 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
18 changes: 16 additions & 2 deletions src/lib/dates.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,31 @@ function isWorldCalendar(calendar) {
/*
* dateTick0: get the canonical tick for this calendar
*
* integer weekdays : Saturday: 0, Sunday: 1, Monday: 2, etc.
*/
exports.dateTick0 = function(calendar, dayOfWeek) {
var tick0 = _dateTick0(calendar, !!dayOfWeek);
if(dayOfWeek < 2) return tick0;

var v = exports.dateTime2ms(tick0, calendar);
v += ONEDAY * (dayOfWeek - 1); // shift Sunday to Monday, etc.
return exports.ms2DateTime(v, 0, calendar);
};

/*
* _dateTick0: get the canonical tick for this calendar
*
* bool sunday is for week ticks, shift it to a Sunday.
*/
exports.dateTick0 = function(calendar, sunday) {
function _dateTick0(calendar, sunday) {
if(isWorldCalendar(calendar)) {
return sunday ?
Registry.getComponentMethod('calendars', 'CANONICAL_SUNDAY')[calendar] :
Registry.getComponentMethod('calendars', 'CANONICAL_TICK')[calendar];
} else {
return sunday ? '2000-01-02' : '2000-01-01';
}
};
}

/*
* dfltRange: for each calendar, give a valid default range
Expand Down
17 changes: 8 additions & 9 deletions src/plots/cartesian/axes.js
Original file line number Diff line number Diff line change
Expand Up @@ -630,12 +630,14 @@ axes.calcTicks = function calcTicks(ax, opts) {
generateTicks();

var isPeriod = ax.ticklabelmode === 'period';
if(isPeriod) {
var addedPreTick0Label = false;
if(isPeriod && tickVals[0]) {
// add one label to show pre tick0 period
tickVals.unshift({
minor: false,
value: axes.tickIncrement(tickVals[0].value, ax.dtick, !axrev, ax.caldendar)
});
addedPreTick0Label = true;
}

if(ax.rangebreaks) {
Expand Down Expand Up @@ -778,7 +780,7 @@ axes.calcTicks = function calcTicks(ax, opts) {
ticksOut.push(t);
}

if(isPeriod) {
if(isPeriod && addedPreTick0Label) {
var removedPreTick0Label = false;

for(i = 0; i < ticksOut.length; i++) {
Expand Down Expand Up @@ -965,7 +967,7 @@ axes.autoTicks = function(ax, roughDTick) {
}

if(ax.type === 'date') {
ax.tick0 = Lib.dateTick0(ax.calendar);
ax.tick0 = Lib.dateTick0(ax.calendar, 0);
// the criteria below are all based on the rough spacing we calculate
// being > half of the final unit - so precalculate twice the rough val
var roughX2 = 2 * roughDTick;
Expand All @@ -982,14 +984,11 @@ axes.autoTicks = function(ax, roughDTick) {
// get week ticks on sunday
// this will also move the base tick off 2000-01-01 if dtick is
// 2 or 3 days... but that's a weird enough case that we'll ignore it.
ax.tick0 = Lib.dateTick0(ax.calendar, true);

var tickformat = axes.getTickFormat(ax);
if(/%[uVW]/.test(tickformat)) {
// replace Sunday with Monday for ISO and Monday-based formats
var len = ax.tick0.length;
var lastD = +ax.tick0[len - 1];
ax.tick0 = ax.tick0.substring(0, len - 2) + String(lastD + 1);
ax.tick0 = Lib.dateTick0(ax.calendar, 2); // Monday
} else {
ax.tick0 = Lib.dateTick0(ax.calendar, 1); // Sunday
}
} else if(roughX2 > ONEHOUR) {
ax.dtick = roundDTick(roughDTick, ONEHOUR, roundBase24);
Expand Down
8 changes: 6 additions & 2 deletions src/plots/cartesian/clean_ticks.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@

var isNumeric = require('fast-isnumeric');
var Lib = require('../../lib');
var ONEDAY = require('../../constants/numerical').ONEDAY;
var constants = require('../../constants/numerical');
var ONEDAY = constants.ONEDAY;
var ONEWEEK = constants.ONEWEEK;

/**
* Return a validated dtick value for this axis
Expand Down Expand Up @@ -75,7 +77,9 @@ exports.dtick = function(dtick, axType) {
*/
exports.tick0 = function(tick0, axType, calendar, dtick) {
if(axType === 'date') {
return Lib.cleanDate(tick0, Lib.dateTick0(calendar));
return Lib.cleanDate(tick0,
Lib.dateTick0(calendar, (dtick % ONEWEEK === 0) ? 1 : 0)
);
}
if(dtick === 'D1' || dtick === 'D2') {
// D1 and D2 modes ignore tick0 entirely
Expand Down
6 changes: 4 additions & 2 deletions src/traces/scatter/period_defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ var numConstants = require('../../constants/numerical');
var ONEWEEK = numConstants.ONEWEEK;

function getPeriod0Dflt(period, calendar) {
var n = period / ONEWEEK;
return dateTick0(calendar, Math.round(n) === n);
if(period % ONEWEEK === 0) {
return dateTick0(calendar, 1); // Sunday
}
return dateTick0(calendar, 0);
}

module.exports = function handlePeriodDefaults(traceIn, traceOut, layout, coerce, opts) {
Expand Down
42 changes: 40 additions & 2 deletions test/jasmine/tests/axes_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ var Cartesian = require('@src/plots/cartesian');
var Axes = require('@src/plots/cartesian/axes');
var Fx = require('@src/components/fx');
var supplyLayoutDefaults = require('@src/plots/cartesian/layout_defaults');
var BADNUM = require('@src/constants/numerical').BADNUM;
var ONEDAY = require('@src/constants/numerical').ONEDAY;
var numerical = require('@src/constants/numerical');
var BADNUM = numerical.BADNUM;
var ONEDAY = numerical.ONEDAY;
var ONEWEEK = numerical.ONEWEEK;

var createGraphDiv = require('../assets/create_graph_div');
var destroyGraphDiv = require('../assets/destroy_graph_div');
Expand Down Expand Up @@ -6020,6 +6022,42 @@ describe('Test axes', function() {
.then(done);
});
});

[undefined, '%U', '%V', '%W'].forEach(function(tickformat) {
it('with ' + tickformat + ' tickformat, should default tick0 on a Sunday when dtick is a round number of weeks', function(done) {
var fig = {
data: [
{
showlegend: false,
type: 'bar',
width: ONEWEEK,
xperiod: ONEWEEK,
x: [
'2020-09-16',
'2020-09-24',
'2020-09-30'
],
y: [3, 2, 4]
}
],
layout: {
xaxis: {
tickformat: tickformat,
dtick: ONEWEEK,
ticklabelmode: 'period',
showgrid: true,
}
}
};

Plotly.newPlot(gd, fig)
.then(function() {
expect(gd._fullLayout.xaxis.tick0).toBe('2000-01-02');
})
.catch(failTest)
.then(done);
});
});
});
});

Expand Down