func (f *Frame) TypeIndices(fTypes ...FieldType) []int {
	var indices []int
	if f.Fields == nil {
		return indices
	}
	for fieldIdx, f := range f.Fields {
		vecType := f.Type()
		for _, fType := range fTypes {
			if fType == vecType {
				indices = append(indices, fieldIdx)
				break
			}
		}
	}
	return indices
}
TypeIndices returns a slice of Field index positions for the given fTypes.
package data
import (
	"bytes"
	"encoding/json"
	"fmt"
	"math"
	"reflect"
	"strings"
	"time"
	"github.com/google/go-cmp/cmp"
	"github.com/google/go-cmp/cmp/cmpopts"
	jsoniter "github.com/json-iterator/go"
	"github.com/olekukonko/tablewriter"
)
type Frame struct {
	Name string
	Fields []*Field
	RefID string
	Meta *FrameMeta
}
func (f *Frame) UnmarshalJSON(b []byte) error {
	iter := jsoniter.ParseBytes(jsoniter.ConfigDefault, b)
	return readDataFrameJSON(f, iter)
}
func (f *Frame) MarshalJSON() ([]byte, error) {
	cfg := jsoniter.ConfigCompatibleWithStandardLibrary
	stream := cfg.BorrowStream(nil)
	defer cfg.ReturnStream(stream)
	writeDataFrame(f, stream, true, true)
	if stream.Error != nil {
		return nil, stream.Error
	}
	return append([]byte(nil), stream.Buffer()...), nil
}
type Frames []*Frame
func (f *Frame) AppendRow(vals ...interface{}) {
	for i, v := range vals {
		f.Fields[i].vector.Append(v)
	}
}
func (f *Frame) InsertRow(rowIdx int, vals ...interface{}) {
	for i, v := range vals {
		f.Fields[i].vector.Insert(rowIdx, v)
	}
}
func (f *Frame) DeleteRow(rowIdx int) {
	for _, field := range f.Fields {
		field.vector.Delete(rowIdx)
	}
}
func (f *Frame) SetRow(rowIdx int, vals ...interface{}) {
	for i, v := range vals {
		f.Fields[i].vector.Set(rowIdx, v)
	}
}
func (f *Frame) RowCopy(rowIdx int) []interface{} {
	vals := make([]interface{}, len(f.Fields))
	for i := range f.Fields {
		vals[i] = f.CopyAt(i, rowIdx)
	}
	return vals
}
func (f *Frame) FilterRowsByField(fieldIdx int, filter func(i interface{}) (bool, error)) (*Frame, error) {
	filteredFrame := f.EmptyCopy()
	rowLen, err := f.RowLen()
	if err != nil {
		return nil, err
	}
	for inRowIdx := 0; inRowIdx < rowLen; inRowIdx++ {
		match, err := filter(f.At(fieldIdx, inRowIdx))
		if err != nil {
			return nil, err
		}
		if !match {
			continue
		}
		filteredFrame.AppendRow(f.RowCopy(inRowIdx)...)
	}
	return filteredFrame, nil
}
func (f *Frame) EmptyCopy() *Frame {
	newFrame := &Frame{
		Name:   f.Name,
		RefID:  f.RefID,
		Fields: make(Fields, 0, len(f.Fields)),
	}
	for _, field := range f.Fields {
		fieldCopy := NewFieldFromFieldType(field.Type(), 0)
		fieldCopy.Name = field.Name
		fieldCopy.Labels = field.Labels.Copy()
		newFrame.Fields = append(newFrame.Fields, fieldCopy)
	}
	return newFrame
}
func NewFrameOfFieldTypes(name string, fieldLen int, fTypes ...FieldType) *Frame {
	f := &Frame{
		Name:   name,
		Fields: make(Fields, len(fTypes)),
	}
	for i, fT := range fTypes {
		f.Fields[i] = NewFieldFromFieldType(fT, fieldLen)
	}
	return f
}