vedo.colors

Colors definitions and printing methods.

   1#!/usr/bin/env python3
   2# -*- coding: utf-8 -*-
   3import os
   4import sys
   5from time import time, ctime
   6
   7import numpy as np
   8import vedo.vtkclasses as vtki
   9import vedo
  10
  11__docformat__ = "google"
  12
  13__doc__ = """
  14Colors definitions and printing methods.
  15
  16![](https://vedo.embl.es/images/basic/colorcubes.png)
  17"""
  18
  19__all__ = [
  20    "printc",
  21    "printd",
  22    "get_color",
  23    "get_color_name",
  24    "color_map",
  25    "build_palette",
  26    "build_lut",
  27]
  28
  29#########################################################
  30try:
  31    import matplotlib
  32    try:
  33        matplotlib.colormaps # v3.4 will fail this
  34        _has_matplotlib = True
  35        cmaps = {}
  36    except AttributeError:
  37        _has_matplotlib = False
  38except ModuleNotFoundError:
  39    from vedo.cmaps import cmaps
  40    _has_matplotlib = False
  41    # see below, this is dealt with in color_map()
  42# print("colors.py: _has_matplotlib", _has_matplotlib)
  43
  44_printc_delay_timestamp = [0]
  45
  46
  47#########################################################
  48# handy global shortcuts for terminal printing
  49# Ex.: print(colors.red + "hello" + colors.reset)
  50#########################################################
  51red = "\x1b[1m\x1b[31;1m"
  52green = "\x1b[1m\x1b[32;1m"
  53yellow = "\x1b[1m\x1b[33;1m"
  54blue = "\x1b[1m\x1b[34;1m"
  55reset = "\x1b[0m"
  56
  57
  58#########################################################
  59# basic color schemes
  60#########################################################
  61colors = {
  62    # order kind of matters because of pyplot.plot()
  63    "blue9": "#a8cbfe",  # bootstrap5 colors
  64    "blue8": "#81b4fe",
  65    "blue7": "#5a9cfe",
  66    "blue6": "#3485fd",
  67    "blue5": "#0d6efd",
  68    "blue4": "#0b5cd5",
  69    "blue3": "#094bac",
  70    "blue2": "#073984",
  71    "blue1": "#05285b",
  72    "indigo9": "#c8a9fa",
  73    "indigo8": "#af83f8",
  74    "indigo7": "#975cf6",
  75    "indigo6": "#7e36f4",
  76    "indigo5": "#6610f2",
  77    "indigo4": "#560dcb",
  78    "indigo3": "#450ba5",
  79    "indigo2": "#35087e",
  80    "indigo1": "#250657",
  81    "purple9": "#cbbbe9",
  82    "purple8": "#b49ddf",
  83    "purple7": "#9d7ed5",
  84    "purple6": "#8660cb",
  85    "purple5": "#6f42c1",
  86    "purple4": "#5d37a2",
  87    "purple3": "#4b2d83",
  88    "purple2": "#3a2264",
  89    "purple1": "#281845",
  90    "pink9": "#f0b6d3",
  91    "pink8": "#ea95bf",
  92    "pink7": "#e374ab",
  93    "pink6": "#dd5498",
  94    "pink5": "#d63384",
  95    "pink4": "#b42b6f",
  96    "pink3": "#92235a",
  97    "pink2": "#6f1b45",
  98    "pink1": "#4d1230",
  99    "red9": "#f2b6bc",
 100    "red8": "#ed969e",
 101    "red7": "#e77681",
 102    "red6": "#e25563",
 103    "red5": "#dc3545",
 104    "red4": "#b92d3a",
 105    "red3": "#96242f",
 106    "red2": "#721c24",
 107    "red1": "#4f1319",
 108    "orange9": "#fed1aa",
 109    "orange8": "#febc85",
 110    "orange7": "#fea75f",
 111    "orange6": "#fd933a",
 112    "orange5": "#fd7e14",
 113    "orange4": "#d56a11",
 114    "orange3": "#ac560e",
 115    "orange2": "#84420a",
 116    "orange1": "#5b2d07",
 117    "yellow9": "#ffe9a6",
 118    "yellow8": "#ffdf7e",
 119    "yellow7": "#ffd556",
 120    "yellow6": "#ffcb2f",
 121    "yellow5": "#ffc107",
 122    "yellow4": "#d6a206",
 123    "yellow3": "#ad8305",
 124    "yellow2": "#856404",
 125    "yellow1": "#5c4503",
 126    "green9": "#b2dfbc",
 127    "green8": "#8fd19e",
 128    "green7": "#6dc381",
 129    "green6": "#4ab563",
 130    "green5": "#28a745",
 131    "green4": "#228c3a",
 132    "green3": "#1b722f",
 133    "green2": "#155724",
 134    "green1": "#0e3c19",
 135    "teal9": "#afecda",
 136    "teal8": "#8be3c9",
 137    "teal7": "#67dab8",
 138    "teal6": "#44d2a8",
 139    "teal5": "#20c997",
 140    "teal4": "#1ba97f",
 141    "teal3": "#168967",
 142    "teal2": "#11694f",
 143    "teal1": "#0c4836",
 144    "cyan9": "#abdee5",
 145    "cyan8": "#86cfda",
 146    "cyan7": "#61c0cf",
 147    "cyan6": "#3cb1c3",
 148    "cyan5": "#17a2b8",
 149    "cyan4": "#13889b",
 150    "cyan3": "#106e7d",
 151    "cyan2": "#0c5460",
 152    "cyan1": "#083a42",
 153    "gray9": "#f8f9fa",
 154    "gray8": "#e9edef",
 155    "gray7": "#dee2e6",
 156    "gray6": "#ced4da",
 157    "gray5": "#adb5bd",
 158    "gray4": "#6c757d",
 159    "gray3": "#495057",
 160    "gray2": "#343a40",
 161    "gray1": "#212529",
 162    "aliceblue": "#F0F8FF",  # matplotlib scheme
 163    "antiquewhite": "#FAEBD7",
 164    "aqua": "#00FFFF",
 165    "aquamarine": "#7FFFD4",
 166    "azure": "#F0FFFF",
 167    "beige": "#F5F5DC",
 168    "bisque": "#FFE4C4",
 169    "black": "#000000",
 170    "blanchedalmond": "#FFEBCD",
 171    "blue": "#0f00fb",
 172    "blueviolet": "#8A2BE2",
 173    "brown": "#A52A2A",
 174    "burlywood": "#DEB887",
 175    "cadetblue": "#5F9EA0",
 176    "chartreuse": "#7FFF00",
 177    "chocolate": "#D2691E",
 178    "coral": "#FF7F50",
 179    "cornflowerblue": "#6495ED",
 180    "cornsilk": "#FFF8DC",
 181    "crimson": "#DC143C",
 182    "cyan": "#00FFFF",
 183    "darkblue": "#00008B",
 184    "darkcyan": "#008B8B",
 185    "darkgoldenrod": "#B8860B",
 186    "darkgray": "#A9A9A9",
 187    "darkgreen": "#006400",
 188    "darkkhaki": "#BDB76B",
 189    "darkmagenta": "#8B008B",
 190    "darkolivegreen": "#556B2F",
 191    "darkorange": "#FF8C00",
 192    "darkorchid": "#9932CC",
 193    "darkred": "#8B0000",
 194    "darksalmon": "#E9967A",
 195    "darkseagreen": "#8FBC8F",
 196    "darkslateblue": "#483D8B",
 197    "darkslategray": "#2F4F4F",
 198    "darkturquoise": "#00CED1",
 199    "darkviolet": "#9400D3",
 200    "deeppink": "#FF1493",
 201    "deepskyblue": "#00BFFF",
 202    "dimgray": "#696969",
 203    "dodgerblue": "#1E90FF",
 204    "firebrick": "#B22222",
 205    "floralwhite": "#FFFAF0",
 206    "forestgreen": "#228B22",
 207    "fuchsia": "#FF00FF",
 208    "gainsboro": "#DCDCDC",
 209    "ghostwhite": "#F8F8FF",
 210    "gold": "#FFD700",
 211    "goldenrod": "#DAA520",
 212    "gray": "#808080",
 213    "green": "#047f10",
 214    "greenyellow": "#ADFF2F",
 215    "honeydew": "#F0FFF0",
 216    "hotpink": "#FF69B4",
 217    "indianred": "#CD5C5C",
 218    "indigo": "#4B0082",
 219    "ivory": "#FFFFF0",
 220    "khaki": "#F0E68C",
 221    "lavender": "#E6E6FA",
 222    "lavenderblush": "#FFF0F5",
 223    "lawngreen": "#7CFC00",
 224    "lemonchiffon": "#FFFACD",
 225    "lightblue": "#ADD8E6",
 226    "lightcoral": "#F08080",
 227    "lightcyan": "#E0FFFF",
 228    "lightgray": "#D3D3D3",
 229    "lightgreen": "#90EE90",
 230    "lightpink": "#FFB6C1",
 231    "lightsalmon": "#FFA07A",
 232    "lightseagreen": "#20B2AA",
 233    "lightskyblue": "#87CEFA",
 234    "lightsteelblue": "#B0C4DE",
 235    "lightyellow": "#FFFFE0",
 236    "lime": "#00FF00",
 237    "limegreen": "#32CD32",
 238    "linen": "#FAF0E6",
 239    "magenta": "#FF00FF",
 240    "maroon": "#800000",
 241    "mediumaquamarine": "#66CDAA",
 242    "mediumblue": "#0000CD",
 243    "mediumorchid": "#BA55D3",
 244    "mediumpurple": "#9370DB",
 245    "mediumseagreen": "#3CB371",
 246    "mediumslateblue": "#7B68EE",
 247    "mediumspringgreen": "#00FA9A",
 248    "mediumturquoise": "#48D1CC",
 249    "mediumvioletred": "#C71585",
 250    "midnightblue": "#191970",
 251    "mintcream": "#F5FFFA",
 252    "mistyrose": "#FFE4E1",
 253    "moccasin": "#FFE4B5",
 254    "navajowhite": "#FFDEAD",
 255    "navy": "#000080",
 256    "oldlace": "#FDF5E6",
 257    "olive": "#808000",
 258    "olivedrab": "#6B8E23",
 259    "orange": "#FFA500",
 260    "orangered": "#FF4500",
 261    "orchid": "#DA70D6",
 262    "palegoldenrod": "#EEE8AA",
 263    "palegreen": "#98FB98",
 264    "paleturquoise": "#AFEEEE",
 265    "palevioletred": "#DB7093",
 266    "papayawhip": "#FFEFD5",
 267    "peachpuff": "#FFDAB9",
 268    "peru": "#CD853F",
 269    "pink": "#FFC0CB",
 270    "plum": "#DDA0DD",
 271    "powderblue": "#B0E0E6",
 272    "purple": "#800080",
 273    "rebeccapurple": "#663399",
 274    "red": "#fe1e1f",  # "#FF0000",
 275    "rosybrown": "#BC8F8F",
 276    "royalblue": "#4169E1",
 277    "saddlebrown": "#8B4513",
 278    "salmon": "#FA8072",
 279    "sandybrown": "#F4A460",
 280    "seagreen": "#2E8B57",
 281    "seashell": "#FFF5EE",
 282    "sienna": "#A0522D",
 283    "silver": "#C0C0C0",
 284    "skyblue": "#87CEEB",
 285    "slateblue": "#6A5ACD",
 286    "slategray": "#708090",
 287    "snow": "#FFFAFA",
 288    "blackboard": "#393939",
 289    "springgreen": "#00FF7F",
 290    "steelblue": "#4682B4",
 291    "tan": "#D2B48C",
 292    "teal": "#008080",
 293    "thistle": "#D8BFD8",
 294    "tomato": "#FF6347",
 295    "turquoise": "#40E0D0",
 296    "violet": "#EE82EE",
 297    "wheat": "#F5DEB3",
 298    "white": "#FFFFFF",
 299    "whitesmoke": "#F5F5F5",
 300    "yellow": "#ffff36",  # "#FFFF00",
 301    "yellowgreen": "#9ACD32",
 302}
 303
 304
 305color_nicks = {  # color nicknames
 306    "bb": "blackboard",
 307    "lb": "lightblue",  # light
 308    "lg": "lightgreen",
 309    "lr": "orangered",
 310    "lc": "lightcyan",
 311    "ls": "lightsalmon",
 312    "ly": "lightyellow",
 313    "dr": "darkred",  # dark
 314    "db": "darkblue",
 315    "dg": "darkgreen",
 316    "dm": "darkmagenta",
 317    "dc": "darkcyan",
 318    "ds": "darksalmon",
 319    "dv": "darkviolet",
 320    "b1": "blue1",  # bootstrap5 colors
 321    "b2": "blue2",
 322    "b3": "blue3",
 323    "b4": "blue4",
 324    "b5": "blue5",
 325    "b6": "blue6",
 326    "b7": "blue7",
 327    "b8": "blue8",
 328    "b9": "blue9",
 329    "i1": "indigo1",
 330    "i2": "indigo2",
 331    "i3": "indigo3",
 332    "i4": "indigo4",
 333    "i5": "indigo5",
 334    "i6": "indigo6",
 335    "i7": "indigo7",
 336    "i8": "indigo8",
 337    "i9": "indigo9",
 338    "p1": "purple1",
 339    "p2": "purple2",
 340    "p3": "purple3",
 341    "p4": "purple4",
 342    "p5": "purple5",
 343    "p6": "purple6",
 344    "p7": "purple7",
 345    "p8": "purple8",
 346    "p9": "purple9",
 347    "r1": "red1",
 348    "r2": "red2",
 349    "r3": "red3",
 350    "r4": "red4",
 351    "r5": "red5",
 352    "r6": "red6",
 353    "r7": "red7",
 354    "r8": "red8",
 355    "r9": "red9",
 356    "o1": "orange1",
 357    "o2": "orange2",
 358    "o3": "orange3",
 359    "o4": "orange4",
 360    "o5": "orange5",
 361    "o6": "orange6",
 362    "o7": "orange7",
 363    "o8": "orange8",
 364    "o9": "orange9",
 365    "y1": "yellow1",
 366    "y2": "yellow2",
 367    "y3": "yellow3",
 368    "y4": "yellow4",
 369    "y5": "yellow5",
 370    "y6": "yellow6",
 371    "y7": "yellow7",
 372    "y8": "yellow8",
 373    "y9": "yellow9",
 374    "g1": "green1",
 375    "g2": "green2",
 376    "g3": "green3",
 377    "g4": "green4",
 378    "g5": "green5",
 379    "g6": "green6",
 380    "g7": "green7",
 381    "g8": "green8",
 382    "g9": "green9",
 383    "k1": "gray1",
 384    "k2": "gray2",
 385    "k3": "gray3",
 386    "k4": "gray4",
 387    "k5": "gray5",
 388    "k6": "gray6",
 389    "k7": "gray7",
 390    "k8": "gray8",
 391    "k9": "gray9",
 392    "a": "aqua",
 393    "b": "blue",
 394    "c": "cyan",
 395    "d": "gold",
 396    "f": "fuchsia",
 397    "g": "green",
 398    "i": "indigo",
 399    "k": "black",
 400    "m": "magenta",
 401    "n": "navy",
 402    "l": "lavender",
 403    "o": "orange",
 404    "p": "purple",
 405    "r": "red",
 406    "s": "salmon",
 407    "t": "tomato",
 408    "v": "violet",
 409    "y": "yellow",
 410    "w": "white",
 411}
 412
 413
 414# available colormap names:
 415cmaps_names = [
 416    "Accent", "Accent_r", "Blues", "Blues_r", "BrBG",
 417    "BrBG_r", "BuGn", "BuGn_r", "BuPu", "BuPu_r",
 418    "CMRmap", "CMRmap_r", "Dark2", "Dark2_r", "GnBu",
 419    "GnBu_r", "Greens", "Greens_r", "Greys", "Greys_r",
 420    "OrRd", "OrRd_r", "Oranges", "Oranges_r", "PRGn",
 421    "PRGn_r", "Paired", "Paired_r", "Pastel1", "Pastel1_r",
 422    "Pastel2", "Pastel2_r", "PiYG", "PiYG_r", "PuBu",
 423    "PuBuGn", "PuBuGn_r", "PuBu_r", "PuOr", "PuOr_r",
 424    "PuRd", "PuRd_r", "Purples", "Purples_r", "RdBu",
 425    "RdBu_r", "RdGy", "RdGy_r", "RdPu", "RdPu_r",
 426    "RdYlBu", "RdYlBu_r", "RdYlGn", "RdYlGn_r", "Reds",
 427    "Reds_r", "Set1", "Set1_r", "Set2", "Set2_r",
 428    "Set3", "Set3_r", "Spectral", "Spectral_r", "Wistia",
 429    "Wistia_r", "YlGn", "YlGnBu", "YlGnBu_r", "YlGn_r",
 430    "YlOrBr", "YlOrBr_r", "YlOrRd", "YlOrRd_r", "afmhot",
 431    "afmhot_r", "autumn", "autumn_r", "binary", "binary_r",
 432    "bone", "bone_r", "brg", "brg_r", "bwr", "bwr_r",
 433    "cividis", "cividis_r", "cool", "cool_r", "coolwarm",
 434    "coolwarm_r", "copper", "copper_r", "cubehelix", "cubehelix_r",
 435    "flag", "flag_r", "gist_earth", "gist_earth_r", "gist_gray",
 436    "gist_gray_r", "gist_heat", "gist_heat_r", "gist_ncar", "gist_ncar_r",
 437    "gist_rainbow", "gist_rainbow_r", "gist_stern", "gist_stern_r", "gist_yarg",
 438    "gist_yarg_r", "gnuplot", "gnuplot2", "gnuplot2_r", "gnuplot_r", "gray_r",
 439    "hot", "hot_r", "hsv", "hsv_r", "inferno", "inferno_r",
 440    "jet", "jet_r", "magma", "magma_r", "nipy_spectral", "nipy_spectral_r",
 441    "ocean", "ocean_r", "pink_r", "plasma", "plasma_r", "prism",
 442    "prism_r", "rainbow", "rainbow_r", "seismic", "seismic_r", "spring",
 443    "spring_r", "summer", "summer_r", "tab10", "tab10_r", "tab20",
 444    "tab20_r", "tab20b", "tab20b_r", "tab20c", "tab20c_r", "terrain",
 445    "terrain_r", "twilight", "twilight_r", "twilight_shifted", "twilight_shifted_r",
 446    "viridis", "viridis_r", "winter", "winter_r",
 447]
 448
 449# default color palettes when using an index
 450palettes = (
 451    (
 452       [1.        , 0.75686275, 0.02745098], # yellow5
 453       [0.99215686, 0.49411765, 0.07843137], # orange5
 454       [0.8627451 , 0.20784314, 0.27058824], # red5
 455       [0.83921569, 0.2       , 0.51764706], # pink5
 456       [0.1254902 , 0.78823529, 0.59215686], # teal5
 457       [0.15686275, 0.65490196, 0.27058824], # green5
 458       [0.09019608, 0.63529412, 0.72156863], # cyan5
 459       [0.05098039, 0.43137255, 0.99215686], # blue5
 460       [0.4       , 0.0627451 , 0.94901961], # indigo5
 461       [0.67843137, 0.70980392, 0.74117647], # gray5
 462    ),
 463    (
 464        (1.0, 0.832, 0.000),  # gold
 465        (0.960, 0.509, 0.188),
 466        (0.901, 0.098, 0.194),
 467        (0.235, 0.85, 0.294),
 468        (0.46, 0.48, 0.000),
 469        (0.274, 0.941, 0.941),
 470        (0.0, 0.509, 0.784),
 471        (0.1, 0.1, 0.900),
 472        (0.902, 0.7, 1.000),
 473        (0.941, 0.196, 0.901),
 474    ),
 475    (
 476        (1.0, 0.832, 0),    # gold
 477        (0.59, 0.0, 0.09),  # dark red
 478        (0.5, 0.5, 0),      # yellow-green
 479        (0.0, 0.66, 0.42),  # green blue
 480        (0.5, 1.0, 0.0),    # green
 481        (0.0, 0.18, 0.65),  # blue
 482        (0.4, 0.0, 0.4),    # plum
 483        (0.4, 0.0, 0.6),
 484        (0.2, 0.4, 0.6),
 485        (0.1, 0.3, 0.2),
 486    ),
 487    (
 488        (0.010, 0.0706, 0.098),  #  -> black
 489        (0.0196, 0.369, 0.447),
 490        (0.0745, 0.573, 0.584),
 491        (0.584, 0.820, 0.741),
 492        (0.914, 0.847, 0.663),
 493        (0.929, 0.616, 0.149),
 494        (0.788, 0.412, 0.110),
 495        (0.729, 0.259, 0.0902),
 496        (0.678, 0.153, 0.110),
 497        (0.604, 0.153, 0.165),  #  -> red3
 498    ),
 499    (
 500        (0.345, 0.188, 0.071),  #  -> orange1
 501        (0.498, 0.314, 0.161),
 502        (0.573, 0.404, 0.239),
 503        (0.651, 0.545, 0.400),
 504        (0.714, 0.678, 0.569),
 505        (0.761, 0.773, 0.671),
 506        (0.643, 0.675, 0.533),
 507        (0.396, 0.427, 0.298),
 508        (0.255, 0.282, 0.204),
 509        (0.200, 0.239, 0.165),  #  -> blackboard
 510    ),
 511    (
 512        (0.937, 0.969, 0.820),  #  -> beige
 513        (0.729, 0.851, 0.714),
 514        (0.671, 0.639, 0.396),
 515        (0.447, 0.180, 0.180),
 516        (0.259, 0.055, 0.082),  #  -> red1
 517        (0.937, 0.969, 0.820),  #  -> beige
 518        (0.729, 0.851, 0.714),
 519        (0.671, 0.639, 0.396),
 520        (0.447, 0.180, 0.180),
 521        (0.259, 0.055, 0.082),  #  -> red1
 522    ),
 523    (
 524        (0.933, 0.298, 0.443),  #  -> red6
 525        (0.996, 0.824, 0.431),
 526        (0.082, 0.835, 0.631),
 527        (0.094, 0.537, 0.690),
 528        (0.035, 0.231, 0.294),  #  -> cyan1
 529        (0.933, 0.298, 0.443),  #  -> red6
 530        (0.996, 0.824, 0.431),
 531        (0.082, 0.835, 0.631),
 532        (0.094, 0.537, 0.690),
 533        (0.035, 0.231, 0.294),  #  -> cyan1
 534    ),
 535)
 536
 537
 538emoji = {
 539    ":bomb:": "\U0001F4A5",
 540    ":sparks:": "\U00002728",
 541    ":thumbup:": "\U0001F44D",
 542    ":target:": "\U0001F3AF",
 543    ":save:": "\U0001F4BE",
 544    ":noentry:": "\U000026D4",
 545    ":video:": "\U0001F4FD",
 546    ":lightning:": "\U000026A1",
 547    ":camera:": "\U0001F4F8",
 548    ":times:": "\U0000274C",
 549    ":world:": "\U0001F30D",
 550    ":rainbow:": "\U0001F308",
 551    ":idea:": "\U0001F4A1",
 552    ":pin:": "\U0001F4CC",
 553    ":construction:": "\U0001F6A7",
 554    ":rocket:": "\U0001F680",
 555    ":hourglass:": "\U000023F3",
 556    ":prohibited:": "\U0001F6AB",
 557    ":checked:": "\U00002705",
 558    ":smile:": "\U0001F642",
 559    ":sad:": "\U0001F612",
 560    ":star:": "\U00002B50",
 561    ":zzz:": "\U0001F4A4",
 562    ":mu:": "\U000003BC",
 563    ":pi:": "\U000003C0",
 564    ":sigma:": "\U000003C3",
 565    ":rightarrow:": "\U000027A1",
 566}
 567
 568
 569# terminal or notebook can do color print
 570def _has_colors(stream):
 571    try:
 572        import IPython
 573        return True
 574    except:
 575        pass
 576
 577    if not hasattr(stream, "isatty"):
 578        return False
 579    if not stream.isatty():
 580        return False
 581    return True
 582_terminal_has_colors = _has_colors(sys.stdout)
 583
 584
 585def _is_sequence(arg):
 586    # Check if input is iterable.
 587    if hasattr(arg, "strip"):
 588        return False
 589    if hasattr(arg, "__getslice__"):
 590        return True
 591    if hasattr(arg, "__iter__"):
 592        return True
 593    return False
 594
 595
 596def get_color(rgb=None, hsv=None):
 597    """
 598    Convert a color or list of colors to (r,g,b) format from many different input formats.
 599
 600    Set `hsv` to input as (hue, saturation, value).
 601
 602    Example:
 603         - `RGB    = (255, 255, 255)` corresponds to white
 604         - `rgb    = (1,1,1)` is again white
 605         - `hex    = #FFFF00` is yellow
 606         - `string = 'white'`
 607         - `string = 'w'` is white nickname
 608         - `string = 'dr'` is darkred
 609         - `string = 'red4'` is a shade of red
 610         - `int    =  7` picks color nr. 7 in a predefined color list
 611         - `int    = -7` picks color nr. 7 in a different predefined list
 612
 613
 614    Examples:
 615        - [colorcubes.py](https://github.com/marcomusy/vedo/tree/master/examples/basic/colorcubes.py)
 616
 617            ![](https://vedo.embl.es/images/basic/colorcubes.png)
 618    """
 619    # recursion, return a list if input is list of colors:
 620    if _is_sequence(rgb) and (len(rgb) > 3 or _is_sequence(rgb[0])):
 621        seqcol = []
 622        for sc in rgb:
 623            seqcol.append(get_color(sc))
 624        return seqcol
 625
 626    # because they are most common:
 627    if isinstance(rgb, str):
 628        if rgb == "r":
 629            return (0.9960784313725, 0.11764705882352, 0.121568627450980)
 630        elif rgb == "g":
 631            return (0.0156862745098, 0.49803921568627, 0.062745098039215)
 632        elif rgb == "b":
 633            return (0.0588235294117, 0.0, 0.984313725490196)
 634
 635    if str(rgb).isdigit():
 636        rgb = int(rgb)
 637
 638    if hsv:
 639        c = hsv2rgb(hsv)
 640    else:
 641        c = rgb
 642
 643    if _is_sequence(c):
 644        if c[0] <= 1 and c[1] <= 1 and c[2] <= 1:
 645            return c  # already rgb
 646        if len(c) == 3:
 647            return list(np.array(c) / 255.0)  # RGB
 648        return (c[0] / 255.0, c[1] / 255.0, c[2] / 255.0, c[3])  # RGBA
 649
 650    elif isinstance(c, str):  # is string
 651        c = c.replace("grey", "gray").replace(" ", "")
 652        if 0 < len(c) < 3:  # single/double letter color
 653            if c.lower() in color_nicks:
 654                c = color_nicks[c.lower()]
 655            else:
 656                # vedo.logger.warning(
 657                #     f"Unknown color nickname {c}\nAvailable abbreviations: {color_nicks}"
 658                # )
 659                return (0.5, 0.5, 0.5)
 660
 661        if c.lower() in colors:  # matplotlib name color
 662            c = colors[c.lower()]
 663            # from now format is hex!
 664
 665        if c.startswith("#"):  # hex to rgb
 666            h = c.lstrip("#")
 667            rgb255 = list(int(h[i : i + 2], 16) for i in (0, 2, 4))
 668            rgbh = np.array(rgb255) / 255.0
 669            if np.sum(rgbh) > 3:
 670                vedo.logger.error(f"in get_color(): Wrong hex color {c}")
 671                return (0.5, 0.5, 0.5)
 672            return tuple(rgbh)
 673
 674        else:  # vtk name color
 675            namedColors = vtki.new("NamedColors")
 676            rgba = [0, 0, 0, 0]
 677            namedColors.GetColor(c, rgba)
 678            return (rgba[0] / 255.0, rgba[1] / 255.0, rgba[2] / 255.0)
 679
 680    elif isinstance(c, (int, float)):  # color number
 681        return palettes[vedo.settings.palette % len(palettes)][abs(int(c)) % 10]
 682
 683    return (0.5, 0.5, 0.5)
 684
 685
 686def get_color_name(c) -> str:
 687    """Find the name of the closest color."""
 688    c = np.array(get_color(c))  # reformat to rgb
 689    mdist = 99.0
 690    kclosest = ""
 691    for key in colors:
 692        ci = np.array(get_color(key))
 693        d = np.linalg.norm(c - ci)
 694        if d < mdist:
 695            mdist = d
 696            kclosest = str(key)
 697    return kclosest
 698
 699
 700def hsv2rgb(hsv: list) -> list:
 701    """Convert HSV to RGB color."""
 702    ma = vtki.new("Math")
 703    rgb = [0, 0, 0]
 704    ma.HSVToRGB(hsv, rgb)
 705    return rgb
 706
 707
 708def rgb2hsv(rgb: list) -> list:
 709    """Convert RGB to HSV color."""
 710    ma = vtki.new("Math")
 711    hsv = [0, 0, 0]
 712    ma.RGBToHSV(get_color(rgb), hsv)
 713    return hsv
 714
 715
 716def rgb2hex(rgb: list) -> str:
 717    """Convert RGB to Hex color."""
 718    h = "#%02x%02x%02x" % (int(rgb[0] * 255), int(rgb[1] * 255), int(rgb[2] * 255))
 719    return h
 720
 721
 722def hex2rgb(hx: str) -> list:
 723    """Convert Hex to rgb color."""
 724    h = hx.lstrip("#")
 725    rgb255 = [int(h[i : i + 2], 16) for i in (0, 2, 4)]
 726    return (rgb255[0] / 255.0, rgb255[1] / 255.0, rgb255[2] / 255.0)
 727
 728
 729def color_map(value, name="jet", vmin=None, vmax=None):
 730    """
 731    Map a real value in range [vmin, vmax] to a (r,g,b) color scale.
 732
 733    Return the (r,g,b) color, or a list of (r,g,b) colors.
 734
 735    Arguments:
 736        value : (float, list)
 737            scalar value to transform into a color
 738        name : (str, matplotlib.colors.LinearSegmentedColormap)
 739            color map name
 740
 741    Very frequently used color maps are:
 742
 743        ![](https://user-images.githubusercontent.com/32848391/50738804-577e1680-11d8-11e9-929e-fca17a8ac6f3.jpg)
 744
 745    A more complete color maps list:
 746
 747        ![](https://matplotlib.org/1.2.1/_images/show_colormaps.png)
 748
 749    .. note:: Can also directly use and customize a matplotlib color map
 750
 751    Example:
 752        ```python
 753        import matplotlib
 754        from vedo import color_map
 755        rgb = color_map(0.2, matplotlib.colormaps["jet"], 0, 1)
 756        print("rgb =", rgb)  # [0.0, 0.3, 1.0]
 757        ```
 758
 759    Examples:
 760        - [plot_bars.py](https://github.com/marcomusy/vedo/tree/master/examples/pyplot/plot_bars.py)
 761
 762            <img src="https://vedo.embl.es/images/pyplot/plot_bars.png" width="400"/>
 763
 764    """
 765    cut = _is_sequence(value)  # to speed up later
 766
 767    if cut:
 768        values = np.asarray(value)
 769        if vmin is None:
 770            vmin = np.min(values)
 771        if vmax is None:
 772            vmax = np.max(values)
 773        values = np.clip(values, vmin, vmax)
 774        values = (values - vmin) / (vmax - vmin)
 775    else:
 776        if vmin is None:
 777            vedo.logger.warning("in color_map() you must specify vmin! Assume 0.")
 778            vmin = 0
 779        if vmax is None:
 780            vedo.logger.warning("in color_map() you must specify vmax! Assume 1.")
 781            vmax = 1
 782        if vmax == vmin:
 783            values = [value - vmin]
 784        else:
 785            values = [(value - vmin) / (vmax - vmin)]
 786
 787    if _has_matplotlib:
 788        # matplotlib is available, use it! ###########################
 789        if isinstance(name, str):
 790            mp = matplotlib.colormaps[name]
 791        else:
 792            mp = name  # assume matplotlib.colors.LinearSegmentedColormap
 793        result = mp(values)[:, [0, 1, 2]]
 794
 795    else:
 796        # matplotlib not available ###################################
 797        invert = False
 798        if name.endswith("_r"):
 799            invert = True
 800            name = name.replace("_r", "")
 801        try:
 802            cmap = cmaps[name]
 803        except KeyError:
 804            vedo.logger.error(f"in color_map(), no color map with name {name} or {name}_r")
 805            vedo.logger.error(f"Available color maps are:\n{cmaps.keys()}")
 806            return np.array([0.5, 0.5, 0.5])
 807
 808        result = []
 809        n = len(cmap) - 1
 810        for v in values:
 811            iv = int(v * n)
 812            if invert:
 813                iv = n - iv
 814            rgb = hex2rgb(cmap[iv])
 815            result.append(rgb)
 816        result = np.array(result)
 817
 818    if cut:
 819        return result
 820    return result[0]
 821
 822
 823def build_palette(color1, color2, n, hsv=True) -> np.ndarray:
 824    """
 825    Generate N colors starting from `color1` to `color2`
 826    by linear interpolation in HSV or RGB spaces.
 827
 828    Arguments:
 829        N : (int)
 830            number of output colors.
 831        color1 : (color)
 832            first color.
 833        color2 : (color)
 834            second color.
 835        hsv : (bool)
 836            if `False`, interpolation is calculated in RGB space.
 837
 838    Examples:
 839        - [mesh_custom.py](https://github.com/marcomusy/vedo/tree/master/examples/basic/mesh_custom.py)
 840
 841            ![](https://vedo.embl.es/images/basic/mesh_custom.png)
 842    """
 843    if hsv:
 844        color1 = rgb2hsv(color1)
 845        color2 = rgb2hsv(color2)
 846    c1 = np.array(get_color(color1))
 847    c2 = np.array(get_color(color2))
 848    cols = []
 849    for f in np.linspace(0, 1, n, endpoint=True):
 850        c = c1 * (1 - f) + c2 * f
 851        if hsv:
 852            c = np.array(hsv2rgb(c))
 853        cols.append(c)
 854    return np.array(cols)
 855
 856
 857def build_lut(
 858    colorlist,
 859    vmin=None,
 860    vmax=None,
 861    below_color=None,
 862    above_color=None,
 863    nan_color=None,
 864    below_alpha=1,
 865    above_alpha=1,
 866    nan_alpha=1,
 867    interpolate=False,
 868) -> vtki.vtkLookupTable:
 869    """
 870    Generate colors in a lookup table (LUT).
 871
 872    Return the `vtkLookupTable` object. This can be fed into `cmap()` method.
 873
 874    Arguments:
 875        colorlist : (list)
 876            a list in the form `[(scalar1, [r,g,b]), (scalar2, 'blue'), ...]`.
 877        vmin : (float)
 878            specify minimum value of scalar range
 879        vmax : (float)
 880            specify maximum value of scalar range
 881        below_color : (color)
 882            color for scalars below the minimum in range
 883        below_alpha : (float)
 884            opacity for scalars below the minimum in range
 885        above_color : (color)
 886            color for scalars above the maximum in range
 887        above_alpha : (float)
 888            alpha for scalars above the maximum in range
 889        nan_color : (color)
 890            color for invalid (nan) scalars
 891        nan_alpha : (float)
 892            alpha for invalid (nan) scalars
 893        interpolate : (bool)
 894            interpolate or not intermediate scalars
 895
 896    Examples:
 897        - [mesh_lut.py](https://github.com/marcomusy/vedo/tree/master/examples/basic/mesh_lut.py)
 898
 899            ![](https://vedo.embl.es/images/basic/mesh_lut.png)
 900    """
 901    ctf = vtki.new("ColorTransferFunction")
 902    ctf.SetColorSpaceToRGB()
 903    ctf.SetScaleToLinear()
 904
 905    alpha_x, alpha_vals = [], []
 906    for sc in colorlist:
 907        if len(sc) >= 3:
 908            scalar, col, alf = sc[:3]
 909        else:
 910            alf = 1
 911            scalar, col = sc
 912        r, g, b = get_color(col)
 913        ctf.AddRGBPoint(scalar, r, g, b)
 914        alpha_x.append(scalar)
 915        alpha_vals.append(alf)
 916
 917    ncols = max(256, len(colorlist))
 918    if not interpolate:
 919        ncols = len(colorlist)
 920
 921    lut = vtki.new("LookupTable")
 922    lut.SetNumberOfTableValues(ncols)
 923
 924    x0, x1 = ctf.GetRange()  # range of the introduced values
 925    if vmin is not None:
 926        x0 = vmin
 927    if vmax is not None:
 928        x1 = vmax
 929    ctf.SetRange(x0, x1)
 930    lut.SetRange(x0, x1)
 931
 932    if below_color is not None:
 933        lut.SetBelowRangeColor(list(get_color(below_color)) + [below_alpha])
 934        lut.SetUseBelowRangeColor(True)
 935    if above_color is not None:
 936        lut.SetAboveRangeColor(list(get_color(above_color)) + [above_alpha])
 937        lut.SetUseAboveRangeColor(True)
 938    if nan_color is not None:
 939        lut.SetNanColor(list(get_color(nan_color)) + [nan_alpha])
 940
 941    if interpolate:
 942        for i in range(ncols):
 943            p = i / (ncols-1)
 944            x = (1 - p) * x0 + p * x1
 945            alf = np.interp(x, alpha_x, alpha_vals)
 946            rgba = list(ctf.GetColor(x)) + [alf]
 947            lut.SetTableValue(i, rgba)
 948    else:
 949        for i in range(ncols):
 950            if len(colorlist[i]) > 2:
 951                alpha = colorlist[i][2]
 952            else:
 953                alpha = 1.0
 954            # print("colorlist entry:", colorlist[i])
 955            rgba = list(get_color(colorlist[i][1])) + [alpha]
 956            lut.SetTableValue(i, rgba)
 957
 958    lut.Build()
 959    return lut
 960
 961
 962#########################################################################
 963def printc(
 964    *strings,
 965    c=None,
 966    bc=None,
 967    bold=True,
 968    italic=False,
 969    blink=False,
 970    underline=False,
 971    strike=False,
 972    dim=False,
 973    invert=False,
 974    box="",
 975    link="",
 976    end="\n",
 977    flush=True,
 978    delay=0,
 979    return_string=False,
 980):
 981    """
 982    Print to terminal in color (any color!).
 983
 984    Arguments:
 985        c : (color)
 986            foreground color name or (r,g,b)
 987        bc : (color)
 988            background color name or (r,g,b)
 989        bold : (bool)
 990            boldface [True]
 991        italic : (bool)
 992            italic [False]
 993        blink : (bool)
 994            blinking text [False]
 995        underline : (bool)
 996            underline text [False]
 997        strike : (bool)
 998            strike through text [False]
 999        dim : (bool)
1000            make text look dimmer [False]
1001        invert : (bool)
1002            invert background and forward colors [False]
1003        box : (bool)
1004            print a box with specified text character ['']
1005        link : (str)
1006            print a clickable url link (works on Linux)
1007            (must press Ctrl+click to open the link)
1008        flush : (bool)
1009            flush buffer after printing [True]
1010        delay : (float)
1011            print only every `delay` seconds
1012        return_string : (bool)
1013            return the string without printing it [False]
1014        end : (str)
1015            the end character to be printed [newline]
1016
1017    Example:
1018        ```python
1019        from vedo.colors import printc
1020        printc('anything', c='tomato', bold=False, end=' ')
1021        printc('anything', 455.5, c='lightblue')
1022        printc(299792.48, c=4)
1023        ```
1024
1025    Examples:
1026        - [printc.py](https://github.com/marcomusy/vedo/tree/master/examples/other/printc.py)
1027
1028        ![](https://user-images.githubusercontent.com/32848391/50739010-2bfc2b80-11da-11e9-94de-011e50a86e61.jpg)
1029    """
1030
1031    if delay:
1032        tm = time()
1033        if tm - _printc_delay_timestamp[0] > delay:
1034            _printc_delay_timestamp[0] = tm
1035        else:
1036            return ''  # skip print
1037
1038    if not vedo.settings.enable_print_color or not _terminal_has_colors:
1039        if return_string:
1040            return ''.join(strings)
1041        else:
1042            print(*strings, end=end, flush=flush)
1043            return ''
1044
1045    try:  # -------------------------------------------------------------
1046
1047        txt = str()
1048        ns = len(strings) - 1
1049        separator = " "
1050        offset = 0
1051        for i, s in enumerate(strings):
1052            if i == ns:
1053                separator = ""
1054            if ":" in repr(s):
1055                for k in emoji:
1056                    if k in str(s):
1057                        s = s.replace(k, emoji[k])
1058                        offset += 1
1059                for k, rp in vedo.shapes._reps:  # check symbols in shapes._reps
1060                    if k in str(s):
1061                        s = s.replace(k, rp)
1062                        offset += 1
1063
1064            txt += str(s) + separator
1065
1066        special, cseq = "", ""
1067        oneletter_colors = {
1068            "k": "\u001b[30m",  # because these are supported by most terminals
1069            "r": "\u001b[31m",
1070            "g": "\u001b[32m",
1071            "y": "\u001b[33m",
1072            "b": "\u001b[34m",
1073            "m": "\u001b[35m",
1074            "c": "\u001b[36m",
1075            "w": "\u001b[37m",
1076        }
1077
1078        if c is not None:
1079            if c is True:
1080                c = "g"
1081            elif c is False:
1082                c = "r"
1083
1084            if isinstance(c, str) and c in oneletter_colors:
1085                cseq += oneletter_colors[c]
1086            else:
1087                r, g, b = get_color(c)  # not all terms support this syntax
1088                cseq += f"\x1b[38;2;{int(r*255)};{int(g*255)};{int(b*255)}m"
1089
1090        if bc:
1091            if bc in oneletter_colors:
1092                cseq += oneletter_colors[bc]
1093            else:
1094                r, g, b = get_color(bc)
1095                cseq += f"\x1b[48;2;{int(r*255)};{int(g*255)};{int(b*255)}m"
1096
1097        if box is True:
1098            box = "-"
1099        if underline and not box:
1100            special += "\x1b[4m"
1101        if strike and not box:
1102            special += "\x1b[9m"
1103        if dim:
1104            special += "\x1b[2m"
1105        if invert:
1106            special += "\x1b[7m"
1107        if bold:
1108            special += "\x1b[1m"
1109        if italic:
1110            special += "\x1b[3m"
1111        if blink:
1112            special += "\x1b[5m"
1113
1114        if box and "\n" not in txt:
1115            box = box[0]
1116            boxv = box
1117            if box in ["_", "=", "-", "+", "~"]:
1118                boxv = "|"
1119
1120            if box in ("_", "."):
1121                outtxt = special + cseq + " " + box * (len(txt) + offset + 2) + " \n"
1122                outtxt += boxv + " " * (len(txt) + 2) + boxv + "\n"
1123            else:
1124                outtxt = special + cseq + box * (len(txt) + offset + 4) + "\n"
1125
1126            outtxt += boxv + " " + txt + " " + boxv + "\n"
1127
1128            if box == "_":
1129                outtxt += "|" + box * (len(txt) + offset + 2) + "|" + reset + end
1130            else:
1131                outtxt += box * (len(txt) + offset + 4) + reset + end
1132
1133            sys.stdout.write(outtxt)
1134
1135        else:
1136
1137            out = special + cseq + txt + reset
1138
1139            if link:
1140                # embed a link in the terminal
1141                out = f"\x1b]8;;{link}\x1b\\{out}\x1b]8;;\x1b\\"
1142
1143            if return_string:
1144                return out + end
1145            else:
1146                sys.stdout.write(out + end)
1147
1148    except:  # --------------------------------------------------- fallback
1149
1150        if return_string:
1151            return ''.join(strings)
1152
1153        try:
1154            print(*strings, end=end)
1155        except UnicodeEncodeError as e:
1156            print(e, end=end)
1157
1158    if flush:
1159        sys.stdout.flush()
1160    return ''
1161
1162
1163def printd(*strings, q=False):
1164    """
1165    Print debug information about the environment where the printd() is called.
1166    Local variables are printed out with their current values.
1167
1168    Use `q` to quit (exit) the python session after the printd call.
1169    """
1170    from inspect import currentframe, getframeinfo
1171
1172    cf = currentframe().f_back
1173    cfi = getframeinfo(cf)
1174
1175    fname = os.path.basename(getframeinfo(cf).filename)
1176    print("\x1b[7m\x1b[3m\x1b[37m" + fname + " line:\x1b[1m" + str(cfi.lineno) + reset, end="")
1177    print("\x1b[3m\x1b[37m\x1b[2m", "\U00002501" * 30, ctime(), reset)
1178    if strings:
1179        print("    \x1b[37m\x1b[1mMessage : ", *strings)
1180    print("    \x1b[37m\x1b[1mFunction:\x1b[0m\x1b[37m " + str(cfi.function))
1181    print("    \x1b[1mLocals  :" + reset)
1182    for loc in cf.f_locals.keys():
1183        obj = cf.f_locals[loc]
1184        var = repr(obj)
1185        if 'module ' in var: continue
1186        if 'function ' in var: continue
1187        if 'class ' in var: continue
1188        if loc.startswith('_'): continue
1189        if hasattr(obj, 'name'):
1190            if not obj.name:
1191                oname = str(type(obj))
1192            else:
1193                oname = obj.name
1194            var = oname + ", at " + vedo.utils.precision(obj.GetPosition(), 3)
1195
1196        var = var.replace("vtkmodules.", "")
1197        print("      \x1b[37m", loc, "\t\t=", var[:60].replace("\n", ""), reset)
1198        if vedo.utils.is_sequence(obj) and len(obj) > 4:
1199            print('           \x1b[37m\x1b[2m\x1b[3m len:', len(obj),
1200                  ' min:', vedo.utils.precision(min(obj), 4),
1201                  ' max:', vedo.utils.precision(max(obj), 4),
1202                  reset)
1203
1204    if q:
1205        print(f"    \x1b[1m\x1b[37mExiting python now (q={bool(q)}).\x1b[0m\x1b[37m")
1206        sys.exit(0)
1207    sys.stdout.flush()
def printc( *strings, c=None, bc=None, bold=True, italic=False, blink=False, underline=False, strike=False, dim=False, invert=False, box='', link='', end='\n', flush=True, delay=0, return_string=False):
 964def printc(
 965    *strings,
 966    c=None,
 967    bc=None,
 968    bold=True,
 969    italic=False,
 970    blink=False,
 971    underline=False,
 972    strike=False,
 973    dim=False,
 974    invert=False,
 975    box="",
 976    link="",
 977    end="\n",
 978    flush=True,
 979    delay=0,
 980    return_string=False,
 981):
 982    """
 983    Print to terminal in color (any color!).
 984
 985    Arguments:
 986        c : (color)
 987            foreground color name or (r,g,b)
 988        bc : (color)
 989            background color name or (r,g,b)
 990        bold : (bool)
 991            boldface [True]
 992        italic : (bool)
 993            italic [False]
 994        blink : (bool)
 995            blinking text [False]
 996        underline : (bool)
 997            underline text [False]
 998        strike : (bool)
 999            strike through text [False]
1000        dim : (bool)
1001            make text look dimmer [False]
1002        invert : (bool)
1003            invert background and forward colors [False]
1004        box : (bool)
1005            print a box with specified text character ['']
1006        link : (str)
1007            print a clickable url link (works on Linux)
1008            (must press Ctrl+click to open the link)
1009        flush : (bool)
1010            flush buffer after printing [True]
1011        delay : (float)
1012            print only every `delay` seconds
1013        return_string : (bool)
1014            return the string without printing it [False]
1015        end : (str)
1016            the end character to be printed [newline]
1017
1018    Example:
1019        ```python
1020        from vedo.colors import printc
1021        printc('anything', c='tomato', bold=False, end=' ')
1022        printc('anything', 455.5, c='lightblue')
1023        printc(299792.48, c=4)
1024        ```
1025
1026    Examples:
1027        - [printc.py](https://github.com/marcomusy/vedo/tree/master/examples/other/printc.py)
1028
1029        ![](https://user-images.githubusercontent.com/32848391/50739010-2bfc2b80-11da-11e9-94de-011e50a86e61.jpg)
1030    """
1031
1032    if delay:
1033        tm = time()
1034        if tm - _printc_delay_timestamp[0] > delay:
1035            _printc_delay_timestamp[0] = tm
1036        else:
1037            return ''  # skip print
1038
1039    if not vedo.settings.enable_print_color or not _terminal_has_colors:
1040        if return_string:
1041            return ''.join(strings)
1042        else:
1043            print(*strings, end=end, flush=flush)
1044            return ''
1045
1046    try:  # -------------------------------------------------------------
1047
1048        txt = str()
1049        ns = len(strings) - 1
1050        separator = " "
1051        offset = 0
1052        for i, s in enumerate(strings):
1053            if i == ns:
1054                separator = ""
1055            if ":" in repr(s):
1056                for k in emoji:
1057                    if k in str(s):
1058                        s = s.replace(k, emoji[k])
1059                        offset += 1
1060                for k, rp in vedo.shapes._reps:  # check symbols in shapes._reps
1061                    if k in str(s):
1062                        s = s.replace(k, rp)
1063                        offset += 1
1064
1065            txt += str(s) + separator
1066
1067        special, cseq = "", ""
1068        oneletter_colors = {
1069            "k": "\u001b[30m",  # because these are supported by most terminals
1070            "r": "\u001b[31m",
1071            "g": "\u001b[32m",
1072            "y": "\u001b[33m",
1073            "b": "\u001b[34m",
1074            "m": "\u001b[35m",
1075            "c": "\u001b[36m",
1076            "w": "\u001b[37m",
1077        }
1078
1079        if c is not None:
1080            if c is True:
1081                c = "g"
1082            elif c is False:
1083                c = "r"
1084
1085            if isinstance(c, str) and c in oneletter_colors:
1086                cseq += oneletter_colors[c]
1087            else:
1088                r, g, b = get_color(c)  # not all terms support this syntax
1089                cseq += f"\x1b[38;2;{int(r*255)};{int(g*255)};{int(b*255)}m"
1090
1091        if bc:
1092            if bc in oneletter_colors:
1093                cseq += oneletter_colors[bc]
1094            else:
1095                r, g, b = get_color(bc)
1096                cseq += f"\x1b[48;2;{int(r*255)};{int(g*255)};{int(b*255)}m"
1097
1098        if box is True:
1099            box = "-"
1100        if underline and not box:
1101            special += "\x1b[4m"
1102        if strike and not box:
1103            special += "\x1b[9m"
1104        if dim:
1105            special += "\x1b[2m"
1106        if invert:
1107            special += "\x1b[7m"
1108        if bold:
1109            special += "\x1b[1m"
1110        if italic:
1111            special += "\x1b[3m"
1112        if blink:
1113            special += "\x1b[5m"
1114
1115        if box and "\n" not in txt:
1116            box = box[0]
1117            boxv = box
1118            if box in ["_", "=", "-", "+", "~"]:
1119                boxv = "|"
1120
1121            if box in ("_", "."):
1122                outtxt = special + cseq + " " + box * (len(txt) + offset + 2) + " \n"
1123                outtxt += boxv + " " * (len(txt) + 2) + boxv + "\n"
1124            else:
1125                outtxt = special + cseq + box * (len(txt) + offset + 4) + "\n"
1126
1127            outtxt += boxv + " " + txt + " " + boxv + "\n"
1128
1129            if box == "_":
1130                outtxt += "|" + box * (len(txt) + offset + 2) + "|" + reset + end
1131            else:
1132                outtxt += box * (len(txt) + offset + 4) + reset + end
1133
1134            sys.stdout.write(outtxt)
1135
1136        else:
1137
1138            out = special + cseq + txt + reset
1139
1140            if link:
1141                # embed a link in the terminal
1142                out = f"\x1b]8;;{link}\x1b\\{out}\x1b]8;;\x1b\\"
1143
1144            if return_string:
1145                return out + end
1146            else:
1147                sys.stdout.write(out + end)
1148
1149    except:  # --------------------------------------------------- fallback
1150
1151        if return_string:
1152            return ''.join(strings)
1153
1154        try:
1155            print(*strings, end=end)
1156        except UnicodeEncodeError as e:
1157            print(e, end=end)
1158
1159    if flush:
1160        sys.stdout.flush()
1161    return ''

