TSV file with metrics-graphics.js - javascript

i'm trying to display a graph with data from this .tsv file:
d3.tsv('GDP.tsv', function(data) {
for (var i = 0; i < data.length; i++) {
console.log(data[i]);
}
MG.data_graphic({
title: "Line Chart",
description: "This is a simple line chart. You can remove the area portion by adding area: false to the arguments list.",
data: data, /*This is very probably part of the issue*/
width: 240,
height: 128,
target: document.getElementById('graph-gdp'),
x_accessor: 'value', /*This is very probably part of the issue*/
y_accessor: 'time' /*This is very probably part of the issue*/
});
This is outputing each row as:
{na_item,unit,geo\time: "B1GQ,CP_MEUR,AL",
2005 : "6475.3 ",
2006 : "7090.8 ",
2007 : "7809.8 ",
2008 : "8800.3 ",
2009 : "8662.2 ",
2010 : "8996.6 ",
2011 : "9268.3 ",
2012 : "9585.8 ",
2013 : "9625.4 "(etc...)}
How would I do to display a single row, so selected with it's name ("B1GQ,CP_MEUR,AL", for example), and display that data on a graph, with x=year and y=value?
Sorry if this is a rather noobish question, but I'm new to .js, .tsv files, and web development in general. I've tried figuring this out by myself, but have been failing pathetically.

Once you loaded that TSV using d3.tsv, the first step is filtering the data array, getting only that row you chose:
var filtered = data.filter(d => d["na_item,unit,geo\\time"] == "B1GQ,CP_EUR_HAB,AL");
//escaping the backslash here ---------------------^
However, since that TSV has strange headers (and values as well...), remember to escape the backslash.
That filtered array has only one object, and you're not going too far away with it. Thus, the next step is converting it in an array of several objects, one for each data point, using d3.entries:
var selectedData = d3.entries(filtered[0]).filter(d => d.key != ["na_item,unit,geo\\time"])
With that array, you can create your graph.
Here is a demo code, the array is printed in the console ("key" is the year, that you're gonna use in the x axis, and "value" is the value, that you're gonna use in the y axis):
data = d3.tsvParse(d3.select("#tsv").text());
var filtered = data.filter(d => d["na_item,unit,geo\\time"] == "B1GQ,CP_EUR_HAB,AL");
var selectedData = d3.entries(filtered[0]).filter(d => d.key != ["na_item,unit,geo\\time"])
console.log(selectedData);
pre {
display: none;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<pre id="tsv">na_item,unit,geo\time 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016
B1GQ,CP_EUR_HAB,AL 2200 2400 2600 3000 3000 3100 3200 3300 3300 3400 p 3600 p :
B1GQ,CP_EUR_HAB,AT 30800 32200 34000 35100 34300 35200 36800 37600 38000 38700 39400 40000
B1GQ,CP_EUR_HAB,BE 29700 31000 32500 33100 32300 33500 34500 35100 35300 35900 36600 37400
B1GQ,CP_EUR_HAB,BG 3100 3600 4300 5000 5000 5200 5600 5700 5800 5900 p 6300 p 6600 p</pre>
PS: Again, that TSV has several problems with the values.
PPS: This answer only shows you how to filter and prepare your data array, and that only.

Related

How to create csv file from json

I have a json like
{
"connectEnd": 1366.2749999930384,
"connectStart": 175.91999999422114,
"decodedBodySize": 3360,
"domComplete": 10424.984999990556,
"domContentLoadedEventEnd": 6581.454999992275,
"domContentLoadedEventStart": 6581.454999992275,
"domInteractive": 6581.420000002254,
"domainLookupEnd": 175.91999999422114,
"domainLookupStart": 12.000000002444722,
"duration": 10425.015000000712,
"encodedBodySize": 1279,
"entryType": "navigation",
"fetchStart": 0.22499999613501132,
"initiatorType": "navigation",
"loadEventEnd": 10425.015000000712,
"loadEventStart": 10424.994999993942,
"name": "https://something/login",
"nextHopProtocol": "http/1.1",
"redirectCount": 0,
"redirectEnd": 0,
"redirectStart": 0,
"requestStart": 1366.394999990007,
"responseEnd": 2062.7999999996973,
"responseStart": 2059.7599999891827,
"secureConnectionStart": 414.94000000238884,
"serverTiming": [],
"startTime": 0,
"transferSize": 2679,
"type": "navigate",
"unloadEventEnd": 0,
"unloadEventStart": 0,
"workerStart": 0,
"workerTiming": []
}
I used papaparse to convert JSON into csv and I am getting this:
"Request time","Time to first byte","Response time","Request Response time","Cache seek plus response time","Dom interactive","Dom complete","Transfer Size","duration","Domain lookup time taken","Connection time taken"
693.3649999991758,3.040000010514632,3.040000010514632,696.4050000096904,2062.5750000035623,6581.420000002254,10424.984999990556,2679,10425.015000000712,163.91999999177642,1190.3549999988172
I am planning to use Jenkins plugin called BenchMark Evaluator
This plugin accepts csv only in this format:
csv table image link
My problem statement: How I change the structure of parsed csv into the desired csv format. Is there a npm package that can give me directly what I want or the parsed csv needs to be converted.
A more elegant way to convert json to csv is to use the map function without any framework:
var json = json3.items
var fields = Object.keys(json[0])
var replacer = function(key, value) { return value === null ? '' : value }
var csv = json.map(function(row){
return fields.map(function(fieldName){
return JSON.stringify(row[fieldName], replacer)
}).join(',')
})
csv.unshift(fields.join(',')) // add header column
csv = csv.join('\r\n');
console.log(csv)
Output:
title,description,link,timestamp,image,embed,language,user,user_image,user_link,user_id,geo,source,favicon,type,domain,id
"Apple iPhone 4S Sale Cancelled in Beijing Amid Chaos (Design You Trust)","Advertise here with BSA Apple cancelled its scheduled sale of iPhone 4S in one of its stores in China’s capital Beijing on January 13. Crowds outside the store in the Sanlitun district were waiting on queues overnight. There were incidents of scuffle between shoppers and the store’s security staff when shoppers, hundreds of them, were told that the sales [...]Source : Design You TrustExplore : iPhone, iPhone 4, Phone","http://wik.io/info/US/309201303","1326439500","","","","","","","","","wikio","http://wikio.com/favicon.ico","blogs","wik.io","2388575404943858468"
"Apple to halt sales of iPhone 4S in China (Fame Dubai Blog)","SHANGHAI – Apple Inc said on Friday it will stop selling its latest iPhone in its retail stores in Beijing and Shanghai to ensure the safety of its customers and employees. Go to SourceSource : Fame Dubai BlogExplore : iPhone, iPhone 4, Phone","http://wik.io/info/US/309198933","1326439320","","","","","","","","","wikio","http://wikio.com/favicon.ico","blogs","wik.io","16209851193593872066"
Use this less dense syntax and also JSON.stringify to add quotes to strings while keeping numbers unquoted:
const items = json3.items
const replacer = (key, value) => value === null ? '' : value // specify how you want to handle null values here
const header = Object.keys(items[0])
const csv = [
header.join(','), // header row first
...items.map(row => header.map(fieldName => JSON.stringify(row[fieldName], replacer)).join(','))
].join('\r\n')
console.log(csv)

C3js - Failed to parse x 'time' to Date object

I am constantly facing a failed to parse time to date object issue. I want to generate a graph which on the left (Y-axis) shows a probability. Say the probability is 0, 0.2, 0.4 etc.. to 1. On the graph, I would like to plot the probability of something at a specific time. The below code is what I am using.
arr1 is the array containing the probabilities.
arr5 is the array containing the timestamp for each of the probability in arr1. The time format is in "12:03:55".
The issue now is if I were to hard code the timestamps into the chart columns, the chart would display perfectly fine. However I am getting the time from a user uploaded .csv file, hence I am concatenating an array which has the timestamps. And this gives me the error of Failed to parse x '12:03:55' to Date object.
I did console.log(dataTime), so I know my concat has been performed correctly in the intended format. This is what the console.log returns.
["times", "12:03:55", "12:03:56", "12:03:56", "12:03:56", "12:03:57", "12:03:57", "12:03:58", "12:03:58", "12:03:59", "12:03:59", "12:04:00"]
This is what the console.log for dataMood returns.
["Mood", 0.3677342, 0.34968433, 0.32662648, 0.3163717, 0.78009516, 0.97079295, 0.97183245, 0.9724318, 0.9689829, 0.7293974, 0.12735543]
Below is the code I am using.
var labelMood = 'Mood';
var dataMood = [labelMood].concat(arr1);
var times = 'times';
var dataTime = [times].concat(arr5);
var chart = c3.generate({
bindto: '#line',
data: {
x: 'times',
xFormat: '%H:%M:%S',
columns: [
dataTime, dataMood
]
},
axis: {
x: {
type: 'timeseries',
tick: {
format: '%H:%M:%S'
}
}
}
});
I really can't see why this isn't working since the format of the concatenated object is the same as how I would've hard coded the times into columns. I'm at my wits end after having Googled for hours. Hopefully someone has came across this issued before and has solved it successfully.

Excel Javascript API - Add chart with Category Axis values

I am adding\inserting a Line chart to Excel via the following JS call:
var newSheet = ctx.workbook.worksheets.add();
newSheet.activate();
// populate grid
// category (axis)
var cell = newSheet.getCell(0, 0)
...
// values (axis)
cell = newSheet.getCell(0, 1)
...
var range = newSheet.getUsedRange();
newSheet.charts.add("Line", range);
My "range" data looks like this:
2012 10
2013 20
2014 30
2015 40
2016 50
The issue I'm having is each column is treated as an individual series, and 2 lines are rendered in the chart. I only want one line and the Category Axis to contain the years. Does anyone know if this is possible?
Screenshot:
Chris,
The current JavaScript API for Excel that you use to create the chart doesn't give you much control of how Excel should construct the series and axis for the chart. When using the ChartCollection.add() method, you are depending on the "smarts" of the Excel Recommended Charts algorithm, and in this particular case the, answer it comes up with as the first answer is not what you expect.
We have an item in our API backlog to provide more fine-grained control for charts similar to what is available in other Excel APIs. At this time I can't say when this will be available in the API. I encourage you to follow our open specification process to get a heads up, and an opportunity to give feedback on our designs.
As a workaround for your particular case, I would suggest that you try using date values for the first column instead of numbers. You can format the column to show only the year part of the dates:
async function run() {
try {
await Excel.run(async (context) => {
var sheet = context.workbook.worksheets.getActiveWorksheet();
let data = [
["Year", "Measure"],
["2010-12-31", 10],
["2011-12-31", 20],
["2012-12-31", 30],
["2013-12-31", 40],
["2014-12-31", 50],
];
let format = [
["#"],
["yyyy"],
["yyyy"],
["yyyy"],
["yyyy"],
["yyyy"]
];
let categories = sheet.getRange("A1:A6");
categories.numberFormat = format;
var range = sheet.getRange("A1:B6");
range.values = data;
sheet.charts.add(Excel.ChartType.line, range, Excel.ChartSeriesBy.columns);
await context.sync();
});
}
catch (error) {
OfficeHelpers.Utilities.log(error);
}
}
This snippet is written in TypeScript using async/await, but easily be translated to JavaScript.
Jakob

How do I chart the a second custom data point in Dygraphs?

I'm toying around with Dygraphs and really liking it. However I'm having trouble setting a string value for the second point. I've tried to produce it to be a date, but I would rather keep the custom format for my own date and time.
My simple chart is
new Dygraph(document.getElementById("graphdiv"),
dataload
,
{
labels: [ "x", "A" ],
title: 'Point',
ylabel: 'Value in Eng Units',
xlabel: 'Time & Date'
});
The code that provides the data into dataload is
i = 0
while ( i < 100){
datappointvalue = [ archivetime[i], archivevalue[i] ] ;
dataload.push(datapidvalue);
}
As you can guess archivetime and archivevalue are arrays that I populate.
archivetime has the format of a string "22-MAR-2016 20:20:41.26" archivevalue has the format of decimal/int "144.32".
My graph always comes out like
this - It will always get the values of archivevalue, but never archivetime.
So the question is ultimately how can I display my second value to be the date and time. I would prefer not having to reformat my archivedate into something else, but if necessary that can be done.
Thanks!
I've figured it out.
I did not realize that the x-axis had to be in a specific date format and to use new Date() in the code.
So my code is now
i = 0
while ( i < 100){
datappointvalue = [ new date(archivetime[i]), archivevalue[i] ] ;
dataload.push(datapidvalue);
}
where archivetime[i] now has the format "2016/3/17 20:20:41" as specified in http://dygraphs.com/data.html
Thanks

Javascript array to sorted html table by time

I need to transform an array to html table sorted by time, add rank and calculate time loss for the first place.
Array example:`
var array = [
["McNulty Oscar", "USA", "108:45.1"],
["Johansson Anton", "SWE", "87:48.9"],
["Schneider Florian", "SUI", "dns"],
["Rio Nicolas", "FRA", "57:45.1"]
];`
Final HTML table should look like this:
1 Rio Nicolas FRA 57:45.1
2 Johansson Anton SWE 87:55.9 30:10.8
3 McNulty Oscar USA 107:45.2 51:03.1
Schneider Florian SUI dns dns
My idea how to do it is in Jquery transform Array to HTML table and then sort it using tablesorter plugin. I still don't know when and how to calculate the time loss. Is it good way or am I totally out?
There is no simple solution to your situation, unfortunately. The values that you are dealing with are neither time values (as far as JS is concerned . . . see the JS Date object for more info on time: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date ), nor are they numbers that you can directly subtract, without manipulation.
Your best bet is to split up the values and do the subtraction in the long drawn out way . . . use var timeElements[2] = each.split(".") to get an array of the minutes/seconds/tenths-of-seconds for each value. At that point, you can either:
Do the subtraction the long way . . . subtract each value separately, carrying over values between the "columns", as needed, or
Convert the minutes and seconds into tenths of seconds, combine all three values into "total tenths-of-seconds", do the subtraction, and then convert them back to the three separate values, to get the difference.
The second option is probably the easier logic to pull off, even if it's a lot of steps.
There is also one other option, if you can do without the time differences . . . if you can prepend zeros to all of the time values, so that each of the minutes, seconds and tenths-of-seconds always have the same number of characters, AND if "dns" is the only other value that will ever occur, besides a time, a direct < comparison of the strings will still actually work for sorting, due to the way that greater than/less than works when used on strings. For example:
"057:45.1" is less than "087:48.9"
"087:48.9" is less than "108:45.1"
"108:45.1" is less than "123.54.7"
"123.54.7" is less than "243.04.6"
"243.04.6" is less than "dns"
This really isn't an optimal approach . . . it doesn't take much to throw off this kind of string comparison . . . but it's still worth mentioning, if you can be very sure of the values that you are getting.
. . . and if you can skip that whole "time difference" part of it. :D
I put together this demo using tablesorter and the tablesorter build table widget.
HTML
<div id="result"></div>
Script
$(function () {
var array = [
["Name", "Country", "Time", "Diff"],
["McNulty Oscar", "USA", "108:45.1", ""],
["Johansson Anton", "SWE", "87:48.9", ""],
["Schneider Florian", "SUI", "dns", ""],
["Rio Nicolas", "FRA", "57:45.1", ""]
],
// time column (zero-based index)
timeColumn = 3,
diffColumn = 4,
// convert min:sec.ms => sec.ms
convertTime = function (time) {
var val;
if (time && /:/.test(time)) {
val = time.split(':');
return parseFloat(val[0] || 0) * 60 + parseFloat(val[1] || 0);
} else {
return Number.POSITIVE_INFINITY;
}
},
// convert sec.ms => min:sec.ms
formatTime = function (time) {
var minutes = parseInt(time / 60);
return minutes + ':' + (time - (minutes * 60)).toFixed(1);
},
calculateDiff = function (table) {
var $tds, minTime,
$table = $(table),
$trs = $table.children('tbody').children(),
times = [];
$trs.each(function () {
$tds = $(this).children();
times.push(convertTime($tds.eq(timeColumn).text()));
});
minTime = Math.min.apply(Math, times);
$trs.each(function (i) {
var diff = times[i] - minTime,
result = times[i] === Number.POSITIVE_INFINITY ? 'dns' :
diff === 0 ? '' : formatTime(diff);
$(this).children()
.eq(0).html(result !== 'dns' ? i + 1 : '').end()
.eq(diffColumn).html(result);
})
.trigger('update');
};
$('#result').tablesorter({
theme: 'blue',
emptyTo: 'zero',
widgets: ['zebra', 'build'],
sortList: [[3, 0]],
widgetOptions: {
build_source: array,
build_footers: {
rows: 0
},
build_numbers: {
// include row numbering column?
addColumn: "Rank",
// make column sortable?
sortable: true
}
},
initialized: function (table) {
calculateDiff(table);
}
});
});
Update: Modified code and demo to include rank column and sort.

Categories