CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-plotly-js-dist

JavaScript data visualization library for creating interactive charts, graphs, and scientific visualizations

81

1.02x
Overview
Eval results
Files

animation.mddocs/

Animation

Functions for creating smooth animated transitions between plot states and managing animation frames. Plotly.js provides a powerful animation system for creating engaging data visualizations.

Capabilities

animate

Animates the plot through a sequence of frames or to a specific frame state with customizable animation options.

/**
 * Animates the plot through frames or to a target state
 * @param graphDiv - DOM element ID (string) or element reference
 * @param frames - Frame objects, frame names, or frame group names to animate to
 * @param animationOpts - Animation configuration options
 * @returns Promise that resolves when animation completes
 */
function animate(
  graphDiv: string | HTMLElement,
  frames: Frame[] | string | string[],
  animationOpts?: AnimationOptions
): Promise<void>;

Usage Examples:

import Plotly from 'plotly.js-dist';

// Basic animation between two states
const frames = [
  {
    name: 'frame1',
    data: [{
      x: [1, 2, 3],
      y: [1, 4, 9],
      type: 'scatter'
    }]
  },
  {
    name: 'frame2', 
    data: [{
      x: [1, 2, 3],
      y: [2, 8, 18],
      type: 'scatter'
    }]
  }
];

// Add frames first
await Plotly.addFrames('chart', frames);

// Animate to specific frame
await Plotly.animate('chart', 'frame2', {
  transition: { duration: 1000, easing: 'cubic-in-out' },
  frame: { duration: 500, redraw: false }
});

// Animate through multiple frames
await Plotly.animate('chart', ['frame1', 'frame2'], {
  transition: { duration: 800 },
  frame: { duration: 1000 }
});

// Advanced animation with custom easing
await Plotly.animate('chart', frames, {
  transition: {
    duration: 2000,
    easing: 'elastic-out'
  },
  frame: {
    duration: 1500,
    redraw: true
  },
  mode: 'afterall'
});

addFrames

Adds animation frames to a plot at specified positions. Frames define different states of the plot for animation.

/**
 * Adds animation frames to a plot
 * @param graphDiv - DOM element ID (string) or element reference
 * @param frameList - Array of frame objects defining animation states
 * @param indices - Position(s) to insert frames (optional, defaults to end)
 * @returns Promise that resolves to the graph div element
 */
function addFrames(
  graphDiv: string | HTMLElement,
  frameList: Frame[],
  indices?: number | number[]
): Promise<HTMLElement>;

Usage Examples:

// Basic frame creation
const frames = [
  {
    name: 'year2020',
    data: [{
      x: countries,
      y: gdp2020,
      type: 'bar'
    }],
    layout: {
      title: 'GDP by Country - 2020'
    }
  },
  {
    name: 'year2021',
    data: [{
      x: countries,
      y: gdp2021,
      type: 'bar'
    }],
    layout: {
      title: 'GDP by Country - 2021'
    }
  }
];

await Plotly.addFrames('chart', frames);

// Frames with custom traces and layout changes
const evolutionFrames = [
  {
    name: 'step1',
    data: [{
      x: [1, 2, 3],
      y: [1, 4, 2],
      mode: 'markers',
      marker: { size: 10, color: 'red' }
    }],
    traces: [0],  // Apply to first trace only
    layout: { 
      xaxis: { range: [0, 5] },
      annotations: [{
        text: 'Step 1',
        x: 2.5,
        y: 4
      }]
    }
  },
  {
    name: 'step2',
    data: [{
      x: [1, 2, 3, 4],
      y: [1, 4, 2, 6],
      mode: 'lines+markers',
      marker: { size: 8, color: 'blue' }
    }],
    traces: [0],
    layout: {
      annotations: [{
        text: 'Step 2',
        x: 2.5,
        y: 6
      }]
    }
  }
];

await Plotly.addFrames('evolution-chart', evolutionFrames);

// Add frames at specific positions
await Plotly.addFrames('chart', newFrames, [0, 2]);  // Insert at positions 0 and 2

deleteFrames

Removes animation frames from a plot by their names or indices.

/**
 * Removes animation frames from a plot
 * @param graphDiv - DOM element ID (string) or element reference
 * @param frameList - Array of frame names or indices to remove
 * @returns Promise that resolves to the graph div element
 */
function deleteFrames(
  graphDiv: string | HTMLElement,
  frameList: string[] | number[]
): Promise<HTMLElement>;

Usage Examples:

// Remove frames by name
await Plotly.deleteFrames('chart', ['frame1', 'frame3']);

