How to use more than 3 column data with Google GeoChart - google-visualization

I am working on data visualization and want to show average wage and Estimated population on EVERY state of US. Now I am using google geochart for this part and I almost get the work done.
But I found out google geo chart doesn't support data which contains more than 3 columns.
Below is my work and how it looks when I run it.
function drawNewChart(){
google.charts.load('current', {
'packages':['geochart'],
// Note: you will need to get a mapsApiKey for your project.
// See: https://developers.google.com/chart/interactive/docs/basic_load_libs#load-settings
'mapsApiKey': 'my key'
});
google.charts.setOnLoadCallback(function(){
let map_data = [['State', 'Count', 'AvgWages']]
Object.getOwnPropertyNames(stateData).forEach(function(item, index){
map_data.push(['US-' + item, stateData[item].count, stateData[item].AvgWages / stateData[item].count])
})
console.log('full data', map_data)
var data = google.visualization.arrayToDataTable(map_data);
var options = {
region: "US",
resolution: "provinces"
};
var chart = new google.visualization.GeoChart(document.getElementById('chart_div'));
chart.draw(data, options);
});
}
With 3 columns it works fine and it shows this.
However I want to add 1 more column to it. (EstimatedPopulation). When I add this then it shows this error message:
Incompatible data table: Error: Table contains more columns than expected (Expecting 3 columns)
How can I solve this problem ?

Here are few solutions for your query
https://codesandbox.io/s/xjqrk659zw?file=/src/index.js:847-892
You need to define
tooltip: { isHtml: true, trigger: "visible" }
in the options
And then
{ role: "tooltip", type: "string", p: { html: true } }
in your data parameter.
Hope it will help

Related

Amplify AppSync: custom sorting and filtering with pagination

I'm trying to write a schema so that I can query models filtered by multiple keys, sorted by a custom key and paginated.
an example of my model:
type Article {
id: ID!
category: String!
area: String!
publishOn: AWSDate!
}
And an example of the query I would like to do is: retrieve all the Articles which are part of both a given category AND area, returned in descending order by publishOn in chunks of 10 items each (to implement pagination server-side, and have a lightweight UI).
The response should include also the nextToken attribute that can be used to load the "next" page of the filtered articles list.
I have multiple problems with what I can do with the automatically generated schema and can't find a way to implement manually a solution that works for all what I want to do. I try and make a list of what goes wrong:
Filtering
Let's say I want to query 10 articles that belong to the category "Holiday":
listArticles(filter: {category: {eq: "Holiday} }, limit: 10)
I won't get the first 10 articles that match that category, but instead, it seems that AppSync selects the first 10 items in the table, and then it filters these 10 items by the filter criteria.
In other words, it seems that the sequence in which filtering and sorting are applied is the opposite of what expected. Expected: firstly filter the table by the filter critaria, then return the first 10 items of the filtered result sets.
Sorting
I couldn't find a way to add sorting with AppSync, so I added searchable:
type Article (
#searchable
) {
id: ID!
category: String!
area: String!
publishOn: AWSDate!
}
Now if I sort by date, that key will be used as nextToken and brake the pagination. This is a known issue: https://github.com/aws-amplify/amplify-cli/issues/4434
Do you have any good tip on how to find a workaround to these bugs? I dag into the documentation and in couple of issue, but didn't come up with a solution that works well...
Thanks in advance,
Matteo
Filtering
You will need a Global Secondary Index in DynamoDB to achieve such a behaviour. You can create them with the #key annotation. I your case I would create a composite key consisting of the category for the partition key and area and publishOn as the sort key(s).
type Article
#model
#key(fields: ["id"])
#key(name: "byCategory", fields: ["category", "publishOn"])
#key(name: "byCategoryArea", fields: ["category", "area", "publishOn"])
{
id: ID!
category: String!
area: String!
publishOn: AWSDate!
}
Sorting
Sorting is done by the sortDirection property which is either DESC or ASC and can only be done on the sort key.
The #searchable directive enables elasticsearch on the table, which is a fulltext search engine and probably a bit pricy for small applications and wouldn't be required here unless you would want to query based on e.g. the article description text.
listArticles(filter: {category: {eq: "Holiday"} }, limit: 10, sortDirection: DESC)
Amplify AppSync: filtering with pagination
let allClubsList = async (sport) => {
try {
let clubsList;
let clubsInfoList = [];
let nextTokenInfo = null;
do{
let clubs = await client.query({
query: gql(clubBySportStatus),
variables: {
sport: sport,
eq: { status: "ACTIVE" },
},
limit: 100,
nextToken: nextTokenInfo,
fetchPolicy: "network-only",
});
clubsList = clubs.data.clubBySportStatus.items;
clubsList.forEach((item) => clubsInfoList.push(item));
nextTokenInfo = clubs.data.clubBySportStatus.nextToken;
} while (Boolean(nextTokenInfo));
if (clubsInfoList && clubsInfoList.length) {
return {
success: true,
data: clubsInfoList,
};
}
} catch (eX) {
console.error(`Error in allClubsList: ${JSON.stringify(eX)}`);
return {
success: false,
message: eX.message,
};
}
};

Chartjs doughnut chart for conditional data

As i am pretty new to Charting libraries and in my case i have been asked to implement a Chartjs library for my requirement. So i have chosen a chartjs library.
The use case i must want to know if anybody can help me then it would be a great time saver for me. Actually i am googleling since morning for this.
The actual use case is i have doughnut chart in which i am trying to show the data of a single value. As i have gone through the documentation the chartjs works on a array of data values. But my API is having only one value, means in my case its a counter variable. Assume if my maximum counter limit is say 5000 then i have to show that 5000 as a maximum counter and as the current counter is say 100 then i have to show it in the doughnut arc in red color. Means how much the graph has consumed the data something like that.
Assume total runs 5000
If runs became any count like 100 then we need to do minus from total runs - current runs count = 4900 inside the doughnut circle. As the runs increases then we need to show the reduced count runs inside the doughnut circle graph.
Once if the current runs count comes to total runs the show the circle in red color and make the count to 0.
Is this possible using Chartjs? See below picture.
There is no built-in support for doing this in Chart.js, however, it can be achieved using a very simple hack. Look at the code and try to understand, if any issues feel free to comment.
I have used chartjs-datalabels plugin to show datalabels on the pieChart.
Hope it helps!
Fiddle -> http://jsfiddle.net/y6mnkz84/7/
function drawPieChart(value, maxValue) {
var ctx = document.getElementById("myChart").getContext('2d');
var myChart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: ["Consumed"],
datasets: [{
data: [value, maxValue - value],
backgroundColor: ['green', 'red'],
}]
},
options: {
tooltips: {
enabled: false,
},
plugins: {
datalabels: {
backgroundColor: function(context) {
return context.dataset.backgroundColor;
},
display: function(context) {
var dataset = context.dataset;
var value = dataset.data[context.dataIndex];
return value > 0;
},
color: 'white'
}
}
}
});
}
drawPieChart(5000, 5000);

