Skip to content

Commit

Permalink
[canvas-] draw lines at user-defined x or y
Browse files Browse the repository at this point in the history
  • Loading branch information
midichef committed Aug 6, 2024
1 parent 8f823f5 commit 752be13
Showing 1 changed file with 65 additions and 1 deletion.
66 changes: 65 additions & 1 deletion visidata/canvas.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@
vd.theme_option('disp_graph_labels', True, 'show axes and legend on graph')
vd.theme_option('plot_colors', 'green red yellow cyan magenta white 38 136 168', 'list of distinct colors to use for plotting distinct objects')
vd.theme_option('disp_canvas_charset', ''.join(chr(0x2800+i) for i in range(256)), 'charset to render 2x4 blocks on canvas')
vd.theme_option('disp_graph_lines_x_charset', '▏┃┃▕', 'charset to render vertical lines on graph')
vd.theme_option('disp_graph_lines_y_charset', '▁━━▔', 'charset to render horizontal lines on graph')
vd.theme_option('disp_graph_multiple_lines_char', '▒', 'char to render multiple parallel lines')
vd.theme_option('color_gridline', '', 'color for graph grid lines')

vd.theme_option('disp_pixel_random', False, 'randomly choose attr from set of pixels instead of most common')
vd.theme_option('disp_zoom_incr', 2.0, 'amount to multiply current zoomlevel when zooming')
vd.theme_option('color_graph_hidden', '238 blue', 'color of legend for hidden attribute')
Expand Down Expand Up @@ -173,6 +178,40 @@ def plotlegend(self, i, txt, attr:"str|ColorAttr=''", width=15):
# 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)

def plot_gridlines(self, invert_y=False):
self.gridlines_char_x = {}
self.gridlines_char_y = {}

bb = self.visibleBox
xmin, ymin, xmax, ymax = bb.xmin, bb.ymin, bb.xmax, bb.ymax

for data_y in self.gridlines_y:
if data_y >= ymin and data_y <= ymax:
char_y, offset = divmod(self.scaleY(data_y), 4)
chars = self.options.disp_graph_lines_y_charset
if invert_y:
chars = chars[::-1]
# if we're drawing two different guide_lines in the same square, fill it with a different char
if char_y in self.gridlines_char_y and self.gridlines_char_y[char_y] != chars[offset]:
self.gridlines_char_y[char_y] = vd.options.disp_graph_multiple_lines_char
else:
self.gridlines_char_y[char_y] = chars[offset]

for data_x in self.gridlines_x:
if data_x >= xmin and data_x <= xmax:
plot_x = self.scaleX(data_x)
# plot_x is an integer count of plotter pixels, and each character box has 2 plotter pixels
char_x = plot_x // 2
# To subdivide the 2 plotter pixels per square into 4 zones, we have to first multiply by 2.
offset = 2*plot_x % 4
chars = self.options.disp_graph_lines_x_charset
# if we're drawing two different guide_lines in the same square, fill it with a different char
if char_x in self.gridlines_char_x and self.gridlines_char_x[char_x] != chars[offset]:
self.gridlines_char_x[char_x] = vd.options.disp_graph_lines_crossing
else:
self.gridlines_char_x[char_x] = chars[offset]


@property
def plotterCursorBox(self):
'Returns pixel bounds of cursor as a Box. Override to provide a cursor.'
Expand Down Expand Up @@ -245,7 +284,9 @@ def draw(self, scr):
getPixelAttr = self.getPixelAttrRandom if self.options.disp_pixel_random else self.getPixelAttrMost