// Remove frames by index
await Plotly.deleteFrames('chart', [0, 2, 4]);

// Remove all frames
const chartDiv = document.getElementById('chart');
const frameNames = chartDiv._transitionData._frames.map(f => f.name);
await Plotly.deleteFrames('chart', frameNames);

Animation Patterns

Time Series Animation

// Animate through time series data
async function createTimeSeriesAnimation(data, timeField, valueField) {
  const timePoints = [...new Set(data.map(d => d[timeField]))].sort();
  
  const frames = timePoints.map(time => ({
    name: time.toString(),
    data: [{
      x: data.filter(d => d[timeField] <= time).map(d => d.x),
      y: data.filter(d => d[timeField] <= time).map(d => d[valueField]),
      type: 'scatter',
      mode: 'lines+markers'
    }],
    layout: {
      title: `Data as of ${time}`,
      xaxis: { range: [minX, maxX] },
      yaxis: { range: [minY, maxY] }
    }
  }));
  
  await Plotly.addFrames('timeseries-chart', frames);
  
  // Auto-play animation
  await Plotly.animate('timeseries-chart', frames.map(f => f.name), {
    transition: { duration: 300 },
    frame: { duration: 500 }
  });
}

Scatter Plot Evolution

// Animate scatter plot data evolution
const scatterFrames = years.map(year => ({
  name: `year-${year}`,
  data: [{
    x: countries.map(country => getGDP(country, year)),
    y: countries.map(country => getLifeExpectancy(country, year)),
    text: countries,
    mode: 'markers',
    marker: {
      size: countries.map(country => getPopulation(country, year) / 1000000),
      color: countries.map(country => getRegionColor(country)),
      sizemode: 'diameter',
      sizeref: 0.1
    },
    type: 'scatter'
  }],
  layout: {
    title: `World Development Indicators - ${year}`,
    xaxis: { title: 'GDP per Capita' },
    yaxis: { title: 'Life Expectancy' }
  }
}));

await Plotly.addFrames('world-chart', scatterFrames);

Bar Chart Race Animation

// Create animated bar chart race
function createBarRace(data, categories, timePoints) {
  const frames = timePoints.map(time => {
    const timeData = data.filter(d => d.time === time)
      .sort((a, b) => b.value - a.value)
      .slice(0, 10);  // Top 10
    
    return {
      name: time.toString(),
      data: [{
        x: timeData.map(d => d.value),
        y: timeData.map(d => d.category),
        type: 'bar',
        orientation: 'h',
        marker: {
          color: timeData.map(d => getCategoryColor(d.category))
        }
      }],
      layout: {
        title: `Rankings - ${time}`,
        xaxis: { range: [0, Math.max(...timeData.map(d => d.value)) * 1.1] },
        yaxis: { 
          categoryorder: 'array',
          categoryarray: timeData.map(d => d.category).reverse()
        }
      }
    };
  });
  
  return frames;
}

Morphing Shapes Animation

// Animate between different shape configurations
const shapeFrames = [
  {
    name: 'circle',
    data: [{
      x: circleX,
      y: circleY,
      mode: 'markers',
      marker: { size: 20, color: 'blue' }
    }]
  },
  {
    name: 'square',
    data: [{
      x: squareX,
      y: squareY,
      mode: 'markers',
      marker: { size: 20, color: 'red' }
    }]
  },
  {
    name: 'triangle',
    data: [{
      x: triangleX,
      y: triangleY,
      mode: 'markers',
      marker: { size: 20, color: 'green' }
    }]
  }
];

await Plotly.addFrames('morph-chart', shapeFrames);

// Smooth morphing animation
await Plotly.animate('morph-chart', ['circle', 'square', 'triangle'], {
  transition: {
    duration: 2000,
    easing: 'cubic-in-out'
  },
  frame: {
    duration: 500,
    redraw: false
  }
});

Interactive Animation Controls

Animation Slider

// Create animation with slider control
const layout = {
  title: 'Animated Plot with Slider',
  sliders: [{
    active: 0,
    steps: frames.map((frame, i) => ({
      label: frame.name,
      method: 'animate',
      args: [[frame.name], {
        mode: 'immediate',
        transition: { duration: 300 },
        frame: { duration: 300, redraw: false }
      }]
    })),
    x: 0.1,
    len: 0.9,
    xanchor: 'left',
    y: 0,
    yanchor: 'top',
    pad: { t: 50, b: 10 },
    currentvalue: {
      visible: true,
      prefix: 'Year:',
      xanchor: 'right',
      font: { size: 20, color: '#666' }
    }
  }]
};

