StackGenVis: Alignment of Data, Algorithms, and Models for Stacking Ensemble Learning Using Performance Metrics
https://doi.org/10.1109/TVCG.2020.3030352
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
210 lines
6.4 KiB
210 lines
6.4 KiB
/* global d3:false */
|
|
/* global describe:false, it:false, expect:false fail:false beforeEach:false, afterEach:false */
|
|
|
|
/*
|
|
* N.B. these test assert ./index.js which itself requires dist/*,
|
|
* so make sure to run `npm start` before `npm test` to test new topojson files
|
|
*
|
|
*/
|
|
|
|
var saneTopojson = require('../')
|
|
var assets = require('./assets')
|
|
var topojson = require('topojson')
|
|
var diff = require('fast-array-diff').diff
|
|
|
|
describe('sane topojson general', () => {
|
|
it('should have correct test environments', () => {
|
|
expect(d3.version).toEqual('3.5.17')
|
|
expect(Object.keys(saneTopojson)).toEqual(Object.keys(assets.GEOMETRY_COUNT))
|
|
})
|
|
|
|
it('should have all the correct layers', () => {
|
|
Object.keys(saneTopojson).forEach((k) => {
|
|
var saneTopojsonItem = saneTopojson[k]
|
|
|
|
expect(Object.keys(saneTopojsonItem)).toEqual([
|
|
'type', 'objects', 'arcs', 'transform', 'bbox'
|
|
])
|
|
|
|
expect(Object.keys(saneTopojsonItem.objects)).toEqual([
|
|
'coastlines', 'land', 'ocean', 'lakes',
|
|
'rivers', 'countries', 'subunits'
|
|
])
|
|
|
|
var objs = saneTopojsonItem.objects
|
|
Object.keys(objs).forEach((l) => {
|
|
expect(Object.keys(objs[l])).toEqual(['type', 'geometries'])
|
|
})
|
|
})
|
|
})
|
|
|
|
it('should have correct number of geometries per layer', () => {
|
|
Object.keys(saneTopojson).forEach((k) => {
|
|
var objs = saneTopojson[k].objects
|
|
|
|
Object.keys(objs).forEach((l) => {
|
|
expect(objs[l].geometries.length).toBe(assets.GEOMETRY_COUNT[k][l], [k, l])
|
|
})
|
|
})
|
|
})
|
|
|
|
it('should have a minimal set of *properties*', () => {
|
|
Object.keys(saneTopojson).forEach((k) => {
|
|
var objs = saneTopojson[k].objects
|
|
|
|
Object.keys(objs).forEach((l) => {
|
|
var o = objs[l]
|
|
var list = []
|
|
|
|
switch (l) {
|
|
case 'coastlines':
|
|
case 'land':
|
|
case 'ocean':
|
|
case 'lakes':
|
|
case 'rivers':
|
|
o.geometries.forEach(function (g, i) {
|
|
var msg = [k, l, i]
|
|
|
|
expect(Object.keys(g).length).toBe(2, 'just two fields| ' + msg)
|
|
expect(Array.isArray(g.arcs)).toBe(true, '*arcs* is an array| ' + msg)
|
|
expect(typeof g.type === 'string').toBe(true, '*type* is a string |' + msg)
|
|
})
|
|
break
|
|
case 'countries':
|
|
case 'subunits':
|
|
var expNumOfProps = { countries: 1, subunits: 2 }[l]
|
|
|
|
o.geometries.forEach(function (g, i) {
|
|
var msg = [k, l, i]
|
|
var p = g.properties
|
|
|
|
if (p) {
|
|
expect(Object.keys(g).length).toBe(4, 'four fields| ' + msg)
|
|
expect(typeof g.id === 'string').toBe(true, '*id* is a string| ' + msg)
|
|
|
|
var pLen = Object.keys(p).length
|
|
expect(pLen).toBe(expNumOfProps, '# properties field| ' + msg)
|
|
expect(Array.isArray(p.ct)).toBe(true, '*properties.ct* is an array| ' + msg)
|
|
if (pLen > 1) {
|
|
expect(typeof p.gu === 'string').toBe(true, '*properties.gu* is a string| ' + msg)
|
|
}
|
|
|
|
list.push(g.id)
|
|
} else {
|
|
expect(Object.keys(g).length).toBe(2, 'just two fields| ' + msg)
|
|
}
|
|
|
|
expect(Array.isArray(g.arcs)).toBe(true, '*arcs* is an array| ' + msg)
|
|
expect(typeof g.type === 'string').toBe(true, '*type* is a string| ' + msg)
|
|
})
|
|
break
|
|
default:
|
|
fail('Unknown layer ' + l + ' in topojson ' + k)
|
|
break
|
|
}
|
|
|
|
switch (l) {
|
|
case 'countries':
|
|
expect(list.length).toBe(assets.COUNTRIES_CNT[k], '# of countries| ' + [k, l])
|
|
break
|
|
case 'subunits':
|
|
expect(list.length).toBe(assets.SUBUNITS_CNT[k], '# of subunits| ' + [k, l])
|
|
break
|
|
}
|
|
})
|
|
})
|
|
})
|
|
|
|
it('should have correct set of country IDs', () => {
|
|
Object.keys(saneTopojson).forEach((k) => {
|
|
var actual = saneTopojson[k].objects.countries.geometries
|
|
.map(g => g.id).filter(Boolean).sort()
|
|
var d = diff(assets.COUNTRY_LIST[k], actual)
|
|
expect(d.removed).withContext('removed country for list| ' + k).toEqual([])
|
|
expect(d.added).withContext('added country for list| ' + k).toEqual([])
|
|
})
|
|
})
|
|
|
|
it('should have correct set of subunit IDs', () => {
|
|
Object.keys(saneTopojson).forEach((k) => {
|
|
var actual = saneTopojson[k].objects.subunits.geometries
|
|
.map(g => g.id).filter(Boolean).sort()
|
|
var d = diff(assets.SUBUNITS_LIST[k], actual)
|
|
expect(d.removed).withContext('removed subunit for list| ' + k).toEqual([])
|
|
expect(d.added).withContext('added subunit for list| ' + k).toEqual([])
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('sane topojson with d3-geo & topojson', () => {
|
|
beforeEach(() => {
|
|
this.svg = d3.select('body').append('svg')
|
|
.attr('width', 960)
|
|
.attr('height', 500)
|
|
})
|
|
|
|
afterEach(() => {
|
|
document.body.removeChild(this.svg.node())
|
|
})
|
|
|
|
describe('should be able to draw path all layers', () => {
|
|
Object.keys(saneTopojson).forEach((k) => {
|
|
var saneTopojsonItem = saneTopojson[k]
|
|
|
|
Object.keys(d3.geo).forEach((p) => {
|
|
var projFunc = d3.geo[p]
|
|
|
|
if (!(
|
|
typeof projFunc === 'function' &&
|
|
projFunc.raw !== undefined
|
|
)) return
|
|
|
|
it('in topojson ' + k + ' using projection function ' + p, () => {
|
|
appendLayers(this.svg, projFunc, saneTopojsonItem)
|
|
|
|
var paths = this.svg.selectAll('path')
|
|
|
|
expect(paths.size()).toEqual(7)
|
|
|
|
paths.each(function () {
|
|
var path = d3.select(this)
|
|
|
|
var l = path.attr('id')
|
|
|
|
if (
|
|
l === 'subunits' &&
|
|
assets.ITEM_WITH_NO_SUBUNITS.indexOf(k) !== -1
|
|
) {
|
|
expect(path.attr('d')).toBe(null)
|
|
} else {
|
|
expect(path.attr('d').length > 1).toBe(true)
|
|
}
|
|
})
|
|
})
|
|
})
|
|
})
|
|
})
|
|
})
|
|
|
|
function appendLayers (svg, projFunc, saneTopojsonItem) {
|
|
var width = +svg.attr('width')
|
|
var height = svg.attr('height')
|
|
|
|
var projection = projFunc()
|
|
.translate([width / 2, height / 2])
|
|
.precision(0.1)
|
|
|
|
var path = d3.geo.path().projection(projection)
|
|
|
|
Object.keys(saneTopojsonItem.objects).forEach((l) => {
|
|
var datum = topojson.feature(
|
|
saneTopojsonItem,
|
|
saneTopojsonItem.objects[l]
|
|
)
|
|
|
|
svg.append('path')
|
|
.datum(datum)
|
|
.attr('d', path)
|
|
.attr('id', l)
|
|
})
|
|
}
|
|
|