Skip to content

Repository files navigation

Vue Plot

npm version npm downloads License

Vue components for building data visualizations with @observablehq/plot.

Note

This project is a work in progress. APIs may change between minor versions.

Quick Start

pnpm add @memotux/vue-plot @observablehq/plot
// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { plotCustomElement } from '@memotux/vue-plot'

export default defineConfig({
  plugins: [
    vue({
      template: plotCustomElement.template,
    }),
  ],
})
<!-- App.vue -->
<script setup>
import { VPlot } from '@memotux/vue-plot'

const data = [
  { name: 'A', value: 10 },
  { name: 'B', value: 20 },
  { name: 'C', value: 15 },
]
</script>

<template>
  <VPlot :width="680">
    <PlotBarY :data="data" x="name" y="value" />
  </VPlot>
</template>

Installation

pnpm add @memotux/vue-plot @observablehq/plot
# or
npm install @memotux/vue-plot @observablehq/plot
# or
yarn add @memotux/vue-plot @observablehq/plot

Important

@observablehq/plot is a required peer dependency. It is NOT bundled with this package — you must install it separately.

Setup

Vite Plugin Configuration

Configure the Vite plugin so Vue recognizes <Plot*> tags as custom elements:

// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { plotCustomElement } from '@memotux/vue-plot'

export default defineConfig({
  plugins: [
    vue({
      template: plotCustomElement.template,
    }),
  ],
})

Note

This step is only required when using mark components as children. If you prefer to pass marks via the marks prop, you can skip this configuration.

Component Registration

Choose one of the following methods to use <VPlot> in your components.

Global Registration (Vue Plugin)

Registers <VPlot> globally across your application.

// main.ts
import { createApp } from 'vue'
import { VuePlot } from '@memotux/vue-plot'
import App from './App.vue'

const app = createApp(App)
app.use(VuePlot)
app.mount('#app')

Local Registration

Import <VPlot> directly in individual components without global registration.

<!-- MyChart.vue -->
<script setup>
import { VPlot } from '@memotux/vue-plot'
</script>

<template>
  <VPlot :width="680" :marks="[]" />
</template>

Usage

Marks as Children

Use <Plot*> components directly in your template. Each mark from @observablehq/plot maps to a Plot{MarkName} component with PascalCase naming.

<script setup>
import { VPlot } from '@memotux/vue-plot'

const data = [
  { name: 'A', value: 10 },
  { name: 'B', value: 20 },
  { name: 'C', value: 15 },
]
</script>

<template>
  <VPlot :width="680">
    <PlotBarY :data="data" x="name" y="value" />
  </VPlot>
</template>

Note

This pattern requires the Vite Plugin Configuration setup step.

Marks as Props

Pass marks from @observablehq/plot through the marks prop. This pattern does not require the Vite plugin.

<script setup>
import { VPlot } from '@memotux/vue-plot'
import { barY } from '@observablehq/plot'

const data = [
  { name: 'A', value: 10 },
  { name: 'B', value: 20 },
  { name: 'C', value: 15 },
]

const options = {
  width: 680,
  marks: [barY(data, { x: 'name', y: 'value' })],
}
</script>

<template>
  <VPlot v-bind="options" />
</template>

Reactive Data

Bind reactive data to update plots when data changes.

<script setup>
import { ref } from 'vue'
import { VPlot } from '@memotux/vue-plot'

const data = ref([
  { x: 1, y: 2 },
  { x: 2, y: 4 },
  { x: 3, y: 1 },
])

function addPoint() {
  data.value.push({
    x: data.value.length + 1,
    y: Math.random() * 10,
  })
}
</script>

<template>
  <VPlot :width="680">
    <PlotDot :data="data" x="x" y="y" />
  </VPlot>
  <button @click="addPoint">Add Point</button>
</template>

Marks Priority

If marks are provided both as props and as children, only child marks are rendered.

<!-- Only PlotBarY renders — the marks prop is ignored -->
<VPlot :marks="[frame()]">
  <PlotBarY :data="data" x="name" y="value" />
</VPlot>

API Reference

VPlot

The main chart component. Accepts plot configuration via props.

Prop Type Description
All PlotOptions fields Spread any PlotOptions property (width, height, style, etc.)
marks RenderableMark[] Array of mark functions from @observablehq/plot

