Meteor.js with D3 - d3.js

I'm a newbie for Meteor.js but however I need to make some chart like http://nvd3.org/examples/pie.html. Bu I have no idea to render data on my html page.
Pie = new Meteor.Collection("pie");
if (Meteor.isClient) {
Template.chart.created = function(){ //not sure for template style.
_.defer(function () {
Deps.autorun(function () {
pp = Pie.find({}, {fields: {_id: 0}});
exampleData = _.toArray(pp);
console.log(exampleData);
//Regular pie chart example
nv.addGraph(function() {
var chart = nv.models.pieChart()
.x(function(d) { return d.label })
.y(function(d) { return d.value })
.showLabels(true);
d3.select("#chart svg")
.datum(exampleData)
.transition().duration(350)
.call(chart);
return chart;
});
//Donut chart example
nv.addGraph(function() {
var chart = nv.models.pieChart()
.x(function(d) { return d.label })
.y(function(d) { return d.value })
.showLabels(true) //Display pie labels
.labelThreshold(.05) //Configure the minimum slice size for labels to show up
.labelType("percent") //Configure what type of data to show in the label. Can be "key", "value" or "percent"
.donut(true) //Turn on Donut mode. Makes pie chart look tasty!
.donutRatio(0.35) //Configure how big you want the donut hole size to be.
;
d3.select("#chart2 svg")
.datum(exampleData)
.transition().duration(350)
.call(chart);
return chart;
});
});
});
}
}
if (Meteor.isServer) {
Meteor.startup(function () {
if(Pie.find().count() === 0) {
var data = [
{
"label": "One",
"value" : 29.765957771107
} ,
{
"label": "Two",
"value" : 0
} ,
{
"label": "Three",
"value" : 32.807804682612
} ,
{
"label": "Four",
"value" : 196.45946739256
} ,
{
"label": "Five",
"value" : 0.19434030906893
} ,
{
"label": "Six",
"value" : 98.079782601442
} ,
{
"label": "Seven",
"value" : 13.925743130903
} ,
{
"label": "Eight",
"value" : 5.1387322875705
}
];
for(var i=0; i < data.length; i++){
Pie.insert({
label: data[i].label,
value: data[i].value
});
}
}
});
}
d3.html
<head>
<meta charset="utf-8">
<title>d3</title>
</head>
<body>
{{> chart}}
</body>
<template name="chart">
<div width="500" height="500">
<svg id="chart"></svg>
<svg id="chart2"></svg>
</div>
</template>

As tested with Meteor both prior to Blaze and with Blaze: it is enough to start your Deps.autorun in the rendered callback of the template and just put your d3 drawing code there.
In Meteor prior to v.0.8.0, you would need to wrap the svg part into #constant region but once you use Blaze, it is not necessary.
An alternative is to draw everything once in rendered callback and then start observeChanges and keep your d3 view-model up to date.
I have a simple example here: https://github.com/Slava/d3-meteor-basic

Related

How to assign different colors to chart labels on graph interface in amChart 5?

I have a simple amChart5 chart.
I would like to change the colors of the text that displays on the axes and assign a different color to each of these elements.
What I have:
What I want:
The documentation explains that you can change the color but it applies to the whole axis, to all elements at the same time.
Do you know if there is a way to treat each element individually?
A nice solution is to use an adapter like so:
xAxis.get("renderer").labels.template.adapters.add("fill", (fill, target) => {
if (target.dataItem && target.dataItem.dataContext) {
let category = target.dataItem.dataContext.category;
if (category === "Category 1") {
return "#ff0000";
} else if (category === "Category 2") {
return "#00ff00";
} else {
return "#0000ff";
}
}
return fill;
});
Full code:
am5.ready(() => {
let root = am5.Root.new("chartdiv");
let chart = root.container.children.push(am5xy.XYChart.new(root, {}));
let legend = chart.children.push(am5.Legend.new(root, {
centerX: am5.p50,
x: am5.p50
}));
let data = [
{
"category": "Category 1",
"value1": 10,
"value2": 1
},
{
"category": "Category 2",
"value1": 20,
"value2": 7
},
{
"category": "Category 3",
"value1": 15,
"value2": 3
}
];
let xAxis = chart.xAxes.push(am5xy.CategoryAxis.new(root, {
categoryField: "category",
renderer: am5xy.AxisRendererX.new(root, {})
}));
xAxis.data.setAll(data);
// ==================================================
xAxis.get("renderer").labels.template.adapters.add("fill", (fill, target) => {
if (target.dataItem && target.dataItem.dataContext) {
let category = target.dataItem.dataContext.category;
if (category === "Category 1") {
return "#ff0000";
} else if (category === "Category 2") {
return "#00ff00";
} else {
return "#0000ff";
}
}
return fill;
});
// ==================================================
let yAxis = chart.yAxes.push(am5xy.ValueAxis.new(root, {
renderer: am5xy.AxisRendererY.new(root, {})
}));
function makeSeries(name, fieldName) {
let series = chart.series.push(am5xy.ColumnSeries.new(root, {
name: name,
xAxis: xAxis,
yAxis: yAxis,
categoryXField: "category",
valueYField: fieldName
}));
series.data.setAll(data);
legend.data.push(series);
}
makeSeries("Series 1", "value1");
makeSeries("Series 2", "value2");
});
#chartdiv {
width: 100%;
height: 350px;
}
<script src="https://cdn.amcharts.com/lib/5/index.js"></script>
<script src="https://cdn.amcharts.com/lib/5/xy.js"></script>
<div id="chartdiv"></div>

