KevinHu
KevinHu

Reputation: 1029

d3 v4 line chart data

I want to use this line chart example with my new format data.

https://codepen.io/sky790312/pen/EbdRNb

Old data format and x-axis:

  const DATA1 = [9.5, 2, 5, 7, 5, 3, 0];
  const LABELS = [
    'monday',
    'tuesday',
    'wednesday',
    'thursday',
    'friday',
    'saturday',
    'sunday'
  ];

New data format::

  // parse the date / time
  const parseDate = d3.timeParse('%Y%m%d')
  const formatTime = d3.timeFormat('%y/%m/%d')

  const data = [
    {dataX: '20171016', dataY: 54.13},
    {dataX: '20171017', dataY: 50.13},
    {dataX: '20171018', dataY: 70.13},
    {dataX: '20171019', dataY: 53.98}]
  data.map(d => {
    d.dataX = parseDate(d.dataX)
    d.dataY = +d.dataY
  })

But I still facing some problem with the new format.

Upvotes: 1

Views: 806

Answers (2)

Lary Ciminera
Lary Ciminera

Reputation: 1270

you have to use d3.scaleTime as your x axis : https://bl.ocks.org/d3indepth/8948c9936c71e63ef2647bc4cc2ebf78 then when you bind attribute with data value you have to use:

xScale(d.dataX)

instead of :

xScale(LABELS[i])

same for y values use

d => yScale(d.dataY)

instead of

d => yScale(d)

Upvotes: 0

Cyril Cherian
Cyril Cherian

Reputation: 32327

You will need to change the scale from scaleBand to timeScale then changes as per the new data set.

const graphContainer = d3.select(".d3--line");
const svg = d3.select("svg");
const margin = { top: 50, right: 50, bottom: 50, left: 50 };
const duration = 500;
let width, height, innerWidth, innerHeight;
let xScale, yScale;
const parseDate = d3.timeParse("%Y%m%d");
const formatTime = d3.timeFormat("%y/%m/%d");

const data = [
  { dataX: "20171016", dataY: 54.13 },
  { dataX: "20171017", dataY: 50.13 },
  { dataX: "20171018", dataY: 70.13 },
  { dataX: "20171019", dataY: 53.98 }
];
data.map(d => {
  d.dataX = parseDate(d.dataX);
  d.dataY = +d.dataY;
});

(function init() {
  getDimentions();
  getScaleDomains();
  getScaleRanges();
  renderGraph(data);
})();

d3.select(window).on("resize", resize);

function resize() {
  destroyGraph();
  getDimentions();
  getScaleRanges();
  renderGraph(data);
}

function renderGraph(data) {

  const line = d3
    .line()
    .x((d, i) => xScale(d.dataX))
    .y(d => yScale(d.dataY))
    .curve(d3.curveCatmullRom.alpha(0.5));

  const area = d3
    .area()
    .x((d, i) => xScale(d.dataX))
    .y0(innerHeight)
    .y1(d => yScale(d.dataY))
    .curve(d3.curveCatmullRom.alpha(0.5));

  const xAxis = d3.axisBottom(xScale).tickFormat((d, i) => formatTime(d)).ticks(4);

  const yAxis = d3.axisLeft(yScale).ticks(4);

  svg.attr("width", width).attr("height", height);

  const inner = svg.selectAll("g.inner").data([null]);
  inner.exit().remove();
  inner
    .enter()
    .append("g")
    .attr("class", "inner")
    .attr("transform", `translate(${margin.top}, ${margin.right})`);

  const horizontalLineGroup = svg
    .selectAll("g.inner")
    .selectAll(".line-group")
    .data([null]);
  horizontalLineGroup.exit().remove();
  horizontalLineGroup
    .enter()
    .append("g")
    .attr("class", "line-group");

  const horizontalLine = svg
    .selectAll("g.line-group")
    .selectAll(".grid-line")
    .data(yScale.ticks(4));
  horizontalLine.exit().remove();
  horizontalLine
    .enter()
    .append("line")
    .attr("class", "grid-line")
    .attr("x1", 0)
    .attr("x2", innerWidth)
    .attr("y1", d => yScale(d))
    .attr("y2", d => yScale(d));

  const xa = svg
    .selectAll("g.inner")
    .selectAll("g.x.axis")
    .data([null]);
  xa.exit().remove();
  xa
    .enter()
    .append("g")
    .attr("class", "x axis")
    .attr("transform", `translate(0, ${innerHeight})`)
    .call(xAxis);

  const ya = svg
    .selectAll("g.inner")
    .selectAll("g.y.axis")
    .data([null]);
  ya.exit().remove();
  ya
    .enter()
    .append("g")
    .attr("class", "y axis")
    .call(yAxis);

  const pathLine1 = svg
    .selectAll("g.inner")
    .selectAll(".path-line1")
    .data([null]);
  pathLine1.exit().remove();
  pathLine1
    .enter()
    .append("path")
    .attr("class", "path-line path-line1")
    .attr("d", () => line(createZeroDataArray(data)))
    .transition()
    .duration(duration)
    .ease(d3.easePoly.exponent(2))
    .attr("d", line(data));

  const pathArea1 = svg
    .selectAll("g.inner")
    .selectAll(".path-area1")
    .data([null]);
  pathArea1.exit().remove();
  pathArea1
    .enter()
    .append("path")
    .attr("class", "path-area path-area1")
    .attr("d", () => area(createZeroDataArray(data)))
    .transition()
    .duration(duration)
    .ease(d3.easePoly.exponent(2))
    .attr("d", area(data));
}

function destroyGraph() {
  svg.selectAll("*").remove();
}

function getDimentions() {
  width = graphContainer.node().clientWidth;
  height = 500;
  innerWidth = width - margin.left - margin.right;
  innerHeight = height - margin.top - margin.bottom;
}

function getScaleRanges() {
  xScale.range([0, innerWidth]);
  yScale.range([innerHeight, 0]).nice();
}

function getScaleDomains() {
  xScale = d3.scaleTime().domain(d3.extent(data, a => a.dataX));
  yScale = d3.scaleLinear().domain([0, d3.max(data, a=>a.dataY)]);
}

function createZeroDataArray(arr) {
  const newArr = [];
  arr.forEach((item, index) => (newArr[index] = { dataX: new Date(), dataY: 0 }));
  return newArr;
}

console.log("refres   h");
.d3 {
  box-shadow: 0 0 0 1px #eee;
  box-sizing: border-box;
}

path,
line {
  fill: none;
  shape-rendering: crispEdges;
  stroke: #E8E8E8;
}

.path-line {
  shape-rendering: initial;
}
.path-line.path-line1 {
  stroke: #0baadd;
}
.path-line.path-line2 {
  stroke: #47cf73;
}

.path-area {
  stroke: none;
}
.path-area.path-area1 {
  fill: rgba(11, 170, 221, 0.7);
  stroke: rgba(11, 170, 221, 0.7);
}
.path-area.path-area2 {
  fill: rgba(71, 207, 115, 0.55);
  stroke: rgba(71, 207, 115, 0.55);
}

.tick text {
  font-family: sans-serif;
  font-size: 10px;
  fill: #999;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.1.1/d3.min.js"></script>

<div class="d3 d3--line">
  <svg class="line-graph"></svg>
</div>

Upvotes: 2

Related Questions