I'm trying to load data from a csv-File to create a pie chart.
I found a example and copied it to test it. But it doesn't work. It seems that I'm the only one with this Problem. Whats my fault? Can someone help me?
My html-file:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
}
.arc path {
stroke: #fff;
}
</style>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<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.population; });
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
d3.csv("data.csv", function(error, data) {
data.forEach(function(d) {
d.population = +d.population;
});
var g = svg.selectAll(".arc")
.data(pie(data))
.enter().append("g")
.attr("class", "arc");
g.append("path")
.attr("d", arc)
.style("fill", function(d) { return color(d.data.age); });
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.age; });
});
</script>
and the csv:
age,population
<5,2704659
5-13,4499890
14-17,2159981
18-24,3853788
25-44,14106543
45-64,8819342
≥65,612463
Perhaps I have to edit, that I'm using it with django. Without django it works.
So here is my view:
def test(request):
t = get_template('test.html')
html = t.render()
return HttpResponse(html)
Related
I look after the website for a walking club in SW England, which shows a list of forthcoming walks. Each walk entry has an OS Grid Reference for the start of the walk, and a UK Postcode which a walker can enter to their SatNav device, to help them drive to the start of the walk. I currently get the nearest postcode to the starting point grid reference for each walk, using the API for Nearby UK, which also gives me the compass bearing and distance from my grid reference to the centre of the postcode, which in a country area can be a mile or more from the walk start. From these I work out the grid reference at the postcode centre, and then I can show both points as markers on an OS map - so far, so good.
Having recently completed the migration from OS Open Space to OS Data Hub, I wonder if I could also use OS Data Hub to give me the nearest postcode to a grid reference, plus either bearing and distance from one to the other, or the grid reference of the postcode centre, rather than needing to use the Nearby API for this purpose.
I asked the Customer Success team at Ordnance Survey about this, about a month ago, but no help from them yet. I've also tried various ways of using the UK Postcodes Database, which lists every UK postcode with its Eastings and Northings co-ordinates, but searching through the entire list looking for the nearest co-ordinates, using Pythagoras to work out the distance to a walk starting point, takes minutes. This may be because I have to make the search using our walks database, which is written in Visual Basic, but that's another story.
Any pointers as to how to get a nearest postcode and its location from OS Data Hub, for a given grid reference, would be most welcome.
You can find the nearest postcode as long as it is centred no more than 1km away, for example
https://api.os.uk/search/names/v1/nearest?point=440200,458300&radius=1000&fq=LOCAL_TYPE:Postcode&key=yourkey
Beyond 1km you would need further searches in an outer circle around the original point
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Basic Map</title>
<link rel="stylesheet" href="https://labs.os.uk/public/os-api-branding/v0.2.0/os-api-branding.css" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io#master/en/v6.5.0/css/ol.css" />
<style>
body { margin:0; padding:0; }
#map { position:absolute; top:0; bottom:0; width:100%; }
</style>
</head>
<body>
<div id="map"></div>
<script src="https://labs.os.uk/public/os-api-branding/v0.2.0/os-api-branding.js"></script>
<script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io#master/en/v6.5.0/build/ol.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/proj4js/2.5.0/proj4.js"></script>
<script>
var apiKey = 'ufArYa1UUPHJcOYbiJDaKkA7Fb4oCkEs';
var serviceUrl = 'https://api.os.uk/maps/raster/v1/zxy';
// Setup the EPSG:27700 (British National Grid) projection.
proj4.defs("EPSG:27700", "+proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 +x_0=400000 +y_0=-100000 +ellps=airy +towgs84=446.448,-125.157,542.06,0.15,0.247,0.842,-20.489 +units=m +no_defs");
ol.proj.proj4.register(proj4);
var tilegrid = new ol.tilegrid.TileGrid({
resolutions: [ 896.0, 448.0, 224.0, 112.0, 56.0, 28.0, 14.0, 7.0, 3.5, 1.75 ],
origin: [ -238375.0, 1376256.0 ]
});
var gridReference = new ol.Feature();
gridReference.setStyle(
new ol.style.Style({
image: new ol.style.Circle({
radius: 6,
fill: new ol.style.Fill({
color: 'red'
})
}),
text: new ol.style.Text({
font: 'bold 14px sans-serif',
offsetY: -6,
textBaseline: 'bottom'
})
})
);
var postcode = new ol.Feature();
postcode.setStyle(
new ol.style.Style({
image: new ol.style.Circle({
radius: 6,
fill: new ol.style.Fill({
color: 'blue'
})
}),
text: new ol.style.Text({
font: 'bold 14px sans-serif',
offsetY: -6,
textBaseline: 'bottom'
})
})
);
// Initialize the map object.
var map = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.XYZ({
url: serviceUrl + '/Road_27700/{z}/{x}/{y}.png?key=' + apiKey,
projection: 'EPSG:27700',
tileGrid: tilegrid
})
}),
new ol.layer.Vector({
source: new ol.source.Vector({
features: [gridReference, postcode]
})
})
],
target: 'map',
view: new ol.View({
projection: 'EPSG:27700',
extent: [ -238375.0, 0.0, 900000.0, 1376256.0 ],
resolutions: tilegrid.getResolutions(),
minZoom: 0,
maxZoom: 9,
center: [ 337297, 503695 ],
zoom: 7
})
});
map.on('singleclick', function(evt) {
gridReference.setGeometry(new ol.geom.Point(evt.coordinate));
postcode.setGeometry(undefined);
var x = (Math.round(evt.coordinate[0]/10)/10) + 10000;
var y = (Math.round(evt.coordinate[1]/10)/10) + 5000;
var a1y = (4 - (Math.floor(y/5000)%5))*5;
var a2y = (4 - (Math.floor(y/1000)%5))*5;
var y1 = Math.floor(y/100)%10;
var y2 = Math.floor(y/10)%10;
var y3 = Math.floor(y)%10;
a1y += (Math.floor(x/5000)%5);
a2y += (Math.floor(x/1000)%5);
var x1 = Math.floor(x/100)%10;
var x2 = Math.floor(x/10)%10;
var x3 = Math.floor(x)%10;
var grid500km = String.fromCharCode(a1y + Math.floor((a1y+17)/25) + "A".charCodeAt(0));
var grid100km = grid500km + String.fromCharCode(a2y + Math.floor((a2y+17)/25) + "A".charCodeAt(0));
var gridText = grid100km + x1 + x2 + x3 + y1 + y2 + y3;
gridReference.getStyle().getText().setText(gridText);
var minDistSq = Infinity;
var postcodeCoord, postcodeText;
var radius = 0;
tryPoints([evt.coordinate]);
function tryPoints(coordinates) {
var promises = [];
coordinates.forEach(function(coordinate) {
promises.push(
fetch(
'https://api.os.uk/search/names/v1/nearest?point=' +
coordinate[0].toFixed(2) + ',' + coordinate[1].toFixed(2) +
'&radius=1000&fq=LOCAL_TYPE:Postcode&key=' + apiKey
).then(function(response) {
return response.json();
})
);
});
Promise.all(promises).then(function(results) {
results.forEach(function(result) {
if (result.results && result.results.length > 0) {
var entry = result.results[0]['GAZETTEER_ENTRY'];
var dx = entry['GEOMETRY_X'] - evt.coordinate[0];
var dy = entry['GEOMETRY_Y'] - evt.coordinate[1];
var distSq = dx * dx + dy * dy;
if (distSq < minDistSq) {
minDistSq = distSq;
postcodeCoord = [entry['GEOMETRY_X'], entry['GEOMETRY_Y']];
postcodeText = entry['NAME1'];
}
}
});
if (postcodeCoord) {
postcode.setGeometry(new ol.geom.Point(postcodeCoord));
postcode.getStyle().getText().setText(postcodeText);
} else if (radius < 4) {
radius++;
var outerCircle = ol.geom.Polygon.fromCircle(new ol.geom.Circle(evt.coordinate, radius * 1000), 16 * radius);
tryPoints(outerCircle.getCoordinates()[0].slice(0, -1));
}
});
}
});
</script>
</body>
</html>
I'm generating a pie chart with legend that looks like so:
As you can perceive, the pie is pitifully puny. I prefer it to be twice as tall and twice as wide.
Here is the code I am using:
var formatter = new Intl.NumberFormat("en-US");
Chart.pluginService.register({
afterDatasetsDraw: function (chartInstance) {
var ctx = chartInstance.chart.ctx;
ctx.font = Chart.helpers.fontString(14, 'bold', Chart.defaults.global.defaultFontFamily);
ctx.textAlign = 'center';
ctx.textBaseline = 'bottom';
ctx.fillStyle = '#666';
chartInstance.config.data.datasets.forEach(function (dataset) {
for (var i = 0; i < dataset.data.length; i++) {
var model = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._model,
total = dataset._meta[Object.keys(dataset._meta)[0]].total,
mid_radius = model.innerRadius + (model.outerRadius - model.innerRadius) / 2,
start_angle = model.startAngle,
end_angle = model.endAngle,
mid_angle = start_angle + (end_angle - start_angle) / 2;
var x = mid_radius * 1.5 * Math.cos(mid_angle);
var y = mid_radius * 1.5 * Math.sin(mid_angle);
ctx.fillStyle = '#fff';
if (i === 0 || i === 3 || i === 7) { // Darker text color for lighter background
ctx.fillStyle = '#666';
}
var percent = String(Math.round(dataset.data[i] / total * 100)) + "%";
// this prints the data number
// this prints the percentage
ctx.fillText(percent, model.x + x, model.y + y);
}
});
}
});
var data = {
labels: [
"Bananas (18%)",
"Lettuce, Romaine (14%)",
"Melons, Watermelon (10%)",
"Pineapple (10%)",
"Berries (10%)",
"Lettuce, Spring Mix (9%)",
"Broccoli (8%)",
"Melons, Honeydew (7%)",
"Grapes (7%)",
"Melons, Cantaloupe (7%)"
],
datasets: [
{
data: [2755, 2256, 1637, 1608, 1603, 1433, 1207, 1076, 1056, 1048],
backgroundColor: [
"#FFE135",
"#3B5323",
"#fc6c85",
"#ffec89",
"#021c3d",
"#3B5323",
"#046b00",
"#cef45a",
"#421C52",
"#FEA620"
]
}]
};
var optionsPie = {
responsive: true,
scaleBeginAtZero: true,
legend: {
display: false
},
tooltips: {
callbacks: {
label: function (tooltipItem, data) {
return data.labels[tooltipItem.index] + ": " +
formatter.format(data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index]);
}
}
}
};
var ctx = $("#top10ItemsChart").get(0).getContext("2d");
var top10PieChart = new Chart(ctx,
{
type: 'pie',
data: data,
options: optionsPie,
animation: {
duration: 0,
easing: "easeOutQuart",
onComplete: function () {
var ctx = this.chart.ctx;
ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontFamily, 'normal', Chart.defaults.global.defaultFontFamily);
ctx.textAlign = 'center';
ctx.textBaseline = 'bottom';
this.data.datasets.forEach(function (dataset) {
for (var i = 0; i < dataset.data.length; i++) {
var model = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._model,
total = dataset._meta[Object.keys(dataset._meta)[0]].total,
mid_radius = model.innerRadius + (model.outerRadius - model.innerRadius) / 2,
start_angle = model.startAngle,
end_angle = model.endAngle,
mid_angle = start_angle + (end_angle - start_angle) / 2;
var x = mid_radius * Math.cos(mid_angle);
var y = mid_radius * Math.sin(mid_angle);
ctx.fillStyle = '#fff';
if (i === 3) { // Darker text color for lighter background
ctx.fillStyle = '#444';
}
var percent = String(Math.round(dataset.data[i] / total * 100)) + "%";
// this prints the data number
ctx.fillText(dataset.data[i], model.x + x, model.y + y);
// this prints the percentage
ctx.fillText(percent, model.x + x, model.y + y + 15);
}
});
}
}
});
$("#top10Legend").html(top10PieChart.generateLegend());
How can I increase the size of the pie?
UPDATE
The "View" as requested by Nkosi is:
<div class="row" id="top10Items">
<div class="col-md-6">
<div class="topleft">
<h2 class="sectiontext">Top 10 Items</h2>
<br />
<div id="piechartlegendleft">
<div id="container">
<canvas id="top10ItemsChart"></canvas>
</div>
<div id="top10Legend" class="pieLegend"></div>
</div>
</div>
</div>
. . .
The classes "row" and "col-md-6" are Bootstrap classes.
The custom classes are "topleft":
.topleft {
margin-top: -4px;
margin-left: 16px;
margin-bottom: 16px;
padding: 16px;
border: 1px solid black;
}
...sectionText:
.sectiontext {
font-size: 1.5em;
font-weight: bold;
font-family: Candara, Calibri, Cambria, serif;
color: green;
margin-top: -4px;
}
...and "pieLegend":
.pieLegend li span {
display: inline-block;
width: 12px;
height: 12px;
margin-right: 5px;
}
You just need to change the canvas size.
When you are creating the chart you can specify it right in the element:
<canvas id="top10ItemsChart" width="1000" height="1000"></canvas>
Or if you prefer to do it in javascript
var ctx = $("#top10ItemsChart").get(0).getContext("2d");
ctx.width = 1000;
ctx.height = 1000;
If the resizing doesn't work as you wish, you can also try setting the maintainAspectRatio option to false:
var optionsPie = {
/** ... */
responsive: true,
maintainAspectRatio: false,
/** ... */
};
Hope it helps.
Using the following code to save a Google chart. But it is getting downloaded as a file and not an image, it was throwing following
"Resource interpreted as Document but transferred with MIME type image/octet-stream: "data:image/octet-stream;base64,..."
And the code:
function getImgData(chartContainer) {
var chartArea = chartContainer.getElementsByTagName('div')[1];
var svg = chartArea.innerHTML;
var doc = chartContainer.ownerDocument;
var canvas = doc.createElement('canvas');
canvas.setAttribute('width', chartArea.offsetWidth);
canvas.setAttribute('height', chartArea.offsetHeight);
canvas.setAttribute(
'style',
'position: absolute; ' +
'top: ' + (-chartArea.offsetHeight * 2) + 'px;' +
'left: ' + (-chartArea.offsetWidth * 2) + 'px;');
doc.body.appendChild(canvas);
canvg(canvas, svg);
var imgData = canvas.toDataURL("image/png");
canvas.parentNode.removeChild(canvas);
return imgData;
}
function saveAsImg(chartContainer) {
var imgData = getImgData(chartContainer);
window.location = imgData.replace("image/png", "image/octet-stream");
}
you can use an anchor tag with a download attribute to assign the file name
and most charts have a getImageURI method
also, don't see the need to replace("image/png", "image/octet-stream")
see following working snippet...
google.charts.load('current', {
callback: function () {
var chart = new google.visualization.PieChart(document.getElementById('chart_div'));
google.visualization.events.addListener(chart, 'ready', function () {
// set anchor tag
var saveLink = document.getElementById('saveLink');
saveLink.href = chart.getImageURI();
// cause download to occur
saveLink.click();
});
chart.draw(google.visualization.arrayToDataTable([
['Task', 'Hours'],
['A', 19.2],
['B', 30.8],
['C', 50.0]
]), {
height: 200,
chartArea: {
top: 24
},
legend: 'none',
pieHole: 0.4,
theme: 'maximized',
width: 200
});
},
packages: ['corechart']
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>
<a id="saveLink" download="chart.png">Save Chart</a>
I've been using Google Fusion Tables periodically for a few years, though I'm still a novice.
I've recently been charged with querying one of my tables on a geo-spatial relationship. I found a great example that functions exactly as I need it to, and updated the code with my tableId, ensured that the location column was exactly the same (spelling, capitalization, etc), but when I try to update the map layer, it gives me a permanent "Data may still be loading. Drag or refresh to find out!" on the tiles. My table is public, the data downloadable... I'm not sure what I'm missing.
I'm stumped. I've included the code below and simply used // to disable the tableid from the example.
Any assistance/suggestions would be greatly appreciated!
~Nicole
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
<title>Austin TX Delivery Locations</title>
<style>
body { font-family: Arial, sans-serif; padding: 0px; margin: 0px; }
#map_canvas { height: 80%; width:100%; }
#query{font-family:courier;}
</style>
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
<script type="text/javascript">
var tableid = '11QnfV_1v3N5GQs70e13SRxGR6_zYOSFJlCpMuD3C';
//var tableid = 790805;
function initialize() {
map = new google.maps.Map(document.getElementById('map_canvas'), {
center: new google.maps.LatLng(30.35, -97.70),
zoom: 10,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
google.maps.event.addListener(map, 'click', function(event) {
latlng = event.latLng;
updateQuery();
});
query = {
select: 'address',
from: tableid
}
layer = new google.maps.FusionTablesLayer(tableid);
layer.setMap(map);
}
function updateQuery(){
var limit = document.getElementById('limit').value;
var lat = parseInt(latlng.lat() * 1000) / 1000;
var lng = parseInt(latlng.lng() * 1000) / 1000;
query = "SELECT address FROM " + tableid;
query += " ORDER BY ST_Distance(address, LatLng(" + lat + ',' + lng + "))";
query += " LIMIT " + limit;
layer.setQuery(query);
document.getElementById('query').innerHTML = layer.getQuery();
}
</script>
</head>
<body onLoad="initialize()">
<div id="map_canvas"></div>
<input type="text" id="limit" value="50" onChange="javascript:updateQuery()"/>
<div id="query"></div>
</body>
</html>
When you see the ""Data may still be loading." message it usually means your query is invalid.
Your example has an old "numeric" table id. The syntax for the new "encrypted" table ids is different (and as currently documented)
Constructor Description
FusionTablesLayer(options:FusionTablesLayerOptions) A layer that displays data from a Fusion Table.
Change:
query = {
select: 'address',
from: tableid
}
layer = new google.maps.FusionTablesLayer(tableid);
layer.setMap(map);
To:
query = {
select: 'address',
from: tableid,
};
layer = new google.maps.FusionTablesLayer({query: query });
layer.setMap(map);
And your query in updateQuery to:
query = {
select: 'address',
from: tableid,
limit: limit,
orderBy: ST_Distance(address, LATLNG(" + lat + ',' + lng + "))"
}
layer.setQuery(query);
working fiddle
code snippet:
var tableid = '11QnfV_1v3N5GQs70e13SRxGR6_zYOSFJlCpMuD3C';
//var tableid = 790805;
var latlng;
function initialize() {
map = new google.maps.Map(document.getElementById('map_canvas'), {
center: new google.maps.LatLng(30.35, -97.70),
zoom: 10,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
google.maps.event.addListener(map, 'click', function(event) {
latlng = event.latLng;
updateQuery(latlng);
});
query = {
select: 'address',
from: tableid
};
layer = new google.maps.FusionTablesLayer({
query: query
});
layer.setMap(map);
}
google.maps.event.addDomListener(window, 'load', initialize);
function updateQuery(latlng) {
var limit = document.getElementById('limit').value;
query = {
select: 'address',
from: tableid,
limit: limit,
orderBy: 'ST_Distance(address, LATLNG(' + latlng.lat() + ',' + latlng.lng() + '))'
}
layer.setQuery(query);
var queryObj = layer.getQuery()
var queryStr = "from:" + queryObj.from + "<br>";
queryStr += "select:" + queryObj.select + "<br>";
queryStr += "limit:" + queryObj.limit + "<br>";
queryStr += "orderBy:" + queryObj.orderBy + "<br>";
document.getElementById('query').innerHTML = queryStr;
}
html,
body {
font-family: Arial, sans-serif;
padding: 0px;
margin: 0px;
height: 100%;
width: 100%;
}
#map_canvas {
height: 80%;
width: 100%;
}
<script src="https://maps.googleapis.com/maps/api/js"></script>
<div id="map_canvas"></div>
<input type="text" id="limit" value="50" onChange="javascript:updateQuery()" />
<div id="query"></div>
I'm new to Chart.js and ng2-charts. I want this functionality in chart.js to be re-written in ng2-charts. Is it even possibe?
Chart.defaults.LineWithLine = Chart.defaults.line;
Chart.controllers.LineWithLine = Chart.controllers.line.extend({
draw: function(ease) {
Chart.controllers.line.prototype.draw.call(this, ease);
if (this.chart.tooltip._active && this.chart.tooltip._active.length) {
var activePoint = this.chart.tooltip._active[0],
ctx = this.chart.ctx,
x = activePoint.tooltipPosition().x,
topY = this.chart.scales['y-axis-0'].top,
bottomY = this.chart.scales['y-axis-0'].bottom;
// draw line
ctx.save();
ctx.beginPath();
ctx.moveTo(x, topY);
ctx.lineTo(x, bottomY);
ctx.lineWidth = 2;
ctx.strokeStyle = '#07C';
ctx.stroke();
ctx.restore();
}
}
});
Here's my fiddle: https://jsfiddle.net/haq5k2mw/
You can use clipboardjs instead
Download it: https://zenorocha.github.io/clipboard.js/
You can use this method now: (require jquery)
In your html head add:
<script src="dist/clipboard.min.js"></script>
In your html code add:
<pre class="copytoclipboard">
<code class="language-html">
<h1>Hello world !</h1>
</code>
</pre>
In your page footer add:
<script>
/* Prism copy to clipbaord for all pre with copytoclipboard class */
$('pre.copytoclipboard').each(function () {
$this = $(this);
$button = $('<button>Copy</button>');
$this.wrap('<div/>').removeClass('copytoclipboard');
$wrapper = $this.parent();
$wrapper.addClass('copytoclipboard-wrapper').css({position: 'relative'})
$button.css({position: 'absolute', top: 10, right: 10}).appendTo($wrapper).addClass('copytoclipboard btn btn-default');
/* */
var copyCode = new Clipboard('button.copytoclipboard', {
target: function (trigger) {
return trigger.previousElementSibling;
}
});
copyCode.on('success', function (event) {
event.clearSelection();
event.trigger.textContent = 'Copied';
window.setTimeout(function () {
event.trigger.textContent = 'Copy';
}, 2000);
});
copyCode.on('error', function (event) {
event.trigger.textContent = 'Press "Ctrl + C" to copy';
window.setTimeout(function () {
event.trigger.textContent = 'Copy';
}, 2000);
});
});
</script>
Based on: http://webdesign.tutsplus.com/tutorials/copy-to-clipboard-made-easy-with-clipboardjs--cms-25086