Print to terminal in color (any color!).

Arguments:
  • c : (color) foreground color name or (r,g,b)
  • bc : (color) background color name or (r,g,b)
  • bold : (bool) boldface [True]
  • italic : (bool) italic [False]
  • blink : (bool) blinking text [False]
  • underline : (bool) underline text [False]
  • strike : (bool) strike through text [False]
  • dim : (bool) make text look dimmer [False]
  • invert : (bool) invert background and forward colors [False]
  • box : (bool) print a box with specified text character ['']
  • link : (str) print a clickable url link (works on Linux) (must press Ctrl+click to open the link)
  • flush : (bool) flush buffer after printing [True]
  • delay : (float) print only every delay seconds
  • return_string : (bool) return the string without printing it [False]
  • end : (str) the end character to be printed [newline]
Example:
from vedo.colors import printc
printc('anything', c='tomato', bold=False, end=' ')
printc('anything', 455.5, c='lightblue')
printc(299792.48, c=4)
Examples:

def printd(*strings, q=False):
1164def printd(*strings, q=False):
1165    """
1166    Print debug information about the environment where the printd() is called.
1167    Local variables are printed out with their current values.
1168
1169    Use `q` to quit (exit) the python session after the printd call.
1170    """
1171    from inspect import currentframe, getframeinfo
1172
1173    cf = currentframe().f_back
1174    cfi = getframeinfo(cf)
1175
1176    fname = os.path.basename(getframeinfo(cf).filename)
1177    print("\x1b[7m\x1b[3m\x1b[37m" + fname + " line:\x1b[1m" + str(cfi.lineno) + reset, end="")
1178    print("\x1b[3m\x1b[37m\x1b[2m", "\U00002501" * 30, ctime(), reset)
1179    if strings:
1180        print("    \x1b[37m\x1b[1mMessage : ", *strings)
1181    print("    \x1b[37m\x1b[1mFunction:\x1b[0m\x1b[37m " + str(cfi.function))
1182    print("    \x1b[1mLocals  :" + reset)
1183    for loc in cf.f_locals.keys():
1184        obj = cf.f_locals[loc]
1185        var = repr(obj)
1186        if 'module ' in var: continue
1187        if 'function ' in var: continue
1188        if 'class ' in var: continue
1189        if loc.startswith('_'): continue
1190        if hasattr(obj, 'name'):
1191            if not obj.name:
1192                oname = str(type(obj))
1193            else:
1194                oname = obj.name
1195            var = oname + ", at " + vedo.utils.precision(obj.GetPosition(), 3)
1196
1197        var = var.replace("vtkmodules.", "")
1198        print("      \x1b[37m", loc, "\t\t=", var[:60].replace("\n", ""), reset)
1199        if vedo.utils.is_sequence(obj) and len(obj) > 4:
1200            print('           \x1b[37m\x1b[2m\x1b[3m len:', len(obj),
1201                  ' min:', vedo.utils.precision(min(obj), 4),
1202                  ' max:', vedo.utils.precision(max(obj), 4),
1203                  reset)
1204
1205    if q:
1206        print(f"    \x1b[1m\x1b[37mExiting python now (q={bool(q)}).\x1b[0m\x1b[37m")
1207        sys.exit(0)
1208    sys.stdout.flush()

