Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
20 changed files
with
5,348 additions
and
1,674 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,4 +17,4 @@ indent_size = 2 | |
[*.tsx] | ||
indent_size = 2 | ||
[*.json] | ||
indent_size = 4 | ||
indent_size = 2 |
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
.cache | ||
build | ||
dist | ||
node_modules | ||
yarn-error.log |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
.cache | ||
.DS_Store | ||
.gitignore | ||
.prettierrc.json | ||
.travis.yml | ||
.vscode | ||
concat_lp.sh | ||
demo | ||
dist | ||
node_modules | ||
rollup.config.js | ||
test | ||
tsconfig.json | ||
tslint.json | ||
yarn-error.log |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
{ | ||
"overrides": [ | ||
{ | ||
"files": "*.ts", | ||
"options": { | ||
"printWidth": 120, | ||
"parser": "typescript", | ||
"singleQuote": true, | ||
"trailingComma": "es5" | ||
} | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Draco Core | ||
|
||
JavaScript module with the Draco knowledge base and helper functions to convert from ASP to Vega-Lite and vice-versa. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
{ | ||
"name": "draco-core", | ||
"description": "Visualization Knowledge as Constraints.", | ||
"version": "0.0.1", | ||
"author": "Dominik Moritz", | ||
"license": "BSD-3-Clause", | ||
"dependencies": { | ||
"vega-lite": "^3.0.0-rc8" | ||
}, | ||
"devDependencies": { | ||
"@types/jest": "^23.3.9", | ||
"jest": "^23.6.0", | ||
"prettier": "^1.14.3", | ||
"ts-jest": "^23.10.4", | ||
"typescript": "^3.1.4" | ||
}, | ||
"scripts": { | ||
"test": "jest", | ||
"concat": "bash scripts/concat_lp.sh ../asp build", | ||
"build": "rm -rf build && tsc && concat", | ||
"format": "tslint -p . --fix && prettier --write '{src,test}/**/*.ts'", | ||
"lint": "tslint -p . && prettier --list-different '{src,test}/**/*.ts'" | ||
}, | ||
"jest": { | ||
"transform": { | ||
"^.+\\.tsx?$": "ts-jest" | ||
}, | ||
"testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$", | ||
"moduleFileExtensions": [ | ||
"ts", | ||
"tsx", | ||
"js", | ||
"jsx", | ||
"json", | ||
"node" | ||
], | ||
"testPathIgnorePatterns": [ | ||
"node_modules", | ||
"<rootDir>/build", | ||
"src" | ||
] | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
# usage: ./concat_lp.sh srcdir destdir | ||
|
||
declare -a files=("topk-lua" | ||
"define" | ||
"generate" | ||
"hard" | ||
"soft" | ||
"weights" | ||
"assign_weights" | ||
"optimize" | ||
"output" | ||
) | ||
|
||
output="" | ||
newline=$'\n\n' | ||
|
||
for file in "${files[@]}" | ||
do | ||
path="${1}/${file}.lp" | ||
lp=$(cat $path | sed -e s/\`/\'/g) | ||
const=$(echo $file | tr a-z A-Z | tr \- _) | ||
output+="export const ${const}: string = \`${lp}\`;${newline}" | ||
done | ||
|
||
echo "$output" > $2/constraints.ts |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
import { TopLevelFacetedUnitSpec } from 'vega-lite/build/src/spec'; | ||
|
||
const REGEX = /(\w+)\(([\w\.\/]+)(,([\w\.]+))?\)/; | ||
|
||
/** | ||
* Convert from ASP to Vega-Lite. | ||
*/ | ||
export function asp2vl(facts: string[]): TopLevelFacetedUnitSpec { | ||
let mark = ''; | ||
let url = 'data/cars.json'; // default dataset | ||
const encodings: { [enc: string]: any } = {}; | ||
|
||
for (const value of facts) { | ||
// TODO: Better handle quoted fields. We currently simply remove all ". | ||
const cleanedValue = value.replace(/\"/g, ''); | ||
const negSymbol = value.trim().startsWith(':-'); // TODO: remove this | ||
const [_, predicate, first, __, second] = REGEX.exec(cleanedValue) as any; | ||
|
||
if (predicate === 'mark') { | ||
mark = first; | ||
} else if (predicate === 'data') { | ||
url = first; | ||
} else if (predicate !== 'violation') { | ||
if (!encodings[first]) { | ||
encodings[first] = {}; | ||
} | ||
// if it contains the neg symbol, and the field is a boolean field, its value would be false | ||
// e.g., for the case ":- zero(e3)" | ||
encodings[first][predicate] = second || !negSymbol; | ||
} | ||
} | ||
|
||
const encoding: { [channel: string]: any } = {}; | ||
|
||
for (const e of Object.keys(encodings)) { | ||
const enc = encodings[e]; | ||
|
||
// if quantitative encoding and zero is not set, set zero to false | ||
if (enc.type === 'quantitative' && enc.zero === undefined && enc.bin === undefined) { | ||
enc.zero = false; | ||
} | ||
|
||
const scale = { | ||
...(enc.log ? { type: 'log' } : {}), | ||
...(enc.zero === undefined ? {} : enc.zero ? { zero: true } : { zero: false }), | ||
}; | ||
|
||
encoding[enc.channel] = { | ||
type: enc.type, | ||
...(enc.aggregate ? { aggregate: enc.aggregate } : {}), | ||
...(enc.field ? { field: enc.field } : {}), | ||
...(enc.stack ? { stack: enc.stack } : {}), | ||
...(enc.bin !== undefined ? { bin: { maxbins: +enc.bin } } : {}), | ||
...(Object.keys(scale).length ? { scale } : {}), | ||
}; | ||
} | ||
|
||
return { | ||
$schema: 'https://vega.github.io/schema/vega-lite/v3.json', | ||
data: { url: `${url}` }, | ||
mark, | ||
encoding, | ||
} as TopLevelFacetedUnitSpec; | ||
} | ||
|
||
/** | ||
* Get the array of witnesses from clingo output. | ||
* Return undefined if no witnesses were found. | ||
*/ | ||
export function getModels(result: any) { | ||
return (result.Call || []).reduce((arr: any[], el: any) => { | ||
el.Witnesses.forEach((d: any) => | ||
arr.push({ | ||
facts: d.Value, | ||
costs: d.Costs, | ||
}) | ||
); | ||
return arr; | ||
}, []); | ||
} | ||
|
||
export function models2vl(models: any[]) { | ||
return models.map(model => asp2vl(model.facts)); | ||
} | ||
|
||
/** | ||
* Convert from Vega-Lite to ASP. | ||
*/ | ||
export function vl2asp(spec: TopLevelFacetedUnitSpec): string[] { | ||
const facts = [`mark(${spec.mark})`]; | ||
|
||
if ('data' in spec && 'url' in spec.data) { | ||
facts.push(`data("${spec.data.url}")`); | ||
} | ||
|
||
const encoding = spec.encoding || {}; | ||
|
||
let i = 0; | ||
for (const channel of Object.keys(encoding)) { | ||
const eid = `e${i++}`; | ||
facts.push(`encoding(${eid})`); | ||
facts.push(`channel(${eid},${channel})`); | ||
|
||
let encFieldType = null; | ||
let encZero = null; | ||
let encBinned = null; | ||
|
||
// translate encodings | ||
for (const field of Object.keys(encoding[channel])) { | ||
const fieldContent = encoding[channel][field]; | ||
if (field === 'type') { | ||
encFieldType = fieldContent; | ||
} | ||
if (field === 'bin') { | ||
encBinned = fieldContent; | ||
} | ||
if (field === 'scale') { | ||
// translate two boolean fields | ||
if ('zero' in fieldContent) { | ||
encZero = fieldContent.zero; | ||
if (fieldContent.zero) { | ||
facts.push(`zero(${eid})`); | ||
} else { | ||
facts.push(`:- zero(${eid})`); | ||
} | ||
} | ||
if ('log' in fieldContent) { | ||
if (fieldContent.log) { | ||
facts.push(`log(${eid})`); | ||
} else { | ||
facts.push(`:-log(${eid})`); | ||
} | ||
} | ||
} else if (field === 'bin') { | ||
facts.push(`${field}(${eid},${fieldContent.maxbins})`); | ||
} else if (field === 'field') { | ||
// fields can have spaces and start with capital letters | ||
facts.push(`${field}(${eid},"${fieldContent}")`); | ||
} else { | ||
// translate normal fields | ||
facts.push(`${field}(${eid},${fieldContent})`); | ||
} | ||
} | ||
|
||
if (encFieldType === 'quantitative' && encZero === null && encBinned === null) { | ||
facts.push(`zero(${eid})`); | ||
} | ||
} | ||
|
||
return facts; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
import { asp2vl, vl2asp } from '../src'; | ||
import { aspSpecs, vlSpecs } from './specs'; | ||
|
||
test('asp2vl and vl2asp work', () => { | ||
for (let i = 0; i < vlSpecs.length; i++) { | ||
const aspSpec = aspSpecs[i]; | ||
const vlSpec = vlSpecs[i]; | ||
expect([asp2vl(aspSpec), vl2asp(vlSpec).sort()]).toEqual([vlSpec, aspSpec.sort()]); | ||
} | ||
}); | ||
|
||
test('parses results correctly', () => { | ||
expect( | ||
asp2vl([ | ||
'mark(bar)', | ||
|
||
'encoding(e0)', | ||
'channel(e0,x)', | ||
'field(e0,"foo")', | ||
'type(e0,ordinal)', | ||
|
||
'encoding(e1)', | ||
'channel(e1,y)', | ||
'aggregate(e1,count)', | ||
'type(e1,quantitative)', | ||
'zero(e1)', | ||
]) | ||
).toEqual({ | ||
$schema: 'https://vega.github.io/schema/vega-lite/v3.json', | ||
data: { url: 'data/cars.json' }, | ||
mark: 'bar', | ||
encoding: { | ||
x: { field: 'foo', type: 'ordinal' }, | ||
y: { aggregate: 'count', type: 'quantitative', scale: { zero: true } }, | ||
}, | ||
}); | ||
}); | ||
|
||
test('generates correct asp', () => { | ||
expect( | ||
vl2asp({ | ||
$schema: 'https://vega.github.io/schema/vega-lite/v3.json', | ||
data: { url: 'data/cars.json' }, | ||
mark: 'bar', | ||
encoding: { | ||
x: { field: 'foo', type: 'ordinal' }, | ||
y: { aggregate: 'count', type: 'quantitative', scale: { zero: true } }, | ||
}, | ||
}).sort() | ||
).toEqual( | ||
[ | ||
'data("data/cars.json")', | ||
'mark(bar)', | ||
|
||
'encoding(e0)', | ||
'channel(e0,x)', | ||
'field(e0,"foo")', | ||
'type(e0,ordinal)', | ||
|
||
'encoding(e1)', | ||
'channel(e1,y)', | ||
'aggregate(e1,count)', | ||
'type(e1,quantitative)', | ||
'zero(e1)', | ||
].sort() | ||
); | ||
}); |
Oops, something went wrong.