diff --git a/vg/vgimg/vgimg.go b/vg/vgimg/vgimg.go
index 5558e1d493fffe0ab46c141c3c10bcf507cf0a55..c35510f71ac09f72f1d44df56cff77b347c500b6 100644
--- a/vg/vgimg/vgimg.go
+++ b/vg/vgimg/vgimg.go
@@ -53,13 +53,22 @@ func New(width, height vg.Length) *Canvas {
 // minimum point of the given image
 // should probably be 0,0.
 func NewImage(img draw.Image) *Canvas {
-	w := float64(img.Bounds().Max.X - img.Bounds().Min.X)
 	h := float64(img.Bounds().Max.Y - img.Bounds().Min.Y)
-	draw.Draw(img, img.Bounds(), image.White, image.ZP, draw.Src)
 	gc := draw2d.NewGraphicContext(img)
 	gc.SetDPI(dpi)
 	gc.Scale(1, -1)
 	gc.Translate(0, -h)
+	return NewImageWithContext(img, gc)
+}
+
+// NewImageWithContext returns a new image canvas
+// that draws to the given image, using the given graphic context.
+// The minimum point of the given image
+// should probably be 0,0.
+func NewImageWithContext(img draw.Image, gc draw2d.GraphicContext) *Canvas {
+	w := float64(img.Bounds().Max.X - img.Bounds().Min.X)
+	h := float64(img.Bounds().Max.Y - img.Bounds().Min.Y)
+	draw.Draw(img, img.Bounds(), image.White, image.ZP, draw.Src)
 	c := &Canvas{
 		gc:    gc,
 		img:   img,
diff --git a/vg/vgx11/canvas.go b/vg/vgx11/canvas.go
new file mode 100644
index 0000000000000000000000000000000000000000..3a0d2ada4347e3ca9fe574351dfb7a4a7da1b457
--- /dev/null
+++ b/vg/vgx11/canvas.go
@@ -0,0 +1,92 @@
+// Copyright ©2015 The gonum Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !windows
+
+// The vgx11 package uses xgbutil (github.com/BurntSushi/xgbutil)
+// as a X11-display backend for vg.
+package vgx11
+
+import (
+	"image"
+	"image/draw"
+
+	"code.google.com/p/draw2d/draw2d"
+	"github.com/BurntSushi/xgbutil"
+	"github.com/BurntSushi/xgbutil/keybind"
+	"github.com/BurntSushi/xgbutil/xevent"
+	"github.com/BurntSushi/xgbutil/xgraphics"
+	"github.com/BurntSushi/xgbutil/xwindow"
+	"github.com/gonum/plot/vg"
+	"github.com/gonum/plot/vg/vgimg"
+)
+
+// dpi is the number of dots per inch.
+const dpi = 96
+
+// Canvas implements the vg.Canvas interface,
+// drawing to an image.Image using draw2d.
+type Canvas struct {
+	*vgimg.Canvas
+
+	// X window values
+	x    *xgbutil.XUtil
+	ximg *xgraphics.Image
+	wid  *xwindow.Window
+}
+
+// New returns a new image canvas with
+// the size specified  rounded up to the
+// nearest pixel.
+func New(width, height vg.Length, name string) (*Canvas, error) {
+	w := width / vg.Inch * dpi
+	h := height / vg.Inch * dpi
+	img := image.NewRGBA(image.Rect(0, 0, int(w+0.5), int(h+0.5)))
+
+	return NewImage(img, name)
+}
+
+// NewImage returns a new image canvas
+// that draws to the given image.  The
+// minimum point of the given image
+// should probably be 0,0.
+func NewImage(img draw.Image, name string) (*Canvas, error) {
+	w := float64(img.Bounds().Max.X - img.Bounds().Min.X)
+	h := float64(img.Bounds().Max.Y - img.Bounds().Min.Y)
+
+	X, err := xgbutil.NewConn()
+	if err != nil {
+		return nil, err
+	}
+	keybind.Initialize(X)
+	ximg := xgraphics.New(X, image.Rect(0, 0, int(w), int(h)))
+	err = ximg.CreatePixmap()
+	if err != nil {
+		return nil, err
+	}
+	painter := NewPainter(ximg)
+	gc := draw2d.NewGraphicContextWithPainter(ximg, painter)
+	gc.SetDPI(dpi)
+	gc.Scale(1, -1)
+	gc.Translate(0, -h)
+
+	wid := ximg.XShowExtra(name, true)
+	go func() {
+		xevent.Main(X)
+	}()
+
+	c := &Canvas{
+		Canvas: vgimg.NewImageWithContext(img, gc),
+		x:      X,
+		ximg:   ximg,
+		wid:    wid,
+	}
+	vg.Initialize(c)
+	return c, nil
+}
+
+func (c *Canvas) Paint() {
+	c.ximg.XDraw()
+	c.ximg.XPaint(c.wid.Id)
+}
diff --git a/vg/vgx11/main.go b/vg/vgx11/main.go
new file mode 100644
index 0000000000000000000000000000000000000000..7365061914cff8bc621fbf9502ca825660f23a65
--- /dev/null
+++ b/vg/vgx11/main.go
@@ -0,0 +1,80 @@
+// Copyright ©2015 The gonum Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//+build ignore
+
+package main
+
+import (
+	"math/rand"
+	"time"
+
+	"github.com/gonum/plot"
+	"github.com/gonum/plot/plotter"
+	"github.com/gonum/plot/plotutil"
+	"github.com/gonum/plot/vg/draw"
+	"github.com/gonum/plot/vg/vgx11"
+)
+
+func main() {
+	rand.Seed(int64(0))
+
+	p, err := plot.New()
+	if err != nil {
+		panic(err)
+	}
+
+	p.Title.Text = "Plotutil example"
+	p.X.Label.Text = "X"
+	p.Y.Label.Text = "Y"
+
+	err = plotutil.AddLinePoints(
+		p,
+		"First", randomPoints(15),
+	)
+	if err != nil {
+		panic(err)
+	}
+
+	cnvs, err := vgx11.New(4*96, 4*96, "Example")
+	if err != nil {
+		panic(err)
+	}
+
+	p.Draw(draw.New(cnvs))
+	cnvs.Paint()
+	time.Sleep(5 * time.Second)
+
+	err = plotutil.AddLinePoints(
+		p,
+		"Second", randomPoints(15),
+		"Third", randomPoints(15),
+	)
+	if err != nil {
+		panic(err)
+	}
+
+	p.Draw(draw.New(cnvs))
+	cnvs.Paint()
+	time.Sleep(10 * time.Second)
+
+	// Save the plot to a PNG file.
+	//        if err := p.Save(4, 4, "points.png"); err != nil {
+	//                panic(err)
+	//        }
+}
+
+// randomPoints returns some random x, y points.
+func randomPoints(n int) plotter.XYs {
+	pts := make(plotter.XYs, n)
+	for i := range pts {
+		if i == 0 {
+			pts[i].X = rand.Float64()
+		} else {
+			pts[i].X = pts[i-1].X + rand.Float64()
+		}
+		pts[i].Y = pts[i].X + 10*rand.Float64()
+	}
+	return pts
+}
diff --git a/vg/vgx11/painter.go b/vg/vgx11/painter.go
new file mode 100644
index 0000000000000000000000000000000000000000..d661fa1f60dce666dda4d9868f5dea03d3b30737
--- /dev/null
+++ b/vg/vgx11/painter.go
@@ -0,0 +1,99 @@
+// Copyright ©2015 The gonum Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !windows
+
+// Very liberally copied the code from freetype-go (file: paint.go)
+// Adapted to the *xgraphics.Image type.
+
+// Copyright 2010 The Freetype-Go Authors. All rights reserved.
+// Use of this source code is governed by your choice of either the
+// FreeType License or the GNU General Public License version 2 (or
+// any later version), both of which can be found in the LICENSE file.
+//
+// Use of the Freetype-Go software is subject to your choice of exactly one of
+// the following two licenses:
+// * The FreeType License, which is similar to the original BSD license with
+// an advertising clause, or
+// * The GNU General Public License (GPL), version 2 or later.
+//
+// The text of these licenses are available in the licenses/ftl.txt and the
+// licenses/gpl.txt files respectively. They are also available at
+// http://freetype.sourceforge.net/license.html
+
+package vgx11
+
+import (
+	"image/color"
+	"image/draw"
+
+	"code.google.com/p/freetype-go/freetype/raster"
+	"github.com/BurntSushi/xgbutil/xgraphics"
+)
+
+type Painter struct {
+	// The image to compose onto.
+	Image *xgraphics.Image
+	// The Porter-Duff composition operator.
+	Op draw.Op
+	// The 16-bit color to paint the spans.
+	cr, cg, cb, ca uint32
+}
+
+// Paint satisfies the Painter interface by painting ss onto an xgraphics.Image.
+func (r *Painter) Paint(ss []raster.Span, done bool) {
+	b := r.Image.Bounds()
+	for _, s := range ss {
+		if s.Y < b.Min.Y {
+			continue
+		}
+		if s.Y >= b.Max.Y {
+			return
+		}
+		if s.X0 < b.Min.X {
+			s.X0 = b.Min.X
+		}
+		if s.X1 > b.Max.X {
+			s.X1 = b.Max.X
+		}
+		if s.X0 >= s.X1 {
+			continue
+		}
+		// This code is similar to drawGlyphOver in $GOROOT/src/pkg/image/draw/draw.go.
+		ma := s.A >> 16
+		const m = 1<<16 - 1
+		i0 := (s.Y-r.Image.Rect.Min.Y)*r.Image.Stride + (s.X0-r.Image.Rect.Min.X)*4
+		i1 := i0 + (s.X1-s.X0)*4
+		if r.Op == draw.Over {
+			for i := i0; i < i1; i += 4 {
+				dr := uint32(r.Image.Pix[i+0])
+				dg := uint32(r.Image.Pix[i+1])
+				db := uint32(r.Image.Pix[i+2])
+				da := uint32(r.Image.Pix[i+3])
+				a := (m - (r.ca * ma / m)) * 0x101
+				r.Image.Pix[i+0] = uint8((dr*a + r.cr*ma) / m >> 8)
+				r.Image.Pix[i+1] = uint8((dg*a + r.cg*ma) / m >> 8)
+				r.Image.Pix[i+2] = uint8((db*a + r.cb*ma) / m >> 8)
+				r.Image.Pix[i+3] = uint8((da*a + r.ca*ma) / m >> 8)
+			}
+		} else {
+			for i := i0; i < i1; i += 4 {
+				r.Image.Pix[i+0] = uint8(r.cr * ma / m >> 8)
+				r.Image.Pix[i+1] = uint8(r.cg * ma / m >> 8)
+				r.Image.Pix[i+2] = uint8(r.cb * ma / m >> 8)
+				r.Image.Pix[i+3] = uint8(r.ca * ma / m >> 8)
+			}
+		}
+	}
+}
+
+// SetColor sets the color to paint the spans.
+func (r *Painter) SetColor(c color.Color) {
+	r.cr, r.cg, r.cb, r.ca = c.RGBA()
+}
+
+// NewPainter creates a new Painter for the given image.
+func NewPainter(img *xgraphics.Image) *Painter {
+	return &Painter{Image: img}
+}