Print debug information about the environment where the printd() is called. Local variables are printed out with their current values.

Use q to quit (exit) the python session after the printd call.

def get_color(rgb=None, hsv=None):
597def get_color(rgb=None, hsv=None):
598    """
599    Convert a color or list of colors to (r,g,b) format from many different input formats.
600
601    Set `hsv` to input as (hue, saturation, value).
602
603    Example:
604         - `RGB    = (255, 255, 255)` corresponds to white
605         - `rgb    = (1,1,1)` is again white
606         - `hex    = #FFFF00` is yellow
607         - `string = 'white'`
608         - `string = 'w'` is white nickname
609         - `string = 'dr'` is darkred
610         - `string = 'red4'` is a shade of red
611         - `int    =  7` picks color nr. 7 in a predefined color list
612         - `int    = -7` picks color nr. 7 in a different predefined list
613
614
615    Examples:
616        - [colorcubes.py](https://github.com/marcomusy/vedo/tree/master/examples/basic/colorcubes.py)
617
618            ![](https://vedo.embl.es/images/basic/colorcubes.png)
619    """
620    # recursion, return a list if input is list of colors:
621    if _is_sequence(rgb) and (len(rgb) > 3 or _is_sequence(rgb[0])):
622        seqcol = []
623        for sc in rgb:
624            seqcol.append(get_color(sc))
625        return seqcol
626
627    # because they are most common:
628    if isinstance(rgb, str):
629        if rgb == "r":
630            return (0.9960784313725, 0.11764705882352, 0.121568627450980)
631        elif rgb == "g":
632            return (0.0156862745098, 0.49803921568627, 0.062745098039215)
633        elif rgb == "b":
634            return (0.0588235294117, 0.0, 0.984313725490196)
635
636    if str(rgb).isdigit():
637        rgb = int(rgb)
638
639    if hsv:
640        c = hsv2rgb(hsv)
641    else:
642        c = rgb
643
644    if _is_sequence(c):
645        if c[0] <= 1 and c[1] <= 1 and c[2] <= 1:
646            return c  # already rgb
647        if len(c) == 3:
648            return list(np.array(c) / 255.0)  # RGB
649        return (c[0] / 255.0, c[1] / 255.0, c[2] / 255.0, c[3])  # RGBA
650
651    elif isinstance(c, str):  # is string
652        c = c.replace("grey", "gray").replace(" ", "")
653        if 0 < len(c) < 3:  # single/double letter color
654            if c.lower() in color_nicks:
655                c = color_nicks[c.lower()]
656            else:
657                # vedo.logger.warning(
658                #     f"Unknown color nickname {c}\nAvailable abbreviations: {color_nicks}"
659                # )
660                return (0.5, 0.5, 0.5)
661
662        if c.lower() in colors:  # matplotlib name color
663            c = colors[c.lower()]
664            # from now format is hex!
665
666        if c.startswith("#"):  # hex to rgb
667            h = c.lstrip("#")
668            rgb255 = list(int(h[i : i + 2], 16) for i in (0, 2, 4))
669            rgbh = np.array(rgb255) / 255.0
670            if np.sum(rgbh) > 3:
671                vedo.logger.error(f"in get_color(): Wrong hex color {c}")
672                return (0.5, 0.5, 0.5)
673            return tuple(rgbh)
674
675        else:  # vtk name color
676            namedColors = vtki.new("NamedColors")
677            rgba = [0, 0, 0, 0]
678            namedColors.GetColor(c, rgba)
679            return (rgba[0] / 255.0, rgba[1] / 255.0, rgba[2] / 255.0)
680
681    elif isinstance(c, (int, float)):  # color number
682        return palettes[vedo.settings.palette % len(palettes)][abs(int(c)) % 10]
683
684    return (0.5, 0.5, 0.5)