google chart obtaining position in select event listener

I have the following google chart:
var elms=xml.getElementsByTagName("overall")[0];
var avgs=elms.getElementsByTagName("average");
for(var i=0;i<avgs.length;i++){
chartArr[0][i+1]=avgs[i].getAttribute("name");
chartArr[1][i+1]=parseFloat(avgs[i].getAttribute("avg"));
}
var data = google.visualization.arrayToDataTable(chartArr);
var options = {
title: 'Average Club Rating',
is3D: true,
width:1200,
chartArea:{
width:800,
left:92
}
};
var chart = new google.visualization.ColumnChart(document.getElementById('averagechart'));
chart.draw(data, options);
google.visualization.events.addListener(chart, 'select', function() {
console.log(this.getPosition());
});
If you look, i first populate the charArr then i create and setup the google chart.
On the bottom, you'll see the addListener call. What I want is when that element is clicked, a custom url most likely from the chartArr is used and determines the endpoint location.
How do I get the position of the listener so i can grab the custom url which is going to be created.
I dont really sure to understand your request, but you can print the event with this method,
console.log(chart.getSelection());
Regards,

Google Visualization GeoMap with Google Analytics

Ok, so I'm really hoping someone can help me get started, I have been able to plot pies and timelines from my google analytics data via api with google visualization. I now want to extract the data from google analytics of visits and plot a geomap. This is the geomap sample code which works
google.load('visualization', '1', {packages: ['geochart']});
function drawVisualization() {
var data = google.visualization.arrayToDataTable([
['Country', 'Popularity'],
['Germany', 200],
['United States', 300],
['Brazil', 400],
['Canada', 500],
['France', 600],
['RU', 700],
['South Africa', 800]
]);
var geochart = new google.visualization.GeoChart(
document.getElementById('visualization'));
geochart.draw(data, {width: 556, height: 347});
}
google.setOnLoadCallback(drawVisualization);
but of course I want to get the var 'data' from my google analytics api into such an array and plot say the top 10 popular countries based on pageviews from the last 30 days?
I believe the following query will give me what I want
dimensions=ga:country
metrics=ga:visits
sort=-ga:visits
How do I get this into the proper format for the data variable to plot this geomap? If you can help me rewrite the var data so that it works, I could be the happiest man alive.
Thanks in advance
This function should take the data returned by Google Analytics, input it into a DataTable, and draw a GeoChart of the top 10 countries by visit count:
function drawChart(results) {
var entries = results.feed.getEntries();
var data = new google.visualization.DataTable();
data.addColumn('string', 'Country');
data.addColumn('number', 'Visits');
for (var i = 0; i < entries.length; i++) {
data.addRow([entries.getValueOf('ga:country'), parseInt(entries.getValueOf('ga:visits'))]);
}
// sort by visits, descending
var sortedRows = data.getSortedRows([{column: 1, desc: true}]);
// remove all elements after the 10th
while (sortedRows.length > 10) {
sortedRows.splice(10, 1);
}
var view = new google.visualization.DataView(data);
view.setRows(sortedRows);
var geochart = new google.visualization.GeoChart(document.getElementById('visualization'));
// draw the chart using the view
geochart.draw(view, {width: 556, height: 347});
}
You should look into using the new Google Analytics SuperProxy, it simplifies the process of getting api queries into the charts api, there are still a few bugs but very simple to setup, the youtibe video on the link below will take you through the full process. https://developers.google.com/analytics/solutions/google-analytics-super-proxy

