vedo.colors

Colors definitions and printing methods.

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

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]
  • 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):
1278def printd(*strings, q=False):
1279    """
1280    Print debug information about the environment where the printd() is called.
1281    Local variables are printed out with their current values.
1282
1283    Use `q` to quit (exit) the python session after the printd call.
1284    """
1285    from inspect import currentframe, getframeinfo
1286
1287    cf = currentframe().f_back
1288    cfi = getframeinfo(cf)
1289
1290    fname = os.path.basename(getframeinfo(cf).filename)
1291    print("\x1b[7m\x1b[3m\x1b[37m" + fname + " line:\x1b[1m" + str(cfi.lineno) + reset, end="")
1292    print("\x1b[3m\x1b[37m\x1b[2m", "\U00002501" * 30, time.ctime(), reset)
1293    if strings:
1294        print("    \x1b[37m\x1b[1mMessage : ", *strings)
1295    print("    \x1b[37m\x1b[1mFunction:\x1b[0m\x1b[37m " + str(cfi.function))
1296    print("    \x1b[1mLocals  :" + reset)
1297    for loc in cf.f_locals.keys():
1298        obj = cf.f_locals[loc]
1299        var = repr(obj)
1300        if 'module ' in var: continue
1301        if 'function ' in var: continue
1302        if 'class ' in var: continue
1303        if loc.startswith('_'): continue
1304        if hasattr(obj, 'name'):
1305            if not obj.name:
1306                oname = str(type(obj))
1307            else:
1308                oname = obj.name
1309            var = oname + ", at " + vedo.utils.precision(obj.GetPosition(), 3)
1310
1311        var = var.replace("vtkmodules.", "")
1312        print("      \x1b[37m", loc, "\t\t=", var[:60].replace("\n", ""), reset)
1313        if vedo.utils.is_sequence(obj) and len(obj) > 4:
1314            print('           \x1b[37m\x1b[2m\x1b[3m len:', len(obj),
1315                  ' min:', vedo.utils.precision(min(obj), 4),
1316                  ' max:', vedo.utils.precision(max(obj), 4),
1317                  reset)
1318
1319    if q:
1320        print(f"    \x1b[1m\x1b[37mExiting python now (q={bool(q)}).\x1b[0m\x1b[37m")
1321        sys.exit(0)
1322    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):
721def get_color(rgb=None, hsv=None):
722    """
723    Convert a color or list of colors to (r,g,b) format from many different input formats.
724
725    Set `hsv` to input as (hue, saturation, value).
726
727    Example:
728         - `RGB    = (255, 255, 255)` corresponds to white
729         - `rgb    = (1,1,1)` is again white
730         - `hex    = #FFFF00` is yellow
731         - `string = 'white'`
732         - `string = 'w'` is white nickname
733         - `string = 'dr'` is darkred
734         - `string = 'red4'` is a shade of red
735         - `int    =  7` picks color nr. 7 in a predefined color list
736         - `int    = -7` picks color nr. 7 in a different predefined list
737
738
739    Examples:
740        - [colorcubes.py](https://github.com/marcomusy/vedo/tree/master/examples/basic/colorcubes.py)
741
742            ![](https://vedo.embl.es/images/basic/colorcubes.png)
743    """
744    # recursion, return a list if input is list of colors:
745    if _is_sequence(rgb) and (len(rgb) > 3 or _is_sequence(rgb[0])):
746        seqcol = []
747        for sc in rgb:
748            seqcol.append(get_color(sc))
749        return seqcol
750
751    # because they are most common:
752    if isinstance(rgb, str):
753        if rgb == "r":
754            return (0.9960784313725, 0.11764705882352, 0.121568627450980)
755        elif rgb == "g":
756            return (0.0156862745098, 0.49803921568627, 0.062745098039215)
757        elif rgb == "b":
758            return (0.0588235294117, 0.0, 0.984313725490196)
759
760    if str(rgb).isdigit():
761        rgb = int(rgb)
762
763    if hsv:
764        c = hsv2rgb(hsv)
765    else:
766        c = rgb
767
768    if _is_sequence(c):
769        if c[0] <= 1 and c[1] <= 1 and c[2] <= 1:
770            return c  # already rgb
771        if len(c) == 3:
772            return list(np.array(c) / 255.0)  # RGB
773        return (c[0] / 255.0, c[1] / 255.0, c[2] / 255.0, c[3])  # RGBA
774
775    elif isinstance(c, str):  # is string
776        c = c.replace("grey", "gray").replace(" ", "")
777        if 0 < len(c) < 3:  # single/double letter color
778            if c.lower() in color_nicks:
779                c = color_nicks[c.lower()]
780            else:
781                # vedo.logger.warning(
782                #     f"Unknown color nickname {c}\nAvailable abbreviations: {color_nicks}"
783                # )
784                return (0.5, 0.5, 0.5)
785
786        if c.lower() in colors:  # matplotlib name color
787            c = colors[c.lower()]
788            # from now format is hex!
789
790        if c.startswith("#"):  # hex to rgb
791            h = c.lstrip("#")
792            rgb255 = list(int(h[i : i + 2], 16) for i in (0, 2, 4))
793            rgbh = np.array(rgb255) / 255.0
794            if np.sum(rgbh) > 3:
795                vedo.logger.error(f"in get_color(): Wrong hex color {c}")
796                return (0.5, 0.5, 0.5)
797            return tuple(rgbh)
798
799        else:  # vtk name color
800            namedColors = vtki.new("NamedColors")
801            rgba = [0, 0, 0, 0]
802            namedColors.GetColor(c, rgba)
803            return (rgba[0] / 255.0, rgba[1] / 255.0, rgba[2] / 255.0)
804
805    elif isinstance(c, (int, float)):  # color number
806        return palettes[vedo.settings.palette % len(palettes)][abs(int(c)) % 10]
807
808    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:
811def get_color_name(c) -> str:
812    """Find the name of the closest color."""
813    c = np.array(get_color(c))  # reformat to rgb
814    mdist = 99.0
815    kclosest = ""
816    for key in colors:
817        ci = np.array(get_color(key))
818        d = np.linalg.norm(c - ci)
819        if d < mdist:
820            mdist = d
821            kclosest = str(key)
822    return kclosest