Convert a color or list of colors to (r,g,b) format from many different input formats.

Set hsv to input as (hue, saturation, value).

Example:
  • RGB = (255, 255, 255) corresponds to white
  • rgb = (1,1,1) is again white
  • hex = #FFFF00 is yellow
  • string = 'white'
  • string = 'w' is white nickname
  • string = 'dr' is darkred
  • string = 'red4' is a shade of red
  • int = 7 picks color nr. 7 in a predefined color list
  • int = -7 picks color nr. 7 in a different predefined list
Examples:
def get_color_name(c) -> str:
687def get_color_name(c) -> str:
688    """Find the name of the closest color."""
689    c = np.array(get_color(c))  # reformat to rgb
690    mdist = 99.0
691    kclosest = ""
692    for key in colors:
693        ci = np.array(get_color(key))
694        d = np.linalg.norm(c - ci)
695        if d < mdist:
696            mdist = d
697            kclosest = str(key)
698    return kclosest

Find the name of the closest color.

def color_map(value, name='jet', vmin=None, vmax=None):
730def color_map(value, name="jet", vmin=None, vmax=None):
731    """
732    Map a real value in range [vmin, vmax] to a (r,g,b) color scale.
733
734    Return the (r,g,b) color, or a list of (r,g,b) colors.
735
736    Arguments:
737        value : (float, list)
738            scalar value to transform into a color
739        name : (str, matplotlib.colors.LinearSegmentedColormap)
740            color map name
741
742    Very frequently used color maps are:
743
744        ![](https://user-images.githubusercontent.com/32848391/50738804-577e1680-11d8-11e9-929e-fca17a8ac6f3.jpg)
745
746    A more complete color maps list:
747
748        ![](https://matplotlib.org/1.2.1/_images/show_colormaps.png)
749
750    .. note:: Can also directly use and customize a matplotlib color map
751
752    Example:
753        ```python
754        import matplotlib
755        from vedo import color_map
756        rgb = color_map(0.2, matplotlib.colormaps["jet"], 0, 1)
757        print("rgb =", rgb)  # [0.0, 0.3, 1.0]
758        ```
759
760    Examples:
761        - [plot_bars.py](https://github.com/marcomusy/vedo/tree/master/examples/pyplot/plot_bars.py)
762
763            <img src="https://vedo.embl.es/images/pyplot/plot_bars.png" width="400"/>
764
765    """
766    cut = _is_sequence(value)  # to speed up later
767
768    if cut:
769        values = np.asarray(value)
770        if vmin is None:
771            vmin = np.min(values)
772        if vmax is None:
773            vmax = np.max(values)
774        values = np.clip(values, vmin, vmax)
775        values = (values - vmin) / (vmax - vmin)
776    else:
777        if vmin is None:
778            vedo.logger.warning("in color_map() you must specify vmin! Assume 0.")
779            vmin = 0
780        if vmax is None:
781            vedo.logger.warning("in color_map() you must specify vmax! Assume 1.")
782            vmax = 1
783        if vmax == vmin:
784            values = [value - vmin]
785        else:
786            values = [(value - vmin) / (vmax - vmin)]
787
788    if _has_matplotlib:
789        # matplotlib is available, use it! ###########################
790        if isinstance(name, str):
791            mp = matplotlib.colormaps[name]
792        else:
793            mp = name  # assume matplotlib.colors.LinearSegmentedColormap
794        result = mp(values)[:, [0, 1, 2]]
795
796    else:
797        # matplotlib not available ###################################
798        invert = False
799        if name.endswith("_r"):
800            invert = True
801            name = name.replace("_r", "")
802        try:
803            cmap = cmaps[name]
804        except KeyError:
805            vedo.logger.error(f"in color_map(), no color map with name {name} or {name}_r")
806            vedo.logger.error(f"Available color maps are:\n{cmaps.keys()}")
807            return np.array([0.5, 0.5, 0.5])
808
809        result = []
810        n = len(cmap) - 1
811        for v in values:
812            iv = int(v * n)
813            if invert:
814                iv = n - iv
815            rgb = hex2rgb(cmap[iv])
816            result.append(rgb)
817        result = np.array(result)
818
819    if cut:
820        return result
821    return result[0]

