Piechart not being rendered when values supplied through d3.json - json

I am trying to read the values as specified in a JSON and based on those values creating a Piechart in d3.json. But on supplying values manually, the piechart is fully functional! The JSON file is present in the same directory as the .html file. Moreover, the var dataset is being populated with the desired values, which is verified by logging the dataset in the console. And I am not getting any error in the Chrome Browser.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Sentiments Score</title>
<script type="text/javascript" src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<div id="chart"></div>
<script type="text/javascript">
var dataset = [
{ "label": 'Neutral'},
{ "label": 'Positive'},
{ "label": 'Negative' }
];
d3.json("senti_analysis.json", function(data){
for (var i =0; i<dataset.length;i++)
{
if (dataset[i].label == 'Neutral')
{
dataset[i].count = +data.key.senti.neu;
}
else if (dataset[i].label == 'Positive') {
dataset[i].count = +data.key.senti.pos;
}
else
{
dataset[i].count = +data.key.senti.neg;
}
}
});
/*
var dataset = [{ label: 'Neutral', count: 0.45 },
{ label: 'Positive', count: 0.45 },
{ label: 'Negative', count: 0.10 }
];*/
console.log(dataset);
var w = 360;
var h = 360;
var r = Math.min(w, h) / 2;
var color = d3.scaleOrdinal(d3.schemeCategory20b);
var svg = d3.select('#chart')
.append('svg')
.attr('width', w)
.attr('height', h)
.append('g')
.attr('transform', 'translate(' + (w / 2) + ',' + (h / 2) + ')');
var arc = d3.arc()
.innerRadius(0)
.outerRadius(r);
var pie = d3.pie()
.value(function(d) { return d.count; })
.sort(null);
var path = svg.selectAll('path')
.data(pie(dataset))
.enter()
.append('path')
.attr('d', arc)
.attr('fill', function(d, i) {
return color(d.data.label);
});
</script>
</body>
The json file I am trying to read is as below:
{
"key": {
"senti": {
"neg": 0.10,
"neu": 0.45,
"pos": 0.45,
"compound": 0.784
},
"post": "I am excited to do Sentiment Analysis. I live in Tempe
and I love learning!"
}
}

Related

simplest way to update data in VegaEmbed

I made a small graph to show some data from a bluetooth device.
I used a sample I found for VegaEmbed, it was all very easy.
But the sample uses a timer to get data, so even if there is no data the dataset will be changed. What is the simples way to update data inside VegaEmbed from another part of the website ?
I cannot call res.view.change('table', changeSet).run(); from outside VegaEmbded..
Here is snappshot of the code :
(the function handleDataChanged is called when there is bluetooth data.)
function handleDataChanged(event) {
var value = event.target.value;
value = value.buffer ? value : new DataView(value);
let result = {};
let index = 1;
datapointx = value.getInt16(index, /*littleEndian=*/false);
console.log('X: ' + value.getInt16(index, /*littleEndian=*/false));
index += 2;
datapointy = value.getInt16(index, /*littleEndian=*/true);
console.log('Y: ' + value.getInt16(index, /*littleEndian=*/false));
index += 2;
datapointz = value.getInt16(index, /*littleEndian=*/true);
console.log('Z: ' + value.getInt16(index, /*littleEndian=*/false));
index += 2;
}
</script>
<script>
document.querySelector('button').addEventListener('click', function() {
onButtonClick();
});
</script>
<script type="text/javascript">
var vlSpec = {
$schema: 'https://vega.github.io/schema/vega-lite/v3.json',
data: {name: 'table'},
width: 400,
mark: 'line',
encoding: {
x: {field: 'x', type: 'quantitative', scale: {zero: false}},
y: {field: 'y', type: 'quantitative'},
color: {field: 'category', type: 'nominal'}
}
};
vegaEmbed('#chart', vlSpec).then(function(res) {
/**
* Generates a new tuple with random walk.
*/
function newGenerator() {
var counter = -1;
var previousY = [5, 5, 5];
return function() {
counter++;
var newVals = previousY.map(function(v, c)
{
console.log('c = ' + c);
var yval = 0;
if (c == 0)
yval = datapointx;
if (c == 1)
yval = datapointy;
if (c == 2)
yval = datapointz;
return {
x: counter,
// y: v + Math.round(Math.random() * 10 - c * 3),
y: yval,
category: c
};
});
previousY = newVals.map(function(v) {
return v.y;
});
return newVals;
};
}
var valueGenerator = newGenerator();
var minimumX = -100;
window.setInterval(function() {
minimumX++;
var changeSet = vega
.changeset()
.insert(valueGenerator())
.remove(function(t) {
return t.x < minimumX;
});
res.view.change('table', changeSet).run();
}, 100);
});
</script>
The simplest way to update data in an existing vega-lite chart is to use a streaming data model. There is an example in the Vega-Lite documentation here: https://vega.github.io/vega-lite/tutorials/streaming.html

