├── examples ├── bar │ ├── Bar.png │ ├── bar.html │ └── main.go ├── wasm │ ├── main.wasm │ ├── run.sh │ ├── index.html │ └── main.go ├── static_image │ ├── out.png │ ├── README.md │ └── main.go ├── numpy_bdata │ ├── Dockerfile │ ├── Makefile │ ├── compute.py │ └── main.go ├── transforms │ ├── bar.html │ └── main.go ├── responsive │ ├── bar.html │ └── main.go ├── bar_custom │ ├── bar_custom.html │ └── main.go ├── go.mod ├── shapes │ ├── bar.html │ └── main.go ├── subplots_share_axes │ ├── subplots_share_axes.html │ └── main.go ├── unmarshal │ └── main.go ├── scatter │ ├── main.go │ └── scatter.html ├── scatter3d │ ├── main.go │ └── scatter3d.html ├── animation_slider │ └── main_test.go ├── colorscale │ └── main.go ├── waterfall_bar_chart │ ├── waterfall.html │ └── main.go ├── animation │ └── animation.go ├── stargazers │ └── main.go ├── range_slider │ └── main.go └── go.sum ├── .gitignore ├── generator ├── templates │ ├── config_base.tmpl │ ├── layout_base.tmpl │ ├── animation_base.tmpl │ ├── enum.tmpl │ ├── trace.tmpl │ ├── flaglist.tmpl │ ├── dummy_types.go │ ├── trace_base.tmpl │ ├── unmarshal.tmpl │ ├── unmarshal_test.go │ ├── frames.go │ └── plotly.go ├── generator_suite_test.go ├── parser_test.go ├── cmd │ ├── downloader │ │ └── main.go │ └── generator │ │ └── main.go ├── mocks │ └── creator.go ├── renderer_test.go └── schema.go ├── pkg ├── types │ ├── trace.go │ ├── fig.go │ ├── arrayok.go │ ├── basic.go │ ├── color.go │ ├── data_array_test.go │ └── data_array.go └── offline │ └── plot.go ├── go.mod ├── generated ├── v2.19.0 │ └── graph_objects │ │ ├── unmarshal_gen_test.go │ │ ├── frames_gen.go │ │ ├── plotly_gen.go │ │ ├── animation_gen.go │ │ └── unmarshal_gen.go ├── v2.29.1 │ └── graph_objects │ │ ├── unmarshal_gen_test.go │ │ ├── frames_gen.go │ │ ├── plotly_gen.go │ │ ├── animation_gen.go │ │ └── unmarshal_gen.go ├── v2.31.1 │ └── graph_objects │ │ ├── unmarshal_gen_test.go │ │ ├── frames_gen.go │ │ ├── plotly_gen.go │ │ ├── animation_gen.go │ │ └── unmarshal_gen.go └── v2.34.0 │ └── graph_objects │ ├── unmarshal_gen_test.go │ ├── frames_gen.go │ ├── plotly_gen.go │ ├── animation_gen.go │ └── unmarshal_gen.go ├── .github └── workflows │ └── test.yaml ├── schemas.yaml ├── LICENSE ├── go.sum └── README.md /examples/bar/Bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetalBlueberry/go-plotly/HEAD/examples/bar/Bar.png -------------------------------------------------------------------------------- /examples/wasm/main.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetalBlueberry/go-plotly/HEAD/examples/wasm/main.wasm -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | examples/Bar/Bar 2 | examples/bar/bar 3 | examples/bar_custom/go_custom 4 | .vscode/launch.json 5 | -------------------------------------------------------------------------------- /examples/static_image/out.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetalBlueberry/go-plotly/HEAD/examples/static_image/out.png -------------------------------------------------------------------------------- /generator/templates/config_base.tmpl: -------------------------------------------------------------------------------- 1 | package grob 2 | 3 | {{ . }} 4 | 5 | import ( 6 | "github.com/MetalBlueberry/go-plotly/pkg/types" 7 | ) 8 | -------------------------------------------------------------------------------- /generator/templates/layout_base.tmpl: -------------------------------------------------------------------------------- 1 | package grob 2 | 3 | {{ . }} 4 | 5 | import ( 6 | "github.com/MetalBlueberry/go-plotly/pkg/types" 7 | ) 8 | -------------------------------------------------------------------------------- /examples/wasm/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | GOOS=js GOARCH=wasm go build -o main.wasm 3 | goexec 'http.ListenAndServe(`:8080`, http.FileServer(http.Dir(`.`)))' -------------------------------------------------------------------------------- /generator/templates/animation_base.tmpl: -------------------------------------------------------------------------------- 1 | package grob 2 | 3 | {{ . }} 4 | 5 | import ( 6 | "github.com/MetalBlueberry/go-plotly/pkg/types" 7 | ) 8 | -------------------------------------------------------------------------------- /examples/numpy_bdata/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9-slim 2 | 3 | WORKDIR /app 4 | 5 | RUN pip install numpy 6 | 7 | COPY compute.py . 8 | 9 | CMD ["python", "compute.py"] 10 | -------------------------------------------------------------------------------- /examples/numpy_bdata/Makefile: -------------------------------------------------------------------------------- 1 | IMAGE_NAME = plotly-data-generator 2 | 3 | all: build run 4 | 5 | build: 6 | @docker build -t $(IMAGE_NAME) . 7 | 8 | run: 9 | @docker run --rm $(IMAGE_NAME) 10 | 11 | 12 | 13 | clean: 14 | @docker rmi $(IMAGE_NAME) 15 | -------------------------------------------------------------------------------- /generator/templates/enum.tmpl: -------------------------------------------------------------------------------- 1 | {{- $root := . -}} 2 | // {{.Name }} {{.Description}} 3 | // {{ .JSONPath }} 4 | type {{.Name }} {{.Type}} 5 | 6 | {{ .ConstOrVar }} ( 7 | {{ range .Values -}} 8 | {{.Name}} {{$root.Name}} = {{.Value}} 9 | {{ end }} 10 | ) 11 | -------------------------------------------------------------------------------- /examples/static_image/README.md: -------------------------------------------------------------------------------- 1 | # Static Image 2 | 3 | To save Plotly images as static images, you should use the [orca](https://github.com/plotly/orca) project. This example uses a docker image with orca to render a plot to PNG. You can refer to orca documentation to extend this further. 4 | -------------------------------------------------------------------------------- /generator/generator_suite_test.go: -------------------------------------------------------------------------------- 1 | package generator_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/onsi/ginkgo/v2" 7 | . "github.com/onsi/gomega" 8 | ) 9 | 10 | func TestGenerator(t *testing.T) { 11 | RegisterFailHandler(Fail) 12 | RunSpecs(t, "Generator Suite") 13 | } 14 | -------------------------------------------------------------------------------- /generator/templates/trace.tmpl: -------------------------------------------------------------------------------- 1 | // {{.Name }} {{.Description}} 2 | type {{.Name }} struct { 3 | {{ range .Fields }} 4 | // {{.Name }} {{ range .Description }} 5 | // {{.}} {{ end }} 6 | // {{ .JSONPath }} 7 | {{.Name }} {{.Type}} `json:"{{.JSONName}},omitempty"` 8 | {{ end }} 9 | } 10 | -------------------------------------------------------------------------------- /pkg/types/trace.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | // TraceType is the type for the TraceType field on every trace 4 | type TraceType string 5 | 6 | // Trace Every trace implements this interface 7 | // It is useful for autocompletion, it is a better idea to use 8 | // type assertions/switches to identify trace types 9 | type Trace interface { 10 | GetType() TraceType 11 | } 12 | -------------------------------------------------------------------------------- /examples/bar/bar.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
7 | 11 | 12 | -------------------------------------------------------------------------------- /examples/transforms/bar.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
7 | 11 | 12 | -------------------------------------------------------------------------------- /generator/templates/flaglist.tmpl: -------------------------------------------------------------------------------- 1 | {{- $root := . -}} 2 | // {{.Name }} {{.Description}} 3 | // {{ .JSONPath }} 4 | type {{.Name }} {{.Type}} 5 | 6 | {{ .ConstOrVar }} ( 7 | // Flags 8 | {{ range .Flags -}} 9 | {{.Name}} {{$root.Name}} = {{.Value}} 10 | {{ end }} 11 | // Extra 12 | {{ range .Extra -}} 13 | {{.Name}} {{$root.Name}} = {{.Value}} 14 | {{ end }} 15 | ) 16 | -------------------------------------------------------------------------------- /examples/responsive/bar.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
7 | 11 | 12 | -------------------------------------------------------------------------------- /generator/parser_test.go: -------------------------------------------------------------------------------- 1 | package generator_test 2 | 3 | import ( 4 | "bytes" 5 | "log" 6 | 7 | "github.com/MetalBlueberry/go-plotly/generator" 8 | . "github.com/onsi/ginkgo/v2" 9 | . "github.com/onsi/gomega" 10 | ) 11 | 12 | var _ = Describe("Parser", func() { 13 | It("Should parse traces", func() { 14 | reader := bytes.NewReader(schema) 15 | 16 | root, err := generator.LoadSchema(reader) 17 | Expect(err).To(BeNil()) 18 | 19 | log.Println(root) 20 | }) 21 | }) 22 | -------------------------------------------------------------------------------- /examples/wasm/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 19 | -------------------------------------------------------------------------------- /examples/bar_custom/bar_custom.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
7 | 11 | 12 | -------------------------------------------------------------------------------- /examples/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/metalblueberry/plotly/examples 2 | 3 | go 1.22 4 | 5 | require ( 6 | github.com/MetalBlueberry/go-plotly v0.4.0 7 | github.com/go-gota/gota v0.12.0 8 | github.com/lucasb-eyer/go-colorful v1.2.0 9 | github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c 10 | golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 11 | ) 12 | 13 | require ( 14 | golang.org/x/net v0.28.0 // indirect 15 | golang.org/x/sys v0.23.0 // indirect 16 | gonum.org/v1/gonum v0.15.0 // indirect 17 | ) 18 | 19 | replace github.com/MetalBlueberry/go-plotly => ./../ 20 | -------------------------------------------------------------------------------- /examples/shapes/bar.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
7 | 11 | 12 | -------------------------------------------------------------------------------- /generator/templates/dummy_types.go: -------------------------------------------------------------------------------- 1 | package grob 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MetalBlueberry/go-plotly/pkg/types" 7 | ) 8 | 9 | // Types defined here are just meant to allow compilation for the template package 10 | // This simplifies the process of writing the static templates 11 | 12 | type Layout struct{} 13 | type Config struct{} 14 | type Animation struct{} 15 | 16 | func UnmarshalTrace(json.RawMessage) (types.Trace, error) { return &Bar{}, nil } 17 | 18 | type Bar struct { 19 | Type types.TraceType `json:"type"` 20 | } 21 | 22 | func (b *Bar) GetType() types.TraceType { return "bar" } 23 | -------------------------------------------------------------------------------- /examples/subplots_share_axes/subplots_share_axes.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
7 | 11 | 12 | -------------------------------------------------------------------------------- /pkg/types/fig.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | // Fig Represents a plotly figure 4 | // use the Info method to get details about the plotly version 5 | type Fig interface { 6 | Info() Version 7 | } 8 | 9 | type Version struct { 10 | Name string `yaml:"Name"` // name of the version 11 | Tag string `yaml:"Tag"` // git tag of the plotly version 12 | URL string `yaml:"URL"` // url under which the plotly schema json file can be downloaded directly 13 | Path string `yaml:"Path"` // path under which the schema file will be saved locally for future use 14 | Generated string `yaml:"Generated"` // path for the generated package 15 | Cdn string `yaml:"CDN"` // url for the cdn which should be included in the head of the generated html 16 | } 17 | -------------------------------------------------------------------------------- /generator/templates/trace_base.tmpl: -------------------------------------------------------------------------------- 1 | package grob 2 | 3 | {{ .DoNotEdit }} 4 | 5 | import ( 6 | "github.com/MetalBlueberry/go-plotly/pkg/types" 7 | "encoding/json" 8 | ) 9 | 10 | var TraceType{{ .TraceTypeName }} types.TraceType = "{{ .TraceName }}" 11 | 12 | func (t *{{ .TraceTypeName }}) GetType() types.TraceType { 13 | return TraceType{{ .TraceTypeName }} 14 | } 15 | 16 | func (t *{{ .TraceTypeName }}) MarshalJSON() ([]byte, error) { 17 | // Define the custom JSON structure including the "type" field 18 | type Alias {{ .TraceTypeName }} 19 | return json.Marshal(&struct { 20 | Type types.TraceType `json:"type"` 21 | *Alias 22 | }{ 23 | Type: t.GetType(), // Add your desired default value here 24 | Alias: (*Alias)(t), // Embed the original struct fields 25 | }) 26 | } 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/MetalBlueberry/go-plotly 2 | 3 | go 1.22 4 | 5 | require ( 6 | github.com/golang/mock v1.6.0 7 | github.com/huandu/xstrings v1.4.0 8 | github.com/onsi/ginkgo/v2 v2.17.2 9 | github.com/onsi/gomega v1.33.0 10 | github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c 11 | gopkg.in/yaml.v3 v3.0.1 12 | ) 13 | 14 | require ( 15 | github.com/go-logr/logr v1.4.1 // indirect 16 | github.com/go-task/slim-sprig/v3 v3.0.0 // indirect 17 | github.com/google/go-cmp v0.6.0 // indirect 18 | github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 // indirect 19 | golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 20 | golang.org/x/net v0.28.0 // indirect 21 | golang.org/x/sys v0.23.0 // indirect 22 | golang.org/x/text v0.17.0 // indirect 23 | golang.org/x/tools v0.24.0 // indirect 24 | ) 25 | -------------------------------------------------------------------------------- /examples/numpy_bdata/compute.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import json 3 | import base64 4 | 5 | # Generate Z data using NumPy 6 | # Let's create a similar 3x5 matrix with some values 7 | z = np.array([ 8 | [1, np.nan, 30, 50, 1], 9 | [20, 1, 60, 80, 30], 10 | [30, 60, 1, -10, 20] 11 | ]) 12 | 13 | 14 | 15 | dtype = z.dtype 16 | bdata = z.tobytes() # Binary data representation 17 | shape = z.shape 18 | 19 | # Encode the binary data as a base64 string 20 | z_bdata_base64 = base64.b64encode(bdata).decode('utf-8') 21 | 22 | # Create the dictionary that represents the JSON object 23 | z_data = { 24 | 'dtype': str(dtype), 25 | 'shape': shape, 26 | 'bdata': z_bdata_base64 27 | } 28 | 29 | # Convert the dictionary to a JSON object 30 | json_data = json.dumps(z_data, indent=2) 31 | 32 | # Output the JSON object 33 | print(json_data) -------------------------------------------------------------------------------- /examples/transforms/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | grob "github.com/MetalBlueberry/go-plotly/generated/v2.31.1/graph_objects" 5 | "github.com/MetalBlueberry/go-plotly/pkg/offline" 6 | "github.com/MetalBlueberry/go-plotly/pkg/types" 7 | ) 8 | 9 | func main() { 10 | /* 11 | fig = dict({ 12 | "data": [{"type": "bar", 13 | "x": [1, 2, 3], 14 | "y": [1, 3, 2]}], 15 | "layout": {"title": {"text": "A Figure Specified By Python Dictionary"}} 16 | }) 17 | */ 18 | fig := &grob.Fig{ 19 | Data: []types.Trace{ 20 | &grob.Bar{ 21 | X: types.DataArray([]float64{1, 2, 3}), 22 | Y: types.DataArray([]float64{1, 2, 3}), 23 | }, 24 | }, 25 | Layout: &grob.Layout{ 26 | Title: &grob.LayoutTitle{ 27 | Text: types.S("A Figure Specified By Go Struct"), 28 | }, 29 | }, 30 | } 31 | 32 | offline.ToHtml(fig, "bar.html") 33 | offline.Show(fig) 34 | } 35 | -------------------------------------------------------------------------------- /examples/bar/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | grob "github.com/MetalBlueberry/go-plotly/generated/v2.31.1/graph_objects" 5 | "github.com/MetalBlueberry/go-plotly/pkg/offline" 6 | "github.com/MetalBlueberry/go-plotly/pkg/types" 7 | ) 8 | 9 | func main() { 10 | /* 11 | fig = dict({ 12 | "data": [{"type": "bar", 13 | "x": [1, 2, 3], 14 | "y": [1, 3, 2]}], 15 | "layout": {"title": {"text": "A Figure Specified By Python Dictionary"}} 16 | }) 17 | */ 18 | fig := &grob.Fig{ 19 | Data: []types.Trace{ 20 | &grob.Bar{ 21 | X: types.DataArray([]float64{1, 2, 3}), 22 | Y: types.DataArray([]float64{1, 2, 3}), 23 | }, 24 | }, 25 | Layout: &grob.Layout{ 26 | Title: &grob.LayoutTitle{ 27 | Text: "A Figure Specified By Go Struct", 28 | }, 29 | }, 30 | } 31 | 32 | offline.ToHtml(fig, "bar.html") 33 | offline.Show(fig) 34 | offline.Serve(fig) 35 | } 36 | -------------------------------------------------------------------------------- /generator/templates/unmarshal.tmpl: -------------------------------------------------------------------------------- 1 | package grob 2 | 3 | // Code generated by go-plotly/generator. DO NOT EDIT 4 | 5 | import ( 6 | "encoding/json" 7 | "errors" 8 | "github.com/MetalBlueberry/go-plotly/pkg/types" 9 | ) 10 | 11 | type unmarshalType struct { 12 | Type types.TraceType `json:"type,omitempty"` 13 | } 14 | 15 | // UnmarshalTrace decodes an array of bytes into a Trace interface. 16 | func UnmarshalTrace(data []byte) (types.Trace,error) { 17 | traceType := unmarshalType{} 18 | err := json.Unmarshal(data, &traceType) 19 | if err != nil { 20 | return nil, err 21 | } 22 | switch traceType.Type { 23 | {{- range $name := .Types }} 24 | case TraceType{{ $name }}: 25 | trace := &{{ $name }}{} 26 | err = json.Unmarshal(data,trace) 27 | if err != nil { 28 | return nil, err 29 | } 30 | return trace, nil 31 | {{- end }} 32 | default: 33 | return nil, errors.New("Trace Type is not registered") 34 | } 35 | } -------------------------------------------------------------------------------- /examples/responsive/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | grob "github.com/MetalBlueberry/go-plotly/generated/v2.31.1/graph_objects" 5 | "github.com/MetalBlueberry/go-plotly/pkg/offline" 6 | "github.com/MetalBlueberry/go-plotly/pkg/types" 7 | ) 8 | 9 | func main() { 10 | /* 11 | fig = dict({ 12 | "data": [{"type": "bar", 13 | "x": [1, 2, 3], 14 | "y": [1, 3, 2]}], 15 | "layout": {"title": {"text": "A Figure Specified By Python Dictionary"}} 16 | }) 17 | */ 18 | fig := &grob.Fig{ 19 | Data: []types.Trace{ 20 | &grob.Bar{ 21 | X: types.DataArray([]float64{1, 2, 3}), 22 | Y: types.DataArray([]float64{1, 2, 3}), 23 | }, 24 | }, 25 | Layout: &grob.Layout{ 26 | Title: &grob.LayoutTitle{ 27 | Text: types.S("A Figure Specified By Go Struct"), 28 | }, 29 | }, 30 | Config: &grob.Config{ 31 | Responsive: types.True, 32 | }, 33 | } 34 | 35 | offline.ToHtml(fig, "bar.html") 36 | offline.Show(fig) 37 | } 38 | -------------------------------------------------------------------------------- /generator/templates/unmarshal_test.go: -------------------------------------------------------------------------------- 1 | package grob 2 | 3 | import ( 4 | "encoding/json" 5 | "strings" 6 | "testing" 7 | ) 8 | 9 | func TestUnmarshalTrace(t *testing.T) { 10 | data := `{"type":"bar"}` 11 | trace, err := UnmarshalTrace([]byte(data)) 12 | if err != nil { 13 | t.Logf("Error during Unmarshal, %s", err) 14 | t.FailNow() 15 | } 16 | if traceType := trace.GetType(); traceType != "bar" { 17 | t.Logf("Error recovering type, Expected \"bar\", got %s", traceType) 18 | t.FailNow() 19 | } 20 | } 21 | 22 | func TestMarshalTrace(t *testing.T) { 23 | bar := &Bar{} 24 | v, err := json.Marshal(bar) 25 | if err != nil { 26 | t.Logf("Error during Marshal, %s", err) 27 | t.FailNow() 28 | } 29 | if !strings.Contains(string(v), "type") { 30 | t.Logf("Output doesn't contain the type field, Expected to contain \"type\", got: %s", v) 31 | t.FailNow() 32 | } 33 | if strings.Contains(string(v), "null") { 34 | t.Logf("Output contains null fields, Expected to not contain any, got: %s", v) 35 | t.FailNow() 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /generated/v2.19.0/graph_objects/unmarshal_gen_test.go: -------------------------------------------------------------------------------- 1 | package grob 2 | 3 | import ( 4 | "encoding/json" 5 | "strings" 6 | "testing" 7 | ) 8 | 9 | func TestUnmarshalTrace(t *testing.T) { 10 | data := `{"type":"bar"}` 11 | trace, err := UnmarshalTrace([]byte(data)) 12 | if err != nil { 13 | t.Logf("Error during Unmarshal, %s", err) 14 | t.FailNow() 15 | } 16 | if traceType := trace.GetType(); traceType != "bar" { 17 | t.Logf("Error recovering type, Expected \"bar\", got %s", traceType) 18 | t.FailNow() 19 | } 20 | } 21 | 22 | func TestMarshalTrace(t *testing.T) { 23 | bar := &Bar{} 24 | v, err := json.Marshal(bar) 25 | if err != nil { 26 | t.Logf("Error during Marshal, %s", err) 27 | t.FailNow() 28 | } 29 | if !strings.Contains(string(v), "type") { 30 | t.Logf("Output doesn't contain the type field, Expected to contain \"type\", got: %s", v) 31 | t.FailNow() 32 | } 33 | if strings.Contains(string(v), "null") { 34 | t.Logf("Output contains null fields, Expected to not contain any, got: %s", v) 35 | t.FailNow() 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /generated/v2.29.1/graph_objects/unmarshal_gen_test.go: -------------------------------------------------------------------------------- 1 | package grob 2 | 3 | import ( 4 | "encoding/json" 5 | "strings" 6 | "testing" 7 | ) 8 | 9 | func TestUnmarshalTrace(t *testing.T) { 10 | data := `{"type":"bar"}` 11 | trace, err := UnmarshalTrace([]byte(data)) 12 | if err != nil { 13 | t.Logf("Error during Unmarshal, %s", err) 14 | t.FailNow() 15 | } 16 | if traceType := trace.GetType(); traceType != "bar" { 17 | t.Logf("Error recovering type, Expected \"bar\", got %s", traceType) 18 | t.FailNow() 19 | } 20 | } 21 | 22 | func TestMarshalTrace(t *testing.T) { 23 | bar := &Bar{} 24 | v, err := json.Marshal(bar) 25 | if err != nil { 26 | t.Logf("Error during Marshal, %s", err) 27 | t.FailNow() 28 | } 29 | if !strings.Contains(string(v), "type") { 30 | t.Logf("Output doesn't contain the type field, Expected to contain \"type\", got: %s", v) 31 | t.FailNow() 32 | } 33 | if strings.Contains(string(v), "null") { 34 | t.Logf("Output contains null fields, Expected to not contain any, got: %s", v) 35 | t.FailNow() 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /generated/v2.31.1/graph_objects/unmarshal_gen_test.go: -------------------------------------------------------------------------------- 1 | package grob 2 | 3 | import ( 4 | "encoding/json" 5 | "strings" 6 | "testing" 7 | ) 8 | 9 | func TestUnmarshalTrace(t *testing.T) { 10 | data := `{"type":"bar"}` 11 | trace, err := UnmarshalTrace([]byte(data)) 12 | if err != nil { 13 | t.Logf("Error during Unmarshal, %s", err) 14 | t.FailNow() 15 | } 16 | if traceType := trace.GetType(); traceType != "bar" { 17 | t.Logf("Error recovering type, Expected \"bar\", got %s", traceType) 18 | t.FailNow() 19 | } 20 | } 21 | 22 | func TestMarshalTrace(t *testing.T) { 23 | bar := &Bar{} 24 | v, err := json.Marshal(bar) 25 | if err != nil { 26 | t.Logf("Error during Marshal, %s", err) 27 | t.FailNow() 28 | } 29 | if !strings.Contains(string(v), "type") { 30 | t.Logf("Output doesn't contain the type field, Expected to contain \"type\", got: %s", v) 31 | t.FailNow() 32 | } 33 | if strings.Contains(string(v), "null") { 34 | t.Logf("Output contains null fields, Expected to not contain any, got: %s", v) 35 | t.FailNow() 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /generated/v2.34.0/graph_objects/unmarshal_gen_test.go: -------------------------------------------------------------------------------- 1 | package grob 2 | 3 | import ( 4 | "encoding/json" 5 | "strings" 6 | "testing" 7 | ) 8 | 9 | func TestUnmarshalTrace(t *testing.T) { 10 | data := `{"type":"bar"}` 11 | trace, err := UnmarshalTrace([]byte(data)) 12 | if err != nil { 13 | t.Logf("Error during Unmarshal, %s", err) 14 | t.FailNow() 15 | } 16 | if traceType := trace.GetType(); traceType != "bar" { 17 | t.Logf("Error recovering type, Expected \"bar\", got %s", traceType) 18 | t.FailNow() 19 | } 20 | } 21 | 22 | func TestMarshalTrace(t *testing.T) { 23 | bar := &Bar{} 24 | v, err := json.Marshal(bar) 25 | if err != nil { 26 | t.Logf("Error during Marshal, %s", err) 27 | t.FailNow() 28 | } 29 | if !strings.Contains(string(v), "type") { 30 | t.Logf("Output doesn't contain the type field, Expected to contain \"type\", got: %s", v) 31 | t.FailNow() 32 | } 33 | if strings.Contains(string(v), "null") { 34 | t.Logf("Output contains null fields, Expected to not contain any, got: %s", v) 35 | t.FailNow() 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /.github/workflows/test.yaml: -------------------------------------------------------------------------------- 1 | # This workflow will build a golang project 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go 3 | 4 | name: Go 5 | 6 | on: 7 | push: 8 | pull_request: 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v4 15 | 16 | - name: Set up Go 17 | uses: actions/setup-go@v4 18 | with: 19 | go-version: "1.22" 20 | 21 | - name: Check Generated Schema 22 | run: | 23 | go generate ./... 24 | git diff --exit-code 25 | 26 | - name: Test 27 | run: go test -v ./... 28 | 29 | - name: Build all packages 30 | run: go build -v ./... 31 | 32 | - name: Build all examples 33 | run: cd examples && go build -v ./... 34 | 35 | - name: Build readme examples 36 | run: |- 37 | mkdir -p readme 38 | sed -n '/^```go/,/^```/p' README.md | sed -e '/^```/d' > "readme/main.go" 39 | go build -o readme/readme "readme/main.go" 40 | rm -rd readme 41 | -------------------------------------------------------------------------------- /schemas.yaml: -------------------------------------------------------------------------------- 1 | versions: 2 | - Name: Plotly 2.34.0 3 | Tag: v2.34.0 4 | URL: https://raw.githubusercontent.com/plotly/plotly.js/v2.34.0/test/plot-schema.json 5 | Path: schemas/v2.34.0/plot-schema.json 6 | Generated: generated/v2.34.0 7 | CDN: https://cdn.plot.ly/plotly-2.34.0.min.js 8 | - Name: Plotly 2.31.1 9 | Tag: v2.31.1 10 | URL: https://raw.githubusercontent.com/plotly/plotly.js/v2.31.1/test/plot-schema.json 11 | Path: schemas/v2.31.1/plot-schema.json 12 | Generated: generated/v2.31.1 13 | CDN: https://cdn.plot.ly/plotly-2.31.1.min.js 14 | - Name: Plotly 2.29.1 15 | Tag: v2.29.1 16 | URL: https://raw.githubusercontent.com/plotly/plotly.js/v2.29.1/test/plot-schema.json 17 | Path: schemas/v2.29.1/plot-schema.json 18 | Generated: generated/v2.29.1 19 | CDN: https://cdn.plot.ly/plotly-2.29.1.min.js 20 | - Name: Plotly 2.19.0 21 | Tag: v2.19.0 22 | URL: https://raw.githubusercontent.com/plotly/plotly.js/v2.19.0/test/plot-schema.json 23 | Path: schemas/v2.19.0/plot-schema.json 24 | Generated: generated/v2.19.0 25 | CDN: https://cdn.plot.ly/plotly-2.19.0.min.js 26 | -------------------------------------------------------------------------------- /generator/cmd/downloader/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "os" 7 | 8 | "github.com/MetalBlueberry/go-plotly/generator" 9 | ) 10 | 11 | // schemaPath location of the schemas file, holding all version to be created 12 | const configPath = "schemas.yaml" 13 | 14 | func main() { 15 | var schemapath string 16 | flag.StringVar(&schemapath, "config", configPath, "yaml file defining versions to be generated") 17 | flag.Parse() 18 | 19 | // Define a flag for the version 20 | versions := generator.ReadSchemas(schemapath) 21 | if versions == nil { 22 | fmt.Printf("could not find versions\n") 23 | return 24 | } 25 | var err error 26 | for _, version := range versions { 27 | 28 | // check if version already downloaded: 29 | _, err = os.Stat(version.Path) 30 | if err == nil { 31 | fmt.Printf("already downloaded version: %s\n", version.Tag) 32 | continue 33 | } 34 | 35 | // download schema 36 | _, err = generator.DownloadSchema(version.Tag, version.URL, version.Path) 37 | if err != nil { 38 | fmt.Printf("failed to download version: %s\n", version.Tag) 39 | return 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Víctor Pérez (MetalBlueberry) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /examples/unmarshal/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "math" 6 | 7 | grob "github.com/MetalBlueberry/go-plotly/generated/v2.31.1/graph_objects" 8 | "github.com/MetalBlueberry/go-plotly/pkg/offline" 9 | "github.com/MetalBlueberry/go-plotly/pkg/types" 10 | ) 11 | 12 | func main() { 13 | t := linspace(0, 10, 100) 14 | y := sin(t) 15 | 16 | fig := &grob.Fig{ 17 | Data: []types.Trace{ 18 | &grob.Scatter{ 19 | X: types.DataArray(t), 20 | Y: types.DataArray(y), 21 | Mode: grob.ScatterModeMarkers, 22 | }, 23 | }, 24 | } 25 | 26 | bytes, err := json.Marshal(fig) 27 | if err != nil { 28 | panic(err) 29 | } 30 | 31 | // Demonstrates that a json representation can be loaded 32 | recoveredFig := &grob.Fig{} 33 | json.Unmarshal(bytes, recoveredFig) 34 | offline.Show(recoveredFig) 35 | } 36 | 37 | func linspace(start, stop float64, points int) []float64 { 38 | step := (stop - start) / float64(points) 39 | out := make([]float64, points) 40 | 41 | for i := 0; i < points; i++ { 42 | out[i] = start + step*float64(i) 43 | } 44 | return out 45 | } 46 | 47 | func sin(x []float64) []float64 { 48 | y := make([]float64, len(x)) 49 | for i := 1; i < len(x); i++ { 50 | y[i] = math.Sin(x[i]) 51 | } 52 | return y 53 | } 54 | -------------------------------------------------------------------------------- /generator/templates/frames.go: -------------------------------------------------------------------------------- 1 | package grob 2 | 3 | // {{ . }} 4 | 5 | import ( 6 | "github.com/MetalBlueberry/go-plotly/pkg/types" 7 | ) 8 | 9 | // Frame 10 | type Frame struct { 11 | 12 | // Baseframe 13 | // The name of the frame into which this frame's properties are merged before applying. This is used to unify properties and avoid needing to specify the same values for the same properties in multiple frames. 14 | Baseframe types.StringType `json:"baseframe,omitempty"` 15 | 16 | // Data 17 | // A list of traces this frame modifies. The format is identical to the normal trace definition. 18 | Data []types.Trace `json:"data,omitempty"` 19 | 20 | // Group 21 | // An identifier that specifies the group to which the frame belongs, used by animate to select a subset of frames. 22 | Group types.StringType `json:"group,omitempty"` 23 | 24 | // Layout 25 | // Layout properties which this frame modifies. The format is identical to the normal layout definition. 26 | Layout *Layout `json:"layout,omitempty"` 27 | 28 | // Name 29 | // A label by which to identify the frame 30 | Name types.StringType `json:"name,omitempty"` 31 | 32 | // Traces 33 | // A list of trace indices that identify the respective traces in the data attribute 34 | Traces []int `json:"traces,omitempty"` 35 | } 36 | -------------------------------------------------------------------------------- /examples/scatter/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "math" 5 | 6 | grob "github.com/MetalBlueberry/go-plotly/generated/v2.31.1/graph_objects" 7 | "github.com/MetalBlueberry/go-plotly/pkg/offline" 8 | "github.com/MetalBlueberry/go-plotly/pkg/types" 9 | ) 10 | 11 | func main() { 12 | /* 13 | import plotly.graph_objects as go 14 | import numpy as np 15 | 16 | N = 1000 17 | t = np.linspace(0, 10, 100) 18 | y = np.sin(t) 19 | 20 | fig = go.Figure(data=go.Scatter(x=t, y=y, mode='markers')) 21 | 22 | fig.show() 23 | */ 24 | t := linspace(0, 10, 100) 25 | y := sin(t) 26 | 27 | fig := &grob.Fig{ 28 | Data: []types.Trace{ 29 | &grob.Scatter{ 30 | X: types.DataArray(t), 31 | Y: types.DataArray(y), 32 | Mode: grob.ScatterModeMarkers, 33 | }, 34 | }, 35 | } 36 | 37 | offline.ToHtml(fig, "scatter.html") 38 | offline.Show(fig) 39 | } 40 | 41 | func linspace(start, stop float64, points int) []float64 { 42 | step := (stop - start) / float64(points) 43 | out := make([]float64, points) 44 | 45 | for i := 0; i < points; i++ { 46 | out[i] = start + step*float64(i) 47 | } 48 | return out 49 | } 50 | 51 | func sin(x []float64) []float64 { 52 | y := make([]float64, len(x)) 53 | for i := 1; i < len(x); i++ { 54 | y[i] = math.Sin(x[i]) 55 | } 56 | return y 57 | } 58 | -------------------------------------------------------------------------------- /generated/v2.19.0/graph_objects/frames_gen.go: -------------------------------------------------------------------------------- 1 | package grob 2 | 3 | // // Code generated by go-plotly/generator. DO NOT EDIT. 4 | 5 | import ( 6 | "github.com/MetalBlueberry/go-plotly/pkg/types" 7 | ) 8 | 9 | // Frame 10 | type Frame struct { 11 | 12 | // Baseframe 13 | // The name of the frame into which this frame's properties are merged before applying. This is used to unify properties and avoid needing to specify the same values for the same properties in multiple frames. 14 | Baseframe types.StringType `json:"baseframe,omitempty"` 15 | 16 | // Data 17 | // A list of traces this frame modifies. The format is identical to the normal trace definition. 18 | Data []types.Trace `json:"data,omitempty"` 19 | 20 | // Group 21 | // An identifier that specifies the group to which the frame belongs, used by animate to select a subset of frames. 22 | Group types.StringType `json:"group,omitempty"` 23 | 24 | // Layout 25 | // Layout properties which this frame modifies. The format is identical to the normal layout definition. 26 | Layout *Layout `json:"layout,omitempty"` 27 | 28 | // Name 29 | // A label by which to identify the frame 30 | Name types.StringType `json:"name,omitempty"` 31 | 32 | // Traces 33 | // A list of trace indices that identify the respective traces in the data attribute 34 | Traces []int `json:"traces,omitempty"` 35 | } 36 | -------------------------------------------------------------------------------- /generated/v2.29.1/graph_objects/frames_gen.go: -------------------------------------------------------------------------------- 1 | package grob 2 | 3 | // // Code generated by go-plotly/generator. DO NOT EDIT. 4 | 5 | import ( 6 | "github.com/MetalBlueberry/go-plotly/pkg/types" 7 | ) 8 | 9 | // Frame 10 | type Frame struct { 11 | 12 | // Baseframe 13 | // The name of the frame into which this frame's properties are merged before applying. This is used to unify properties and avoid needing to specify the same values for the same properties in multiple frames. 14 | Baseframe types.StringType `json:"baseframe,omitempty"` 15 | 16 | // Data 17 | // A list of traces this frame modifies. The format is identical to the normal trace definition. 18 | Data []types.Trace `json:"data,omitempty"` 19 | 20 | // Group 21 | // An identifier that specifies the group to which the frame belongs, used by animate to select a subset of frames. 22 | Group types.StringType `json:"group,omitempty"` 23 | 24 | // Layout 25 | // Layout properties which this frame modifies. The format is identical to the normal layout definition. 26 | Layout *Layout `json:"layout,omitempty"` 27 | 28 | // Name 29 | // A label by which to identify the frame 30 | Name types.StringType `json:"name,omitempty"` 31 | 32 | // Traces 33 | // A list of trace indices that identify the respective traces in the data attribute 34 | Traces []int `json:"traces,omitempty"` 35 | } 36 | -------------------------------------------------------------------------------- /generated/v2.31.1/graph_objects/frames_gen.go: -------------------------------------------------------------------------------- 1 | package grob 2 | 3 | // // Code generated by go-plotly/generator. DO NOT EDIT. 4 | 5 | import ( 6 | "github.com/MetalBlueberry/go-plotly/pkg/types" 7 | ) 8 | 9 | // Frame 10 | type Frame struct { 11 | 12 | // Baseframe 13 | // The name of the frame into which this frame's properties are merged before applying. This is used to unify properties and avoid needing to specify the same values for the same properties in multiple frames. 14 | Baseframe types.StringType `json:"baseframe,omitempty"` 15 | 16 | // Data 17 | // A list of traces this frame modifies. The format is identical to the normal trace definition. 18 | Data []types.Trace `json:"data,omitempty"` 19 | 20 | // Group 21 | // An identifier that specifies the group to which the frame belongs, used by animate to select a subset of frames. 22 | Group types.StringType `json:"group,omitempty"` 23 | 24 | // Layout 25 | // Layout properties which this frame modifies. The format is identical to the normal layout definition. 26 | Layout *Layout `json:"layout,omitempty"` 27 | 28 | // Name 29 | // A label by which to identify the frame 30 | Name types.StringType `json:"name,omitempty"` 31 | 32 | // Traces 33 | // A list of trace indices that identify the respective traces in the data attribute 34 | Traces []int `json:"traces,omitempty"` 35 | } 36 | -------------------------------------------------------------------------------- /generated/v2.34.0/graph_objects/frames_gen.go: -------------------------------------------------------------------------------- 1 | package grob 2 | 3 | // // Code generated by go-plotly/generator. DO NOT EDIT. 4 | 5 | import ( 6 | "github.com/MetalBlueberry/go-plotly/pkg/types" 7 | ) 8 | 9 | // Frame 10 | type Frame struct { 11 | 12 | // Baseframe 13 | // The name of the frame into which this frame's properties are merged before applying. This is used to unify properties and avoid needing to specify the same values for the same properties in multiple frames. 14 | Baseframe types.StringType `json:"baseframe,omitempty"` 15 | 16 | // Data 17 | // A list of traces this frame modifies. The format is identical to the normal trace definition. 18 | Data []types.Trace `json:"data,omitempty"` 19 | 20 | // Group 21 | // An identifier that specifies the group to which the frame belongs, used by animate to select a subset of frames. 22 | Group types.StringType `json:"group,omitempty"` 23 | 24 | // Layout 25 | // Layout properties which this frame modifies. The format is identical to the normal layout definition. 26 | Layout *Layout `json:"layout,omitempty"` 27 | 28 | // Name 29 | // A label by which to identify the frame 30 | Name types.StringType `json:"name,omitempty"` 31 | 32 | // Traces 33 | // A list of trace indices that identify the respective traces in the data attribute 34 | Traces []int `json:"traces,omitempty"` 35 | } 36 | -------------------------------------------------------------------------------- /examples/wasm/main.go: -------------------------------------------------------------------------------- 1 | //go:build ignore 2 | 3 | package main 4 | 5 | import ( 6 | "encoding/json" 7 | "syscall/js" 8 | 9 | grob "github.com/MetalBlueberry/go-plotly/generated/v2.31.1/graph_objects" 10 | "github.com/MetalBlueberry/go-plotly/pkg/types" 11 | ) 12 | 13 | // to run this, wasm need to be set: GOOS=js GOARCH=wasm go build -o main.wasm 14 | 15 | func plot(this js.Value, inputs []js.Value) interface{} { 16 | fig := &grob.Fig{ 17 | Data: []types.Trace{ 18 | &grob.Choropleth{ 19 | Autocolorscale: types.True, 20 | Locationmode: grob.ChoroplethLocationmodeUSAStates, 21 | }, 22 | }, 23 | Layout: &grob.Layout{ 24 | Title: &grob.LayoutTitle{ 25 | Text: "Demo", 26 | }, 27 | Geo: &grob.LayoutGeo{ 28 | Scope: grob.LayoutGeoScopeUsa, 29 | }, 30 | }, 31 | } 32 | b, err := json.Marshal(fig) 33 | if err != nil { 34 | return nil 35 | } 36 | 37 | plot := js.Global().Get("JSON").Call("parse", string(b)) 38 | plotly := js.Global().Get("Plotly") 39 | plotly.Call("plot", "plot", plot) 40 | return nil 41 | } 42 | 43 | var c chan bool 44 | 45 | func init() { 46 | c = make(chan bool) 47 | } 48 | 49 | func stop(this js.Value, inputs []js.Value) interface{} { 50 | c <- true 51 | return nil 52 | } 53 | 54 | func main() { 55 | js.Global().Set("plot", js.FuncOf(plot)) 56 | js.Global().Set("stop", js.FuncOf(stop)) 57 | <-c 58 | println("We are out of here") 59 | } 60 | -------------------------------------------------------------------------------- /pkg/types/arrayok.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "encoding/json" 5 | ) 6 | 7 | func ArrayOKValue[T any](value T) *ArrayOK[*T] { 8 | v := &value 9 | return &ArrayOK[*T]{Value: v} 10 | } 11 | 12 | func ArrayOKArray[T any](array ...T) *ArrayOK[*T] { 13 | out := make([]*T, len(array)) 14 | for i, v := range array { 15 | value := v 16 | out[i] = &value 17 | } 18 | return &ArrayOK[*T]{ 19 | Array: out, 20 | } 21 | } 22 | func ArrayOKAppend[T any](array *ArrayOK[*T], values ...T) { 23 | for _, el := range values { 24 | array.Array = append(array.Array, &el) 25 | } 26 | } 27 | 28 | // ArrayOK is a type that allows you to define a single value or an array of values, But not both. 29 | // If Array is defined, Value will be ignored. 30 | type ArrayOK[T any] struct { 31 | Value T 32 | Array []T 33 | } 34 | 35 | func (arrayOK *ArrayOK[T]) MarshalJSON() ([]byte, error) { 36 | if arrayOK.Array != nil { 37 | return json.Marshal(arrayOK.Array) 38 | } 39 | return json.Marshal(arrayOK.Value) 40 | } 41 | 42 | func (arrayOK *ArrayOK[T]) UnmarshalJSON(data []byte) error { 43 | arrayOK.Array = nil 44 | 45 | var array []T 46 | err := json.Unmarshal(data, &array) 47 | if err == nil { 48 | arrayOK.Array = array 49 | return nil 50 | } 51 | 52 | var value T 53 | err = json.Unmarshal(data, &value) 54 | if err != nil { 55 | return err 56 | } 57 | arrayOK.Value = value 58 | return nil 59 | } 60 | -------------------------------------------------------------------------------- /examples/numpy_bdata/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "os/exec" 6 | 7 | grob "github.com/MetalBlueberry/go-plotly/generated/v2.31.1/graph_objects" 8 | "github.com/MetalBlueberry/go-plotly/pkg/offline" 9 | "github.com/MetalBlueberry/go-plotly/pkg/types" 10 | ) 11 | 12 | func main() { 13 | // https://plotly.com/javascript/heatmaps/ 14 | // var data = [ 15 | // { 16 | // z: [[1, null, 30, 50, 1], [20, 1, 60, 80, 30], [30, 60, 1, -10, 20]], 17 | // x: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'], 18 | // y: ['Morning', 'Afternoon', 'Evening'], 19 | // type: 'heatmap', 20 | // hoverongaps: false 21 | // } 22 | // ]; 23 | zJSON, err := exec.Command("make").Output() 24 | if err != nil { 25 | panic(err) 26 | } 27 | type bdata struct { 28 | DType types.DType 29 | Shape []int 30 | BData []byte 31 | } 32 | 33 | z := &bdata{} 34 | err = json.Unmarshal(zJSON, z) 35 | if err != nil { 36 | panic(err) 37 | } 38 | 39 | fig := &grob.Fig{ 40 | Data: []types.Trace{ 41 | &grob.Heatmap{ 42 | X: types.DataArray([]string{"Monday", "Tuesday", "Wednesday", "Thursday", "Friday"}), 43 | Y: types.DataArray([]string{"Morning", "Afternoon", "Evening"}), 44 | Z: types.BDataArray(z.DType, z.BData, z.Shape), 45 | Hoverongaps: types.False, 46 | }, 47 | }, 48 | } 49 | 50 | offline.Show(fig) 51 | 52 | } 53 | -------------------------------------------------------------------------------- /generator/mocks/creator.go: -------------------------------------------------------------------------------- 1 | // Code generated by MockGen. DO NOT EDIT. 2 | // Source: github.com/MetalBlueberry/go-plotly/generator (interfaces: Creator) 3 | 4 | // Package mocks is a generated GoMock package. 5 | package mocks 6 | 7 | import ( 8 | gomock "github.com/golang/mock/gomock" 9 | io "io" 10 | reflect "reflect" 11 | ) 12 | 13 | // MockCreator is a mock of Creator interface 14 | type MockCreator struct { 15 | ctrl *gomock.Controller 16 | recorder *MockCreatorMockRecorder 17 | } 18 | 19 | // MockCreatorMockRecorder is the mock recorder for MockCreator 20 | type MockCreatorMockRecorder struct { 21 | mock *MockCreator 22 | } 23 | 24 | // NewMockCreator creates a new mock instance 25 | func NewMockCreator(ctrl *gomock.Controller) *MockCreator { 26 | mock := &MockCreator{ctrl: ctrl} 27 | mock.recorder = &MockCreatorMockRecorder{mock} 28 | return mock 29 | } 30 | 31 | // EXPECT returns an object that allows the caller to indicate expected use 32 | func (m *MockCreator) EXPECT() *MockCreatorMockRecorder { 33 | return m.recorder 34 | } 35 | 36 | // Create mocks base method 37 | func (m *MockCreator) Create(arg0 string) (io.WriteCloser, error) { 38 | m.ctrl.T.Helper() 39 | ret := m.ctrl.Call(m, "Create", arg0) 40 | ret0, _ := ret[0].(io.WriteCloser) 41 | ret1, _ := ret[1].(error) 42 | return ret0, ret1 43 | } 44 | 45 | // Create indicates an expected call of Create 46 | func (mr *MockCreatorMockRecorder) Create(arg0 interface{}) *gomock.Call { 47 | mr.mock.ctrl.T.Helper() 48 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockCreator)(nil).Create), arg0) 49 | } 50 | -------------------------------------------------------------------------------- /examples/shapes/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | grob "github.com/MetalBlueberry/go-plotly/generated/v2.19.0/graph_objects" 5 | "github.com/MetalBlueberry/go-plotly/pkg/offline" 6 | "github.com/MetalBlueberry/go-plotly/pkg/types" 7 | ) 8 | 9 | func main() { 10 | /* 11 | fig = dict({ 12 | "data": [{"type": "bar", 13 | "x": [1, 2, 3], 14 | "y": [1, 3, 2]}], 15 | "layout": {"title": {"text": "A Figure Specified By Python Dictionary"}} 16 | }) 17 | */ 18 | fig := &grob.Fig{ 19 | Layout: &grob.Layout{ 20 | Title: &grob.LayoutTitle{ 21 | Text: types.S("A Figure Specified By Go Struct"), 22 | }, 23 | Shapes: []grob.LayoutShape{ 24 | { 25 | Type: "line", 26 | X0: 1, 27 | Y0: 0, 28 | X1: 1, 29 | Y1: 2, 30 | Line: &grob.LayoutShapeLine{ 31 | Color: "RoyalBlue", 32 | Width: types.N(3), 33 | }, 34 | }, 35 | { 36 | Type: "line", 37 | X0: 2, 38 | Y0: 2, 39 | X1: 5, 40 | Y1: 2, 41 | Line: &grob.LayoutShapeLine{ 42 | Color: "LightSeaGreen", 43 | Width: types.N(4), 44 | Dash: types.S(string(grob.Scatter3dLineDashDashdot)), 45 | }, 46 | }, 47 | { 48 | Type: "line", 49 | X0: 4, 50 | Y0: 0, 51 | X1: 6, 52 | Y1: 2, 53 | Line: &grob.LayoutShapeLine{ 54 | Color: "MediumPurple", 55 | Width: types.N(4), 56 | Dash: types.S(string(grob.Scatter3dLineDashDot)), 57 | }, 58 | }, 59 | }, 60 | }, 61 | } 62 | 63 | offline.ToHtml(fig, "bar.html") 64 | offline.Show(fig) 65 | } 66 | -------------------------------------------------------------------------------- /examples/scatter3d/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "math" 5 | 6 | grob "github.com/MetalBlueberry/go-plotly/generated/v2.31.1/graph_objects" 7 | "github.com/MetalBlueberry/go-plotly/pkg/offline" 8 | "github.com/MetalBlueberry/go-plotly/pkg/types" 9 | ) 10 | 11 | func main() { 12 | /* 13 | https://plotly.com/python/3d-scatter-plots/ 14 | import plotly.graph_objects as go 15 | import numpy as np 16 | 17 | # Helix equation 18 | t = np.linspace(0, 10, 50) 19 | x, y, z = np.cos(t), np.sin(t), t 20 | 21 | fig = go.Figure(data=[go.Scatter3d(x=x, y=y, z=z, 22 | mode='markers')]) 23 | fig.show() 24 | */ 25 | t := linspace(0, 10, 50) 26 | x := cos(t) 27 | y := sin(t) 28 | z := t 29 | 30 | fig := &grob.Fig{ 31 | Data: []types.Trace{ 32 | &grob.Scatter3d{ 33 | X: types.DataArray(x), 34 | Y: types.DataArray(y), 35 | Z: types.DataArray(z), 36 | Mode: grob.Scatter3dModeMarkers, 37 | }, 38 | }, 39 | } 40 | 41 | offline.ToHtml(fig, "scatter3d.html") 42 | offline.Show(fig) 43 | } 44 | 45 | func linspace(start, stop float64, points int) []float64 { 46 | step := (stop - start) / float64(points) 47 | out := make([]float64, points) 48 | 49 | for i := 0; i < points; i++ { 50 | out[i] = start + step*float64(i) 51 | } 52 | return out 53 | } 54 | 55 | func sin(x []float64) []float64 { 56 | y := make([]float64, len(x)) 57 | for i := 0; i < len(x); i++ { 58 | y[i] = math.Sin(x[i]) 59 | } 60 | return y 61 | } 62 | 63 | func cos(x []float64) []float64 { 64 | z := make([]float64, len(x)) 65 | for i := 0; i < len(x); i++ { 66 | z[i] = math.Cos(x[i]) 67 | } 68 | return z 69 | 70 | } 71 | -------------------------------------------------------------------------------- /examples/animation_slider/main_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | ) 7 | 8 | func TestSplit(t *testing.T) { 9 | // Test case 1: Basic functionality 10 | reference := []string{"a", "b", "a", "b"} 11 | slices := [][]interface{}{ 12 | {1, 2, 3, 4}, 13 | {"s1", "s2", "s3", "s4"}, 14 | } 15 | expected := map[string][][]interface{}{ 16 | "a": { 17 | {1, 3}, 18 | {"s1", "s3"}, 19 | }, 20 | "b": { 21 | {2, 4}, 22 | {"s2", "s4"}, 23 | }, 24 | } 25 | 26 | result, _ := split(reference, slices) 27 | 28 | if !reflect.DeepEqual(result, expected) { 29 | t.Errorf("Test case 1 failed. Expected %v, got %v", expected, result) 30 | } 31 | 32 | // Test case 2: Single element in reference 33 | reference = []string{"a"} 34 | slices = [][]interface{}{ 35 | {5}, 36 | {"single"}, 37 | } 38 | expected = map[string][][]interface{}{ 39 | "a": { 40 | {5}, 41 | {"single"}, 42 | }, 43 | } 44 | 45 | result, _ = split(reference, slices) 46 | 47 | if !reflect.DeepEqual(result, expected) { 48 | t.Errorf("Test case 2 failed. Expected %v, got %v", expected, result) 49 | } 50 | 51 | // Test case 3: Empty slices 52 | reference = []string{} 53 | slices = [][]interface{}{} 54 | expected = map[string][][]interface{}{} 55 | 56 | result, _ = split(reference, slices) 57 | 58 | if !reflect.DeepEqual(result, expected) { 59 | t.Errorf("Test case 3 failed. Expected %v, got %v", expected, result) 60 | } 61 | 62 | // Test case 4: Multiple same keys 63 | reference = []string{"x", "x", "y", "y"} 64 | slices = [][]interface{}{ 65 | {10, 20, 30, 40}, 66 | {"a", "b", "c", "d"}, 67 | } 68 | expected = map[string][][]interface{}{ 69 | "x": { 70 | {10, 20}, 71 | {"a", "b"}, 72 | }, 73 | "y": { 74 | {30, 40}, 75 | {"c", "d"}, 76 | }, 77 | } 78 | 79 | result, _ = split(reference, slices) 80 | 81 | if !reflect.DeepEqual(result, expected) { 82 | t.Errorf("Test case 4 failed. Expected %v, got %v", expected, result) 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /examples/static_image/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "io" 7 | "os" 8 | "os/exec" 9 | "strings" 10 | 11 | grob "github.com/MetalBlueberry/go-plotly/generated/v2.31.1/graph_objects" 12 | "github.com/MetalBlueberry/go-plotly/pkg/types" 13 | ) 14 | 15 | func main() { 16 | /* 17 | fig = dict({ 18 | "data": [{"type": "bar", 19 | "x": [1, 2, 3], 20 | "y": [1, 3, 2]}], 21 | "layout": {"title": {"text": "A Figure Specified By Python Dictionary"}} 22 | }) 23 | */ 24 | fig := &grob.Fig{ 25 | Data: []types.Trace{ 26 | &grob.Bar{ 27 | X: types.DataArray([]float64{1, 2, 3}), 28 | Y: types.DataArray([]float64{1, 2, 3}), 29 | }, 30 | }, 31 | Layout: &grob.Layout{ 32 | Title: &grob.LayoutTitle{ 33 | Text: types.S("A Figure Specified By Go Struct"), 34 | }, 35 | }, 36 | } 37 | 38 | fmt.Fprint(os.Stderr, "saving to PNG...\n") 39 | err := savePNG(fig, "out.png") 40 | if err != nil { 41 | panic(err) 42 | } 43 | fmt.Fprint(os.Stderr, "Done!\n") 44 | } 45 | 46 | func savePNG(fig *grob.Fig, path string) error { 47 | args := "run --rm -i quay.io/plotly/orca graph --format png" 48 | cmd := exec.Command("docker", strings.Split(args, " ")...) 49 | 50 | in, err := cmd.StdinPipe() 51 | if err != nil { 52 | return fmt.Errorf("Failed to open StdIn, %w", err) 53 | } 54 | go func() { 55 | err := json.NewEncoder(in).Encode(fig) 56 | if err != nil { 57 | panic(err) 58 | } 59 | err = in.Close() 60 | }() 61 | 62 | out, err := cmd.StdoutPipe() 63 | if err != nil { 64 | return fmt.Errorf("Failed to open StdOut, %w", err) 65 | } 66 | 67 | f, err := os.Create(path) 68 | if err != nil { 69 | return fmt.Errorf("Cannot create output file") 70 | } 71 | go func() { 72 | defer f.Close() 73 | _, err = io.Copy(f, out) 74 | if err != nil { 75 | panic(err) 76 | } 77 | }() 78 | 79 | cmd.Stderr = os.Stderr 80 | 81 | err = cmd.Run() 82 | if err != nil { 83 | return fmt.Errorf("Failed to run command, %w", err) 84 | } 85 | 86 | return nil 87 | } 88 | -------------------------------------------------------------------------------- /examples/subplots_share_axes/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | grob "github.com/MetalBlueberry/go-plotly/generated/v2.31.1/graph_objects" 5 | "github.com/MetalBlueberry/go-plotly/pkg/offline" 6 | "github.com/MetalBlueberry/go-plotly/pkg/types" 7 | ) 8 | 9 | func main() { 10 | /* 11 | https://plotly.com/javascript/subplots/#subplots-with-shared-axes 12 | 13 | var trace1 = { 14 | x: [1, 2, 3], 15 | y: [2, 3, 4], 16 | type: 'scatter' 17 | }; 18 | 19 | var trace2 = { 20 | x: [20, 30, 40], 21 | y: [5, 5, 5], 22 | xaxis: 'x2', 23 | yaxis: 'y', 24 | type: 'scatter' 25 | }; 26 | 27 | var trace3 = { 28 | x: [2, 3, 4], 29 | y: [600, 700, 800], 30 | xaxis: 'x', 31 | yaxis: 'y3', 32 | type: 'scatter' 33 | }; 34 | 35 | var trace4 = { 36 | x: [4000, 5000, 6000], 37 | y: [7000, 8000, 9000], 38 | xaxis: 'x4', 39 | yaxis: 'y4', 40 | type: 'scatter' 41 | }; 42 | 43 | var data = [trace1, trace2, trace3, trace4]; 44 | 45 | var layout = { 46 | grid: { 47 | rows: 2, 48 | columns: 2, 49 | subplots:[['xy','x2y'], ['xy3','x4y4']], 50 | roworder:'bottom to top' 51 | } 52 | }; 53 | 54 | Plotly.newPlot('myDiv', data, layout); 55 | */ 56 | fig := &grob.Fig{ 57 | Data: []types.Trace{ 58 | &grob.Scatter{ 59 | X: types.DataArray([]float64{1, 2, 3}), 60 | Y: types.DataArray([]float64{2, 3, 4}), 61 | }, 62 | &grob.Scatter{ 63 | X: types.DataArray([]float64{20, 30, 40}), 64 | Y: types.DataArray([]float64{5, 5, 5}), 65 | Xaxis: types.S("x2"), 66 | Yaxis: types.S("y"), 67 | }, 68 | &grob.Scatter{ 69 | X: types.DataArray([]float64{2, 3, 4}), 70 | Y: types.DataArray([]float64{600, 700, 800}), 71 | Xaxis: types.S("x"), 72 | Yaxis: types.S("y3"), 73 | }, 74 | &grob.Scatter{ 75 | X: types.DataArray([]float64{4000, 5000, 6000}), 76 | Y: types.DataArray([]float64{7000, 8000, 9000}), 77 | Xaxis: types.S("x4"), 78 | Yaxis: types.S("y4"), 79 | }, 80 | }, 81 | Layout: &grob.Layout{ 82 | Grid: &grob.LayoutGrid{ 83 | Rows: types.I(2), 84 | Columns: types.I(2), 85 | Subplots: [][]string{ 86 | {"xy", "x2y"}, 87 | {"xy3", "x4y4"}, 88 | }, 89 | Roworder: grob.LayoutGridRoworderBottomToTop, 90 | }, 91 | }, 92 | } 93 | 94 | offline.ToHtml(fig, "subplots_share_axes.html") 95 | offline.Show(fig) 96 | } 97 | -------------------------------------------------------------------------------- /examples/bar_custom/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "image/color" 5 | "strconv" 6 | 7 | "github.com/lucasb-eyer/go-colorful" 8 | 9 | grob "github.com/MetalBlueberry/go-plotly/generated/v2.31.1/graph_objects" 10 | "github.com/MetalBlueberry/go-plotly/pkg/offline" 11 | "github.com/MetalBlueberry/go-plotly/pkg/types" 12 | ) 13 | 14 | func main() { 15 | /* 16 | https://plotly.com/javascript/bar-charts/ 17 | var xValue = ['Product A', 'Product B', 'Product C']; 18 | 19 | var yValue = [20, 14, 23]; 20 | 21 | var trace1 = { 22 | x: xValue, 23 | y: yValue, 24 | type: 'bar', 25 | text: yValue.map(String), 26 | textposition: 'auto', 27 | hoverinfo: 'none', 28 | marker: { 29 | color: 'rgb(158,202,225)', 30 | opacity: 0.6, 31 | line: { 32 | color: 'rgb(8,48,107)', 33 | width: 1.5 34 | } 35 | } 36 | }; 37 | 38 | var data = [trace1]; 39 | 40 | var layout = { 41 | title: 'January 2013 Sales Report', 42 | barmode: 'stack' 43 | }; 44 | 45 | */ 46 | xValue := []string{"Product A", "Product B", "Product C"} 47 | yValue := []int{20, 14, 23} 48 | 49 | markerColor, ok := colorful.MakeColor(color.NRGBA{158, 202, 225, 1}) 50 | if !ok { 51 | panic("fail to build a color") 52 | } 53 | 54 | trace1 := &grob.Bar{ 55 | X: types.DataArray(xValue), 56 | Y: types.DataArray(yValue), 57 | Text: types.ArrayOKArray(toString(yValue)...), 58 | Textposition: types.ArrayOKValue(grob.BarTextpositionAuto), 59 | Hoverinfo: types.ArrayOKValue(grob.BarHoverinfoNone), 60 | Marker: &grob.BarMarker{ 61 | Color: types.ArrayOKValue(types.UseColor(types.Color( 62 | markerColor.Hex(), // Use colorfull 63 | ))), 64 | Opacity: types.ArrayOKValue(types.N(0.6)), 65 | Line: &grob.BarMarkerLine{ 66 | Color: types.ArrayOKValue(types.UseColor("rgb(8,48,107)")), // Or just write the string 67 | Width: types.ArrayOKValue(types.N(1.5)), 68 | }, 69 | }, 70 | } 71 | 72 | layout := &grob.Layout{ 73 | Title: &grob.LayoutTitle{ 74 | Text: types.S("A Figure Specified By Go Struct"), 75 | }, 76 | } 77 | 78 | fig := &grob.Fig{ 79 | Data: []types.Trace{trace1}, 80 | Layout: layout, 81 | } 82 | 83 | offline.ToHtml(fig, "bar_custom.html") 84 | offline.Show(fig) 85 | } 86 | 87 | func toString(in []int) []types.StringType { 88 | out := make([]types.StringType, len(in)) 89 | for i := range in { 90 | out[i] = types.S(strconv.Itoa(in[i])) 91 | } 92 | return out 93 | } 94 | -------------------------------------------------------------------------------- /examples/colorscale/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "math" 5 | 6 | grob "github.com/MetalBlueberry/go-plotly/generated/v2.31.1/graph_objects" 7 | "github.com/MetalBlueberry/go-plotly/pkg/offline" 8 | "github.com/MetalBlueberry/go-plotly/pkg/types" 9 | ) 10 | 11 | func main() { 12 | t := linspace(0, 10, 50) 13 | x := cos(t) 14 | y := sin(t) 15 | z := t 16 | fig := &grob.Fig{ 17 | Data: []types.Trace{ 18 | &grob.Scatter3d{ 19 | X: types.DataArray(x), 20 | Y: types.DataArray(y), 21 | Z: types.DataArray(z), 22 | Mode: grob.Scatter3dModeMarkers, 23 | Marker: &grob.Scatter3dMarker{ 24 | Autocolorscale: types.False, 25 | Cauto: types.False, 26 | Cmin: types.N(0), 27 | Cmid: types.N(5), 28 | Cmax: types.N(10), 29 | Color: types.ArrayOKArray(types.UseColorScaleValues(z)...), 30 | Colorscale: &types.ColorScale{ 31 | Values: []types.ColorScaleReference{ 32 | {NormalizedValue: 0.0, Color: "#6e40aa"}, 33 | {NormalizedValue: 0.1, Color: `#963db3`}, 34 | {NormalizedValue: 0.2, Color: "#bf3caf"}, 35 | {NormalizedValue: 0.3, Color: "#e4419d"}, 36 | {NormalizedValue: 0.4, Color: "#fe4b83"}, 37 | {NormalizedValue: 0.5, Color: "#ff5e63"}, 38 | {NormalizedValue: 0.6, Color: "#ff7847"}, 39 | {NormalizedValue: 0.7, Color: "#fb9633"}, 40 | {NormalizedValue: 0.8, Color: "#e2b72f"}, 41 | {NormalizedValue: 0.9, Color: "#c6d63c"}, 42 | {NormalizedValue: 1.0, Color: "#aff05b"}, 43 | }, 44 | }, 45 | Showscale: types.True, 46 | Size: types.ArrayOKValue(types.N(4.0)), 47 | }, 48 | }, 49 | }, 50 | Layout: &grob.Layout{ 51 | Height: types.N(700), 52 | Width: types.N(1200), 53 | Title: &grob.LayoutTitle{ 54 | Text: types.S("3D Spiral"), 55 | }, 56 | }, 57 | } 58 | offline.Show(fig) 59 | } 60 | 61 | func linspace(start, stop float64, points int) []float64 { 62 | step := (stop - start) / float64(points) 63 | out := make([]float64, points) 64 | 65 | for i := 0; i < points; i++ { 66 | out[i] = start + step*float64(i) 67 | } 68 | return out 69 | } 70 | 71 | func sin(x []float64) []float64 { 72 | y := make([]float64, len(x)) 73 | for i := 0; i < len(x); i++ { 74 | y[i] = math.Sin(x[i]) 75 | } 76 | return y 77 | } 78 | 79 | func cos(x []float64) []float64 { 80 | z := make([]float64, len(x)) 81 | for i := 0; i < len(x); i++ { 82 | z[i] = math.Cos(x[i]) 83 | } 84 | return z 85 | 86 | } 87 | -------------------------------------------------------------------------------- /examples/scatter3d/scatter3d.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
7 | 11 | 12 | -------------------------------------------------------------------------------- /examples/waterfall_bar_chart/waterfall.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
7 | 11 | 12 | -------------------------------------------------------------------------------- /examples/animation/animation.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "math/rand" 5 | 6 | grob "github.com/MetalBlueberry/go-plotly/generated/v2.19.0/graph_objects" 7 | "github.com/MetalBlueberry/go-plotly/pkg/offline" 8 | "github.com/MetalBlueberry/go-plotly/pkg/types" 9 | ) 10 | 11 | // Plotly.newPlot('myDiv', [{ 12 | // x: [1, 2, 3], 13 | // y: [0, 0.5, 1], 14 | // line: {simplify: false}, 15 | // }]); 16 | 17 | // function randomize() { 18 | // Plotly.animate('myDiv', { 19 | // data: [{y: [Math.random(), Math.random(), Math.random()]}], 20 | // traces: [0], 21 | // layout: {} 22 | // }, { 23 | // transition: { 24 | // duration: 500, 25 | // easing: 'cubic-in-out' 26 | // }, 27 | // frame: { 28 | // duration: 500 29 | // } 30 | // }) 31 | // } 32 | func main() { 33 | 34 | frames := []grob.Frame{} 35 | // Because this example runs entirely in go, build a few random frames 36 | for i := 0; i < 20; i++ { 37 | frames = append(frames, grob.Frame{ 38 | Data: []types.Trace{ 39 | &grob.Scatter{ 40 | Y: types.DataArray([]float64{rand.Float64(), rand.Float64(), rand.Float64()}), 41 | }, 42 | }, 43 | }) 44 | } 45 | 46 | fig := &grob.Fig{ 47 | Data: []types.Trace{ 48 | &grob.Scatter{ 49 | X: types.DataArray([]float64{1, 2, 3}), 50 | Y: types.DataArray([]float64{0, 0.5, 1}), 51 | Line: &grob.ScatterLine{ 52 | Simplify: types.False, 53 | }, 54 | }, 55 | }, 56 | Layout: &grob.Layout{ 57 | Yaxis: &grob.LayoutYaxis{ 58 | Range: []int{0, 1}, 59 | }, 60 | Updatemenus: []grob.LayoutUpdatemenu{ 61 | { 62 | Type: grob.LayoutUpdatemenuTypeButtons, 63 | Showactive: types.False, 64 | Buttons: []grob.LayoutUpdatemenuButton{ 65 | { 66 | Label: types.S("Play"), 67 | Method: grob.LayoutUpdatemenuButtonMethodAnimate, 68 | Args: []*ButtonArgs{ 69 | nil, 70 | { 71 | Mode: "immediate", 72 | FromCurrent: false, 73 | }, 74 | }, 75 | }, 76 | }, 77 | }, 78 | }, 79 | }, 80 | Frames: frames, 81 | Animation: &grob.Animation{ 82 | Transition: &grob.AnimationTransition{ 83 | Duration: types.N(500), 84 | Easing: grob.AnimationTransitionEasingCubicInOut, 85 | }, 86 | Frame: &grob.AnimationFrame{ 87 | Duration: types.N(500), 88 | Redraw: types.True, 89 | }, 90 | }, 91 | } 92 | 93 | offline.Show(fig) 94 | } 95 | 96 | type ButtonArgs struct { 97 | Frame map[string]interface{} `json:"frame,omitempty"` 98 | Transition map[string]interface{} `json:"transition,omitempty"` 99 | FromCurrent bool `json:"fromcurrent,omitempty"` 100 | Mode string `json:"mode,omitempty"` 101 | } 102 | -------------------------------------------------------------------------------- /generator/templates/plotly.go: -------------------------------------------------------------------------------- 1 | package grob 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MetalBlueberry/go-plotly/pkg/types" 7 | ) 8 | 9 | // Fig is the base type for figures. 10 | type Fig struct { 11 | // Data The data to be plotted is described in an array usually called data, whose elements are trace objects of various types (e.g. scatter, bar etc) as documented in the Full Reference. 12 | // https://plotly.com/javascript/reference 13 | Data []types.Trace `json:"data,omitempty"` 14 | 15 | // Layout The layout of the plot – non-data-related visual attributes such as the title, annotations etc – is described in an object usually called layout, as documented in/ the Full Reference. 16 | // https://plotly.com/javascript/reference/layout 17 | Layout *Layout `json:"layout,omitempty"` 18 | 19 | // Config High-level configuration options for the plot, such as the scroll/zoom/hover behaviour, is described in an object usually called config, as documented here. The difference between config and layout is that layout relates to the content of the plot, whereas config relates to the context in which the plot is being shown. 20 | // https://plotly.com/javascript/configuration-options 21 | Config *Config `json:"config,omitempty"` 22 | 23 | // Animation is not yet implemented, feel free to insert custom a struct 24 | Animation *Animation `json:"animation,omitempty"` 25 | 26 | // Frames are the animation frames 27 | Frames []Frame `json:"frames,omitempty"` 28 | } 29 | 30 | // AddTraces Is a shorthand to add figures to a given figure. It handles the case where the Traces value is nil. 31 | func (fig *Fig) AddTraces(traces ...types.Trace) { 32 | if fig.Data == nil { 33 | fig.Data = make([]types.Trace, 0) 34 | } 35 | fig.Data = append(fig.Data, traces...) 36 | } 37 | 38 | func (fig *Fig) Info() types.Version { 39 | return types.Version{ 40 | // {{ printf "\nName: \"%s\"," .Name }} 41 | // {{ printf "\nTag: \"%s\"," .Tag }} 42 | // {{ printf "\nURL: \"%s\"," .URL }} 43 | // {{ printf "\nPath: \"%s\"," .Path }} 44 | // {{ printf "\nGenerated: \"%s\"," .Generated }} 45 | // {{ printf "\nCdn: \"%s\"," .Cdn }} 46 | } 47 | } 48 | 49 | // UnmarshalJSON is a custom unmarshal function to properly handle special cases. 50 | func (fig *Fig) UnmarshalJSON(data []byte) error { 51 | var err error 52 | tmp := unmarshalFig{} 53 | err = json.Unmarshal(data, &tmp) 54 | if err != nil { 55 | return err 56 | } 57 | 58 | fig.Layout = tmp.Layout 59 | fig.Config = tmp.Config 60 | 61 | for i := range tmp.Data { 62 | trace, err := UnmarshalTrace(tmp.Data[i]) 63 | if err != nil { 64 | return err 65 | } 66 | fig.AddTraces(trace) 67 | } 68 | return nil 69 | } 70 | 71 | type unmarshalFig struct { 72 | Data []json.RawMessage `json:"data,omitempty"` 73 | Layout *Layout `json:"layout,omitempty"` 74 | Config *Config `json:"config,omitempty"` 75 | } 76 | -------------------------------------------------------------------------------- /generated/v2.19.0/graph_objects/plotly_gen.go: -------------------------------------------------------------------------------- 1 | package grob 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MetalBlueberry/go-plotly/pkg/types" 7 | ) 8 | 9 | // Fig is the base type for figures. 10 | type Fig struct { 11 | // Data The data to be plotted is described in an array usually called data, whose elements are trace objects of various types (e.g. scatter, bar etc) as documented in the Full Reference. 12 | // https://plotly.com/javascript/reference 13 | Data []types.Trace `json:"data,omitempty"` 14 | 15 | // Layout The layout of the plot – non-data-related visual attributes such as the title, annotations etc – is described in an object usually called layout, as documented in/ the Full Reference. 16 | // https://plotly.com/javascript/reference/layout 17 | Layout *Layout `json:"layout,omitempty"` 18 | 19 | // Config High-level configuration options for the plot, such as the scroll/zoom/hover behaviour, is described in an object usually called config, as documented here. The difference between config and layout is that layout relates to the content of the plot, whereas config relates to the context in which the plot is being shown. 20 | // https://plotly.com/javascript/configuration-options 21 | Config *Config `json:"config,omitempty"` 22 | 23 | // Animation is not yet implemented, feel free to insert custom a struct 24 | Animation *Animation `json:"animation,omitempty"` 25 | 26 | // Frames are the animation frames 27 | Frames []Frame `json:"frames,omitempty"` 28 | } 29 | 30 | // AddTraces Is a shorthand to add figures to a given figure. It handles the case where the Traces value is nil. 31 | func (fig *Fig) AddTraces(traces ...types.Trace) { 32 | if fig.Data == nil { 33 | fig.Data = make([]types.Trace, 0) 34 | } 35 | fig.Data = append(fig.Data, traces...) 36 | } 37 | 38 | func (fig *Fig) Info() types.Version { 39 | return types.Version{ 40 | // 41 | Name: "Plotly 2.19.0", 42 | // 43 | Tag: "v2.19.0", 44 | // 45 | URL: "https://raw.githubusercontent.com/plotly/plotly.js/v2.19.0/test/plot-schema.json", 46 | // 47 | Path: "schemas/v2.19.0/plot-schema.json", 48 | // 49 | Generated: "generated/v2.19.0", 50 | // 51 | Cdn: "https://cdn.plot.ly/plotly-2.19.0.min.js", 52 | } 53 | } 54 | 55 | // UnmarshalJSON is a custom unmarshal function to properly handle special cases. 56 | func (fig *Fig) UnmarshalJSON(data []byte) error { 57 | var err error 58 | tmp := unmarshalFig{} 59 | err = json.Unmarshal(data, &tmp) 60 | if err != nil { 61 | return err 62 | } 63 | 64 | fig.Layout = tmp.Layout 65 | fig.Config = tmp.Config 66 | 67 | for i := range tmp.Data { 68 | trace, err := UnmarshalTrace(tmp.Data[i]) 69 | if err != nil { 70 | return err 71 | } 72 | fig.AddTraces(trace) 73 | } 74 | return nil 75 | } 76 | 77 | type unmarshalFig struct { 78 | Data []json.RawMessage `json:"data,omitempty"` 79 | Layout *Layout `json:"layout,omitempty"` 80 | Config *Config `json:"config,omitempty"` 81 | } 82 | -------------------------------------------------------------------------------- /generated/v2.29.1/graph_objects/plotly_gen.go: -------------------------------------------------------------------------------- 1 | package grob 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MetalBlueberry/go-plotly/pkg/types" 7 | ) 8 | 9 | // Fig is the base type for figures. 10 | type Fig struct { 11 | // Data The data to be plotted is described in an array usually called data, whose elements are trace objects of various types (e.g. scatter, bar etc) as documented in the Full Reference. 12 | // https://plotly.com/javascript/reference 13 | Data []types.Trace `json:"data,omitempty"` 14 | 15 | // Layout The layout of the plot – non-data-related visual attributes such as the title, annotations etc – is described in an object usually called layout, as documented in/ the Full Reference. 16 | // https://plotly.com/javascript/reference/layout 17 | Layout *Layout `json:"layout,omitempty"` 18 | 19 | // Config High-level configuration options for the plot, such as the scroll/zoom/hover behaviour, is described in an object usually called config, as documented here. The difference between config and layout is that layout relates to the content of the plot, whereas config relates to the context in which the plot is being shown. 20 | // https://plotly.com/javascript/configuration-options 21 | Config *Config `json:"config,omitempty"` 22 | 23 | // Animation is not yet implemented, feel free to insert custom a struct 24 | Animation *Animation `json:"animation,omitempty"` 25 | 26 | // Frames are the animation frames 27 | Frames []Frame `json:"frames,omitempty"` 28 | } 29 | 30 | // AddTraces Is a shorthand to add figures to a given figure. It handles the case where the Traces value is nil. 31 | func (fig *Fig) AddTraces(traces ...types.Trace) { 32 | if fig.Data == nil { 33 | fig.Data = make([]types.Trace, 0) 34 | } 35 | fig.Data = append(fig.Data, traces...) 36 | } 37 | 38 | func (fig *Fig) Info() types.Version { 39 | return types.Version{ 40 | // 41 | Name: "Plotly 2.29.1", 42 | // 43 | Tag: "v2.29.1", 44 | // 45 | URL: "https://raw.githubusercontent.com/plotly/plotly.js/v2.29.1/test/plot-schema.json", 46 | // 47 | Path: "schemas/v2.29.1/plot-schema.json", 48 | // 49 | Generated: "generated/v2.29.1", 50 | // 51 | Cdn: "https://cdn.plot.ly/plotly-2.29.1.min.js", 52 | } 53 | } 54 | 55 | // UnmarshalJSON is a custom unmarshal function to properly handle special cases. 56 | func (fig *Fig) UnmarshalJSON(data []byte) error { 57 | var err error 58 | tmp := unmarshalFig{} 59 | err = json.Unmarshal(data, &tmp) 60 | if err != nil { 61 | return err 62 | } 63 | 64 | fig.Layout = tmp.Layout 65 | fig.Config = tmp.Config 66 | 67 | for i := range tmp.Data { 68 | trace, err := UnmarshalTrace(tmp.Data[i]) 69 | if err != nil { 70 | return err 71 | } 72 | fig.AddTraces(trace) 73 | } 74 | return nil 75 | } 76 | 77 | type unmarshalFig struct { 78 | Data []json.RawMessage `json:"data,omitempty"` 79 | Layout *Layout `json:"layout,omitempty"` 80 | Config *Config `json:"config,omitempty"` 81 | } 82 | -------------------------------------------------------------------------------- /generated/v2.31.1/graph_objects/plotly_gen.go: -------------------------------------------------------------------------------- 1 | package grob 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MetalBlueberry/go-plotly/pkg/types" 7 | ) 8 | 9 | // Fig is the base type for figures. 10 | type Fig struct { 11 | // Data The data to be plotted is described in an array usually called data, whose elements are trace objects of various types (e.g. scatter, bar etc) as documented in the Full Reference. 12 | // https://plotly.com/javascript/reference 13 | Data []types.Trace `json:"data,omitempty"` 14 | 15 | // Layout The layout of the plot – non-data-related visual attributes such as the title, annotations etc – is described in an object usually called layout, as documented in/ the Full Reference. 16 | // https://plotly.com/javascript/reference/layout 17 | Layout *Layout `json:"layout,omitempty"` 18 | 19 | // Config High-level configuration options for the plot, such as the scroll/zoom/hover behaviour, is described in an object usually called config, as documented here. The difference between config and layout is that layout relates to the content of the plot, whereas config relates to the context in which the plot is being shown. 20 | // https://plotly.com/javascript/configuration-options 21 | Config *Config `json:"config,omitempty"` 22 | 23 | // Animation is not yet implemented, feel free to insert custom a struct 24 | Animation *Animation `json:"animation,omitempty"` 25 | 26 | // Frames are the animation frames 27 | Frames []Frame `json:"frames,omitempty"` 28 | } 29 | 30 | // AddTraces Is a shorthand to add figures to a given figure. It handles the case where the Traces value is nil. 31 | func (fig *Fig) AddTraces(traces ...types.Trace) { 32 | if fig.Data == nil { 33 | fig.Data = make([]types.Trace, 0) 34 | } 35 | fig.Data = append(fig.Data, traces...) 36 | } 37 | 38 | func (fig *Fig) Info() types.Version { 39 | return types.Version{ 40 | // 41 | Name: "Plotly 2.31.1", 42 | // 43 | Tag: "v2.31.1", 44 | // 45 | URL: "https://raw.githubusercontent.com/plotly/plotly.js/v2.31.1/test/plot-schema.json", 46 | // 47 | Path: "schemas/v2.31.1/plot-schema.json", 48 | // 49 | Generated: "generated/v2.31.1", 50 | // 51 | Cdn: "https://cdn.plot.ly/plotly-2.31.1.min.js", 52 | } 53 | } 54 | 55 | // UnmarshalJSON is a custom unmarshal function to properly handle special cases. 56 | func (fig *Fig) UnmarshalJSON(data []byte) error { 57 | var err error 58 | tmp := unmarshalFig{} 59 | err = json.Unmarshal(data, &tmp) 60 | if err != nil { 61 | return err 62 | } 63 | 64 | fig.Layout = tmp.Layout 65 | fig.Config = tmp.Config 66 | 67 | for i := range tmp.Data { 68 | trace, err := UnmarshalTrace(tmp.Data[i]) 69 | if err != nil { 70 | return err 71 | } 72 | fig.AddTraces(trace) 73 | } 74 | return nil 75 | } 76 | 77 | type unmarshalFig struct { 78 | Data []json.RawMessage `json:"data,omitempty"` 79 | Layout *Layout `json:"layout,omitempty"` 80 | Config *Config `json:"config,omitempty"` 81 | } 82 | -------------------------------------------------------------------------------- /generated/v2.34.0/graph_objects/plotly_gen.go: -------------------------------------------------------------------------------- 1 | package grob 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/MetalBlueberry/go-plotly/pkg/types" 7 | ) 8 | 9 | // Fig is the base type for figures. 10 | type Fig struct { 11 | // Data The data to be plotted is described in an array usually called data, whose elements are trace objects of various types (e.g. scatter, bar etc) as documented in the Full Reference. 12 | // https://plotly.com/javascript/reference 13 | Data []types.Trace `json:"data,omitempty"` 14 | 15 | // Layout The layout of the plot – non-data-related visual attributes such as the title, annotations etc – is described in an object usually called layout, as documented in/ the Full Reference. 16 | // https://plotly.com/javascript/reference/layout 17 | Layout *Layout `json:"layout,omitempty"` 18 | 19 | // Config High-level configuration options for the plot, such as the scroll/zoom/hover behaviour, is described in an object usually called config, as documented here. The difference between config and layout is that layout relates to the content of the plot, whereas config relates to the context in which the plot is being shown. 20 | // https://plotly.com/javascript/configuration-options 21 | Config *Config `json:"config,omitempty"` 22 | 23 | // Animation is not yet implemented, feel free to insert custom a struct 24 | Animation *Animation `json:"animation,omitempty"` 25 | 26 | // Frames are the animation frames 27 | Frames []Frame `json:"frames,omitempty"` 28 | } 29 | 30 | // AddTraces Is a shorthand to add figures to a given figure. It handles the case where the Traces value is nil. 31 | func (fig *Fig) AddTraces(traces ...types.Trace) { 32 | if fig.Data == nil { 33 | fig.Data = make([]types.Trace, 0) 34 | } 35 | fig.Data = append(fig.Data, traces...) 36 | } 37 | 38 | func (fig *Fig) Info() types.Version { 39 | return types.Version{ 40 | // 41 | Name: "Plotly 2.34.0", 42 | // 43 | Tag: "v2.34.0", 44 | // 45 | URL: "https://raw.githubusercontent.com/plotly/plotly.js/v2.34.0/test/plot-schema.json", 46 | // 47 | Path: "schemas/v2.34.0/plot-schema.json", 48 | // 49 | Generated: "generated/v2.34.0", 50 | // 51 | Cdn: "https://cdn.plot.ly/plotly-2.34.0.min.js", 52 | } 53 | } 54 | 55 | // UnmarshalJSON is a custom unmarshal function to properly handle special cases. 56 | func (fig *Fig) UnmarshalJSON(data []byte) error { 57 | var err error 58 | tmp := unmarshalFig{} 59 | err = json.Unmarshal(data, &tmp) 60 | if err != nil { 61 | return err 62 | } 63 | 64 | fig.Layout = tmp.Layout 65 | fig.Config = tmp.Config 66 | 67 | for i := range tmp.Data { 68 | trace, err := UnmarshalTrace(tmp.Data[i]) 69 | if err != nil { 70 | return err 71 | } 72 | fig.AddTraces(trace) 73 | } 74 | return nil 75 | } 76 | 77 | type unmarshalFig struct { 78 | Data []json.RawMessage `json:"data,omitempty"` 79 | Layout *Layout `json:"layout,omitempty"` 80 | Config *Config `json:"config,omitempty"` 81 | } 82 | -------------------------------------------------------------------------------- /examples/scatter/scatter.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
7 | 11 | 12 | -------------------------------------------------------------------------------- /pkg/types/basic.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "strconv" 5 | ) 6 | 7 | // BoolType represents a *bool value. Needed to tell the different between false and nil. 8 | type BoolType *bool 9 | 10 | func B(v bool) BoolType { 11 | return BoolType(&v) 12 | } 13 | 14 | // BA converts a list of bool into BooleanType 15 | func BA(v []bool) []BoolType { 16 | result := make([]BoolType, len(v)) 17 | for i := range v { 18 | result[i] = B(v[i]) 19 | } 20 | return result 21 | } 22 | 23 | var ( 24 | trueValue bool = true 25 | falseValue bool = false 26 | 27 | // True is a *bool with true value 28 | True BoolType = &trueValue 29 | // False is a *bool with false value 30 | False BoolType = &falseValue 31 | ) 32 | 33 | // StringType as defined by plotly schema 34 | // This is not *string because I do not see any case where an empty string is a desired input for plotly and having this as string makes it much easier to work with the package. 35 | type StringType string 36 | 37 | // S converts a string to a StringType 38 | // It is not needed, but if you use this method, it will make it easier to migrate to different implementations of String type in case we actually need *string instead of string 39 | func S(v string) StringType { 40 | return StringType(v) 41 | } 42 | 43 | func SA(v []string) []StringType { 44 | result := make([]StringType, len(v)) 45 | for i := range v { 46 | result[i] = S(v[i]) 47 | } 48 | return result 49 | } 50 | 51 | // NumberType as defined by plotly schema 52 | type NumberType *float64 53 | 54 | func N(n float64) NumberType { 55 | return NumberType(&n) 56 | } 57 | 58 | // NA converts a list of float64 to NumberType 59 | func NA(n []float64) []NumberType { 60 | result := make([]NumberType, len(n)) 61 | for i := range n { 62 | result[i] = N(n[i]) 63 | } 64 | return result 65 | } 66 | 67 | // NS Given a string, parses it as a float64 number 68 | // Panics if the string is not a float number 69 | func NS(n string) NumberType { 70 | v, err := strconv.ParseFloat(n, 64) 71 | if err != nil { 72 | panic(err) 73 | } 74 | return NumberType(&v) 75 | } 76 | func NSA(n []string) []NumberType { 77 | result := make([]NumberType, len(n)) 78 | for i := range n { 79 | result[i] = NS(n[i]) 80 | } 81 | return result 82 | } 83 | 84 | // IntegerType as defined by plotly schema 85 | type IntegerType *int 86 | 87 | func I(n int) IntegerType { 88 | return IntegerType(&n) 89 | } 90 | 91 | // IA converts a list of int to IntegerType 92 | func IA(n []int) []IntegerType { 93 | result := make([]IntegerType, len(n)) 94 | for i := range n { 95 | result[i] = I(n[i]) 96 | } 97 | return result 98 | } 99 | 100 | // IS Given a string, parses it as an integer number 101 | // Panics if the string is not an integer number 102 | func IS(n string) IntegerType { 103 | v, err := strconv.Atoi(n) 104 | if err != nil { 105 | panic(err) 106 | } 107 | return IntegerType(&v) 108 | } 109 | func ISA(n []string) []IntegerType { 110 | result := make([]IntegerType, len(n)) 111 | for i := range n { 112 | result[i] = IS(n[i]) 113 | } 114 | return result 115 | } 116 | -------------------------------------------------------------------------------- /generator/renderer_test.go: -------------------------------------------------------------------------------- 1 | package generator_test 2 | 3 | import ( 4 | "bytes" 5 | "go/format" 6 | 7 | _ "embed" 8 | 9 | "github.com/golang/mock/gomock" 10 | . "github.com/onsi/ginkgo/v2" 11 | . "github.com/onsi/gomega" 12 | 13 | // . "github.com/onsi/gomega/format" 14 | 15 | "github.com/MetalBlueberry/go-plotly/generator" 16 | "github.com/MetalBlueberry/go-plotly/generator/mocks" 17 | ) 18 | 19 | // This test schema is used to make sure the generator works as expected 20 | // It may be worth extending this to test with all schemas. 21 | // 22 | //go:embed test_schema.json 23 | var schema []byte 24 | 25 | var _ = Describe("Renderer", func() { 26 | 27 | Describe("A single trace", func() { 28 | var ( 29 | ctrl *gomock.Controller 30 | mockCreator *mocks.MockCreator 31 | ) 32 | BeforeEach(func() { 33 | ctrl = gomock.NewController(GinkgoT()) 34 | mockCreator = mocks.NewMockCreator(ctrl) 35 | }) 36 | AfterEach(func() { 37 | ctrl.Finish() 38 | }) 39 | 40 | It("Should create package", func() { 41 | buf := NopWriterCloser{&bytes.Buffer{}} 42 | 43 | mockCreator.EXPECT().Create(gomock.Eq("scatter_gen.go")).Return(buf, nil).Times(1) 44 | 45 | root, err := generator.LoadSchema(bytes.NewReader(schema)) 46 | Expect(err).To(BeNil()) 47 | 48 | r, err := generator.NewRenderer(mockCreator, root) 49 | Expect(err).To(BeNil()) 50 | 51 | err = r.CreateTrace(".", "scatter") 52 | Expect(err).To(BeNil()) 53 | 54 | formatted, err := format.Source(buf.Bytes()) 55 | Expect(err).To(BeNil()) 56 | 57 | Expect(string(formatted)).To(ContainSubstring(`package grob`)) 58 | // Type is defined 59 | Expect(string(formatted)).To(ContainSubstring(`type Scatter struct`)) 60 | // Implements interface GetType() 61 | Expect(string(formatted)).To(ContainSubstring(`func (t *Scatter) GetType() types.TraceType`)) 62 | 63 | }) 64 | }) 65 | Describe("When writing", func() { 66 | var r *generator.Renderer 67 | 68 | BeforeEach(func() { 69 | root, err := generator.LoadSchema(bytes.NewReader(schema)) 70 | Expect(err).To(BeNil()) 71 | 72 | r, err = generator.NewRenderer(nil, root) 73 | Expect(err).To(BeNil()) 74 | }) 75 | 76 | Describe("The config", func() { 77 | It("Should be consistent", func() { 78 | 79 | original := &bytes.Buffer{} 80 | err := r.WriteConfig(original) 81 | Expect(err).To(BeNil()) 82 | 83 | for i := 0; i < 10; i++ { 84 | attempt := &bytes.Buffer{} 85 | err = r.WriteConfig(attempt) 86 | Expect(err).To(BeNil()) 87 | Expect(attempt).To(Equal(original)) 88 | } 89 | 90 | }) 91 | }) 92 | Describe("The Layout", func() { 93 | // TruncatedDiff = false 94 | // MaxLength = 0 95 | It("Should be consistent", func() { 96 | 97 | original := &bytes.Buffer{} 98 | err := r.WriteLayout(original) 99 | Expect(err).To(BeNil()) 100 | 101 | for i := 0; i < 10; i++ { 102 | attempt := &bytes.Buffer{} 103 | err = r.WriteLayout(attempt) 104 | Expect(err).To(BeNil()) 105 | Expect(attempt.String()).To(Equal(original.String())) 106 | } 107 | 108 | }) 109 | }) 110 | }) 111 | }) 112 | 113 | type NopWriterCloser struct { 114 | *bytes.Buffer 115 | } 116 | 117 | func (_ NopWriterCloser) Close() error { 118 | return nil 119 | } 120 | -------------------------------------------------------------------------------- /pkg/types/color.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | ) 7 | 8 | // Color A string describing color. Supported formats: - hex (e.g. '#d3d3d3') - rgb (e.g. 'rgb(255, 0, 0)') - rgba (e.g. 'rgb(255, 0, 0, 0.5)') - hsl (e.g. 'hsl(0, 100%, 50%)') - hsv (e.g. 'hsv(0, 100%, 100%)') - named colors (full list: http://www.w3.org/TR/css3-color/#svg-color)", 9 | type Color string 10 | 11 | func C(v string) Color { 12 | return Color(v) 13 | } 14 | 15 | func CN(v []string) []Color { 16 | result := make([]Color, len(v)) 17 | for i := range v { 18 | result[i] = C(v[i]) 19 | } 20 | return result 21 | } 22 | 23 | func UseColorScaleValues(in []float64) []ColorWithColorScale { 24 | out := make([]ColorWithColorScale, len(in), len(in)) 25 | for i := 0; i < len(in); i++ { 26 | out[i] = ColorWithColorScale{ 27 | Value: in[i], 28 | } 29 | } 30 | return out 31 | } 32 | 33 | func UseColors(in []Color) []ColorWithColorScale { 34 | out := make([]ColorWithColorScale, len(in), len(in)) 35 | for i := 0; i < len(in); i++ { 36 | out[i] = ColorWithColorScale{ 37 | Color: &in[i], 38 | } 39 | } 40 | return out 41 | } 42 | 43 | func UseColor(in Color) ColorWithColorScale { 44 | return ColorWithColorScale{ 45 | Color: &in, 46 | } 47 | } 48 | 49 | type ColorWithColorScale struct { 50 | Color *Color 51 | Value float64 52 | } 53 | 54 | func (c *ColorWithColorScale) MarshalJSON() ([]byte, error) { 55 | if c.Color != nil { 56 | return json.Marshal(c.Color) 57 | } 58 | return json.Marshal(c.Value) 59 | } 60 | 61 | func (c *ColorWithColorScale) UnmarshalJSON(data []byte) error { 62 | c.Color = nil 63 | 64 | var color Color 65 | err := json.Unmarshal(data, &color) 66 | if err == nil { 67 | c.Color = &color 68 | return nil 69 | } 70 | 71 | var value float64 72 | err = json.Unmarshal(data, &value) 73 | if err != nil { 74 | return err 75 | } 76 | c.Value = value 77 | return nil 78 | } 79 | 80 | // ColorList A list of colors. Must be an {array} containing valid colors. 81 | type ColorList []Color 82 | 83 | // ColorScale A Plotly colorscale either picked by a name: (any of Greys, YlGnBu, Greens, YlOrRd, Bluered, RdBu, Reds, Blues, Picnic, Rainbow, Portland, Jet, Hot, Blackbody, Earth, Electric, Viridis, Cividis ) customized as an {array} of 2-element {arrays} where the first element is the normalized color level value (starting at *0* and ending at *1*), and the second item is a valid color string. 84 | type ColorScale struct { 85 | Name string 86 | Values []ColorScaleReference 87 | } 88 | 89 | type ColorScaleReference struct { 90 | NormalizedValue float64 91 | Color Color 92 | } 93 | 94 | func (cs *ColorScaleReference) MarshalJSON() ([]byte, error) { 95 | data := []interface{}{cs.NormalizedValue, cs.Color} 96 | return json.Marshal(data) 97 | } 98 | 99 | func (cs *ColorScale) MarshalJSON() ([]byte, error) { 100 | if cs.Values != nil { 101 | return json.Marshal(cs.Values) 102 | } 103 | return json.Marshal(cs.Name) 104 | } 105 | 106 | func (cs *ColorScale) UnmarshalJSON(data []byte) error { 107 | var values []ColorScaleReference 108 | 109 | err := json.Unmarshal(data, &values) 110 | if err == nil { 111 | cs.Values = values 112 | return nil 113 | } 114 | var name string 115 | err = json.Unmarshal(data, &name) 116 | if err == nil { 117 | cs.Name = name 118 | return nil 119 | } 120 | return fmt.Errorf("Unable to Unmarshal ColorScale, %w", err) 121 | } 122 | -------------------------------------------------------------------------------- /examples/stargazers/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "io" 8 | "log" 9 | "net/http" 10 | "text/template" 11 | "time" 12 | 13 | "github.com/pkg/browser" 14 | 15 | grob "github.com/MetalBlueberry/go-plotly/generated/v2.31.1/graph_objects" 16 | "github.com/MetalBlueberry/go-plotly/pkg/types" 17 | ) 18 | 19 | type User struct { 20 | Login string `json:"login,omitempty"` 21 | AvatarURL string `json:"avatar_url,omitempty"` 22 | } 23 | 24 | type GitHubStargazers struct { 25 | StarredAt time.Time `json:"starred_at,omitempty"` 26 | User User `json:"user,omitempty"` 27 | } 28 | 29 | func main() { 30 | 31 | request, err := http.NewRequest("GET", "https://api.github.com/repos/MetalBlueberry/go-plotly/stargazers", nil) 32 | if err != nil { 33 | log.Fatalf("Failed to build request, %s", err) 34 | } 35 | request.Header.Set("Accept", "application/vnd.github.star+json") 36 | 37 | q := request.URL.Query() 38 | q.Set("per_page", "100") 39 | request.URL.RawQuery = q.Encode() 40 | 41 | response, err := http.DefaultClient.Do(request) 42 | if err != nil { 43 | log.Fatalf("Failed to make request to github, %s", err) 44 | } 45 | 46 | defer response.Body.Close() 47 | 48 | buf := &bytes.Buffer{} 49 | 50 | starredAt := []GitHubStargazers{} 51 | err = json.NewDecoder(io.TeeReader(response.Body, buf)).Decode(&starredAt) 52 | if err != nil { 53 | log.Fatalf("Failed to decode response, %s\n%s", err, buf.String()) 54 | } 55 | 56 | x := []string{} 57 | y := []int{} 58 | text := []types.StringType{} 59 | link := []interface{}{} 60 | 61 | for i := 0; i < len(starredAt); i++ { 62 | x = append(x, starredAt[i].StarredAt.Format(time.RFC3339)) 63 | y = append(y, i+1) 64 | text = append(text, types.S(starredAt[i].User.Login)) 65 | link = append(link, starredAt[i].User.AvatarURL) 66 | 67 | } 68 | 69 | fig := &grob.Fig{ 70 | Data: []types.Trace{ 71 | &grob.Scatter{ 72 | X: types.DataArray(x), 73 | Y: types.DataArray(y), 74 | Text: types.ArrayOKArray(text...), 75 | Meta: types.ArrayOKArray(link...), 76 | Mode: grob.ScatterModeLines + "+" + grob.ScatterModeMarkers, 77 | Name: types.S("Stars"), 78 | Line: &grob.ScatterLine{ 79 | Color: "#f0ed46", 80 | }, 81 | }, 82 | }, 83 | 84 | Layout: &grob.Layout{ 85 | Title: &grob.LayoutTitle{ 86 | Text: types.S("Metalblueberry/go-plotly Stargazers"), 87 | }, 88 | Legend: &grob.LayoutLegend{}, 89 | }, 90 | } 91 | 92 | db, _ := json.MarshalIndent(fig, "", " ") 93 | fmt.Println(string(db)) 94 | 95 | buf = figToBuffer(fig) 96 | browser.OpenReader(buf) 97 | } 98 | 99 | var page = ` 100 | 101 | 102 | 103 | 104 |
105 | 106 | 119 | 120 | 121 | ` 122 | 123 | func figToBuffer(fig *grob.Fig) *bytes.Buffer { 124 | figBytes, err := json.Marshal(fig) 125 | if err != nil { 126 | panic(err) 127 | } 128 | tmpl, err := template.New("plotly").Parse(page) 129 | if err != nil { 130 | panic(err) 131 | } 132 | buf := &bytes.Buffer{} 133 | tmpl.Execute(buf, string(figBytes)) 134 | return buf 135 | } 136 | -------------------------------------------------------------------------------- /pkg/types/data_array_test.go: -------------------------------------------------------------------------------- 1 | package types_test 2 | 3 | import ( 4 | "encoding/base64" 5 | "encoding/json" 6 | "fmt" 7 | "reflect" 8 | "testing" 9 | 10 | "github.com/MetalBlueberry/go-plotly/pkg/types" 11 | . "github.com/onsi/gomega" 12 | ) 13 | 14 | var testSomeEncodedDataString = "SomeEncodedData" 15 | var testSomeEncodedDataBytes = []byte("SomeEncodedData") 16 | var testSomeEncodedData = base64.StdEncoding.EncodeToString([]byte(testSomeEncodedDataString)) 17 | 18 | func TestDataArrayType_MarshalJSON(t *testing.T) { 19 | 20 | tests := []struct { 21 | name string 22 | data *types.DataArrayType 23 | expected string 24 | }{ 25 | { 26 | name: "Marshal with values", 27 | data: types.DataArray([]int{1, 2, 3}), 28 | expected: `[1,2,3]`, 29 | }, 30 | { 31 | name: "Marshal with bdata", 32 | data: types.BDataArray(types.DTypeFloat32, testSomeEncodedDataBytes, []int{2, 2}), 33 | expected: fmt.Sprintf(`{"dtype":"float32","bdata":"%s","shape":"2,2"}`, testSomeEncodedData), 34 | }, 35 | } 36 | 37 | for _, tt := range tests { 38 | t.Run(tt.name, func(t *testing.T) { 39 | b, err := tt.data.MarshalJSON() 40 | if err != nil { 41 | t.Fatalf("MarshalJSON() error = %v", err) 42 | } 43 | if string(b) != tt.expected { 44 | t.Errorf("MarshalJSON() = %v, want %v", string(b), tt.expected) 45 | } 46 | }) 47 | } 48 | } 49 | 50 | func TestDataArrayType_UnmarshalJSON(t *testing.T) { 51 | tests := []struct { 52 | name string 53 | data string 54 | expected *types.DataArrayType 55 | }{ 56 | { 57 | name: "Unmarshal with values", 58 | data: `[1,2,3]`, 59 | expected: types.DataArray([]float64{1, 2, 3}), 60 | }, 61 | { 62 | name: "Unmarshal with bdata", 63 | data: fmt.Sprintf(`{"dtype":"float32","bdata":"%s","shape":"2,2"}`, testSomeEncodedData), 64 | expected: types.BDataArray(types.DTypeFloat32, testSomeEncodedDataBytes, []int{2, 2}), 65 | }, 66 | } 67 | 68 | for _, tt := range tests { 69 | t.Run(tt.name, func(t *testing.T) { 70 | g := NewWithT(t) 71 | got := &types.DataArrayType{} 72 | if err := json.Unmarshal([]byte(tt.data), got); err != nil { 73 | t.Fatalf("UnmarshalJSON() error = %v", err) 74 | } 75 | g.Expect(tt.expected).To(Equal(got)) 76 | }) 77 | } 78 | } 79 | 80 | func TestDataArrayShape_MarshalJSON(t *testing.T) { 81 | tests := []struct { 82 | name string 83 | data types.DataArrayShape 84 | expected string 85 | }{ 86 | { 87 | name: "Marshal shape", 88 | data: types.DataArrayShape{2, 3, 4}, 89 | expected: `"2,3,4"`, 90 | }, 91 | } 92 | 93 | for _, tt := range tests { 94 | t.Run(tt.name, func(t *testing.T) { 95 | b, err := tt.data.MarshalJSON() 96 | if err != nil { 97 | t.Fatalf("MarshalJSON() error = %v", err) 98 | } 99 | if string(b) != tt.expected { 100 | t.Errorf("MarshalJSON() = %v, want %v", string(b), tt.expected) 101 | } 102 | }) 103 | } 104 | } 105 | 106 | func TestDataArrayShape_UnmarshalJSON(t *testing.T) { 107 | tests := []struct { 108 | name string 109 | data string 110 | expected types.DataArrayShape 111 | }{ 112 | { 113 | name: "Unmarshal shape", 114 | data: `"2,3,4"`, 115 | expected: types.DataArrayShape{2, 3, 4}, 116 | }, 117 | } 118 | 119 | for _, tt := range tests { 120 | t.Run(tt.name, func(t *testing.T) { 121 | var got types.DataArrayShape 122 | if err := json.Unmarshal([]byte(tt.data), &got); err != nil { 123 | t.Fatalf("UnmarshalJSON() error = %v", err) 124 | } 125 | if !reflect.DeepEqual(got, tt.expected) { 126 | t.Errorf("UnmarshalJSON() = %+v, want %+v", got, tt.expected) 127 | } 128 | }) 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /examples/range_slider/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "net/http" 5 | "strings" 6 | 7 | "github.com/go-gota/gota/dataframe" 8 | 9 | grob "github.com/MetalBlueberry/go-plotly/generated/v2.31.1/graph_objects" 10 | "github.com/MetalBlueberry/go-plotly/pkg/offline" 11 | "github.com/MetalBlueberry/go-plotly/pkg/types" 12 | ) 13 | 14 | func main() { 15 | /* 16 | https://plotly.com/python/range-slider/ 17 | import plotly.graph_objects as go 18 | 19 | import pandas as pd 20 | 21 | # Load data 22 | df = pd.read_csv( 23 | "https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv") 24 | df.columns = [col.replace("AAPL.", "") for col in df.columns] 25 | 26 | # Create figure 27 | fig = go.Figure() 28 | 29 | fig.add_trace( 30 | go.Scatter(x=list(df.Date), y=list(df.High))) 31 | 32 | # Set title 33 | fig.update_layout( 34 | title_text="Time series with range slider and selectors" 35 | ) 36 | 37 | # Add range slider 38 | fig.update_layout( 39 | xaxis=dict( 40 | rangeselector=dict( 41 | buttons=list([ 42 | dict(count=1, 43 | label="1m", 44 | step="month", 45 | stepmode="backward"), 46 | dict(count=6, 47 | label="6m", 48 | step="month", 49 | stepmode="backward"), 50 | dict(count=1, 51 | label="YTD", 52 | step="year", 53 | stepmode="todate"), 54 | dict(count=1, 55 | label="1y", 56 | step="year", 57 | stepmode="backward"), 58 | dict(step="all") 59 | ]) 60 | ), 61 | rangeslider=dict( 62 | visible=True 63 | ), 64 | type="date" 65 | ) 66 | ) 67 | 68 | fig.show() 69 | */ 70 | 71 | request, err := http.Get("https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv") 72 | if err != nil { 73 | panic(err) 74 | } 75 | 76 | df := dataframe.ReadCSV(request.Body) 77 | for _, col := range df.Names() { 78 | df = df.Rename(strings.TrimPrefix(col, "AAPL."), col) 79 | } 80 | 81 | fig := &grob.Fig{} 82 | fig.Data = append(fig.Data, &grob.Scatter{ 83 | X: types.DataArray(df.Col("Date").Records()), 84 | Y: types.DataArray(df.Col("High").Float()), 85 | }) 86 | 87 | fig.Layout = &grob.Layout{ 88 | Title: &grob.LayoutTitle{ 89 | Text: types.S("Time series with range slider and selectors"), 90 | }, 91 | Xaxis: &grob.LayoutXaxis{ 92 | Rangeselector: &grob.LayoutXaxisRangeselector{ 93 | Buttons: []grob.LayoutXaxisRangeselectorButton{ 94 | { 95 | Count: types.N(1), 96 | Label: types.S("1m"), 97 | Step: "month", 98 | Stepmode: "backward", 99 | }, 100 | { 101 | Count: types.N(6), 102 | Label: types.S("6m"), 103 | Step: "month", 104 | Stepmode: "backward", 105 | }, 106 | { 107 | Count: types.N(1), 108 | Label: types.S("YTD"), 109 | Step: "year", 110 | Stepmode: "todate", 111 | }, 112 | { 113 | Count: types.N(1), 114 | Label: types.S("1y"), 115 | Step: "year", 116 | Stepmode: "backward", 117 | }, 118 | { 119 | Step: "all", 120 | }, 121 | }, 122 | }, 123 | Rangeslider: &grob.LayoutXaxisRangeslider{ 124 | Visible: types.True, 125 | }, 126 | Type: grob.LayoutXaxisTypeDate, 127 | }, 128 | } 129 | 130 | offline.ToHtml(fig, "range_slider.html") 131 | offline.Show(fig) 132 | } 133 | -------------------------------------------------------------------------------- /generator/cmd/generator/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "io" 7 | "log" 8 | "os" 9 | "path/filepath" 10 | 11 | "github.com/MetalBlueberry/go-plotly/generator" 12 | ) 13 | 14 | type Creator struct{} 15 | 16 | func (c Creator) Create(name string) (io.WriteCloser, error) { 17 | abs, err := filepath.Abs(name) 18 | if err != nil { 19 | return nil, err 20 | } 21 | 22 | return os.Create(abs) 23 | } 24 | 25 | // The generate command always executes with the working directory set to the path with the file with the directive 26 | //go:generate go run main.go --config=../../../schemas.yaml -clean 27 | 28 | const configPath = "schemas.yaml" 29 | 30 | func main() { 31 | var schemapath string 32 | var clean bool 33 | 34 | flag.StringVar(&schemapath, "config", configPath, "yaml file defining versions to be generated") 35 | flag.BoolVar(&clean, "clean", false, "clean the output directory first. Mandatory on CI") 36 | 37 | flag.Parse() 38 | 39 | // Define a flag for the version 40 | schemas := generator.ReadSchemas(schemapath) 41 | if schemas == nil { 42 | fmt.Printf("could not find versions\n") 43 | return 44 | } 45 | 46 | root := filepath.Dir(schemapath) 47 | 48 | for _, schema := range schemas { 49 | generatePackage(root, schema, clean) 50 | } 51 | 52 | } 53 | 54 | func rootDirectories(root, schema, output string) (string, string) { 55 | schema = filepath.Join(root, schema) 56 | output = filepath.Join(root, output) 57 | 58 | return schema, output 59 | } 60 | 61 | // create the packages and write them into the specified folders 62 | 63 | func generatePackage(projectRoot string, version generator.Version, clean bool) { 64 | // look for the correct schema and output paths 65 | schema, relativeVersionOutput := rootDirectories(projectRoot, version.Path, version.Generated) 66 | log.Println("schema:", schema, "versionoutput", relativeVersionOutput) 67 | 68 | file, err := os.Open(schema) 69 | if err != nil { 70 | log.Fatalf("unable to open schema, %s", err) 71 | } 72 | 73 | graphObjectsOuput := filepath.Join(relativeVersionOutput, "graph_objects") 74 | 75 | schemaRoot, err := generator.LoadSchema(file) 76 | if err != nil { 77 | log.Fatalf("unable to load schema, %s", err) 78 | } 79 | 80 | r, err := generator.NewRenderer(Creator{}, schemaRoot) 81 | if err != nil { 82 | log.Fatalf("unable to create a new renderer, %s", err) 83 | } 84 | 85 | if clean { 86 | for _, path := range []string{graphObjectsOuput} { 87 | err = os.RemoveAll(path) 88 | if err != nil { 89 | log.Fatalf("Failed to clean output directory, %s", err) 90 | } 91 | 92 | if err = os.MkdirAll(path, 0755); err != nil { 93 | log.Fatalf("Failed to create output dir %s, %s", path, err) 94 | } 95 | } 96 | } 97 | 98 | err = r.CreatePlotly(graphObjectsOuput, version) 99 | if err != nil { 100 | log.Fatalf("unable to write plotly, %s", err) 101 | } 102 | 103 | err = r.CreateTraces(graphObjectsOuput) 104 | if err != nil { 105 | log.Fatalf("unable to write traces, %s", err) 106 | } 107 | 108 | err = r.CreateLayout(graphObjectsOuput) 109 | if err != nil { 110 | log.Fatalf("unable to write layout, %s", err) 111 | } 112 | 113 | err = r.CreateConfig(graphObjectsOuput) 114 | if err != nil { 115 | log.Fatalf("unable to write config, %s", err) 116 | } 117 | 118 | err = r.CreateAnimation(graphObjectsOuput) 119 | if err != nil { 120 | log.Fatalf("unable to write layout, %s", err) 121 | } 122 | 123 | err = r.CreateFrames(graphObjectsOuput) 124 | if err != nil { 125 | log.Fatalf("unable to write layout, %s", err) 126 | } 127 | 128 | err = r.CreateUnmarshal(graphObjectsOuput) 129 | if err != nil { 130 | log.Fatalf("unable to write unmarshal, %s", err) 131 | } 132 | 133 | err = r.CreateUnmarshalTests(graphObjectsOuput) 134 | if err != nil { 135 | log.Fatalf("unable to write unmarshal, %s", err) 136 | } 137 | 138 | } 139 | -------------------------------------------------------------------------------- /pkg/offline/plot.go: -------------------------------------------------------------------------------- 1 | package offline 2 | 3 | import ( 4 | "bytes" 5 | "encoding/base64" 6 | "encoding/json" 7 | "log" 8 | "net/http" 9 | "os" 10 | "text/template" 11 | 12 | "github.com/MetalBlueberry/go-plotly/pkg/types" 13 | "github.com/pkg/browser" 14 | ) 15 | 16 | type Options struct { 17 | Addr string 18 | } 19 | 20 | // ToHtml saves the figure as standalone HTML. It still requires internet to load plotly.js from CDN. 21 | func ToHtml(fig types.Fig, path string) { 22 | buf := figToBuffer(fig) 23 | os.WriteFile(path, buf.Bytes(), os.ModePerm) 24 | } 25 | 26 | // Show displays the figure in your browser. 27 | // Use serve if you want a persistent view 28 | func Show(fig types.Fig) { 29 | buf := figToBuffer(fig) 30 | browser.OpenReader(buf) 31 | } 32 | 33 | func figToBuffer(fig types.Fig) *bytes.Buffer { 34 | figBytes, err := json.Marshal(fig) 35 | if err != nil { 36 | panic(err) 37 | } 38 | tmpl, err := template.New("plotly").Parse(singleFileHTML) 39 | if err != nil { 40 | panic(err) 41 | } 42 | buf := &bytes.Buffer{} 43 | data := struct { 44 | Version types.Version 45 | B64Content string 46 | }{ 47 | Version: fig.Info(), 48 | // Encode to avoid problems with special characters 49 | B64Content: base64.StdEncoding.EncodeToString(figBytes), 50 | } 51 | 52 | err = tmpl.Execute(buf, data) 53 | if err != nil { 54 | panic(err) 55 | } 56 | return buf 57 | } 58 | 59 | // Serve creates a local web server that displays the image using plotly.js 60 | // Is a good alternative to Show to avoid creating tmp files. 61 | func Serve(fig types.Fig, opt ...Options) { 62 | opts := computeOptions(Options{ 63 | Addr: "localhost:8080", 64 | }, opt...) 65 | 66 | mux := &http.ServeMux{} 67 | srv := &http.Server{ 68 | Handler: mux, 69 | Addr: opts.Addr, 70 | } 71 | 72 | mux.HandleFunc("/content", func(w http.ResponseWriter, r *http.Request) { 73 | err := json.NewEncoder(w).Encode(fig) 74 | if err != nil { 75 | log.Printf("Error rendering template, %s", err) 76 | w.WriteHeader(http.StatusInternalServerError) 77 | } 78 | }) 79 | 80 | mux.HandleFunc("/", webPage(fig, "/content")) 81 | 82 | log.Printf("Starting server at %s", srv.Addr) 83 | if err := srv.ListenAndServe(); err != nil { 84 | log.Print(err) 85 | } 86 | log.Print("Stop server") 87 | } 88 | 89 | func computeOptions(def Options, opt ...Options) Options { 90 | if len(opt) == 1 { 91 | opts := opt[0] 92 | if opts.Addr != "" { 93 | def.Addr = opts.Addr 94 | } 95 | } 96 | return def 97 | } 98 | 99 | var singleFileHTML = ` 100 | 101 | 102 | 103 | 104 |
105 | 109 | 110 | ` 111 | 112 | type serverHTMLdata struct { 113 | Version types.Version 114 | ContentURL string 115 | } 116 | 117 | func webPage(fig types.Fig, contentURL string) func(w http.ResponseWriter, r *http.Request) { 118 | return func(w http.ResponseWriter, r *http.Request) { 119 | tmpl := template.Must(template.New("server").Parse(serverHTML)) 120 | data := serverHTMLdata{ 121 | Version: fig.Info(), 122 | ContentURL: contentURL, 123 | } 124 | err := tmpl.Execute(w, data) 125 | if err != nil { 126 | log.Printf("Error rendering template, %s", err) 127 | w.WriteHeader(http.StatusInternalServerError) 128 | return 129 | } 130 | } 131 | } 132 | 133 | var serverHTML = ` 134 | 135 | 136 | 137 | 138 |
139 | 149 | 150 | ` 151 | -------------------------------------------------------------------------------- /generator/schema.go: -------------------------------------------------------------------------------- 1 | package generator 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "io" 8 | "net/http" 9 | "os" 10 | "path/filepath" 11 | 12 | "gopkg.in/yaml.v3" 13 | ) 14 | 15 | type Schemas struct { 16 | Versions []Version `yaml:"versions"` 17 | } 18 | 19 | type Version struct { 20 | Name string `yaml:"Name"` // name of the version 21 | Tag string `yaml:"Tag"` // git tag of the plotly version 22 | URL string `yaml:"URL"` // url under which the plotly schema json file can be downloaded directly 23 | Path string `yaml:"Path"` // path under which the schema file will be saved locally for future use 24 | Generated string `yaml:"Generated"` // path for the generated package 25 | Cdn string `yaml:"CDN"` // url for the cdn which should be included in the head of the generated html 26 | } 27 | 28 | // cleanJson makes sure that whitespaces and new line characters are removed from the downloaded json 29 | func cleanJson(stream io.ReadCloser) (bytes.Buffer, error) { 30 | var err error 31 | var buf bytes.Buffer 32 | 33 | // Read and decode JSON content 34 | var jsonData interface{} 35 | err = json.NewDecoder(stream).Decode(&jsonData) 36 | if err != nil { 37 | return buf, fmt.Errorf("could not decode json content of response") 38 | } 39 | 40 | // Re-encode JSON content with minimized whitespace and no new lines 41 | encoder := json.NewEncoder(&buf) 42 | encoder.SetIndent("", "") 43 | err = encoder.Encode(jsonData) 44 | if err != nil { 45 | return buf, fmt.Errorf("could not remove whitespaces and new lines from json by encoding content") 46 | } 47 | // Remove newline character from the end of the encoded JSON 48 | buf.Truncate(buf.Len() - 1) 49 | return buf, nil 50 | } 51 | 52 | // DownloadSchema gets the schema file for a given version, and either saves the raw content, 53 | // or prepares the file for the generator if prep is set to true 54 | func DownloadSchema(version string, schemaURL string, outputpath string) (string, error) { 55 | // Make GET request to download schema 56 | response, err := http.Get(schemaURL) 57 | if err != nil { 58 | return "", err 59 | } 60 | if response.StatusCode != http.StatusOK { 61 | return "", fmt.Errorf("could not schema file for version: %s\n[Status Code: %d (%s)]\nused url: %s\nlist the available tags first and recheck", version, response.StatusCode, response.Status, schemaURL) 62 | } 63 | defer response.Body.Close() 64 | 65 | // clean the response 66 | buf, err := cleanJson(response.Body) 67 | if err != nil { 68 | return "", fmt.Errorf("%s: from: %s", err, schemaURL) 69 | } 70 | 71 | // Create file to save the schema 72 | err = os.MkdirAll(filepath.Dir(outputpath), 0755) 73 | if err != nil { 74 | return "", fmt.Errorf("could not create directory for plotly schema: %s", filepath.Dir(outputpath)) 75 | } 76 | 77 | _, err = os.Stat(outputpath) 78 | if err == nil { 79 | fmt.Printf("WARN: overwriting: %s\n", outputpath) 80 | } 81 | file, err := os.Create(outputpath) 82 | if err != nil { 83 | return "", fmt.Errorf("could not create file for saving: %s", outputpath) 84 | } 85 | defer file.Close() 86 | 87 | // Copy response body to file 88 | fmt.Printf("Downloading %s -> %s\n", schemaURL, outputpath) 89 | 90 | _, err = file.Write([]byte(`{"sha1":"11b662302a42aa0698df091a9974ac8f6e1a2292","modified":true,"schema":`)) 91 | if err != nil { 92 | return "", fmt.Errorf("could not write json schema prepared for code generator: %s", outputpath) 93 | } 94 | 95 | // Write JSON content to file 96 | _, err = io.Copy(file, &buf) 97 | if err != nil { 98 | return "", err 99 | } 100 | 101 | _, err = file.Write([]byte(`}`)) 102 | if err != nil { 103 | return "", err 104 | } 105 | 106 | fmt.Printf("Schema downloaded and saved as: %s\n", outputpath) 107 | return outputpath, nil 108 | } 109 | 110 | func ReadSchemas(schemapath string) []Version { 111 | var err error 112 | f, err := os.Open(schemapath) 113 | if err != nil { 114 | fmt.Printf("error opening schema yaml file: %s\n", err) 115 | return nil 116 | } 117 | 118 | var schemas Schemas 119 | decoder := yaml.NewDecoder(f) 120 | err = decoder.Decode(&schemas) 121 | if err != nil { 122 | fmt.Printf("error decoding schema yaml file: %s\n", err) 123 | return nil 124 | } 125 | 126 | return schemas.Versions 127 | } 128 | -------------------------------------------------------------------------------- /examples/waterfall_bar_chart/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | grob "github.com/MetalBlueberry/go-plotly/generated/v2.31.1/graph_objects" 5 | "github.com/MetalBlueberry/go-plotly/pkg/offline" 6 | "github.com/MetalBlueberry/go-plotly/pkg/types" 7 | ) 8 | 9 | func main() { 10 | /* 11 | https://plotly.com/javascript/bar-charts/#waterfall-bar-chart 12 | 13 | // Base 14 | 15 | var xData = ['Product
Revenue', 'Services
Revenue', 16 | 'Total
Revenue', 'Fixed
Costs', 17 | 'Variable
Costs', 'Total
Costs', 'Total' 18 | ]; 19 | 20 | var yData = [400, 660, 660, 590, 400, 400, 340]; 21 | 22 | var textList = ['$430K', '$260K', '$690K', '$-120K', '$-200K', '$-320K', '$370K']; 23 | 24 | //Base 25 | 26 | var trace1 = { 27 | x: xData, 28 | y: [0, 430, 0, 570, 370, 370, 0], 29 | marker: { 30 | color: 'rgba(1,1,1,0.0)' 31 | }, 32 | type: 'bar' 33 | }; 34 | 35 | //Revenue 36 | 37 | var trace2 = { 38 | x: xData, 39 | y: [430, 260, 690, 0, 0, 0, 0], 40 | type: 'bar', 41 | marker: { 42 | color: 'rgba(55,128,191,0.7)', 43 | line: { 44 | color: 'rgba(55,128,191,1.0)', 45 | width: 2 46 | } 47 | } 48 | }; 49 | 50 | //Cost 51 | 52 | var trace3 = { 53 | x: xData, 54 | y: [0, 0, 0, 120, 200, 320, 0], 55 | type: 'bar', 56 | marker: { 57 | color: 'rgba(219, 64, 82, 0.7)', 58 | line: { 59 | color: 'rgba(219, 64, 82, 1.0)', 60 | width: 2 61 | } 62 | } 63 | }; 64 | 65 | //Profit 66 | 67 | var trace4 = { 68 | x: xData, 69 | y: [0, 0, 0, 0, 0, 0, 370], 70 | type: 'bar', 71 | marker: { 72 | color: 'rgba(50,171, 96, 0.7)', 73 | line: { 74 | color: 'rgba(50,171,96,1.0)', 75 | width: 2 76 | } 77 | } 78 | }; 79 | 80 | var data = [trace1, trace2, trace3, trace4]; 81 | 82 | var layout = { 83 | title: 'Annual Profit 2015', 84 | barmode: 'stack', 85 | paper_bgcolor: 'rgba(245,246,249,1)', 86 | plot_bgcolor: 'rgba(245,246,249,1)', 87 | width: 600, 88 | height: 600, 89 | showlegend: false, 90 | annotations: [] 91 | }; 92 | 93 | for ( var i = 0 ; i < 7 ; i++ ) { 94 | var result = { 95 | x: xData[i], 96 | y: yData[i], 97 | text: textList[i], 98 | font: { 99 | family: 'Arial', 100 | size: 14, 101 | color: 'rgba(245,246,249,1)' 102 | }, 103 | showarrow: false 104 | }; 105 | layout.annotations.push(result); 106 | }; 107 | 108 | Plotly.newPlot('myDiv', data, layout); 109 | */ 110 | xData := []string{ 111 | "Product
Revenue", 112 | "Services
Revenue", 113 | "Total
Revenue", 114 | "Fixed
Costs", 115 | "Variable
Costs", 116 | "Total
Costs", 117 | "Total", 118 | } 119 | yData := []int{400, 660, 660, 590, 400, 400, 340} 120 | textList := []string{"$430K", "$260K", "$690K", "$-120K", "$-200K", "$-320K", "$370K"} 121 | 122 | // Base 123 | 124 | trace1 := &grob.Bar{ 125 | X: types.DataArray(xData), 126 | Y: types.DataArray([]int{0, 430, 0, 570, 370, 370, 0}), 127 | Marker: &grob.BarMarker{ 128 | Color: types.ArrayOKValue(types.UseColor("rgba(1,1,1,0.0)")), 129 | }, 130 | } 131 | 132 | // Revenue 133 | 134 | trace2 := &grob.Bar{ 135 | X: types.DataArray(xData), 136 | Y: types.DataArray([]int{430, 260, 690, 0, 0, 0, 0}), 137 | Marker: &grob.BarMarker{ 138 | Color: types.ArrayOKValue(types.UseColor("rgba(55,128,191,0.7)")), 139 | Line: &grob.BarMarkerLine{ 140 | Color: types.ArrayOKValue(types.UseColor("rgba(55,128,191,1.0)")), 141 | Width: types.ArrayOKValue(types.N(2.0)), 142 | }, 143 | }, 144 | } 145 | 146 | // Cost 147 | 148 | trace3 := &grob.Bar{ 149 | X: types.DataArray(xData), 150 | Y: types.DataArray([]int{0, 0, 0, 120, 200, 320, 0}), 151 | Marker: &grob.BarMarker{ 152 | Color: types.ArrayOKValue(types.UseColor("rgba(219, 64, 82, 0.7)")), 153 | Line: &grob.BarMarkerLine{ 154 | Color: types.ArrayOKValue(types.UseColor("rgba(219, 64, 82, 1.0)")), 155 | Width: types.ArrayOKValue(types.N(2.0)), 156 | }, 157 | }, 158 | } 159 | 160 | // Profit 161 | 162 | trace4 := &grob.Bar{ 163 | X: types.DataArray(xData), 164 | Y: types.DataArray([]int{0, 0, 0, 0, 0, 0, 370}), 165 | Marker: &grob.BarMarker{ 166 | Color: types.ArrayOKValue(types.UseColor("rgba(50,171, 96, 0.7)")), 167 | Line: &grob.BarMarkerLine{ 168 | Color: types.ArrayOKValue(types.UseColor("rgba(50,171,96,1.0)")), 169 | Width: types.ArrayOKValue(types.N(2.0)), 170 | }, 171 | }, 172 | } 173 | 174 | data := []types.Trace{trace1, trace2, trace3, trace4} 175 | 176 | annotations := make([]grob.LayoutAnnotation, 7) 177 | for i := 0; i < len(annotations); i++ { 178 | annotations[i] = grob.LayoutAnnotation{ 179 | X: xData[i], 180 | Y: yData[i], 181 | Text: types.S(textList[i]), 182 | Font: &grob.LayoutAnnotationFont{ 183 | Family: types.S("Arial"), 184 | Size: types.N(14), 185 | Color: "rgba(245,246,249,1)", 186 | }, 187 | Showarrow: types.False, 188 | } 189 | } 190 | 191 | layout := &grob.Layout{ 192 | Title: &grob.LayoutTitle{ 193 | Text: types.S("Annual Profit 2015"), 194 | }, 195 | Barmode: grob.BarBarmodeStack, 196 | PaperBgcolor: "rgba(245,246,249,1)", 197 | PlotBgcolor: "rgba(245,246,249,1)", 198 | Width: types.N(600), 199 | Height: types.N(600), 200 | Showlegend: types.False, 201 | Annotations: annotations, 202 | } 203 | 204 | fig := &grob.Fig{ 205 | Data: data, 206 | Layout: layout, 207 | } 208 | 209 | offline.ToHtml(fig, "waterfall.html") 210 | offline.Show(fig) 211 | } 212 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= 4 | github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= 5 | github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= 6 | github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= 7 | github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= 8 | github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= 9 | github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= 10 | github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 11 | github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 h1:k7nVchz72niMH6YLQNvHSdIE7iqsQxK1P41mySCvssg= 12 | github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= 13 | github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU= 14 | github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= 15 | github.com/onsi/ginkgo/v2 v2.17.2 h1:7eMhcy3GimbsA3hEnVKdw/PQM9XN9krpKVXsZdph0/g= 16 | github.com/onsi/ginkgo/v2 v2.17.2/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc= 17 | github.com/onsi/gomega v1.33.0 h1:snPCflnZrpMsy94p4lXVEkHo12lmPnc3vY5XBbreexE= 18 | github.com/onsi/gomega v1.33.0/go.mod h1:+925n5YtiFsLzzafLUHzVMBpvvRAzrydIBiSIxjX3wY= 19 | github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= 20 | github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= 21 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 22 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 23 | github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= 24 | github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= 25 | github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= 26 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 27 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 28 | golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 h1:kx6Ds3MlpiUHKj7syVnbp57++8WpuKPcR5yjLBjvLEA= 29 | golang.org/x/exp v0.0.0-20240823005443-9b4947da3948/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ= 30 | golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 31 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 32 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 33 | golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= 34 | golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= 35 | golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= 36 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 37 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 38 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 39 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 40 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 41 | golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 42 | golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 43 | golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 44 | golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= 45 | golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 46 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 47 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 48 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 49 | golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= 50 | golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= 51 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 52 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 53 | golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 54 | golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= 55 | golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= 56 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 57 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 58 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 59 | google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= 60 | google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= 61 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 62 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 63 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 64 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 65 | -------------------------------------------------------------------------------- /pkg/types/data_array.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "reflect" 8 | ) 9 | 10 | // DataArrayType An {array} of data. 11 | // The value must represent an {array} or it will be ignored, but this array can be provided in several forms: 12 | // (1) a regular {array} object 13 | // (2) a typed array (e.g. Float32Array) 14 | // (3) an object with keys dtype, bdata, and optionally shape. 15 | // In this 3rd form, dtype is one of *f8*, *f4*. *i4*, *u4*, *i2*, *u2*, *i1*, *u1* or *u1c* for Uint8ClampedArray. 16 | // In addition to shorthand `dtype` above one could also use the following forms: *float64*, *float32*, *int32*, *uint32*, *int16*, *uint16*, *int8*, *uint8* or *uint8c* for Uint8ClampedArray. 17 | // `bdata` is either a base64-encoded string or the ArrayBuffer of an integer or float typed array. 18 | // For either multi-dimensional arrays you must also provide its dimensions separated by comma via `shape`. 19 | // For example using `dtype`: *f4* and `shape`: *5,100* you can declare a 2-D array that has 5 rows and 100 columns containing 20 | // float32 values i.e. 4 bits per value. `shape` is optional for one dimensional arrays.", 21 | type DataArrayType struct { 22 | // Option 1 23 | values interface{} 24 | 25 | // Option 2 // doesn't apply in go as option one already has types 26 | 27 | // Option 3 28 | dtype DType 29 | // Base64 encoded data 30 | bdata []byte 31 | shape DataArrayShape 32 | } 33 | 34 | type BDataArrayType struct { 35 | Dtype DType `json:"dtype,omitempty"` 36 | Bdata []byte `json:"bdata,omitempty"` 37 | Shape DataArrayShape `json:"shape,omitempty"` 38 | } 39 | 40 | // Value returns either the underlying interface values OR the BDataArrayType, depending on how the DataArray was created. 41 | func (da *DataArrayType) Value() interface{} { 42 | if da.values != nil { 43 | return da.values 44 | } 45 | if da.bdata != nil { 46 | return BDataArrayType{ 47 | Dtype: da.dtype, 48 | Bdata: da.bdata, 49 | Shape: da.shape, 50 | } 51 | } 52 | return nil 53 | } 54 | 55 | type DataArrayShape []int 56 | 57 | type DType string 58 | 59 | const ( 60 | DTypeFloat64 DType = "float64" 61 | DTypeFloat32 DType = "float32" 62 | DTypeInt32 DType = "int32" 63 | DTypeUInt32 DType = "uint32" 64 | DTypeInt16 DType = "int16" 65 | DTypeUInt16 DType = "uint16" 66 | DTypeInt8 DType = "int8" 67 | DTypeUInt8 DType = "uint8" 68 | DTypeUInt8c DType = "uint8c" 69 | ) 70 | 71 | func DataArray[T any](data []T) *DataArrayType { 72 | return &DataArrayType{ 73 | values: data, 74 | } 75 | } 76 | 77 | func BDataArray(dtype DType, bdata []byte, shape []int) *DataArrayType { 78 | return &DataArrayType{ 79 | dtype: dtype, 80 | bdata: bdata, 81 | shape: shape, 82 | } 83 | } 84 | 85 | func (d *DataArrayType) MarshalJSON() ([]byte, error) { 86 | if d.values != nil { 87 | // If Values is not nil, marshal it directly 88 | return json.Marshal(d.values) 89 | } 90 | 91 | return json.Marshal(BDataArrayType{ 92 | Dtype: d.dtype, 93 | Bdata: d.bdata, 94 | Shape: d.shape, 95 | }) 96 | } 97 | 98 | func (d *DataArrayType) UnmarshalJSON(data []byte) error { 99 | 100 | bData := &BDataArrayType{} 101 | err := json.Unmarshal(data, bData) 102 | if err == nil { 103 | d.bdata = bData.Bdata 104 | d.dtype = bData.Dtype 105 | d.shape = bData.Shape 106 | return nil 107 | } 108 | 109 | values, err := unmarshalToGenericSlice(data) 110 | if err != nil { 111 | return err 112 | } 113 | d.values = values 114 | return nil 115 | } 116 | 117 | // unmarshalToGenericSlice unmarshals JSON data into a generic slice. 118 | // It returns the data as a slice of interface{} and its detected type. 119 | func unmarshalToGenericSlice(data []byte) (interface{}, error) { 120 | var genericSlice []interface{} 121 | if err := json.Unmarshal(data, &genericSlice); err != nil { 122 | return nil, err 123 | } 124 | 125 | if len(genericSlice) == 0 { 126 | return genericSlice, nil 127 | } 128 | 129 | // Determine the type of elements in the slice 130 | elemType := reflect.TypeOf(genericSlice[0]) 131 | return convertToType(genericSlice, elemType.Kind()) 132 | } 133 | 134 | // Convert a slice of interface{} to a slice of the detected type 135 | func convertToType(slice []interface{}, elemType reflect.Kind) (interface{}, error) { 136 | switch elemType { 137 | // I believe json package will never use this type, but will use float64 138 | case reflect.Int: 139 | intSlice := make([]int, len(slice)) 140 | for i, v := range slice { 141 | if v, ok := v.(float64); ok { // JSON numbers are float64 by default 142 | intSlice[i] = int(v) 143 | } else { 144 | return nil, fmt.Errorf("unexpected type %T for int", v) 145 | } 146 | } 147 | return intSlice, nil 148 | case reflect.Float64: 149 | floatSlice := make([]float64, len(slice)) 150 | for i, v := range slice { 151 | if v, ok := v.(float64); ok { 152 | floatSlice[i] = v 153 | } else { 154 | return nil, fmt.Errorf("unexpected type %T for float64", v) 155 | } 156 | } 157 | return floatSlice, nil 158 | case reflect.String: 159 | stringSlice := make([]string, len(slice)) 160 | for i, v := range slice { 161 | if v, ok := v.(string); ok { 162 | stringSlice[i] = v 163 | } else { 164 | return nil, fmt.Errorf("unexpected type %T for string", v) 165 | } 166 | } 167 | return stringSlice, nil 168 | default: 169 | return nil, fmt.Errorf("unsupported type %s", elemType) 170 | } 171 | } 172 | 173 | func (d DataArrayShape) MarshalJSON() ([]byte, error) { 174 | b, err := json.Marshal([]int(d)) 175 | if err != nil { 176 | return b, err 177 | } 178 | // make data compatible with what plotty expects 179 | b = bytes.Replace(b, []byte("["), []byte("\""), -1) 180 | b = bytes.Replace(b, []byte("]"), []byte("\""), -1) 181 | 182 | return b, nil 183 | } 184 | 185 | func (d *DataArrayShape) UnmarshalJSON(data []byte) error { 186 | data = bytes.Replace(data, []byte("\""), []byte("["), 1) 187 | data = bytes.Replace(data, []byte("\""), []byte("]"), 1) 188 | 189 | intSlice := []int{} 190 | err := json.Unmarshal(data, &intSlice) 191 | if err != nil { 192 | return err 193 | } 194 | (*d) = intSlice 195 | return nil 196 | } 197 | -------------------------------------------------------------------------------- /generated/v2.19.0/graph_objects/animation_gen.go: -------------------------------------------------------------------------------- 1 | package grob 2 | 3 | // Code generated by go-plotly/generator. DO NOT EDIT. 4 | 5 | import ( 6 | "github.com/MetalBlueberry/go-plotly/pkg/types" 7 | ) 8 | 9 | // Animation Plot animation options 10 | type Animation struct { 11 | 12 | // Direction 13 | // arrayOK: false 14 | // default: forward 15 | // type: enumerated 16 | // The direction in which to play the frames triggered by the animation call 17 | // .schema.animation.direction 18 | Direction AnimationDirection `json:"direction,omitempty"` 19 | 20 | // Frame 21 | // arrayOK: false 22 | // role: Object 23 | // .schema.animation.frame 24 | Frame *AnimationFrame `json:"frame,omitempty"` 25 | 26 | // Fromcurrent 27 | // arrayOK: false 28 | // type: boolean 29 | // Play frames starting at the current frame instead of the beginning. 30 | // .schema.animation.fromcurrent 31 | Fromcurrent types.BoolType `json:"fromcurrent,omitempty"` 32 | 33 | // Mode 34 | // arrayOK: false 35 | // default: afterall 36 | // type: enumerated 37 | // Describes how a new animate call interacts with currently-running animations. If `immediate`, current animations are interrupted and the new animation is started. If `next`, the current frame is allowed to complete, after which the new animation is started. If `afterall` all existing frames are animated to completion before the new animation is started. 38 | // .schema.animation.mode 39 | Mode AnimationMode `json:"mode,omitempty"` 40 | 41 | // Transition 42 | // arrayOK: false 43 | // role: Object 44 | // .schema.animation.transition 45 | Transition *AnimationTransition `json:"transition,omitempty"` 46 | } 47 | 48 | // AnimationFrame 49 | type AnimationFrame struct { 50 | 51 | // Duration 52 | // arrayOK: false 53 | // type: number 54 | // The duration in milliseconds of each frame. If greater than the frame duration, it will be limited to the frame duration. 55 | // .schema.animation.frame.duration 56 | Duration types.NumberType `json:"duration,omitempty"` 57 | 58 | // Redraw 59 | // arrayOK: false 60 | // type: boolean 61 | // Redraw the plot at completion of the transition. This is desirable for transitions that include properties that cannot be transitioned, but may significantly slow down updates that do not require a full redraw of the plot 62 | // .schema.animation.frame.redraw 63 | Redraw types.BoolType `json:"redraw,omitempty"` 64 | } 65 | 66 | // AnimationTransition 67 | type AnimationTransition struct { 68 | 69 | // Duration 70 | // arrayOK: false 71 | // type: number 72 | // The duration of the transition, in milliseconds. If equal to zero, updates are synchronous. 73 | // .schema.animation.transition.duration 74 | Duration types.NumberType `json:"duration,omitempty"` 75 | 76 | // Easing 77 | // arrayOK: false 78 | // default: cubic-in-out 79 | // type: enumerated 80 | // The easing function used for the transition 81 | // .schema.animation.transition.easing 82 | Easing AnimationTransitionEasing `json:"easing,omitempty"` 83 | 84 | // Ordering 85 | // arrayOK: false 86 | // default: layout first 87 | // type: enumerated 88 | // Determines whether the figure's layout or traces smoothly transitions during updates that make both traces and layout change. 89 | // .schema.animation.transition.ordering 90 | Ordering AnimationTransitionOrdering `json:"ordering,omitempty"` 91 | } 92 | 93 | // AnimationDirection The direction in which to play the frames triggered by the animation call 94 | // .schema.animation.direction 95 | type AnimationDirection string 96 | 97 | const ( 98 | AnimationDirectionForward AnimationDirection = "forward" 99 | AnimationDirectionReverse AnimationDirection = "reverse" 100 | ) 101 | 102 | // AnimationMode Describes how a new animate call interacts with currently-running animations. If `immediate`, current animations are interrupted and the new animation is started. If `next`, the current frame is allowed to complete, after which the new animation is started. If `afterall` all existing frames are animated to completion before the new animation is started. 103 | // .schema.animation.mode 104 | type AnimationMode string 105 | 106 | const ( 107 | AnimationModeImmediate AnimationMode = "immediate" 108 | AnimationModeNext AnimationMode = "next" 109 | AnimationModeAfterall AnimationMode = "afterall" 110 | ) 111 | 112 | // AnimationTransitionEasing The easing function used for the transition 113 | // .schema.animation.transition.easing 114 | type AnimationTransitionEasing string 115 | 116 | const ( 117 | AnimationTransitionEasingLinear AnimationTransitionEasing = "linear" 118 | AnimationTransitionEasingQuad AnimationTransitionEasing = "quad" 119 | AnimationTransitionEasingCubic AnimationTransitionEasing = "cubic" 120 | AnimationTransitionEasingSin AnimationTransitionEasing = "sin" 121 | AnimationTransitionEasingExp AnimationTransitionEasing = "exp" 122 | AnimationTransitionEasingCircle AnimationTransitionEasing = "circle" 123 | AnimationTransitionEasingElastic AnimationTransitionEasing = "elastic" 124 | AnimationTransitionEasingBack AnimationTransitionEasing = "back" 125 | AnimationTransitionEasingBounce AnimationTransitionEasing = "bounce" 126 | AnimationTransitionEasingLinearIn AnimationTransitionEasing = "linear-in" 127 | AnimationTransitionEasingQuadIn AnimationTransitionEasing = "quad-in" 128 | AnimationTransitionEasingCubicIn AnimationTransitionEasing = "cubic-in" 129 | AnimationTransitionEasingSinIn AnimationTransitionEasing = "sin-in" 130 | AnimationTransitionEasingExpIn AnimationTransitionEasing = "exp-in" 131 | AnimationTransitionEasingCircleIn AnimationTransitionEasing = "circle-in" 132 | AnimationTransitionEasingElasticIn AnimationTransitionEasing = "elastic-in" 133 | AnimationTransitionEasingBackIn AnimationTransitionEasing = "back-in" 134 | AnimationTransitionEasingBounceIn AnimationTransitionEasing = "bounce-in" 135 | AnimationTransitionEasingLinearOut AnimationTransitionEasing = "linear-out" 136 | AnimationTransitionEasingQuadOut AnimationTransitionEasing = "quad-out" 137 | AnimationTransitionEasingCubicOut AnimationTransitionEasing = "cubic-out" 138 | AnimationTransitionEasingSinOut AnimationTransitionEasing = "sin-out" 139 | AnimationTransitionEasingExpOut AnimationTransitionEasing = "exp-out" 140 | AnimationTransitionEasingCircleOut AnimationTransitionEasing = "circle-out" 141 | AnimationTransitionEasingElasticOut AnimationTransitionEasing = "elastic-out" 142 | AnimationTransitionEasingBackOut AnimationTransitionEasing = "back-out" 143 | AnimationTransitionEasingBounceOut AnimationTransitionEasing = "bounce-out" 144 | AnimationTransitionEasingLinearInOut AnimationTransitionEasing = "linear-in-out" 145 | AnimationTransitionEasingQuadInOut AnimationTransitionEasing = "quad-in-out" 146 | AnimationTransitionEasingCubicInOut AnimationTransitionEasing = "cubic-in-out" 147 | AnimationTransitionEasingSinInOut AnimationTransitionEasing = "sin-in-out" 148 | AnimationTransitionEasingExpInOut AnimationTransitionEasing = "exp-in-out" 149 | AnimationTransitionEasingCircleInOut AnimationTransitionEasing = "circle-in-out" 150 | AnimationTransitionEasingElasticInOut AnimationTransitionEasing = "elastic-in-out" 151 | AnimationTransitionEasingBackInOut AnimationTransitionEasing = "back-in-out" 152 | AnimationTransitionEasingBounceInOut AnimationTransitionEasing = "bounce-in-out" 153 | ) 154 | 155 | // AnimationTransitionOrdering Determines whether the figure's layout or traces smoothly transitions during updates that make both traces and layout change. 156 | // .schema.animation.transition.ordering 157 | type AnimationTransitionOrdering string 158 | 159 | const ( 160 | AnimationTransitionOrderingLayoutFirst AnimationTransitionOrdering = "layout first" 161 | AnimationTransitionOrderingTracesFirst AnimationTransitionOrdering = "traces first" 162 | ) 163 | -------------------------------------------------------------------------------- /generated/v2.29.1/graph_objects/animation_gen.go: -------------------------------------------------------------------------------- 1 | package grob 2 | 3 | // Code generated by go-plotly/generator. DO NOT EDIT. 4 | 5 | import ( 6 | "github.com/MetalBlueberry/go-plotly/pkg/types" 7 | ) 8 | 9 | // Animation Plot animation options 10 | type Animation struct { 11 | 12 | // Direction 13 | // arrayOK: false 14 | // default: forward 15 | // type: enumerated 16 | // The direction in which to play the frames triggered by the animation call 17 | // .schema.animation.direction 18 | Direction AnimationDirection `json:"direction,omitempty"` 19 | 20 | // Frame 21 | // arrayOK: false 22 | // role: Object 23 | // .schema.animation.frame 24 | Frame *AnimationFrame `json:"frame,omitempty"` 25 | 26 | // Fromcurrent 27 | // arrayOK: false 28 | // type: boolean 29 | // Play frames starting at the current frame instead of the beginning. 30 | // .schema.animation.fromcurrent 31 | Fromcurrent types.BoolType `json:"fromcurrent,omitempty"` 32 | 33 | // Mode 34 | // arrayOK: false 35 | // default: afterall 36 | // type: enumerated 37 | // Describes how a new animate call interacts with currently-running animations. If `immediate`, current animations are interrupted and the new animation is started. If `next`, the current frame is allowed to complete, after which the new animation is started. If `afterall` all existing frames are animated to completion before the new animation is started. 38 | // .schema.animation.mode 39 | Mode AnimationMode `json:"mode,omitempty"` 40 | 41 | // Transition 42 | // arrayOK: false 43 | // role: Object 44 | // .schema.animation.transition 45 | Transition *AnimationTransition `json:"transition,omitempty"` 46 | } 47 | 48 | // AnimationFrame 49 | type AnimationFrame struct { 50 | 51 | // Duration 52 | // arrayOK: false 53 | // type: number 54 | // The duration in milliseconds of each frame. If greater than the frame duration, it will be limited to the frame duration. 55 | // .schema.animation.frame.duration 56 | Duration types.NumberType `json:"duration,omitempty"` 57 | 58 | // Redraw 59 | // arrayOK: false 60 | // type: boolean 61 | // Redraw the plot at completion of the transition. This is desirable for transitions that include properties that cannot be transitioned, but may significantly slow down updates that do not require a full redraw of the plot 62 | // .schema.animation.frame.redraw 63 | Redraw types.BoolType `json:"redraw,omitempty"` 64 | } 65 | 66 | // AnimationTransition 67 | type AnimationTransition struct { 68 | 69 | // Duration 70 | // arrayOK: false 71 | // type: number 72 | // The duration of the transition, in milliseconds. If equal to zero, updates are synchronous. 73 | // .schema.animation.transition.duration 74 | Duration types.NumberType `json:"duration,omitempty"` 75 | 76 | // Easing 77 | // arrayOK: false 78 | // default: cubic-in-out 79 | // type: enumerated 80 | // The easing function used for the transition 81 | // .schema.animation.transition.easing 82 | Easing AnimationTransitionEasing `json:"easing,omitempty"` 83 | 84 | // Ordering 85 | // arrayOK: false 86 | // default: layout first 87 | // type: enumerated 88 | // Determines whether the figure's layout or traces smoothly transitions during updates that make both traces and layout change. 89 | // .schema.animation.transition.ordering 90 | Ordering AnimationTransitionOrdering `json:"ordering,omitempty"` 91 | } 92 | 93 | // AnimationDirection The direction in which to play the frames triggered by the animation call 94 | // .schema.animation.direction 95 | type AnimationDirection string 96 | 97 | const ( 98 | AnimationDirectionForward AnimationDirection = "forward" 99 | AnimationDirectionReverse AnimationDirection = "reverse" 100 | ) 101 | 102 | // AnimationMode Describes how a new animate call interacts with currently-running animations. If `immediate`, current animations are interrupted and the new animation is started. If `next`, the current frame is allowed to complete, after which the new animation is started. If `afterall` all existing frames are animated to completion before the new animation is started. 103 | // .schema.animation.mode 104 | type AnimationMode string 105 | 106 | const ( 107 | AnimationModeImmediate AnimationMode = "immediate" 108 | AnimationModeNext AnimationMode = "next" 109 | AnimationModeAfterall AnimationMode = "afterall" 110 | ) 111 | 112 | // AnimationTransitionEasing The easing function used for the transition 113 | // .schema.animation.transition.easing 114 | type AnimationTransitionEasing string 115 | 116 | const ( 117 | AnimationTransitionEasingLinear AnimationTransitionEasing = "linear" 118 | AnimationTransitionEasingQuad AnimationTransitionEasing = "quad" 119 | AnimationTransitionEasingCubic AnimationTransitionEasing = "cubic" 120 | AnimationTransitionEasingSin AnimationTransitionEasing = "sin" 121 | AnimationTransitionEasingExp AnimationTransitionEasing = "exp" 122 | AnimationTransitionEasingCircle AnimationTransitionEasing = "circle" 123 | AnimationTransitionEasingElastic AnimationTransitionEasing = "elastic" 124 | AnimationTransitionEasingBack AnimationTransitionEasing = "back" 125 | AnimationTransitionEasingBounce AnimationTransitionEasing = "bounce" 126 | AnimationTransitionEasingLinearIn AnimationTransitionEasing = "linear-in" 127 | AnimationTransitionEasingQuadIn AnimationTransitionEasing = "quad-in" 128 | AnimationTransitionEasingCubicIn AnimationTransitionEasing = "cubic-in" 129 | AnimationTransitionEasingSinIn AnimationTransitionEasing = "sin-in" 130 | AnimationTransitionEasingExpIn AnimationTransitionEasing = "exp-in" 131 | AnimationTransitionEasingCircleIn AnimationTransitionEasing = "circle-in" 132 | AnimationTransitionEasingElasticIn AnimationTransitionEasing = "elastic-in" 133 | AnimationTransitionEasingBackIn AnimationTransitionEasing = "back-in" 134 | AnimationTransitionEasingBounceIn AnimationTransitionEasing = "bounce-in" 135 | AnimationTransitionEasingLinearOut AnimationTransitionEasing = "linear-out" 136 | AnimationTransitionEasingQuadOut AnimationTransitionEasing = "quad-out" 137 | AnimationTransitionEasingCubicOut AnimationTransitionEasing = "cubic-out" 138 | AnimationTransitionEasingSinOut AnimationTransitionEasing = "sin-out" 139 | AnimationTransitionEasingExpOut AnimationTransitionEasing = "exp-out" 140 | AnimationTransitionEasingCircleOut AnimationTransitionEasing = "circle-out" 141 | AnimationTransitionEasingElasticOut AnimationTransitionEasing = "elastic-out" 142 | AnimationTransitionEasingBackOut AnimationTransitionEasing = "back-out" 143 | AnimationTransitionEasingBounceOut AnimationTransitionEasing = "bounce-out" 144 | AnimationTransitionEasingLinearInOut AnimationTransitionEasing = "linear-in-out" 145 | AnimationTransitionEasingQuadInOut AnimationTransitionEasing = "quad-in-out" 146 | AnimationTransitionEasingCubicInOut AnimationTransitionEasing = "cubic-in-out" 147 | AnimationTransitionEasingSinInOut AnimationTransitionEasing = "sin-in-out" 148 | AnimationTransitionEasingExpInOut AnimationTransitionEasing = "exp-in-out" 149 | AnimationTransitionEasingCircleInOut AnimationTransitionEasing = "circle-in-out" 150 | AnimationTransitionEasingElasticInOut AnimationTransitionEasing = "elastic-in-out" 151 | AnimationTransitionEasingBackInOut AnimationTransitionEasing = "back-in-out" 152 | AnimationTransitionEasingBounceInOut AnimationTransitionEasing = "bounce-in-out" 153 | ) 154 | 155 | // AnimationTransitionOrdering Determines whether the figure's layout or traces smoothly transitions during updates that make both traces and layout change. 156 | // .schema.animation.transition.ordering 157 | type AnimationTransitionOrdering string 158 | 159 | const ( 160 | AnimationTransitionOrderingLayoutFirst AnimationTransitionOrdering = "layout first" 161 | AnimationTransitionOrderingTracesFirst AnimationTransitionOrdering = "traces first" 162 | ) 163 | -------------------------------------------------------------------------------- /generated/v2.31.1/graph_objects/animation_gen.go: -------------------------------------------------------------------------------- 1 | package grob 2 | 3 | // Code generated by go-plotly/generator. DO NOT EDIT. 4 | 5 | import ( 6 | "github.com/MetalBlueberry/go-plotly/pkg/types" 7 | ) 8 | 9 | // Animation Plot animation options 10 | type Animation struct { 11 | 12 | // Direction 13 | // arrayOK: false 14 | // default: forward 15 | // type: enumerated 16 | // The direction in which to play the frames triggered by the animation call 17 | // .schema.animation.direction 18 | Direction AnimationDirection `json:"direction,omitempty"` 19 | 20 | // Frame 21 | // arrayOK: false 22 | // role: Object 23 | // .schema.animation.frame 24 | Frame *AnimationFrame `json:"frame,omitempty"` 25 | 26 | // Fromcurrent 27 | // arrayOK: false 28 | // type: boolean 29 | // Play frames starting at the current frame instead of the beginning. 30 | // .schema.animation.fromcurrent 31 | Fromcurrent types.BoolType `json:"fromcurrent,omitempty"` 32 | 33 | // Mode 34 | // arrayOK: false 35 | // default: afterall 36 | // type: enumerated 37 | // Describes how a new animate call interacts with currently-running animations. If `immediate`, current animations are interrupted and the new animation is started. If `next`, the current frame is allowed to complete, after which the new animation is started. If `afterall` all existing frames are animated to completion before the new animation is started. 38 | // .schema.animation.mode 39 | Mode AnimationMode `json:"mode,omitempty"` 40 | 41 | // Transition 42 | // arrayOK: false 43 | // role: Object 44 | // .schema.animation.transition 45 | Transition *AnimationTransition `json:"transition,omitempty"` 46 | } 47 | 48 | // AnimationFrame 49 | type AnimationFrame struct { 50 | 51 | // Duration 52 | // arrayOK: false 53 | // type: number 54 | // The duration in milliseconds of each frame. If greater than the frame duration, it will be limited to the frame duration. 55 | // .schema.animation.frame.duration 56 | Duration types.NumberType `json:"duration,omitempty"` 57 | 58 | // Redraw 59 | // arrayOK: false 60 | // type: boolean 61 | // Redraw the plot at completion of the transition. This is desirable for transitions that include properties that cannot be transitioned, but may significantly slow down updates that do not require a full redraw of the plot 62 | // .schema.animation.frame.redraw 63 | Redraw types.BoolType `json:"redraw,omitempty"` 64 | } 65 | 66 | // AnimationTransition 67 | type AnimationTransition struct { 68 | 69 | // Duration 70 | // arrayOK: false 71 | // type: number 72 | // The duration of the transition, in milliseconds. If equal to zero, updates are synchronous. 73 | // .schema.animation.transition.duration 74 | Duration types.NumberType `json:"duration,omitempty"` 75 | 76 | // Easing 77 | // arrayOK: false 78 | // default: cubic-in-out 79 | // type: enumerated 80 | // The easing function used for the transition 81 | // .schema.animation.transition.easing 82 | Easing AnimationTransitionEasing `json:"easing,omitempty"` 83 | 84 | // Ordering 85 | // arrayOK: false 86 | // default: layout first 87 | // type: enumerated 88 | // Determines whether the figure's layout or traces smoothly transitions during updates that make both traces and layout change. 89 | // .schema.animation.transition.ordering 90 | Ordering AnimationTransitionOrdering `json:"ordering,omitempty"` 91 | } 92 | 93 | // AnimationDirection The direction in which to play the frames triggered by the animation call 94 | // .schema.animation.direction 95 | type AnimationDirection string 96 | 97 | const ( 98 | AnimationDirectionForward AnimationDirection = "forward" 99 | AnimationDirectionReverse AnimationDirection = "reverse" 100 | ) 101 | 102 | // AnimationMode Describes how a new animate call interacts with currently-running animations. If `immediate`, current animations are interrupted and the new animation is started. If `next`, the current frame is allowed to complete, after which the new animation is started. If `afterall` all existing frames are animated to completion before the new animation is started. 103 | // .schema.animation.mode 104 | type AnimationMode string 105 | 106 | const ( 107 | AnimationModeImmediate AnimationMode = "immediate" 108 | AnimationModeNext AnimationMode = "next" 109 | AnimationModeAfterall AnimationMode = "afterall" 110 | ) 111 | 112 | // AnimationTransitionEasing The easing function used for the transition 113 | // .schema.animation.transition.easing 114 | type AnimationTransitionEasing string 115 | 116 | const ( 117 | AnimationTransitionEasingLinear AnimationTransitionEasing = "linear" 118 | AnimationTransitionEasingQuad AnimationTransitionEasing = "quad" 119 | AnimationTransitionEasingCubic AnimationTransitionEasing = "cubic" 120 | AnimationTransitionEasingSin AnimationTransitionEasing = "sin" 121 | AnimationTransitionEasingExp AnimationTransitionEasing = "exp" 122 | AnimationTransitionEasingCircle AnimationTransitionEasing = "circle" 123 | AnimationTransitionEasingElastic AnimationTransitionEasing = "elastic" 124 | AnimationTransitionEasingBack AnimationTransitionEasing = "back" 125 | AnimationTransitionEasingBounce AnimationTransitionEasing = "bounce" 126 | AnimationTransitionEasingLinearIn AnimationTransitionEasing = "linear-in" 127 | AnimationTransitionEasingQuadIn AnimationTransitionEasing = "quad-in" 128 | AnimationTransitionEasingCubicIn AnimationTransitionEasing = "cubic-in" 129 | AnimationTransitionEasingSinIn AnimationTransitionEasing = "sin-in" 130 | AnimationTransitionEasingExpIn AnimationTransitionEasing = "exp-in" 131 | AnimationTransitionEasingCircleIn AnimationTransitionEasing = "circle-in" 132 | AnimationTransitionEasingElasticIn AnimationTransitionEasing = "elastic-in" 133 | AnimationTransitionEasingBackIn AnimationTransitionEasing = "back-in" 134 | AnimationTransitionEasingBounceIn AnimationTransitionEasing = "bounce-in" 135 | AnimationTransitionEasingLinearOut AnimationTransitionEasing = "linear-out" 136 | AnimationTransitionEasingQuadOut AnimationTransitionEasing = "quad-out" 137 | AnimationTransitionEasingCubicOut AnimationTransitionEasing = "cubic-out" 138 | AnimationTransitionEasingSinOut AnimationTransitionEasing = "sin-out" 139 | AnimationTransitionEasingExpOut AnimationTransitionEasing = "exp-out" 140 | AnimationTransitionEasingCircleOut AnimationTransitionEasing = "circle-out" 141 | AnimationTransitionEasingElasticOut AnimationTransitionEasing = "elastic-out" 142 | AnimationTransitionEasingBackOut AnimationTransitionEasing = "back-out" 143 | AnimationTransitionEasingBounceOut AnimationTransitionEasing = "bounce-out" 144 | AnimationTransitionEasingLinearInOut AnimationTransitionEasing = "linear-in-out" 145 | AnimationTransitionEasingQuadInOut AnimationTransitionEasing = "quad-in-out" 146 | AnimationTransitionEasingCubicInOut AnimationTransitionEasing = "cubic-in-out" 147 | AnimationTransitionEasingSinInOut AnimationTransitionEasing = "sin-in-out" 148 | AnimationTransitionEasingExpInOut AnimationTransitionEasing = "exp-in-out" 149 | AnimationTransitionEasingCircleInOut AnimationTransitionEasing = "circle-in-out" 150 | AnimationTransitionEasingElasticInOut AnimationTransitionEasing = "elastic-in-out" 151 | AnimationTransitionEasingBackInOut AnimationTransitionEasing = "back-in-out" 152 | AnimationTransitionEasingBounceInOut AnimationTransitionEasing = "bounce-in-out" 153 | ) 154 | 155 | // AnimationTransitionOrdering Determines whether the figure's layout or traces smoothly transitions during updates that make both traces and layout change. 156 | // .schema.animation.transition.ordering 157 | type AnimationTransitionOrdering string 158 | 159 | const ( 160 | AnimationTransitionOrderingLayoutFirst AnimationTransitionOrdering = "layout first" 161 | AnimationTransitionOrderingTracesFirst AnimationTransitionOrdering = "traces first" 162 | ) 163 | -------------------------------------------------------------------------------- /generated/v2.34.0/graph_objects/animation_gen.go: -------------------------------------------------------------------------------- 1 | package grob 2 | 3 | // Code generated by go-plotly/generator. DO NOT EDIT. 4 | 5 | import ( 6 | "github.com/MetalBlueberry/go-plotly/pkg/types" 7 | ) 8 | 9 | // Animation Plot animation options 10 | type Animation struct { 11 | 12 | // Direction 13 | // arrayOK: false 14 | // default: forward 15 | // type: enumerated 16 | // The direction in which to play the frames triggered by the animation call 17 | // .schema.animation.direction 18 | Direction AnimationDirection `json:"direction,omitempty"` 19 | 20 | // Frame 21 | // arrayOK: false 22 | // role: Object 23 | // .schema.animation.frame 24 | Frame *AnimationFrame `json:"frame,omitempty"` 25 | 26 | // Fromcurrent 27 | // arrayOK: false 28 | // type: boolean 29 | // Play frames starting at the current frame instead of the beginning. 30 | // .schema.animation.fromcurrent 31 | Fromcurrent types.BoolType `json:"fromcurrent,omitempty"` 32 | 33 | // Mode 34 | // arrayOK: false 35 | // default: afterall 36 | // type: enumerated 37 | // Describes how a new animate call interacts with currently-running animations. If `immediate`, current animations are interrupted and the new animation is started. If `next`, the current frame is allowed to complete, after which the new animation is started. If `afterall` all existing frames are animated to completion before the new animation is started. 38 | // .schema.animation.mode 39 | Mode AnimationMode `json:"mode,omitempty"` 40 | 41 | // Transition 42 | // arrayOK: false 43 | // role: Object 44 | // .schema.animation.transition 45 | Transition *AnimationTransition `json:"transition,omitempty"` 46 | } 47 | 48 | // AnimationFrame 49 | type AnimationFrame struct { 50 | 51 | // Duration 52 | // arrayOK: false 53 | // type: number 54 | // The duration in milliseconds of each frame. If greater than the frame duration, it will be limited to the frame duration. 55 | // .schema.animation.frame.duration 56 | Duration types.NumberType `json:"duration,omitempty"` 57 | 58 | // Redraw 59 | // arrayOK: false 60 | // type: boolean 61 | // Redraw the plot at completion of the transition. This is desirable for transitions that include properties that cannot be transitioned, but may significantly slow down updates that do not require a full redraw of the plot 62 | // .schema.animation.frame.redraw 63 | Redraw types.BoolType `json:"redraw,omitempty"` 64 | } 65 | 66 | // AnimationTransition 67 | type AnimationTransition struct { 68 | 69 | // Duration 70 | // arrayOK: false 71 | // type: number 72 | // The duration of the transition, in milliseconds. If equal to zero, updates are synchronous. 73 | // .schema.animation.transition.duration 74 | Duration types.NumberType `json:"duration,omitempty"` 75 | 76 | // Easing 77 | // arrayOK: false 78 | // default: cubic-in-out 79 | // type: enumerated 80 | // The easing function used for the transition 81 | // .schema.animation.transition.easing 82 | Easing AnimationTransitionEasing `json:"easing,omitempty"` 83 | 84 | // Ordering 85 | // arrayOK: false 86 | // default: layout first 87 | // type: enumerated 88 | // Determines whether the figure's layout or traces smoothly transitions during updates that make both traces and layout change. 89 | // .schema.animation.transition.ordering 90 | Ordering AnimationTransitionOrdering `json:"ordering,omitempty"` 91 | } 92 | 93 | // AnimationDirection The direction in which to play the frames triggered by the animation call 94 | // .schema.animation.direction 95 | type AnimationDirection string 96 | 97 | const ( 98 | AnimationDirectionForward AnimationDirection = "forward" 99 | AnimationDirectionReverse AnimationDirection = "reverse" 100 | ) 101 | 102 | // AnimationMode Describes how a new animate call interacts with currently-running animations. If `immediate`, current animations are interrupted and the new animation is started. If `next`, the current frame is allowed to complete, after which the new animation is started. If `afterall` all existing frames are animated to completion before the new animation is started. 103 | // .schema.animation.mode 104 | type AnimationMode string 105 | 106 | const ( 107 | AnimationModeImmediate AnimationMode = "immediate" 108 | AnimationModeNext AnimationMode = "next" 109 | AnimationModeAfterall AnimationMode = "afterall" 110 | ) 111 | 112 | // AnimationTransitionEasing The easing function used for the transition 113 | // .schema.animation.transition.easing 114 | type AnimationTransitionEasing string 115 | 116 | const ( 117 | AnimationTransitionEasingLinear AnimationTransitionEasing = "linear" 118 | AnimationTransitionEasingQuad AnimationTransitionEasing = "quad" 119 | AnimationTransitionEasingCubic AnimationTransitionEasing = "cubic" 120 | AnimationTransitionEasingSin AnimationTransitionEasing = "sin" 121 | AnimationTransitionEasingExp AnimationTransitionEasing = "exp" 122 | AnimationTransitionEasingCircle AnimationTransitionEasing = "circle" 123 | AnimationTransitionEasingElastic AnimationTransitionEasing = "elastic" 124 | AnimationTransitionEasingBack AnimationTransitionEasing = "back" 125 | AnimationTransitionEasingBounce AnimationTransitionEasing = "bounce" 126 | AnimationTransitionEasingLinearIn AnimationTransitionEasing = "linear-in" 127 | AnimationTransitionEasingQuadIn AnimationTransitionEasing = "quad-in" 128 | AnimationTransitionEasingCubicIn AnimationTransitionEasing = "cubic-in" 129 | AnimationTransitionEasingSinIn AnimationTransitionEasing = "sin-in" 130 | AnimationTransitionEasingExpIn AnimationTransitionEasing = "exp-in" 131 | AnimationTransitionEasingCircleIn AnimationTransitionEasing = "circle-in" 132 | AnimationTransitionEasingElasticIn AnimationTransitionEasing = "elastic-in" 133 | AnimationTransitionEasingBackIn AnimationTransitionEasing = "back-in" 134 | AnimationTransitionEasingBounceIn AnimationTransitionEasing = "bounce-in" 135 | AnimationTransitionEasingLinearOut AnimationTransitionEasing = "linear-out" 136 | AnimationTransitionEasingQuadOut AnimationTransitionEasing = "quad-out" 137 | AnimationTransitionEasingCubicOut AnimationTransitionEasing = "cubic-out" 138 | AnimationTransitionEasingSinOut AnimationTransitionEasing = "sin-out" 139 | AnimationTransitionEasingExpOut AnimationTransitionEasing = "exp-out" 140 | AnimationTransitionEasingCircleOut AnimationTransitionEasing = "circle-out" 141 | AnimationTransitionEasingElasticOut AnimationTransitionEasing = "elastic-out" 142 | AnimationTransitionEasingBackOut AnimationTransitionEasing = "back-out" 143 | AnimationTransitionEasingBounceOut AnimationTransitionEasing = "bounce-out" 144 | AnimationTransitionEasingLinearInOut AnimationTransitionEasing = "linear-in-out" 145 | AnimationTransitionEasingQuadInOut AnimationTransitionEasing = "quad-in-out" 146 | AnimationTransitionEasingCubicInOut AnimationTransitionEasing = "cubic-in-out" 147 | AnimationTransitionEasingSinInOut AnimationTransitionEasing = "sin-in-out" 148 | AnimationTransitionEasingExpInOut AnimationTransitionEasing = "exp-in-out" 149 | AnimationTransitionEasingCircleInOut AnimationTransitionEasing = "circle-in-out" 150 | AnimationTransitionEasingElasticInOut AnimationTransitionEasing = "elastic-in-out" 151 | AnimationTransitionEasingBackInOut AnimationTransitionEasing = "back-in-out" 152 | AnimationTransitionEasingBounceInOut AnimationTransitionEasing = "bounce-in-out" 153 | ) 154 | 155 | // AnimationTransitionOrdering Determines whether the figure's layout or traces smoothly transitions during updates that make both traces and layout change. 156 | // .schema.animation.transition.ordering 157 | type AnimationTransitionOrdering string 158 | 159 | const ( 160 | AnimationTransitionOrderingLayoutFirst AnimationTransitionOrdering = "layout first" 161 | AnimationTransitionOrderingTracesFirst AnimationTransitionOrdering = "traces first" 162 | ) 163 | -------------------------------------------------------------------------------- /examples/go.sum: -------------------------------------------------------------------------------- 1 | dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= 2 | gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= 3 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= 4 | github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= 5 | github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= 6 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 7 | github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= 8 | github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= 9 | github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g= 10 | github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks= 11 | github.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= 12 | github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmnUIzUY= 13 | github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= 14 | github.com/go-gota/gota v0.12.0 h1:T5BDg1hTf5fZ/CO+T/N0E+DDqUhvoKBl+UVckgcAAQg= 15 | github.com/go-gota/gota v0.12.0/go.mod h1:UT+NsWpZC/FhaOyWb9Hui0jXg0Iq8e/YugZHTbyW/34= 16 | github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= 17 | github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= 18 | github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= 19 | github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 20 | github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= 21 | github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= 22 | github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= 23 | github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= 24 | github.com/onsi/gomega v1.33.0 h1:snPCflnZrpMsy94p4lXVEkHo12lmPnc3vY5XBbreexE= 25 | github.com/onsi/gomega v1.33.0/go.mod h1:+925n5YtiFsLzzafLUHzVMBpvvRAzrydIBiSIxjX3wY= 26 | github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= 27 | github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= 28 | github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= 29 | github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= 30 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 31 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 32 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 33 | github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= 34 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 35 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 36 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 37 | golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 38 | golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 39 | golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 40 | golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 41 | golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgnvsSFpcKLM5xXVWnvZS97DWHgE= 42 | golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 h1:kx6Ds3MlpiUHKj7syVnbp57++8WpuKPcR5yjLBjvLEA= 43 | golang.org/x/exp v0.0.0-20240823005443-9b4947da3948/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ= 44 | golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= 45 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= 46 | golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 47 | golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 48 | golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 49 | golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 50 | golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 51 | golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 52 | golang.org/x/image v0.0.0-20210216034530-4410531fe030/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 53 | golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= 54 | golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= 55 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 56 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 57 | golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= 58 | golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= 59 | golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= 60 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 61 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 62 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 63 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 64 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 65 | golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 66 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 67 | golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 68 | golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= 69 | golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 70 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 71 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 72 | golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 73 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 74 | golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= 75 | golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= 76 | golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 77 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 78 | golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 79 | golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 80 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 81 | gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= 82 | gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= 83 | gonum.org/v1/gonum v0.9.1/go.mod h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0= 84 | gonum.org/v1/gonum v0.15.0 h1:2lYxjRbTYyxkJxlhC+LvJIx3SsANPdRybu1tGj9/OrQ= 85 | gonum.org/v1/gonum v0.15.0/go.mod h1:xzZVBJBtS+Mz4q0Yl2LJTk+OxOg4jiXZ7qBoM0uISGo= 86 | gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= 87 | gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= 88 | gonum.org/v1/plot v0.9.0/go.mod h1:3Pcqqmp6RHvJI72kgb8fThyUnav364FOsdDo2aGW5lY= 89 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 90 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 91 | rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= 92 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Go Report Card](https://goreportcard.com/badge/github.com/MetalBlueberry/go-plotly)](https://goreportcard.com/report/github.com/MetalBlueberry/go-plotly) 2 | [![godoc](https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white)](https://pkg.go.dev/mod/github.com/MetalBlueberry/go-plotly?tab=overview) 3 | 4 | # go-plotly 5 | 6 | Inspired by [Python Plotly](https://plotly.com/python/creating-and-updating-figures/) 7 | 8 | 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. 9 | 10 | In the context of the plotly.js library, a figure is specified by a declarative JSON data structure. 11 | 12 | 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. 13 | 14 | > Yes, that text is a copy paste from Python description. 15 | 16 | The good thing about this package is that it's **automatically generated** based on the schema described [here](https://plotly.com/chart-studio-help/json-chart-schema/) so It will be easy to keep it up to date or to generate different versions of it. 17 | 18 | > 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.** 19 | 20 | ## Example 21 | 22 | ```go 23 | package main 24 | 25 | import ( 26 | grob "github.com/MetalBlueberry/go-plotly/generated/v2.31.1/graph_objects" 27 | "github.com/MetalBlueberry/go-plotly/pkg/offline" 28 | "github.com/MetalBlueberry/go-plotly/pkg/types" 29 | ) 30 | 31 | func main() { 32 | /* 33 | fig = dict({ 34 | "data": [{"type": "bar", 35 | "x": [1, 2, 3], 36 | "y": [1, 3, 2]}], 37 | "layout": {"title": {"text": "A Figure Specified By Python Dictionary"}} 38 | }) 39 | */ 40 | fig := &grob.Fig{ 41 | Data: []types.Trace{ 42 | &grob.Bar{ 43 | X: types.DataArray([]float64{1, 2, 3}), 44 | Y: types.DataArray([]float64{1, 2, 3}), 45 | }, 46 | }, 47 | Layout: &grob.Layout{ 48 | Title: &grob.LayoutTitle{ 49 | Text: "A Figure Specified By Go Struct", 50 | }, 51 | }, 52 | } 53 | 54 | offline.Show(fig) 55 | } 56 | ``` 57 | 58 | This will open your browser and display the following plot 59 | 60 | ![Bar](./examples/bar/Bar.png) 61 | 62 | And that's it. 63 | 64 | See the [examples dir](./examples/) for more examples. 65 | 66 | ## Structure 67 | 68 | > Auto completion is your best friend on this package. It will get the right type (almost) every time! 69 | 70 | To keep the plotly.js independent of the version of this package, the generated directory contains a directory per plotly version supported. The plan is to support all minor releases and update as patches are released. But because I can not do it myself, I will accept PRs if anyone wants any specific version. 71 | 72 | Updates to the package will affect all schemas. This will be done as we improve the generator. 73 | 74 | 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](https://plotly.com/python/). 75 | 76 | Types that can have single values or lists, are defined as `types.ArrayOK` types. You can use the helper methods `types.ArrayOKArray` and `types.ArrayOKValue` depending on which value you want to set. 77 | 78 | Basic types have been defined to follow plotly specs. Than means you will find types for strings, bools, numbers and integers. Those types are basically pointers to the equivalent value in Go, as plotly supports null values on any of those fields. To make it easier to work with the library, you can find utility functions to build such types. For example. `types.N()` will create a `types.Number` value from a `float64` value. `types.NS()` attempts to parse a string as a number to follow what plotly specifications says about Number type. `types.NA()` converts `[]float64` into `[]types.Number`. Equivalent functions can be found for other types. 79 | 80 | 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`. 81 | 82 | 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. 83 | 84 | ## Progress 85 | 86 | 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. 87 | 88 | Currently, most common use cases should be already covered. Feel free to create an issue if you find something that it's not working. 89 | 90 | - [x] Basic types 91 | - [x] Traces 92 | - [x] Layout 93 | - [x] Config 94 | - [x] Animation 95 | - [x] Frames 96 | - [ ] Type definitions 97 | - [ ] defs valobjects 98 | - [ ] angle **needs validations** 99 | - [x] any 100 | - [x] boolean 101 | - [x] color 102 | - [x] colorlist 103 | - [x] colorscale 104 | - [x] data_array 105 | - [x] enumerated 106 | - [x] flaglist 107 | - [ ] info_array 108 | - [x] integer 109 | - [x] number 110 | - [x] string 111 | - [ ] subplotid 112 | - [ ] defs_modifier 113 | - [x] arrayOK 114 | - [ ] min/max validations 115 | - [x] dflt **This is not needed in the output, as plotly will do it. But it would be nice to have a method to fetch it** 116 | - [ ] noBlank validation 117 | - [ ] strict validation 118 | - [ ] values list validation 119 | 120 | ## FAQ 121 | 122 | ### Is this cross platform? 123 | 124 | YES* 125 | 126 | *The output of the package is usually a webpage that renders the figure using plotly.js. That means it will work on almost any browser. For further details, check plotly.js docs 127 | 128 | ### Why this library and not go-echarts 129 | 130 | go-echarts is an amazing library! It is the exact same idea as this library but for Apache ECharts. 131 | 132 | To make a meaningful choice, you should compare plotly.js features ve ECharts, 133 | 134 | ### Why this library and not gonum/plot 135 | 136 | gonum/plot is focus on building static images while go-plotly has al the interactive features plotly.js provides. 137 | 138 | If you want interactive dashboards, this library is way better. 139 | 140 | ### What's the meaning of "grob"? 141 | 142 | 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. 143 | 144 | ### What are the usecases? 145 | 146 | 1. Quickly visualize data using only Go 147 | 148 | 2. Send plotly figures to the frontend ready to be drawn, avoiding possible mistakes in JS thanks to types! 149 | 150 | 3. Generate an awesome dynamic plot in a local file with offline package. 151 | 152 | 4. I don't know, just do something awesome and let me know it. 153 | 154 | ### Go Plotly Update to any json schema version 155 | 156 | [Example PR](https://github.com/MetalBlueberry/go-plotly/pull/29) 157 | 158 | #### Update the config to add a new version 159 | 160 | 1. To add a new version, add a new entry in: [schemas.yaml](schemas.yaml) 161 | > The documentation for each field can be found in [schema.go](generator%2Fschema.go) 162 | 163 | Example entry: 164 | 165 | ```yaml 166 | - Name: Plotly 2.31.1 167 | Tag: v2.31.1 168 | URL: https://raw.githubusercontent.com/plotly/plotly.js/v2.31.1/test/plot-schema.json 169 | # relative to the project root. 170 | Path: schemas/v2.31.1/plot-schema.json 171 | Generated: generated/v2.31.1 172 | CDN: https://cdn.plot.ly/plotly-2.31.1.min.js 173 | ``` 174 | 175 | #### Run download and regeneration 176 | 177 | 1. Download all the schemas: 178 | 179 | ```shell 180 | go run generator/cmd/downloader/main.go --config="schemas.yaml" 181 | ``` 182 | 183 | 2. Then run the generator: 184 | 185 | ```shell 186 | go generate ./... 187 | ``` 188 | 189 | ## Star History 190 | 191 | [![Star History Chart](https://api.star-history.com/svg?repos=Metalblueberry/go-plotly&type=Date)](https://star-history.com/#Metalblueberry/go-plotly&Date) 192 | 193 | ## Other tools and information links 194 | 195 | ### Plotly online editor sandbox 196 | 197 | http://plotly-json-editor.getforge.io/ 198 | 199 | ### Official Plotly Release Notes 200 | 201 | For detailed changes please follow the release notes of the original JS repo: https://github.com/plotly/plotly.js/releases -------------------------------------------------------------------------------- /generated/v2.19.0/graph_objects/unmarshal_gen.go: -------------------------------------------------------------------------------- 1 | package grob 2 | 3 | // Code generated by go-plotly/generator. DO NOT EDIT 4 | 5 | import ( 6 | "encoding/json" 7 | "errors" 8 | "github.com/MetalBlueberry/go-plotly/pkg/types" 9 | ) 10 | 11 | type unmarshalType struct { 12 | Type types.TraceType `json:"type,omitempty"` 13 | } 14 | 15 | // UnmarshalTrace decodes an array of bytes into a Trace interface. 16 | func UnmarshalTrace(data []byte) (types.Trace, error) { 17 | traceType := unmarshalType{} 18 | err := json.Unmarshal(data, &traceType) 19 | if err != nil { 20 | return nil, err 21 | } 22 | switch traceType.Type { 23 | case TraceTypeBar: 24 | trace := &Bar{} 25 | err = json.Unmarshal(data, trace) 26 | if err != nil { 27 | return nil, err 28 | } 29 | return trace, nil 30 | case TraceTypeBarpolar: 31 | trace := &Barpolar{} 32 | err = json.Unmarshal(data, trace) 33 | if err != nil { 34 | return nil, err 35 | } 36 | return trace, nil 37 | case TraceTypeBox: 38 | trace := &Box{} 39 | err = json.Unmarshal(data, trace) 40 | if err != nil { 41 | return nil, err 42 | } 43 | return trace, nil 44 | case TraceTypeCandlestick: 45 | trace := &Candlestick{} 46 | err = json.Unmarshal(data, trace) 47 | if err != nil { 48 | return nil, err 49 | } 50 | return trace, nil 51 | case TraceTypeCarpet: 52 | trace := &Carpet{} 53 | err = json.Unmarshal(data, trace) 54 | if err != nil { 55 | return nil, err 56 | } 57 | return trace, nil 58 | case TraceTypeChoropleth: 59 | trace := &Choropleth{} 60 | err = json.Unmarshal(data, trace) 61 | if err != nil { 62 | return nil, err 63 | } 64 | return trace, nil 65 | case TraceTypeChoroplethmapbox: 66 | trace := &Choroplethmapbox{} 67 | err = json.Unmarshal(data, trace) 68 | if err != nil { 69 | return nil, err 70 | } 71 | return trace, nil 72 | case TraceTypeCone: 73 | trace := &Cone{} 74 | err = json.Unmarshal(data, trace) 75 | if err != nil { 76 | return nil, err 77 | } 78 | return trace, nil 79 | case TraceTypeContour: 80 | trace := &Contour{} 81 | err = json.Unmarshal(data, trace) 82 | if err != nil { 83 | return nil, err 84 | } 85 | return trace, nil 86 | case TraceTypeContourcarpet: 87 | trace := &Contourcarpet{} 88 | err = json.Unmarshal(data, trace) 89 | if err != nil { 90 | return nil, err 91 | } 92 | return trace, nil 93 | case TraceTypeDensitymapbox: 94 | trace := &Densitymapbox{} 95 | err = json.Unmarshal(data, trace) 96 | if err != nil { 97 | return nil, err 98 | } 99 | return trace, nil 100 | case TraceTypeFunnel: 101 | trace := &Funnel{} 102 | err = json.Unmarshal(data, trace) 103 | if err != nil { 104 | return nil, err 105 | } 106 | return trace, nil 107 | case TraceTypeFunnelarea: 108 | trace := &Funnelarea{} 109 | err = json.Unmarshal(data, trace) 110 | if err != nil { 111 | return nil, err 112 | } 113 | return trace, nil 114 | case TraceTypeHeatmap: 115 | trace := &Heatmap{} 116 | err = json.Unmarshal(data, trace) 117 | if err != nil { 118 | return nil, err 119 | } 120 | return trace, nil 121 | case TraceTypeHeatmapgl: 122 | trace := &Heatmapgl{} 123 | err = json.Unmarshal(data, trace) 124 | if err != nil { 125 | return nil, err 126 | } 127 | return trace, nil 128 | case TraceTypeHistogram: 129 | trace := &Histogram{} 130 | err = json.Unmarshal(data, trace) 131 | if err != nil { 132 | return nil, err 133 | } 134 | return trace, nil 135 | case TraceTypeHistogram2d: 136 | trace := &Histogram2d{} 137 | err = json.Unmarshal(data, trace) 138 | if err != nil { 139 | return nil, err 140 | } 141 | return trace, nil 142 | case TraceTypeHistogram2dcontour: 143 | trace := &Histogram2dcontour{} 144 | err = json.Unmarshal(data, trace) 145 | if err != nil { 146 | return nil, err 147 | } 148 | return trace, nil 149 | case TraceTypeIcicle: 150 | trace := &Icicle{} 151 | err = json.Unmarshal(data, trace) 152 | if err != nil { 153 | return nil, err 154 | } 155 | return trace, nil 156 | case TraceTypeImage: 157 | trace := &Image{} 158 | err = json.Unmarshal(data, trace) 159 | if err != nil { 160 | return nil, err 161 | } 162 | return trace, nil 163 | case TraceTypeIndicator: 164 | trace := &Indicator{} 165 | err = json.Unmarshal(data, trace) 166 | if err != nil { 167 | return nil, err 168 | } 169 | return trace, nil 170 | case TraceTypeIsosurface: 171 | trace := &Isosurface{} 172 | err = json.Unmarshal(data, trace) 173 | if err != nil { 174 | return nil, err 175 | } 176 | return trace, nil 177 | case TraceTypeMesh3d: 178 | trace := &Mesh3d{} 179 | err = json.Unmarshal(data, trace) 180 | if err != nil { 181 | return nil, err 182 | } 183 | return trace, nil 184 | case TraceTypeOhlc: 185 | trace := &Ohlc{} 186 | err = json.Unmarshal(data, trace) 187 | if err != nil { 188 | return nil, err 189 | } 190 | return trace, nil 191 | case TraceTypeParcats: 192 | trace := &Parcats{} 193 | err = json.Unmarshal(data, trace) 194 | if err != nil { 195 | return nil, err 196 | } 197 | return trace, nil 198 | case TraceTypeParcoords: 199 | trace := &Parcoords{} 200 | err = json.Unmarshal(data, trace) 201 | if err != nil { 202 | return nil, err 203 | } 204 | return trace, nil 205 | case TraceTypePie: 206 | trace := &Pie{} 207 | err = json.Unmarshal(data, trace) 208 | if err != nil { 209 | return nil, err 210 | } 211 | return trace, nil 212 | case TraceTypePointcloud: 213 | trace := &Pointcloud{} 214 | err = json.Unmarshal(data, trace) 215 | if err != nil { 216 | return nil, err 217 | } 218 | return trace, nil 219 | case TraceTypeSankey: 220 | trace := &Sankey{} 221 | err = json.Unmarshal(data, trace) 222 | if err != nil { 223 | return nil, err 224 | } 225 | return trace, nil 226 | case TraceTypeScatter: 227 | trace := &Scatter{} 228 | err = json.Unmarshal(data, trace) 229 | if err != nil { 230 | return nil, err 231 | } 232 | return trace, nil 233 | case TraceTypeScatter3d: 234 | trace := &Scatter3d{} 235 | err = json.Unmarshal(data, trace) 236 | if err != nil { 237 | return nil, err 238 | } 239 | return trace, nil 240 | case TraceTypeScattercarpet: 241 | trace := &Scattercarpet{} 242 | err = json.Unmarshal(data, trace) 243 | if err != nil { 244 | return nil, err 245 | } 246 | return trace, nil 247 | case TraceTypeScattergeo: 248 | trace := &Scattergeo{} 249 | err = json.Unmarshal(data, trace) 250 | if err != nil { 251 | return nil, err 252 | } 253 | return trace, nil 254 | case TraceTypeScattergl: 255 | trace := &Scattergl{} 256 | err = json.Unmarshal(data, trace) 257 | if err != nil { 258 | return nil, err 259 | } 260 | return trace, nil 261 | case TraceTypeScattermapbox: 262 | trace := &Scattermapbox{} 263 | err = json.Unmarshal(data, trace) 264 | if err != nil { 265 | return nil, err 266 | } 267 | return trace, nil 268 | case TraceTypeScatterpolar: 269 | trace := &Scatterpolar{} 270 | err = json.Unmarshal(data, trace) 271 | if err != nil { 272 | return nil, err 273 | } 274 | return trace, nil 275 | case TraceTypeScatterpolargl: 276 | trace := &Scatterpolargl{} 277 | err = json.Unmarshal(data, trace) 278 | if err != nil { 279 | return nil, err 280 | } 281 | return trace, nil 282 | case TraceTypeScattersmith: 283 | trace := &Scattersmith{} 284 | err = json.Unmarshal(data, trace) 285 | if err != nil { 286 | return nil, err 287 | } 288 | return trace, nil 289 | case TraceTypeScatterternary: 290 | trace := &Scatterternary{} 291 | err = json.Unmarshal(data, trace) 292 | if err != nil { 293 | return nil, err 294 | } 295 | return trace, nil 296 | case TraceTypeSplom: 297 | trace := &Splom{} 298 | err = json.Unmarshal(data, trace) 299 | if err != nil { 300 | return nil, err 301 | } 302 | return trace, nil 303 | case TraceTypeStreamtube: 304 | trace := &Streamtube{} 305 | err = json.Unmarshal(data, trace) 306 | if err != nil { 307 | return nil, err 308 | } 309 | return trace, nil 310 | case TraceTypeSunburst: 311 | trace := &Sunburst{} 312 | err = json.Unmarshal(data, trace) 313 | if err != nil { 314 | return nil, err 315 | } 316 | return trace, nil 317 | case TraceTypeSurface: 318 | trace := &Surface{} 319 | err = json.Unmarshal(data, trace) 320 | if err != nil { 321 | return nil, err 322 | } 323 | return trace, nil 324 | case TraceTypeTable: 325 | trace := &Table{} 326 | err = json.Unmarshal(data, trace) 327 | if err != nil { 328 | return nil, err 329 | } 330 | return trace, nil 331 | case TraceTypeTreemap: 332 | trace := &Treemap{} 333 | err = json.Unmarshal(data, trace) 334 | if err != nil { 335 | return nil, err 336 | } 337 | return trace, nil 338 | case TraceTypeViolin: 339 | trace := &Violin{} 340 | err = json.Unmarshal(data, trace) 341 | if err != nil { 342 | return nil, err 343 | } 344 | return trace, nil 345 | case TraceTypeVolume: 346 | trace := &Volume{} 347 | err = json.Unmarshal(data, trace) 348 | if err != nil { 349 | return nil, err 350 | } 351 | return trace, nil 352 | case TraceTypeWaterfall: 353 | trace := &Waterfall{} 354 | err = json.Unmarshal(data, trace) 355 | if err != nil { 356 | return nil, err 357 | } 358 | return trace, nil 359 | default: 360 | return nil, errors.New("Trace Type is not registered") 361 | } 362 | } 363 | -------------------------------------------------------------------------------- /generated/v2.29.1/graph_objects/unmarshal_gen.go: -------------------------------------------------------------------------------- 1 | package grob 2 | 3 | // Code generated by go-plotly/generator. DO NOT EDIT 4 | 5 | import ( 6 | "encoding/json" 7 | "errors" 8 | "github.com/MetalBlueberry/go-plotly/pkg/types" 9 | ) 10 | 11 | type unmarshalType struct { 12 | Type types.TraceType `json:"type,omitempty"` 13 | } 14 | 15 | // UnmarshalTrace decodes an array of bytes into a Trace interface. 16 | func UnmarshalTrace(data []byte) (types.Trace, error) { 17 | traceType := unmarshalType{} 18 | err := json.Unmarshal(data, &traceType) 19 | if err != nil { 20 | return nil, err 21 | } 22 | switch traceType.Type { 23 | case TraceTypeBar: 24 | trace := &Bar{} 25 | err = json.Unmarshal(data, trace) 26 | if err != nil { 27 | return nil, err 28 | } 29 | return trace, nil 30 | case TraceTypeBarpolar: 31 | trace := &Barpolar{} 32 | err = json.Unmarshal(data, trace) 33 | if err != nil { 34 | return nil, err 35 | } 36 | return trace, nil 37 | case TraceTypeBox: 38 | trace := &Box{} 39 | err = json.Unmarshal(data, trace) 40 | if err != nil { 41 | return nil, err 42 | } 43 | return trace, nil 44 | case TraceTypeCandlestick: 45 | trace := &Candlestick{} 46 | err = json.Unmarshal(data, trace) 47 | if err != nil { 48 | return nil, err 49 | } 50 | return trace, nil 51 | case TraceTypeCarpet: 52 | trace := &Carpet{} 53 | err = json.Unmarshal(data, trace) 54 | if err != nil { 55 | return nil, err 56 | } 57 | return trace, nil 58 | case TraceTypeChoropleth: 59 | trace := &Choropleth{} 60 | err = json.Unmarshal(data, trace) 61 | if err != nil { 62 | return nil, err 63 | } 64 | return trace, nil 65 | case TraceTypeChoroplethmapbox: 66 | trace := &Choroplethmapbox{} 67 | err = json.Unmarshal(data, trace) 68 | if err != nil { 69 | return nil, err 70 | } 71 | return trace, nil 72 | case TraceTypeCone: 73 | trace := &Cone{} 74 | err = json.Unmarshal(data, trace) 75 | if err != nil { 76 | return nil, err 77 | } 78 | return trace, nil 79 | case TraceTypeContour: 80 | trace := &Contour{} 81 | err = json.Unmarshal(data, trace) 82 | if err != nil { 83 | return nil, err 84 | } 85 | return trace, nil 86 | case TraceTypeContourcarpet: 87 | trace := &Contourcarpet{} 88 | err = json.Unmarshal(data, trace) 89 | if err != nil { 90 | return nil, err 91 | } 92 | return trace, nil 93 | case TraceTypeDensitymapbox: 94 | trace := &Densitymapbox{} 95 | err = json.Unmarshal(data, trace) 96 | if err != nil { 97 | return nil, err 98 | } 99 | return trace, nil 100 | case TraceTypeFunnel: 101 | trace := &Funnel{} 102 | err = json.Unmarshal(data, trace) 103 | if err != nil { 104 | return nil, err 105 | } 106 | return trace, nil 107 | case TraceTypeFunnelarea: 108 | trace := &Funnelarea{} 109 | err = json.Unmarshal(data, trace) 110 | if err != nil { 111 | return nil, err 112 | } 113 | return trace, nil 114 | case TraceTypeHeatmap: 115 | trace := &Heatmap{} 116 | err = json.Unmarshal(data, trace) 117 | if err != nil { 118 | return nil, err 119 | } 120 | return trace, nil 121 | case TraceTypeHeatmapgl: 122 | trace := &Heatmapgl{} 123 | err = json.Unmarshal(data, trace) 124 | if err != nil { 125 | return nil, err 126 | } 127 | return trace, nil 128 | case TraceTypeHistogram: 129 | trace := &Histogram{} 130 | err = json.Unmarshal(data, trace) 131 | if err != nil { 132 | return nil, err 133 | } 134 | return trace, nil 135 | case TraceTypeHistogram2d: 136 | trace := &Histogram2d{} 137 | err = json.Unmarshal(data, trace) 138 | if err != nil { 139 | return nil, err 140 | } 141 | return trace, nil 142 | case TraceTypeHistogram2dcontour: 143 | trace := &Histogram2dcontour{} 144 | err = json.Unmarshal(data, trace) 145 | if err != nil { 146 | return nil, err 147 | } 148 | return trace, nil 149 | case TraceTypeIcicle: 150 | trace := &Icicle{} 151 | err = json.Unmarshal(data, trace) 152 | if err != nil { 153 | return nil, err 154 | } 155 | return trace, nil 156 | case TraceTypeImage: 157 | trace := &Image{} 158 | err = json.Unmarshal(data, trace) 159 | if err != nil { 160 | return nil, err 161 | } 162 | return trace, nil 163 | case TraceTypeIndicator: 164 | trace := &Indicator{} 165 | err = json.Unmarshal(data, trace) 166 | if err != nil { 167 | return nil, err 168 | } 169 | return trace, nil 170 | case TraceTypeIsosurface: 171 | trace := &Isosurface{} 172 | err = json.Unmarshal(data, trace) 173 | if err != nil { 174 | return nil, err 175 | } 176 | return trace, nil 177 | case TraceTypeMesh3d: 178 | trace := &Mesh3d{} 179 | err = json.Unmarshal(data, trace) 180 | if err != nil { 181 | return nil, err 182 | } 183 | return trace, nil 184 | case TraceTypeOhlc: 185 | trace := &Ohlc{} 186 | err = json.Unmarshal(data, trace) 187 | if err != nil { 188 | return nil, err 189 | } 190 | return trace, nil 191 | case TraceTypeParcats: 192 | trace := &Parcats{} 193 | err = json.Unmarshal(data, trace) 194 | if err != nil { 195 | return nil, err 196 | } 197 | return trace, nil 198 | case TraceTypeParcoords: 199 | trace := &Parcoords{} 200 | err = json.Unmarshal(data, trace) 201 | if err != nil { 202 | return nil, err 203 | } 204 | return trace, nil 205 | case TraceTypePie: 206 | trace := &Pie{} 207 | err = json.Unmarshal(data, trace) 208 | if err != nil { 209 | return nil, err 210 | } 211 | return trace, nil 212 | case TraceTypePointcloud: 213 | trace := &Pointcloud{} 214 | err = json.Unmarshal(data, trace) 215 | if err != nil { 216 | return nil, err 217 | } 218 | return trace, nil 219 | case TraceTypeSankey: 220 | trace := &Sankey{} 221 | err = json.Unmarshal(data, trace) 222 | if err != nil { 223 | return nil, err 224 | } 225 | return trace, nil 226 | case TraceTypeScatter: 227 | trace := &Scatter{} 228 | err = json.Unmarshal(data, trace) 229 | if err != nil { 230 | return nil, err 231 | } 232 | return trace, nil 233 | case TraceTypeScatter3d: 234 | trace := &Scatter3d{} 235 | err = json.Unmarshal(data, trace) 236 | if err != nil { 237 | return nil, err 238 | } 239 | return trace, nil 240 | case TraceTypeScattercarpet: 241 | trace := &Scattercarpet{} 242 | err = json.Unmarshal(data, trace) 243 | if err != nil { 244 | return nil, err 245 | } 246 | return trace, nil 247 | case TraceTypeScattergeo: 248 | trace := &Scattergeo{} 249 | err = json.Unmarshal(data, trace) 250 | if err != nil { 251 | return nil, err 252 | } 253 | return trace, nil 254 | case TraceTypeScattergl: 255 | trace := &Scattergl{} 256 | err = json.Unmarshal(data, trace) 257 | if err != nil { 258 | return nil, err 259 | } 260 | return trace, nil 261 | case TraceTypeScattermapbox: 262 | trace := &Scattermapbox{} 263 | err = json.Unmarshal(data, trace) 264 | if err != nil { 265 | return nil, err 266 | } 267 | return trace, nil 268 | case TraceTypeScatterpolar: 269 | trace := &Scatterpolar{} 270 | err = json.Unmarshal(data, trace) 271 | if err != nil { 272 | return nil, err 273 | } 274 | return trace, nil 275 | case TraceTypeScatterpolargl: 276 | trace := &Scatterpolargl{} 277 | err = json.Unmarshal(data, trace) 278 | if err != nil { 279 | return nil, err 280 | } 281 | return trace, nil 282 | case TraceTypeScattersmith: 283 | trace := &Scattersmith{} 284 | err = json.Unmarshal(data, trace) 285 | if err != nil { 286 | return nil, err 287 | } 288 | return trace, nil 289 | case TraceTypeScatterternary: 290 | trace := &Scatterternary{} 291 | err = json.Unmarshal(data, trace) 292 | if err != nil { 293 | return nil, err 294 | } 295 | return trace, nil 296 | case TraceTypeSplom: 297 | trace := &Splom{} 298 | err = json.Unmarshal(data, trace) 299 | if err != nil { 300 | return nil, err 301 | } 302 | return trace, nil 303 | case TraceTypeStreamtube: 304 | trace := &Streamtube{} 305 | err = json.Unmarshal(data, trace) 306 | if err != nil { 307 | return nil, err 308 | } 309 | return trace, nil 310 | case TraceTypeSunburst: 311 | trace := &Sunburst{} 312 | err = json.Unmarshal(data, trace) 313 | if err != nil { 314 | return nil, err 315 | } 316 | return trace, nil 317 | case TraceTypeSurface: 318 | trace := &Surface{} 319 | err = json.Unmarshal(data, trace) 320 | if err != nil { 321 | return nil, err 322 | } 323 | return trace, nil 324 | case TraceTypeTable: 325 | trace := &Table{} 326 | err = json.Unmarshal(data, trace) 327 | if err != nil { 328 | return nil, err 329 | } 330 | return trace, nil 331 | case TraceTypeTreemap: 332 | trace := &Treemap{} 333 | err = json.Unmarshal(data, trace) 334 | if err != nil { 335 | return nil, err 336 | } 337 | return trace, nil 338 | case TraceTypeViolin: 339 | trace := &Violin{} 340 | err = json.Unmarshal(data, trace) 341 | if err != nil { 342 | return nil, err 343 | } 344 | return trace, nil 345 | case TraceTypeVolume: 346 | trace := &Volume{} 347 | err = json.Unmarshal(data, trace) 348 | if err != nil { 349 | return nil, err 350 | } 351 | return trace, nil 352 | case TraceTypeWaterfall: 353 | trace := &Waterfall{} 354 | err = json.Unmarshal(data, trace) 355 | if err != nil { 356 | return nil, err 357 | } 358 | return trace, nil 359 | default: 360 | return nil, errors.New("Trace Type is not registered") 361 | } 362 | } 363 | -------------------------------------------------------------------------------- /generated/v2.31.1/graph_objects/unmarshal_gen.go: -------------------------------------------------------------------------------- 1 | package grob 2 | 3 | // Code generated by go-plotly/generator. DO NOT EDIT 4 | 5 | import ( 6 | "encoding/json" 7 | "errors" 8 | "github.com/MetalBlueberry/go-plotly/pkg/types" 9 | ) 10 | 11 | type unmarshalType struct { 12 | Type types.TraceType `json:"type,omitempty"` 13 | } 14 | 15 | // UnmarshalTrace decodes an array of bytes into a Trace interface. 16 | func UnmarshalTrace(data []byte) (types.Trace, error) { 17 | traceType := unmarshalType{} 18 | err := json.Unmarshal(data, &traceType) 19 | if err != nil { 20 | return nil, err 21 | } 22 | switch traceType.Type { 23 | case TraceTypeBar: 24 | trace := &Bar{} 25 | err = json.Unmarshal(data, trace) 26 | if err != nil { 27 | return nil, err 28 | } 29 | return trace, nil 30 | case TraceTypeBarpolar: 31 | trace := &Barpolar{} 32 | err = json.Unmarshal(data, trace) 33 | if err != nil { 34 | return nil, err 35 | } 36 | return trace, nil 37 | case TraceTypeBox: 38 | trace := &Box{} 39 | err = json.Unmarshal(data, trace) 40 | if err != nil { 41 | return nil, err 42 | } 43 | return trace, nil 44 | case TraceTypeCandlestick: 45 | trace := &Candlestick{} 46 | err = json.Unmarshal(data, trace) 47 | if err != nil { 48 | return nil, err 49 | } 50 | return trace, nil 51 | case TraceTypeCarpet: 52 | trace := &Carpet{} 53 | err = json.Unmarshal(data, trace) 54 | if err != nil { 55 | return nil, err 56 | } 57 | return trace, nil 58 | case TraceTypeChoropleth: 59 | trace := &Choropleth{} 60 | err = json.Unmarshal(data, trace) 61 | if err != nil { 62 | return nil, err 63 | } 64 | return trace, nil 65 | case TraceTypeChoroplethmapbox: 66 | trace := &Choroplethmapbox{} 67 | err = json.Unmarshal(data, trace) 68 | if err != nil { 69 | return nil, err 70 | } 71 | return trace, nil 72 | case TraceTypeCone: 73 | trace := &Cone{} 74 | err = json.Unmarshal(data, trace) 75 | if err != nil { 76 | return nil, err 77 | } 78 | return trace, nil 79 | case TraceTypeContour: 80 | trace := &Contour{} 81 | err = json.Unmarshal(data, trace) 82 | if err != nil { 83 | return nil, err 84 | } 85 | return trace, nil 86 | case TraceTypeContourcarpet: 87 | trace := &Contourcarpet{} 88 | err = json.Unmarshal(data, trace) 89 | if err != nil { 90 | return nil, err 91 | } 92 | return trace, nil 93 | case TraceTypeDensitymapbox: 94 | trace := &Densitymapbox{} 95 | err = json.Unmarshal(data, trace) 96 | if err != nil { 97 | return nil, err 98 | } 99 | return trace, nil 100 | case TraceTypeFunnel: 101 | trace := &Funnel{} 102 | err = json.Unmarshal(data, trace) 103 | if err != nil { 104 | return nil, err 105 | } 106 | return trace, nil 107 | case TraceTypeFunnelarea: 108 | trace := &Funnelarea{} 109 | err = json.Unmarshal(data, trace) 110 | if err != nil { 111 | return nil, err 112 | } 113 | return trace, nil 114 | case TraceTypeHeatmap: 115 | trace := &Heatmap{} 116 | err = json.Unmarshal(data, trace) 117 | if err != nil { 118 | return nil, err 119 | } 120 | return trace, nil 121 | case TraceTypeHeatmapgl: 122 | trace := &Heatmapgl{} 123 | err = json.Unmarshal(data, trace) 124 | if err != nil { 125 | return nil, err 126 | } 127 | return trace, nil 128 | case TraceTypeHistogram: 129 | trace := &Histogram{} 130 | err = json.Unmarshal(data, trace) 131 | if err != nil { 132 | return nil, err 133 | } 134 | return trace, nil 135 | case TraceTypeHistogram2d: 136 | trace := &Histogram2d{} 137 | err = json.Unmarshal(data, trace) 138 | if err != nil { 139 | return nil, err 140 | } 141 | return trace, nil 142 | case TraceTypeHistogram2dcontour: 143 | trace := &Histogram2dcontour{} 144 | err = json.Unmarshal(data, trace) 145 | if err != nil { 146 | return nil, err 147 | } 148 | return trace, nil 149 | case TraceTypeIcicle: 150 | trace := &Icicle{} 151 | err = json.Unmarshal(data, trace) 152 | if err != nil { 153 | return nil, err 154 | } 155 | return trace, nil 156 | case TraceTypeImage: 157 | trace := &Image{} 158 | err = json.Unmarshal(data, trace) 159 | if err != nil { 160 | return nil, err 161 | } 162 | return trace, nil 163 | case TraceTypeIndicator: 164 | trace := &Indicator{} 165 | err = json.Unmarshal(data, trace) 166 | if err != nil { 167 | return nil, err 168 | } 169 | return trace, nil 170 | case TraceTypeIsosurface: 171 | trace := &Isosurface{} 172 | err = json.Unmarshal(data, trace) 173 | if err != nil { 174 | return nil, err 175 | } 176 | return trace, nil 177 | case TraceTypeMesh3d: 178 | trace := &Mesh3d{} 179 | err = json.Unmarshal(data, trace) 180 | if err != nil { 181 | return nil, err 182 | } 183 | return trace, nil 184 | case TraceTypeOhlc: 185 | trace := &Ohlc{} 186 | err = json.Unmarshal(data, trace) 187 | if err != nil { 188 | return nil, err 189 | } 190 | return trace, nil 191 | case TraceTypeParcats: 192 | trace := &Parcats{} 193 | err = json.Unmarshal(data, trace) 194 | if err != nil { 195 | return nil, err 196 | } 197 | return trace, nil 198 | case TraceTypeParcoords: 199 | trace := &Parcoords{} 200 | err = json.Unmarshal(data, trace) 201 | if err != nil { 202 | return nil, err 203 | } 204 | return trace, nil 205 | case TraceTypePie: 206 | trace := &Pie{} 207 | err = json.Unmarshal(data, trace) 208 | if err != nil { 209 | return nil, err 210 | } 211 | return trace, nil 212 | case TraceTypePointcloud: 213 | trace := &Pointcloud{} 214 | err = json.Unmarshal(data, trace) 215 | if err != nil { 216 | return nil, err 217 | } 218 | return trace, nil 219 | case TraceTypeSankey: 220 | trace := &Sankey{} 221 | err = json.Unmarshal(data, trace) 222 | if err != nil { 223 | return nil, err 224 | } 225 | return trace, nil 226 | case TraceTypeScatter: 227 | trace := &Scatter{} 228 | err = json.Unmarshal(data, trace) 229 | if err != nil { 230 | return nil, err 231 | } 232 | return trace, nil 233 | case TraceTypeScatter3d: 234 | trace := &Scatter3d{} 235 | err = json.Unmarshal(data, trace) 236 | if err != nil { 237 | return nil, err 238 | } 239 | return trace, nil 240 | case TraceTypeScattercarpet: 241 | trace := &Scattercarpet{} 242 | err = json.Unmarshal(data, trace) 243 | if err != nil { 244 | return nil, err 245 | } 246 | return trace, nil 247 | case TraceTypeScattergeo: 248 | trace := &Scattergeo{} 249 | err = json.Unmarshal(data, trace) 250 | if err != nil { 251 | return nil, err 252 | } 253 | return trace, nil 254 | case TraceTypeScattergl: 255 | trace := &Scattergl{} 256 | err = json.Unmarshal(data, trace) 257 | if err != nil { 258 | return nil, err 259 | } 260 | return trace, nil 261 | case TraceTypeScattermapbox: 262 | trace := &Scattermapbox{} 263 | err = json.Unmarshal(data, trace) 264 | if err != nil { 265 | return nil, err 266 | } 267 | return trace, nil 268 | case TraceTypeScatterpolar: 269 | trace := &Scatterpolar{} 270 | err = json.Unmarshal(data, trace) 271 | if err != nil { 272 | return nil, err 273 | } 274 | return trace, nil 275 | case TraceTypeScatterpolargl: 276 | trace := &Scatterpolargl{} 277 | err = json.Unmarshal(data, trace) 278 | if err != nil { 279 | return nil, err 280 | } 281 | return trace, nil 282 | case TraceTypeScattersmith: 283 | trace := &Scattersmith{} 284 | err = json.Unmarshal(data, trace) 285 | if err != nil { 286 | return nil, err 287 | } 288 | return trace, nil 289 | case TraceTypeScatterternary: 290 | trace := &Scatterternary{} 291 | err = json.Unmarshal(data, trace) 292 | if err != nil { 293 | return nil, err 294 | } 295 | return trace, nil 296 | case TraceTypeSplom: 297 | trace := &Splom{} 298 | err = json.Unmarshal(data, trace) 299 | if err != nil { 300 | return nil, err 301 | } 302 | return trace, nil 303 | case TraceTypeStreamtube: 304 | trace := &Streamtube{} 305 | err = json.Unmarshal(data, trace) 306 | if err != nil { 307 | return nil, err 308 | } 309 | return trace, nil 310 | case TraceTypeSunburst: 311 | trace := &Sunburst{} 312 | err = json.Unmarshal(data, trace) 313 | if err != nil { 314 | return nil, err 315 | } 316 | return trace, nil 317 | case TraceTypeSurface: 318 | trace := &Surface{} 319 | err = json.Unmarshal(data, trace) 320 | if err != nil { 321 | return nil, err 322 | } 323 | return trace, nil 324 | case TraceTypeTable: 325 | trace := &Table{} 326 | err = json.Unmarshal(data, trace) 327 | if err != nil { 328 | return nil, err 329 | } 330 | return trace, nil 331 | case TraceTypeTreemap: 332 | trace := &Treemap{} 333 | err = json.Unmarshal(data, trace) 334 | if err != nil { 335 | return nil, err 336 | } 337 | return trace, nil 338 | case TraceTypeViolin: 339 | trace := &Violin{} 340 | err = json.Unmarshal(data, trace) 341 | if err != nil { 342 | return nil, err 343 | } 344 | return trace, nil 345 | case TraceTypeVolume: 346 | trace := &Volume{} 347 | err = json.Unmarshal(data, trace) 348 | if err != nil { 349 | return nil, err 350 | } 351 | return trace, nil 352 | case TraceTypeWaterfall: 353 | trace := &Waterfall{} 354 | err = json.Unmarshal(data, trace) 355 | if err != nil { 356 | return nil, err 357 | } 358 | return trace, nil 359 | default: 360 | return nil, errors.New("Trace Type is not registered") 361 | } 362 | } 363 | -------------------------------------------------------------------------------- /generated/v2.34.0/graph_objects/unmarshal_gen.go: -------------------------------------------------------------------------------- 1 | package grob 2 | 3 | // Code generated by go-plotly/generator. DO NOT EDIT 4 | 5 | import ( 6 | "encoding/json" 7 | "errors" 8 | "github.com/MetalBlueberry/go-plotly/pkg/types" 9 | ) 10 | 11 | type unmarshalType struct { 12 | Type types.TraceType `json:"type,omitempty"` 13 | } 14 | 15 | // UnmarshalTrace decodes an array of bytes into a Trace interface. 16 | func UnmarshalTrace(data []byte) (types.Trace, error) { 17 | traceType := unmarshalType{} 18 | err := json.Unmarshal(data, &traceType) 19 | if err != nil { 20 | return nil, err 21 | } 22 | switch traceType.Type { 23 | case TraceTypeBar: 24 | trace := &Bar{} 25 | err = json.Unmarshal(data, trace) 26 | if err != nil { 27 | return nil, err 28 | } 29 | return trace, nil 30 | case TraceTypeBarpolar: 31 | trace := &Barpolar{} 32 | err = json.Unmarshal(data, trace) 33 | if err != nil { 34 | return nil, err 35 | } 36 | return trace, nil 37 | case TraceTypeBox: 38 | trace := &Box{} 39 | err = json.Unmarshal(data, trace) 40 | if err != nil { 41 | return nil, err 42 | } 43 | return trace, nil 44 | case TraceTypeCandlestick: 45 | trace := &Candlestick{} 46 | err = json.Unmarshal(data, trace) 47 | if err != nil { 48 | return nil, err 49 | } 50 | return trace, nil 51 | case TraceTypeCarpet: 52 | trace := &Carpet{} 53 | err = json.Unmarshal(data, trace) 54 | if err != nil { 55 | return nil, err 56 | } 57 | return trace, nil 58 | case TraceTypeChoropleth: 59 | trace := &Choropleth{} 60 | err = json.Unmarshal(data, trace) 61 | if err != nil { 62 | return nil, err 63 | } 64 | return trace, nil 65 | case TraceTypeChoroplethmapbox: 66 | trace := &Choroplethmapbox{} 67 | err = json.Unmarshal(data, trace) 68 | if err != nil { 69 | return nil, err 70 | } 71 | return trace, nil 72 | case TraceTypeCone: 73 | trace := &Cone{} 74 | err = json.Unmarshal(data, trace) 75 | if err != nil { 76 | return nil, err 77 | } 78 | return trace, nil 79 | case TraceTypeContour: 80 | trace := &Contour{} 81 | err = json.Unmarshal(data, trace) 82 | if err != nil { 83 | return nil, err 84 | } 85 | return trace, nil 86 | case TraceTypeContourcarpet: 87 | trace := &Contourcarpet{} 88 | err = json.Unmarshal(data, trace) 89 | if err != nil { 90 | return nil, err 91 | } 92 | return trace, nil 93 | case TraceTypeDensitymapbox: 94 | trace := &Densitymapbox{} 95 | err = json.Unmarshal(data, trace) 96 | if err != nil { 97 | return nil, err 98 | } 99 | return trace, nil 100 | case TraceTypeFunnel: 101 | trace := &Funnel{} 102 | err = json.Unmarshal(data, trace) 103 | if err != nil { 104 | return nil, err 105 | } 106 | return trace, nil 107 | case TraceTypeFunnelarea: 108 | trace := &Funnelarea{} 109 | err = json.Unmarshal(data, trace) 110 | if err != nil { 111 | return nil, err 112 | } 113 | return trace, nil 114 | case TraceTypeHeatmap: 115 | trace := &Heatmap{} 116 | err = json.Unmarshal(data, trace) 117 | if err != nil { 118 | return nil, err 119 | } 120 | return trace, nil 121 | case TraceTypeHeatmapgl: 122 | trace := &Heatmapgl{} 123 | err = json.Unmarshal(data, trace) 124 | if err != nil { 125 | return nil, err 126 | } 127 | return trace, nil 128 | case TraceTypeHistogram: 129 | trace := &Histogram{} 130 | err = json.Unmarshal(data, trace) 131 | if err != nil { 132 | return nil, err 133 | } 134 | return trace, nil 135 | case TraceTypeHistogram2d: 136 | trace := &Histogram2d{} 137 | err = json.Unmarshal(data, trace) 138 | if err != nil { 139 | return nil, err 140 | } 141 | return trace, nil 142 | case TraceTypeHistogram2dcontour: 143 | trace := &Histogram2dcontour{} 144 | err = json.Unmarshal(data, trace) 145 | if err != nil { 146 | return nil, err 147 | } 148 | return trace, nil 149 | case TraceTypeIcicle: 150 | trace := &Icicle{} 151 | err = json.Unmarshal(data, trace) 152 | if err != nil { 153 | return nil, err 154 | } 155 | return trace, nil 156 | case TraceTypeImage: 157 | trace := &Image{} 158 | err = json.Unmarshal(data, trace) 159 | if err != nil { 160 | return nil, err 161 | } 162 | return trace, nil 163 | case TraceTypeIndicator: 164 | trace := &Indicator{} 165 | err = json.Unmarshal(data, trace) 166 | if err != nil { 167 | return nil, err 168 | } 169 | return trace, nil 170 | case TraceTypeIsosurface: 171 | trace := &Isosurface{} 172 | err = json.Unmarshal(data, trace) 173 | if err != nil { 174 | return nil, err 175 | } 176 | return trace, nil 177 | case TraceTypeMesh3d: 178 | trace := &Mesh3d{} 179 | err = json.Unmarshal(data, trace) 180 | if err != nil { 181 | return nil, err 182 | } 183 | return trace, nil 184 | case TraceTypeOhlc: 185 | trace := &Ohlc{} 186 | err = json.Unmarshal(data, trace) 187 | if err != nil { 188 | return nil, err 189 | } 190 | return trace, nil 191 | case TraceTypeParcats: 192 | trace := &Parcats{} 193 | err = json.Unmarshal(data, trace) 194 | if err != nil { 195 | return nil, err 196 | } 197 | return trace, nil 198 | case TraceTypeParcoords: 199 | trace := &Parcoords{} 200 | err = json.Unmarshal(data, trace) 201 | if err != nil { 202 | return nil, err 203 | } 204 | return trace, nil 205 | case TraceTypePie: 206 | trace := &Pie{} 207 | err = json.Unmarshal(data, trace) 208 | if err != nil { 209 | return nil, err 210 | } 211 | return trace, nil 212 | case TraceTypePointcloud: 213 | trace := &Pointcloud{} 214 | err = json.Unmarshal(data, trace) 215 | if err != nil { 216 | return nil, err 217 | } 218 | return trace, nil 219 | case TraceTypeSankey: 220 | trace := &Sankey{} 221 | err = json.Unmarshal(data, trace) 222 | if err != nil { 223 | return nil, err 224 | } 225 | return trace, nil 226 | case TraceTypeScatter: 227 | trace := &Scatter{} 228 | err = json.Unmarshal(data, trace) 229 | if err != nil { 230 | return nil, err 231 | } 232 | return trace, nil 233 | case TraceTypeScatter3d: 234 | trace := &Scatter3d{} 235 | err = json.Unmarshal(data, trace) 236 | if err != nil { 237 | return nil, err 238 | } 239 | return trace, nil 240 | case TraceTypeScattercarpet: 241 | trace := &Scattercarpet{} 242 | err = json.Unmarshal(data, trace) 243 | if err != nil { 244 | return nil, err 245 | } 246 | return trace, nil 247 | case TraceTypeScattergeo: 248 | trace := &Scattergeo{} 249 | err = json.Unmarshal(data, trace) 250 | if err != nil { 251 | return nil, err 252 | } 253 | return trace, nil 254 | case TraceTypeScattergl: 255 | trace := &Scattergl{} 256 | err = json.Unmarshal(data, trace) 257 | if err != nil { 258 | return nil, err 259 | } 260 | return trace, nil 261 | case TraceTypeScattermapbox: 262 | trace := &Scattermapbox{} 263 | err = json.Unmarshal(data, trace) 264 | if err != nil { 265 | return nil, err 266 | } 267 | return trace, nil 268 | case TraceTypeScatterpolar: 269 | trace := &Scatterpolar{} 270 | err = json.Unmarshal(data, trace) 271 | if err != nil { 272 | return nil, err 273 | } 274 | return trace, nil 275 | case TraceTypeScatterpolargl: 276 | trace := &Scatterpolargl{} 277 | err = json.Unmarshal(data, trace) 278 | if err != nil { 279 | return nil, err 280 | } 281 | return trace, nil 282 | case TraceTypeScattersmith: 283 | trace := &Scattersmith{} 284 | err = json.Unmarshal(data, trace) 285 | if err != nil { 286 | return nil, err 287 | } 288 | return trace, nil 289 | case TraceTypeScatterternary: 290 | trace := &Scatterternary{} 291 | err = json.Unmarshal(data, trace) 292 | if err != nil { 293 | return nil, err 294 | } 295 | return trace, nil 296 | case TraceTypeSplom: 297 | trace := &Splom{} 298 | err = json.Unmarshal(data, trace) 299 | if err != nil { 300 | return nil, err 301 | } 302 | return trace, nil 303 | case TraceTypeStreamtube: 304 | trace := &Streamtube{} 305 | err = json.Unmarshal(data, trace) 306 | if err != nil { 307 | return nil, err 308 | } 309 | return trace, nil 310 | case TraceTypeSunburst: 311 | trace := &Sunburst{} 312 | err = json.Unmarshal(data, trace) 313 | if err != nil { 314 | return nil, err 315 | } 316 | return trace, nil 317 | case TraceTypeSurface: 318 | trace := &Surface{} 319 | err = json.Unmarshal(data, trace) 320 | if err != nil { 321 | return nil, err 322 | } 323 | return trace, nil 324 | case TraceTypeTable: 325 | trace := &Table{} 326 | err = json.Unmarshal(data, trace) 327 | if err != nil { 328 | return nil, err 329 | } 330 | return trace, nil 331 | case TraceTypeTreemap: 332 | trace := &Treemap{} 333 | err = json.Unmarshal(data, trace) 334 | if err != nil { 335 | return nil, err 336 | } 337 | return trace, nil 338 | case TraceTypeViolin: 339 | trace := &Violin{} 340 | err = json.Unmarshal(data, trace) 341 | if err != nil { 342 | return nil, err 343 | } 344 | return trace, nil 345 | case TraceTypeVolume: 346 | trace := &Volume{} 347 | err = json.Unmarshal(data, trace) 348 | if err != nil { 349 | return nil, err 350 | } 351 | return trace, nil 352 | case TraceTypeWaterfall: 353 | trace := &Waterfall{} 354 | err = json.Unmarshal(data, trace) 355 | if err != nil { 356 | return nil, err 357 | } 358 | return trace, nil 359 | default: 360 | return nil, errors.New("Trace Type is not registered") 361 | } 362 | } 363 | --------------------------------------------------------------------------------