Map a real value in range [vmin, vmax] to a (r,g,b) color scale.

Return the (r,g,b) color, or a list of (r,g,b) colors.

Arguments:
  • value : (float, list) scalar value to transform into a color
  • name : (str, matplotlib.colors.LinearSegmentedColormap) color map name
Very frequently used color maps are:

A more complete color maps list:

Can also directly use and customize a matplotlib color map
Example:
import matplotlib
from vedo import color_map
rgb = color_map(0.2, matplotlib.colormaps["jet"], 0, 1)
print("rgb =", rgb)  # [0.0, 0.3, 1.0]
Examples:
def build_palette(color1, color2, n, hsv=True) -> numpy.ndarray:
824def build_palette(color1, color2, n, hsv=True) -> np.ndarray:
825    """
826    Generate N colors starting from `color1` to `color2`
827    by linear interpolation in HSV or RGB spaces.
828
829    Arguments:
830        N : (int)
831            number of output colors.
832        color1 : (color)
833            first color.
834        color2 : (color)
835            second color.
836        hsv : (bool)
837            if `False`, interpolation is calculated in RGB space.
838
839    Examples:
840        - [mesh_custom.py](https://github.com/marcomusy/vedo/tree/master/examples/basic/mesh_custom.py)
841
842            ![](https://vedo.embl.es/images/basic/mesh_custom.png)
843    """
844    if hsv:
845        color1 = rgb2hsv(color1)
846        color2 = rgb2hsv(color2)
847    c1 = np.array(get_color(color1))
848    c2 = np.array(get_color(color2))
849    cols = []
850    for f in np.linspace(0, 1, n, endpoint=True):
851        c = c1 * (1 - f) + c2 * f
852        if hsv:
853            c = np.array(hsv2rgb(c))
854        cols.append(c)
855    return np.array(cols)