D3 - Updating Choropleth csv to change mapping of colours

Hi I'm new to D3 and am having trouble updating my map through buttons that trigger a function to load a new csv. I looked at similar posts which mentioned that I would only need to update the section which fills the map with colours, and have tried to adapt this but clicking on my button doesn't affect the map.
Here is my code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>D3: Setting path fills dynamically to generate a choropleth</title>
<h1>Relation between Managers and Tertiary Education </h1>
<div id="option1">
<input type="button"value="Education"onclick="viewEducation()" />
</div>
<div id="option2">
<input type="button"value="Managers"onclick="viewManagers()" />
</div>
<script type="text/javascript" src="d3.js"></script>
<style type="text/css">
/* No style rules here yet */
</style>
</head>
<body>
<script type="text/javascript">
//Width and height
var w = 1000;
var h = 600;
var path = d3.geoPath()
.projection(d3.geoMercator()
.center([151,-33.5])
.scale(17000)
.translate([w/2,h/2]));
//Define quantize scale to sort data values into buckets of color
var color = d3.scaleQuantize()
.range(["rgb(237,248,233)","rgb(200,235,198)", "rgb(186,228,179)","rgb(146,208,140)", "rgb(116,196,118)", "rgb(88,178,100)", "rgb(49,163,84)", "rgb(20,130,60)", "rgb(0,109,44)"])
.domain([6274, 39796]);
//Colors derived from ColorBrewer, by Cynthia Brewer, and included in
//https://github.com/d3/d3-scale-chromatic
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
//Load in agriculture data
d3.csv("ManagerPercentage.csv", function(d) { d.value = parseFloat(d.value); parseFloat(d.value1); return d; }, function(data) {
//Set input domain for color scale
color.domain([
d3.min(data, function(d) { return d.value; }),
d3.max(data, function(d) { return d.value; })
]);
//Load in GeoJSON data
d3.json("australia_adm2.json", function(json) {
//Merge the ag. data and GeoJSON
//Loop through once for each ag. data value
for (var i = 0; i < data.length; i++) {
//Grab state name
var dataState = data[i].state;
//Grab data value, and convert from string to float
var dataValue = parseFloat(data[i].value);
//Find the corresponding state inside the GeoJSON
for (var j = 0; j < json.features.length; j++) {
var jsonState = json.features[j].properties.sa4_name11;
if (dataState == jsonState) {
//Copy the data value into the JSON
json.features[j].properties.value = dataValue;
//Stop looking through the JSON
break;
}
}
}
//Bind data and create one path per GeoJSON feature
svg.selectAll("path")
.data(json.features)
.enter()
.append("path")
.attr("d", path)
.style("fill", function(d) {
//Get data value
var value = d.properties.value;
if (value) {
//If value exists…
return color(value);
} else {
//If value is undefined…
return "#ccc";
}
});
});
});
function viewEducation () {
d3.select("option1")
d3.csv("EducationPercentage.csv", function(data) {
svg.selectAll("path")
.style("fill", function(d) {
var value = d.properties.value;
if (value) {
return color(value);
} else {
return "#ccc";
}
});
});
}
function viewManagers () {
d3.select("option2")
d3.csv("ManagerPercentage.csv", function(data) {
svg.selectAll("path")
.style("fill", function(d) {
var value = d.properties.value;
if (value) {
return color(value);
} else {
return "#ccc";
}
});
});
});
}
</script>
</body>
</html>

d3.tree get min & max value

