I use this code to create a bullet chart with d3. Now I want to create a bullet chart in an Angular component.
I'm new to d3 so i tried to convert the code to typescript.
Here is my code. I know there are mistakes in the code. Could you help me to make it working?
this.svg = d3.select('body').selectAll('svg')
.enter().append('svg')
.attr('class', 'bullet')
.attr('width', 100 + this.margin.left + this.margin.right)
.attr('height', 300 + this.margin.top + this.margin.bottom);
this.g = this.svg.append('g')
.attr('transform', 'translate(' + this.margin.left + ',' + this.margin.top + ')')
;
This is the svg init function. I should create a svg element in the dom, but it doesn't.
In the example .attr('class', 'bullet') does the work. But this will not work in angular.
Any ideas?
Remove the .selectAll('svg').enter(). Enter only works after a .data() join. Have a look at Mike Bostock's Thinking with Joins.
Related
I am working off of the d3 "Calendar View" example and would like to display 1 year at a time with some buttons to progress or regress the year being shown. In this example all of the data (years 1990-2010) arrive with the d3.csv call and is being rendered in a chart defined by...
var svg = d3.select("body")
.selectAll("svg")
.data(d3.range(1990, 2011))
.enter().append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + ((width - cellSize * 53) / 2) + "," + (height - cellSize * 7 - 1) + ")");
I would like to be able to update the data attribute on the d3 class and update the chart via a clickable event.
For example maybe showing the year 2010 is default like this...
var svg = d3.select("body")
.selectAll("svg")
.data(d3.range(2010, 2011))
.enter().append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + ((width - cellSize * 53) / 2) + "," + (height - cellSize * 7 - 1) + ")");
and i just want to modify the data element to d3.range(2009, 2010) on an event and redraw the chart.
I've tried removing and re-rendering the chart but haven't had success. There must be an easier way to do this.
In your code above you are only ever calling enter which is designed to add new elements to the DOM. There's a really good article from the author Mike Bostock called 3 Little Circles that explains how the enter/exit/update pattern works (note that it was for v3 though).
const join = d3
.select("body")
.selectAll("svg")
.data(d3.range(2010, 2011), d => d);
First thing to note is that we've provided a key function to .data(). In this case the key is literally the value d which will return 2010 and 2011 for the two data points.
join.exit().remove();
Get rid of the old calendars!
join.enter()
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + ((width - cellSize * 53) / 2) + "," + (height - cellSize * 7 - 1) + ")")
.merge(join)
... do more stuff
The next importing bit you're missing is to update the existing stuff. You do that by taking your enter selection and calling merge(join). That gives you all the new and updated items so you can start changing attributes/styles or do further nested joins on.
I created a polar scatter plot using D3.js (based on this post) .
I would like to add the functionality to zoom and pan. I've seen examples for rectangular plots, but nothing for zooming/panning on circular plots.
I am just a beginner with using D3 so I'm a little lost. Can anyone help/offer suggestions?
I'm not entirely sure what your goal is, but I tried something below.
First you should add zoom behaviour. I used the r scale for both your x and y directions like:
var zoomBeh = d3.behavior.zoom()
.x(r)
.y(r)
.on("zoom", zoom);
And call the zoom behaviour into your svg:
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")")
.call(zoomBeh);
Finally you should make a zoom function.
function zoom() {
var t = svg.transition().duration(750);
svg.selectAll(".point").transition(t)
.attr("transform", function(d) {
var coors = line([d]).slice(1).slice(0, -1);
return "translate(" + coors + ")"
})
}
Here is an updated fiddle. It's a little bit staggering, I'm not sure why yet.
I'm trying to implement box plots as part of a data visualization interface that uses d3 and AngularJS. I'm working with this box plot package: https://bl.ocks.org/mbostock/4061502.
However, I can't figure out which part of the sample code controls the positioning of the box plots. In the example, the five box plots are arranged sequentially. When I try to generate my plots, they all appear on top of each other.
Here is the code that I'm using to generate the box plots:
boxplots = svg.selectAll("svg")
.data(boxPlotData)
.enter().append("svg")
.attr("class", "box")
.attr("width", boxWidth + margin.left + margin.right)
.attr("height", boxHeight + margin.bottom + margin.top)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.call(chart);
Here's the code for how my svg canvas is created. This is done in an angular directive:
template:"<svg width='825' height='600'></svg>",
link: function($scope, elem){
var d3 = $window.d3;
var rawSvg=elem.find('svg'); // this is the svg created in the template
var width = rawSvg[0].attributes[0].value;
var height = rawSvg[0].attributes[1].value;
var svg = d3.select(rawSvg[0]);
Edit: not perfect yet but getting there:
What you need is an ordinal scale to position the svg-elements for the boxes within the parent svg. Assuming width represents the width of your parent svg element and data is an array of your data elements, you can use this to create the scale:
const x = d3.scaleBand()
.range( [0, width] )
.domain( data.map( (el,i) => i ) );
Within the svg creation you can now use
boxplots = svg.selectAll("svg")
.data(boxPlotData)
.enter().append("svg")
.attr( "x", (d,i) => x(i) ) // this is added
.attr("class", "box")
.attr("width", boxWidth + margin.left + margin.right)
.attr("height", boxHeight + margin.bottom + margin.top)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.call(chart);
PS: This assumes you use v4 of d3js. The syntax in v3 for the scale is different.
PPS: I currently can not test the code, but it should work like described.
again I am struggling with d3.js. I have a working Line Chart and partially working mouseover. The goal is to limit the mouseover solely to the svg element, like Mark has it working in his answer Multiseries line chart with mouseover tooltip
I have created a Plunker with it. My is-situation is like that.
http://plnkr.co/edit/Jt5jZhnPQy4VpjwY3YBv?p=preview
And I have tried things like:
http://plnkr.co/edit/lRMfa0OiDWEXWYBAjoPd?p=preview
by adding:
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
But it's always pushing the circles and the bar out of the chart, I am fiddling for some days now and would be extremely glad if someone happens to point me in the right direction.
Thank you in advance.
Here is the plunker:
http://plnkr.co/edit/MEtbBqN5qr82yr0CNhUN?p=preview
I simply changed the size of your rectangle:
mouseG.append('rect')
.attr("x", margin.left)
.attr("y", margin.top)
.attr('width', w - margin.left - margin.right)
.attr('height', height - margin.bottom - margin.top)
PS: I don't know if you want the line limited to the chart area as well, but if you want, this is the plunker: http://plnkr.co/edit/RP4uYKBYnHtX1SvYsLKq?p=preview
Instead of giving width as width :
mouseG.append('svg:rect')
.attr('width', width)
do this (give the width of the group same as domain x for the line chart)
mouseG.append('svg:rect')
.attr('width', w - padding * 2)
Reason:
var xScale = d3.time.scale()
.domain([xExtents[0], xExtents[1]])
.range([padding, w - padding * 2]);
Your width of the x scale is w - padding * 2 so the width of the group listening to the mouse event should be same.
working code here
I am fairly new to D3 and javascript. Very useful library, though. But I am having trouble to make my stacked bar chart (I got the code from D3js.org website) responsive. Actually, I have problems making all kinds of D3 charts responsive when I start from scratch .
I tried using viewbox attribute and also preserveAspectRatio, but I am probably doing it wrong.
Here is my entire code: http://codepen.io/voltdatalab/pen/avMoMx
var svg = d3.select("graph").append("svg")
.attr("width", "100%")
.attr('preserveAspectRatio','xMinYMid')
.attr('viewBox','0 100% '+Math.min(width,height)+' '+Math.min(width,height))
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
Could someone give me a hand with this?
You need to set the viewbox attribute first. Try this:
var svg = d3.select("#chart").append("svg")
.attr("viewBox", "0 0 " + (width) + " " + (height))
.attr("preserveAspectRatio", "xMinYMin");
For this to work, you have to change your html:
<div id="chart"></div>