Donut3D.js 3d pie chart change data event not firing

I'm using Donut3D.js library (which is based on D3.js chart library) (http://bl.ocks.org/NPashaP/9994181).
I've created a javascript event listener to listen for changes in a select option Html combo box control. Users select an option from the combo box and based on the selected option, the data for the 3d pie chart is fetched from a SQL Server database and the chart is re-drawn. However, my chart is not rendering, although when I'm in Firebug debug mode, it is re-drawn. I'm using Firefox and Firebug for debugging. My Web app is using an MVC pattern and C# programming language. Following are the code snippets:
In Partial View1:
<select id=hucDdl></select>
In Partial View2:
<script>
$(document).ready(function(){
//Event listener when selection changes
$("#hucDdl").change(function () {
//Get huc value
var huc;
if($("#hucDdl").val() != null){
huc = $("#hucDdl").val();
});
//Call function
ChangeData();
});
function ChangeData(){
<blockquote>var huc = $("#hucDdl").val();
var arr = [];
var lulcData = null;
//get data from SQL Server
$.ajax({<br/></blockquote>
url: "/Home/GetBaseLulcJson/",
type: "GET",
data: {huccode: huc},
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function(result){
arr = result;
},
error: function(data){
}
})
lulcData = [
{ "label": "Cropland", "value": arr[0], "color": "#ffb3ba" },
{ "label": "Forest", "value": arr[1], "color": "#ffdfba" },
{ "label": "Pasture", "value": arr[2], "color": "#ffffba" },
{ "label": "Rangeland", "value": arr[3], "color": "#baffc9" },
{ "label": "Urban", "value": arr[4], "color": "#bae1ff" }
];
//Draw the 3d pie chart
Donut3D.draw("blulcpie", getData(), 90, 50, 90, 40, 30, 0);
function getData(){
<blockquote>return lulcData.map(function (d) {
return { label: d.label, value: +d.value, color: d.color };
});
}
});
</script>
The ChangeData() function is not firing on selection change.
Does anyone know how to get the chart to re-draw when data changes?
The data fetched from SQL Server are correct.
I'm just not sure what's causing the chart not to re-draw.
Solved this issue. I revised my codes as follows:
Index.cshmtl (main view):
<!--d3.js references-->
<script src="http://d3js.org/d3.v3.min.js" type="text/javascript"></script>
<script src="~/myscripts/donut3d.js" type="text/javascript"></script>
<div id="bLulc">
<label>Major Landuse</label>
#Html.Partial("~/Views/Shared/_BaseLanduse.cshtml")
</div>
Partial View1 (holds the select HTML control):
<select id = "hucDdl"></select>
Partial View2 (contains the 3d pie chart) "_BaseLanduse.cshtml":
<script type="text/javascript">
$(document).ready(function () {
//Set default array values for initial display on page load
var def_arr = [0.2, 80.3, 1.9, 16.9, 0.7];
var defData = [
{ "label": "Cropland", "value": def_arr[0], "color": "#ffb3ba" },
{ "label": "Forest", "value": def_arr[1], "color": "#ffdfba" },
{ "label": "Pasture", "value": def_arr[2], "color": "#ffffba" },
{ "label": "Rangeland", "value": def_arr[3], "color": "#baffc9" },
{ "label": "Urban", "value": def_arr[4], "color": "#bae1ff" }
];
//Define chart parameters
var margin = { top: 0, right: 20, bottom: 0, left: 20 }
var width = 180,
height = 230 - margin.bottom;
var svg = d3.select("#bLulc")
.append("svg")
.attr("width", width)
.attr("height", height);
svg.append("g")
.data([defData])
.attr("id", "blulcpie");
//Draw the chart
Donut3D.draw("blulcpie", defData, 90, 50, 90, 40, 30, 0);
//Define legend square size
var legendSpace = 4;
var rectSize = 8;
//Add legend
defData.forEach(function (d, i) {
svg.append("rect")
.attr("transform", "translate(0," + i * (rectSize + legendSpace) + ")")
.attr("class", "rect")
.attr("width", rectSize)
.attr("height", rectSize)
.attr("x", 50) //x-axis of rect
.attr("y", 130) //y-axis of rect
.style("stroke", "#000000")
.style("stroke-width", .25)
.style("fill", defData[i].color);
svg.append("text")
.attr("class", "legend")
.attr("x", rectSize + legendSpace)
.attr("y", (i * legendSpace) + (i * rectSize))
.attr("dx", 50) //x-axis of text
.attr("dy", 138) //y-axis of text
.style("font-size", "10px")
.text(defData[i].label);
});
//Event listener when huccode changes
$("#hucDdl").bind("mousedown mouseup", function () {
debugger;
//Get data from SQL Server via Controller
$.ajax({
url: "/Home/GetBaseLulcJson/",
type: "GET",
data: { huccode: $("#hucDdl").val() },
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function (result) {
arr = result;
//alert(arr);
},
error: function (data) {
//alert(data);
}
})
var currData = [
{ label: "Cropland", value: arr[0], color: "#ffb3ba" },
{ label: "Forest", value: arr[1], color: "#ffdfba" },
{ label: "Pasture", value: arr[2], color: "#ffffba" },
{ label: "Rangeland", value: arr[3], color: "#baffc9" },
{ label: "Urban", value: arr[4], color: "#bae1ff" }
];
Donut3D.transition("blulcpie", currData, 90, 40, 30, 0);
});
});
Controller:
[HttpGet]
public JsonResult GetBaseLulcJson(string huccode)
{
//Returns single row, selected columns
var lulcBase = (from f in db.FractionsLulcs
where f.HUCCODE == huccode
select new
{
f.Cropland,
f.Forest,
f.Pasture,
f.Range,
f.Urban
}).SingleOrDefault();
//Convert to percentage
double?[] lulc = new double?[5];
lulc[0] = Math.Round(Convert.ToDouble(lulcBase.Cropland) * 100, 1);
lulc[1] = Math.Round(Convert.ToDouble(lulcBase.Forest) * 100, 1);
lulc[2] = Math.Round(Convert.ToDouble(lulcBase.Pasture) * 100, 1);
lulc[3] = Math.Round(Convert.ToDouble(lulcBase.Range) * 100, 1);
lulc[4] = Math.Round(Convert.ToDouble(lulcBase.Urban) * 100, 1);
return Json(lulc, JsonRequestBehavior.AllowGet);
}

