uwdata / gemini

A grammar and recommender system for animated transitions in Vega/Vega-Lite
BSD 3-Clause "New" or "Revised" License
103 stars 6 forks source link

Gemini²

Gemini² extends Gemini to support keyframe-oriented animated transition between single-view Vega/Vega-Lite charts. This repository contains the source code of Gemini and Gemini².

Compile And Play Animated Transitions With The Gemini Grammar

<head>
  <script src="https://cdn.jsdelivr.net/npm/vega@5"></script>
  <script src="https://cdn.jsdelivr.net/npm/vega-lite@4"></script>
  <script src="https://cdn.jsdelivr.net/npm/vega-embed@6"></script>
  <script src="https://d3js.org/d3.v6.min.js"></script>
  <script src="https://github.com/uwdata/gemini/raw/master/./gemini.web.js" ></script>

</head>
<body>
  <div id="view"></div>
  <script>

  const gemSpec = {
    "timeline": {
      "sync": [
        {"component": {"axis": "x"}, "timing": {"duration": 1000}},
        {"component": {"mark": "marks"}, "timing": {"duration": 1000}}
      ]
    }
  };
  const data = { values: [{"Hungry": 50, "Name": "Gemini"}, {"Hungry": 100, "Name": "Cordelia"}] };
  const sSpec = {
    data: data,
    mark: "bar",
    encoding: {
      x: { field: "Hungry", type: "quantitative"},
      y: { field: "Name", type: "nominal"}
    }
  }
  const eSpec = {
    data: data,
    mark: "bar",
    encoding: {
      x: { field: "Hungry", type: "quantitative"},
      y: { field: "Name", type: "nominal"}
    }
  }
  vegaEmbed("#view", sSpec, {renderer: "svg"})
  async function play() {
    let anim = await gemini.animate(sSpec, eSpec, gemSpec);
    await anim.play("#view")
  }

  </script>
</body>

Gemini APIs


Animate

# gemini.animate(start, end, spec) <>

Compile the Gemini spec for the transition between the start and end Vega visualizations to an Animation object.

Input

Parameter Type Description
start Object A Vega/Vega-Lite visualization spec* for the start state.
end Object A Vega/Vega-Lite visualization spec* for the end state.
spec Object A Gemini spec for the animation design.

*📢 Notes

See more details here.

Output

It returns a promise that triggers then with an animation object when it compiles successfully. The animation object can be played.

# gemini.animateSequence(chartSequence, animSpecs) <>

Compile the Gemini specs for the Vega chart sequence to an AnimationSequence object.

Input

Parameter Type Description
chartSequence Array An array Vega/Vega-Lite visualization specs. The compiled animation will uses them as keyframes.
animSpecs Array An array of Gemini animation specs for adjacent keyframes. For a sequence of N visualizations, N-1 Gemini specs are required.

Output

It returns a promise that triggers then with an animationSequence object when it compiles successfully. The animationSequence object can be played.

# animation.play(target) <>

Play the compiled animation at the place where the start Vega visualization is embedded.

Input

Parameter Type Description
target String A CSS selector string to select the target DOM. The start Vega visualization must be embedded at the target DOM.

Output

It returns a promise that triggers then when it completes the animation play. The promise has no success value.


Automate

# gemini.recommend(start, end, options) <>

Enumerates the candidate animation designs of the transition between the given two Vega visualizations in Gemini grammar. It sorts the candidates by their evaluated effectiveness.

Input

Parameter Type Description
start Object A Vega visualization spec for the start state.
end Object A Vega visualization spec for the end state.
options Object Options for the recommendations. See below.
let options = {
  stageN: ...,
  scales: {
    __scaleName__: { domainDimension: ... },
    ...
  },
  marks: {
    __markName__: { change: { data: [ ... ] } },
    ...
  },
  totalDuration: ...,
  includeMeta: ...
}
Property Type Description
stageN Integer The number of stages of the recommended animation design.(Default: 2)
totalDuration Number The total duration of the recommended animation design in milliseconds. (Default: 2000ms)
scales Object Set change.domainDimension of the scale(__scaleName__)'s corresponding axis component.
marks Object Set change.data of the corresponding mark component (__markName__). (Default: undefined which using the indices of the data as the join key.)
includeMeta Bool Include the meta information such as evaluated costs of each step and the whole design. (Default: false)

