how to remove gridlines for subticks for log scale - d3.js

I have made a graph with log scale for which there are grid lines in the background. The grid lines are drawn for the sub-ticks also which i want to remove. can anyone know how to do it. I have tried it using linear scale also but it wasn't looking proper on the log graph. Please suggest some tricks. Thank you.
Here is the link to image of the graph:
http://snag.gy/24j4i.jpg
Below is my code to generate grid lines
function make_x_axis1() {
return d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(12)
}
function make_y_axis1() {
return d3.svg.axis()
.scale(y)
.orient("left")
.ticks(8)
}
svg1.append("g")
.attr("class", "grid")
.attr("transform", "translate(0," + height + ")")
.call(make_x_axis1()
.tickSize(-height, 0, 0)
.tickFormat("")
);
svg1.append("g")
.attr("class", "grid")
.call(make_y_axis1()
.tickSize(-width,0, 0)
.tickFormat("")
);

I think what you are looking for is the .tickSubdivide setting on your axis. There are a bunch of examples at http://bl.ocks.org/GerHobbelt/3605035. This seems to be the relevant one that you are looking for:
svg.append("g")
.attr("class", "x minor endticks classical log_x")
.attr("transform", "translate(0," + axis_y + ")")
.call(d3.svg.axis().scale(log_x).tickSubdivide(example_subdiv_A(log_x))
.tickSize(12, function(d, i) {
return (2 * d.subindex == d.modulus ? 8 :
((5 * d.subindex == d.modulus) && (d.modulus >= 10) ? 6 :
((d.subindex % 2 == 0) && (d.modulus > 10) ? 5 :
(d.modulus > 10 ? 2 : 4))));
}, -10))
.call(descr("classical logarithmic, with output-dependent # of subticks, emphasis on the 2nd and other even (but only when we have 10+ subticks!) and .5 subdiv, and longer start/end ticks"));
Here he varies not only the number of subticks but also their size. If you don't want the subticks at all, you can set tickSubdivide to 0 to remove them. If you want them just as ticks on the axis, you'll need to use .tickSize and do a little math to set the tick mark size for major tick marks separately from minor tick marks.

I ran into this problem today and found a solution. I created a function to remove those gridlines manually. The gridlines which you want to remove are the one that does not have the text value.
function removeNoNameTicks(logAxisSelector) {
var targetAxis = d3.select('g.x.axis');
var gTicks = targetAxis.selectAll('.tick');
if (gTicks.length > 0 && gTicks[0]) {
gTicks[0].forEach(function (item, index) {
// find the text if the text content is ""
var textElement = d3.select(item).select('text');
if (textElement.html() == '') {
item.remove();
}
});
}
}

Related

D3JS: unable to set only 5 ticks in x Axis

