Принудительное наложение отметок на графике области по оси X на основе точек данных

#javascript #d3.js #charts

#javascript #d3.js #Диаграммы

Вопрос:

Я использую диаграмму областей D3 для построения диаграммы для данных с такой структурой:

 data = [
  {
    date: "2019-02-01", 
    value: 100
  }, {
    date: "2019-03-01", 
    value: 1
  }
]
  

Когда я использую пример диаграммы области D3, они устанавливают ось X как:

 const x = d3.scaleTime()
    .domain(d3.extent(data, d => Date.parse(d.date)))
    .range([margin.left, width - margin.right])
const xAxis = g => g
    .attr("transform", `translate(0,${height - margin.bottom})`)
    .call(d3.axisBottom(x).ticks(width / 80).tickSizeOuter(0));
  

Однако это равномерно добавляет отметки по всей оси X. Я попытался сделать что-то вроде:

 const xAxis = g => g
    .attr("transform", 'translate(0,'   (height   data.length)   ')')
    .call(d3.axisBottom(x).ticks(data.length).tickSizeOuter(0));
  

но затем на оси X ничего не появилось.. Как я могу заставить ось X отображать отметки только для заданных date значений из моих данных (т. Е. Для приведенного выше примера данных я хочу видеть только 2019-02-01 и 2019-03-01 на оси X).

Еще лучше было бы просто отобразить месяц и год этих дат (т. е. 2019-02-01 они отображались бы как Feb. 2019 на графике).

Ответ №1:

Вы можете указать, какие значения должны быть отметками, предоставив массив axis.tickValues() , содержащий желаемые значения отметок. Если вашими отметками должны быть значения в вашем массиве данных, то вам нужно только перебрать ваш массив и выбрать значения. В вашем случае это может выглядеть следующим образом:

 var axis = d3.axisBottom()
  .scale(x)
  .tickValues(
     data.map(function(d) { return timeParse(d.date); })
  )
  

Если ваша шкала является шкалой времени, то значения должны быть объектами даты, поэтому мы не можем передавать форматированные даты. Но, если мы хотим указать, как будет отображаться отметка, тогда мы также можем передать формат axis.tickFormat , это позволит вам установить, как отображаются даты. Вместе мы получаем:

 var svg = d3.select("svg");

var data = data = [
  {
    date: "2019-02-01", 
    value: 100
  },
  {
    date: "2019-03-1", 
    value: 50
  },
  {
    date: "2019-05-01", 
    value: 1
  }

];

var timeParse = d3.timeParse("%Y-%m-%d");
var timeFormat = d3.timeFormat("%B %Y");

var x = d3.scaleTime()
  .domain(d3.extent(data,function(d) { return timeParse(d.date); }))
  .range([20,300]);
  
var y = d3.scaleLinear()
  .domain([0,100])
  .range([10,100]);
  
var line = d3.line()
  .x(function(d) { return x(timeParse(d.date)); })
  .y(function(d) { return y(d.value); })
  
svg.append("path")
  .datum(data)
  .attr("d", line);
  
// Axis:
var axisBottom = d3.axisBottom()
  .scale(x)
  .tickValues(data.map(function(d) {
    return timeParse(d.date); // specify which values should be ticks.
  }))
  .tickFormat(timeFormat);
  
svg.append("g")
  .attr("transform","translate(0,100)")
  .call(axisBottom);
  
  
  
svg.selectAll("text")
  .attr("text-anchor","start")
  .attr("transform","rotate(90)translate(10,-13)");  
 path {
  fill: none;
  stroke: black;
  stroke-width: 1px;
}  
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg width="400" height="400"></svg>