def printd(*strings, q=False): """ Print debug information about the evironment where the printd() is called. Local variables are printed out with their current values. :param bool q: quit (exit) python session after the printd call. """ from inspect import currentframe, getframeinfo from vedo.utils import isSequence, precision cf = currentframe().f_back cfi = getframeinfo(cf) fname = os.path.basename(getframeinfo(cf).filename) print("\x1b[7m\x1b[3m\x1b[37m" + fname + " line:\x1b[1m" + str(cfi.lineno) + reset, end='') print('\x1b[3m\x1b[37m\x1b[2m', "\U00002501" * 30, time.ctime(), reset) if len(strings): print(" \x1b[37m\x1b[1mMessage : ", *strings) print(" \x1b[37m\x1b[1mFunction:\x1b[0m\x1b[37m " + str(cfi.function)) print(' \x1b[1mLocals :' + reset) for loc in cf.f_locals.keys(): obj = cf.f_locals[loc] var = repr(obj) if 'module ' in var: continue if 'function ' in var: continue if 'class ' in var: continue if loc.startswith('_'): continue if hasattr(obj, 'name'): if not obj.name: oname = str(type(obj)) else: oname = obj.name var = oname + ', at ' + precision(obj.GetPosition(), 3) var = var.replace('vtkmodules.', '') print(' \x1b[37m', loc, '\t\t=', var[:60].replace('\n', ''), reset) if isSequence(obj) and len(obj) > 4: try: print(' \x1b[37m\x1b[2m\x1b[3m len:', len(obj), ' min:', precision(min(obj), 4), ' max:', precision(max(obj), 4), reset) except: pass print(" \x1b[1m\x1b[37mElapsed time:\x1b[0m\x1b[37m", str(time.time() - _global_start_time)[:6], 's' + reset) if q: print( f" \x1b[1m\x1b[37mExiting python now (q={bool(q)}).\x1b[0m\x1b[37m" ) exit(0) sys.stdout.flush()
def ruler(p1, p2, unit_scale=1, units=None, s=50): actors = [] # Make two line segments midpoint = np.array([(x + y) / 2 for x, y in zip(p1, p2)]) gap1 = ((midpoint - p1) * 0.8) + p1 gap2 = ((midpoint - p2) * 0.8) + p2 actors.append(Line(p1, gap1, lw=200)) actors.append(Line(gap2, p2, lw=200)) # Add label if units is None: units = "" dist = mag(p2 - p1) * unit_scale label = precision(dist, 3) + " " + units lbl = Text(label, pos=midpoint, s=s + 100, justify="center") lbl.SetOrientation([0, 0, 180]) actors.append(lbl) # Add spheres add end actors.append(Sphere(p1, r=s, c=[0.3, 0.3, 0.3])) actors.append(Sphere(p2, r=s, c=[0.3, 0.3, 0.3])) acts = merge(*actors).c((0.3, 0.3, 0.3)).alpha(1).lw(2) acts.name = "Ruler" acts.bg_class = "Ruler" return acts
def sliderThres(widget, event): prevact = vp.actors[0] wval = widget.GetRepresentation().GetValue() wval_2 = precision(wval, 2) if wval_2 in bacts.keys(): # reusing the already available mesh mesh = bacts[wval_2] else: # else generate it if lego: mesh = volume.legosurface(vmin=wval, cmap=cmap) else: mesh = volume.isosurface(threshold=wval).color(c).alpha(alpha) bacts.update({wval_2: mesh}) # store it vp.renderer.RemoveActor(prevact) vp.renderer.AddActor(mesh) vp.actors[0] = mesh
def ruler(p1, p2, unit_scale=1, units=None, s=50): """ Creates a ruler showing the distance between two points. The ruler is composed of a line between the points and a text indicating the distance. :param p1: list, np.ndarray with coordinates of first point :param p2: list, np.ndarray with coordinates of second point :param unit_scale: float. To scale the units (e.g. show mm instead of µm) :param units: str, name of unit (e.g. 'mm') :param s: float size of text """ actors = [] # Make two line segments midpoint = np.array([(x + y) / 2 for x, y in zip(p1, p2)]) gap1 = ((midpoint - p1) * 0.8) + p1 gap2 = ((midpoint - p2) * 0.8) + p2 actors.append(Line(p1, gap1, lw=200)) actors.append(Line(gap2, p2, lw=200)) # Add label if units is None: # pragma: no cover units = "" # pragma: no cover dist = mag(p2 - p1) * unit_scale label = precision(dist, 3) + " " + units lbl = Text(label, pos=midpoint, s=s + 100, justify="center") lbl.SetOrientation([0, 0, 180]) actors.append(lbl) # Add spheres add end actors.append(Sphere(p1, r=s, c=[0.3, 0.3, 0.3])) actors.append(Sphere(p2, r=s, c=[0.3, 0.3, 0.3])) act = Actor(merge(*actors), name="Ruler", br_class="Ruler") act.c((0.3, 0.3, 0.3)).alpha(1).lw(2) return act
def Slicer( volume, alpha=1, cmaps=('gist_ncar_r', "hot_r", "bone_r", "jet", "Spectral_r"), map2cells=False, # buggy clamp=True, useSlider3D=False, size=(850, 700), screensize="auto", title="", bg="white", bg2="lightblue", axes=7, showHisto=True, showIcon=True, draggable=False, verbose=True, ): """ Generate a ``Plotter`` window with slicing planes for the input Volume. Returns the ``Plotter`` object. :param float alpha: transparency of the slicing planes :param list cmaps: list of color maps names to cycle when clicking button :param bool map2cells: scalars are mapped to cells, not intepolated. :param bool clamp: clamp scalar to reduce the effect of tails in color mapping :param bool useSlider3D: show sliders attached along the axes :param list size: rendering window size in pixels :param list screensize: size of the screen can be specified :param str title: window title :param bg: background color :param bg2: background gradient color :param int axes: axis type number :param bool showHisto: show histogram on bottom left :param bool showIcon: show a small 3D rendering icon of the volume :param bool draggable: make the icon draggable """ global _cmap_slicer if verbose: printc("Slicer tool", invert=1, c="m") ################################ vp = Plotter( bg=bg, bg2=bg2, size=size, screensize=screensize, title=title, interactive=False, ) ################################ box = volume.box().wireframe().alpha(0) vp.show(box, viewup="z", axes=axes) if showIcon: vp.addInset(volume, pos=(.85, .85), size=0.15, c='w', draggable=draggable) # inits la, ld = 0.7, 0.3 #ambient, diffuse dims = volume.dimensions() data = volume.getPointArray() rmin, rmax = volume.imagedata().GetScalarRange() if clamp: hdata, edg = np.histogram(data, bins=50) logdata = np.log(hdata + 1) # mean of the logscale plot meanlog = np.sum(np.multiply(edg[:-1], logdata)) / np.sum(logdata) rmax = min(rmax, meanlog + (meanlog - rmin) * 0.9) rmin = max(rmin, meanlog - (rmax - meanlog) * 0.9) if verbose: printc('scalar range clamped to: (' + precision(rmin, 3) + ', ' + precision(rmax, 3) + ')', c='m', bold=0) _cmap_slicer = cmaps[0] visibles = [None, None, None] msh = volume.zSlice(int(dims[2] / 2)) msh.alpha(alpha).lighting('', la, ld, 0) msh.cmap(_cmap_slicer, vmin=rmin, vmax=rmax) if map2cells: msh.mapPointsToCells() vp.renderer.AddActor(msh) visibles[2] = msh addScalarBar(msh, pos=(0.04, 0.0), horizontal=True, titleFontSize=0) def sliderfunc_x(widget, event): i = int(widget.GetRepresentation().GetValue()) msh = volume.xSlice(i).alpha(alpha).lighting('', la, ld, 0) msh.cmap(_cmap_slicer, vmin=rmin, vmax=rmax) if map2cells: msh.mapPointsToCells() vp.renderer.RemoveActor(visibles[0]) if i and i < dims[0]: vp.renderer.AddActor(msh) visibles[0] = msh def sliderfunc_y(widget, event): i = int(widget.GetRepresentation().GetValue()) msh = volume.ySlice(i).alpha(alpha).lighting('', la, ld, 0) msh.cmap(_cmap_slicer, vmin=rmin, vmax=rmax) if map2cells: msh.mapPointsToCells() vp.renderer.RemoveActor(visibles[1]) if i and i < dims[1]: vp.renderer.AddActor(msh) visibles[1] = msh def sliderfunc_z(widget, event): i = int(widget.GetRepresentation().GetValue()) msh = volume.zSlice(i).alpha(alpha).lighting('', la, ld, 0) msh.cmap(_cmap_slicer, vmin=rmin, vmax=rmax) if map2cells: msh.mapPointsToCells() vp.renderer.RemoveActor(visibles[2]) if i and i < dims[2]: vp.renderer.AddActor(msh) visibles[2] = msh cx, cy, cz, ch = 'dr', 'dg', 'db', (0.3, 0.3, 0.3) if np.sum(vp.renderer.GetBackground()) < 1.5: cx, cy, cz = 'lr', 'lg', 'lb' ch = (0.8, 0.8, 0.8) if not useSlider3D: vp.addSlider2D(sliderfunc_x, 0, dims[0], title='X', titleSize=0.5, pos=[(0.8, 0.12), (0.95, 0.12)], showValue=False, c=cx) vp.addSlider2D(sliderfunc_y, 0, dims[1], title='Y', titleSize=0.5, pos=[(0.8, 0.08), (0.95, 0.08)], showValue=False, c=cy) vp.addSlider2D(sliderfunc_z, 0, dims[2], title='Z', titleSize=0.6, value=int(dims[2] / 2), pos=[(0.8, 0.04), (0.95, 0.04)], showValue=False, c=cz) else: # 3d sliders attached to the axes bounds bs = box.bounds() vp.addSlider3D( sliderfunc_x, pos1=(bs[0], bs[2], bs[4]), pos2=(bs[1], bs[2], bs[4]), xmin=0, xmax=dims[0], t=box.diagonalSize() / mag(box.xbounds()) * 0.6, c=cx, showValue=False, ) vp.addSlider3D( sliderfunc_y, pos1=(bs[1], bs[2], bs[4]), pos2=(bs[1], bs[3], bs[4]), xmin=0, xmax=dims[1], t=box.diagonalSize() / mag(box.ybounds()) * 0.6, c=cy, showValue=False, ) vp.addSlider3D( sliderfunc_z, pos1=(bs[0], bs[2], bs[4]), pos2=(bs[0], bs[2], bs[5]), xmin=0, xmax=dims[2], value=int(dims[2] / 2), t=box.diagonalSize() / mag(box.zbounds()) * 0.6, c=cz, showValue=False, ) ################# def buttonfunc(): global _cmap_slicer bu.switch() _cmap_slicer = bu.status() for mesh in visibles: if mesh: mesh.cmap(_cmap_slicer, vmin=rmin, vmax=rmax) if map2cells: mesh.mapPointsToCells() vp.renderer.RemoveActor(mesh.scalarbar) mesh.scalarbar = addScalarBar(mesh, pos=(0.04, 0.0), horizontal=True, titleFontSize=0) vp.renderer.AddActor(mesh.scalarbar) bu = vp.addButton( buttonfunc, pos=(0.27, 0.005), states=cmaps, c=["db"] * len(cmaps), bc=["lb"] * len(cmaps), # colors of states size=14, bold=True, ) ################# hist = None if showHisto: hist = cornerHistogram(data, s=0.2, bins=25, logscale=1, pos=(0.02, 0.02), c=ch, bg=ch, alpha=0.7) comment = None if verbose: comment = Text2D( "Use sliders to slice volume\nClick button to change colormap", font='', s=0.8) vp.show(msh, hist, comment, interactive=False) vp.interactive = True if verbose: printc("Press button to cycle through color maps,", c="m") printc("Use sliders to select the slicing planes.", c="m") return vp
def printc(*strings, **keys): """ Print to terminal in color (any color!). :param c: foreground color name or (r,g,b) :param bc: background color name or (r,g,b) :param bool bold: boldface [True] :param bool italic: italic [False] :param bool blink: blinking text [False] :param bool underline: underline text [False] :param bool strike: strike through text [False] :param bool dim: make text look dimmer [False] :param bool invert: invert background and forward colors [False] :param box: print a box with specified text character [''] :param bool flush: flush buffer after printing [True] :param str end: the end character to be printed [newline] :param bool debug: print debug information about the evironment :Example: .. code-block:: python from vedo.colors import printc printc('anything', c='tomato', bold=False, end='' ) printc('anything', 455.5, vtkObject, c='lightblue') printc(299792.48, c=4) .. hint:: |colorprint.py|_ |colorprint| """ end = keys.pop("end", "\n") flush = keys.pop("flush", True) if not settings.enablePrintColor: print(*strings, end=end) if flush: sys.stdout.flush() return if not settings.notebookBackend: if not _terminal_has_colors: print(*strings, end=end) if flush: sys.stdout.flush() return c = keys.pop("c", None) bc = keys.pop("bc", None) bold = keys.pop("bold", True) italic = keys.pop("italic", False) blink = keys.pop("blink", False) underline = keys.pop("underline", False) strike = keys.pop("strike", False) dim = keys.pop("dim", False) invert = keys.pop("invert", False) box = keys.pop("box", "") dbg = keys.pop("debug", False) if c is True: c = "green" elif c is False: c = "red" if box is True: box = '-' if c is not None: c = getColor(c) if bc is not None: bc = getColor(bc) try: # ------------------------------------------------------------- txt = str() ns = len(strings) - 1 separator = " " offset = 0 for i, s in enumerate(strings): if i == ns: separator = "" if "\\" in repr(s): # "in" for some reasons changes s from vedo.shapes import _reps for k in emoji.keys(): if k in str(s): s = s.replace(k, emoji[k]) offset += 1 for k, rp in _reps: # check symbols in shapes._reps if k in str(s): s = s.replace(k, rp) offset += 1 txt += str(s) + separator special, cseq = "", "" if c is not None: r, g, b = c cseq += "\x1b[38;2;" + str(int(r * 255)) + ";" + str(int( g * 255)) + ";" + str(int(b * 255)) + "m" if bc: r, g, b = bc cseq += "\x1b[48;2;" + str(int(r * 255)) + ";" + str(int( g * 255)) + ";" + str(int(b * 255)) + "m" if underline and not box: special += "\x1b[4m" if strike and not box: special += "\x1b[9m" if dim: special += "\x1b[2m" if invert: special += "\x1b[7m" if bold: special += "\x1b[1m" if italic: special += "\x1b[3m" if blink: special += "\x1b[5m" if box and not ("\n" in txt): if len(box) > 1: box = box[0] if box in ["_", "=", "-", "+", "~"]: boxv = "|" else: boxv = box if box == "_" or box == ".": outtxt = special + cseq + " " + box * (len(txt) + offset + 2) + " \n" outtxt += boxv + " " * (len(txt) + 2) + boxv + "\n" else: outtxt = special + cseq + box * (len(txt) + offset + 4) + "\n" outtxt += boxv + " " + txt + " " + boxv + "\n" if box == "_": outtxt += "|" + box * (len(txt) + offset + 2) + "|" + "\x1b[0m" + end else: outtxt += box * (len(txt) + offset + 4) + "\x1b[0m" + end sys.stdout.write(outtxt) else: out = special + cseq + txt + "\x1b[0m" if dbg: from inspect import currentframe, getframeinfo from vedo.utils import isSequence, precision cf = currentframe().f_back cfi = getframeinfo(cf) fname = os.path.basename(getframeinfo(cf).filename) print("\x1b[7m\x1b[3m\x1b[37m" + fname + " line:\x1b[1m" + str(cfi.lineno) + "\x1b[0m", end='') print('\x1b[3m\x1b[37m\x1b[2m', "\U00002501" * 30, time.ctime(), "\x1b[0m") if txt: print(" \x1b[37m\x1b[1mMessage : " + out) print(" \x1b[37m\x1b[1mFunction:\x1b[0m\x1b[37m " + str(cfi.function)) print(' \x1b[1mLocals :\x1b[0m') for loc in cf.f_locals.keys(): obj = cf.f_locals[loc] var = repr(obj) if 'module ' in var: continue if 'function ' in var: continue if 'class ' in var: continue if '_' in loc: continue if hasattr(obj, 'name'): if not obj.name: oname = str(type(obj)) else: oname = obj.name var = oname + ', at ' + precision(obj.GetPosition(), 3) print(' \x1b[37m', loc, '=', var[:60].replace('\n', ''), '\x1b[0m') if isSequence(obj) and len(obj) > 4: print( ' \x1b[37m\x1b[2m\x1b[3m len:', len(obj), ' min:', precision(min(obj), 4), ' max:', precision(max(obj), 4), # ' mean:', np.mean(np.array(obj)), '\x1b[0m') print(" \x1b[1m\x1b[37mElapsed time:\x1b[0m\x1b[37m", str(time.time() - _global_start_time)[:6], 's\x1b[0m') else: sys.stdout.write(out + end) except: # ------------------------------------------------------------- print(*strings, end=end) if flush: sys.stdout.flush()
def __init__(self, volume, qtWidget, alpha=1, cmaps=('gist_ncar_r', "hot_r", "bone_r", "jet", "Spectral_r"), map2cells=False, # buggy clamp=True, useSlider3D=False, size=(850,700), screensize="auto", title="", bg="white", bg2="lightblue", axes=1, draggable=False, verbose=True): super().__init__(qtWidget=qtWidget, bg=bg, bg2=bg2, size=size, screensize=screensize, title=title, interactive=False, offscreen=True, verbose=verbose) ################################ self.volume = volume self.volume_copy = volume.clone() self.cmap_slicer = cmaps[0] self.alpha = alpha self.alphas = [1 for i in range(100)] self.showing_mesh = False self.map2cells = map2cells dims = volume.dimensions() self.rmin, self.rmax = volume.imagedata().GetScalarRange() self.pos_slider = [dims[0], dims[1], int(volume.dimensions()[2]/2)] self.volume.mode(1).color(self.cmap_slicer).jittering(True) self.setOTF() self.box = volume.box().wireframe().alpha(0) self.add(self.box, render=False) # inits la, ld = 0.7, 0.3 #ambient, diffuse data = volume.getPointArray() if clamp: hdata, edg = np.histogram(data, bins=50) logdata = np.log(hdata+1) # mean of the logscale plot meanlog = np.sum(np.multiply(edg[:-1], logdata))/np.sum(logdata) self.rmax = min(self.rmax, meanlog+(meanlog-self.rmin)*0.9) self.rmin = max(self.rmin, meanlog-(self.rmax-meanlog)*0.9) if verbose: printc('scalar range clamped to: (' + precision(self.rmin, 3) +', '+ precision(self.rmax, 3)+')', c='m', bold=0) self.visibles = [None, None, None] self.all_slices = [[], [], []] self.scalar_msh = volume.zSlice(self.pos_slider[2]) self.scalar_msh.alpha(self.alpha).lighting('', la, ld, 0) self.scalar_msh.pointColors(cmap=self.cmap_slicer, vmin=self.rmin, vmax=self.rmax, alpha=self.alphas) self.scalar_msh.SetVisibility(False) self.scalar_msh.scalarbar = addScalarBar(self.scalar_msh, pos=(0.04,0.0), horizontal=True, titleFontSize=0) self.add(self.scalar_msh) self.msh = self.scalar_msh.clone() if map2cells: self.msh.mapPointsToCells() self.renderer.AddActor(self.msh) self.visibles[2] = self.msh def sliderfunc_x(widget, event): """ Event on change slider x """ i = int(widget.GetRepresentation().GetValue()) self.pos_slider[0] = i self.msh = self.volume.xSlice(i).alpha(self.alpha).lighting('', la, ld, 0) self.msh.pointColors(cmap=self.cmap_slicer, vmin=self.rmin, vmax=self.rmax, alpha=self.alphas) if map2cells: self.msh.mapPointsToCells() self.renderer.RemoveActor(self.visibles[0]) if i<dims[0]: self.renderer.AddActor(self.msh) self.visibles[0] = self.msh def sliderfunc_y(widget, event): """ Event on change slider y """ i = int(widget.GetRepresentation().GetValue()) self.pos_slider[1] = i self.msh = self.volume.ySlice(i).alpha(self.alpha).lighting('', la, ld, 0) self.msh.pointColors(cmap=self.cmap_slicer, vmin=self.rmin, vmax=self.rmax, alpha=self.alphas) if map2cells: self.msh.mapPointsToCells() self.renderer.RemoveActor(self.visibles[1]) if i<dims[1]: self.renderer.AddActor(self.msh) self.visibles[1] = self.msh def sliderfunc_z(widget, event): """ Event on change slider z """ i = int(widget.GetRepresentation().GetValue()) self.pos_slider[2] = i self.comment.SetText(4, "z="+str(self.pos_slider[2])) self.msh = self.volume.zSlice(i).alpha(self.alpha).lighting('', la, ld, 0) self.msh.pointColors(cmap=self.cmap_slicer, vmin=self.rmin, vmax=self.rmax, alpha=self.alphas) if map2cells: self.msh.mapPointsToCells() self.renderer.RemoveActor(self.visibles[2]) if i<dims[2]: self.renderer.AddActor(self.msh) self.visibles[2] = self.msh cx, cy, cz, ch = 'dr', 'dg', 'db', (0.3,0.3,0.3) if np.sum(self.renderer.GetBackground()) < 1.5: cx, cy, cz = 'lr', 'lg', 'lb' ch = (0.8,0.8,0.8) self.addSlider2D(sliderfunc_x, 0, dims[0]+1, title='X', titleSize=0.5, value=self.pos_slider[0], pos=[(0.8,0.12), (0.95,0.12)], showValue=False, c=cx) self.addSlider2D(sliderfunc_y, 0, dims[1]+1, title='Y', titleSize=0.5, value=self.pos_slider[1], pos=[(0.8,0.08), (0.95,0.08)], showValue=False, c=cy) self.addSlider2D(sliderfunc_z, 0, dims[2]+1, title='Z', titleSize=0.6, value=self.pos_slider[2], pos=[(0.8,0.04), (0.95,0.04)], showValue=False, c=cz) self.scalar_thresh = self.addSlider2D(self.sliderThreshold, 0, 100, value=100, pos=[(0.04, 0.1), (0.2, 0.1)], showValue=True, title="Scalar") self.opacity_thresh = self.addSlider2D(self.sliderOpacityThreshold, 0, 100, value=0, pos=[(0.04, 0.2), (0.2, 0.2)], showValue=True, title="Opacity") ################# def keyfunc(iren, event): """ Keyboard events on the viewer s : save image x : display all slice on x axis y : display all slice on y axis z : display all slice on z axis v : display volume rendering """ if not iren.GetKeyCode(): return key = iren.GetKeySym() if key=='s': array = self.volume.getDataArray() index = self.pos_slider[2] if index < array.shape[2]: image = self.volume.getDataArray()[..., index].T fig, ax = plt.subplots(1,1) ax.axis("off") ax.imshow(image, cmap="gray") plt.savefig("saved_fig.png", bbox_inches="tight", pad_inches=0) if key=='x': self.display_all_slices(0) if key=='y': self.display_all_slices(1) if key=='z': self.display_all_slices(2) if key=='v': self.showing_mesh = not self.showing_mesh if self.volume.GetBounds()[-1] == 0: return if self.showing_mesh: self.add(self.volume) self.interactive = True else: self.remove(self.volume) def buttonfunc(iren, event): """ Mouse event Allows to change color map """ clickPos = iren.GetEventPosition() picker = vtk.vtkPropPicker() picker.Pick(clickPos[0], clickPos[1], 0, self.renderer) if not picker.GetActor2D(): return bu.switch() self.cmap_slicer = bu.status() self.refresh() # self.add(self.scalar_msh) bu = self.addButton(buttonfunc, pos=(0.27, 0.005), states=cmaps, c=["db"]*len(cmaps), bc=["lb"]*len(cmaps), # colors of states size=14, bold=True, ) self.interactor.AddObserver("KeyPressEvent", keyfunc) self.interactor.AddObserver("LeftButtonPressEvent", buttonfunc) ################# self.comment = Text2D("z="+str(self.pos_slider[2]),pos=5, font='Montserrat', s=0.6) self.add([self.msh, self.comment]) if verbose: printc("Press button to cycle through color maps,", c="m") printc("Use sliders to select the slicing planes.", c="m")
def printc( *strings, c=None, bc=None, bold=True, italic=False, blink=False, underline=False, strike=False, dim=False, invert=False, box="", dbg=False, end="\n", flush=True, ): """ Print to terminal in color (any color!). :param c: foreground color name or (r,g,b) :param bc: background color name or (r,g,b) :param bool bold: boldface [True] :param bool italic: italic [False] :param bool blink: blinking text [False] :param bool underline: underline text [False] :param bool strike: strike through text [False] :param bool dim: make text look dimmer [False] :param bool invert: invert background and forward colors [False] :param box: print a box with specified text character [''] :param bool flush: flush buffer after printing [True] :param str end: the end character to be printed [newline] :param bool dbg: print debug information about the evironment :Example: .. code-block:: python from vedo.colors import printc printc('anything', c='tomato', bold=False, end='' ) printc('anything', 455.5, vtkObject, c='lightblue') printc(299792.48, c=4) .. hint:: |colorprint.py|_ |colorprint| """ if not settings.enablePrintColor: print(*strings, end=end, flush=flush) return if not settings.notebookBackend: if not _terminal_has_colors: print(*strings, end=end, flush=flush) return try: # ------------------------------------------------------------- txt = str() ns = len(strings) - 1 separator = " " offset = 0 for i, s in enumerate(strings): if i == ns: separator = "" if "\\" in repr(s): # "in" for some reasons changes s from vedo.shapes import _reps for k in emoji.keys(): if k in str(s): s = s.replace(k, emoji[k]) offset += 1 for k, rp in _reps: # check symbols in shapes._reps if k in str(s): s = s.replace(k, rp) offset += 1 txt += str(s) + separator special, cseq, reset = "", "", u"\u001b[0m" oneletter_colors = { 'k': u'\u001b[30;1m', # because these are supported by most terminals 'r': u'\u001b[31;1m', 'g': u'\u001b[32;1m', 'y': u'\u001b[33;1m', 'b': u'\u001b[34;1m', 'm': u'\u001b[35;1m', 'c': u'\u001b[36;1m', 'w': u'\u001b[37;1m', } if c is not None: if c is True: c = "g" elif c is False: c = "r" if isinstance(c, str) and c in oneletter_colors.keys(): cseq += oneletter_colors[c] else: r, g, b = getColor(c) # not all terms support this syntax cseq += f"\x1b[38;2;{int(r*255)};{int(g*255)};{int(b*255)}m" if bc: if bc in oneletter_colors.keys(): cseq += oneletter_colors[bc] else: r, g, b = getColor(bc) cseq += f"\x1b[48;2;{int(r*255)};{int(g*255)};{int(b*255)}m" if box is True: box = '-' if underline and not box: special += "\x1b[4m" if strike and not box: special += "\x1b[9m" if dim: special += "\x1b[2m" if invert: special += "\x1b[7m" if bold: special += "\x1b[1m" if italic: special += "\x1b[3m" if blink: special += "\x1b[5m" if box and not ("\n" in txt): box = box[0] boxv = box if box in ["_", "=", "-", "+", "~"]: boxv = "|" if box == "_" or box == ".": outtxt = special + cseq + " " + box * (len(txt) + offset + 2) + " \n" outtxt += boxv + " " * (len(txt) + 2) + boxv + "\n" else: outtxt = special + cseq + box * (len(txt) + offset + 4) + "\n" outtxt += boxv + " " + txt + " " + boxv + "\n" if box == "_": outtxt += "|" + box * (len(txt) + offset + 2) + "|" + reset + end else: outtxt += box * (len(txt) + offset + 4) + reset + end sys.stdout.write(outtxt) else: out = special + cseq + txt + reset if dbg: from inspect import currentframe, getframeinfo from vedo.utils import isSequence, precision cf = currentframe().f_back cfi = getframeinfo(cf) fname = os.path.basename(getframeinfo(cf).filename) print("\x1b[7m\x1b[3m\x1b[37m" + fname + " line:\x1b[1m" + str(cfi.lineno) + reset, end='') print('\x1b[3m\x1b[37m\x1b[2m', "\U00002501" * 30, time.ctime(), reset) if txt: print(" \x1b[37m\x1b[1mMessage : " + out) print(" \x1b[37m\x1b[1mFunction:\x1b[0m\x1b[37m " + str(cfi.function)) print(' \x1b[1mLocals :' + reset) for loc in cf.f_locals.keys(): obj = cf.f_locals[loc] var = repr(obj) if 'module ' in var: continue if 'function ' in var: continue if 'class ' in var: continue if '_' in loc: continue if hasattr(obj, 'name'): if not obj.name: oname = str(type(obj)) else: oname = obj.name var = oname + ', at ' + precision(obj.GetPosition(), 3) print(' \x1b[37m', loc, '=', var[:60].replace('\n', ''), reset) if isSequence(obj) and len(obj) > 4: print(' \x1b[37m\x1b[2m\x1b[3m len:', len(obj), ' min:', precision(min(obj), 4), ' max:', precision(max(obj), 4), reset) print(" \x1b[1m\x1b[37mElapsed time:\x1b[0m\x1b[37m", str(time.time() - _global_start_time)[:6], 's' + reset) else: sys.stdout.write(out + end) except: # ------------------------------------------------------------- fallback print(*strings, end=end) if flush: sys.stdout.flush()