I want to get the min and max value of the "size" attributes(the json structure for tree includes three attributes: name, size and children)
But I cannot get the right value. Though in the json file, the max value is 100, the min value is 5, the result I get is 94 and 100. And the most strange thing is that when I change the maximum size "100" to "99", the max and min value changes to 99 and 11. What is the problem?
here is the html file:
<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
var margin = {top: 20, right: 120, bottom: 20, left: 120}, width = 1500 - margin.right - margin.left, height = 500 - margin.top - margin.bottom;
var i = 0, duration = 750, root;
var tree = d3.layout.tree() .size([height, width]) .value(function(d) { return d.size;});
var svg = d3.select("body").append("svg")
.attr("width", width + margin.right + margin.left)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
d3.json("./parse_tree.json", function(error, parse_tree) {
root = parse_tree;
root.x0 = height / 2;
root.y0 = 0;
update(root);
});
function update(source1) {
var originalConsole = console;
var nodes = tree.nodes(root).reverse(),
links = tree.links(nodes);
var node = svg.selectAll("g.node")
.data(nodes, function(d) { return d.id || (d.id = ++i); });
var t_max = d3.max(nodes, function(d) { return d.size;})
var t_min = d3.min(nodes, function(d) { return d.size;});
originalConsole.log(t_max);
originalConsole.log(t_min);
}
</script>
Here is the json file:
{
"name":"para",
"size":"11",
"children":[
{
"name":"top",
"size":"32",
"children":[
{"name":"S",
"size":"13",
"children": [
{"name":"NP",
"size":"5",
"children":[
{"name":"PRP",
"size":"89",
"children":[{"name":"You","size":"88"}]
}
]
},
{"name":"VP",
"size":"89",
"children": [
{"name":"VBP",
"size":"15",
"children":[{"name":"are", "size":"38"}]
},
{"name":"NP",
"size":"83",
"children": [
{"name":"DT",
"size":"29",
"children":[{"name":"a", "size":"53"}]
},
{"name":"NN",
"size":"50",
"children":[{"name":"boy", "size":"99"}]
}
]
}
]
},
{"name":".",
"size":"94",
"children":[{"name":".", "size": "67"}]
}
]
}
]
}
]
}
The size in the JSON object is a string, thus things turn out "not quite like expected".
So, to fix it, you have to change type to int, which is "luckily" pretty direct in JS:
var t_max = d3.max(nodes, function(d) {
return +d.size;
})
var t_min = d3.min(nodes, function(d) {
return +d.size;
});
... or somewhere else in the script.
Oh, and by the way, try this:
console.log(d3.extent(nodes, function(d) { return +d.size;})); // [5, 99]

How to integrate a dynamic graph in a webpage?

I am getting dynamically generated data from my Raspberry PI in .csv format and I want to make a webpage for my institute to analyze the waveform of the output . The main feature of this graph is that the graph should auto-update according to the modified data. How should I go about making this?
I am assuming that the solution you are looking for must work in HTML 5 and JavaScript where there is NO server side processing. The raspberry pi posts a file to the server.
We are using morris charts which is JavaScript library
http://morrisjs.github.io/morris.js/
Morris uses a json format
1: read the csv file
2: convert the csv data to a json object
3: initialise the chart
try this example csv data
"elapsed","value",b
"Oct-12",24,2
"Oct-13",34,22
"Oct-14",33,7
"Oct-15",22,6
"Oct-16",28,17
"Oct-17",60,15
"Oct-18",60,17
"Oct-19",70,7
"Oct-20",67,18
"Oct-21",86,18
"Oct-22",86,18
$(document).ready(function() {
$.ajax({
url: "linechartdata.csv",
success: function(data) {
processData(data)
}
});
});
function processData(data) {
var record_num = 3; // or however many elements there are in each row
var dataLines = data.split(/\r\n|\n/);
var entries = dataLines[0].split(',');
var records = [];
var headers = entries.splice(0, record_num);
console.log(dataLines.length)
for (var i = 1; i < dataLines.length; i++) {
var obj = dataLines[i].split(',');
if (obj.length == headers.length) {
var tarr = [];
for (var j = 0; j < headers.length; j++) {
//doing it this way to get strings and numbers
var field01;
var field02;
var field03;
if (j == 0) {
field01 = obj[j]
}
if (j == 1) {
field02 = obj[j]
}
if (j == 2) {
field03 = obj[j]
}
var o = {
elapsed: field01,
value: field02,
b: field03
}
records.push(o);
}
}
}
initChart(records)
}
function initChart(records) {
var chart = Morris.Line({
element: 'morris-chart-network',
data: records,
axes: false,
xkey: 'elapsed',
ykeys: ['value', 'b'],
labels: ['Download Speed', 'Upload Speed'],
yLabelFormat: function(y) {
return y.toString() + ' Mb/s';
},
gridEnabled: false,
gridLineColor: 'transparent',
lineColors: ['#5b6b79', '#a5a5a5'],
lineWidth: [2, 1],
pointSize: [0, 2],
fillOpacity: .7,
gridTextColor: '#999',
parseTime: false,
resize: true,
behaveLikeLine: true,
hideHover: 'auto'
});
};
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Morris Chart</title>
</head>
<script src="//code.jquery.com/jquery-1.11.3.min.js"></script>
<script src="//code.jquery.com/jquery-migrate-1.2.1.min.js"></script>
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/morris.js/0.5.1/morris.css">
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/raphael/2.1.0/raphael-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/morris.js/0.5.1/morris.min.js"></script>
<body>
<div>Morris Chart</div>
<div id="morris-chart-network" style="width:800px;height:600px">
</div>
<div>
example
</div>