Map data for lineWithFocusChart time series

I am trying to create a timeseries using the nvd3 lineWithFocusChart model. My data is an array of objects like this:
[
{
"key": "red",
"values": [
{
"date": "2015-06-17T11:00:00.000Z",
"value": 17
},
...]
},
{
"key": "green",
"values": [
{
"date": "2015-06-17T11:00:00.000Z",
"value": 20
},
...]
},
]
I just want to map date to x and value to y, which looking at other examples is typically done like this:
nv.addGraph(function() {
var chart = nv.models.lineWithFocusChart()
.x(function(d) { return new Date(d.daterun)})
.y(function(d) { return d.value});
chart.brushExtent([50,70]);
chart.xAxis.tickFormat(d3.format(function(d) {
return d3.time.format('%x')(new Date(d));
}));
chart.x2Axis.tickFormat(d3.format(',f'));
chart.yAxis.tickFormat(d3.format(',.2f'));
chart.y2Axis.tickFormat(d3.format(',.2f'));
chart.useInteractiveGuideline(true);
d3.select('#chart svg')
.datum(data)
.call(chart);
nv.utils.windowResize(chart.update);
return chart;
});
But on the .x(function(d) { return new Date(d.date)}) I am getting TypeError: d is undefined.
How can I map my data correctly for this chart model?
I have created the following code from the parts you provided I do not receive the error that you refer to, my lines do not draw probably because I only have two points of data. See below:
<link href="libs/nv.d3.css" rel="stylesheet" type="text/css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.2/d3.min.js" charset="utf-8"></script>
<script src="libs/nv.d3.js"></script>
<script src="libs/stream_layers.js"></script>
<body>
<div id="chart" class='with-3d-shadow with-transitions'>
<svg></svg>
</div>
<script>
nv.addGraph(function() {
var chart = nv.models.lineWithFocusChart()
.x(function(d) { return new Date(d.date)})
.y(function(d) { return d.value});
chart.brushExtent([50,70]);
chart.xAxis.tickFormat(d3.format(function(d) {
return d3.time.format('%x')(new Date(d.date));
}));
chart.x2Axis.tickFormat(d3.format(',f'));
chart.yAxis.tickFormat(d3.format(',.2f'));
chart.y2Axis.tickFormat(d3.format(',.2f'));
chart.useInteractiveGuideline(true);
d3.select('#chart svg')
.datum(data())
.call(chart);
nv.utils.windowResize(chart.update);
return chart;
});
function data() {
return [
{
"key": "red",
"values": [
{
"date": "2015-06-17T11:00:00.000Z",
"value": 17
},
{
"date": "2015-06-17T11:00:00.000Z",
"value": 18
},
]
},
{
"key": "green",
"values": [
{
"date": "2015-06-17T11:00:00.000Z",
"value": 20
},
{
"date": "2015-06-17T11:00:00.000Z",
"value": 17
},
]
}
]
}
</script>
</body>
the only thing I found which was wrong is that you're referring to your date data point as "d.daterun" and in data as "date" which should be as "d.date" in code.
Hope this helps.

