calcuvizspec = ({
models,
introspections = [],
input_cursors,
mark,
encodings,
width,
height,
spec_post_process = (spec) => spec
}) => {
if (!models.length) return;
let encodings_for_cql = Object.entries(encodings)
.filter(([k, v]) => k != "detail_only_proj")
.map(([k, v]) => ({
type: v.type ?? "nominal",
channel: k,
field: v.name ?? v
}));
let input_domains = {};
let input_domains2 = Object.values(encodings).filter(
({ name }) => name == "formulae" || name.substr(-3) == "_in"
);
input_domains2.forEach(({ name, domain }) => {
input_domains[name] = domain;
}); // follow from encodings names
//.map(({name, domain}) => ({[name]:domain}))
// outputs should depend on specified formulae, or domain of 'formulae', other?
let outputs = [
/*specified formulae mapped to channels*/ ...Object.values(encodings)
.map((d) => d.name)
.filter(
(name) =>
name != "formula" &&
name != "value" &&
name != "input_cursor_id" &&
name.substr(-3) != "_in"
) /*'formula' with domains mapped to channels*/
];
let outputs2 = Object.values(encodings)
.filter(({ name }) => name == "formula")
.map((d) => d.domain);
if (outputs2.length) outputs = [...outputs, ...outputs2[0]];
//return outputs2
//return outputs
let data = calcudata({
models,
introspections,
input_domains,
input_cursors,
outputs,
pivot:
Object.values(encodings).filter((d) => d.name == "formula").length == 0
});
/*return ({
models,
introspections,
input_domains,
input_cursors,
outputs,
pivot:true
})*/
let schema = cql.schema.build(data);
//return encodings_for_cql
let cql_output = cql.recommend(
{
spec: {
data,
mark, // bar/line override?
encodings: encodings_for_cql
},
chooseBy: "effectiveness"
},
schema
);
let vlTree = cql.result.mapLeaves(cql_output.result, function (item) {
return item; //.toSpec();
});
let c_spec = vlTree.items[0].toSpec();
//return c_spec // done ! todo bring some customizations together
c_spec.data = { name: "data" };
//s.width = /*viz.width ??*/ 500;
//s.height = spec.height;
c_spec.datasets = { data /*.filter(d => d.y>-100)*/ };
//var r = {}
// todo independent scales Object.entries(viz_spec.independent_scales).filter(([k,v]) => v == true).forEach(([k,v]) => { r[k] = 'independent' })
//s.resolve = {scale: r}
/// NEEDED? if (spec.mark == "bar") s.mark = "bar"; //{"type": "bar", "tooltip": true};
if (typeof mark === "string") mark = { type: mark, tooltip: true };
else if (mark.tooltip == undefined) mark.tooltip = true;
c_spec.mark = mark; //{type: mark, tooltip:true}
//if (spec.mark == "line") {s.mark.point = true; s.encoding.order={field:spec.channels.detail_only_proj}/*s.encoding.size = {value:20}*/}
//if (spec.mark == "point") {s.encoding.size = {value:100};
//s.mark.strokeWidth = 5};
//s["config"] ={"legend": {"disable": true}}
//s['encoding']['x']['axis']['labelAngle'] = 0 //.x.axis.labelAngle=0// = {"orient": "top", "labelAngle":0};
if (width) c_spec.width = width;
if (height) c_spec.height = height;
if (encodings.x?.name == "formula")
c_spec.encoding.x.axis = { labelAngle: 0, orient: "top", labelLimit: 90 };
if (encodings.row?.name == "formula")
c_spec.encoding.row.header = { labelLimit: 70 };
// TODO allow for interactions of options below!
Object.entries(encodings).forEach(([v, e]) => {
if (e.format) {
c_spec.encoding[v].format = e.format;
if (c_spec.encoding[v].axis == undefined)
c_spec.encoding[v].axis = { format: e.format };
}
if (e.scale) c_spec.encoding[v].scale = e.scale;
if (e.sort) c_spec.encoding[v].sort = e.sort;
if (e.zero != undefined) c_spec.encoding[v].scale = { zero: e.zero };
if (e.nice != undefined) c_spec.encoding[v].scale = { nice: e.nice };
if (e.grid != undefined) c_spec.encoding[v].axis = { grid: e.grid };
if (e.legend == false) c_spec.config = { legend: { disable: true } };
if (e.legend == null && e.legend != undefined)
c_spec.encoding[v].legend = null; // replace above line if working?
if (e.independent) c_spec.resolve = { scale: { [v]: "independent" } };
});
// optional legends?
return spec_post_process(c_spec);
}