Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[graph] labels: add tick symbol, int precision, right margin #1931

Merged
merged 4 commits into from
Jun 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 15 additions & 4 deletions visidata/canvas.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,8 @@ def plotlabel(self, x, y, text, attr=0, row=None):
self.labels.append((x, y, text, attr, row))

def plotlegend(self, i, txt, attr=0, width=15):
self.plotlabel(self.plotwidth-width*2, i*4, txt, attr)
# move it 1 character to the left b/c the rightmost column can't be drawn to
self.plotlabel(self.plotwidth-(width+1)*2, i*4, txt, attr)

@property
def plotterCursorBox(self):
Expand Down Expand Up @@ -374,10 +375,19 @@ def resetCanvasDimensions(self, windowHeight, windowWidth):
if self.cursorBox.xmin == self.visibleBox.xmin and self.cursorBox.ymin == self.calcBottomCursorY():
realign_cursor = True
super().resetCanvasDimensions(windowHeight, windowWidth)
if hasattr(self, 'legendwidth'):
# +4 = 1 empty space after the graph + 2 characters for the legend prefixes of "1:", "2:", etc +
# 1 character for the empty rightmost column
new_margin = max(self.rightMarginPixels, (self.legendwidth+4)*2)
pvbox_w = self.plotwidth-new_margin-1
# ensure the graph data takes up at least 3/4 of the width of the screen no matter how wide the legend gets
pvbox_w = max(pvbox_w, math.ceil(self.plotwidth * 3/4)//2*2 + 1)
else:
pvbox_w = self.plotwidth-self.rightMarginPixels-1
self.plotviewBox = BoundingBox(self.leftMarginPixels, self.topMarginPixels,
self.plotwidth-self.rightMarginPixels-1, self.plotheight-self.bottomMarginPixels-1)
pvbox_w, self.plotheight-self.bottomMarginPixels-1)
if [self.plotheight, self.plotwidth] != old_plotsize:
if hasattr(self, 'cursorBox'):
if hasattr(self, 'cursorBox') and self.cursorBox:
self.setCursorSizeInPlotterPixels(2, 4)
if realign_cursor:
self.cursorBox.ymin = self.calcBottomCursorY()
Expand Down Expand Up @@ -550,7 +560,8 @@ def plotlegends(self):
self.addCommand(str(i+1), 'toggle-%s'%(i+1), 'hideAttr(%s, %s not in hiddenAttrs)' % (attr, attr), 'toggle display of "%s"' % legend)
if attr in self.hiddenAttrs:
attr = colors.color_graph_hidden
self.plotlegend(i, '%s:%s'%(i+1,legend), attr, width=self.legendwidth+4)
# add 2 characters to width to account for '1:' '2:' etc
self.plotlegend(i, '%s:%s'%(i+1,legend), attr, width=self.legendwidth+2)

def checkCursor(self):
'override Sheet.checkCursor'
Expand Down
41 changes: 36 additions & 5 deletions visidata/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import math

vd.option('color_graph_axis', 'bold', 'color for graph axis labels')
vd.option('disp_graph_tick_x', '╵', 'character for graph x-axis ticks')


@VisiData.api
Expand Down Expand Up @@ -114,28 +115,58 @@ def formatY(self, amt):
srccol = self.ycols[0]
return srccol.format(srccol.type(amt))

def formatXLabel(self, amt):
if self.xzoomlevel < 1:
labels = []
for xcol in self.xcols:
if vd.isNumeric(xcol):
col_amt = float(amt) if xcol.type is int else xcol.type(amt)
else:
continue
labels.append(xcol.format(col_amt))
return ','.join(labels)
else:
return self.formatX(amt)

def formatYLabel(self, amt):
srccol = self.ycols[0]
if srccol.type is int and self.yzoomlevel < 1:
return srccol.format(float(amt))
else:
return self.formatY(amt)

def parseX(self, txt):
return self.xcols[0].type(txt)

def parseY(self, txt):
return self.ycols[0].type(txt)

def add_y_axis_label(self, frac):
txt = self.formatY(self.visibleBox.ymin + frac*self.visibleBox.h)
txt = self.formatYLabel(self.visibleBox.ymin + frac*self.visibleBox.h)

# plot y-axis labels on the far left of the canvas, but within the plotview height-wise
attr = colors.color_graph_axis
self.plotlabel(0, self.plotviewBox.ymin + (1.0-frac)*self.plotviewBox.h, txt, attr)

def add_x_axis_label(self, frac):
txt = self.formatX(self.visibleBox.xmin + frac*self.visibleBox.w)
txt = self.formatXLabel(self.visibleBox.xmin + frac*self.visibleBox.w)
tick = vd.options.disp_graph_tick_x or ''

# plot x-axis labels below the plotviewBox.ymax, but within the plotview width-wise
attr = colors.color_graph_axis
x = self.plotviewBox.xmin + frac*self.plotviewBox.w
if frac == 1.0:
# shift rightmost label to be readable
x -= 2*max(len(txt) - math.ceil(self.rightMarginPixels/2), 0)

if frac < 1.0:
txt = tick + txt
else:
if (len(txt)+len(tick))*2 <= self.rightMarginPixels:
txt = tick + txt
else:
# shift rightmost label to be left of its tick
x -= len(txt)*2
if len(tick) == 0:
x += 1
txt = txt + tick

self.plotlabel(x, self.plotviewBox.ymax+4, txt, attr)

Expand Down