Generate N colors starting from color1 to color2 by linear interpolation in HSV or RGB spaces.

Arguments:
  • N : (int) number of output colors.
  • color1 : (color) first color.
  • color2 : (color) second color.
  • hsv : (bool) if False, interpolation is calculated in RGB space.
Examples:
def build_lut( colorlist, vmin=None, vmax=None, below_color=None, above_color=None, nan_color=None, below_alpha=1, above_alpha=1, nan_alpha=1, interpolate=False) -> vtkmodules.vtkCommonCore.vtkLookupTable:
858def build_lut(
859    colorlist,
860    vmin=None,
861    vmax=None,
862    below_color=None,
863    above_color=None,
864    nan_color=None,
865    below_alpha=1,
866    above_alpha=1,
867    nan_alpha=1,
868    interpolate=False,
869) -> vtki.vtkLookupTable:
870    """
871    Generate colors in a lookup table (LUT).
872
873    Return the `vtkLookupTable` object. This can be fed into `cmap()` method.
874
875    Arguments:
876        colorlist : (list)
877            a list in the form `[(scalar1, [r,g,b]), (scalar2, 'blue'), ...]`.
878        vmin : (float)
879            specify minimum value of scalar range
880        vmax : (float)
881            specify maximum value of scalar range
882        below_color : (color)
883            color for scalars below the minimum in range
884        below_alpha : (float)
885            opacity for scalars below the minimum in range
886        above_color : (color)
887            color for scalars above the maximum in range
888        above_alpha : (float)
889            alpha for scalars above the maximum in range
890        nan_color : (color)
891            color for invalid (nan) scalars
892        nan_alpha : (float)
893            alpha for invalid (nan) scalars
894        interpolate : (bool)
895            interpolate or not intermediate scalars
896
897    Examples:
898        - [mesh_lut.py](https://github.com/marcomusy/vedo/tree/master/examples/basic/mesh_lut.py)
899
900            ![](https://vedo.embl.es/images/basic/mesh_lut.png)
901    """
902    ctf = vtki.new("ColorTransferFunction")
903    ctf.SetColorSpaceToRGB()
904    ctf.SetScaleToLinear()
905
906    alpha_x, alpha_vals = [], []
907    for sc in colorlist:
908        if len(sc) >= 3:
909            scalar, col, alf = sc[:3]
910        else:
911            alf = 1
912            scalar, col = sc
913        r, g, b = get_color(col)
914        ctf.AddRGBPoint(scalar, r, g, b)
915        alpha_x.append(scalar)
916        alpha_vals.append(alf)
917
918    ncols = max(256, len(colorlist))
919    if not interpolate:
920        ncols = len(colorlist)
921
922    lut = vtki.new("LookupTable")
923    lut.SetNumberOfTableValues(ncols)
924
925    x0, x1 = ctf.GetRange()  # range of the introduced values
926    if vmin is not None:
927        x0 = vmin
928    if vmax is not None:
929        x1 = vmax
930    ctf.SetRange(x0, x1)
931    lut.SetRange(x0, x1)
932
933    if below_color is not None:
934        lut.SetBelowRangeColor(list(get_color(below_color)) + [below_alpha])
935        lut.SetUseBelowRangeColor(True)
936    if above_color is not None:
937        lut.SetAboveRangeColor(list(get_color(above_color)) + [above_alpha])
938        lut.SetUseAboveRangeColor(True)
939    if nan_color is not None:
940        lut.SetNanColor(list(get_color(nan_color)) + [nan_alpha])
941
942    if interpolate:
943        for i in range(ncols):
944            p = i / (ncols-1)
945            x = (1 - p) * x0 + p * x1
946            alf = np.interp(x, alpha_x, alpha_vals)
947            rgba = list(ctf.GetColor(x)) + [alf]
948            lut.SetTableValue(i, rgba)
949    else:
950        for i in range(ncols):
951            if len(colorlist[i]) > 2:
952                alpha = colorlist[i][2]
953            else:
954                alpha = 1.0
955            # print("colorlist entry:", colorlist[i])
956            rgba = list(get_color(colorlist[i][1])) + [alpha]
957            lut.SetTableValue(i, rgba)
958
959    lut.Build()
960    return lut

Generate colors in a lookup table (LUT).

Return the vtkLookupTable object. This can be fed into cmap() method.

Arguments:
  • colorlist : (list) a list in the form [(scalar1, [r,g,b]), (scalar2, 'blue'), ...].
  • vmin : (float) specify minimum value of scalar range
  • vmax : (float) specify maximum value of scalar range
  • below_color : (color) color for scalars below the minimum in range
  • below_alpha : (float) opacity for scalars below the minimum in range
  • above_color : (color) color for scalars above the maximum in range
  • above_alpha : (float) alpha for scalars above the maximum in range
  • nan_color : (color) color for invalid (nan) scalars
  • nan_alpha : (float) alpha for invalid (nan) scalars
  • interpolate : (bool) interpolate or not intermediate scalars
Examples: