Skip to content

Instantly share code, notes, and snippets.

@thegamecracks
Last active May 31, 2024 02:59
Show Gist options
  • Save thegamecracks/1ddaf262a04ec3404727148cdf4be3be to your computer and use it in GitHub Desktop.
Save thegamecracks/1ddaf262a04ec3404727148cdf4be3be to your computer and use it in GitHub Desktop.
Interactive visualization of Python slicing with Tkinter
import sys
from tkinter import StringVar, Text, Tk
from tkinter.ttk import Entry, Frame, Label
from typing import Sequence
if sys.platform == "win32":
from ctypes import windll
windll.shcore.SetProcessDpiAwareness(2)
def main() -> None:
def refresh_output() -> None:
output.configure(state="normal")
output.delete("1.0", "end")
try_render_output()
output.configure(state="disabled")
def try_render_output() -> None:
values = parse_list(list_var.get())
if values is None:
return
slice = parse_index_or_slice(slice_var.get())
output.insert("1.0", format_sliced_seq(values, slice))
app = Tk()
app.geometry("500x200")
app.grid_columnconfigure(1, weight=1)
app.grid_rowconfigure(2, weight=1)
list_var = StringVar(value="1, 2, 3, 4, 5, 6, 7, 8, 9, 10")
list_var.trace_add("write", lambda *args: refresh_output())
slice_var = StringVar(value="::2")
slice_var.trace_add("write", lambda *args: refresh_output())
list_label = Label(app, text="List:")
list_label.grid(row=0, column=0, sticky="e", padx=(10, 0), pady=(10, 0))
list_entry = Entry(app, textvariable=list_var, font="TkFixedFont")
list_entry.grid(row=0, column=1, sticky="ew", padx=(0, 10), pady=(10, 0))
slice_label = Label(app, text="Slice:")
slice_label.grid(row=1, column=0, sticky="e", padx=(10, 0))
slice_entry = Entry(app, textvariable=slice_var, font="TkFixedFont")
slice_entry.grid(row=1, column=1, sticky="ew", padx=(0, 10))
output = Text(app)
output.grid(row=2, column=0, columnspan=2, sticky="nesw", padx=10, pady=(0, 10))
refresh_output()
app.mainloop()
def parse_list(s: str) -> Sequence[float | int | str]:
values = s.split(",")
values = [s.strip() for s in values]
values = [n if (n := maybe_parse_num(s)) is not None else s for s in values]
return values
def maybe_parse_num(s: str) -> float | int | None:
try:
f = float(s)
except ValueError:
return
if f % 1 != 0:
return f
try:
return int(s)
except ValueError:
return f
def parse_index_or_slice(s: str) -> int | slice | None:
s = s.strip()
if s == "":
return
parts = s.split(":")
if len(parts) > 3:
return
try:
parts = [int(n) if n else None for n in parts]
except ValueError:
return
if len(parts) == 1:
return parts[0]
return slice(*parts)
def format_sliced_seq(values: Sequence[object], index: int | slice | None) -> str:
sep = ", "
elements = [str(e) for e in values]
rendered = "[{}]".format(sep.join(elements))
if isinstance(index, int):
index = slice(index, index + 1)
if index is None or index.step == 0:
return rendered
underline = [" " * len(e) for e in elements]
selection = []
start, stop, step = index.indices(len(elements))
for i in range(start, stop, step):
e = elements[i]
underline[i] = "^" * len(e)
selection.append(e)
underline = " {} ".format((" " * len(sep)).join(underline))
if len(selection) > 1:
selection = "[{}]".format(sep.join(selection))
else:
selection = ""
return "\n".join([rendered, underline, selection])
if __name__ == "__main__":
main()
@thegamecracks
Copy link
Author



Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment