github.com/wrgl/wrgl@v0.14.0/pkg/widgets/prof/stat_table.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright © 2022 Wrangle Ltd 3 4 package widgetsprof 5 6 import ( 7 "fmt" 8 "strings" 9 10 "github.com/gdamore/tcell/v2" 11 "github.com/rivo/tview" 12 "github.com/wrgl/wrgl/pkg/objects" 13 "github.com/wrgl/wrgl/pkg/widgets" 14 ) 15 16 func floatString(f float64) string { 17 return strings.TrimRight(strings.TrimRight(fmt.Sprintf("%f", f), "0"), ".") 18 } 19 20 var ( 21 cellStyle = tcell.StyleDefault.Foreground(tcell.ColorWhite).Background(tcell.ColorBlack) 22 columnStyle = tcell.StyleDefault.Background(tcell.ColorBlack).Bold(true) 23 pctStyle = tcell.StyleDefault.Foreground(tcell.ColorLightGray).Background(tcell.ColorBlack) 24 statNameStyle = tcell.StyleDefault.Foreground(tcell.ColorAqua).Background(tcell.ColorBlack).Bold(true) 25 statValueStyle = tcell.StyleDefault.Foreground(tcell.ColorYellow).Background(tcell.ColorBlack) 26 addedStyle = cellStyle.Foreground(tcell.ColorGreen) 27 removedStyle = cellStyle.Foreground(tcell.ColorRed) 28 29 statCells = []StatCells{ 30 newSingleStatCells("NA count", func(colProf *objects.ColumnProfile) string { 31 return fmt.Sprintf("%d", colProf.NACount) 32 }), 33 newSingleStatCells("Min", func(colProf *objects.ColumnProfile) string { 34 if colProf.Min == nil { 35 return "" 36 } 37 return floatString(*colProf.Min) 38 }), 39 newSingleStatCells("Max", func(colProf *objects.ColumnProfile) string { 40 if colProf.Max == nil { 41 return "" 42 } 43 return floatString(*colProf.Max) 44 }), 45 newSingleStatCells("Mean", func(colProf *objects.ColumnProfile) string { 46 if colProf.Mean == nil { 47 return "" 48 } 49 return floatString(*colProf.Mean) 50 }), 51 newSingleStatCells("Median", func(colProf *objects.ColumnProfile) string { 52 if colProf.Median == nil { 53 return "" 54 } 55 return floatString(*colProf.Median) 56 }), 57 newSingleStatCells("Std. Deviation", func(colProf *objects.ColumnProfile) string { 58 if colProf.StdDeviation == nil { 59 return "" 60 } 61 return floatString(*colProf.StdDeviation) 62 }), 63 newSingleStatCells("Min length", func(colProf *objects.ColumnProfile) string { 64 if colProf.MinStrLen == 0 { 65 return "" 66 } 67 return fmt.Sprintf("%d", colProf.MinStrLen) 68 }), 69 newSingleStatCells("Max length", func(colProf *objects.ColumnProfile) string { 70 if colProf.MaxStrLen == 0 { 71 return "" 72 } 73 return fmt.Sprintf("%d", colProf.MaxStrLen) 74 }), 75 newSingleStatCells("Avg length", func(colProf *objects.ColumnProfile) string { 76 if colProf.AvgStrLen == 0 { 77 return "" 78 } 79 return fmt.Sprintf("%d", colProf.AvgStrLen) 80 }), 81 newTopValuesCells("Top values", func(colProf *objects.ColumnProfile) objects.ValueCounts { return colProf.TopValues }), 82 newPercentilesCells("Percentiles", func(colProf *objects.ColumnProfile) []float64 { return colProf.Percentiles }), 83 } 84 ) 85 86 type StatTable struct { 87 *widgets.SelectableTable 88 pool *widgets.CellsPool 89 tblProf *objects.TableProfile 90 rowsPerStat []int 91 statCells []StatCells 92 } 93 94 func NewStatTable(tblProf *objects.TableProfile) *StatTable { 95 t := &StatTable{ 96 SelectableTable: widgets.NewSelectableTable(), 97 tblProf: tblProf, 98 } 99 t.SelectableTable.SetGetCellsFunc(t.getCells). 100 SetMinSelection(1, 1). 101 Select(1, 1, 0) 102 totalRows := t.calculateRowsCount() 103 t.VirtualTable.SetFixed(1, 1). 104 SetShape(totalRows+1, len(tblProf.Columns)+1). 105 SetSeparator('│') 106 t.pool = widgets.NewCellsPool(t.VirtualTable) 107 return t 108 } 109 110 func (t *StatTable) calculateRowsCount() int { 111 totalRows := 0 112 for _, sc := range statCells { 113 c := 0 114 for _, col := range t.tblProf.Columns { 115 if v := sc.NumRows(col); v > c { 116 c = v 117 } 118 } 119 if c > 0 { 120 t.rowsPerStat = append(t.rowsPerStat, c) 121 totalRows += c 122 t.statCells = append(t.statCells, sc) 123 } 124 } 125 return totalRows 126 } 127 128 func (t *StatTable) getCells(row, column int) []*widgets.TableCell { 129 if row == 0 { 130 if column == 0 { 131 return nil 132 } 133 cells, ok := t.pool.Get(row, column, 1) 134 if !ok { 135 cells[0].SetText(t.tblProf.Columns[column-1].Name). 136 SetStyle(columnStyle). 137 SetAlign(tview.AlignCenter) 138 } 139 return cells 140 } 141 sum := 0 142 var sc StatCells 143 var statRow int 144 for i, rowsCount := range t.rowsPerStat { 145 sum += rowsCount 146 if sum > row-1 { 147 sc = t.statCells[i] 148 statRow = row - 1 - sum + rowsCount 149 break 150 } 151 } 152 if column == 0 { 153 cells, ok := t.pool.Get(row, column, 1) 154 if !ok && statRow == 0 { 155 cells[0].SetText(sc.Name()).SetStyle(statNameStyle) 156 } 157 return cells 158 } 159 cells, ok := t.pool.Get(row, column, sc.NumColumns()) 160 if !ok { 161 cp := t.tblProf.Columns[column-1] 162 if statRow < sc.NumRows(cp) { 163 sc.DecorateCells(statRow, t.tblProf, cp, cells) 164 } 165 } 166 return cells 167 }