D3.js: Trying to build flat calendar - javascript

Newbie here.I am trying to build a horizontal calendar to indicate people on vacations. I have placed the mockup below with annotation of key feature, I'm trying to incorporate.
Legend Y - Indicates the person
Legend X - Indicates the Month and year.
Each cell is color coded based on holiday or vacation or weekend.
The calendar part (not including legend area) should be draggable.
I have got rough implementation going...I am able to get the first horizontal calendar,
Code: http://jsbin.com/xumabavo/1/edit
Is my approach correct?
how to stack each other?
How to enable dragging and render dates before and after the window?
Thanks for helping out.

Is my approach correct?
Yes. Mockup is crucial. Prototype as well. It looks to me that you have confidence, determination, and intelligence necessary for this project.
How to stack each other?
I gather you will get overall data as an array of individual data specific for particular person. You can use index of that array (index corresponds to a person) to shift all visual elements to the appropriate row - in other words, to stack the data. Callback functions can have two parameters d (data) and i (index), something like this:
.style( "background-color", function( d, i ) {
// d is datum being rendered
// i is datum's index in dataset
// return value based on logic
} )
How to enable dragging and render dates before and after the window?
It seems to me you would benefit from analyzing this small app: link

Related

Drawing plots interactively in a web app

I am looking for a library preferably in JavaScript, that will allow a user to draw a plot (simple one consisting of vertical and horizontal steps) like this one:
The idea is that when the user is done with the plot I can generate data points from the graph and process them.
I don't know where to start, I am looking to start learning to do this within a JS based framework (meteor) but I can't find a library that allows for something like this. The closest library I found is d3.js but I couldn't find any example that allows for this.
Would anyone be able to point out to me a sample example to start from? Would you know of a better suited library to accomplish what I am asking for?
Here is a relatively simple fiddle which accomplishes some of what you asked for, excluding axis (which are relatively easy and has plenty of examples). It uses D3 for all the drawing and mouse event handling. On click it simply executes svg.append("circle").attr("r", 5), and if it's not the first click (i.e. linking points) then it also will create a path element using the previous mouse click coordinates:
svg.insert("path", "circle").attr("d", function () {
return [
"M", prevClickLoc[0], prevClickLoc[1],
"L", prevClickLoc[0], y,
"L", x, y].join(" ");
})
Where x and y are the current mouse coordinates. Also has an export button that will output a list in the form of cx,cy,cx,cy,... :: d,d,d,d,.... On import, you could easily split this array into two using indexOf("::") or whatever you choose if you want to change the formatting. Then just exectue for (x in circles) {svg.append("circle").attr("cx", function...).attr("cy", function...);} and do something similar for paths for (y in paths) {svg.append("path").attr("d", function(){return paths[y];});}. It would be even easier if on export you made the cxcy array in the format cx;cy,cx;cy since then you could simply split the array at each comma and then split each index of the resulting array at the semicolon for a nice nested array.
Small update in this version, you can only place points if the current mouse x is greater than the previous x coordinate, and it also has the line d3.event.stopPropagation(); which prevents accidental highlighting of the page.

second d3.js triggered from first doesn't fully iterate over X axis

