I need to display only time labels on xAxis. I'm using Highcharts and don't fully understand how to do it. On xAxis there should be time labels in format like 21:00. I do not need dates, only time is needed. In addition, the difference between two labels should be 00:30 (half an hour) or 01:30 and it should be zoomable. My PHP script writes some value in database every half an hour and I need to display it on a graph. Sorry for my poor English, I'm Russian. Any help would be appreciated :)
In xAxis of your chart you need to provide tickinterval and dateTimeLabelFormats. Following code gives the tick interval of 1.5 hours. You can change that to any number of hours you want by replacing 1.5 in tickInterval: 1.5 * 3600 * 1000,
xAxis: {
type: 'datetime',
//Sets tickInterval to 24 * 3600 * 1000 if display is by day
tickInterval: 1.5 * 3600 * 1000,
dateTimeLabelFormats : {
day: '%H:%M'
}
}
Related
I am building a timeline chart - that will change its date scale at the top when the brush becomes small to the scope of 1 day -- but when it hits this mode -- the labels overlap and it looks messy until you get to a 12 hour spread.
What is the best way of cleaning this functionality up so it doesn't overlap. I thought about having 1 line that shows date -- and another line under it that shows the hours at that level.
https://jsfiddle.net/aLh9d51t/
var tFormat = '%Y-%m';
var tTick = 'timeMonth';
if (days < 40) {
tFormat = '%Y-%m-%d';
tTick = 'timeWeek';
}
if (days <= 7) {
tFormat = '%Y-%m-%d';
tTick = 'timeDay';
}
if (days <= 1) {
tFormat = '%Y-%m-%d %H%p';
tTick = 'timeHour';
}
First, you can hide redundant parts of date when possible: show years, months, days only if there are more than one visible. So you definitely do not need years and months when you show hours and minutes.
Just look how default d3 axis handles this (e.g. https://bl.ocks.org/mbostock/1166403).
Second, considering your chart has fixed width, you can fine-tune different formats for different zoom levels (you already do this in your code snippet).
Take a look at this example: http://bl.ocks.org/oluckyman/6199145
It has similar logic as in your code snippet:
https://gist.github.com/oluckyman/6199145#file-axisdaysview-js-L33-L58
But the decision which format to choose depends on chart width:
https://gist.github.com/oluckyman/6199145#file-axisdaysview-js-L72-L75
And third, if you restricted to long labels for some reason, you can rotate them to 30°-45°
Also this could be useful: https://bl.ocks.org/mbostock/4149176
I am trying to display a multi-line chart of temperatures for 5 days on an hourly basis. I was able to create the both axes but I'm having trouble displaying the lines.
I have a JSON like so where x is a date object for every 3 hours and y is the temperature.
var dataset = [
//day 1
[
{x: Date 2015-09-07T21:00:00.000Z, y: 30.75},
{x: Date 2015-09-08T00:00:00.000Z, y: 29.32},
{x: Date 2015-09-08T03:00:00.000Z, y: 25.67},
{x: Date 2015-09-08T06:00:00.000Z, y: 22.7}
],
//day 2
[
{x: Date 2015-09-08T09:00:00.000Z, y: 23.69},
{x: Date 2015-09-08T12:00:00.000Z, y: 24.18},
{x: Date 2015-09-08T15:00:00.000Z, y: 26.69},
{x: Date 2015-09-08T18:00:00.000Z, y: 22.36},
{x: Date 2015-09-08T21:00:00.000Z, y: 23.91},
{x: Date 2015-09-09T00:00:00.000Z, y: 22.98}
],
//day 3
Array[8],
//day 4
Array[8],
//day 5
Array[8]
]
When initialize the graph like below, instead of a multi-line graph, I get one line containing all 4 days.
var chart = lineChart("graph")
.x(d3.time.scale().domain([
dataset[0][0].x, dataset[3][7].x
]))
.y(d3.scale.linear().domain([min, max]));
dataset.forEach(function (series) {
chart.addSeries(series);
});
chart.render();
If I change the domain to,
dataset[4][0].x, dataset[4][7].x
it only draws the line for that day.
The strange thing is that when I "Inspect Elemet" via the browser, I can see that all 5 paths have been drawn out but they just dont show up on the UI. I think this has something to do with the way I'm setting the domain but I'm not sure what.
How do I set the domain so that d3js plots each days array on a 24-hour x-axis?
If I understand correctly, you want to have the x-axis from midnight to midnight, as if everything is happening "on one day", like so:
NOTE: something is a bit weird with the timestamps in the source. I have no idea how dt and dt_text are related. Please adjust my examples accordingly...
How can you get that?
The problem in your code is indeed related to the domain. How?
If you set the domain to be from the very first timestamp to the last, like:
.domain([
dataset[0][0].x, dataset[3][7].x
])
then the chart will span over 4 days (by the way: these hard-coded indices are not very robust coding...)
So the chart will then obviously plot over all days, it has no way of knowing that you only want hourly time-stamps.
If you, on the other hand, just use the most recent day as domain:
.domain([
dataset[3][0].x, dataset[3][7].x
]))
It will plot just that, i.e. the last day. The other lines will be plotted too (what you see in the inspector), but the will be hidden away on the left (as you clip the stuff).
So: the problem is, that the x-coordinates are different, as they occur on different dates. There is plenty of ways to work around that (I personally always use moment.js for dates), but to show the effect, here's a quick hack to achieve the graph above:
-> JSFiddle
What did I do? I added a new helper function to calculate the x time-stamp:
function gDate2(date) {
var now = new Date();
var hours = (new Date(date * 1000)).getHours();
var date = now.getDate();
var month = now.getMonth();
var d = new Date(2015, month, date, hours, 0, 0, 0);
return d;
}
Yes, it's not pretty. Personally, I like moment.js to calculate dates and stuff. The important part is that I return all dates as if it's all today (or any other arbitrary day). Then I extract the hour of the timestamp of the according data point and add that (as in the note: maybe you need minutes, seconds too?)
If you are going to use it, please make sure you have timezones, day-light saving etc. under control! I hate dates...)
And again: I am not sure about dt and dt_text. Make sure you got that right!
I hope this helps.
I am using following example:
http://dojo.telerik.com/AkIwo
When I select the time I get values like 12:00 / 12:30 / 13:00 - so half hour gaps.
Does anyone know how to define the "gaps", hence I want to change it to 12:00 / 12:15 / 12:30 / 12:45 and so on?
Cheers
Here is the answer (I was looking at the wrong doc, sorry)
$("#dateTimePicker").kendoDateTimePicker({
interval: 15
});
Simply set the interval property:
$(document).ready(function () {
// create DateTimePicker from input HTML element
$("#datetimepicker").kendoDateTimePicker({
value:new Date(),
interval: 15
});
});
Here's the Dojo
You can use interval for time picker:
$("#timepicker").kendoTimePicker({
interval: 10 //the interval you want to have between two time gap
});
I'm working with a D3 time scale. My input data is in seconds, and it's duration data rather than dates - so 10 seconds, 30 seconds etc.
I want to create an axis that lets me do the following:
Display ticks formatted in minutes and seconds: like "0m 30s", "1m 00s", etc. This formatting on its own is fairly straightforward, but not when I also need to...
Display ticks at intervals that look neat when formatted in minutes. If I just use D3's default tick formatting then I get ticks at intervals that make sense in minutes, but not seconds.
Here is my code:
var values = [100,200,300....]; // values in seconds
var formatCount = d3.format(",.0f"),
formatTime = d3.time.format("%Mm %Ss"),
formatMinutes = function(d) {
var t = new Date(2012, 0, 1, 0, 0, d);
t.setSeconds(t.getSeconds() + d);
return formatTime(t);
};
var x = d3.scale.linear()
.domain([0, d3.max(values)])
.range([0, width]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.tickFormat(formatMinutes);
This gives me nicely-formatted ticks at irregular intervals: "16m 40s", "33m 20s" etc. How can I generate ticks at "10m 00s", "20m 00s", etc?
The obvious answer would be to transform the values array into minutes, use a linear scale and write a formatter to handle it, but I'd prefer to use a time scale if possible
Here is a JSFiddle to demonstrate the problem: http://jsfiddle.net/83Xmf/
Normally when making a time scale, you would use d3.time.scale(), rather than a linear scale.
Your case is a little odd in that you are using abstract durations of time, and not specific points in time for your data. Unfortunately it seems that d3's built in time functionality is not well-suited to this case. There are a couple of options I can think of for workarounds:
Option 1: Use a linear scale with manual .tickValues()
Rather than formatting your ticks using a Date object. You could simply break down your data value (which is in seconds) into hours, minutes, and seconds. Something like this:
formatMinutes = function(d) {
var hours = Math.floor(d / 3600),
minutes = Math.floor((d - (hours * 3600)) / 60),
seconds = d - (minutes * 60);
var output = seconds + 's';
if (minutes) {
output = minutes + 'm ' + output;
}
if (hours) {
output = hours + 'h ' + output;
}
return output;
};
Basically, this takes the total number of seconds, creates an hour for every 3600 seconds, creates a minute for each remaining 60 seconds, and finally gives back the remaining seconds. Then it outputs a string representation, for example: 17s or 12m 42s or 4h 8m 22s.
Then when you make your axis, you can use the .tickValues() method to assign a range from zero to your data's max value, going by steps of 600, since there are 600 seconds in 10 minutes. That would look like this:
var x = d3.scale.linear()
.domain([0, d3.max(values)])
.range([0, width]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.tickFormat(formatMinutes)
.tickValues(d3.range(0, d3.max(values), 600));
Here's a JSFiddle of the output.
Option 2: Use a time scale with a fixed duration for .ticks()
Time scales let you specify directly that you'd like ticks every 10 minutes. You do that simply by passing a d3 duration and a multiplier to the .ticks() method of your axis. Like this:
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(d3.time.minute, 10)
In order to do this, you must first set up your time scale. For the domain of your scale, you can use a range of millisecond values, since d3 will turn these into Date objects. In this case, since your data is in seconds, we can simply multiply by 1000 to get milliseconds. In this case we'll round up the max value to the nearest millisecond, since it must be an integer to make a valid date:
var x = d3.time.scale()
.domain([0, Math.ceil(d3.max(values) * 1000)])
.range([0, width]);
Finally, you can pass your format in directly to the axis, using .tickFormat():
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(d3.time.minute, 10)
.tickFormat(d3.time.format('%Mm %Ss'));
However, at this point I need to point something out because, as I mentioned, the built-in time functions are not well-suited to dealing with abstract durations. I'm going to change the .tickFormat to show the hours as well:
.tickFormat(d3.time.format('%Hh %Mm %Ss'));
Have a look at the JSFiddle of what the result would be...
Depending on where you are in the world, you'll get a different value for the hours place. I'm on the East coast of the US, so my hours place says 19. Where is that coming from? Shouldn't it be zero?
Well, unfortunately, when we made the domain of the scale go from 0 to the number of milliseconds of the largest data value, it created regular Date objects, using those values for the millisecond input. This means that they represent the number of milliseconds since midnight UTC time on January 1, 1970. Here in the Eastern time zone of the US, that means it was 19:00:00 on December 31, 1969. That's where the 19 comes from, or whatever other value you get.
If you know that all of your data will be less than 1 hour, then perhaps you can just ignore this. If you need to use an hours place, you can work around this by forcing d3 to use UTC time to format the axis using d3.time.format.utc():
.tickFormat(d3.time.format.utc('%Hh %Mm %Ss'))
Here's the JSFiddle updated to use UTC.
Now you can see that the hour is 0 as expected.
Of course, if any of your data is ever longer than 24 hours, this method won't work at all, and you'll have to resort to doing the axis manually as in Option 1.
Hopefully this helps to at least get you started, it's a tricky problem though, and there doesn't seem to be an elegant solution built into the library for handling this. Perhaps it would make for a good feature request on d3's git repo. I'd love to hear if #mbostock has any suggestions on how to handle abstract durations of time in d3 without having to be tied to Date objects, which require references to absolute points in time.
Having the current scale level for the time scale from d3.event.scale (e.g. 0.5 or 1.5), is there any rule of how to convert it to human readable form, like - day, week, month or year?
UPDATE:
Here is a draft of what I'm working on: http://cdpn.io/gzfyj. I'm basically seeking for a way to get time boundaries after zooming or panning and the zoom factor in above mentioned identifiers.
After zooming,
var width = x.domain();
var dur = width[1] - width[0];
will return the width of the scale in milliseconds. Then this duration can be converted to any form you like.
This is an working example where I have used moment.js to humanize the duration at the bottom of the graph: http://codepen.io/musically_ut/pen/DJqtw
var ext = x.domain();
var duration = moment.duration(ext[1] - ext[0]).humanize();
chart
.select("text.duration")
.text(duration);