I'm very new to doing anything with d3 and jSon. Here is a pice of data I'm trying to get out from json and I would just like to know if I'm even on the right path.
Basically each status group would have more servers inside than just one like at the moment and the idea would be to get rectangle graph for one server and list these nicely next to each other.
I've been reading a lot of tutorials and trying to browse for similiar kind of issues other people might've had, but so far had really no luck...
jSon data I'm trying to pull out
[
{
"status": "ok",
"servers":
[
{
"id": "VR01",
"servername": "Server_1",
"cpu": 45, "mem": 25,
"diskIO": 0, "bandwith": 200
}
]
},
{
"status": "attention",
"servers":
[
{
"id": "VR10",
"servername": "Server_10",
"cpu": 55, "mem": 35,
"diskIO": 1, "bandwith": 2000
}
]
},
{
"status": "warning",
"servers":
[
{
"id": "VR02",
"servername": "Server_02",
"cpu": 98, "mem": 85,
"diskIO": 1,
"bandwith": 2000
}
]
},
{
"status": "dead",
"servers":
[
{
"id": "VR20",
"servername": "Server_20",
"cpu": 0, "mem": 0,
"diskIO": 0,
"bandwith": 0
}
]
}
]
the D3 bit
<script>
var width = ("width", 1000);
var height = ("height", 800);
d3.json("mydata.json", function(data) {
var canvas = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
var status = function sortData(data){
for (i = 0; i < d.length; i++) {
if(d.status ==="ok")
canvas.selectAll("rect")
.data(d.server)
.enter()
.append("rect")
.attr("x", 25)
.attr("y", function(d, i){return 25 * i;})
.attr("fill", "purple")
}
}
})
</script>
Really appreciate any suggestions you might have!
I think that it would be better to use nested selections to create your dashboard.
// Create one group for each server group
var serverGroup = svg.selectAll('g')
.data(data)
.enter()
.append('g')
.attr('transform', function(d, i) { return 'translate(0, ' + 50 * i + ')');
// Create the inner elements for each group
var servers = serverGroup.selectAll('rect')
.data(function(d) { return d.servers; })
.enter()
.append('rect')
// ... more settings here ...
This will create three groups, one for each group of servers and translate each one vertically. Each group contains the group data, so we can use the group data to create elements inside each group. Also, you can add a title, background color and other settings for each group using this structure. This article contains the concepts that you need to work on your problem: How Selections Work. Regards,
Related
i am trying to run this code but some how it throws error i have created a json file that is saved in mine data folder i am calling this file. is there anyway to solve this problem
Here is mine code snippet
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
text-align: center;
}
svg {
margin-top: 32px;
border: 1px solid #aaa;
}
.person rect {
fill: #fff;
stroke: steelblue;
stroke-width: 1px;
}
.person {
font: 14px sans-serif;
}
.link {
fill: none;
stroke: #ccc;
stroke-width: 1.5px;
}
</style>
<body>
<script src="http://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<script>
var boxWidth = 150,
boxHeight = 40;
// Setup zoom and pan
var zoom = d3.behavior.zoom()
.scaleExtent([.1,1])
.on('zoom', function(){
svg.attr("transform", "translate(" + d3.event.translate + ") scale(" + d3.event.scale + ")");
})
// Offset so that first pan and zoom does not jump back to the origin
.translate([150, 200]);
var svg = d3.select("body").append("svg")
.attr('width', 1000)
.attr('height', 500)
.call(zoom)
.append('g')
// Left padding of tree so that the whole root node is on the screen.
// TODO: find a better way
.attr("transform", "translate(150,200)");
var tree = d3.layout.tree()
// Using nodeSize we are able to control
// the separation between nodes. If we used
// the size parameter instead then d3 would
// calculate the separation dynamically to fill
// the available space.
.nodeSize([100, 200])
// By default, cousins are drawn further apart than siblings.
// By returning the same value in all cases, we draw cousins
// the same distance apart as siblings.
.separation(function(){
return .5;
})
// Tell d3 what the child nodes are. Remember, we're drawing
// a tree so the ancestors are child nodes.
.children(function(person){
return person._parents;
});
d3.json('Data/4gens.json', function(error, json){
if(error) {
return console.error(error);
}
var nodes = tree.nodes(json),
links = tree.links(nodes);
// Style links (edges)
svg.selectAll("path.link")
.data(links)
.enter().append("path")
.attr("class", "link")
.attr("d", elbow);
// Style nodes
var node = svg.selectAll("g.person")
.data(nodes)
.enter().append("g")
.attr("class", "person")
.attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; });
// Draw the rectangle person boxes
node.append("rect")
.attr({
x: -(boxWidth/2),
y: -(boxHeight/2),
width: boxWidth,
height: boxHeight
});
// Draw the person's name and position it inside the box
node.append("text")
.attr("dx", -(boxWidth/2) + 10)
.attr("dy", 0)
.attr("text-anchor", "start")
.attr('class', 'name')
.text(function(d) {
return d.name;
});
});
/**
* Custom path function that creates straight connecting lines.
*/
function elbow(d) {
return "M" + d.source.y + "," + d.source.x
+ "H" + (d.source.y + (d.target.y-d.source.y)/2)
+ "V" + d.target.x
+ "H" + d.target.y;
}
</script>
</body>
</html>
It throws error
d3.min.js:1 Access to XMLHttpRequest at 'file:///C:/Users/xyz34/Desktop/treant-js-master/Data/4gens.json' from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https.
when i update the cdn to this https://cdnjs.cloudflare.com/ajax/libs/d3/5.12.0/d3.min.js
then it throws the following error
Uncaught TypeError: Cannot read property 'zoom' of undefined
at basic.html:39
Uncaught TypeError: Cannot read property 'tree' of undefined
at basic.html:48
here is mine json content
{
"name": "Maude Fernandez",
"id": "06ada7cd-3078-54bc-bb87-72e9d6f38abf",
"_parents": [
{
"name": "Janie Norton",
"id": "a39bfa73-6617-5e8e-9470-d26b68787e52",
"_parents": [
{
"name": "Pearl Cannon",
"id": "fc956046-a5c3-502f-b853-d669804d428f",
"_parents": [
{
"name": "Augusta Miller",
"id": "fa5b0c07-9000-5475-a90e-b76af7693a57"
},
{
"name": "Clayton Welch",
"id": "3194517d-1151-502e-a3b6-d1ae8234c647"
}
]
},
{
"name": "Nell Morton",
"id": "06c7b0cb-cd21-53be-81bd-9b088af96904",
"_parents": [
{
"name": "Lelia Hernandez",
"id": "667d2bb6-c26e-5881-9bdc-7ac9805f96c2"
},
{
"name": "Randy Welch",
"id": "104039bb-d353-54a9-a4f2-09fda08b58bb"
}
]
}
]
},
{
"name": "Helen Alvarado",
"id": "522266d2-f01a-5ec0-9977-622e4cb054c0",
"_parents": [
{
"name": "Gussie Glover",
"id": "da430aa2-f438-51ed-ae47-2d9f76f8d831",
"_parents": [
{
"name": "Mina Freeman",
"id": "d384197e-2e1e-5fb2-987b-d90a5cdc3c15"
},
{
"name": "Charlotte Martin",
"id": "ea01728f-e542-53a6-acd0-6f43805c31a3"
}
]
},
{
"name": "Jesus Pierce",
"id": "bfd1612c-b90d-5975-824c-49ecf62b3d5f",
"_parents": [
{
"name": "Donald Cox",
"id": "4f910be4-b827-50be-b783-6ba3249f6ebc"
},
{
"name": "Alex Gonzales",
"id": "efb2396d-478a-5cbc-b168-52e028452f3b"
}
]
}
]
}
]
}
Your code works fine, I created one html file and one json file with your code and data and it just works.
Based on the comment in the question:
d3.min.js:1 Access to XMLHttpRequest at 'file:///C:/Users/ptiwar34/Desktop/treant-js-master/Data/4gens.json' from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https
This is a CORS problem. D3.js is not able to access to your data because it is in a different domain, and for security reasons, the browser blocks it.
You can solve that by running a HTTP server, here is a small guide on how to do it, there are also different alternatives, but in my case, that is the one that I find more comfortable.
Good luck.
This is JSON file named Unit2Vec_tSNE.json and we can get the data points from pos element.
{
"No 0": {
"dur": 135,
"name": "00000001_0",
"lab": "sil",
"pos": [
17.64800262451172,
-1.794445514678955
]
},
"No 1": {
"dur": 28,
"name": "00000001_1",
"lab": "uo",
"pos": [
-17.94196891784668,
-0.8764857649803162
]
},
"No 2": {
"dur": 21,
"name": "00000001_2",
"lab": "x",
"pos": [
2.7473323345184326,
13.970715522766113
]
}
}
The JavaScript code is the following and I try use .data(dataset) function to bind the JSON data to points.
But very strangely, it displays nothing and the console.log('Here!!!!!!!!!') of .attr("cx", function(d) doesn't run.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>D3: A simple scatterplot, setting radii from data</title>
<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 = 500;
var h = 100;
var dataset; // a global
d3.json("Unit2Vec_tSNE.json", function(error, json) {
if (error) return console.warn(error);
dataset = json;
visualize();
});
function visualize() {
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
console.log(dataset); //work at here
svg.selectAll("circle")
.data(dataset)
.enter()
.append("circle")
.attr("cx", function(d) {
console.log('Here!!!!!!!!!'); //not work at here
return d.pos[0];
})
.attr("cy", function(d) {
return d.pos[1];
})
.attr("r", 1);
}
</script>
</body>
</html>
The points can't be seen and console.log('Here!!!!!!!!!'); doesn't run.
Why? How to fix it? Thanks.
I am a new man to D3.js. Because I want to use it do an interactive project for my AI experiment, so display this points (in real application, there are 450000 points) is needed.
It is because dataset is an object and not array.
Quoting the d3 API :
selection.data([data[, key]]) Joins the specified array of data with the selected elements
So, if you change the structure of your JSON accordingly, you will see that your console.log is correctly executed.
You will have to tweak your code though to make it compatible in order to display the circles.
Demo with a correct format for the dataset variable:
var dataset = [
{"No 0": {
"dur": 135,
"name": "00000001_0",
"lab": "sil",
"pos": [
17.64800262451172,
-1.794445514678955
]
}},
{"No 1": {
"dur": 28,
"name": "00000001_1",
"lab": "uo",
"pos": [
-17.94196891784668,
-0.8764857649803162
]
}},
{"No 2": {
"dur": 21,
"name": "00000001_2",
"lab": "x",
"pos": [
2.7473323345184326,
13.970715522766113
]
}}
];
//Width and height
var w = 500;
var h = 100;
visualize();
function visualize()
{
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
console.log(dataset); //work at here
svg.selectAll("circle")
.data(dataset)
.enter()
.append("circle")
.attr("cx", function(d) {
console.log('Here!!!!!!!!!'); //work at here now too
// return d.pos[0]; // edit this according to the new structure
})
.attr("cy", function(d) {
// return d.pos[1]; // edit this according to the new structure
})
.attr("r", 1);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
I have a data array that looks like this:
var data = [
{
"key": "user",
"values": [
"roles",
"manager",
"otherRoles",
"reports",
"devices",
"coffees"
]
},
{
"key": "role",
"values": [
"assignments",
"members",
"otherMembers"
]
},
{
"key": "assignment",
"values": [
"roles"
]
},
{
"key": "Device",
"values": [
"owners",
"roles"
]
},
{
"key": "Coffee",
"values": [
"drinkers"
]
}
];
I am attempting to render tables from SVG rectangles where the table header is the "key" and the table rows are the "values". The only way I was able to make this work was to give a unique incremental class to each table (table0, table1 etc.) I know this is terrible and prevents me from easily accessing all tables in the future. Here is the pertinent code:
parentBox = svgContainer.selectAll('.table')
.data(data, function(d) {return d.key;})
.enter()
.append('g')
.attr('class', function(d, i) {
return "table" + i;
})
.attr("transform", function(d, i) {
return "translate(" + boxWidth*i + "," + rowHeight*i + ")";
});
I'd like to figure out the right way to access nested data in D3. Here is the code in its entirety: D3 Example
Turns out the solution just requires understanding selections better. I first created the parentBox container:
parentBox = svgContainer.selectAll('.table')
.data(data, function(d) {return d.key;})
.enter()
.append('g')
.attr('class', 'table') (etc.)
Then, when populating the table with rows I first selected the created tables, used the each method to loop through each table and create each row. The one trick was to use d3.select(this) to make sure the rows were created properly.
svgContainer.selectAll('.table')
.each(function (d, i) {
tableRows = d3.select(this).selectAll('.row')
.data(d.values)
.enter()
.append(g) (etc.)
I am reading an Arc information from json file and visualizing them using d3.
Actually I am using d3.layout to grouping data. so I have to read this file where tag is our svg tag that is path and the value is the d value of path ,The problem is d value will be changed after reading and return 0 . How do I read the value? Should I organize my json file differently?
Here is my code :
The json file:
{"id": "svgContent","children": [
{"id": "circle1","tag": "path",
"value": "M0,160A160,160 0 1,1 0,-160A160,160 0 1,1 0,160M0,100A100,100 0 1,0 0,-100A100,100 0 1,0 0,100Z",
"children": [
{ "id": "point", "cx": "-67.59530401363443", "cy": "-93.03695435311894" },
{ "id": "point", "cx": "-109.37149937394265", "cy": "35.53695435311897" },
{ "id": "point", "cx": "1.4083438190194563e-14", "cy": "115" }
]
},
{"id": "circle2","tag": "path","value": "M0,260A260,260 0 1,1 0,-260A260,260 0 1,1 0,260M0,200A200,200 0 1,0 0,-200A200,200 0 1,0 0,200Z",
"children": [
{ "id": "point", "cx": "-126.37382924288177", "cy": "-173.93865379061367" },
{ "id": "point", "cx": "-204.477151003458", "cy": "66.43865379061373" },
{ "id": "point", "cx": "2.6329906181668095e-14", "cy": "215" }
]
}
]}
This is my source code :
var w = 1200, h = 780;
var svgContainer = d3.select("#body").append("svg")
.attr("width", w).attr("height", h).attr("id", "svgContent");
var pack = d3.layout.partition();
d3.json("/data.json", function(error, root) {
if (error) return console.error(error);
var nodes = pack.nodes(root);
svgContainer.selectAll("pack").data(nodes).enter().append("svg")
.attr("id", function (d) { return d.id; }).append("path")
.attr("d", function (d) {
console.log(d.value);
return d.value; })
.attr("transform", "translate(600,0)");
});
When I checked the console I expected "M0,260A260,260 0 1,1 0,-260A260,260 0 1,1 0,260M0,200A200,200 0 1,0 0,-200A200,200 0 1,0 0,200Z" but it's return 0 ,How can I handle it?
First of all I'm not quite sure if your d3.select("#body") should maybe be a d3.select("body")? Or do you have an element with id body?
The problem with reseting the value to 0 is, that the d3.layout.partition() uses the value field. You could rename your value field to something else like pathand set it with
.attr("d", function(d){
return d.path;
})
Another problem with your code is, that you add several svg elements.
If you really just want to read the circle paths and display them, then this code does the job:
var w = 1200,
h = 780;
var svgContainer = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h)
.attr("id", "svgContent");
d3.json("/data.json", function(error, root) {
if (error) return console.error(error);
svgContainer.selectAll("path")
.data(root.children)
.enter()
.append("path")
.attr("id", function (d) { return d.id; })
.attr("d", function(d) { return d.value})
.attr("transform", "translate(260,260)");
});
No need for the partition layout. Just create path elements and add the path from the json.
If you want to show the circles, it would be better to place them outside of the pathelements in your json, because you can't add svg circles inside of path elements.
tl;dr
Can I create elements using data that looks like:
[{"id": 1, ...}, {"id: 2, ...}, ..]
and update attributes of the elements using data that looks like:
[2, 4, 7]
(where the elements of the array are a subset of the ids of the initial data set).
Long version
I have data that looks like this:
[
{
"id": 1,
"latitude": 38.314552,
"longitude": -88.9025347755102,
"name": "JEFFERSON COUNTY JAIL ",
"official_name": "Jefferson County Justice Center",
"url": "https://www.ice.gov/detention-facilities/facilities/jeffeil.htm"
},
{
"id": 2,
"latitude": 41.875702,
"longitude": -87.63072,
"name": "CHICAGO HOLD ROOM ",
"official_name": "Chicago Hold Room",
"url": ""
},
{
"id": 3,
"latitude": 43.407029,
"longitude": -88.704349,
"name": "DODGE COUNTY JAIL, JUNEAU ",
"official_name": "Dodge Detention Facility",
"url": "https://www.ice.gov/detention-facilities/facilities/dodgewi.htm"
},
...
]
I put it on an SVG map like this:
var projection = d3.geo.albersUsa()
.scale(scale)
.translate([width / 2, height / 2]);
var facilityCircles = svg.append("svg:g")
.attr("id", "facilities");
d3.json("data/facilities.json", function(facilities) {
var positions = [];
var positionsByFacilityId = {};
var pointSize = 5;
facilities.forEach(function(facility) {
var loc = [facility.longitude, facility.latitude];
var pos = projection(loc);
positions.push(pos);
positionsByFacilityId[facility.id] = pos;
});
facilityCircles.selectAll("circle")
.data(facilities, function(d) { return d.id; })
.enter().append("svg:circle")
.attr("data-facility-id", function(d, i) { return d.id; })
.attr("cx", function(d, i) { return positionsByFacilityId[d.id][0]; })
.attr("cy", function(d, i) { return positionsByFacilityId[d.id][1]; })
.attr("r", function(d, i) { return pointSize; });
}
However, later on, I want to update attributes of the circles based on another data object, which would just be an array of ids representing a subset of the id properties from the initial data, e.g. [2, 4, 5]
Can I do something like this to update the attributes of only selected elements mapped to data objects with the given ids?
facilitiesSubset = [2, 4, 5];
facilityCircles.selectAll("circle")
.data(facilitiesSubset)
.attr("fill", "green");
or, should I just extract the ids from the initial data and use those in the call to data() that is used to create the elements?
To make this a little easier, I'd suggest changing the naming convention a little bit:
var facilityCircleContainer = svg.append("svg:g")
.attr("id", "facilities");
Since the svg:g object isn't actually the circles, it is just holding them. So then:
var facilityCircles = facilityCircleContainer.selectAll("circle")
.data(facilities, function(d) { return d.id; })
.enter().append("svg:circle")
.attr("data-facility-id", function(d, i) { return d.id; })
.ect(...)
facilityCircles now refers to the circles with their attached data now. Updating the fill based on the array is pretty simple:
facilityCircles.attr("fill", function(d){
facilitiesSubset.indexOf(d.id) != -1 ? "green" : "red"});