Output

It returns an array of objects ({spec: ...}), where spec is the Gemini spec.

# gemini.canRecommend(start, end, stageN) <>

Determine if the given inputs are valid to get recommendations.

Input

Parameter Type Description
start Object A Vega/Vega-Lite visualization spec for the start state.
end Object A Vega/Vega-Lite visualization spec for the end state.
stageN Number The number of stages for recommendations.

Output

{
  "result": false, // boolean. true: Gemini can recommend, false: cannot
  "reason": ... // string or undefined when result===true.
}

# gemini.recommendForSeq(sequence, options) <>

Enumerates the candidate animation designs of given Vega/Vega-Lite visualization sequence (keyfreame sequence). It sorts the candidates by their evaluated effectiveness.

Input

Parameter Type Description
sequence Array An Vega/Vega-Lite visualization array.
options Object Options for the recommendations. Same as the .recommend's options.

Output

{
  "specs": [ {"spec": geminiSpec, ... }, ...],
  "cost": Number //total complexity of the gemini specs
}

# gemini.canRecommendForSeq(sequence) <>

Determine if the given inputs are valid to get recommendations.

Input

Parameter Type Description
sequence Array An array of Vega/Vega-Lite visualization specs.

Output

{
  "result": false, // boolean. true: Gemini can recommend, false: cannot
  "reason": ... // string or undefined when result===true.
}

# gemini.recommendKeyframes(start, end, keyframeM) <>

By leveraging GraphScape, it enumerates the candidate keyframe sequences (Vega-Lite visualization sequences) for given start and end Vega-Lite charts. It sorts the candidates by their evaluated effectiveness.

Input

Parameter Type Description
start Object A Vega-Lite visualization spec for the start state.
end Object A Vega-Lite visualization spec for the end state.
keyframeM Number The number of sub-transitions between adjacent keyframes. For example, keyframeM=2 means to 3 keyframes per sequence. If it is undefined, it returns all possible keyframe sequences with key-value pair.

Output

If keyframeM is specified, it returns a path array (Array<Path>). If not, it returns object having possible keyframeMs and corresponding paths as keys and values({ "1": Array<Path>, "2": ..., ...})

Each Path has these properties:

{
  "sequence": [startChart, ..., endChart ],
  // The partition of the edit operations from the start and the end.
  "editOpPartition": [editOpArray1, ..., editOpArrayM],

  "eval": {
    // GraphScape's heuristic evaluation score for this path. Higher means better.
    "score": 1, //Number
    "satisfiedRules": ... // The reasons for the scores.
  }
}

# gemini.canRecommendKeyframes(start, end) <>

Determine if the given inputs are valid to get recommendations.

Input

Parameter Type Description
start Object A Vega/Vega-Lite visualization spec for the start state.
end Object A Vega/Vega-Lite visualization spec for the end state.

Output

{
  "result": false, // boolean. true: Gemini can recommend, false: cannot
  "reason": ... // string or undefined when result===true.
}

# gemini.recommendWithPath(start, end, option) <>

Enumerates the candidate keyframe sequences (Vega-Lite visualization sequences) with Gemini animation specs for given start and end Vega-Lite charts. It sorts the candidates by their evaluated effectiveness.

Input

Parameter Type Description
start Object A Vega-Lite visualization spec for the start state.
end Object A Vega-Lite visualization spec for the end state.
option Object Options for the recommendations. Same as the .recommend's options.

Output

It returns object with the number of sub-transitions and corresponding recommendations for each Path as keys and values:

{
  "1": [ {"path": path_1_1, "recommendations": recomsForPath_1_1}, ...],
  "2": [ {"path": path_2_1, "recommendations": recomsForPath_2_1}, ...],
  ...
}

Utility

# gemini.vl2vg4gemini(vlSpec) <>

Compile the given vega-lite spec to the vega spec with the necessary information for Gemini, such as each component's name.

Cite us!

If you use Gemini in published research, please cite these papers: 1, TBD.