Custom D3 `tickValue` on x axis -- horizontal bar chart - javascript

I am trying to create custom tick values on X axis.
Chart is generated from data.csv file. There are 144 data points. Each data value represent 10 minutes cycle, so first tick should appear on 6th tick representing 1 hour.
If I use .domain([new Date('2014-03-08T12:00:00'), new Date('2014-03-9T00:00:00')]) for example, I will get X axis right, but my chart would be gone.
I can't use tickValues([]) in this case either.
What I should see on X axis is something like this 00:00 AM...(6 tick values)...1:00 AM...(6 tick values)...2:00 AM etc. Or it could be 00:00 AM...(12 tick values)...2:00 AM...(12 tick values)...3:00 AM etc. Just to be able to customize it.
Not sure if this is even possible. I tried following this simple example http://bl.ocks.org/phoebebright/3059392, but again, I get X axis right, but my chart is gone.
This would be the code: https://plnkr.co/edit/kc4E43Bgo4bNMB9hKX2j?p=preview
Thank you in advance!

Since your data doesn't contain actual date values, this is my solution:
You want to show one tick out of 6, since each tick represents 10 minutes and you want to show only the "hourly" tick. So, define the tick values using your x scale domain:
.tickValues(d3.range(x.domain()[0], x.domain()[1]).filter(function(d) {
return d % 6 === 0;
}))
And then, format the ticks to add a :00 to each one:
.tickFormat(function(d) {
return d/6 + ":00";
});
Here is your updated plunker: https://plnkr.co/edit/8EOGt8UvYq1J8qpIdArN?p=preview
Edit: As discussed in the comments, here is the solution with "am" and "pm": https://plnkr.co/edit/OvtVlgT4I6Y19hgoMKIK?p=preview

Related

Why does my d3 chart's x-axis include the first of every month as a tick even though I set the tick interval to every 7 days?

I am new to d3 but I have set the tick interval for my x-axis to every 7 days using d3.timeDay.every(7). However when my graph is created, I also see a tick mark added for the first of every month. For example, my graph shows ticks at 10/1, 10/8, 10/15, 10/22, 10/29, and 11/1, even though 11/1 is not 7 days after 10/29. If I expand this range to include multiple months, I see a tick at the first of every month.
I have included my code for this axis below. What might be causing the first of each month to be displayed as a tick?
const xScale = d3.scaleTime().range([0, innerWidth]);
const tickAmount = d3.timeDay.every(7);
chart.append("g")
.classed('x-axis', true)
.attr("transform", "translate(0," + innerHeight + ")")
.call(d3.axisBottom(xScale)
.ticks(tickAmount)
.tickSize(-innerHeight)
.tickFormat(d3.timeFormat('%m/%d/%y')));
Try const tickAmount = d3.timeWeek.every(1); instead:
Note that for some intervals, the resulting dates may not be uniformly-spaced; d3.timeDay’s parent interval is d3.timeMonth, and thus the interval number resets at the start of each month. If step is not valid, returns null. If step is one, returns this interval. from the d3 docs
You can also use .tickFormat(function(d, i) { return d; }) to filter out given ticks from display if you like (e.g. exclude first tick: return i>0 ? d : ''), though this is more hacky.
Found a better way to do this from d3 issue tracker:
d3.axisBottom(x)
.ticks(d3.timeDay.filter(d=>d3.timeDay.count(0, d) % N === 0))
.tickFormat(d3.timeFormat('%m/%d/%y'))
.tickSizeOuter(0)
This will give you consistent ticks every N-th day without the months repeating. That a tick exists does not mean a point exists at that date in your dataset, but they are scaled correctly over the date range.
Here's a demo: https://beta.observablehq.com/#thmsdnnr/d3-ticks-every-7-or-10-days

Highcharts Y-Axis Limits

I am having problems controlling the Y-Axis range of a highcharts graph. It seems like highcharts likes nice round numbers. When my data passes or is close to certain thresholds, the Y-Axis range can expand a lot which effectively compresses all the plot points downward.
Here is a jsfiddle that illustrates the problem I am having:
https://jsfiddle.net/shannonwrege/z8h5eork
The relevant code for this post is this:
chart.yAxis[0].setExtremes(0, max, true, false);
Keep in mind that I don't know what the data will look like in advance, so I must dynamically modify the Y-Axis range. Right now I am using the setExtremes because of other suggestions I've read on stackoverflow.
The maximum y-value of the data in the first two charts is 99. You'll notice that the y-axis is set at 150 in the first chart where the range is automatically calculated and 100 in the second chart where I specifically set the extreme values. The look of the 2nd chart is what I want. So it seems like setExtremes(0,99,true,false) should do the trick, but it actually doesn't.
In the 3rd chart I changed the data so that the maximum y-value of the data is 101, and I called setExtremes(0,101,true,false). You'll note that the y-axis is now back to 150.
Ideally I want the scale of the graph to be capped on the maximum value to limit the about of extra white space. I want to see all of the data, but I don't necessarily care about the y-axis displaying a maximum band that is greater than the max data value. In this case, I would be happy with the y-axis displaying 100 on the axis and some points over but still visible.
Does anyone know how to make this work?
I ended up using the endOnTick parameter to solve this problem. Adding the following line to the yAxis configuration parameters did exactly what I wanted:
endOnTick: false,
Here's the updated Fiddle showing the results.
https://jsfiddle.net/shannonwrege/z8h5eork/3/
All of the charts look pretty good in my opinion (even the one where the yAxis range was auto calculated).
You will need to read the data and then round up to set the idealMax
var chart,
idealMax = 0; // init the max value
// Read the data to find the highest value
for (i=0;i < (options.series[0].data).length; i++ ){
if (options.series[0].data[i][1] > idealMax) {
idealMax = options.series[0].data[i][1];
}
}
// Round the max to the nearest 10
idealMax = Math.round(idealMax / 10) * 10;
options.yAxis.tickPixelInterval = idealMax/10;
Highcharts.chart('container1', options);
chart = $('#container1').highcharts();
chart.yAxis[0].setExtremes(0, idealMax, true, false);
Updated Fiddle

