Line - area chart not showing - javascript

I am working with line-area chart using d3. But somehow the chart is not showing and there's no error in the console. I'm unable to figure out the issue. It will be helpful if anyone can help me with that.
I've added the entire code in Codepen. This is the link
Here's the sample code for ref:
const svg = d3.select("#chart")
.append('svg')
.attr('width', width)
.attr('height', height)
.append('g')
.attr('transform', `translate(${margin.left}, ${margin.top})`);
svg.append('defs');
svg.call(createGradient);
svg.call(createGlowFilter);
const xScale = d3.scaleTime()
.domain([
d3.min(parsedData, d => d3.min(d.values, v => v.x)),
d3.max(parsedData, d => d3.max(d.values, v => v.x))
])
.range([0, width]);
const yScale = d3.scaleLinear()
.domain([
d3.min(parsedData, d => d3.min(d.values, v => v.y)),
d3.max(parsedData, d => d3.max(d.values, v => v.y))
])
.range([height, 0]);
const line = d3.line()
.x(d => xScale(d.x))
.y(d => yScale(d.y))
.curve(d3.curveCatmullRom.alpha());
svg.selectAll('.line')
.data(parsedData)
.enter()
.append('path')
.attr('d', (d) => {
const lineValues = line(d.values).slice(1);
const splitedValues = lineValues.split(',');
return `M0,${height},${lineValues},l0,${height - splitedValues[splitedValues.length - 1]}`
})
.style('fill', 'url(#gradient)')
svg.selectAll('.line')
.data(parsedData)
.enter()
.append('path')
.attr('d', d => line(d.values))
.attr('stroke-width', '2')
.style('fill', 'none')
.style('filter', 'url(#glow)')
.attr('stroke', '#e4647f');
Thanks in advance!

I've created a fork of your code that has the line and area showing.
Here are the major changes.
First, I parsed the strings into dates:
const parseTime = d3.timeParse("%b %Y");
const parsedData = bar_chart_data.map(val => ({
close: val.y,
date: parseTime(val.x)
}));
parsedData is now an array of objects, so we can update the scales accordingly:
const xScale = d3.scaleTime()
// extent returns an array containing the min and max
.domain(d3.extent(parsedData, d => d.date))
.range([0, width]);
const yScale = d3.scaleLinear()
.domain([0, d3.max(parsedData, d => d.close)])
.range([height, 0]);
Next, I switched d3.line() to d3.area(), since you want to draw an area underneath the line. This will save you from having to manually construct the "d" attribute for the area.
const area = d3.area()
.x(d => xScale(d.date))
.y1(d => yScale(d.close)) // top line
.y0(yScale(0)) // base line, always at 0
.curve(d3.curveCatmullRom.alpha(0.5));
For drawing the line and area, we do not need to do a data join, we can just use append() and pass the parsedData array to the area generator for the area and to area.lineY1() for the top line:
svg.append("path")
.attr("d", area(parsedData))
.style("fill", "url(#gradient)");
svg.append("path")
.attr("d", area.lineY1()(parsedData))
.attr("stroke-width", "2")
.style("fill", "none")
.style("filter", "url(#glow)")
.attr("stroke", "#e4647f");

Related

How to set width for rect element in a bar chart using d3

I'm trying to plot a simple bar chart with date as x axis and temperature value as y axis. I'm using d3 library.
Created the xScale ans yScale as
const xScale = d3
.scaleTime()
.domain(d3.extent(dataset, xAccessor))
.range([0, dimensions.boundWidth]);
const yScale = d3
.scaleLinear()
.domain([0, d3.max(dataset, yAccessor)])
.range([dimensions.boundHeight, 0]);
Set the accessor functions as
const dateParse = d3.timeParse("%Y-%m-%d");
const xAccessor = (d) => dateParse(d["date"]);
const yAccessor = (d) => d["temperatureMax"];
And drew the rectangles using
const barsGroup = bounds.append("g");
const barGroups = barsGroup
.selectAll("mybars")
.data(dataset.slice(0, 10))
.join("g");
const barRects = barGroups
.append("rect")
.attr("x", (d) => xScale(xAccessor(d)))
.attr("y", (d) => yScale(yAccessor(d)))
.attr("width", "10")
.attr("height", (d) => dimensions.boundHeight - yScale(yAccessor(d)))
.attr("fill", "darkgray");
I'm trying to find out how to set the width attribute. Here I set it as a constant "10" just to see something on screen. Also trying to find out how to set proper spacing between each bars. I have a set up a codesandbox.io with the above set up. Any suggestions would be really helpful.

Date axis labels with d3.js

The date axis of my d3 line chart contains a mixture of months and weekdays. I just want it to be the months and the day of the month (eg 15 Feb).
chart with weird axis
Does anyone know how to fix this?
Super new to d3.js so excuse me.
Thank you!
//create scales
const yScale = d3.scaleLinear()
.domain(d3.extent(dataset, yAccessor))
.range([dimensions.boundedHeight, 0])
const xScale = d3.scaleTime()
.domain(d3.extent(dataset, xAccessor))
.range([0, dimensions.boundedWidth])
// draw data
const lineGenerator = d3.line()
.x(d => xScale(xAccessor(d)))
.y(d => yScale(yAccessor(d)))
const line = bounds.append("path")
.attr("d", lineGenerator(dataset))
.attr("fill", "none")
.attr("stroke", "#af9358")
.attr("stroke-width", 2)
//draw peripherals
const yAxisGenerator = d3.axisLeft()
.scale(yScale)
const yAxis = bounds.append("g")
.call(yAxisGenerator)
const xAxisGenerator = d3.axisBottom()
.scale(xScale)
const xAxis = bounds.append("g")
.call(xAxisGenerator)
.style("transform", `translateY(${
dimensions.boundedHeight
}px)`)
const xAxisLabel = xAxis.append("text")
.attr("x", dimensions.boundedWidth / 2)
.attr("y", dimensions.marginBottom -10)
.attr("fill", "black")
.style("font-size", "1.4em")
//.html("Date")
}
drawLineChart()
Fixed this myself using
.tickFormat(d3.timeFormat ("%d %b"))
as a method on the axis function
ie
const xAxisGenerator = d3.axisBottom()
.scale(xScale)
.tickFormat(d3.timeFormat ("%d %b"))