Folks -
I'm now trying to trigger a second chart based on which series in the first chart is clicked on.
Based on which is chosen, one of two data sets are sent to the function:
.on("mouseup", function(d) {return d.myCat == 0 ? updateData(yesXYZData) : updateData(nonXYZData)})
This part works, but I'm getting one big stack in the target div, not the iteration I am expecting.
function updateData(whichDataSet) {...
I've tried putting the updateData() function into the window.onload function, duping or reusing various elements (since the domain and range for the X axis are the same, I expect to reuse).
[Note- I have taken Lars Kothoff's advice regarding numbers in the data object. Also, I will create a better data structure later, using crossfilter.js and native d3.js data manipulation- for now I need a working prototype demonstrating functionality.]
here is the gist:
https://gist.github.com/RCL1/6906892
Thanks in advance!
-RL
line 242 of the gist. I needed to use a non-filtered version of the data to calculate x axis (totalAll.map).

D3 graphing selective portions of data set

I have a large time series data set I need to graph, and am trying to use D3 to do it. I plan to have my graph have the x-axis be time, and allow for movement of the graph in the x direction. I want to have the graph only load/display the points that exist in the current time range on the screen.
For example, if my dataset has times 1-100, but the graph starts out with times 1-10 shown, the graph should only graph points 1-10. Then the user may move to the right and see times 5-15 and the graph should update accordingly.
Can anyone explain to me how this might be done via d3? I am having a hard time bridging the understanding from an entire data set being loaded in at once and graphed immediately to selective graphing of subsets of the data.
I think you are looking for the selection.filter() function. For example you can have:
var allNodes = vis.selectAll("Nodes").data(data.nodes);
var validNodes = allNodes.filter(function(d){return (d.time>1 && d.time <10)});
//use normal graph functions on validNodes.
You can also apply filter directly on the array of nodes.

in d3js how can I filter data by clicking on stack bar

I'm trying to filter data by clicking on certain rect bar in a stacked bar. This stack bar is a two dimention graph, the horizontal index is years, and the vertical index different product revenues, I want to filter by certain product in certain year. means when I click on a rect bar of the whole graph, the data should get filtered by certain year and certain product.
my code is :
metrics.on("click", function(d,i,j){
d3.select(this)
.style("fill","lightcoral")
.style("stroke","red");
fdata =rawdata.filter(function(d){return (d[xvalue]==_seriesA[i])&&(d[yvalue]==_seriesB[j])});
});
but the weird thing is the value of j is always undefined, although if I attach a title to it :
metrics.append("title").text(
function(d,i,j) {
return i + ' - '+j ;
});
the value of j will get printed correctly, is there anything special about the 'on' click function? why I cannot get the value of j? any help will be appreciated....this is triving me crazy for the whole night...
According to the documentation, the second argument to .on() is a function that takes two arguments, not three. Similarly, it shouldn't work in your second example either.
I think you're getting confused about the distinction between the data and how it is rendered. The .on() function will get you the data. The scales you have created somewhere in your code take that data and map it to x and y coordinates in your graph (or you use the data directly without scales). In the .on() function, you use the data in exactly the same way you used it when you created the graph to start with. That is, the data item (d in your code) contains the data for the specific position that you're highlighting.

Interactive area chart using Protovis

This is quite a daunting project to a Protovis newcomer, but maybe you could help me split it into digestible chunks?
What I would like to build is an "interactive Area chart", as sketched here:
First of all, it's the data ...
I have data for provinces in Excel:
Province Year 10 100 1000 10000
A 1970 2 4 6 3
A 1971 3 6 8 5
B 1970 6 9 12 6
B 1971 4 8 11 8
.... ... . . . .
For each province and year, I would like to be able to draw an area chart:
vis.add(pv.Area)
.data(data.ProvinceA[1970])
.bottom(1)
.interpolate("basis")
.left(function(d) x(d.x))
.height(function(d) y(d.y))
.fillStyle("rgb(21,173,210)")
.anchor("top").add(pv.Line)
.lineWidth(3);
Then I would like to add 2 types of interactivity:
Selection of Province
Time slider
Together, the selection checkboxes and the time slider determine which areas are visible at any given time.
If, for example, Province A is selected and the year is 1984, only that area is displayed. If the time slider is now dragged, the corresponding years are now displayed for Province A. If another Province is checked, the areas are overlayed and both areas are redrawn when the time slider moves.
Protovis questions:
How do I format the data (province, year, x, y) for this application?
How do I achieve the binding of checkboxes to area?
How do I implement the time slider? Within Protovis or like an external component with listeners that trigger re-rendering of the graph?
Formatting data: The first step is to get it into JSON, using some external tool (I really like Google Refine for this, though it's a pretty big tool if this is all you need it for - try Mr. Data Converter for a quick and dirty option). These tools will probably give you data as a JSON object, like this:
`[{"Province":"A", "Year":"1970", "10":2, "100":4, "1000":6, "10000":3}, ...]`
Once you have the data available as JSON, you'll want to get it into shape for your vis. You're going to want to pass each pv.Area an array of values - from your description it looks like you want the [10, 100, 1000, 10000] values. Protovis has a lot of tools for manipulating data - see the pv.Nest operator. There are lots of ways you might approach this - I might do this:
data = pv.nest(data)
.key(function(x) {return x.Province})
.key(function(x) {return x.Year})
.rollup(function(v) {
return [v[0]['10'], v[0]['100'], v[0]['1000'], v[0]['10000']];
});
which gives you an object like:
{
A: {
1970: [2,4,6,3]
// ...
},
// ...
}
This sets you up for the interface elements. Keep the array of checked Provinces and the current year in global variables:
var currentProvinces = ['A', 'B', ...];
var currentYear = 1970;
and set up your area to reference those variables:
// a containing panel to help with layout and data
var panel = vis.add(pv.Panel)
.data(function() currentProvinces); // making this a function allows it to
// be re-evaluated later
// the area itself
var area = panel.add(pv.Area)
.data(function(province) data[province][currentYear]);
// plus more area settings as needed
Now use some other library - I'm partial to jQuery, with jQuery UI for the slider - to create your interface elements. The onchange function for each element just needs to set the corresponding global variable and call vis.render() (assuming your root panel is called vis). This should be pretty simple - see here for a Protovis example using jQuery UI to make a time slider very similar to what you have in mind.
I think that you are trying to make that pair of charts:
http://mbostock.github.io/protovis/ex/zoom.html

Categories

Resources