I have the following data and i want to plot them with jqplot on line-chart with 2 lines.
series:[Time Value1 Value2]
[13:51 22.875 9.275]
What I am looking for is a Chat with
XAxis:Time
L1:[Yaxis1:Value1]
L2:[Yaxis2:Value2].
I can fairly change data structure into [Time Value1] and [Time Value2] or any other kind
But It is important to plot them both in one chart together.
Could you please write the scratch of the code or refer me to a proper example ?
Thank you
It's actually very easy. You define an array of values for each data line:
var line1 = [[date1, val1], [date2, val2]];
var line2 = [[date1, val11], [date2, val12]];
var plot = $.jqplot('chart1', [line1, line2]);
If the time values are the same, you can do
var line1 = [val1_1, val1_2];
var line2 = [val2_1, val2_2];
var ticks = [time1, time2]
var plot = $.jqplot('chart1', [line1, line2], {
xaxis: { ticks: ticks }
});
The 'multiple ticks for the same date' for the date-axis can be solved by including the following code snippet:
xaxis: { label: "Whatever you name it", renderer: $.jqplot.DateAxisRenderer, min:dateVal[0], max:dateVal[dateVal.length-1], tickInterval: '1 day',
Please include min,max and tickInterval under 'xaxis:' and not under 'tickOptions:' . In my case i am having the date values in the array dateVal where the 0th element is the minimum value of date for the x-axis and the last element is the max date value. If you so wish you could hard-code the date values.
I hope this will be of help.
Related
I have a stackblitz here - https://stackblitz.com/edit/d3-one-y-axis?embed=1&file=src/app/bar-chart.ts&hideNavigation=1
I have a stacked bar chart with line chart on top.
The bar chart and line chart have two different data sets and I'm using a seond y-axis to plot the line chart data.
The line chart points are the totals for the two stacked charts in each months column.
Instead of having separate data and y-axis for the line chart is it possible to add up the data from the each months stacked bar and plot that on the graph using one y axis
It can be achieved in several ways. You can either redefine line.x, .y and .defined accessors using all three d, i, data arguments or you can map the data like this:
.data(
linedata.reduce(function(acc, current, index) {
let isFirstPair = index % 2 === 0;
let currentDate = that.y1(current.date)
let currentValue = that.y1(current.value)
if (isFirstPair) {
acc.push({ date: currentDate, value: currentValue });
} else {
acc[acc.length - 1].value += currentValue;
}
return acc;
}, [])
)
It will create a new object for every consequent pair in the source array. You may need to tweak the date or .x accessor.
Good Evening Everyone,
I'm trying to take the data from a database full of hour reports (name, timestamp, hours worked, etc.) and create a plot using dc.js to visualize the data. I would like the timestamp to be on the x-axis, the sum of hours for the particular timestamp on the y-axis, and a new bar graph for each unique name all on the same chart.
It appears based on my objectives that using crossfilter.js the timestamp should be my 'dimension' and then the sum of hours should be my 'group'.
Question 1, how would I then use the dimension and group to further split the data based on the person's name and then create a bar graph to add to my composite graph? I would like for the crossfilter.js functionality to remain intact so that if I add a date range tool or some other user controllable filter, everything updates accordingly.
Question 2, my timestamps are in MySQL datetime format: YYYY-mm-dd HH:MM:SS so how would I go about dropping precision? For instance, if I want to combine all entries from the same day into one entry (day precision) or combine all entries in one month into a single entry (month precision).
Thanks in advance!
---- Added on 2017/01/28 16:06
To further clarify, I'm referencing the Crossfilter & DC APIs alongside the DC NASDAQ and Composite examples. The Composite example has shown me how to place multiple line/bar charts on a single graph. On the composite chart I've created, each of the bar charts I've added a dimension based off of the timestamps in the data-set. Now I'm trying to figure out how to define the groups for each. I want each bar chart to represent the total time worked per timestamp.
For example, I have five people in my database, so I want there to be five bar charts within the single composite chart. Today all five submitted reports saying they worked 8 hours, so now all five bar charts should show a mark at 01/28/2017 on the x-axis and 8 hours on the y-axis.
var parseDate = d3.time.format('%Y-%m-%d %H:%M:%S').parse;
data.forEach(function(d) {
d.timestamp = parseDate(d.timestamp);
});
var ndx = crossfilter(data);
var writtenDimension = ndx.dimension(function(d) {
return d.timestamp;
});
var hoursSumGroup = writtenDimension.group().reduceSum(function(d) {
return d.time_total;
});
var minDate = parseDate('2017-01-01 00:00:00');
var maxDate = parseDate('2017-01-31 23:59:59');
var mybarChart = dc.compositeChart("#my_chart");
mybarChart
.width(window.innerWidth)
.height(480)
.x(d3.time.scale().domain([minDate,maxDate]))
.brushOn(false)
.clipPadding(10)
.yAxisLabel("This is the Y Axis!")
.compose([
dc.barChart(mybarChart)
.dimension(writtenDimension)
.colors('red')
.group(hoursSumGroup, "Top Line")
]);
So based on what I have right now and the example I've provided, in the compose section I should have 5 charts because there are 5 people (obviously this needs to be dynamic in the end) and each of those charts should only show the timestamp: total_time data for that person.
At this point I don't know how to further breakup the group hoursSumGroup based on each person and this is where my Question #1 comes in and I need help figuring out.
Question #2 above is that I want to make sure that the code is both dynamic (more people can be handled without code change), when minDate and maxDate are later tied to user input fields, the charts update automatically (I assume through adjusting the dimension variable in some way), and if I add a names filter that if I unselect names that the chart will update by removing the data for that person.
A Question #3 that I'm now realizing I'll want to figure out is how to get the person's name to show up in the pointer tooltip (the title) along with timestamp and total_time values.
There are a number of ways to go about this, but I think the easiest thing to do is to create a custom reduction which reduces each person into a sub-bin.
First off, addressing question #2, you'll want to set up your dimension based on the time interval you're interested in. For instance, if you're looking at days:
var writtenDimension = ndx.dimension(function(d) {
return d3.time.hour(d.timestamp);
});
chart.xUnits(d3.time.hours);
This will cause each timestamp to be rounded down to the nearest hour, and tell the chart to calculate the bar width accordingly.
Next, here's a custom reduction (from the FAQ) which will create an object for each reduced value, with values for each person's name:
var hoursSumGroup = writtenDimension.group().reduce(
function(p, v) { // add
p[v.name] = (p[v.name] || 0) + d.time_total;
return p;
},
function(p, v) { // remove
p[v.name] -= d.time_total;
return p;
},
function() { // init
return {};
});
I did not go with the series example I mentioned in the comments, because I think composite keys can be difficult to deal with. That's another option, and I'll expand my answer if that's necessary.
Next, we can feed the composite line charts with value accessors that can fetch the value by name.
Assume we have an array names.
compositeChart.shareTitle(false);
compositeChart.compose(
names.map(function(name) {
return dc.lineChart(compositeChart)
.dimension(writtenDimension)
.colors('red')
.group(hoursSumGroup)
.valueAccessor(function(kv) {
return kv.value[name];
})
.title(function(kv) {
return name + ' ' + kv.key + ': ' + kv.value;
});
}));
Again, it wouldn't make sense to use bar charts here, because they would obscure each other.
If you filter a name elsewhere, it will cause the line for the name to drop to zero. Having the line disappear entirely would probably not be so simple.
The above shareTitle(false) ensures that the child charts will draw their own titles; the title functions just add the current name to those titles (which would usually just be key:value).
My dataset is an array of json of the like :
var data = [ { company: "A", date_round_1: "21/05/2002", round_1: 5, date_round_2: "21/05/2004", round_2: 20 },
...
{ company: "Z", date_round_1: "16/01/2004", round_1: 10, date_round_2: "20/12/2006", round_2: 45 }]
and I wish to display both 'round_1' and 'round_2' time series as stacked line charts.
The base line would look like this :
var fundsChart = dc.lineChart("#fundsChart");
var ndx = crossfilter(data);
var all = ndx.groupAll();
var date_1 = ndx.dimension(function(d){
return d3.time.year(d.date_round_1);
})
fundsChart
.renderArea(true)
.renderHorizontalGridLines(true)
.width(400)
.height(360)
.dimension(date_1)
.group(date_1.group().reduceSum(function(d) { return +d.round_1 }))
.x(d3.time.scale().domain([new Date(2000, 0, 1), new Date(2015, 0, 1)]))
I have tried using the stack method to add the series but the problem resides in the fact that only a single dimension can be passed as argument of the lineChart.
Can you think of a turnaround to display both series while still using a dc chart?
Are you going to be filtering on this chart? If not, just create a different group on a date_2 dimension and use that in the stack. Should work.
If you are going to be filtering, I think you'll have to change your data model a bit. You'll want to switch to have 1 record per round, so in this case you'll have 2 records for every 1 record you have now. There should be 1 date property (the date for that round), an amount property (the contents of round_x in the current structure), and a 'round' property (which would be '1', or '2', for example).
Then you need to create a date dimension and multiple groups on that dimension. The group will have a reduceSum function that looks something like:
var round1Group = dateDim.group().reduceSum(function(d) {
return d.round === '1' ? d.amount : 0;
});
So, what happens here is that we have a group that will only aggregate values from round 1. You'll create similar groups for round 2, etc. Then stack these groups in the dc.js chart.
Hopefully that helps!
I have added a datetime X-axis to my rickshaw graph:
var x_axis = new Rickshaw.Graph.Axis.Time({
graph: graph,
timeFixture: new Rickshaw.Fixtures.Time(),
});
However, it doesn't generally give me the format I want. Can I give it a specifier so the datetimes are always in a specified format (i.e. something like d3.time.format(specifier) )?
Based on Lars' linked example I have done the following:
var format = function(d) {
d = new Date(d)
return d3.time.format("%c")(d)
}
var x_axis = new Rickshaw.Graph.Axis.X({
graph: graph,
tickFormat: format,
});
Which seems to work, so now I just have to find a way to make the spacing come out okay....
The formatter will only format the string, it will not determine the spacing.
In order to control spacing and formatting, you could write your own 'Fixture', e.g. take a look at https://github.com/shutterstock/rickshaw/blob/master/src/js/Rickshaw.Fixtures.Time.js for an example.
The fixture provides two things: the spacing (e.g. year, month, day, hour) and the formatting of each.
Create a similar fixture, space and format to your needs and set it on the x-axis:
var xAxis = new Rickshaw.Graph.Axis.Time( {
graph: graph,
//timeFixture: new Rickshaw.Fixtures.Time()
timeFixture: new MyOwnTimeFixture()
} );
try this one it will work
var xAxis = new Rickshaw.Graph.Axis.Time({
graph: graph,
tickFormat: function(x){
return new Date(x).toLocaleString();
},
ticks: 4
});
I have a long list of data for x-axis data when drawing a line chart (about 800 entries). The problem is it will not display correctly and overwrite each other. I am thinking a way to show (for example, every one hundred for a grid) and don't know how to do it. Please help me out.
Thanks.
You can specify an array of ticks to display on your chosen axis :
var xTicks = new Array(1,101,201,301,401,501,601,701,800);
--In your plot, add ticks option to your chosen axis :
axes: {
xaxis: {
ticks: xTicks --my ticks array
renderer: $.jqplot.CategoryAxisRenderer,
autoscale: false
}
}
It should do the trick.