D3.js year scale shows different data for users in Europe and North America

During the development of a website showing data for various indicators using D3.js, I experience a strange bug which I am unable to explain.
How to recreate the issue
Please visit the page at http://green-horizons.eu/indicator/scientific-publications-bioeconomy
Below the two text boxes there is a map with four buttons above it, please click on "Line Chart".
The map will be replaced by a line chart, showing a green line for Belgium's data and a red line for EU/ERA average values.
Now, please focus on the x axis which shows the years.
The x axis should cover the year range 1990-2013. This is true for all tests I and my colleagues did when in Europe (tested countries are Belgium, Estonia and Germany), see following image.
However, for anyone in the USA (and possibly Canada), the x axis shows a range of 1989-2012, see screenshot below (please note, the red line is missing due to only been added as a new feature recently).
Internally, the data comes from uploaded CSV files which are parsed into JSON and then used in D3.js. For the date scale, all year values are expanded to make a full date by using sth like
dateValue = year + '-01-01';
The javascript object containing the data also shows the correct years for all users (even in the US) but the display is off by one year.
How is this possible? I thought about time zones but I am not working with times, just dates.
I even tried to set the date to first of June instead of January to be sure but still the same behaviour.
Can anyone point me into a direction what to look for, I am stuck and out of ideas of how to pinpoint the source of the error.
Update regarding Mark's comment about the function
// Determine year range.
var yearTicks = [];
for (var y = obj.chartYMin; y <= obj.chartYMax; y++) {
yearTicks.push(new Date(y + "-01-01"));
}
// Set x scale function
var x = d3.time.scale()
.domain([new Date((obj.chartYMin - 1) + "-01-01"),
d3.time.day.offset(new Date((obj.chartYMax + 1) + "-01-01"), 1)])
.rangeRound([0, obj.width]);
// Create x axis
var xAxis = d3.svg.axis().scale(x)
.tickSize(-obj.height)
.tickSubdivide(true)
.tickValues(yearTicks)
.tickFormat(d3.time.format("%Y"));
// Update x axis in graph.
d3.select("#scoreboard-" + obj.chartType + "-canvas .x.axis").call(xAxis);
obj.chartYMin and obj.chartYMax are the minimum and maximum year values in the data provided, yearTicks is an array of all years present in data.

Why my d3 line chart only has two ticks on x axis?

My data is something like this:
[
{"months": ["2012.10","2012.11"], "score": 0.1048387096775},
{"months": ["2012.11","2013.1" ], "score": 0.1048387096775},
{"months":["2013.1","2013.2"],"score":0.45362903225749995},
{"months":["2013.2","2013.3"],"score":0.4912023460409091},
...
]
The x axis shows the months in the form of 2012.10 & 2012.11; the y axis shows the score accordingly. However, the x axis only has two ticks and the line chart turns into a weird shape.
Here is my code: http://plnkr.co/edit/uX8ctTEJy5lDs7LWY0Pq?p=preview
The problem is that you are using an ordinal scale. Ordinal scales are a map between the domain values to range values. I think that you may want to use an actual date (the end of the first month, for instance) and set the label to have both values. Take a look at the avg.axis.tickFormat documentation.

Nvd3 multibarcharts - display gaps in the data on the xAxis

I just started using nvd3 a short while ago and am now facing a big problem for me with multibar charts:
My xAxis data has gaps in between, e.g. [1,2,3,4,9,24,120].
I want these gaps to be displayed in the graph, but nvd3 just displays all bars next to each other, so, that the distance between the bars with the x value 2 and 3 is the same as between those with 9 and 24.
Is there any way to change this, so that you can see all the gaps in the data?
The code I used is just the same as nvd3s example code.
Thank you very much.
Sure there is. You will fill in 0 for all the missing values. For each y that will correspond to a missing value you will set x = 0. That's all you need to do (it's not as simple as it sounds since there can be cases with series which have no data and so on, but this is the main trick).

Categories

Resources