Currently I’m using OmniGraffle to create a large infographic on the state of a number of projects and their dependencies. It started out quite small, but is now becoming unwieldy and the data it represents quite vast.
It occurred to me that it would be really convenient to create the base graph programmatically and then beautify manually for clarity. I’ve been learning about the OmniJS and JXA, but have real trouble finding examples that do the following:
- read a file of values (JSON, CSV, or some other standard format)
- create an new OG document
- create the graph based on the values, with shapes and colors adapted to their meaning
- saves the graph ready for further use.
During my journey through the tutorials I have learnt how to create the shapes I want, with the values and labels (in OmniJS), I have also learnt how to open a new OG document and draw a shape (JXA), but I am completely confused on how, or where (in which context) to open the file of values, read the values and plot them in the graph. Encoding an OmniJS script in JXA with embedded data seems an awfully convoluted way to solve my problem.
Is there a more straightforward way of programmatically creating a graph from values in a file?
This is what I have now:
function arrowHead(og,x,y,dx,dy) {
var a=[x,y+dy/2],
b=[x-dx,y+dy],
c=[x-dx+dy/2,y];
var arrow=og.Line({
pointList: [
a,b,c,
b,c,a,
c,a,b
],
color: [0.3,0.4,0.5],
drawsShadow: true,
thickness: 3,
strokeColor: [0.0, 0.0, 0.0]
});
return arrow;
}
function filledArrow(og,x,y,dx,dy) {
var a=[x,y+dy/2],
b=[x-dx,y+dy],
c=[x-dx+dy/2,y];
var arrow=og.Shape({
pointList: [
a,a,a,
b,b,b,
c,c,c
],
fill : "solid fill",
fillColor : [0.4,0.3,0.2],
color: [0.3,0.4,0.5],
drawsShadow: true,
thickness: 3,
strokeColor: [0.0, 0.0, 0.0]
});
return arrow;
}
function filledParallelogram(og, x, y, dx, dy) {
var a=[x,y+dy],
b=[x+dx-dy/2,y+dy],
c=[x+dx,y],
d=[x+dy/2,y];
var pp = og.Shape({
pointList: [
a,a,a,
b,b,b,
c,c,c,
d,d,d
],
fill : "solid fill",
fillColor : [0.4,0.3,0.2],
color: [0.3,0.4,0.5],
drawsShadow: true,
thickness: 3,
strokeColor: [0.0, 0.0, 0.0]
});
return pp;
}
function run() {
'use strict'
var og = Application('OmniGraffle'),
ws = og.windows,
w = ws.length ? ws[0] : undefined, // document window ?
graphics = (w && w.id() !== -1 ? w.canvas.graphics : undefined);
if (graphics) {
var shp = og.Shape({
origin: [100, 40],
size: [60, 20],
text: "Text"
});
var arr = arrowHead(og,60,40,40,20);
var farr = filledArrow(og, 100,40, 40,20);
var pp = filledParallelogram(og, 200,40,100,20);
var textRuns = (graphics.push(shp),shp.text.attributeRuns);
var arrRuns = (graphics.push(arr), arr.text.attributeRuns);
var farrRuns= (graphics.push(farr),farr.text.attributeRuns);
var ppRuns = (graphics.push(pp),pp.text.attributeRuns);
}
}
But it is not very fast, and I can see real issues when trying to do hundreds of elements this way.