I've been able to use the great tutorial for brush/zoom:
https://bl.ocks.org/mbostock/34f08d5e11952a80609169b7917d4172
I'm using the following scales and axis variables:
var x = d3.scaleTime().range([0, width]);
var x2 = d3.scaleTime().range([0, width]);
var xAxis = d3.axisBottom(x).ticks(d3.timeDay).tickFormat(d3.timeFormat("%x"));
var xAxis2 = d3.axisBottom(x2).ticks(10).tickFormat(d3.timeFormat("%x"));
Looks OK when zoomed in:
However, it gets extremely packed when zooming out:
How can I set the max number of tick marks, but limit the most granular tick to a single day?
Related
I have a chart as shown below
where the radius of the pie chart on the chart is am trying to do it as shown below
<PieChartMarkers
totalSites={totalSites}
key={i}
keymarket={name}
pieData={pieData}
x={projection(coordinates)[0]}
y={projection(coordinates)[1]}
**radius={this.getMarketRadius(totalCase)}**
mouseOverHandler={this.showTooltip}
mouseOutHandler={this.hideTooltip}
/>
getMarketRadius = (totalCase) => {
let radius = null;
// let data=d3.scaleLinear([10,130]).range([0,960]);
let callback= d3.scaleLinear()
.range([0, totalCase])
.domain([10, 130])
radius = totalCase / 650 + 10;
console.log(radius)
return radius;
};
currently i am getting the radius radius = totalCase / 650 + 10; which is working fine but suggestion is to use d3.scaleLinear to get the radius of the on chart when trying to use i am getting the value as 1313316 using the below code snippet
//totalCase is the variable value coming from API
let callback= d3.scaleLinear()
.range([0, totalCase])
.domain([10, 130]
please help me understand how to get the radius using d3.scaleLinear to draw the pie chart on the map
First of all, you should not use a linear scale to get these radii: we encode the data as the area of the circles, not as their radii. That said, you should use d3.scaleSqrt. Also, set the 0 range for the 0 domain, because there should be no circle if there are no cases.
So, your function would be something like this:
getMarketRadius = totalCase => {
return d3.scaleLinear().range([0, totalCase]).domain([0, 130])(totalCase);
};
A better option is just setting the scale outside the function, and using it directly for setting the radius.
myScale = d3.scaleLinear()
.range([0, totalCase])
.domain([0, 130]);
radius={this.myScale(totalCase)}
I am trying to build a d3js timeline chart with axis grid lines vertically indicating the month region.
https://www.cssscript.com/demo/simple-scrollable-timeline-chart-with-d3-js-d3-timeline/
^ something like this featured some code - which I think is v3
var xAxis = d3.svg.axis().scale(x).orient('bottom').tickSize(-height);
svg.append('g').attr('class', 'x axis').attr('transform', 'translate(0,' + height + ')').call(xAxis);
my current implementation has failed.
https://jsfiddle.net/g89kuoe1/4/
these are the v4 methods to create axis -- but it needs to be repeated on the chart to formulate the grid lines.
var xAxis = d3.axisBottom(xRange).tickFormat(function(d){ return d.x;});
var yAxis = d3.axisLeft(yRange);
or should a new clip path be made to contain these lines - and add them as lines - with x1 values that hit each month?
https://jsfiddle.net/c8gdfxob/
** SOLVED -- had to use minExtent and maxExtent -- and force the scale of the ticks to be a month
this creates non-moving vertical grid lines - but I am unsure how to adapt it to the codebase so they morph with the scrub
it maps the timeline months -- but doesn't flow with the morph..
var scale = d3
.scaleTime()
.range([0, w])
.domain([minExtent, maxExtent]);
// Gridline
var gridlines = d3.axisTop()
.tickFormat("")
.ticks(d3.timeMonth)
.tickSize(-mainHeight)
.scale(scale);
main.selectAll(".grid").remove()
main.append("g")
.attr("class", "grid")
.call(gridlines);
I am using d3 v4 for ploting the graph. And currently the tick text on the x-axis is coming below the axis. and I want that text on above the axis.
//Set the Xaxis scale Range
let x = scaleLinear().rangeRound([0, width]);
let x_axis = axisBottom(x);
x.domain(extent(graphData, function (d) {
return d.weeks;
}));
g.append("g").attr("transform", "translate(0," + height + ")").call(axisBottom(x).ticks(5)).attr("transform", "translate(0, 120)");
so can you help me how to put the tick text above the x-axis.
If you want the ticks on top of the axis, you should use axisTop, instead of axisBottom.
The names are pretty easy to understand and the API is very clear:
d3.axisTop(scale): In this orientation, ticks are drawn above the horizontal domain path.
d3.axisBottom(scale): In this orientation, ticks are drawn below
the horizontal domain path. (emphases mine)
Here is a demo, the first axis uses axisTop, and the second one, below, uses axisBottom:
var svg = d3.select("svg");
var x = d3.scaleLinear().range([20, 280]);
var xAxisTop = d3.axisTop(x)(svg.append("g").attr("transform", "translate(0,50)"))
var xAxisBottom = d3.axisBottom(x)(svg.append("g").attr("transform", "translate(0,100)"))
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg></svg>
How to make a logarithmic datetime scale in D3?
a simple time scale is like this:
d3.time.scale()
.domain([new Date(2014, 0, 1), new Date()])
.range([0, 500])
and a simple log scale is like:
d3.scale.log()
.domain([new Date(2014, 0, 1), new Date()])
.rangeRound([0, 500])
.base(10)
Tried to chain their syntax in a various ways with no effect.
Chart will position users by last login date. Range will be about one year. If we space data linearly, most users will collide during last days/hours. With logarithm we can zoom last hours.
Solution could be by interactive zoom or several charts. But goal here is to make single static chart with nonlinear overview of year.
One alternative could be to convert datetime to "days from now", a number. It would work for data. But then I wouldn't know how to label axis ticks like "01-01-2014"...
Something like the below seems to fool d3js into thinking it has a real scale object. It should make a good starting point:
var xt = d3.scaleUtc()
.domain([start, now])
.range([1, width])
var xp = d3.scalePow()
.exponent(2)
.domain([1, width])
.range([0, width])
// Fool d3js into thinking that it is looking at a scale object.
function x_copy() {
var x = function(t) { return xp(xt(t)) }
x.domain = xt.domain
x.range = xp.range
x.copy = x_copy
x.tickFormat = xt.tickFormat
x.ticks = xt.ticks
return x
}
x = x_copy()
var xAxis = d3.axisBottom(x)
Create two scales and use one after the other. First use the time scale and than the log or pow scale.
var parseDate = d3.time.format("%Y-%m-%d").parse;
var x = d3.time.scale()
.range([0,width]);
var xLog = d3.scale.pow().exponent(4)
.domain([1,width])
.range([0,width]);
than I'm using .forEach to get the linear points:
x.domain(d3.extent(data, function(d) { return parseDate(d.start); }));
data.forEach(function(d) {
d.start = x(parseDate(d.start));
});
when I'm drawing the objects I add the log scale:
.attr('cx', function (d) { return xLog(d.start)})
I usually place my axis ticks on the svg using this:
d3.svg.axis().scale(xScale(width)).ticks(4)
Is it possible to get these tick values and their svg coordinates so I can use a custom axis outside the svg using d3.svg.axis() ?
Yes, xScale.ticks(4) should give you the actual tick points as values, and you can pipe those back through your xScale to the the X position. You can also just pull the tick points back from the generated elements after you apply the axis to an actual element:
var svg = d3.select("svg");
var scale = d3.scale.linear()
.range([20, 280])
.domain([0, 100])
var axis = d3.svg.axis().scale(scale).orient("bottom").ticks(9);
// grab the "scale" used by the axis, call .ticks()
// passing the value we have for .ticks()
console.log("all the points", axis.scale().ticks(axis.ticks()[0]));
// note, we actually select 11 points not 9, "closest guess"
// paint the axis and then find its ticks
svg.call(axis).selectAll(".tick").each(function(data) {
var tick = d3.select(this);
// pull the transform data out of the tick
var transform = d3.transform(tick.attr("transform")).translate;
// passed in "data" is the value of the tick, transform[0] holds the X value
console.log("each tick", data, transform);
});
jsbin
In d3 v4 I ended up just parsing the rendered x values from the tick nodes
function parseX(transformText) {
let m = transformText.match(/translate\(([0-9\.]*)/);
let x = m[1];
if (x) {
return parseFloat(x);
}
}