Как увеличить экстенты на оси даты в d3? - PullRequest
0 голосов
/ 02 марта 2020

У меня есть линейный график в d3. Ось X - это даты. Я хочу немного увеличить экстенты, чтобы первая и последняя точки данных не попадали прямо в первую и последнюю дату на графике. Вот пи c графика: enter image description here

Обратите внимание, как первая точка данных и последняя точка данных находятся в начале и в конце диаграммы? Я хотел бы иметь небольшой запас с обеих сторон, так как самая маленькая дата должна быть немного меньше, а самая большая дата должна быть немного больше. Есть ли простой способ расширить экстенты?

Вот способ, которым он в настоящее время создается:

x.domain(d3.extent(data, function(d) { return d.date; }));

РЕДАКТИРОВАТЬ: Дата является динамической c и может быть несколько дней или несколько десятилетий. Я надеюсь на ответ, который смотрит на диапазон дат и добавляет примерно на 5% больше к каждому концу. Также, пожалуйста, предоставьте решение, которое не зависит от добавления другой библиотеки, которая может конфликтовать с существующими библиотечными функциями.

Например, приведенное ниже решение Герардо зависит от добавления дополнительной библиотеки, чтобы заставить работать функцию подсчета. Но это мешает функции оси позже в коде.

Единственный способ заставить работать следующий код:

  const minDate = new Date("October 10, 2010");
  const maxDate = new Date("January 31, 2020");
  const daysBetween = d3.timeDay.count(minDate,maxDate);

- включить эту библиотеку:

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

Но это приводит к сбою следующего кода, который будет использован позже:

  var xAxis = d3.svg.axis()
    .scale(x)
    .ticks(d3.time.years,1)
    .tickSize(10)
    .orient("bottom");

Это моя попытка найти решение. Я получаю минимальную и максимальную дату из экстентов, конвертирую их в миллисекунды, затем вычитаю 5% из минимума, добавляю 5% к максимальному, затем устанавливаю новые экстенты:

  var xSpan = maxTime - minTime;
  console.log("maxTime=" +maxTime +", minTime=" +minTime +", xSpan="+xSpan);
  xMarg = xSpan * 0.05;  
  xMarg = xMarg.toFixed(0); //nearest millisecond
  console.log("xMarg="+xMarg);
  var minDate = new Date(minTime-xMarg);
  var maxDate = new Date(maxTime+xMarg);
  console.log("minDate="+minDate +", maxDate="+maxDate);
  x.domain([minDate,maxDate]);

Но вывод maxDate показывает ошибку:

maxTime = 1580454000000, minTime = 1288332000000, xSpan = 292122000000 xMarg = 14606100000 minDate = ср. 12 мая 2010 22:45:00 GMT-0600 (горное дневное время), maxDate = Invalid Дата

Ответы [ 3 ]

2 голосов
/ 02 марта 2020

Модуль d3-time имеет несколько удобных методов, которые вы можете использовать, в вашем случае interval.offset. Вы можете выбрать, хотите ли вы добавить / вычесть миллисекунды, секунды, минуты, часы, дни, недели, месяцы или годы.

Например, если вы хотите добавить 15 дней к дате, как сегодня:

const todayPlus15days = d3.timeDay.offset(new Date(), 15);
//Interval type and offset-----^-----------------------^

console.log("In 15 days, it will be: " + todayPlus15days);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

В вашем случае давайте вычтем / сложим 2 месяца. Для этого мы заменим d3.extent на d3.min / d3.max:

x.domain([d3.timeMonth.offset(d3.min(data, function(d) {
    return d.date;
  }), -2),//subtracting 2 months
  d3.timeMonth.offset(d3.max(data, function(d) {
    return d.date;
  }), 2)//adding 2 months
])

Стоит отметить, что d3.timeMonth.offset(date, 2) может показаться таким же, как d3.timeDay.offset(date, 60), но 60 дней не обязательно 2 месяца. В вашем случае такая точность не важна.


РЕДАКТИРОВАТЬ

Согласно вашему комментарию ,

Все ответы до сих пор предполагают известный диапазон дат. Диапазон дат может составлять несколько дней или несколько десятилетий. Я надеюсь на ответ, который рассматривает диапазон дат и добавляет примерно на 5% больше к каждому концу.

Это также легко реализовать. Сначала мы устанавливаем процент (например, 5%), а затем получаем интервал дат. Для большей точности вы можете использовать секунды или даже миллисекунды, но я буду использовать здесь дни (d3.timeDay.count). Наконец, вы устанавливаете смещения (начало / конец) в соответствии с процентом.

Вот демоверсия:

const date1 = new Date("March 19, 2019");
const date2 = new Date("December 10, 2019");
const percentage = 0.05;
const numberOfDays = d3.timeDay.count(date1, date2);
const domain = [d3.timeDay.offset(date1, -(~~(numberOfDays * percentage))),
  d3.timeDay.offset(date2, +(~~(numberOfDays * percentage)))
];

console.log(domain)
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
0 голосов
/ 02 марта 2020

Вы можете просто добавить значение к дате на обоих концах и добавить его в X домен. Вы автоматически получите поля с обоих концов. Надеюсь, это поможет.

//assuming that date is in years
let min=Number.MAX_VALUE;
let max=Number.MIN_VALUE;
for (var property in data) {
  let date = data[property].date;
  if( date<min ){
     min = date;   
  }
  if( date>max ){
    max = date;
  }
}
//once we find min and max, assign it to domian of x-axis
x.domain(min-1,max+1);
0 голосов
/ 02 марта 2020

Вы можете узнать min max дополнительно и добавить / вычесть год / месяц из этого и использовать его вместо домена:

....
let extent = d3.extent(data, function(d) { return d.date; });
x.domain([addYear(extent[0], -1), addYear(extent[1], 1));
...
...
function addYear(date, number) {
    var year = date.getFullYear();
    var month = date.getMonth();
    var day = date.getDate();
    var c = new Date(year + number, month, day);
}
...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...