I've been unable to set only 5 ticks on my x Axis, by default it set 10 ticks, multiples of 5, I tried to use ´.ticks(5)´ but it's not working for me. If if visualize the chart on mobile, 10 ticks becomes almost unreadable. But as I mentioned ´.ticks(5)´ it's not working
this is the snippet which draws the x axis:
var xAxis = svg.append("g")
.style("font-size", textSetter())
.attr("class", "xAxis", "axis")
.attr("transform", "translate(" + 0 + "," + heightTwo + ")")
.call(d3.axisBottom(xScale).ticks(5)
.tickPadding(5).tickFormat(d => d + "%"))
How can I solve this? Thanks
You could set all the text in the axis to a particular class and then hide the ticks based on the number for example.
//Create the xAxis and assign x-axisticks class to the tick text
var xAxis = svg.append("g")
.style("font-size", textSetter())
.attr("class", "xAxis", "axis")
.attr("transform", "translate(" + 0 + "," + heightTwo + ")")
.call(d3.axisBottom(xScale)
.selectAll('text')
.attr('class', 'x-axisticks');
//remove the ticks which based on the multiples
var xticks = d3.selectAll('.x-axisticks');
xticks.attr('class', function (d, i) {
i = i + 1;
if (i % 5 !== 0) d3.select(this).remove();
});
Hope this helps. A more specific use-case answer would probably require some more code to be posted from your end so that I can tailor an answer, but this should work.

make a circle progress bar, but animate arc.endAngle (angle >180 degree) stops working in d3.js

I am running D3.js to draw a progress bar in circle shape, which you will see the demo on jsfiddle , the progress bar has a transition animation.
The main code is
var width = 960,
height = 500,
twoPi = 2 * Math.PI,
progress = 0,
total = 1308573, // must be hard-coded if server doesn't report Content-Length
formatPercent = d3.format(".0%");
var arc = d3.svg.arc()
.startAngle(0)
.innerRadius(0)
.outerRadius(240);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var meter = svg.append("g")
.attr("class", "progress-meter");
meter.append("path")
.attr("class", "background")
.attr("d", arc.endAngle(twoPi));
var foreground = meter.append("path")
.attr("class", "foreground");
foreground.attr("d", arc.endAngle(twoPi * 0))
foreground.transition().duration(1500).attr("d", arc.endAngle( twoPi * 2/3 ));
var text = meter.append("text")
.attr("text-anchor", "middle")
.attr("dy", ".35em");
to make the progress bar move, we only need to change to the arc.endAngle(), which is on the line.
foreground.transition().duration(1500).attr("d", arc.endAngle( twoPi * 2/3 ));
if the angle is less than 180, ( endangle < twoPi*1/2), then the animation works fine, but when the angle is larger than 180, so means endangle >= twoPi*1/2. then the animation would not show, and if you look at the console, you will find many errors on d3.js
Error: Problem parsing d="M1.1633760361312584e-14,-190A190,190 0 1.481481481481482e-7,1 -0.000022772330200401806,-189.9999883969182L0,0Z" meeting.html:1
2
Error: Problem parsing d="M1.1633760361312584e-14,-190A190,190 0 2.56e-7,1 -0.00003935058659476369,-189.99997994987467L0,0Z"
so what is the exact problem for this, how to solve it
It doesn't work because you can't use the standard transition for radial paths. By default, it simply interpolates the numbers without knowing what they represent, so in your case, you end up with some really small numbers (e.g. 1.1633760361312584e-14) which Javascript represents in exponential notation which is not valid for SVG paths.
The solution is to use a custom tween function that knows how to interpolate arcs:
function arcTween() {
var i = d3.interpolate(0, twoPi * 2/3);
return function(t) {
return arc.endAngle(i(t))();
};
}
Complete example here. You may also be interested in this example, which shows how to do it with data bound to the paths.

Don't show negative sign d3 axis labels

I have a scale in which I don't want the negative signs to appear before the numbers - how can this be done in the d3 formatter? The scale is built as follows:
var formater = d3.format("0");
self.x = d3.scale.linear().domain([self.xmin, self.xmax]).range([0, self.settings.width])
self.axis = d3.svg.axis()
.scale(self.x)
.orient("bottom")
.tickFormat(formater);
self.axisLabels = self.svg.append("g")
.attr("class", "axis")
.attr("id", "axis")
.call(self.axis)
I see an option to add a "+" sign but not remove a "-" sign https://github.com/mbostock/d3/wiki/Formatting#wiki-d3_format
Also, is it possible to remove one label? I'm labeling from -5 to 5 on the scale, and don't want the negative signs to appear, and I don't want to label 0. Thanks.
You are using a formatter already and you do not need to rely on D3 to remove the '-' sign, you can do it yourself:
var formatter = d3.format("0");
// ...
self.axis = d3.svg.axis()
.scale(self.x)
.orient("bottom")
.tickFormat(function (d) {
if (d === 0) return ''; // No label for '0'
else if (d < 0) d = -d; // No nagative labels
return formatter(d);
});

simple multi line chart with D3

http://jsfiddle.net/ytvka/4/
I know this one has been asked before but I've not been able to use those examples to figure out what I'm doing wrong.
I want to create a simple 6 point, 3 series chart with data that looks like:
data = [
{"key":"D78","date":"2013-09-23T17:26:21.258Z","value":1.25},
{"key":"D78","date":"2013-09-23T17:28:21.258Z","value":2.25},
{"key":"R71","date":"2013-09-23T17:26:21.258Z","value":2.45},
{"key":"R71","date":"2013-09-23T17:28:21.258Z","value":2.85},
{"key":"X44","date":"2013-09-23T17:26:21.258Z","value":3.87},
{"key":"X44","date":"2013-09-23T17:28:21.258Z","value":3.87}
]
Nothing exciting there. What I'd ideally like to do is make a 3-series line chart out of this data.
svg = d3.select(selector).append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom).append("g")
x = d3.time.scale().range([ 0, width ])
y = d3.scale.linear().range([ height, 0 ])
format = d3.time.format("%Y-%m-%dT%H:%M:%S.%LZ")
valueLine = d3.svg.line().interpolate("basis")
.x((d) ->
console.log format.parse(d.date)
x(format.parse(d.date))
)
.y((d) ->
console.log d.value
y d.value
)
svg.append("path").attr("class", "line")
.attr "d", valueLine(u.where(data, key: "X44"))
Which generates SVG: <path class="line" d="M137998238125800,-287L137998250125800,-287"></path>
This code just pulls out one of the series using lodash. Problem is: nothing on the screen. It runs through and grabs the value but there's no lines. I'm finding that existing examples are either complex and not well explained (http://bl.ocks.org/mbostock/3884955) or missing key parts (http://www.d3noob.org/2013/01/adding-more-than-one-line-to-graph-in.html).
What's wrong with my code?
How can I add in the other series (R71, D78)?
Is there a good tutorial of this out there that has complete code and walks through all the steps?
Your first point is at (137998238125800,-287) pixel coordinate, which is far away from the visible screen area. You don't use the selectAll/enter pattern which is at the core of D3. So you should start with this fundamental tutorial, then probably the code example you mention will make more sense:
var city = svg.selectAll(".city")
.data(cities)
.enter().append("g")
.attr("class", "city");
city.append("path")
.attr("class", "line")
.attr("d", function(d) { return line(d.values); })
.style("stroke", function(d) { return color(d.name); });

Custom quantized ticks on axis

I'm creating a line-chart in d3js, which draws a graph of your performance over time. This means my data is a certain score at a certain point in time. Example:
2011-01-01: 75
2012-01-01: 83
2013-01-01: 50
Now I don't want to display the score as integer values on my Y-axis, but I'd like to map the integer values into useful words. Example:
a score between 50 and 70 means you've scored Excellent
a score between 25 and 50 means you've scored Very Good
etc.
What's the best way for doing this?
The implementation of my axis is as follows:
var y = d3.scale.linear().range([settings.height, 0]);
var yAxis = d3.svg.axis()
.scale(y)
.ticks(5)
.orient("left");
y.domain(d3.extent(data, function(d) { return d.score; }));
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("x", (settings.width - 10 ))
.attr("dy", ".71em")
.style("text-anchor", "end")
.text(settings.labels.y);
You can define your own tickFormat. For example:
function scoreFormat(d) {
if (d <= 70 && d > 50) {
return "Good";
} else if (d <= 50 && d > 25) {
return "Bad";
}
return "Ugly";
}
var yAxis = d3.svg.axis()
.scale(y)
.ticks(5)
.orient("left")
.tickFormat(function(d) { return scoreFormat(d); });
Check out d3.scale.quantize, which takes a domain similar to a linear scale but breaks it to discrete range values in even chunks. If even sized chunks won't work for you, d3.scale.threshold is a similar idea except you can define your own mapping between subsets of the domain and the discrete range values.

Resources