dc.js line chart - Date Value issue - d3.js

Okay, so I created a basic line chart where x = months and y = values as per the below CSV:
dates,purpose,num
01/04/2015,Commute,1
01/05/2015,Commute,15
01/06/2015,Commute,48
01/07/2015,Commute,4
01/08/2015,Commute,4
01/09/2015,Commute,52
01/10/2015,Commute,163
01/11/2015,Commute,222
01/12/2015,Commute,126
01/01/2016,Commute,174
01/02/2016,Commute,11
01/03/2016,Commute,15
01/04/2015,Walk,0
01/05/2015,Walk,600
01/06/2015,Walk,13
01/07/2015,Walk,1
01/08/2015,Walk,1
01/09/2015,Walk,14
01/10/2015,Walk,44
01/11/2015,Walk,60
01/12/2015,Walk,34
01/01/2016,Walk,47
01/02/2016,Walk,3
01/03/2016,Walk,900
HTML is as follows:
<head>
<title>dc.js - Line Chart Example</title>
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" href="../css/dc.css"/>
</head>
<body>
<div id="test"></div>
<script type="text/javascript" src="../js/d3.js"></script>
<script type="text/javascript" src="../js/crossfilter.js"></script>
<script type="text/javascript" src="../js/dc.js"></script>
<script type="text/javascript">
var Chart5 = dc.lineChart("#test");
d3.csv("morley3.csv", function(data) {
var dateFormat = d3.time.format("%d/%m/%Y");
var numberFormat = d3.format(".2f");
data.forEach(function(d) {
d.dd = dateFormat.parse(d.dates);
d.month = d3.time.month(d.dd);
//d.day = d3.time.day(d.dd);
//d.year = d.dd.getFullYear();
//d.num = +d.num;
//d.purpose = d.purpose;
});
var facts = crossfilter(data);
var dateDimension = facts.dimension(function(d) {return d.month;});
var dateDimension2 = facts.dimension(function(d) { if (d.purpose == "Walk") {return d.month;}});
var numberByDate2 = dateDimension2.group().reduceSum(function(d) { return d.num; });
minDate = dateDimension2.bottom(1)[0];
maxDate = dateDimension2.top(1)[0];
Chart5
.renderArea(true)
.width(900)
.height(300)
.renderArea(false)
.brushOn(false)
.dimension(dateDimension2)
.group(numberByDate2)
.x(d3.time.scale().domain([minDate, maxDate]))
// .xUnits(d3.time.day)
renderHorizontalGridLines(true)
.elasticX(true)
.elasticY(true)
.legend(dc.legend().x(800).y(10).itemHeight(13).gap(5))
.valueAccessor(function (d) {return d.value;}) // What does this do?
.yAxisLabel("")
.xAxis();
dc.renderAll();
});
</script>
</body>
</html>
I've asked to show just "Walk" and the result is showing the months ok in the correct order.
The issue I'm having is that the first month is adding 835 to the result.
This is the sum of all "num" where "purpose" = "Commute".
See pic here: http://tinypic.com/r/qx9kih/8
Any ideas where I'm going wrong?

Dimension accessor functions must return naturally ordered values, and yours does not. If the values aren't naturally ordered, group calculations start randomly including incorrect records. Try changing your dimension to:
var dateDimension2 = facts.dimension(function(d) { return d.month; });
var numberByDate2 = dateDimension2.group().reduceSum(function(d) {
if (d.purpose == "Walk") { return d.num } else { return 0; };
});
In other words, do your filtering in the sum accessor function rather than the dimension accessor function.

Related

How to show a color-coded country map (with city boundaries) in Aframe

