github.com/tobgu/qframe@v0.4.0/contrib/gonum/qplot/plotter.go (about) 1 package qplot 2 3 import ( 4 "strconv" 5 6 "github.com/tobgu/qframe" 7 "github.com/tobgu/qframe/qerrors" 8 "github.com/tobgu/qframe/types" 9 ) 10 11 // LabelFunc returns a string representation of 12 // the value in row i. 13 type LabelFunc func(i int) string 14 15 // LabelOfString returns a StringView compatible LabelFunc 16 func LabelOfString(view qframe.StringView) LabelFunc { 17 return func(i int) string { 18 return *view.ItemAt(i) 19 } 20 } 21 22 // LabelOfEnum returns a EnumView compatible LabelFunc 23 func LabelOfEnum(view qframe.EnumView) LabelFunc { 24 return func(i int) string { 25 return *view.ItemAt(i) 26 } 27 } 28 29 // LabelOfFloat returns a FloatView compatible LabelFunc 30 // fmt determines the float format when creating a string 31 func LabelOfFloat(fmt byte, view qframe.FloatView) LabelFunc { 32 return func(i int) string { 33 return strconv.FormatFloat(view.ItemAt(i), fmt, -1, 64) 34 } 35 } 36 37 // LabelOfInt returns an IntView compatible LabelFunc 38 func LabelOfInt(view qframe.IntView) LabelFunc { 39 return func(i int) string { 40 return strconv.FormatInt(int64(view.ItemAt(i)), 10) 41 } 42 } 43 44 // LabelOfBool returns a BoolView compatible LabelFunc 45 func LabelOfBool(view qframe.BoolView) LabelFunc { 46 return func(i int) string { 47 return strconv.FormatBool(view.ItemAt(i)) 48 } 49 } 50 51 // Labeller implements the Labeller interface 52 // defined in gonum.org/v1/plot/plotter. It accepts 53 // any of the predefined LabelFunc methods in this 54 // package or a custom function may be specified. 55 type Labeller struct { 56 len int 57 fn LabelFunc 58 } 59 60 // Label returns the label at i 61 func (l Labeller) Label(i int) string { return l.fn(i) } 62 63 // NewLabeller returns a new Labeller 64 func NewLabeller(len int, fn LabelFunc) Labeller { 65 return Labeller{len: len, fn: fn} 66 } 67 68 // XYLabeller implements the XYLabeller interface 69 // defined in gonum.org/v1/plot/plotter. 70 // It is a union of the Labeller and XYer 71 // types defined in this package. 72 type XYLabeller struct { 73 Labeller 74 XYer 75 } 76 77 // ValueFunc returns a float representation of 78 // the value in row i. 79 type ValueFunc func(i int) float64 80 81 // NewValueFunc returns a ValueFunc for column col 82 // if it is a numeric column, or returns an error. 83 func NewValueFunc(col string, qf qframe.QFrame) (ValueFunc, error) { 84 if !isNumCol(col, qf) { 85 return nil, qerrors.New("NewValueFunc", "Column %s is not a numeric value", col) 86 } 87 if !qf.Contains(col) { 88 return nil, qerrors.New("NewValueFunc", "QFrame does not contain column %s", col) 89 } 90 switch qf.ColumnTypeMap()[col] { 91 case types.Int: 92 return ValueOfInt(qf.MustIntView(col)), nil 93 case types.Float: 94 return ValueOfFloat(qf.MustFloatView(col)), nil 95 default: 96 panic(qerrors.New("NewValueFunc", "forgot to support a new column type?")) 97 } 98 } 99 100 // MustNewValueFunc returns a ValueFunc and panics when 101 // an error is encountered. 102 func MustNewValueFunc(col string, qf qframe.QFrame) ValueFunc { 103 fn, err := NewValueFunc(col, qf) 104 if err != nil { 105 panic(qerrors.Propagate("MustNewValueFunc", err)) 106 } 107 return fn 108 } 109 110 // ValueOfInt returns an IntView compatible ValueFunc 111 func ValueOfInt(view qframe.IntView) ValueFunc { 112 return func(i int) float64 { 113 return float64(view.ItemAt(i)) 114 } 115 } 116 117 // ValueOfFloat returns an FloatView compatible ValueFunc 118 func ValueOfFloat(view qframe.FloatView) ValueFunc { 119 return func(i int) float64 { 120 return view.ItemAt(i) 121 } 122 } 123 124 // Valuer implements the Valuer interface 125 // defined in gonum.org/v1/plot/plotter.Valuer 126 type Valuer struct { 127 len int 128 fn ValueFunc 129 } 130 131 // Len returns the length of the underlying view 132 func (v Valuer) Len() int { return v.len } 133 134 // Value returns the value in row i of the underlying view 135 func (v Valuer) Value(i int) float64 { return v.fn(i) } 136 137 // NewValuer returns a new Valuer from the values 138 // in col. The column must be a numeric type. 139 func NewValuer(col string, qf qframe.QFrame) (Valuer, error) { 140 fn, err := NewValueFunc(col, qf) 141 if err != nil { 142 return Valuer{}, err 143 } 144 return Valuer{len: qf.Len(), fn: fn}, nil 145 } 146 147 // MustNewValuer returns a new Valuer from the values 148 // in col. 149 func MustNewValuer(col string, qf qframe.QFrame) Valuer { 150 valuer, err := NewValuer(col, qf) 151 if err != nil { 152 panic(qerrors.Propagate("MustNewValuer", err)) 153 } 154 return valuer 155 } 156 157 // XYer implements the XYer interface 158 // defined in gonum.org/v1/plot/plotter. 159 type XYer struct { 160 len int 161 xfn ValueFunc 162 yfn ValueFunc 163 } 164 165 // Len returns the length of the underlying view 166 func (xy XYer) Len() int { return xy.len } 167 168 // XY returns the values of X and Y in the underlying view 169 func (xy XYer) XY(i int) (float64, float64) { return xy.xfn(i), xy.yfn(i) } 170 171 // NewXYer returns a new XYer from the values 172 // in column x and y. Both columns must have numeric types. 173 func NewXYer(x, y string, qf qframe.QFrame) (XYer, error) { 174 xvals, err := NewValueFunc(x, qf) 175 if err != nil { 176 return XYer{}, qerrors.Propagate("NewXYer", err) 177 } 178 yvals, err := NewValueFunc(y, qf) 179 if err != nil { 180 return XYer{}, qerrors.Propagate("NewXYer", err) 181 } 182 return XYer{len: qf.Len(), xfn: xvals, yfn: yvals}, nil 183 } 184 185 // MustNewXYer returns a new XYer from the values 186 // in column x and y. Both columns must have numeric types. 187 func MustNewXYer(x, y string, qf qframe.QFrame) XYer { 188 xyer, err := NewXYer(x, y, qf) 189 if err != nil { 190 panic(qerrors.Propagate("MustNewXYer", err)) 191 } 192 return xyer 193 } 194 195 // XYZer implements the XYZer interface 196 // defined in gonum.org/v1/plot/plotter 197 type XYZer struct { 198 len int 199 xfn ValueFunc 200 yfn ValueFunc 201 zfn ValueFunc 202 } 203 204 // Len returns the length of the underlying view 205 func (xyz XYZer) Len() int { return xyz.len } 206 207 // XYZ returns the values of X, Y, and Z in the underlying view 208 func (xyz XYZer) XYZ(i int) (float64, float64, float64) { 209 return xyz.xfn(i), xyz.yfn(i), xyz.zfn(i) 210 } 211 212 // XY returns the values of X and Y in the underlying view 213 func (xyz XYZer) XY(i int) (float64, float64) { 214 return xyz.xfn(i), xyz.yfn(i) 215 } 216 217 // NewXYZer returns a new XYZer from the values 218 // in column x, y, and z. All columns must have numeric types. 219 func NewXYZer(x, y, z string, qf qframe.QFrame) (XYZer, error) { 220 xvals, err := NewValueFunc(x, qf) 221 if err != nil { 222 return XYZer{}, qerrors.Propagate("NewXYZer", err) 223 } 224 yvals, err := NewValueFunc(y, qf) 225 if err != nil { 226 return XYZer{}, qerrors.Propagate("NewXYZer", err) 227 } 228 zvals, err := NewValueFunc(z, qf) 229 if err != nil { 230 return XYZer{}, qerrors.Propagate("NewXYZer", err) 231 } 232 return XYZer{len: qf.Len(), xfn: xvals, yfn: yvals, zfn: zvals}, nil 233 } 234 235 // MustNewXYZer returns a new XYZer from the values 236 // in column x, y, and z. All columns must have numeric types. 237 func MustNewXYZer(x, y, z string, qf qframe.QFrame) XYZer { 238 xyzer, err := NewXYZer(x, y, z, qf) 239 if err != nil { 240 panic(qerrors.Propagate("MustNewXYZer", err)) 241 } 242 return xyzer 243 } 244 245 // YErrorer implements the YErrorer interface 246 // defined in gonum.org/v1/plot/plotter 247 type YErrorer struct { 248 low ValueFunc 249 high ValueFunc 250 } 251 252 // YError returns the low and high error values in the underlying view. 253 func (ye YErrorer) YError(i int) (float64, float64) { return ye.low(i), ye.high(i) } 254 255 // NewYErrorer returns a new YErrorer for the values in 256 // column low and high of the QFrame. All columns must have 257 // numeric types. 258 func NewYErrorer(low, high string, qf qframe.QFrame) (YErrorer, error) { 259 lowFn, err := NewValueFunc(low, qf) 260 if err != nil { 261 return YErrorer{}, qerrors.Propagate("NewYErrorer", err) 262 } 263 highFn, err := NewValueFunc(high, qf) 264 if err != nil { 265 return YErrorer{}, qerrors.Propagate("NewYErrorer", err) 266 } 267 return YErrorer{low: lowFn, high: highFn}, nil 268 } 269 270 // NewYErrorer returns a new YErrorer for the values in 271 // column low and high of the QFrame. All columns must have 272 // numeric types. 273 func MustNewYErrorer(low, high string, qf qframe.QFrame) YErrorer { 274 y, err := NewYErrorer(low, high, qf) 275 if err != nil { 276 panic(qerrors.Propagate("MustNewYErrorer", err)) 277 } 278 return y 279 } 280 281 // XErrorer implements the XErrorer interface 282 // defined in gonum.org/v1/plot/plotter 283 type XErrorer struct { 284 low ValueFunc 285 high ValueFunc 286 } 287 288 // XError returns the low and high error values in the underlying view. 289 func (xe XErrorer) XError(i int) (float64, float64) { return xe.low(i), xe.high(i) } 290 291 // NewXErrorer returns a new XErrorer for the values in 292 // column low and high of the QFrame. All columns must have 293 // numeric types. 294 func NewXErrorer(low, high string, qf qframe.QFrame) (XErrorer, error) { 295 lowFn, err := NewValueFunc(low, qf) 296 if err != nil { 297 return XErrorer{}, qerrors.Propagate("NewXErrorer", err) 298 } 299 highFn, err := NewValueFunc(high, qf) 300 if err != nil { 301 return XErrorer{}, qerrors.Propagate("NewXErrorer", err) 302 } 303 return XErrorer{low: lowFn, high: highFn}, nil 304 } 305 306 // MustNewXErrorer returns a new XErrorer for the values in 307 // column low and high of the QFrame. All columns must have 308 // numeric types. 309 func MustNewXErrorer(low, high string, qf qframe.QFrame) XErrorer { 310 x, err := NewXErrorer(low, high, qf) 311 if err != nil { 312 panic(qerrors.Propagate("MustNewXErrorer", err)) 313 } 314 return x 315 } 316 317 // TODO: 318 // GridXYZ is used in HeatMap plotters but is too 319 // specific AFAICT to be generalized here. It can easily 320 // be implemented by wrapping a QFrame or composing 321 // several ValueFunc together.