NVD3 Y axis order

I have the following line chart: http://jsfiddle.net/cp3fV/2/
var data = [
{
"days_to_expiry": 0,
"close": "7.1120000000"
},
{
"days_to_expiry": 1,
"close": "8.4580000000"
},
{
"days_to_expiry": 2,
"close": "7.2830000000"
},
{
"days_to_expiry": 3,
"close": "12.2820000000"
},
{
"days_to_expiry": 4,
"close": "7.1820000000"
}
]
nv.addGraph(function() {
var chart = nv.models.lineChart()
.margin({left: 100, right:50})
.useInteractiveGuideline(true)
.transitionDuration(350)
.showLegend(false)
.showYAxis(true)
.showXAxis(true)
//.forceY([0, 19])
.y(function (d) { return d.close })
.x(function (d) { return d.days_to_expiry })
;
console.log(data);
chart.xAxis
.axisLabel('Date')
.ticks(10);
chart.yAxis
.axisLabel('Close')
.tickFormat(d3.format('.03f'));
var testData = [{key:"Test", color: '#2ca02c', values: data}];
d3.select('#chart svg')
.datum(testData)
.call(chart);
nv.utils.windowResize(function() { chart.update() }); // Update on resize
return chart;
});
I just want to order the Y axis from minimum to maximum. It works fine if all the values are <10
I know I can use forceY(min, max) but I don't want to calculate the minimum every time(I'm planning to use AJAX to update the chart)
It works if you use the numbers as numbers and not as strings:
data.forEach(function(d) { d.close = +d.close; });
Complete example here.

d3.js csv to nvd3 (stacked area chart) format