Following my previous question:Load json map into aframe by aframe-geo-projection-component created by earthlinginteractive
Now, I am trying to find a way to show different geometries (country or city) in AFrame each with a different color,
looking for something like this.
I do not mind which library or approach are used, Found this but not sure how to convert this D3.js to Aframe. However as the community bot asked me to provide more details, I have put the code that I am working on below. Not sure which part I need to modify to have such a color coded map but I am working on that. Again, any working example works for me even if someone can show what I need to modify in the below code.
<!-- https://github.com/EarthlingInteractive/aframe-geo-projection-component
https://earthlinginteractive.github.io/aframe-geo-projection-component/ -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>A-Frame Geo Projection Component - U.S. Population 2017 (est.)</title>
<meta name="description" content="Visualization of estimated U.S. population by state in 2017"></meta>
<script src="https://aframe.io/releases/0.7.1/aframe.min.js"></script>
<script src="//cdn.rawgit.com/donmccurdy/aframe-extras/v3.12.4/dist/aframe-extras.min.js"></script>
<script src="https://unpkg.com/super-hands#2.1.0/dist/super-hands.min.js"></script>
<script src="https://d3js.org/d3.v4.js"></script>
<script src="https://d3js.org/d3-queue.v3.js"></script>
<script src="https://earthlinginteractive.github.io/aframe-geo-projection-component/dist/aframe-geo-projection-component.min.js"></script>
</head>
<body>
<script>
AFRAME.registerComponent('geo-extrude-population-renderer', {
dependencies: ['geo-projection'],
schema: {
maxExtrudeHeight: {
default: 2
}
},
init: function () {
this.system = this.el.sceneEl.systems['geo-projection'];
this.geoProjectionComponent = this.el.components['geo-projection'];
this.geoJsonReady = this.geoJsonReady.bind(this);
// Wait for geoJson to finish loading to avoid race conditions
this.el.addEventListener('geo-src-loaded', this.geoJsonReady);
},
update: function (oldData) {
if (!this.geoProjectionComponent.geoJson) {
return;
}
if (this.data.maxExtrudeHeight !== oldData.maxExtrudeHeight) {
this.geoJsonReady();
}
},
geoJsonReady: function () {
// Now kick off loading the data
d3.queue()
.defer(d3.csv, 'https://cdn.glitch.global/c153e3cf-7430-444d-9897-4e97f1ef8d35/us-population-2017.csv?v=1657704183925', function (d) {
return {
state: d.state,
population: +d.population
}
})
.defer(d3.csv, 'https://cdn.glitch.global/c153e3cf-7430-444d-9897-4e97f1ef8d35/us-state-county-geocodes-v2016.csv?v=1657704190160')
.await(this.onDataLoaded.bind(this));
},
onDataLoaded: function(error, populationData, geocodes) {
if (error) throw error;
var stateFips = geocodes.filter(function (row) {
return row['Summary_Level'] === '040'
});
var maxPopulation = d3.max(populationData, function (d) {
return d.population;
});
var populationByFipsCode = populationData.reduce(function (accum, d) {
var fipsForState = stateFips.find(function (fipsRow) { return fipsRow['Area_Name'] === d.state; });
var fipsCode = fipsForState['State_Code_FIPS'];
accum[fipsCode] = d.population;
return accum;
}, {});
this.render(populationByFipsCode, maxPopulation, this.data.maxExtrudeHeight);
},
render: function (populationByFipsCode, maxPopulation, maxExtrudeHeight) {
if (!populationByFipsCode) return;
var material = [];
var extrudeGeometry = null;
var stateOutlineVertices = [];
// Split the geoJson into features and render each one individually so that we can set a different
// extrusion height for each based on the population.
this.geoProjectionComponent.geoJson.features.forEach(function (feature) {
var population = populationByFipsCode[feature.id];
var extrudeAmount = (population / maxPopulation) * maxExtrudeHeight;
var material="#999999";
const extrudeSettings = {
amount: extrudeAmount,
bevelEnabled: false
};
//Math.floor(Math.random()*16777215).toString(16);
var mapRenderContext = this.system.renderToContext(feature, this.geoProjectionComponent.projection);
const stateShapes = mapRenderContext.toShapes();
// Gather the outline of the state and set the height of the outline to the extrude level
// so that the top of the state is outlined
stateOutlineVertices = stateOutlineVertices.concat(mapRenderContext.toVertices(extrudeAmount));
// Merge all the extruded feature geometries together for better rendering performance
// Need to use ExtrudeGeometry here instead of ExtrudeBufferGeometry because the latter doesn't merge properly
// in this version of Three.js
var extrudedFeatureGeometry = new THREE.ExtrudeGeometry(stateShapes, extrudeSettings);
if (!extrudeGeometry) {
extrudeGeometry = extrudedFeatureGeometry;
} else {
extrudeGeometry.merge(extrudedFeatureGeometry);
}
}.bind(this));
// Convert the extrude geometry into a buffer geometry for better rendering performance
var extrudeBufferGeometry = new THREE.BufferGeometry();
extrudeBufferGeometry.fromGeometry(extrudeGeometry);
var sideMaterial = new THREE.MeshStandardMaterial( { color: 0xaaafff } );
var extrudedMap = new THREE.Mesh(extrudeBufferGeometry, [material, sideMaterial]);
this.el.setObject3D('map', extrudedMap);
var stateOutlineGeometry = new THREE.BufferGeometry();
stateOutlineGeometry.addAttribute('position', new THREE.Float32BufferAttribute(stateOutlineVertices, 3));
var stateOutlineMaterial = new THREE.LineBasicMaterial( { color: 0xcccaaa } );
var stateOutlines = new THREE.LineSegments(stateOutlineGeometry, stateOutlineMaterial);
this.el.setObject3D('lines', stateOutlines);
}
});
</script>
<a-scene>
<a-assets>
<a-asset-item id="json-us" src="https://unpkg.com/us-atlas#1/us/10m.json" />
</a-assets>
<a-sky color="#ECECEC"></a-sky>
<a-entity id="map"
rotation="-90 0 0"
material="color: #123456;"
topojson-loader="src: #json-us; topologyObject: states;"
geo-projection="
projection: geoIdentity;
height: 6;
width: 10;"
geo-extrude-population-renderer
>
</a-entity>
<a-locomotor>
<a-entity hand-controls="left" super-hands></a-entity>
<a-entity hand-controls="right" super-hands></a-entity>
</a-locomotor>
</a-scene>
</body>
</html>
<!--material="color: #123456;"-->
getting this error as well if I use aframe 1.3.0:
Uncaught TypeError: extrudeBufferGeometry.fromGeometry is not a function
at i.render ((index):104:29)
at i.onDataLoaded ((index):66:12)
at Queue._call (d3-queue.v3.js:43:54)
at maybeNotify (d3-queue.v3.js:120:7)
at d3-queue.v3.js:91:12
at Object.<anonymous> (d3.v4.js:11470:86)
at Dispatch.call (d3.v4.js:792:72)
at XMLHttpRequest.respond (d3.v4.js:11395:13)

