D3-request retrieval of a google spreadsheet csv/json file fails - d3.js

I have difficulties to make Google spreadsheet and D3js' D3-request / D3-request > header works together via xhr requests.
I use the following JS :
d3.request(url)
.header("X-Requested-With", "XMLHttpRequest")
.mimeType("text/csv")
.get(function(error, data) {
if (error) throw error;
console.log('request: '+ data);
});
I get the following error:
XMLHttpRequest cannot load https://docs.google.com/spreadsheets/d/e/2PACX-1vSZyV9olwK_hx0BRFgLtTz5hs_Z…mROYhax3VD9AFXTvmcataf8LuSIpxGT2/pub?gid=1023695213&single=true&output=csv. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://fiddle.jshell.net' is therefore not allowed access.
Jsfiddle here
Any idea to bypass it ?

Using D3 only
d3.json(url, function (error, result) {
var data = [];
for (i = 0; i < result.feed.entry.length; i += 1) {
data.push({
"animal": result.feed.entry[i].gsx$animal.$t,
"population": result.feed.entry[i].gsx$population.$t
});
}
pie_chart(data, "#chart1");
});
Using jQuery
$.get(url, function (result) {
var data = [];
$(result.feed.entry).each(function () {
data.push({"animal": this.gsx$animal.$t, "population": this.gsx$population.$t});
});
pie_chart(data, "#chart2");
});
Using tabletop.
Tabletop.init({
key: key,
callback: function (data, tabletop) {
pie_chart(data, "#chart3");
},
simpleSheet: true
});
Below is just a simple example to get data from a Google spreadsheet and turn it into a D3 pie chart.
//draws a pie chart with D3
function pie_chart(data, id) {
var w = 400;
var h = 400;
var r = h / 2;
var color = d3.scale.category20c();
var vis = d3.select(id).append("svg:svg").data([data]).attr("width", w).attr("height", h).append("svg:g").attr("transform", "translate(" + r + "," + r + ")");
var pie = d3.layout.pie().value(function (d) {
return d.population;
});
var arc = d3.svg.arc().outerRadius(r);
var arcs = vis.selectAll("g.slice").data(pie).enter().append("svg:g").attr("class", "slice");
arcs.append("svg:path")
.attr("fill", function (d, i) {
return color(i);
})
.attr("d", function (d) {
return arc(d);
});
arcs.append("svg:text").attr("transform", function (d) {
d.innerRadius = 0;
d.outerRadius = r;
return "translate(" + arc.centroid(d) + ")";
}).attr("text-anchor", "middle").text(function (d, i) {
return data[i].animal;
});
}
//the key of google spreadsheet
var key = "1moczdbrfFwCp0L4Ube1a4GevuDcj2XQmCnpjArF_UEY";
//the url for jQuery and D3
var url = "https://spreadsheets.google.com/feeds/list/" + key + "/od6/public/values?alt=json";
var i = 0;
//D3 only
d3.json(url, function (error, result) {
var data = [];
for (i = 0; i < result.feed.entry.length; i += 1) {
data.push({
"animal": result.feed.entry[i].gsx$animal.$t,
"population": result.feed.entry[i].gsx$population.$t
});
}
pie_chart(data, "#chart1");
});
//Jquery
$.get(url, function (result) {
var data = [];
$(result.feed.entry).each(function () {
data.push({"animal": this.gsx$animal.$t, "population": this.gsx$population.$t});
});
pie_chart(data, "#chart2");
});
//tabletop
Tabletop.init({
key: key,
callback: function (data, tabletop) {
pie_chart(data, "#chart3");
},
simpleSheet: true
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tabletop.js/1.4.3/tabletop.js"></script>
<div id="chart1" style="width: 480px; height: 400px;"><span>D3 only</span></div>
<hr>
<div id="chart2" style="width: 480px; height: 400px;"><span>Jquery</span></div>
<hr>
<div id="chart3" style="width: 480px; height: 400px;"><span>Tabletop</span></div>

Related

Dont want update charts dc.js

I have chart when page load. I see normal charts with data:
Ids,Dates,Values
Бар,2018-12-21,224
Бар,2018-12-22,352
Бар,2018-12-23,61
Бар,2018-12-24,379
Бар,2018-12-25,78.2
Бар,2018-12-26,0
Бар,2018-12-27,0
Бар,2018-12-28,0
Бар,2018-12-29,0
Бар,2018-12-30,0
Бар,2018-12-31,0
Бар,2019-01-01,0
Бар,2019-01-02,0
Бар,2019-01-03,0
Бар,2019-01-04,0
Бар,2019-01-05,270
Бар,2019-01-06,0
Бар,2019-01-07,0
Бар,2019-01-08,0
Бар,2019-01-09,0
Бар,2019-01-10,0
Бар,2019-01-11,0
Бар,2019-01-12,0
Бар,2019-01-13,0
Бар,2019-01-14,0
Бар,2019-01-15,0
Бар,2019-01-16,0
Бар,2019-01-17,0
Бар,2019-01-18,0
Бар,2019-01-19,0
Бар,2019-01-20,0
But if I send ajax chart is empty, but have a data, and if I load page with this data all are correct, only ajax destroy chart:
Ids,Dates,Values
Бар,2018-11-21,178
Бар,2018-11-22,256
Бар,2018-11-23,226
Бар,2018-11-24,570
Бар,2018-11-25,266
Бар,2018-11-26,398
Бар,2018-11-27,0
Бар,2018-11-28,15
Бар,2018-11-29,80
Бар,2018-11-30,118
Бар,2018-12-01,41
Бар,2018-12-02,365
Бар,2018-12-03,180
Бар,2018-12-04,187
Бар,2018-12-05,38
Бар,2018-12-06,82
Бар,2018-12-07,390
Бар,2018-12-08,177
Бар,2018-12-09,359
Бар,2018-12-10,236
Бар,2018-12-11,7
Бар,2018-12-12,34
Бар,2018-12-13,478
Бар,2018-12-14,173
Бар,2018-12-15,290
Бар,2018-12-16,453
Бар,2018-12-17,52
Бар,2018-12-18,334
Бар,2018-12-19,0
Бар,2018-12-20,122
My js code:
$(document).ready(function() {
$('.js_dashboard').focus(function() {
allPostDataForOne($(this));
});
$('.js_dashboard').parents('.container').find('.js_dc_components').find('.js_data_graph').each(function(index, value) {
renderBar(dc.barChart("#js_graphic_" + index), d3.csv.parse(d3.select(value).text()));
});
});
function allPostDataForOne(elem) {
var table = elem.parents('.container').find('.js_main_dasboard');
$.ajax({
url: '/../index/total' + $('.js_suffix').val(),
type: 'POST',
data: 'date=' + elem.val(),
success: function(data) {
table.html($($(data)).find('.js_main_dasboard').html());
table.parents('.container').find('.js_dc_components').find('.js_data_graph').each(function(index, value) {
$($(data)).find('.container').find('.js_dc_components').find('.js_data_graph').each(function(index_res, value_res) {
if (index === index_res) {
value = value_res;
}
});
renderBar(dc.barChart("#js_graphic_" + index), d3.csv.parse(d3.select(value).text()));
});
},
})
}
function renderBar(chart, experiments) {
var start_date = new Date($('.js_start_date').val());
var end_date = new Date($('.js_end_date').val());
var format = d3.time.format("%Y-%m-%d");
experiments.forEach(function(x) {
x.Values = +x.Values;
});
var ndx = crossfilter(experiments);
var runDimension = ndx.dimension(function(d) {
return new Date(d.Dates);
});
var runGroup = runDimension.group().reduceSum(function(d) {
return d.Values;
});
chart
.width(750)
.height(300)
.x(d3.time.scale().domain([start_date, end_date]))
.brushOn(false)
.yAxisLabel(experiments[0]['Ids'])
.xAxisLabel("Date")
.dimension(runDimension)
.mouseZoomable(true)
.group(runGroup)
.title(function(d) {
return d.key.getFullYear() + '-' + parseInt(d.key.getMonth() + 1) + '-' + d.key.getDate() + ': ' + d.value;
})
chart.xUnits(function() {
return experiments.length;
});
chart.render();
}
I can't understand how to correctly update charts. I saw many quations but i cant understand how they update transform in my code.

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>

Want to get region name from drill down map of jvectormap

I am unable to get region name from code of region. My region click event work fine and I also get code properly. My code is:
<div id="map" style="width: 600px; height: 400px"></div>
<script type="text/javascript">
$(function () {
new jvm.MultiMap({
container: $('#map'),
maxLevel: 1,
main: {
map: 'us_lcc_en'
},
mapUrlByCode: function (code, multiMap) {
return 'js/counties/jquery-jvectormap-data-' +
code.toLowerCase() + '-' +
multiMap.defaultProjection + '-en.js';
}
});
$('#map').bind('regionClick.jvectormap', function (event, code) {
var map = $('#map').vectorMap('get', 'mapObject');
alert(map.getRegionName(code));
});
});
</script>
HTML CODE
<div id="map2" style="width: 100%; height: 400px"></div>
Jquery Code
$('#map2').vectorMap({
map: 'world_mill_en',
series: {
regions: [{
scale: ['#C8EEFF', '#0071A4'],
normalizeFunction: 'polynomial',
values: gdpData
}]
},
onRegionClick: function (event, code) {
******* Code To Show Region Name *******
/* Here We are getting Map Object */
var map=$('#map2').vectorMap('get', 'mapObject');
/* Here Using Map Object we are using Inbuilt GetRegionName
function TO Get Regionname for a region Code */
var regionName = map.getRegionName(code);
console.log("Code: "+code+"<br/>");
console.log("Region Name: "+regionName+"<br/>");
******* Code To Show Region Name *******
}
});
I could not figure out how to get the region name from the onRegionClick for a multi map. This is my hack to get what is needed.
var drillDownUSMap;
var stateCode;
var countyName;
$(document).ready(function () {
drillDownUSMap = new jvm.MultiMap({
container: $('#map'),
maxLevel: 1,
main: {
map: 'us_lcc_en',
onRegionClick: function (e, code) {
var map = $('#map div').vectorMap('get', 'mapObject');
var regionName = map.getRegionName(code);
stateCode = code.toLowerCase();
console.log(regionName)
}
},
mapUrlByCode: function (code, multiMap) {
return 'js/counties/jquery-jvectormap-data-' +
code.toLowerCase() + '-' +
multiMap.defaultProjection + '-en.js';
},
mapNameByCode: function (code, multiMap) {
return code.toLowerCase() + '_' +
multiMap.defaultProjection + '_en';
}
});
$(document).on('click', '.jvectormap-region.jvectormap-element', function (evt) {
var regionElem = $(this);
var stateJSFileName = stateCode + "_" + drillDownUSMap.defaultProjection + "_en";
var regionCode = regionElem.attr('data-code');
if (drillDownUSMap.maps[stateJSFileName]) {
countyName = drillDownUSMap.maps[stateJSFileName].regions[regionCode].config.name;
if (regionElem.hasClass("selected-region")) {
regionElem.removeClass("selected-region");
} else {
regionElem.addClass("selected-region");
}
}
});
});
Add this code
onRegionClick:function(event, code) {
var name = (code);
alert(name);
}
All Script Like This
<div id="map" style="width: 600px; height: 400px"></div>
<script type="text/javascript">
$(function () {
new jvm.MultiMap({
container: $('#map'),
maxLevel: 1,
main: {
map: 'us_lcc_en'
},
mapUrlByCode: function (code, multiMap) {
return 'js/counties/jquery-jvectormap-data-' +
code.toLowerCase() + '-' +
multiMap.defaultProjection + '-en.js';
}
});
onRegionClick:function(event, code) {
var name = (code);
alert(name);
}
});
</script>

How to override a function in NVD3 library?

My goal is to override the function used by NVD3 for the content of a tooltip.
I found the function that provides this behaviour: contentGenerator.
Below here the code:
var contentGenerator = function(d) {
if (content != null) {
return content;
}
if (d == null) {
return '';
}
var table = d3.select(document.createElement("table"));
var theadEnter = table.selectAll("thead")
.data([d])
.enter().append("thead");
theadEnter.append("tr")
.append("td")
.attr("colspan",3)
.append("strong")
.classed("x-value",true)
.html(headerFormatter(d.value));
var tbodyEnter = table.selectAll("tbody")
.data([d])
.enter().append("tbody");
var trowEnter = tbodyEnter.selectAll("tr")
.data(function(p) { return p.series})
.enter()
.append("tr")
.classed("highlight", function(p) { return p.highlight});
trowEnter.append("td")
.classed("legend-color-guide",true)
.append("div")
.style("background-color", function(p) { return p.color});
trowEnter.append("td")
.classed("key",true)
.html(function(p) {return p.key});
trowEnter.append("td")
.classed("value",true)
.html(function(p,i) { return valueFormatter(p.value,i) });
trowEnter.selectAll("td").each(function(p) {
if (p.highlight) {
var opacityScale = d3.scale.linear().domain([0,1]).range(["#fff",p.color]);
var opacity = 0.6;
d3.select(this)
.style("border-bottom-color", opacityScale(opacity))
.style("border-top-color", opacityScale(opacity))
;
}
});
var html = table.node().outerHTML;
if (d.footer == undefined)
html += "<div class='footer'>" + d.footer + "</div>";
return html;
};
Now, I'd like to put inside my chart section the function to override this method.
var chart = nv.models.lineChart()
.x(function(d) { return d.x; })
.y(function(d) { return d.y; })
.useInteractiveGuideline(false)
.tooltipContent(function (key, x, y, e, graph) {
return contentGenerator
});
How Can I achieve this goal?
I wanted to customise:
1) In the header add a simple text
2) Add a footer

Resources