Is there an exiting js method/library to convert regular json objects to google visualization type of js objects?

we have existing rest web services that generates json response. now we want to use google charts to show those data. google visualization api seems to expect its own json format. Is there any exiting js method/library to convert regular json objects to google visualization type of js objects? Thanks.
It really depends on what you're aiming for and what data looks like, and the google chart you want to use. I usually do the following when working with REST data and google charts.
In this example I use jQuery, but the js library you use isn't that relevant.
Say you've got the following set of data and what to show it in an areachart:
{"events":[{"event":{"timestamp":"1310926588423","service":"EsperEventProcessor.service","countAll3Sec_EsperEventProcessor":"0","server":"EsperServer"}},{"event":{"timestamp":"1310926578423","service":"EsperEventProcessor.service","countAll3Sec_EsperEventProcessor":"0","server":"EsperServer"}},{"event":{"timestamp":"1310926568423","service":"EsperEventProcessor.service","countAll3Sec_EsperEventProcessor":"0","server":"EsperServer"}},{"event":{"timestamp":"1310926558423","service":"EsperEventProcessor.service","countAll3Sec_EsperEventProcessor":"0","server":"EsperServer"}},{"event":{"timestamp":"1310926548423","service":"EsperEventProcessor.service","countAll3Sec_EsperEventProcessor":"0","server":"EsperServer"}},{"event":{"timestamp":"1310926538423","service":"EsperEventProcessor.service","countAll3Sec_EsperEventProcessor":"0","server":"EsperServer"}},{"event":{"timestamp":"1310926528423","service":"EsperEventProcessor.service","countAll3Sec_EsperEventProcessor":"0","server":"EsperServer"}},{"event":{"timestamp":"1310926518423","service":"EsperEventProcessor.service","countAll3Sec_EsperEventProcessor":"0","server":"EsperServer"}},{"event":{"timestamp":"1310926508423","service":"EsperEventProcessor.service","countAll3Sec_EsperEventProcessor":"0","server":"EsperServer"}},{"event":{"timestamp":"1310926498423","service":"EsperEventProcessor.service","countAll3Sec_EsperEventProcessor":"0","server":"EsperServer"}}]}
To do this with JQuery and JSONQuery (which can help in easy selecting specific content in your JSON data) you can do something like this:
// use the getJSON jQuery operation to get the REST data
$.getJSON(restURL, function(data) {
// use jsonquery to get all the 'event's from the JSON data
var query1 = "..event";
var rootEvent = JSONQuery(query1,data);
// manually create a datatable and fill it in the required
// way for this chart
var data2 = new google.visualization.DataTable();
data2.addColumn('string', 'Number of queries / per 10 seconds');
data2.addColumn('number', '# queries');
// each row is added based on information from the json event
// by simply iterating over the array
data2.addRows(rootEvent.length);
for (i = 0; i < rootEvent.length; i++) {
var date = new Date(parseInt(rootEvent[i]['timestamp']));
var hours = date.getHours();
var minutes = date.getMinutes();
var seconds = date.getSeconds();
var time = '';
if (hours < 10) time=time+'0'; time=time+hours+':';
if (minutes < 10) time=time+'0'; time=time+minutes+':';
if (seconds < 10) time=time+'0'; time=time+seconds;
data2.setCell(i,0,time);
data2.setCell(i,1,parseInt(rootEvent[i]['countAll3Sec_EsperEventProcessor']));
}
chart.draw(data2, {width: 400, height: 240, title: 'Requests per 10 seconds',
hAxis: {title: 'Time', titleTextStyle: {color: '#FF0000'}}
});
});