for char_y in range(0, self.plotheight//4):
has_y_line = char_y in self.gridlines_char_y.keys()
for char_x in range(0, self.plotwidth//2):
has_x_line = char_x in self.gridlines_char_x.keys()
block_attrs = [
getPixelAttr(char_x*2 , char_y*4 ),
getPixelAttr(char_x*2 , char_y*4+1),
Expand All @@ -264,18 +305,27 @@ def draw(self, scr):
braille_num += pow2
pow2 *= 2

ch = disp_canvas_charset[braille_num]
if braille_num != 0:
color = Counter(c for c in block_attrs if c).most_common(1)[0][0]
cattr = colors.get_color(color)
else:
cattr = ColorAttr()
# draw guide lines only on squares that are empty
if has_x_line or has_y_line:
cattr = colors.color_gridline
if has_x_line:
ch = self.gridlines_char_x[char_x]
# where two lines cross, draw the vertical line, not the horizontal one
elif has_y_line:
ch = self.gridlines_char_y[char_y]

if cursorBBox.contains(char_x*2, char_y*4) or \
cursorBBox.contains(char_x*2+1, char_y*4+3):
cattr = update_attr(cattr, colors.color_current_row)

if cattr.attr:
scr.addstr(char_y, char_x, disp_canvas_charset[braille_num], cattr.attr)
scr.addstr(char_y, char_x, ch, cattr.attr)

def _mark_overlap_text(labels, textobj):
def _overlaps(a, b):
Expand Down Expand Up @@ -350,6 +400,11 @@ def __init__(self, *names, **kwargs):
self.polylines = [] # list of ([(canvas_x, canvas_y), ...], fgcolornum, row)
self.gridlabels = [] # list of (grid_x, grid_y, label, fgcolornum, row)

self.gridlines_x = []
self.gridlines_y = []
self.gridlines_char_x = {} # { x value in character coordinates -> character to use to draw that vertical line }
self.gridlines_char_y = {} # { y value in character coordinates -> character to use to draw that horizontal line }

self.legends = OrderedDict() # txt: attr (visible legends only)
self.plotAttrs = {} # key: attr (all keys, for speed)
self.reset()
Expand Down Expand Up @@ -694,6 +749,8 @@ def plot_elements(self, invert_y=False):

self.resetBounds()

self.plot_gridlines(invert_y=True)

bb = self.visibleBox
xmin, ymin, xmax, ymax = bb.xmin, bb.ymin, bb.xmax, bb.ymax
xfactor, yfactor = self.xScaler, self.yScaler
Expand Down Expand Up @@ -808,6 +865,13 @@ def deleteSourceRows(self, rows):
Canvas.addCommand('g'+ENTER, 'dive-visible', 'vs=copy(source); vs.rows=list(rowsWithin(plotterVisibleBox)); vd.push(vs)', 'open sheet of source rows visible on screen')
Canvas.addCommand('gd', 'delete-visible', 'deleteSourceRows(rowsWithin(plotterVisibleBox))', 'delete rows on source sheet visible on screen')

Canvas.addCommand('', 'add-line-x', 'sheet.gridlines_x += [float(x) for x in input("add line(s) at x = ", value="0.0", defaultLast=True).split()]; sheet.refresh()', 'draw a vertical line at x-values (space-separated)')
Canvas.addCommand('', 'add-line-y', 'sheet.gridlines_y += [float(y) for y in input("add line(s) at y = ", value="0.0", defaultLast=True).split()]; sheet.refresh()', 'draw a horizontal line at y-values (space-separated)')
Canvas.addCommand('', 'remove-line-x', 'for x in input("remove line(s) at x = ", value="0.0", defaultLast=True).split(): sheet.gridlines_x.remove(float(x)); sheet.refresh();', 'remove a horizontal line at x-values (space-separated)')
Canvas.addCommand('', 'remove-line-y', 'for y in input("remove line(s) at y = ", value="0.0", defaultLast=True).split(): sheet.gridlines_y.remove(float(y)); sheet.refresh();', 'remove a vertical line at y-values (space-separated)')
Canvas.addCommand('', 'clear-lines-x', 'sheet.gridlines_x = []; sheet.refresh()', 'erase all vertical x-value lines')
Canvas.addCommand('', 'clear-lines-y', 'sheet.gridlines_y = []; sheet.refresh()', 'erase any horizontal y-value lines')

vd.addGlobals({
'Canvas': Canvas,
'Plotter': Plotter,
Expand Down

0 comments on commit 752be13

Please sign in to comment.