diff --git a/Gopkg.lock b/Gopkg.lock index 3844d05e..d22be56d 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -63,7 +63,7 @@ [[projects]] name = "github.com/dustin/go-humanize" packages = ["."] - revision = "bb3d318650d48840a39aa21a027c6630e198e626" + revision = "02af3965c54e8cacf948b97fef38925c4120652c" source = "https://github.com/dustin/go-humanize" [[projects]] @@ -122,7 +122,7 @@ "schema", "top" ] - revision = "187ae4baf4c1bed94dfeb338dfc1137cd6dfadc3" + revision = "997067d2074a699295cf069e19e745e14db9bcf3" source = "https://github.com/gyuho/linux-inspect" [[projects]] @@ -159,7 +159,6 @@ name = "github.com/kr/pty" packages = ["."] revision = "1278f20d9cf7455f0465f3bf74a73d1eeb555c0f" - source = "https://github.com/kr/pty" [[projects]] branch = "master" @@ -186,7 +185,7 @@ [[projects]] name = "github.com/olekukonko/tablewriter" packages = ["."] - revision = "96aac992fc8b1a4c83841a6c3e7178d20d989625" + revision = "d4647c9c7a84d847478d890b816b7d8b62b0b279" source = "https://github.com/olekukonko/tablewriter" [[projects]] @@ -315,7 +314,7 @@ "vg/vgpdf", "vg/vgsvg" ] - revision = "feab214a240f4312b98ab52baf662b55ff1ee377" + revision = "8e90bd1840aacc281e54298e39ac0ae2be794419" source = "https://github.com/gonum/plot" [[projects]] @@ -395,6 +394,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "5f3fd3c1bb42b7e13f03ac35628c6743379babd27ebf047e5f1124fcc7f25125" + inputs-digest = "69cdc0d9c700a95cfecff8f95f783cc922720cd16666ffe7279cb702a812fa58" solver-name = "gps-cdcl" solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index ffa77f22..40b75b3b 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -45,7 +45,7 @@ [[constraint]] name = "github.com/dustin/go-humanize" source = "https://github.com/dustin/go-humanize" - revision = "bb3d318650d48840a39aa21a027c6630e198e626" + revision = "02af3965c54e8cacf948b97fef38925c4120652c" [[constraint]] name = "github.com/spf13/cobra" @@ -55,7 +55,7 @@ [[constraint]] name = "github.com/olekukonko/tablewriter" source = "https://github.com/olekukonko/tablewriter" - revision = "96aac992fc8b1a4c83841a6c3e7178d20d989625" + revision = "d4647c9c7a84d847478d890b816b7d8b62b0b279" [[constraint]] name = "github.com/cheggaaa/pb" @@ -84,13 +84,13 @@ [[constraint]] name = "github.com/gyuho/linux-inspect" source = "https://github.com/gyuho/linux-inspect" - revision = "187ae4baf4c1bed94dfeb338dfc1137cd6dfadc3" + revision = "997067d2074a699295cf069e19e745e14db9bcf3" [[constraint]] name = "gonum.org/v1/plot" source = "https://github.com/gonum/plot" - revision = "feab214a240f4312b98ab52baf662b55ff1ee377" + revision = "8e90bd1840aacc281e54298e39ac0ae2be794419" [[constraint]] diff --git a/scripts/dbtester-google-cloud.sh b/scripts/dbtester-google-cloud.sh index 40437ce1..cae7a660 100755 --- a/scripts/dbtester-google-cloud.sh +++ b/scripts/dbtester-google-cloud.sh @@ -134,7 +134,7 @@ sudo rm -rf ${HOME}/* # GO_VERSION=1.8.3 # etcd v3.3.0 -GO_VERSION=1.9.3 +GO_VERSION=1.9.6 sudo rm -f /usr/local/go/bin/go && sudo rm -rf /usr/local/go && sudo rm -f /bin/go @@ -322,9 +322,9 @@ curl -X PURGE https://camo.githubusercontent.com/a6e057c6a9cff6a8d49f4c5b83a2b47 plotly etcd v3.2.0 (Go 1.8.3) -etcd v3.3.0 (Go 1.9.3) +etcd v3.3.0 (Go 1.9.6) Zookeeper r3.5.3-beta (Java 8) -Consul v1.0.2 (Go 1.9.3) +Consul v1.0.2 (Go 1.9.6) Graph BoxPlot Traces diff --git a/scripts/install-etcd.sh b/scripts/install-etcd.sh index ad278c97..d44ee1a2 100755 --- a/scripts/install-etcd.sh +++ b/scripts/install-etcd.sh @@ -17,7 +17,7 @@ cd ${GOPATH}/src/${GIT_PATH} git reset --hard HEAD -./build +make build ${GOPATH}/src/${GIT_PATH}/bin/etcd --version ${GOPATH}/src/${GIT_PATH}/bin/etcdctl --version diff --git a/vendor/github.com/dustin/go-humanize/comma.go b/vendor/github.com/dustin/go-humanize/comma.go index 13611aaa..520ae3e5 100644 --- a/vendor/github.com/dustin/go-humanize/comma.go +++ b/vendor/github.com/dustin/go-humanize/comma.go @@ -76,6 +76,14 @@ func Commaf(v float64) string { return buf.String() } +// CommafWithDigits works like the Commaf but limits the resulting +// string to the given number of decimal places. +// +// e.g. CommafWithDigits(834142.32, 1) -> 834,142.3 +func CommafWithDigits(f float64, decimals int) string { + return stripTrailingDigits(Commaf(f), decimals) +} + // BigComma produces a string form of the given big.Int in base 10 // with commas after every three orders of magnitude. func BigComma(b *big.Int) string { diff --git a/vendor/github.com/dustin/go-humanize/ftoa.go b/vendor/github.com/dustin/go-humanize/ftoa.go index c76190b1..1c62b640 100644 --- a/vendor/github.com/dustin/go-humanize/ftoa.go +++ b/vendor/github.com/dustin/go-humanize/ftoa.go @@ -1,6 +1,9 @@ package humanize -import "strconv" +import ( + "strconv" + "strings" +) func stripTrailingZeros(s string) string { offset := len(s) - 1 @@ -17,7 +20,27 @@ func stripTrailingZeros(s string) string { return s[:offset+1] } +func stripTrailingDigits(s string, digits int) string { + if i := strings.Index(s, "."); i >= 0 { + if digits <= 0 { + return s[:i] + } + i++ + if i+digits >= len(s) { + return s + } + return s[:i+digits] + } + return s +} + // Ftoa converts a float to a string with no trailing zeros. func Ftoa(num float64) string { return stripTrailingZeros(strconv.FormatFloat(num, 'f', 6, 64)) } + +// FtoaWithDigits converts a float to a string but limits the resulting string +// to the given number of decimal places, and no trailing zeros. +func FtoaWithDigits(num float64, digits int) string { + return stripTrailingZeros(stripTrailingDigits(strconv.FormatFloat(num, 'f', 6, 64), digits)) +} diff --git a/vendor/github.com/dustin/go-humanize/si.go b/vendor/github.com/dustin/go-humanize/si.go index b24e4816..ae659e0e 100644 --- a/vendor/github.com/dustin/go-humanize/si.go +++ b/vendor/github.com/dustin/go-humanize/si.go @@ -93,6 +93,16 @@ func SI(input float64, unit string) string { return Ftoa(value) + " " + prefix + unit } +// SIWithDigits works like SI but limits the resulting string to the +// given number of decimal places. +// +// e.g. SIWithDigits(1000000, 0, "B") -> 1 MB +// e.g. SIWithDigits(2.2345e-12, 2, "F") -> 2.23 pF +func SIWithDigits(input float64, decimals int, unit string) string { + value, prefix := ComputeSI(input) + return FtoaWithDigits(value, decimals) + " " + prefix + unit +} + var errInvalid = errors.New("invalid input") // ParseSI parses an SI string back into the number and unit. diff --git a/vendor/github.com/olekukonko/tablewriter/table.go b/vendor/github.com/olekukonko/tablewriter/table.go index 8b62c628..6bbef96a 100644 --- a/vendor/github.com/olekukonko/tablewriter/table.go +++ b/vendor/github.com/olekukonko/tablewriter/table.go @@ -53,12 +53,13 @@ type Table struct { lines [][][]string cs map[int]int rs map[int]int - headers []string - footers []string + headers [][]string + footers [][]string caption bool captionText string autoFmt bool autoWrap bool + reflowText bool mW int pCenter string pRow string @@ -89,12 +90,13 @@ func NewWriter(writer io.Writer) *Table { lines: [][][]string{}, cs: make(map[int]int), rs: make(map[int]int), - headers: []string{}, - footers: []string{}, + headers: [][]string{}, + footers: [][]string{}, caption: false, captionText: "Table caption.", autoFmt: true, autoWrap: true, + reflowText: true, mW: MAX_ROW_WIDTH, pCenter: CENTER, pRow: ROW, @@ -137,12 +139,17 @@ func (t *Table) Render() { } } +const ( + headerRowIdx = -1 + footerRowIdx = -2 +) + // Set table header func (t *Table) SetHeader(keys []string) { t.colSize = len(keys) for i, v := range keys { - t.parseDimension(v, i, -1) - t.headers = append(t.headers, v) + lines := t.parseDimension(v, i, headerRowIdx) + t.headers = append(t.headers, lines) } } @@ -150,8 +157,8 @@ func (t *Table) SetHeader(keys []string) { func (t *Table) SetFooter(keys []string) { //t.colSize = len(keys) for i, v := range keys { - t.parseDimension(v, i, -1) - t.footers = append(t.footers, v) + lines := t.parseDimension(v, i, footerRowIdx) + t.footers = append(t.footers, lines) } } @@ -173,6 +180,11 @@ func (t *Table) SetAutoWrapText(auto bool) { t.autoWrap = auto } +// Turn automatic reflowing of multiline text when rewrapping. Default is on (true). +func (t *Table) SetReflowDuringAutoWrap(auto bool) { + t.reflowText = auto +} + // Set the Default column width func (t *Table) SetColWidth(width int) { t.mW = width @@ -304,7 +316,7 @@ func (t *Table) ClearRows() { // Clear footer func (t *Table) ClearFooter() { - t.footers = []string{} + t.footers = [][]string{} } // Print line based on row width @@ -367,10 +379,6 @@ func (t *Table) printHeading() { return } - // Check if border is set - // Replace with space if not set - fmt.Fprint(t.out, ConditionString(t.borders.Left, t.pColumn, SPACE)) - // Identify last column end := len(t.cs) - 1 @@ -383,31 +391,39 @@ func (t *Table) printHeading() { is_esc_seq = true } - // Print Heading column - for i := 0; i <= end; i++ { - v := t.cs[i] - h := "" - if i < len(t.headers) { - h = t.headers[i] - } - if t.autoFmt { - h = Title(h) - } - pad := ConditionString((i == end && !t.borders.Left), SPACE, t.pColumn) + // Maximum height. + max := t.rs[headerRowIdx] - if is_esc_seq { - fmt.Fprintf(t.out, " %s %s", - format(padFunc(h, SPACE, v), - t.headerParams[i]), pad) - } else { - fmt.Fprintf(t.out, " %s %s", - padFunc(h, SPACE, v), - pad) - } + // Print Heading + for x := 0; x < max; x++ { + // Check if border is set + // Replace with space if not set + fmt.Fprint(t.out, ConditionString(t.borders.Left, t.pColumn, SPACE)) + for y := 0; y <= end; y++ { + v := t.cs[y] + h := "" + if y < len(t.headers) && x < len(t.headers[y]) { + h = t.headers[y][x] + } + if t.autoFmt { + h = Title(h) + } + pad := ConditionString((y == end && !t.borders.Left), SPACE, t.pColumn) + + if is_esc_seq { + fmt.Fprintf(t.out, " %s %s", + format(padFunc(h, SPACE, v), + t.headerParams[y]), pad) + } else { + fmt.Fprintf(t.out, " %s %s", + padFunc(h, SPACE, v), + pad) + } + } + // Next line + fmt.Fprint(t.out, t.newLine) } - // Next line - fmt.Fprint(t.out, t.newLine) if t.hdrLine { t.printLine(true) } @@ -424,9 +440,6 @@ func (t *Table) printFooter() { if !t.borders.Bottom { t.printLine(true) } - // Check if border is set - // Replace with space if not set - fmt.Fprint(t.out, ConditionString(t.borders.Bottom, t.pColumn, SPACE)) // Identify last column end := len(t.cs) - 1 @@ -440,36 +453,50 @@ func (t *Table) printFooter() { is_esc_seq = true } - // Print Heading column - for i := 0; i <= end; i++ { - v := t.cs[i] - f := t.footers[i] - if t.autoFmt { - f = Title(f) - } - pad := ConditionString((i == end && !t.borders.Top), SPACE, t.pColumn) + // Maximum height. + max := t.rs[footerRowIdx] - if len(t.footers[i]) == 0 { - pad = SPACE - } + // Print Footer + erasePad := make([]bool, len(t.footers)) + for x := 0; x < max; x++ { + // Check if border is set + // Replace with space if not set + fmt.Fprint(t.out, ConditionString(t.borders.Bottom, t.pColumn, SPACE)) - if is_esc_seq { - fmt.Fprintf(t.out, " %s %s", - format(padFunc(f, SPACE, v), - t.footerParams[i]), pad) - } else { - fmt.Fprintf(t.out, " %s %s", - padFunc(f, SPACE, v), - pad) - } + for y := 0; y <= end; y++ { + v := t.cs[y] + f := "" + if y < len(t.footers) && x < len(t.footers[y]) { + f = t.footers[y][x] + } + if t.autoFmt { + f = Title(f) + } + pad := ConditionString((y == end && !t.borders.Top), SPACE, t.pColumn) - //fmt.Fprintf(t.out, " %s %s", - // padFunc(f, SPACE, v), - // pad) + if erasePad[y] || (x == 0 && len(f) == 0) { + pad = SPACE + erasePad[y] = true + } + + if is_esc_seq { + fmt.Fprintf(t.out, " %s %s", + format(padFunc(f, SPACE, v), + t.footerParams[y]), pad) + } else { + fmt.Fprintf(t.out, " %s %s", + padFunc(f, SPACE, v), + pad) + } + + //fmt.Fprintf(t.out, " %s %s", + // padFunc(f, SPACE, v), + // pad) + } + // Next line + fmt.Fprint(t.out, t.newLine) + //t.printLine(true) } - // Next line - fmt.Fprint(t.out, t.newLine) - //t.printLine(true) hasPrinted := false @@ -477,7 +504,7 @@ func (t *Table) printFooter() { v := t.cs[i] pad := t.pRow center := t.pCenter - length := len(t.footers[i]) + length := len(t.footers[i][0]) if length > 0 { hasPrinted = true @@ -505,7 +532,7 @@ func (t *Table) printFooter() { // Change Center start position if center == SPACE { - if i < end && len(t.footers[i+1]) != 0 { + if i < end && len(t.footers[i+1][0]) != 0 { center = t.pCenter } } @@ -564,9 +591,9 @@ func (t *Table) fillAlignment(num int) { // Print Row Information // Adjust column alignment based on type -func (t *Table) printRow(columns [][]string, colKey int) { +func (t *Table) printRow(columns [][]string, rowIdx int) { // Get Maximum Height - max := t.rs[colKey] + max := t.rs[rowIdx] total := len(columns) // TODO Fix uneven col size @@ -578,7 +605,6 @@ func (t *Table) printRow(columns [][]string, colKey int) { //} // Pad Each Height - // pads := []int{} pads := []int{} // Checking for ANSI escape sequences for columns @@ -672,9 +698,9 @@ func (t *Table) printRowsMergeCells() { // Print Row Information to a writer and merge identical cells. // Adjust column alignment based on type -func (t *Table) printRowMergeCells(writer io.Writer, columns [][]string, colKey int, previousLine []string) ([]string, []bool) { +func (t *Table) printRowMergeCells(writer io.Writer, columns [][]string, rowIdx int, previousLine []string) ([]string, []bool) { // Get Maximum Height - max := t.rs[colKey] + max := t.rs[rowIdx] total := len(columns) // Pad Each Height @@ -749,44 +775,59 @@ func (t *Table) printRowMergeCells(writer io.Writer, columns [][]string, colKey func (t *Table) parseDimension(str string, colKey, rowKey int) []string { var ( - raw []string - max int + raw []string + maxWidth int ) - w := DisplayWidth(str) - // Calculate Width - // Check if with is grater than maximum width - if w > t.mW { - w = t.mW - } - - // Check if width exists - v, ok := t.cs[colKey] - if !ok || v < w || v == 0 { - t.cs[colKey] = w - } - - if rowKey == -1 { - return raw - } - // Calculate Height - if t.autoWrap { - raw, _ = WrapString(str, t.cs[colKey]) - } else { - raw = getLines(str) - } + raw = getLines(str) + maxWidth = 0 for _, line := range raw { - if w := DisplayWidth(line); w > max { - max = w + if w := DisplayWidth(line); w > maxWidth { + maxWidth = w } } - // Make sure the with is the same length as maximum word - // Important for cases where the width is smaller than maxu word - if max > t.cs[colKey] { - t.cs[colKey] = max + // If wrapping, ensure that all paragraphs in the cell fit in the + // specified width. + if t.autoWrap { + // If there's a maximum allowed width for wrapping, use that. + if maxWidth > t.mW { + maxWidth = t.mW + } + + // In the process of doing so, we need to recompute maxWidth. This + // is because perhaps a word in the cell is longer than the + // allowed maximum width in t.mW. + newMaxWidth := maxWidth + newRaw := make([]string, 0, len(raw)) + + if t.reflowText { + // Make a single paragraph of everything. + raw = []string{strings.Join(raw, " ")} + } + for i, para := range raw { + paraLines, _ := WrapString(para, maxWidth) + for _, line := range paraLines { + if w := DisplayWidth(line); w > newMaxWidth { + newMaxWidth = w + } + } + if i > 0 { + newRaw = append(newRaw, " ") + } + newRaw = append(newRaw, paraLines...) + } + raw = newRaw + maxWidth = newMaxWidth } + // Store the new known maximum width. + v, ok := t.cs[colKey] + if !ok || v < maxWidth || v == 0 { + t.cs[colKey] = maxWidth + } + + // Remember the number of lines for the row printer. h := len(raw) v, ok = t.rs[rowKey] diff --git a/vendor/github.com/olekukonko/tablewriter/util.go b/vendor/github.com/olekukonko/tablewriter/util.go index 2deefbc5..9e8f0cbb 100644 --- a/vendor/github.com/olekukonko/tablewriter/util.go +++ b/vendor/github.com/olekukonko/tablewriter/util.go @@ -30,12 +30,33 @@ func ConditionString(cond bool, valid, inValid string) string { return inValid } +func isNumOrSpace(r rune) bool { + return ('0' <= r && r <= '9') || r == ' ' +} + // Format Table Header // Replace _ , . and spaces func Title(name string) string { - name = strings.Replace(name, "_", " ", -1) - name = strings.Replace(name, ".", " ", -1) + origLen := len(name) + rs := []rune(name) + for i, r := range rs { + switch r { + case '_': + rs[i] = ' ' + case '.': + // ignore floating number 0.0 + if (i != 0 && !isNumOrSpace(rs[i-1])) || (i != len(rs)-1 && !isNumOrSpace(rs[i+1])) { + rs[i] = ' ' + } + } + } + name = string(rs) name = strings.TrimSpace(name) + if len(name) == 0 && origLen > 0 { + // Keep at least one character. This is important to preserve + // empty lines in multi-line headers/footers. + name = " " + } return strings.ToUpper(name) } diff --git a/vendor/github.com/olekukonko/tablewriter/wrap.go b/vendor/github.com/olekukonko/tablewriter/wrap.go index 9ef69e90..a092ee1f 100644 --- a/vendor/github.com/olekukonko/tablewriter/wrap.go +++ b/vendor/github.com/olekukonko/tablewriter/wrap.go @@ -95,10 +95,5 @@ func WrapWords(words []string, spc, lim, pen int) [][]string { // getLines decomposes a multiline string into a slice of strings. func getLines(s string) []string { - var lines []string - - for _, line := range strings.Split(s, nl) { - lines = append(lines, line) - } - return lines + return strings.Split(s, nl) } diff --git a/vendor/gonum.org/v1/plot/align.go b/vendor/gonum.org/v1/plot/align.go index 523965ff..542f3611 100644 --- a/vendor/gonum.org/v1/plot/align.go +++ b/vendor/gonum.org/v1/plot/align.go @@ -63,10 +63,12 @@ func Align(plots [][]*Plot, t draw.Tiles, dc draw.Canvas) [][]draw.Canvas { for _, s := range xSpacing { xTotalSpace += s.n + s.p } + xTotalSpace += float64(t.PadX) * float64(len(xSpacing)-1) var yTotalSpace float64 for _, s := range ySpacing { yTotalSpace += s.n + s.p } + yTotalSpace += float64(t.PadY) * float64(len(ySpacing)-1) avgWidth := vg.Length((float64(dc.Max.X-dc.Min.X) - xTotalSpace) / float64(t.Cols)) avgHeight := vg.Length((float64(dc.Max.Y-dc.Min.Y) - yTotalSpace) / float64(t.Rows)) diff --git a/vendor/gonum.org/v1/plot/legend.go b/vendor/gonum.org/v1/plot/legend.go index 69e51144..baaa61cb 100644 --- a/vendor/gonum.org/v1/plot/legend.go +++ b/vendor/gonum.org/v1/plot/legend.go @@ -5,6 +5,8 @@ package plot import ( + "math" + "gonum.org/v1/plot/vg" "gonum.org/v1/plot/vg/draw" ) @@ -67,9 +69,9 @@ type Thumbnailer interface { Thumbnail(c *draw.Canvas) } -// makeLegend returns a legend with the default +// NewLegend returns a legend with the default // parameter settings. -func makeLegend() (Legend, error) { +func NewLegend() (Legend, error) { font, err := vg.MakeFont(DefaultFont, vg.Points(12)) if err != nil { return Legend{}, err @@ -80,8 +82,8 @@ func makeLegend() (Legend, error) { }, nil } -// draw draws the legend to the given draw.Canvas. -func (l *Legend) draw(c draw.Canvas) { +// Draw draws the legend to the given draw.Canvas. +func (l *Legend) Draw(c draw.Canvas) { iconx := c.Min.X sty := l.TextStyle textx := iconx + l.ThumbnailWidth + sty.Rectangle(" ").Max.X @@ -118,6 +120,36 @@ func (l *Legend) draw(c draw.Canvas) { } } +// Rectangle returns the extent of the Legend. +func (l *Legend) Rectangle(c draw.Canvas) vg.Rectangle { + var width, height vg.Length + sty := l.TextStyle + entryHeight := l.entryHeight() + for i, e := range l.entries { + width = vg.Length(math.Max(float64(width), float64(l.ThumbnailWidth+sty.Rectangle(" "+e.text).Max.X))) + height += entryHeight + if i != 0 { + height += l.Padding + } + } + var r vg.Rectangle + if l.Left { + r.Max.X = c.Max.X + r.Min.X = c.Max.X - width + } else { + r.Max.X = c.Min.X + width + r.Min.X = c.Min.X + } + if l.Top { + r.Max.Y = c.Max.Y + r.Min.Y = c.Max.Y - height + } else { + r.Max.Y = c.Min.Y + height + r.Min.Y = c.Min.Y + } + return r +} + // entryHeight returns the height of the tallest legend // entry text. func (l *Legend) entryHeight() (height vg.Length) { diff --git a/vendor/gonum.org/v1/plot/plot.go b/vendor/gonum.org/v1/plot/plot.go index 01ee57d9..019df552 100644 --- a/vendor/gonum.org/v1/plot/plot.go +++ b/vendor/gonum.org/v1/plot/plot.go @@ -89,7 +89,7 @@ func New() (*Plot, error) { if err != nil { return nil, err } - legend, err := makeLegend() + legend, err := NewLegend() if err != nil { return nil, err } @@ -165,7 +165,7 @@ func (p *Plot) Draw(c draw.Canvas) { data.Plot(dataC, p) } - p.Legend.draw(draw.Crop(c, ywidth, 0, xheight, 0)) + p.Legend.Draw(draw.Crop(c, ywidth, 0, xheight, 0)) } // DataCanvas returns a new draw.Canvas that diff --git a/vendor/gonum.org/v1/plot/plotter/colorbar.go b/vendor/gonum.org/v1/plot/plotter/colorbar.go index c2bac2b4..1e77276d 100644 --- a/vendor/gonum.org/v1/plot/plotter/colorbar.go +++ b/vendor/gonum.org/v1/plot/plotter/colorbar.go @@ -9,7 +9,6 @@ import ( "gonum.org/v1/plot" "gonum.org/v1/plot/palette" - "gonum.org/v1/plot/vg" "gonum.org/v1/plot/vg/draw" ) @@ -56,16 +55,10 @@ func (l *ColorBar) check() { func (l *ColorBar) Plot(c draw.Canvas, p *plot.Plot) { l.check() colors := l.colors(c) - var img *image.NRGBA64 - var xmin, xmax, ymin, ymax vg.Length + var pImg *Image delta := (l.ColorMap.Max() - l.ColorMap.Min()) / float64(colors) if l.Vertical { - trX, trY := p.Transforms(&c) - xmin = trX(0) - ymin = trY(l.ColorMap.Min()) - xmax = trX(1) - ymax = trY(l.ColorMap.Max()) - img = image.NewNRGBA64(image.Rectangle{ + img := image.NewNRGBA64(image.Rectangle{ Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 1, Y: colors}, }) @@ -76,13 +69,9 @@ func (l *ColorBar) Plot(c draw.Canvas, p *plot.Plot) { } img.Set(0, colors-1-i, color) } + pImg = NewImage(img, 0, l.ColorMap.Min(), 1, l.ColorMap.Max()) } else { - trX, trY := p.Transforms(&c) - xmin = trX(l.ColorMap.Min()) - ymin = trY(0) - xmax = trX(l.ColorMap.Max()) - ymax = trY(1) - img = image.NewNRGBA64(image.Rectangle{ + img := image.NewNRGBA64(image.Rectangle{ Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: colors, Y: 1}, }) @@ -93,12 +82,9 @@ func (l *ColorBar) Plot(c draw.Canvas, p *plot.Plot) { } img.Set(i, 0, color) } + pImg = NewImage(img, l.ColorMap.Min(), 0, l.ColorMap.Max(), 1) } - rect := vg.Rectangle{ - Min: vg.Point{X: xmin, Y: ymin}, - Max: vg.Point{X: xmax, Y: ymax}, - } - c.DrawImage(rect, img) + pImg.Plot(c, p) } // DataRange implements the DataRange method diff --git a/vendor/gonum.org/v1/plot/plotter/image.go b/vendor/gonum.org/v1/plot/plotter/image.go index 19c5c265..86b36fb2 100644 --- a/vendor/gonum.org/v1/plot/plotter/image.go +++ b/vendor/gonum.org/v1/plot/plotter/image.go @@ -56,7 +56,7 @@ func (img *Image) Plot(c draw.Canvas, p *plot.Plot) { Min: vg.Point{X: xmin, Y: ymin}, Max: vg.Point{X: xmax, Y: ymax}, } - c.DrawImage(rect, img.img) + c.DrawImage(rect, img.transformFor(p)) } // DataRange implements the DataRange method @@ -71,6 +71,48 @@ func (img *Image) GlyphBoxes(plt *plot.Plot) []plot.GlyphBox { return nil } +// transform warps the image to align with non-linear axes. +func (img *Image) transformFor(p *plot.Plot) image.Image { + _, xLinear := p.X.Scale.(plot.LinearScale) + _, yLinear := p.Y.Scale.(plot.LinearScale) + if xLinear && yLinear { + return img.img + } + b := img.img.Bounds() + o := image.NewNRGBA64(b) + for c := 0; c < img.cols; c++ { + // Find the equivalent image column after applying axis transforms. + cTrans := int(p.X.Norm(img.x(c)) * float64(img.cols)) + // Find the equivalent column of the previous image column after applying + // axis transforms. + cPrevTrans := int(p.X.Norm(img.x(maxInt(c-1, 0))) * float64(img.cols)) + for r := 0; r < img.rows; r++ { + // Find the equivalent image row after applying axis transforms. + rTrans := int(p.Y.Norm(img.y(r)) * float64(img.rows)) + // Find the equivalent row of the previous image row after applying + // axis transforms. + rPrevTrans := int(p.Y.Norm(img.y(maxInt(r-1, 0))) * float64(img.rows)) + crColor := img.img.At(c, img.rows-r-1) + // Set all the pixels in the new image between (cPrevTrans, rPrevTrans) + // and (cTrans, rTrans) to the color at (c,r) in the original image. + // TODO: Improve interpolation. + for cPrime := cPrevTrans; cPrime <= cTrans; cPrime++ { + for rPrime := rPrevTrans; rPrime <= rTrans; rPrime++ { + o.Set(cPrime, img.rows-rPrime-1, crColor) + } + } + } + } + return o +} + +func maxInt(a, b int) int { + if a > b { + return a + } + return b +} + func (img *Image) x(c int) float64 { if c >= img.cols || c < 0 { panic("plotter/image: illegal range") diff --git a/vendor/gonum.org/v1/plot/vg/vgeps/vgeps.go b/vendor/gonum.org/v1/plot/vg/vgeps/vgeps.go index 5a52e8b6..0228d5a0 100644 --- a/vendor/gonum.org/v1/plot/vg/vgeps/vgeps.go +++ b/vendor/gonum.org/v1/plot/vg/vgeps/vgeps.go @@ -23,12 +23,12 @@ import ( const DPI = 72 type Canvas struct { - stk []ctx - w, h vg.Length - buf *bytes.Buffer + stack []context + w, h vg.Length + buf *bytes.Buffer } -type ctx struct { +type context struct { color color.Color width vg.Length dashes []vg.Length @@ -48,10 +48,10 @@ func New(w, h vg.Length) *Canvas { // NewTitle returns a new Canvas with the given title string. func NewTitle(w, h vg.Length, title string) *Canvas { c := &Canvas{ - stk: []ctx{ctx{}}, - w: w, - h: h, - buf: new(bytes.Buffer), + stack: []context{context{}}, + w: w, + h: h, + buf: new(bytes.Buffer), } c.buf.WriteString("%%!PS-Adobe-3.0 EPSF-3.0\n") c.buf.WriteString("%%Creator gonum.org/v1/plot/vg/vgeps\n") @@ -71,29 +71,29 @@ func (c *Canvas) Size() (w, h vg.Length) { return c.w, c.h } -// cur returns the top context on the stack. -func (e *Canvas) cur() *ctx { - return &e.stk[len(e.stk)-1] +// context returns the top context on the stack. +func (e *Canvas) context() *context { + return &e.stack[len(e.stack)-1] } func (e *Canvas) SetLineWidth(w vg.Length) { - if e.cur().width != w { - e.cur().width = w + if e.context().width != w { + e.context().width = w fmt.Fprintf(e.buf, "%.*g setlinewidth\n", pr, w.Dots(DPI)) } } func (e *Canvas) SetLineDash(dashes []vg.Length, o vg.Length) { - cur := e.cur().dashes + cur := e.context().dashes dashEq := len(dashes) == len(cur) for i := 0; dashEq && i < len(dashes); i++ { if dashes[i] != cur[i] { dashEq = false } } - if !dashEq || e.cur().offs != o { - e.cur().dashes = dashes - e.cur().offs = o + if !dashEq || e.context().offs != o { + e.context().dashes = dashes + e.context().offs = o e.buf.WriteString("[") for _, d := range dashes { fmt.Fprintf(e.buf, " %.*g", pr, d.Dots(DPI)) @@ -107,8 +107,8 @@ func (e *Canvas) SetColor(c color.Color) { if c == nil { c = color.Black } - if e.cur().color != c { - e.cur().color = c + if e.context().color != c { + e.context().color = c r, g, b, _ := c.RGBA() mx := float64(math.MaxUint16) fmt.Fprintf(e.buf, "%.*g %.*g %.*g setrgbcolor\n", pr, float64(r)/mx, @@ -130,17 +130,17 @@ func (e *Canvas) Scale(x, y float64) { } func (e *Canvas) Push() { - e.stk = append(e.stk, *e.cur()) + e.stack = append(e.stack, *e.context()) e.buf.WriteString("gsave\n") } func (e *Canvas) Pop() { - e.stk = e.stk[:len(e.stk)-1] + e.stack = e.stack[:len(e.stack)-1] e.buf.WriteString("grestore\n") } func (e *Canvas) Stroke(path vg.Path) { - if e.cur().width <= 0 { + if e.context().width <= 0 { return } e.trace(path) @@ -178,9 +178,9 @@ func (e *Canvas) trace(path vg.Path) { } func (e *Canvas) FillString(fnt vg.Font, pt vg.Point, str string) { - if e.cur().font != fnt.Name() || e.cur().fsize != fnt.Size { - e.cur().font = fnt.Name() - e.cur().fsize = fnt.Size + if e.context().font != fnt.Name() || e.context().fsize != fnt.Size { + e.context().font = fnt.Name() + e.context().fsize = fnt.Size fmt.Fprintf(e.buf, "/%s findfont %.*g scalefont setfont\n", fnt.Name(), pr, fnt.Size) } diff --git a/vendor/gonum.org/v1/plot/vg/vgsvg/vgsvg.go b/vendor/gonum.org/v1/plot/vg/vgsvg/vgsvg.go index 818c9d89..aadec497 100644 --- a/vendor/gonum.org/v1/plot/vg/vgsvg/vgsvg.go +++ b/vendor/gonum.org/v1/plot/vg/vgsvg/vgsvg.go @@ -31,11 +31,11 @@ const DPI = 90 const pr = 5 type Canvas struct { - svg *svgo.SVG - w, h vg.Length - buf *bytes.Buffer - ht float64 - stk []context + svg *svgo.SVG + w, h vg.Length + buf *bytes.Buffer + ht float64 + stack []context } type context struct { @@ -49,12 +49,12 @@ type context struct { func New(w, h vg.Length) *Canvas { buf := new(bytes.Buffer) c := &Canvas{ - svg: svgo.New(buf), - w: w, - h: h, - buf: buf, - ht: w.Points(), - stk: []context{context{}}, + svg: svgo.New(buf), + w: w, + h: h, + buf: buf, + ht: w.Points(), + stack: []context{context{}}, } // This is like svg.Start, except it uses floats @@ -81,69 +81,69 @@ func (c *Canvas) Size() (w, h vg.Length) { return c.w, c.h } -func (c *Canvas) cur() *context { - return &c.stk[len(c.stk)-1] +func (c *Canvas) context() *context { + return &c.stack[len(c.stack)-1] } func (c *Canvas) SetLineWidth(w vg.Length) { - c.cur().lineWidth = w + c.context().lineWidth = w } func (c *Canvas) SetLineDash(dashes []vg.Length, offs vg.Length) { - c.cur().dashArray = dashes - c.cur().dashOffset = offs + c.context().dashArray = dashes + c.context().dashOffset = offs } func (c *Canvas) SetColor(clr color.Color) { - c.cur().color = clr + c.context().color = clr } func (c *Canvas) Rotate(rot float64) { rot = rot * 180 / math.Pi c.svg.Rotate(rot) - c.cur().gEnds++ + c.context().gEnds++ } func (c *Canvas) Translate(pt vg.Point) { c.svg.Gtransform(fmt.Sprintf("translate(%.*g, %.*g)", pr, pt.X.Dots(DPI), pr, pt.Y.Dots(DPI))) - c.cur().gEnds++ + c.context().gEnds++ } func (c *Canvas) Scale(x, y float64) { c.svg.ScaleXY(x, y) - c.cur().gEnds++ + c.context().gEnds++ } func (c *Canvas) Push() { - top := *c.cur() + top := *c.context() top.gEnds = 0 - c.stk = append(c.stk, top) + c.stack = append(c.stack, top) } func (c *Canvas) Pop() { - for i := 0; i < c.cur().gEnds; i++ { + for i := 0; i < c.context().gEnds; i++ { c.svg.Gend() } - c.stk = c.stk[:len(c.stk)-1] + c.stack = c.stack[:len(c.stack)-1] } func (c *Canvas) Stroke(path vg.Path) { - if c.cur().lineWidth.Dots(DPI) <= 0 { + if c.context().lineWidth.Dots(DPI) <= 0 { return } c.svg.Path(c.pathData(path), style(elm("fill", "#000000", "none"), - elm("stroke", "none", colorString(c.cur().color)), - elm("stroke-opacity", "1", opacityString(c.cur().color)), - elm("stroke-width", "1", "%.*g", pr, c.cur().lineWidth.Dots(DPI)), + elm("stroke", "none", colorString(c.context().color)), + elm("stroke-opacity", "1", opacityString(c.context().color)), + elm("stroke-width", "1", "%.*g", pr, c.context().lineWidth.Dots(DPI)), elm("stroke-dasharray", "none", dashArrayString(c)), - elm("stroke-dashoffset", "0", "%.*g", pr, c.cur().dashOffset.Dots(DPI)))) + elm("stroke-dashoffset", "0", "%.*g", pr, c.context().dashOffset.Dots(DPI)))) } func (c *Canvas) Fill(path vg.Path) { c.svg.Path(c.pathData(path), - style(elm("fill", "#000000", colorString(c.cur().color)), - elm("fill-opacity", "1", opacityString(c.cur().color)))) + style(elm("fill", "#000000", colorString(c.context().color)), + elm("fill-opacity", "1", opacityString(c.context().color)))) } func (c *Canvas) pathData(path vg.Path) string { @@ -253,7 +253,7 @@ func (c *Canvas) FillString(font vg.Font, pt vg.Point, str string) { } sty := style(fontStr, elm("font-size", "medium", "%.*gpt", pr, font.Size.Points()), - elm("fill", "#000000", colorString(c.cur().color))) + elm("fill", "#000000", colorString(c.context().color))) if sty != "" { sty = "\n\t" + sty } @@ -341,7 +341,7 @@ func (c *Canvas) WriteTo(w io.Writer) (int64, error) { // needed before the SVG is saved. func (c *Canvas) nEnds() int { n := 1 // close the transform that moves the origin - for _, ctx := range c.stk { + for _, ctx := range c.stack { n += ctx.gEnds } return n @@ -383,9 +383,9 @@ func elm(key, def, f string, vls ...interface{}) string { // dash array specification. func dashArrayString(c *Canvas) string { str := "" - for i, d := range c.cur().dashArray { + for i, d := range c.context().dashArray { str += fmt.Sprintf("%.*g", pr, d.Dots(DPI)) - if i < len(c.cur().dashArray)-1 { + if i < len(c.context().dashArray)-1 { str += "," } }