I'm trying to convert my csv to the format needed by nvd3's stacked area chart: http://nvd3.org/ghpages/stackedArea.html
but got lost in the arrays conversion. Can someone help?
csv:
length,m1,m2,m3,m4
9,1,2,3,4
99,11,22,33,44
999,111,222,333,444
format needed by nvd3
var histcatexplong = [
{
"key" : "Consumer Discretionary" ,
"values" : [ [ 0000000000000 , 27.38478809681] , [ 0000000000000 , 27.371377218208] , [ 0000000000000 , 26.823411519395] } ,
{
"key" : "Consumer Staples" ,
"values" : [ [ 0000000000000 , 27.45458809681] , [ 0000000000000 , 27.444444444408] , [ 0000000000000 , 26.455555555395] } ,
so if the conversion is right, I should get:
var myall = [
{
"key" : "m3" ,
"values" : [ [ 9 , 3] , [ 99, 33] , [ 999, 333] } ,
{
"key" : "m1" ,
"values" : [ [ 9 , 1] , [ 99, 11] , [ 999, 111] } ,
My code for the conversion:
d3.csv("s1.csv", function (csv) {
var myall = [
{
"key" : "m3",
"values" : []
},
{
"key" : "m2",
"values" : []
}
];
v3 = csv.map(function(d) { return [ +d["length"], +d["m3"] ]; });
v2 = csv.map(function(d) { return [ +d["length"], +d["m2"] ]; });
d3.keys(csv).forEach(function(d) {
myall[0].values.push(v3);
myall[1].values.push(v2);
});
console.log(myall);
The problem is that myall didn't show up in the DOM (console output seems to be missing a top hierarchy:
[Object { key="m345", values=[249]}, Object { key="m2", values=[249]}]
For the nvd3 stacked area chart example, DOM copy/paste for the histcatexplong var:
*histcatexplong
[Object { key="Consumer Discretionary", values=[77]}, Object { key="Consumer Staples", values=[77]}, Object { key="Energy", values=[77]}, 7 more...]*
Thanks.
After some debugging, I fixed the issue. As a help to fellow learners, I post the code.
This is useful for people that need:
a. nvd3 stacked area chart(gives you the tooltips and other utilities for free i.e. no extra programming)
b. x-axis with values instead of dates
c. has csv data (flat hierarchy) in this format:
length,m1,m2
103.10,111,2222
137.91,0.36980639547531,99.6301936045247
113.30,0.176522506619594,99.8234774933804
159.59,0.244376214048499,99.7556237859515
code (modified from http://nvd3.org/ghpages/stackedArea.html):
<script>
<!DOCTYPE html>
<meta charset="utf-8">
<link href="../src/nv.d3.css" rel="stylesheet" type="text/css">
<style>
body {
overflow-y:scroll;
}
text {
font: 12px sans-serif;
}
#chart1, #chart2 {
height: 500px;
}
</style>
<body>
<div>
<svg id="chart1"></svg>
</div>
<script src="../lib/d3.v3.js"></script>
<script src="../nv.d3.js"></script>
<script src="../src/utils.js"></script>
<script src="../src/models/axis.js"></script>
<script src="../src/tooltip.js"></script>
<script src="../src/models/legend.js"></script>
<script src="../src/models/axis.js"></script>
<script src="../src/models/scatter.js"></script>
<script src="../src/models/stackedArea.js"></script>
<script src="../src/models/stackedAreaChart.js"></script>
<script>
var myall = [
{
"key" : "m1",
"values" : []
},
{
"key" : "m2",
"values" : []
}
];
d3.csv("s1.csv", function (error, csv) {
if (error) return console.log("there was an error loading the csv: " + error);
console.log("there are " + csv.length + " elements in my csv set");
csv.sort(function(a,b) {return a.length-b.length;});
var mmm = ["m1","m2"];
for (var i = 0; i < mmm.length; i++) {
myall[i].values = csv.map(function(d) { return [ +d["length"], +d[mmm[i]] ]; });
};
var colors = d3.scale.category20();
keyColor = function(d, i) {return colors(d.key)};
var chart;
nv.addGraph(function() {
chart = nv.models.stackedAreaChart()
.x(function(d) { return d[0] })
.y(function(d) { return d[1] })
.color(keyColor)
.clipEdge(true);
// chart.xAxis
// .tickFormat(function(d) { return d3.time.format('%x')(new Date(d)) });
chart.yAxis
.tickFormat(d3.format(',.2f'));
d3.select('#chart1')
.datum(myall)
.transition().duration(500).call(chart);
nv.utils.windowResize(chart.update);
chart.dispatch.on('stateChange', function(e) { nv.log('New State:', JSON.stringify(e)); });
return chart;
});
// end read csv
});

Resources