aspx page on Sharepoint error: Function Expected only when rendering datatable

I have been building a reporting page in sharepoint with dc and crossfilter.
Right now on my page, I have 5 pie charts that render with no problem. However, when I tried to add a dc datatable to the page to show results of the charts as they are filtered, I get a javascript error on "resultsChart.render();"
Because no errors are given when I render each of the pie charts, I assume this to mean that something is off with the datatable object, or that I cannot call render() on that object (whatever it thinks it is).
Here are the relevant pieces of my code:
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.5.0/d3.min.js" type="text/javascript">
<script src="https://cdnjs.cloudflare.com/ajax/libs/datatables/1.10.19/js/jquery.dataTables.min.js" type="text/javascript"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crossfilter/1.3.12/crossfilter.min.js" type="text/javascript">
<script src="https://cdnjs.cloudflare.com/ajax/libs/dc/3.0.6/dc.min.js" type="text/javascript">
//connect to sharepoint site (change this URL to redirect)
var siteUrl = 'path';
var masterData = [];
//retrieve list data from above sharepoint site based on List Name
function retrieveListItems() {
var clientContext = new SP.ClientContext(siteUrl);
var oList = clientContext.get_web().get_lists().getByTitle('Upcoming');
var camlQuery = new SP.CamlQuery();
camlQuery.set_viewXml("<View><Query></Query></View>");
this.collListItem = oList.getItems(camlQuery);
clientContext.load(collListItem);
clientContext.executeQueryAsync(
Function.createDelegate(this, this.onQuerySucceeded),
Function.createDelegate(this, this.onQueryFailed)
);
}
//on query success
function onQuerySucceeded(sender, args) {
var listItemEnumerator = collListItem.getEnumerator();
while (listItemEnumerator.moveNext()) {
var data = {};
var oListItem = listItemEnumerator.get_current();
//set field keys on array objects
data.project = oListItem.get_item('Project_x0020_Type');
data.stoplight = oListItem.get_item('Stoplight');
data.appmgr = oListItem.get_item('AIT_x0020_App_x0020_Manager');
data.compdate = oListItem.get_item('Completion_x0020_Due_x0020_Date');
data.ait = oListItem.get_item('AIT_x0020_Number');
data.lob = oListItem.get_item('Business_x0020_Area');
data.sublob = oListItem.get_item('Business_x0020_Sub_x0020_Area');
masterData.push(data);
}//end while
var projectChart = dc.pieChart("#project", "project");
var stoplightChart = dc.pieChart("#stoplight", "stoplight");
var appmgrChart = dc.pieChart("#appmgr", "appmgr");
var lobChart = dc.pieChart("#lob", "lob");
var sublobChart = dc.pieChart("#sublob", "sublob");
var resultChart = dc.dataTable("#result_table", "result");
var ndx = crossfilter(masterData),
projectType = ndx.dimension(function(d) { return d.project;}),
stoplight = ndx.dimension(function(d) { return d.stoplight;}),
appMgr = ndx.dimension(function(d) { return d.appmgr;}),
compdate = ndx.dimension(function(d) { return d.compdate;}),
lob = ndx.dimension(function(d) { return d.lob;}),
sublob = ndx.dimension(function(d) { return d.sublob;})
projectTypeGroup = projectType.group();
stoplightGroup = stoplight.group(),
appMgrGroup = appMgr.group(),
compDateGroup = compdate.group(),
lobGroup = lob.group(),
sublobGroup = sublob.group();
projectChart
.dimension(projectType)
.group(projectTypeGroup)
.width(200)
.height(200)
.innerRadius(75)
stoplightChart
.dimension(stoplight)
.group(stoplightGroup)
.width(200)
.height(200)
.innerRadius(75)
appmgrChart
.dimension(appMgr)
.group(appMgrGroup)
.width(200)
.height(200)
.innerRadius(75)
lobChart
.dimension(lob)
.group(lobGroup)
.width(300)
.height(300)
.innerRadius(117)
sublobChart
.dimension(sublob)
.group(sublobGroup)
.width(200)
.height(200)
.innerRadius(75)
resultChart
.dimension(compdate)
.group(compDateGroup)
.columns([
function(d) { return d.ait},
function(d) { return d.project},
function(d) { return d.stoplight},
function(d) { return d.compdate}
])
.size(100);
projectChart.render();
stoplightChart.render();
appmgrChart.render();
lobChart.render();
sublobChart.render();
resultChart.render();
}
function onQueryFailed(sender, args) {
alert('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
}
SP.SOD.executeOrDelayUntilScriptLoaded(retrieveListItems, 'sp.js');
</script>
Any and all help is extremely appreciated!
I figured it out. According to the dc.dataTable documentation, you cannot use a crossfilter group as the .group attribute on a datatable. Instead, you must explicitly use a function there.
So it should be
resultChart
.dimension(compdate)
.group(function(d) { return d.compdate;})
.columns([
function(d) { return d.ait},
function(d) { return d.project},
function(d) { return d.stoplight},
function(d) { return d.compdate}
])
.size(100);
Instead of
resultChart
.dimension(compdate)
.group(compDateGroup)
.columns([
function(d) { return d.ait},
function(d) { return d.project},
function(d) { return d.stoplight},
function(d) { return d.compdate}
])
.size(100);

dc.js library not working as tutorials

I am trying to use the dc.js library for charts. However, what I found was my charts were not loading properly. If I write my code as following, it would not show the charts or error messages. But if I include my script (except the first line of the script) in the ready function like below, the charts load well.
$(document).ready(function (){
d3.json('data/GDX_partial.json', function (data) {
//code goes here......
}
})
Any idea? I omitted the library references and data and I am sure the data is not the issue.
<script type="text/javascript">
observerPieChart = dc.pieChart("#observer-pie-chart");
d3.json('data/GDX_partial.json', function (data) {
var dateFormat = d3.time.format('%m/%d/%Y %I:%M:%S %p').parse;
var numberFormat = d3.format('.2f');
var features = data.features;
features.forEach(function (d) {
d.date = dateFormat(d.attributes.ADD_DATE);
d.newX = Math.round(d.geometry.x);
d.newY = Math.round(d.geometry.y);
});
var gdx = crossfilter(features);
var observerDim = gdx.dimension(function (d) {
return d.attributes.OBSERVER;
});
var obsvCount = observerDim.group().reduce(
function (p, v) {
return p + 1;
},
function (p, v) {
return p - 1;
},
function (p, v) {
return 0;
});
observerPieChart
.width(400)
.height(150)
.dimension(observerDim)
.group(obsvCount);
dc.renderAll();
});
</script>
</head>
<body>
<div class="container-fluid">
<div id="observer-pie-chart"></div>
</div>
</body>

Create addListener click event for more than one shape on the Google map

Look at this code:
This creates four circles on the map in a same position and it creates addListener click event for each one too but I just can click on the last one. I want to fix it in a way that I can click on all of them to make setEditable(true) for each one.
<!DOCTYPE html>
<html>
<head>
<script
src="http://maps.googleapis.com/maps/api/js?key=AIzaSyDY0kkJiTPVd2U7aTOAwhc9ySH6oHxOIYM&sensor=false">
</script>
<script>
var selectedShape;
function clearSelection()
{
if(selectedShape)
{
selectedShape.setEditable(false);
selectedShape = null;
}
}
function setSelection(shape)
{
clearSelection();
selectedShape = shape;
shape.setEditable(true);
}
</script>
<script>
var amsterdam=new google.maps.LatLng(52.395715,4.888916);
function initialize()
{
var mapProp = {center:amsterdam, zoom:7, mapTypeId:google.maps.MapTypeId.ROADMAP};
var map = new google.maps.Map(document.getElementById("googleMap"),mapProp);
var myArray = [];
var myCity;
for(var i = 0; i < 4; i++)
{
myCity = new google.maps.Circle({
center:amsterdam,
radius:20000,
strokeColor:"#0000FF",
strokeOpacity:0.8,
strokeWeight:2,
fillColor:"#0000FF",
fillOpacity:0.4
});
myArray.push(myCity);
google.maps.event.addListener(myCity, 'click', function() {setSelection(myCity)});
myArray[i].setMap(map);
}
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
</head>
<body>
<div id="googleMap" style="width:500px;height:380px;"></div>
</body>
</html>
Use this instead of myCity :
google.maps.event.addListener(myCity, 'click', function() {
setSelection(this)
});
Using setSelection(myCity) will refer to the last myCity created.

jquery plugin problem

i created jquery plugin
and error I get is reference error: mySlider is not defined
(function($){
$.fn.mySlider = function(){
var timeOut = 4000;
var element = this;
var fxDuration = timeOut/6;
var items = $("#" + element[0].id + " li");
var captions = $("#" + element[0].id + " li div");
var fadeIn = function(no){
$(items[no]).fadeIn(fxDuration, function(){
$(captions[no]).fadeIn(fxDuration, function(){
setTimeout(function(){fadeOut(no)}, timeOut);
});
});
}
var fadeOut = function(no){
$(captions[no]).fadeOut(fxDuration, function(){
$(items[no]).fadeOut(fxDuration, function(){
fadeIn(calcNext(no));
});
});
}
var calcNext = function(no){
return ((no+1) == items.length)? 0: (no+1);
}
fadeIn(0);
}
})(jQuery);
and called
<script src="jquery-1.6.1.min.js" type="text/javascript" charset="utf-8"></script>
<script src="mySlider.js" type="text/javascript" charset="utf-8"></script>
<script>
// alert('hi');
$(document).ready(function(){
alert(mySlider());
//$("#slider").mySlider();
});
</script>
It says mySlider is not defined
please help me to solve this. Thanks
It is not defined, since you did not define it.
You defined only $.fn.mySlider
You may want something like this, to have a separate function:
var mySlider = function() {
$("#slider").mySlider();
};

Resources