go chart is a basic charting library in native golang.

go-chart

CircleCI Go Report Card

Package chart is a very simple golang native charting library that supports timeseries and continuous line charts.

Master should now be on the v3.x codebase, which overhauls the api significantly. Per usual, see examples for more information.

Installation

To install chart run the following:

> go get -u github.com/wcharczuk/go-chart

Most of the components are interchangeable so feel free to crib whatever you want.

Output Examples

Spark Lines:

Single axis:

Two axis:

Other Chart Types

Pie Chart:

The code for this chart can be found in examples/pie_chart/main.go.

Stacked Bar:

The code for this chart can be found in examples/stacked_bar/main.go.

Code Examples

Actual chart configurations and examples can be found in the ./examples/ directory. They are simple CLI programs that write to output.png (they are also updated with go generate.

Usage

Everything starts with the chart.Chart object. The bare minimum to draw a chart would be the following:

import (
    ...
    "bytes"
    ...
    "github.com/wcharczuk/go-chart" //exposes "chart"
)

graph := chart.Chart{
    Series: []chart.Series{
        chart.ContinuousSeries{
            XValues: []float64{1.0, 2.0, 3.0, 4.0},
            YValues: []float64{1.0, 2.0, 3.0, 4.0},
        },
    },
}

buffer := bytes.NewBuffer([]byte{})
err := graph.Render(chart.PNG, buffer)

Explanation of the above: A chart can have many Series, a Series is a collection of things that need to be drawn according to the X range and the Y range(s).

Here, we have a single series with x range values as float64s, rendered to a PNG. Note; we can pass any type of io.Writer into Render(...), meaning that we can render the chart to a file or a resonse or anything else that implements io.Writer.

API Overview

Everything on the chart.Chart object has defaults that can be overriden. Whenever a developer sets a property on the chart object, it is to be assumed that value will be used instead of the default.

The best way to see the api in action is to look at the examples in the ./_examples/ directory.

Design Philosophy

I wanted to make a charting library that used only native golang, that could be stood up on a server (i.e. it had built in fonts).

The goal with the API itself is to have the "zero value be useful", and to require the user to not code more than they absolutely needed.

Contributions

Contributions are welcome though this library is in a holding pattern for the forseable future.

Owner
Will Charczuk
How do I bio.
Will Charczuk
Comments
  • Colormap Support

    Colormap Support

    After examining current Go chart options, I find this one to be best-in-class for aesthetics and detail. For my purposes, I'm only missing one key feature: colormaps.

    Specifically, for plotting X/Y scatterplots, I have a Z axis of values associated with each X/Y point. I need that Z axis to have its values from Z-min to Z-max mapped to a color range for each point, as shown here.

    A good set of colormaps is discussed here and here. As you can see there, the viridis colormap is consistently high performing for the human eye.

  • Can't create a chart of a constant function

    Can't create a chart of a constant function

    Because of the way checkRanges is implemented here: https://github.com/wcharczuk/go-chart/blob/master/chart.go#L274, one can't plot something like f(x)=3.14.

  • ZValues in chart.ContinuousSeries

    ZValues in chart.ContinuousSeries

    So I was indeed able to use our features from #33 to plot my z values. But it was pretty ugly. I had to index the z value from the x and y float64 values. The only way I could see to do this was to hash x and y using sprintf("%.3f_%.3f", x, y) and map it to the z value:

    zFirst := zSequence[0]
    zMin, zMax := zFirst, zFirst
    for _, z := range zSequence[1:] {
    	if z < zMin {
    		zMin = z
    	}
    	if z > zMax {
    		zMax = z
    	}
    }
    
    getHash := func(x, y float64) string {
    	hash := sprintf("%.3f_%.3f", x, y)
    	return hash
    }
    
    zHash := map[string]float64{}
    for i, x := range xSequence {
    	y := ySequence[i]
    	z := zSequence[i]
    	hash := getHash(x, y)
    	zHash[hash] = z
    }
    
    viridisOfZ := func(xr, yr chart.Range, x, y float64) drawing.Color {
    	hash := getHash(x, y)
    	z := zHash[hash]
    	return chart.Viridis(z, zMin, zMax)
    }
    

    I think it would be much better to just add and process an optional ZValues in chart.ContinuousSeries the same way XValues and YValues are processed. Then we would need to change DotColorProvider to have tho following signature:

    type DotColorProvider func(xrange, yrange, zrange Range, x, y, z float64) drawing.Color
    

    If the ZValues are not defined, the runtime can just send this function 0 for z and have zrange be from 0 to 0.

    With this functionality added, my entire program above could be reduced to

    viridisOfZ := func(xr, yr, zr chart.Range, x, y, z float64) drawing.Color {
    	return chart.Viridis(z, zr.GetMin(), zr.GetMax())
    }
    

    I think you would have a much easier time implementing this one than I since you know the flow of the plotting section of the package.

  • Program stuck while running the following code

    Program stuck while running the following code

    package main
    
    import (
    	"fmt"
    	"os"
    
    	"github.com/wcharczuk/go-chart"
    )
    
    func drawChart() {
    	sbc := chart.BarChart{
    		Height:   512,
    		BarWidth: 60,
    		XAxis: chart.Style{
    			Show: true,
    		},
    		YAxis: chart.YAxis{
    			Style: chart.Style{
    				Show: true,
    			},
    		},
    		Bars: []chart.Value{
    			{Value: 0, Label: "Blue"},
    			{Value: 0, Label: "Green"},
    			{Value: 0, Label: "Gray"},
    			{Value: 0, Label: "Orange"},
    			{Value: 0, Label: "Test"},
    			{Value: 0, Label: "??"},
    			{Value: 0, Label: "!!"},
    		},
    	}
    
    	println("rendering")
    	err := sbc.Render(chart.PNG, os.Stdout)
    	if err != nil {
    		fmt.Printf("Error rendering chart: %v\n", err)
    	}
    }
    
    func main() {
    	drawChart()
    }
    
  • Adds the ability to draw an XY scatter plot.

    Adds the ability to draw an XY scatter plot.

    This PR introduces two new fields on Style: DotWidth and DotColor. It also tweaks some aspects of the raster renderer, namely the .Circle function and some of the inner workings of the drawing package.

    Important consideration; so far only Draw.LineSeries uses these new fields, support in other types of plots is ongoing.

    Also adds an example for scatter plots in _examples/scatter/main.go.

  • Allow creation of XY scatter plots (i.e. disable line between points)

    Allow creation of XY scatter plots (i.e. disable line between points)

    I'm experimenting with go-chart to replace some python charting (matplotlib), and I need to produce an XY scatter plot with values against time (see attached as a sample).

    When I plot these series using go-chart it draws lines between the points, and I couldn't figure out how to plot points/ticks only.

    Is it possible? Is this something you're considering? How would you recommend going about this if I were to help implement it? :)

    Sample XY scatter plot

    garbage-collection-durations

  • Invert Y Axis

    Invert Y Axis

    As a user I would like to be able to invert a chart axis so that I can show values as having a low absolute value but a high relative value at the top of the graph.

    Context I'm charting rank values with 1 being the highest rank and 100 being a lower relative rank. I would like to be able to invert the Y axis so that the higher rank shows as being higher on the chart.

  • Custom Formatter text angle

    Custom Formatter text angle

    My custom formatter is overlapping the text so I need to either adjust the tick intervals or angle the test. I can see some references in the code to setting text angle but I can't see how it's exposed.

    What are my options here.

    Also, thanks for being responsive to my other issues :)

  • Incorrect SVG rendering of PieChart when one segment makes up >50% of pie

    Incorrect SVG rendering of PieChart when one segment makes up >50% of pie

    I've tried a few different pie charts and and it looks like when one of the segments makes up >50% of the pie that segment is drawn using 360-angle, which in the example below is the orange segment.

    This is the png version that I was expecting the svg version to look like: screenshot

    And here is a screenshot of the svg that I got: screen shot 2017-09-27 at 07 17 11

    Code Snippet:

    	palette := summaryPalette{chart.AlternateColorPalette, myOverrideColors}
    
    	pie := chart.PieChart{
    		Width:  width,
    		Height: height,
    		Values: []chart.Value{
    			{Value: notAtDepotRemaining.Value, Label: fmt.Sprintf("Remaining %.0f %s", notAtDepotRemaining.Value, notAtDepotRemaining.Unit)},
    			{Value: notAtDepotUsed.Value, Label: fmt.Sprintf("Empty %.0f %s", notAtDepotUsed.Value, notAtDepotUsed.Unit)},
    			{Value: depotUsed.Value, Label: fmt.Sprintf("Returned %.0f %s", depotUsed.Value, depotUsed.Unit)},
    			{Value: depotRemaining.Value, Label: fmt.Sprintf("Stock %.0f %s", depotRemaining.Value, depotRemaining.Unit)},
    		},
    		ColorPalette: palette,
    	}
    
            ext := path.Ext(r.URL.Path)
    	switch ext {
    	case ".png":
    		w.Header().Set("Content-Type", "image/png")
    		if err := pie.Render(chart.PNG, w); err != nil {
    			return fmt.Errorf("PNG: %s", err)
    		}
    
    	case ".svg":
    		w.Header().Set("Content-Type", "image/svg+xml")
    		if err := pie.Render(chart.SVG, w); err != nil {
    			return fmt.Errorf("SVG: %s", err)
    		}
    
    	default:
    		http.NotFound(w, r)
    	}
    
  • It's possible to reduce number of labels on X Axis?

    It's possible to reduce number of labels on X Axis?

    It's possible to show less values / labels on X Axis? It would be great if it could only show minimum, maximum, the middle and maybe 1 or 2 between those.

    stats

  • go get github.com/wcharczuk/go-chart failed

    go get github.com/wcharczuk/go-chart failed

    $ go get github.com/wcharczuk/go-chart

    github.com/wcharczuk/go-chart

    E:\Code\Go\src\github.com\wcharczuk\go-chart\vector_renderer.go:173: vr.fc.MeasureString(body).Ceil undefined (type fixed.Int26_6 has no field or method Ceil)

    intel i7 amd64 win10

  • Fix donut chart when there is only one element

    Fix donut chart when there is only one element

    When there was only one value for the pie chart the circle was not drawn. The style of the value was not used, and the radius of the circle was not matching the value when there are more than one elements.

    It seems that "Circle" does not print a correct circle, the shape is weird. To print the donut hole it does not use "Circle", so I used the same code to draw a single element.

  • Single element donut charts renders as an empty canvas

    Single element donut charts renders as an empty canvas

    I had a requirement to generate charts that somtimes contain only 1 element(100%)/ But having only one element as input values ends up with just the canvas. Single item donut charts seem to have some custom handling here . https://github.com/wcharczuk/go-chart/blob/c1468e8ae4ed7c6f564f3bb54ae90b563dcf65ce/donut_chart.go#L134

    func main() {
    	donut := chart.DonutChart{
    		Width:  512,
    		Height: 512,
    		Values: []chart.Value{
    			{
    				Value: 1,
    			},
    		},
    	}
    	f, _ := os.Create("donut.png")
    	donut.Render(chart.PNG, f)
    	
    }
    

    Output(just a white canvas): donut

    Workaround As a workaround I ended up with adding an extra value with a very small value(1e-7) and very small stroke width which triggered the usual rendering. Its not ideal as you can still see a tiny white line but its something.

    Values: []chart.Value{
    			{
    				Value: 1,
    				Style: chart.Style{
    					StrokeWidth: 1e-7,
    				},
    			},
    			{
    				Value: 1e-7,
    				Style: chart.Style{
    					StrokeWidth: 1e-7,
    				},
    			},
    		},
    

    Output donut

  • How to reorder bar charts?

    How to reorder bar charts?

    Trying to put Politics & Government on right side of chart. Despire reordering passed graph.Bars Politics & Government is second anyway

    	for i, value := range values {
    		j := 0 // 0-9
    		switch value.Label {
    		case "Family & Relationships":
    			j = 0
    		case "Entertainment & Music":
    			j = 9
    		case "Society & Culture":
    			j = 2
    		case "Health":
    			j = 3
    		case "Business & Finance":
    			j = 4
    		case "Education & Reference":
    			j = 5
    		case "Sports":
    			j = 6
    		case "Science & Mathematics":
    			j = 7
    		case "Computers & Internet":
    			j = 8
    		case "Politics & Government":
    			values[i].Label = "ХУЙ" // TODO: изменить порядок баров
    			j = 2
    		default:
    			pp.Println("category not found", value.Label)
    		}
    		values[i], values[j] = values[j], values[i]
    	}
    
    	graph := chart.BarChart{
    		Title: text,
    		TitleStyle: chart.Style{
    			Padding: chart.Box{Bottom: 50},
    			Font:    font,
    		},
    		ColorPalette: nil,
    		Width:        1100,
    		Height:       600,
    		DPI:          0,
    		BarWidth:     60,
    		Background:   chart.Style{},
    		Canvas:       chart.Style{},
    		XAxis:        chart.Style{},
    		YAxis: chart.YAxis{
    			AxisType: chart.YAxisPrimary, // TODO: need chart.YAxisSecondary but Yaxis just crops. Waiting for fixing
    		},
    		BarSpacing: 0,
    		Font:       nil,
    		Bars:       values,
    		Elements:   nil,
    	}
    

    https://i.yapx.cc/UNGAJ.png

  • Legend style improvements

    Legend style improvements

    This PR builds on top of #199 and it improves some visual issues such as some poorly chosen paddings and it fixes the issue that for several legends users weren't able to provide custom paddings.

    To get a feeling how I adjusted the default paddings between vertical legend elements:

    Old: output_old

    New: output_new

    PS: This is a clone of https://github.com/wcharczuk/go-chart/pull/190 since my PR was stale and I wanted to create a clone of this project. Hence I merged other changes into my branch. To have a clean feature branch, I created a new one.

  • Implement Legend with fixed length line on the left side

    Implement Legend with fixed length line on the left side

    Hey there,

    I had some issues with #185 - the line in the legend was just way too long in my charts. So I implemented a legend type that puts the line on the left hand side. That way the legend looks a lot cleaner than before for legends with (at least) one long and one short label.

    Let me know what you think about it.

    Cheers, Rico

    PS: This is a clone of https://github.com/wcharczuk/go-chart/pull/189 since my PR was stale and I wanted to create a clone of this project. Hence I merged other changes into my branch. To have a clean feature branch, I created a new one.

A library for basic image processing in Go.
A library for basic image processing in Go.

Imaging Package imaging provides basic image processing functions (resize, rotate, crop, brightness/contrast adjustments, etc.). All the image process

Nov 26, 2021
A library for basic image processing in Go.
A library for basic image processing in Go.

Imaging Package imaging provides basic image processing functions (resize, rotate, crop, brightness/contrast adjustments, etc.). All the image process

Nov 26, 2021
Basic Go server for mbtiles
Basic Go server for mbtiles

mbtileserver A simple Go-based server for map tiles stored in mbtiles format. It currently provides support for png, jpg, and pbf (vector tile) tilese

Dec 26, 2022
Provide basic charts in go
Provide basic charts in go

Charts for Go Basic charts in go. This package focuses more on autoscaling, error bars, and logarithmic plots than on beautifull or marketing ready ch

Dec 17, 2022
Super fast static photo and video gallery generator (written in Go and HTML/CSS/native JS)

fastgallery Fast static photo and video gallery generator Super fast (written in Go and C, concurrent, uses fastest image/video libraries, 4-8 times f

Dec 4, 2022
The android-go project provides a platform for writing native Android apps in Go programming language.
The android-go project provides a platform for writing native Android apps in Go programming language.

android-go The android-go project aims to provide a platform (namely an SDK) for writing native Android apps in Go programming language. All things he

Jan 5, 2023
A library for playing with colors in go (golang).
A library for playing with colors in go (golang).

go-colorful A library for playing with colors in Go. Supports Go 1.13 onwards. Why? I love games. I make games. I love detail and I get lost in detail

Dec 30, 2022
Pure Golang Library that allows simple LSB steganography on images
Pure Golang Library that allows simple LSB steganography on images

Steganography Lib Steganography is a library written in Pure go to allow simple LSB steganography on images. It is capable of both encoding and decodi

Dec 22, 2022
A captcha library written in golang
A captcha library written in golang

gocaptcha 一个简单的Go语言实现的验证码 图片实例 简介 基于Golang实现的图片验证码生成库,可以实现随机字母个数,随机直线,随机噪点等。可以设置任意多字体,每个验证码随机选一种字体展示。 实例 使用: go get github.com/lifei6671/gocaptcha/

Dec 29, 2022
ColorX is a library to determine the most prominent color in an image written in golang

ColorX is a library to determine the most prominent color in an image. ColorX doesn't use any sort of complex algorithms to calculate the prominent color, it simply loops over the image pixels and returns the color that occurs the most.

Nov 11, 2021
A festive Christmas tree GIF generator implemented using only Golang standard library code
A festive Christmas tree GIF generator implemented using only Golang standard library code

Christmas Tree GIF Generator A festive Christmas tree GIF generator implemented

Feb 4, 2022
geoserver is a Go library for manipulating a GeoServer instance via the GeoServer REST API.
geoserver is a Go library for manipulating a GeoServer instance via the GeoServer REST API.

Geoserver geoserver Is a Go Package For Manipulating a GeoServer Instance via the GeoServer REST API. How to install: go get -v gopkg.in/hishamkaram/g

Dec 22, 2022
General purpose library for reading, writing and working with OpenStreetMap data

osm This package is a general purpose library for reading, writing and working with OpenStreetMap data in Go (golang). It has the ability to read OSM

Dec 30, 2022
S2 geometry library in Go

Overview S2 is a library for spherical geometry that aims to have the same robustness, flexibility, and performance as the best planar geometry librar

Jan 8, 2023
Go package for fast high-level image processing powered by libvips C library

bimg Small Go package for fast high-level image processing using libvips via C bindings, providing a simple programmatic API. bimg was designed to be

Jan 2, 2023
Image processing library and rendering toolkit for Go.

blend Image processing library and rendering toolkit for Go. (WIP) Installation: This library is compatible with Go1. go get github.com/phrozen/blend

Nov 11, 2022
Go bindings to OpenGL Utility Library

GLU This package offers minimal bindings for GLU functions. Usage go get github.com/go-gl-legacy/glu License Copyright 2012 The go-gl Authors. All ri

Aug 18, 2018
Go binding for the cairo graphics library

go-cairo Go binding for the cairo graphics library Based on Dethe Elza's version https://bitbucket.org/dethe/gocairo but significantly extended and up

Dec 19, 2022
A lightning fast image processing and resizing library for Go

govips A lightning fast image processing and resizing library for Go This package wraps the core functionality of libvips image processing library by

Jan 8, 2023