D3 Graph - changing y-axis to integer

I'm trying to create integer bands in the y axes.
Have tried changing .scaleband to .scalelinear and .ticks "arbitraryMetric" is stored as an integer.
Code:
const categories = vizData.map(d => d.arbitraryMetric);
const yScale = d3
.scaleBand()
.domain(categories)
.range([0, vizHeight - timelineMargin.bottom]);
const labels = vizCanvas
.selectAll('text')
.data(categories)
.enter()
.append('text')
.style('font-family', style.fontFamily)
.style('fill', '#3C4043')
.attr('x', timelineMargin.left - 10)
.attr('y', d => yScale(d) + yScale.bandwidth() / 2)
.attr('text-anchor', 'end')
.text(d => d);
This following solution will do the trick - credit to this answer
const yAxisTicks = yScale.ticks()
.filter(tick => Number.isInteger(tick));
const yAxis = d3.axisLeft(yScale)
.tickValues(yAxisTicks)
.tickFormat(d3.format('d'));

D3.js line transition is going out of the graph

I have a line graph where I have line transition. However on the initial graph drawing line path is ok, within the graph. But when I use the transition the line goes out of the container to the margins.
Transition function:
that.graph.select('.data-line')
.transition().duration(750)
.attr('fill', 'none')
.attr('stroke', '#ff0000')
.attr('stroke-width', 2)
.attr('d', line);
Line:
const line = d3.line()
.x(d => xAxis(new Date(d.n)))
.y(d => yAxis(d.v))
.defined(d => d.v || d.v === 0);
Axes:
const xAxis = d3.scaleTime()
.range([0, width])
.domain(xDomain);
const yAxis = d3.scaleLinear()
.range([height, 0])
.domain(yDomain);
Domains:
const yDomain = d3.extent(data, d => d.v);
const xDomain = d3.extent(data, d => new Date(d.n));
Dimensions:
const width = window.innerWidth - this.margins.left - this.margins.right;
const height = window.innerHeight - this.margins.top - this.margins.bottom;
Initial line drawing: (this is ok)
this.graph.append('g').attr('class', 'data-wrapper');
const line = d3.line()
.x(d => this.xAxis(new Date(d.n)))
.y(d => this.yAxis(d.v))
.defined(d => d.v || d.v === 0);
this.graph
.select('.data-wrapper')
.append('path')
.datum(data)
.attr('class', 'data-line')
.attr('fill', 'none')
.attr('stroke', '#ff0000')
.attr('stroke-width', 2)
.attr('d', line);
Here is the screenshot:
Any help is appreciated.
As #rioV8 suggested adding clip path solved issue.
If anyone in the feature has this problem here is the solution:
On your topmost SVG add this:
this.graph.append('defs')
.append('clipPath')
.attr('id', 'clip')
.append('rect')
.attr('width', this.width)
.attr('height', this.height);
And on the function where you draw data add
.attr('clip-path', 'url(#clip)')

D3 scales mess up my bar chart

I'm writing a simple bar chart that draws a rect element for each piece of data. This is a part of my code without scales, which works fine:
const rect = svg.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("x", (d, i) => (i*4))
.attr("y", (d) => h - d[1]/50)
However, if I add y-scale, my bars flip over, and if I add x-scale, I can only see one bar. Here's my code with scales:
const xScale = d3.scaleLinear()
.domain([0, d3.max(dataset, (d) => d[0])])
.range([padding, w - padding]);
const yScale = d3.scaleLinear()
.domain([0, d3.max(dataset, (d) => d[1])])
.range([h - padding, padding]);
//some other code
const rect = svg.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("x", (d, i) => xScale(i*4))
.attr("y", (d) => yScale(d[1]/50))
Here's my CodePen with scales, that's what it looks like: http://codepen.io/enk/pen/vgbvWq?editors=1111
I'd be really greatful if somebody told me what am I doing wrong.
D3 scales are not messing with your chart. The problem here is simple.
Right now, this is your dataset:
[["1947-01-01", 243.1], ...]
As you can see, d[0] is a string (representing a date), not a number. And, in d3.scaleLinear, the domain is an array with two values only.
The solution here is using a scaleBand instead:
const xScale = d3.scaleBand()
.domain(dataset.map(d => d[0]))
.range([padding, w - padding]);
And changing the code of the rectangles to actually use the scales (I made several changes, check them):
const rect = svg.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("width", xScale.bandwidth())
.attr("x", (d => xScale(d[0]))) //xScale
.attr("height", (d => h - yScale(d[1]))) //yScale
.style("y", (d => yScale(d[1])))
.attr("data-date", (d) => d[0])
.attr("data-gdp", (d) => d[1])
.attr("class", 'bar')
Here is your updated CodePen: http://codepen.io/anon/pen/NdJGdo?editors=0010

Categories

Resources