d3js animated pie chart using json

I am trying to create an animated pie chart using a JSON file to store the data.
My JSON file is like this:
{"data":[
{"ap": [
{"floorratio": [
{"floor":"Basement", "ratio": 0.20},
{"floor":"Ground", "ratio": 0.20},
{"floor":"First Floor", "ratio": 0.15},
{"floor":"Second Floor", "ratio": 0.20},
{"floor":"Third Floor", "ratio": 0.25}
]}
]},
{"ap": [
{"floorratio": [
{"floor":"Basement", "ratio": 0.10},
{"floor":"Ground", "ratio": 0.30},
{"floor":"First Floor", "ratio": 0.10},
{"floor":"Second Floor", "ratio": 0.15},
{"floor":"Third Floor", "ratio": 0.35}
]}
]}
]}
and my HTML code:
<!doctype html>
<html>
<head>
<title>Pie Chart Test</title>
<script src="d3.min.js"></script>
</head>
<style>
body {
font: 10px sans-serif;
}
.arc path {
stroke: #fff;
}
</style>
<body>
<label><input type="radio" name="dataset" value="0" checked> 1</label>
<label><input type="radio" name="dataset" value="1"> 2</label>
<script>
var width = 960,
height = 500,
radius = Math.min(width, height) / 2;
var color = d3.scale.ordinal()
.range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
var arc = d3.svg.arc()
.outerRadius(radius - 10)
.innerRadius(0);
var pie = d3.layout.pie()
.sort(null)
.value(function (d) { return d.ratio;});
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var nodeSelected;
d3.json("APCategories.json", function (error, data) {
//initialise data
floorRatio = data.data[0].ap[0].floorratio;
var g = svg.selectAll(".arc")
.data(pie(floorRatio))
.enter().append("g")
.attr("class", "arc");
g.append("path")
.attr("d", arc)
.style("fill", function (d) {
return color(d.data.floor);
})
.each(function(d) {this._current = d;});
g.append("text")
.attr("transform", function (d) {
return "translate(" + arc.centroid(d) + ")";
})
.attr("dy", ".35em")
.style("text-anchor", "middle")
.text(function (d) {
return d.data.floor;
});
//showing initial pie chart code ends here
function changePieChart() {
nodeSelected = this.value;
newFloorRatio = data.data[nodeSelected].ap[0].floorratio;
g = g.data(pie(newFloorRatio));
g.transition().duration(750).attrTween("d", arcTween);
}
function radioSelectedChange() {
nodeSelected = this.value;
changePieChart();
}
d3.selectAll("input")
.on("change", changePieChart);
function arcTween(a) {
var i = d3.interpolate(this._current, a);
this._current = i(0);
return function(t) {
return arc(i(t));
};
}
});
</script>
</body>
</html>
So at the moment I am only loading the first set of data because I am calling
floorRatio = data.data[0].ap[0].floorratio
but what I want to be able to do is to have something more along the lines of:
floorRatio = data.data[i].ap[0].floorratio
I have tried to do this in the changePieChart function, however I think the issue lies with the initialising of the data and I am not quite sure of the correct way to do it with JSON files.
Note: My json file is only a small example of a much larger version.
I want to create one pie chart that updates/changes but am unsure how to with JSON data.
What is the correct way of loading all of the data and then utilising it?
You will have to write a function like forEach to browse through each element inside json data. Look at this plnkr link. d will have the object i.e in this example (data.data) and i will hold the index of each object.
d3.json("json/APCategories.json", function (error, data) {
//initialise data
//floorRatio = data.data[0].ap[0].floorratio;
(data.data).forEach(function(d,i) {
console.log(d.ap[i].floorratio);
// d.data = +d.data;
floorRatio = d.ap[i].floorratio;
console.log(floorRatio);
});
EDITED :
I believe you want to draw multiple pie charts for on number of "ap" objects see this link for working demo.
This link will show svg object which will update when selection changes.