Play/Pause Controls

// Add play/pause buttons
const layout = {
  updatemenus: [{
    type: 'buttons',
    direction: 'left',
    buttons: [{
      label: 'Play',
      method: 'animate',
      args: [null, {
        mode: 'immediate',
        fromcurrent: true,
        transition: { duration: 300 },
        frame: { duration: 500, redraw: false }
      }]
    }, {
      label: 'Pause',
      method: 'animate',
      args: [[null], {
        mode: 'immediate',
        transition: { duration: 0 },
        frame: { duration: 0, redraw: false }
      }]
    }],
    pad: { r: 10, t: 87 },
    showactive: false,
    x: 0.011,
    xanchor: 'right',
    y: 0,
    yanchor: 'top'
  }]
};

Animation Events

interface AnimationEvents {
  'plotly_animating': (eventData: { frame: Frame }) => void;
  'plotly_animationinterrupted': (eventData: { frame: Frame }) => void;
  'plotly_transitioned': () => void;
  'plotly_transitioninterrupted': () => void;
}

Usage Examples:

const chartDiv = document.getElementById('animated-chart');

chartDiv.on('plotly_animating', (eventData) => {
  console.log('Animating to frame:', eventData.frame.name);
});

chartDiv.on('plotly_animationinterrupted', () => {
  console.log('Animation was interrupted');
});

chartDiv.on('plotly_transitioned', () => {
  console.log('Transition completed');
});

Performance Optimization

Efficient Frame Management

// Pre-calculate all frame data for smooth animation
function precomputeFrames(rawData, timePoints) {
  return timePoints.map(time => {
    const frameData = processDataForTime(rawData, time);
    return {
      name: time.toString(),
      data: frameData,
      layout: { title: `Time: ${time}` }
    };
  });
}

// Use redraw: false for better performance
const animationOpts = {
  transition: { duration: 300 },
  frame: { 
    duration: 200, 
    redraw: false  // Skip full redraw between frames
  }
};

Memory Management

// Clean up frames when animation is complete
async function runAnimationSequence(chartId, frames) {
  await Plotly.addFrames(chartId, frames);
  
  try {
    await Plotly.animate(chartId, frames.map(f => f.name));
  } finally {
    // Clean up frames to free memory
    await Plotly.deleteFrames(chartId, frames.map(f => f.name));
  }
}

Types

interface Frame {
  name?: string;
  group?: string;
  data?: Partial<PlotlyTrace>[];
  layout?: Partial<Layout>;
  traces?: number[];
  baseframe?: string;
}

interface AnimationOptions {
  mode?: 'immediate' | 'next' | 'afterall';
  direction?: 'forward' | 'reverse';
  fromcurrent?: boolean;
  transition?: TransitionOptions;
  frame?: FrameOptions;
}

interface TransitionOptions {
  duration?: number;
  easing?: 'linear' | 'quad' | 'cubic' | 'sin' | 'exp' | 'circle' | 'elastic' | 'back' | 'bounce' | string;
  ordering?: 'layout first' | 'traces first';
}

interface FrameOptions {
  duration?: number;
  redraw?: boolean;
}

interface SliderStep {
  label?: string;
  method?: 'animate' | 'relayout' | 'restyle' | 'update';
  args?: any[];
  value?: string;
  visible?: boolean;
  execute?: boolean;
}

interface SliderConfig {
  active?: number;
  bgcolor?: string;
  bordercolor?: string;
  borderwidth?: number;
  currentvalue?: {
    font?: FontConfig;
    offset?: number;
    prefix?: string;
    suffix?: string;
    visible?: boolean;
    xanchor?: 'left' | 'center' | 'right';
  };
  font?: FontConfig;
  len?: number;
  lenmode?: 'fraction' | 'pixels';
  steps?: SliderStep[];
  tickcolor?: string;
  ticklen?: number;
  tickwidth?: number;
  transition?: TransitionOptions;
  visible?: boolean;
  x?: number;
  xanchor?: 'auto' | 'left' | 'center' | 'right';
  y?: number;
  yanchor?: 'auto' | 'top' | 'middle' | 'bottom';
}

Install with Tessl CLI

npx tessl i tessl/npm-plotly-js-dist

docs

animation.md

chart-types.md

core-plotting.md

data-streaming.md

data-updates.md

export-utilities.md

index.md

interactive-components.md

layout-system.md

trace-management.md

tile.json