Find the name of the closest color.

def color_map(value, name='jet', vmin=None, vmax=None):
854def color_map(value, name="jet", vmin=None, vmax=None):
855    """
856    Map a real value in range [vmin, vmax] to a (r,g,b) color scale.
857
858    Return the (r,g,b) color, or a list of (r,g,b) colors.
859
860    Arguments:
861        value : (float, list)
862            scalar value to transform into a color
863        name : (str, matplotlib.colors.LinearSegmentedColormap)
864            color map name
865
866    Very frequently used color maps are:
867
868        ![](https://user-images.githubusercontent.com/32848391/50738804-577e1680-11d8-11e9-929e-fca17a8ac6f3.jpg)
869
870    A more complete color maps list:
871
872        ![](https://matplotlib.org/1.2.1/_images/show_colormaps.png)
873
874    .. note:: Can also directly use and customize a matplotlib color map
875
876    Example:
877        ```python
878        import matplotlib
879        from vedo import color_map
880        rgb = color_map(0.2, matplotlib.colormaps["jet"], 0, 1)
881        print("rgb =", rgb)  # [0.0, 0.3, 1.0]
882        ```
883
884    Examples:
885        - [plot_bars.py](https://github.com/marcomusy/vedo/tree/master/examples/pyplot/plot_bars.py)
886
887            <img src="https://vedo.embl.es/images/pyplot/plot_bars.png" width="400"/>
888
889    """
890    cut = _is_sequence(value)  # to speed up later
891
892    if cut:
893        values = np.asarray(value)
894        if vmin is None:
895            vmin = np.min(values)
896        if vmax is None:
897            vmax = np.max(values)
898        values = np.clip(values, vmin, vmax)
899        values = (values - vmin) / (vmax - vmin)
900    else:
901        if vmin is None:
902            vedo.logger.warning("in color_map() you must specify vmin! Assume 0.")
903            vmin = 0
904        if vmax is None:
905            vedo.logger.warning("in color_map() you must specify vmax! Assume 1.")
906            vmax = 1
907        if vmax == vmin:
908            values = [value - vmin]
909        else:
910            values = [(value - vmin) / (vmax - vmin)]
911
912    if _has_matplotlib:
913        # matplotlib is available, use it! ###########################
914        if isinstance(name, str):
915            mp = matplotlib.colormaps[name]
916        else:
917            mp = name  # assume matplotlib.colors.LinearSegmentedColormap
918        result = mp(values)[:, [0, 1, 2]]
919
920    else:
921        # matplotlib not available ###################################
922        invert = False
923        if name.endswith("_r"):
924            invert = True
925            name = name.replace("_r", "")
926        try:
927            cmap = cmaps[name]
928        except KeyError:
929            vedo.logger.error(f"in color_map(), no color map with name {name} or {name}_r")
930            vedo.logger.error(f"Available color maps are:\n{cmaps.keys()}")
931            return np.array([0.5, 0.5, 0.5])
932
933        result = []
934        n = len(cmap) - 1
935        for v in values:
936            iv = int(v * n)
937            if invert:
938                iv = n - iv
939            rgb = hex2rgb(cmap[iv])
940            result.append(rgb)
941        result = np.array(result)
942
943    if cut:
944        return result
945    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:
948def build_palette(color1, color2, n, hsv=True) -> np.ndarray:
949    """
950    Generate N colors starting from `color1` to `color2`
951    by linear interpolation in HSV or RGB spaces.
952
953    Arguments:
954        N : (int)
955            number of output colors.
956        color1 : (color)
957            first color.
958        color2 : (color)
959            second color.
960        hsv : (bool)
961            if `False`, interpolation is calculated in RGB space.
962
963    Examples:
964        - [mesh_custom.py](https://github.com/marcomusy/vedo/tree/master/examples/basic/mesh_custom.py)
965
966            ![](https://vedo.embl.es/images/basic/mesh_custom.png)
967    """
968    if hsv:
969        color1 = rgb2hsv(color1)
970        color2 = rgb2hsv(color2)
971    c1 = np.array(get_color(color1))
972    c2 = np.array(get_color(color2))
973    cols = []
974    for f in np.linspace(0, 1, n, endpoint=True):
975        c = c1 * (1 - f) + c2 * f
976        if hsv:
977            c = np.array(hsv2rgb(c))
978        cols.append(c)
979    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:
 982def build_lut(
 983    colorlist,
 984    vmin=None,
 985    vmax=None,
 986    below_color=None,
 987    above_color=None,
 988    nan_color=None,
 989    below_alpha=1,
 990    above_alpha=1,
 991    nan_alpha=1,
 992    interpolate=False,
 993) -> vtki.vtkLookupTable:
 994    """
 995    Generate colors in a lookup table (LUT).
 996
 997    Return the `vtkLookupTable` object. This can be fed into `cmap()` method.
 998
 999    Arguments:
1000        colorlist : (list)
1001            a list in the form `[(scalar1, [r,g,b]), (scalar2, 'blue'), ...]`.
1002        vmin : (float)
1003            specify minimum value of scalar range
1004        vmax : (float)
1005            specify maximum value of scalar range
1006        below_color : (color)
1007            color for scalars below the minimum in range
1008        below_alpha : (float)
1009            opacity for scalars below the minimum in range
1010        above_color : (color)
1011            color for scalars above the maximum in range
1012        above_alpha : (float)
1013            alpha for scalars above the maximum in range
1014        nan_color : (color)
1015            color for invalid (nan) scalars
1016        nan_alpha : (float)
1017            alpha for invalid (nan) scalars
1018        interpolate : (bool)
1019            interpolate or not intermediate scalars
1020
1021    Examples:
1022        - [mesh_lut.py](https://github.com/marcomusy/vedo/tree/master/examples/basic/mesh_lut.py)
1023
1024            ![](https://vedo.embl.es/images/basic/mesh_lut.png)
1025    """
1026    ctf = vtki.new("ColorTransferFunction")
1027    ctf.SetColorSpaceToRGB()
1028    ctf.SetScaleToLinear()
1029
1030    alpha_x, alpha_vals = [], []
1031    for sc in colorlist:
1032        if len(sc) >= 3:
1033            scalar, col, alf = sc[:3]
1034        else:
1035            alf = 1
1036            scalar, col = sc
1037        r, g, b = get_color(col)
1038        ctf.AddRGBPoint(scalar, r, g, b)
1039        alpha_x.append(scalar)
1040        alpha_vals.append(alf)
1041
1042    ncols = 8 * len(colorlist)
1043    if not interpolate:
1044        ncols = len(colorlist)
1045
1046    lut = vtki.new("LookupTable")
1047    lut.SetNumberOfTableValues(ncols)
1048
1049    x0, x1 = ctf.GetRange()  # range of the introduced values
1050    if vmin is not None:
1051        x0 = vmin
1052    if vmax is not None:
1053        x1 = vmax
1054    ctf.SetRange(x0, x1)
1055    lut.SetRange(x0, x1)
1056
1057    if below_color is not None:
1058        lut.SetBelowRangeColor(list(get_color(below_color)) + [below_alpha])
1059        lut.SetUseBelowRangeColor(True)
1060    if above_color is not None:
1061        lut.SetAboveRangeColor(list(get_color(above_color)) + [above_alpha])
1062        lut.SetUseAboveRangeColor(True)
1063    if nan_color is not None:
1064        lut.SetNanColor(list(get_color(nan_color)) + [nan_alpha])
1065
1066    if interpolate:
1067        for i in range(ncols):
1068            p = i / (ncols-1)
1069            x = (1 - p) * x0 + p * x1
1070            alf = np.interp(x, alpha_x, alpha_vals)
1071            rgba = list(ctf.GetColor(x)) + [alf]
1072            lut.SetTableValue(i, rgba)
1073    else:
1074        for i in range(ncols):
1075            if len(colorlist[i]) > 2: 
1076                alpha = colorlist[i][2]
1077            else:
1078                alpha = 1.0
1079            # print("colorlist entry:", colorlist[i])
1080            rgba = list(get_color(colorlist[i][1])) + [alpha]
1081            lut.SetTableValue(i, rgba)
1082
1083    lut.Build()
1084    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: