Coder Social home page Coder Social logo

metalblueberry / go-plotly Goto Github PK

View Code? Open in Web Editor NEW
94.0 4.0 13.0 2.4 MB

The goal of the go-plotly package is to provide a pleasant Go interface for creating figure specifications which are displayed by the plotly.js JavaScript graphing library.

License: MIT License

Go 100.00%
golang go plotly plotlyjs graph plotting plotly-python

go-plotly's Introduction

Go Report Card godoc

go-plotly

Inspired by Python Plotly

The goal of the go-plotly package is to provide a pleasant Go interface for creating figure specifications which are displayed by the plotly.js JavaScript graphing library.

In the context of the plotly.js library, a figure is specified by a declarative JSON data structure.

Therefore, you should always keep in mind as you are creating and updating figures using the go-plotly package that its ultimate goal is to help users produce Go structures that can be automatically serialized into the JSON data structure that the plotly.js graphing library understands.

Yes, that text is a copy paste from Python description.

The good thing about this package is that it's automatically generated based on the schema described here so It will be easy to keep it up to date or to generate different versions of it.

Just a reminder from semver: Major version zero (0.y.z) is for initial development. Anything MAY change at any time. The public API SHOULD NOT be considered stable.

Example

package main

import (
    grob "github.com/MetalBlueberry/go-plotly/graph_objects"
    "github.com/MetalBlueberry/go-plotly/offline"
)

func main() {
    fig := &grob.Fig{
        Data: grob.Traces{
            &grob.Bar{
                Type: grob.TraceTypeBar,
                X:    []float64{1, 2, 3},
                Y:    []float64{1, 2, 3},
            },
        },
        Layout: &grob.Layout{
            Title: &grob.LayoutTitle{
                Text: "A Figure Specified By Go Struct",
            },
        },
    }

    offline.Show(fig)
}

This will open your browser and display the following plot

Bar

And that's it.

See the examples dir for more examples.

Structure

Each trace type has its own file on graph_objecs (grob) package. The file contains the main structure and all the needed nested objects. Files ending with _gen are automatically generated files running go generate. This is executing the code in generator package to generate the structures from the plotly schema. The types are documented, but you can find more examples and extended documentation at Plotly's documentation.

The values that can hold single values or arrays are defined as custom types that are a type definition of interfaces{}. Most common case are X and Y values. You can pass any number slice and it will work ([]float64,[]int,[]int64...). In case of Hovertext, you can provide a []string to display a text for each point, a string to display the same for all or []int to display a number.

Nested Properties, are defined as new types. This is great for auto completion using vscode because you can write all the boilerplate with ctrl+space. For example, the field Title.Text is accessed by the property Title of type {{Type}}Title that contains the property Text. The Type is always the struct that contains the field. For Layout It is LayoutTitle.

Flaglist and Enumerated fields are defined with a type and its constant values. This provides useful autocompletion. Keep in mind that you can compose multiple values for a Flaglist like Mode: grob.ScatterModeMarkers + "+" + grob.ScatterModeLines,. You can read de inline documentation to see the default value.

Tested

Examples, Code generation and Offline package are based on version 1.58.4, but It should work with other versions as this library just generates standard JSON.

Testing

The package lacks of unit testing basically because it's just building JSON to be consumed by plotly.js. This means that I do not see a clear way of building valuable unit testing that doesn't involve the usage of plotly.js. If the package compiles, It means that types are generated correctly.

Said that, I'm thinking about adding some integration testing with Docker, but for now, I've enough if the examples are working.

If you have any good idea of how to test this code, I will be happy to hear it.

Progress

The main focus is to have the structures to hold the data and provide auto competition. Once we get there, we will be on v1.0.0.

Currently, most common use cases should be already covered. Feel free to create an issue if you find something that it's not working.

FAQ

What's the meaning of "grob"?

In python, the component is called graph_objects, like in this package, but that's too long to write it over and over again. In Python, usually it's called "go" from Graph_Objects but in Go... that's not possible for a conflict with a keyword. as an alternative, I've decided to use "grob" from GRaph_OBjects.

How are the graph_object files generated?

I was using "plate", but it was a bad idea. Now it is just plan go code inside the generator package. This should be much easier to understand and to contribute. Let me know if you want to contribute!!

What are the usecases?

  1. Send plotly figures to the frontend ready to be drawn, avoiding possible mistakes in JS thanks to types!

  2. Generate an awesome dynamic plot in a local file with offline package.

  3. I don't know, just do something awesome and let me know it.

Why are the String and Bool types defined?

I'm thinking about defining everything as a pointer, it should be better in the long run

This is to handle the omitempty flag in json serialization. Turns out that if the flag is set, you cannot create a json object with a flag set to false. For example, turn off visibility of the legend will be impossible without this.

For bool, the solution is as simple as defining the types again inside graph_objects and it feels like using normal bool values.

For strings... This is a little bit more complicated, In AWS package they are using aws.String which maps to *string to workaround this issue, but I find that really annoying because you have to wrap every single string with aws.String("whatever"). For now I've decided to define the type String but leave it as interface{} instead of *string to allow you to use raw strings. The draw back is that you can pass any value of your choice... Hopefully you can live with this :).

For numbers... It's similar to strings, Right now you cannot create plots with integer/float numbers with 0 value. I've only encounter problems when trying to remove the margin and can be workaround with an small value like 0.001. I would like to avoid using interface{} or defining types again to keep the package interface as simple as possible.

Star History

Star History Chart

go-plotly's People

Contributors

adityaxdiwakar avatar metalblueberry avatar mmichal9 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

go-plotly's Issues

Pie charts overlapping

Hello,

First, thank you for your effort in creating a wrapper for Plotly. As a GO enthusiastic I think it's amazing to have such tool in Go ecosystem.

I saw that Fig.Data accepts an array Trace (or Traces), but I'm trying to plot two Pie Charts in the same Fig and they are overlapping. Is it possible to generate multiple charts in the same figure?

This is my code:

func generatePieOfNumberOfDiagnosedPeople(diagnosis *grob.Pie, womans *grob.Pie) {
	fig := &grob.Fig{}
	fig.Data = append(fig.Data, diagnosis, womans)
	fig.Layout = &grob.Layout{
		Title: &grob.LayoutTitle{
			Text: "Número de pessoas com possível diagnóstico de Síndrome do Impostor",
		},
	}

	offline.ToHtml(fig, "diagnosis.html")
}

This is the result:
image

This is what I would like in the same HTML (ignore sizes):
image
image

Here's some color for your 3D scatterplot example

I found the colors somewhat difficult to figure out in GoLang because Go doesn't allow multi-type slices/arrays. Might be fun to show some options. Here's an example where I made custom colors. (Setting Cauto: grob.True also works).

colorScale := "[" +
	"[0.0, #6e40aa]," +
	"[0.1, #963db3]," +
	"[0.2, #bf3caf]," +
	"[0.3, #e4419d]," +
	"[0.4, #fe4b83]," +
	"[0.5, #ff5e63]," +
	"[0.6, #ff7847]," +
	"[0.7, #fb9633]," +
	"[0.8, #e2b72f]," +
	"[0.9, #c6d63c]," +
	"[1.0, #aff05b]" +
	"]"

t := linspace(0, 10, 50)
x := cos(t)
y := sin(t)
z := t
fig := &grob.Fig{
	Data: grob.Traces{
		&grob.Scatter3d{
			Type: grob.TraceTypeScatter3d,
			X:    x,
			Y:    y,
			Z:    z,
			Mode: grob.Scatter3dModeMarkers,
			Marker: &grob.Scatter3dMarker{
				Autocolorscale: grob.False,
				Cauto:          grob.False,
				Cmin:           0,
				Cmid:           5,
				Cmax:           10,
				Color:          z,
				Colorscale:     colorScale,
				Showscale:      grob.True,
				Size:           4,
			},
		},
	},
	Layout: &grob.Layout{
		Height: 700,
		Width: 1200,
		Title: &grob.LayoutTitle{
			Text: "3D Spiral",
		},
	},
}
offline.Show(fig)

Or with a color gradient...

import "github.com/mazznoer/colorgrad"

grad := colorgrad.Warm()
var colorScaleArr []string
for i := 0.; i <= 1; i += 0.1 {
	colorScaleArr = append(colorScaleArr, fmt.Sprintf("[%.1f, %s]", i, grad.At(i).Hex()))
}

fig := &grob.Fig{
	Data: grob.Traces{
		&grob.Scatter3d{
			Type: grob.TraceTypeScatter3d,
			X:    x,
			Y:    y,
			Z:    z,
			Mode: grob.Scatter3dModeMarkers,
			Marker: &grob.Scatter3dMarker{
				Autocolorscale: grob.False,
				Cauto:          grob.True,
				Color: z,
				Colorscale: colorScaleArr,
				Showscale: grob.True,
				Size:      1,
			},
		},
	},
	...
}

Remove plate dependency

It has been fun to use plate to generate the structures, but it is a bad idea for several reasons. The main one is that templates are not prepared for complex logic and this projects requires it.

Therefore, I've started a new branch to see if I can replace plate with pure Go code. Hopefully this will simplify the code generation and more people will be able to understand it. The objective just to autogenerate go structs based on plotly schema.

Support subplots

It would be great if it was possible to compose multiple Fig structs (subplots) to form a single plot. See the attached image for a visual example of what I mean. The image was taken from https://plotly.com/r/subplots/.

image

How to plot multiple lines in one plot?

First of all, very nice package, thank you 🙏🏼 One question please, I see data specification is via Data traces, e.g.:

Data: grob.Traces{
	&grob.Scatter{
		Type: grob.TraceTypeScatter,
		X:    t,
		Y:    y,
		Mode: grob.ScatterModeMarkers,
	},
},

Is it possible to plot multiple lines in a single plot, sth like:

Data: grob.Traces{
	&grob.Scatter{
		Type: grob.TraceTypeScatter,
		X:    t,
		Y1:    y1, // or e.g. Y: [2][2]float64{{1,2},{3,4}} 
                Y2:    y2, 
		Mode: grob.ScatterModeMarkers,
	},
},

An option with [][]float64{{},{}} actually works, but gives strange results. Is there any way to plot multiple lines in single plot, sth like THIS. Thank you 🙏🏼

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.