Usage pattern: Spread a plot options object with v-bind:

<VPlot v-bind="{ width: 680, marks: [...] }" />

Mark Components

Every mark from @observablehq/plot is available as a <Plot*> child component.

Mark Function Component Tag Options Type
area <PlotArea> AreaOptions
areaX <PlotAreaX> AreaXOptions
areaY <PlotAreaY> AreaYOptions
barX <PlotBarX> BarXOptions
barY <PlotBarY> BarYOptions
dot <PlotDot> DotOptions
dotX <PlotDotX> DotXOptions
dotY <PlotDotY> DotYOptions
frame <PlotFrame> FrameOptions
line <PlotLine> LineOptions
lineX <PlotLineX> LineXOptions
lineY <PlotLineY> LineYOptions
rect <PlotRect> RectOptions
rectX <PlotRectX> RectXOptions
rectY <PlotRectY> RectYOptions
ruleX <PlotRuleX> RuleXOptions
ruleY <PlotRuleY> RuleYOptions
text <PlotText> TextOptions
textX <PlotTextX> TextXOptions
textY <PlotTextY> TextYOptions
tickX <PlotTickX> TickXOptions
tickY <PlotTickY> TickYOptions
cell <PlotCell> CellOptions
image <PlotImage> ImageOptions
arrow <PlotArrow> ArrowOptions
link <PlotLink> LinkOptions
vector <PlotVector> VectorOptions
tree <PlotTree> TreeOptions
contour <PlotContour> ContourOptions
hexbin <PlotHexbin> HexbinOptions
density <PlotDensity> DensityOptions
tip <PlotTip> TipOptions
geo <PlotGeo> GeoOptions
raster <PlotRaster> RasterOptions
axisX <PlotAxisX> AxisXOptions
axisY <PlotAxisY> AxisYOptions
crosshair <PlotCrosshair> CrosshairOptions
delaunayLink <PlotDelaunayLink> DelaunayOptions
delaunayMesh <PlotDelaunayMesh> DelaunayOptions
hexgrid <PlotHexgrid> HexgridOptions
hexagon <PlotHexagon> Omit<DotOptions, "symbol">
waffleX <PlotWaffleX> WaffleXOptions
waffleY <PlotWaffleY> WaffleYOptions
bollinger <PlotBollinger> BollingerOptions
boxX <PlotBoxX> BoxXOptions
boxY <PlotBoxY> BoxYOptions
linearRegressionX <PlotLinearRegressionX> LinearRegressionXOptions
linearRegressionY <PlotLinearRegressionY> LinearRegressionYOptions
differenceX <PlotDifferenceX> DifferenceOptions
differenceY <PlotDifferenceY> DifferenceOptions
auto <PlotAuto> AutoOptions

Each mark component accepts a data prop plus all options from the corresponding @observablehq/plot mark function.

TypeScript Types

Import types from @memotux/vue-plot/types:

import type { PlotProps, PlotMarksProps, Marks, PlotContext, PlotChildrenContext } from '@memotux/vue-plot/types'
Type Description
PlotProps Union of PlotOptions | PlotMarksProps — accepted by VPlot
PlotMarksProps<M> Generic: { data?: Data } & MarksOptions[M] — props for a single mark component
Marks Union of all supported mark names ('area' | 'barY' | 'dot' | ...)
PlotContext Reactive context shared between root plot and child marks
PlotChildrenContext<M> Per-mark context with mark, options, data, inserted, and id

PlotMarksProps generic example:

import type { PlotMarksProps } from '@memotux/vue-plot/types'

// Props for a barY mark component
type BarYProps = PlotMarksProps<'barY'>
// → { data?: Data } & BarYOptions

Credits

This library is inspired by:

  • Observable Plot — the underlying visualization engine
  • TresJS — the Vue custom element pattern for Three.js

Contributing

Contributions are welcome! Please open an issue or submit a pull request.

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/my-feature)
  3. Commit your changes (git commit -m 'feat: add my feature')
  4. Push to the branch (git push origin feature/my-feature)
  5. Open a Pull Request

Links

About

Vue.js UI Components for visualizing tabular data using @observablehq/plot library.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages