I am trying to get abbreviated month name in X-axis for DC.js line chart. I have formatted the month column and parsed it before sending it to dimension.Even after formatting the ticks in the line chart, I am getting "Dec" for all of them. Below is the code . Please help me to resolve it
var parseTime = d3.timeParse("%B %d, %Y");
var parseMonth = d3.timeFormat("%B");
canadaclimatProjects.forEach(function (d) {
var date = parseTime(d["year_mon"]);
d["year_mon"] = parseMonth(date);
});
var newMonth = ndx.dimension(function (d) { return d["year_mon"]; });
monthlyPrecipitationChart
.width(380)
.height(250)
.round(d3.timeMonth.round)
.xUnits(d3.timeMonths)
.x(d3.scaleTime().domain(newMonth))
.dimension(newMonth)
.group(precipitationByMonth)
.brushOn(false)
.valueAccessor(function (p) { return p.value.count > 0 ? p.value.total / p.value.count : 0; })
.elasticX(true)
.elasticY(true);
.xAxis().ticks(12).tickFormat(d3.timeFormat("%b"));
d3.scaleTime() won't work if you are passing in strings as the keys of your data. You need to pass in Date objects instead.
You've already handled printing the ticks with abbreviated months with
.xAxis().ticks(12).tickFormat(d3.timeFormat("%b"));
so it's redundant (and won't work) to format the dates on input.
Rarely is it a good idea to pass formatted data into a chart. Formatting usually happens after the chart is drawn.
Hard to say why you are getting the results you describe, without a complete runnable example.
I am making a bubble chart using dc.js , crossfilter.js but bubbles are not showing in the chart !!!! It is just showing x axis and y axis but the bubbles are disappeared.
I was trying make this bubble chart in click to see
here is my code :
var dateDim = ndx.dimension(function(d) {return d.Date;});
var minDate = dateDim.bottom(1)[0].Date;
var maxDate = dateDim.top(1)[0].Date;
console.log(minDate);
console.log(maxDate);
//var ageDim = ndx.dimension(function(d){return +d.Age;});
var daySum = dateDim.group().reduceSum(function(d){return 1;});
//print_filter("ageSum");
// var hits = dateDim.group().reduceSum(function(d) {return d.Age;});
var brush = d3.svg.brush();
suicideBubbleChart
.width(990).height(200)
.transitionDuration(1500)
.dimension(dateDim)
.group(daySum)
.colors(d3.scale.category10())
.x(d3.time.scale().domain([minDate,maxDate]))
.y(d3.time.scale().domain([minDate,maxDate]))
.r(d3.scale.linear().domain([0, 4000]))
.minRadiusWithLabel(15)
.yAxisLabel("Suicides")
.elasticY(true)
.yAxisPadding(100)
.elasticX(true)
.xAxisPadding(200)
.maxBubbleRelativeSize(0.07)
.renderHorizontalGridLines(true)
.renderVerticalGridLines(true)
.renderLabel(true)
.renderTitle(true);
Thank you.
I fixed enough to start getting stuff showing up on the chart.
There was a space before Date that caused that field name to come out wrong, and the date format was wrong, and I added a radiusValueAccessor.
var dateFormat = d3.time.format('%m/%d/%Y');
...
.r(d3.scale.linear().domain([0, 10]))
.radiusValueAccessor(function(d) {
return d.value;
})
http://jsfiddle.net/gordonwoodhull/wjeonreq/15/
Obviously it is still not the chart you want, but hopefully now that you have some stuff showing up on the screen, you can start to shape and debug it.
In particular, you will need a valueAccessor in order to place the bubbles in Y, and a Y scale.
It is one of the frustrating things about dc & d3 that if something doesn't work, then you just get an empty chart. The way I tracked this down, after dealing with the errors above, which showed up in the console, was
look at daySum.all() to make sure the data was okay (it was, after the date correction)
Inspect the svg element in the Elements tab of the Developer tools. The g.chart-body inside there has the actual content. I saw that the bubbles were there but had radius zero. Then I looked back at the stock example to see what radius setup must be missing.
I try to dynamically change the number of ticks on an axis via an input field
// updated by an input field
var nNumberOfTicks;
function updatenumberofticks(nValue) { nNumberOfTicks = nValue; }
// definition of the axis
var xAxis = d3.svg.axis()
.orient('bottom')
.ticks(nNumberOfTicks)
.scale(xScale);
but it doesn't work. See here: https://jsfiddle.net/stefanooo/cn2xo56w/3/.
This example works perfectly when changing xmin. What do I have to change to make it work for the number of ticks also?
You need to give the updated number of ticks to the axis component after changing it, e.g.
d3.select("#numberofticks").on("change", function() {
updatenumberofticks(+this.value);
vis.select('.xaxis').transition().call(xAxis.ticks(+this.value));
});
Complete example here.
I am new to D3. Would be grateful if someone answer my folowing doubts:
On clicking a radio button i am updating the line chart using following code
d3.selectAll(".line").attr("d", line);
However, this updates all the line charts present on page. How do I update line corresponding to this particular graph.
You must label each chart in some way, then use that in the selection.
Set an ID on each chart #chart-1, #chart-2, ..., #chart-n
The select either like this:
d3.selectAll("#chart-1 .line").attr("d", line);
or
d3.select("#chart-1").selectAll(".line").attr("d", line);
With the second one you can store the chart and use it later, it's more efficient then:
var chart1 = d3.select("chart-1");
// ...possibly other code
chart1.selectAll(".line").attr("d", line);
Let's say you have a selection of charts:
var charts = d3.selectAll('.line').data(data);
charts.enter().append('path').attr('class', 'line').attr('d', line);
To work with a specific chart, just filter your charts seletion:
var chart;
chart = charts.filter(function(d) { d.name === selectedGraph; });
// or
chart = charts.filter('#chart-' + selectedGraph)
Is there an easy way to align text labels between ticks?
Here is my time axis with labels above the ticks:
I would like to place these labels like here:
I ended up with one of the Lars Kotthoff's advices.
Every time when I call(axis) I also adjust text labels.
Here is simplified code:
function renderAxis() {
axisContainer
.transition().duration(300)
.call(axis) // draw the standart d3 axis
.call(adjustTextLabels); // adjusts text labels on the axis
}
function adjustTextLabels(selection) {
selection.selectAll('.major text')
.attr('transform', 'translate(' + daysToPixels(1) / 2 + ',0)');
}
// calculate the width of the days in the timeScale
function daysToPixels(days, timeScale) {
var d1 = new Date();
timeScale || (timeScale = Global.timeScale);
return timeScale(d3.time.day.offset(d1, days)) - timeScale(d1);
}
Update:
BTW, here is a calendar demo with I ended up: http://bl.ocks.org/oluckyman/6199145
There is no easy (i.e. built-in) way of doing this, but you can still achieve it. There are a few options. The most straightforward one is probably to use the tickFormat function to specify a format with a suitable number of spaces in front/after the numbers. This would need to be hand-tuned for each application though.
Alternatively, you could select the label elements after they have been drawn and add a suitable transform attribute that shifts them accordingly. Again, this would have to be hand-tuned.
Your third option is to have two different axes, one for the ticks and one for the labels. The idea is that the axis that provides the ticks has no labels and the other one no ticks. You would need to set the tick values appropriately, but at least you wouldn't have to guess the right offset.
You might want to consider using D3FC, which has a drop-in replacement for the D3 axis component that supports this feature.
Here's an example which substitutes the D3 axis d3.axisBottom, for the D3FC equivalent fc.axisBottom:
const axis = fc.axisBottom(linear)
.tickCenterLabel(true);
The tickCenterLabel centres the axis labels as requested.
Here's what the axis looks like with tickCenterLabel = false:
And here with the tickCenterLabel = true:
Full disclosure - I'm a maintainer and contributor to D3FC
You can do this by using axis.tickSize(major[[,minor],end]) and .tickSubdivide(). Your ticks are set to line up with the major ticks, but if you set the height of these ticks to 0, and set some height for minor ticks, and specify that there is one minor tick between each pair of major ticks, you will end up with tick labels between your ticks. Your code would look like this:
var myAxis = d3.svg.axis()
.ticks(15)
.tickSubdivide(1)
.tickSize(0, 6, 0);
Note that you need to explicitly set an end size. If you only provide two numbers, they will be interpreted as major and end and minor will default to 0.
Here's a fiddle.
I often do this by stacking multiple axes, each with a custom .tickFormat().
If I'm placing labels in between dates, I'll often do something like this:
#timeDaysAxisLabels = d3.svg.axis()
.scale(#timescale)
.orient('bottom')
.ticks(d3.time.hour.utc, 12) # I want ticks at noon, easiest to just get them ever 12 hours
.tickFormat((d) =>
# only draw labels at noon, between the date boundaries
if d.getUTCHours() == 12
# draw the label!
formatter = d3.time.format.utc('%a %d %b') # "Mon 12 Apr"
return formatter(d)
else
# not noon, don't draw anything
return null)
.tickSize(0)
.tickPadding(30)
I'll also create a separate axis with no labels at all, and a non-zero .tickSize() to actually draw ticks, but this block above positions date labels in the center of the "column".
Already a few good replies but just to add one more. Note the use of text-anchor.
Same idea: After your call, select the text, reposition.
.call(xAxis)
.selectAll(".tick text")
.style("text-anchor", "start")
.attr("x", axisTextAdjust)
svg.append("g")
.attr("class", "axis axis-years")
.attr("transform", "translate(0," + (height + 1) + ")")
.call(xAxis)
.selectAll("text")
.attr("x", "-1.8em")
.attr("y", ".00em")
.attr("transform", function (d) {
return "rotate(-90)"});