topologicpy 0.5.9__py3-none-any.whl → 6.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. topologicpy/Aperture.py +72 -72
  2. topologicpy/Cell.py +2169 -2169
  3. topologicpy/CellComplex.py +1137 -1137
  4. topologicpy/Cluster.py +1288 -1280
  5. topologicpy/Color.py +423 -423
  6. topologicpy/Context.py +79 -79
  7. topologicpy/DGL.py +3213 -3240
  8. topologicpy/Dictionary.py +698 -698
  9. topologicpy/Edge.py +1187 -1187
  10. topologicpy/EnergyModel.py +1180 -1152
  11. topologicpy/Face.py +2141 -2141
  12. topologicpy/Graph.py +7768 -7768
  13. topologicpy/Grid.py +353 -353
  14. topologicpy/Helper.py +507 -507
  15. topologicpy/Honeybee.py +461 -461
  16. topologicpy/Matrix.py +271 -271
  17. topologicpy/Neo4j.py +521 -521
  18. topologicpy/Plotly.py +2 -2
  19. topologicpy/Polyskel.py +541 -541
  20. topologicpy/Shell.py +1768 -1768
  21. topologicpy/Speckle.py +508 -508
  22. topologicpy/Topology.py +7060 -7002
  23. topologicpy/Vector.py +905 -905
  24. topologicpy/Vertex.py +1585 -1585
  25. topologicpy/Wire.py +3050 -3050
  26. topologicpy/__init__.py +22 -38
  27. topologicpy/version.py +1 -0
  28. {topologicpy-0.5.9.dist-info → topologicpy-6.0.0.dist-info}/LICENSE +661 -704
  29. topologicpy-6.0.0.dist-info/METADATA +751 -0
  30. topologicpy-6.0.0.dist-info/RECORD +32 -0
  31. topologicpy/bin/linux/topologic/__init__.py +0 -2
  32. topologicpy/bin/linux/topologic/libTKBO-6bdf205d.so.7.7.0 +0 -0
  33. topologicpy/bin/linux/topologic/libTKBRep-2960a069.so.7.7.0 +0 -0
  34. topologicpy/bin/linux/topologic/libTKBool-c44b74bd.so.7.7.0 +0 -0
  35. topologicpy/bin/linux/topologic/libTKFillet-9a670ba0.so.7.7.0 +0 -0
  36. topologicpy/bin/linux/topologic/libTKG2d-8f31849e.so.7.7.0 +0 -0
  37. topologicpy/bin/linux/topologic/libTKG3d-4c6bce57.so.7.7.0 +0 -0
  38. topologicpy/bin/linux/topologic/libTKGeomAlgo-26066fd9.so.7.7.0 +0 -0
  39. topologicpy/bin/linux/topologic/libTKGeomBase-2116cabe.so.7.7.0 +0 -0
  40. topologicpy/bin/linux/topologic/libTKMath-72572fa8.so.7.7.0 +0 -0
  41. topologicpy/bin/linux/topologic/libTKMesh-2a060427.so.7.7.0 +0 -0
  42. topologicpy/bin/linux/topologic/libTKOffset-6cab68ff.so.7.7.0 +0 -0
  43. topologicpy/bin/linux/topologic/libTKPrim-eb1262b3.so.7.7.0 +0 -0
  44. topologicpy/bin/linux/topologic/libTKShHealing-e67e5cc7.so.7.7.0 +0 -0
  45. topologicpy/bin/linux/topologic/libTKTopAlgo-e4c96c33.so.7.7.0 +0 -0
  46. topologicpy/bin/linux/topologic/libTKernel-fb7fe3b7.so.7.7.0 +0 -0
  47. topologicpy/bin/linux/topologic/libgcc_s-32c1665e.so.1 +0 -0
  48. topologicpy/bin/linux/topologic/libstdc++-672d7b41.so.6.0.30 +0 -0
  49. topologicpy/bin/linux/topologic/topologic.cpython-310-x86_64-linux-gnu.so +0 -0
  50. topologicpy/bin/linux/topologic/topologic.cpython-311-x86_64-linux-gnu.so +0 -0
  51. topologicpy/bin/linux/topologic/topologic.cpython-38-x86_64-linux-gnu.so +0 -0
  52. topologicpy/bin/linux/topologic/topologic.cpython-39-x86_64-linux-gnu.so +0 -0
  53. topologicpy/bin/linux/topologic.libs/libTKBO-6bdf205d.so.7.7.0 +0 -0
  54. topologicpy/bin/linux/topologic.libs/libTKBRep-2960a069.so.7.7.0 +0 -0
  55. topologicpy/bin/linux/topologic.libs/libTKBool-c44b74bd.so.7.7.0 +0 -0
  56. topologicpy/bin/linux/topologic.libs/libTKFillet-9a670ba0.so.7.7.0 +0 -0
  57. topologicpy/bin/linux/topologic.libs/libTKG2d-8f31849e.so.7.7.0 +0 -0
  58. topologicpy/bin/linux/topologic.libs/libTKG3d-4c6bce57.so.7.7.0 +0 -0
  59. topologicpy/bin/linux/topologic.libs/libTKGeomAlgo-26066fd9.so.7.7.0 +0 -0
  60. topologicpy/bin/linux/topologic.libs/libTKGeomBase-2116cabe.so.7.7.0 +0 -0
  61. topologicpy/bin/linux/topologic.libs/libTKMath-72572fa8.so.7.7.0 +0 -0
  62. topologicpy/bin/linux/topologic.libs/libTKMesh-2a060427.so.7.7.0 +0 -0
  63. topologicpy/bin/linux/topologic.libs/libTKOffset-6cab68ff.so.7.7.0 +0 -0
  64. topologicpy/bin/linux/topologic.libs/libTKPrim-eb1262b3.so.7.7.0 +0 -0
  65. topologicpy/bin/linux/topologic.libs/libTKShHealing-e67e5cc7.so.7.7.0 +0 -0
  66. topologicpy/bin/linux/topologic.libs/libTKTopAlgo-e4c96c33.so.7.7.0 +0 -0
  67. topologicpy/bin/linux/topologic.libs/libTKernel-fb7fe3b7.so.7.7.0 +0 -0
  68. topologicpy/bin/linux/topologic.libs/libgcc_s-32c1665e.so.1 +0 -0
  69. topologicpy/bin/linux/topologic.libs/libstdc++-672d7b41.so.6.0.30 +0 -0
  70. topologicpy/bin/macos/topologic/__init__.py +0 -2
  71. topologicpy/bin/windows/topologic/TKBO-f6b191de.dll +0 -0
  72. topologicpy/bin/windows/topologic/TKBRep-e56a600e.dll +0 -0
  73. topologicpy/bin/windows/topologic/TKBool-7b8d47ae.dll +0 -0
  74. topologicpy/bin/windows/topologic/TKFillet-0ddbf0a8.dll +0 -0
  75. topologicpy/bin/windows/topologic/TKG2d-2e2dee3d.dll +0 -0
  76. topologicpy/bin/windows/topologic/TKG3d-6674513d.dll +0 -0
  77. topologicpy/bin/windows/topologic/TKGeomAlgo-d240e370.dll +0 -0
  78. topologicpy/bin/windows/topologic/TKGeomBase-df87aba5.dll +0 -0
  79. topologicpy/bin/windows/topologic/TKMath-45bd625a.dll +0 -0
  80. topologicpy/bin/windows/topologic/TKMesh-d6e826b1.dll +0 -0
  81. topologicpy/bin/windows/topologic/TKOffset-79b9cc94.dll +0 -0
  82. topologicpy/bin/windows/topologic/TKPrim-aa430a86.dll +0 -0
  83. topologicpy/bin/windows/topologic/TKShHealing-bb48be89.dll +0 -0
  84. topologicpy/bin/windows/topologic/TKTopAlgo-7d0d1e22.dll +0 -0
  85. topologicpy/bin/windows/topologic/TKernel-08c8cfbb.dll +0 -0
  86. topologicpy/bin/windows/topologic/__init__.py +0 -2
  87. topologicpy/bin/windows/topologic/topologic.cp310-win_amd64.pyd +0 -0
  88. topologicpy/bin/windows/topologic/topologic.cp311-win_amd64.pyd +0 -0
  89. topologicpy/bin/windows/topologic/topologic.cp38-win_amd64.pyd +0 -0
  90. topologicpy/bin/windows/topologic/topologic.cp39-win_amd64.pyd +0 -0
  91. topologicpy-0.5.9.dist-info/METADATA +0 -86
  92. topologicpy-0.5.9.dist-info/RECORD +0 -91
  93. {topologicpy-0.5.9.dist-info → topologicpy-6.0.0.dist-info}/WHEEL +0 -0
  94. {topologicpy-0.5.9.dist-info → topologicpy-6.0.0.dist-info}/top_level.txt +0 -0
topologicpy/Color.py CHANGED
@@ -1,423 +1,423 @@
1
- # Copyright (C) 2024
2
- # Wassim Jabi <wassim.jabi@gmail.com>
3
- #
4
- # This program is free software: you can redistribute it and/or modify it under
5
- # the terms of the GNU Affero General Public License as published by the Free Software
6
- # Foundation, either version 3 of the License, or (at your option) any later
7
- # version.
8
- #
9
- # This program is distributed in the hope that it will be useful, but WITHOUT
10
- # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
- # FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
12
- # details.
13
- #
14
- # You should have received a copy of the GNU Affero General Public License along with
15
- # this program. If not, see <https://www.gnu.org/licenses/>.
16
-
17
- import plotly.colors
18
- import math
19
-
20
- class Color:
21
- @staticmethod
22
- def ByCSSNamedColor(color, alpha: float = None):
23
- """
24
- Creates a Color from a CSS named color string. See https://developer.mozilla.org/en-US/docs/Web/CSS/named-color
25
-
26
- Parameters
27
- ----------
28
- color : str
29
- A CSS named color.
30
- alpha : float , optional
31
- THe desired alpha (transparency value). The default is None which means no alpha value will be included in the returned list.
32
-
33
- Returns
34
- -------
35
- list
36
- The color expressed as an [r, g, b] or an [r, g, b, a] list.
37
- """
38
- import warnings
39
- import os
40
- try:
41
- import webcolors
42
- except:
43
- print("Color.ByCSSNamedColor - Information: Installing required webcolors library.")
44
- try:
45
- os.system("pip install webcolors")
46
- except:
47
- os.system("pip install webcolors --user")
48
- try:
49
- import webcolors
50
- print("Color.ByCSSNamedColor - Information: webcolors library installed correctly.")
51
- except:
52
- warnings.warn("Color.ByCSSNamedColor - Error: Could not import webcolors library. Please manually install webcolors. Returning None.")
53
- return None
54
-
55
- if not alpha == None:
56
- if not 0.0 <= alpha <= 1.0:
57
- print("Color.ByCSSNamedColor - Error: alpha is not within the valid range of 0 to 1. Returning None.")
58
- return None
59
- try:
60
- # Get RGB values from the named CSS color
61
- rgbList = list(webcolors.name_to_rgb(color))
62
- if not alpha == None:
63
- rgbList.append(alpha)
64
- return rgbList
65
-
66
- except ValueError:
67
- print(f"Color.ByCSSNamedColor - Error: '{color}' is not a valid named CSS color. Returning None.")
68
- return None
69
-
70
- @staticmethod
71
- def ByHEX(hex: str, alpha: float = None):
72
- """
73
- Converts a hexadecimal color string to RGB color values.
74
-
75
- Parameters
76
- ----------
77
- hex : str
78
- A hexadecimal color string in the format '#RRGGBB'.
79
- alpha : float , optional
80
- The transparency value. 0.0 means the color is fully transparent, 1.0 means the color is fully opaque. The default is None
81
- which means no transparency value will be included in the returned color.
82
- Returns
83
- -------
84
- list
85
- The color expressed as an [r, g, b] or an [r, g, b, a] list.
86
-
87
- """
88
- if not isinstance(hex, str):
89
- print("Color.HEXtoRGB - Error: The input hex parameter is not a valid string. Returning None.")
90
- return None
91
- if not alpha == None:
92
- if not 0.0 <= alpha <= 1.0:
93
- print("Color.ByHEX - Error: alpha is not within the valid range of 0 to 1. Returning None.")
94
- return None
95
- hex = hex.lstrip('#')
96
- if len(hex) != 6:
97
- print("Color.HEXtoRGB - Error: Invalid hexadecimal color format. It should be a 6-digit hex value. Returning None.")
98
- return None
99
- r = int(hex[0:2], 16)
100
- g = int(hex[2:4], 16)
101
- b = int(hex[4:6], 16)
102
- rgbList = [r, g, b]
103
- if not alpha == None:
104
- rgbList.append(alpha)
105
- return rgbList
106
-
107
- @staticmethod
108
- def ByValueInRange(value: float = 0.5, minValue: float = 0.0, maxValue: float = 1.0, alpha: float = None, colorScale="viridis"):
109
- """
110
- Returns the r, g, b, (and optionally) a list of numbers representing the red, green, blue and alpha color elements.
111
-
112
- Parameters
113
- ----------
114
- value : float , optional
115
- The input value. The default is 0.5.
116
- minValue : float , optional
117
- the input minimum value. The default is 0.0.
118
- maxValue : float , optional
119
- The input maximum value. The default is 1.0.
120
- alpha : float , optional
121
- The alpha (transparency) value. 0.0 means the color is fully transparent, 1.0 means the color is fully opaque. The default is 1.0.
122
- useAlpha : bool , optional
123
- If set to True, the returns list includes the alpha value as a fourth element in the list.
124
- colorScale : str , optional
125
- The desired type of plotly color scales to use (e.g. "Viridis", "Plasma"). The default is "Viridis". For a full list of names, see https://plotly.com/python/builtin-colorscales/.
126
-
127
- Returns
128
- -------
129
- list
130
- The color expressed as an [r, g, b] or an [r, g, b, a] list.
131
-
132
- """
133
- if not alpha == None:
134
- if not 0.0 <= alpha <= 1.0:
135
- print("Color.ByValueInRange - Error: alpha is not within the valid range of 0 to 1. Returning None.")
136
- return None
137
- # Code based on: https://stackoverflow.com/questions/62710057/access-color-from-plotly-color-scale
138
-
139
- def hex_to_rgb(value):
140
- value = str(value)
141
- value = value.lstrip('#')
142
- lv = len(value)
143
- returnValue = tuple(int(value[i:i + lv // 3], 16) for i in range(0, lv, lv // 3))
144
- return str(returnValue)
145
-
146
- def get_color(colorscale_name, loc):
147
- from _plotly_utils.basevalidators import ColorscaleValidator
148
- # first parameter: Name of the property being validated
149
- # second parameter: a string, doesn't really matter in our use case
150
- cv = ColorscaleValidator("colorscale", "")
151
- # colorscale will be a list of lists: [[loc1, "rgb1"], [loc2, "rgb2"], ...]
152
- colorscale = cv.validate_coerce(colorscale_name)
153
- if hasattr(loc, "__iter__"):
154
- return [get_continuous_color(colorscale, x) for x in loc]
155
- color = get_continuous_color(colorscale, loc)
156
- color = color.replace("rgb", "")
157
- color = color.replace("(", "")
158
- color = color.replace(")", "")
159
- color = color.split(",")
160
- final_colors = []
161
- for c in color:
162
- final_colors.append(math.floor(float(c)))
163
- return final_colors
164
-
165
- def get_continuous_color(colorscale, intermed):
166
- """
167
- Plotly continuous colorscales assign colors to the range [0, 1]. This function computes the intermediate
168
- color for any value in that range.
169
-
170
- Plotly doesn't make the colorscales directly accessible in a common format.
171
- Some are ready to use:
172
-
173
- colorscale = plotly.colors.PLOTLY_SCALES["Greens"]
174
-
175
- Others are just swatches that need to be constructed into a colorscale:
176
-
177
- viridis_colors, scale = plotly.colors.convert_colors_to_same_type(plotly.colors.sequential.Viridis)
178
- colorscale = plotly.colors.make_colorscale(viridis_colors, scale=scale)
179
-
180
- :param colorscale: A plotly continuous colorscale defined with RGB string colors.
181
- :param intermed: value in the range [0, 1]
182
- :return: color in rgb string format
183
- :rtype: str
184
- """
185
-
186
- if len(colorscale) < 1:
187
- raise ValueError("colorscale must have at least one color")
188
- if intermed <= 0 or len(colorscale) == 1:
189
- c = colorscale[0][1]
190
- return c if c[0] != "#" else hex_to_rgb(c)
191
- if intermed >= 1:
192
- c = colorscale[-1][1]
193
- return c if c[0] != "#" else hex_to_rgb(c)
194
- for cutoff, color in colorscale:
195
- if intermed > cutoff:
196
- low_cutoff, low_color = cutoff, color
197
- else:
198
- high_cutoff, high_color = cutoff, color
199
- break
200
- if (low_color[0] == "#") or (high_color[0] == "#"):
201
- # some color scale names (such as cividis) returns:
202
- # [[loc1, "hex1"], [loc2, "hex2"], ...]
203
- low_color = hex_to_rgb(low_color)
204
- high_color = hex_to_rgb(high_color)
205
- return plotly.colors.find_intermediate_color(
206
- lowcolor=low_color,
207
- highcolor=high_color,
208
- intermed=((intermed - low_cutoff) / (high_cutoff - low_cutoff)),
209
- colortype="rgb",
210
- )
211
-
212
- def get_color_default(ratio):
213
- r = 0.0
214
- g = 0.0
215
- b = 0.0
216
-
217
- finalRatio = ratio;
218
- if (finalRatio < 0.0):
219
- finalRatio = 0.0
220
- elif(finalRatio > 1.0):
221
- finalRatio = 1.0
222
-
223
- if (finalRatio >= 0.0 and finalRatio <= 0.25):
224
- r = 0.0
225
- g = 4.0 * finalRatio
226
- b = 1.0
227
- elif (finalRatio > 0.25 and finalRatio <= 0.5):
228
- r = 0.0
229
- g = 1.0
230
- b = 1.0 - 4.0 * (finalRatio - 0.25)
231
- elif (finalRatio > 0.5 and finalRatio <= 0.75):
232
- r = 4.0*(finalRatio - 0.5);
233
- g = 1.0
234
- b = 0.0
235
- else:
236
- r = 1.0
237
- g = 1.0 - 4.0 * (finalRatio - 0.75)
238
- b = 0.0
239
-
240
- rcom = (max(min(r, 1.0), 0.0))
241
- gcom = (max(min(g, 1.0), 0.0))
242
- bcom = (max(min(b, 1.0), 0.0))
243
-
244
- return [rcom,gcom,bcom]
245
-
246
- if minValue > maxValue:
247
- temp = minValue;
248
- maxValue = minValue
249
- maxValue = temp
250
-
251
- val = value
252
- val = max(min(val,maxValue), minValue) # bracket value to the min and max values
253
- if (maxValue - minValue) != 0:
254
- val = (val - minValue)/(maxValue - minValue)
255
- else:
256
- val = 0
257
- if not colorScale or colorScale.lower() == "default":
258
- rgbList = get_color_default(val)
259
- else:
260
- rgbList = get_color(colorScale, val)
261
- if not alpha == None:
262
- rgbList.append(alpha)
263
- return rgbList
264
-
265
- @staticmethod
266
- def CSSNamedColor(color):
267
- """
268
- Returns the CSS Named color that most closely matches the input color. The input color is assumed to be
269
- in the format [r, g, b]. See https://developer.mozilla.org/en-US/docs/Web/CSS/named-color
270
-
271
- Parameters
272
- ----------
273
- color : list
274
- The input color. This is assumed to be in the format [r, g, b]
275
-
276
- Returns
277
- -------
278
- str
279
- The CSS named color that most closely matches the input color.
280
- """
281
- import numbers
282
- import warnings
283
- import os
284
- try:
285
- import webcolors
286
- except:
287
- print("Color.CSSNamedColor - Information: Installing required webcolors library.")
288
- try:
289
- os.system("pip install webcolors")
290
- except:
291
- os.system("pip install webcolors --user")
292
- try:
293
- import webcolors
294
- print("Color.CSSNamedColor - Information: webcolors library installed correctly.")
295
- except:
296
- warnings.warn("Color.CSSNamedColor - Error: Could not import webcolors library. Please manually install webcolors. Returning None.")
297
- return None
298
-
299
- if not isinstance(color, list):
300
- print("Color.CSSNamedColor - Error: The input color parameter is not a valid list. Returning None.")
301
- return None
302
- color = [int(x) for x in color if isinstance(x, numbers.Real)]
303
- if len(color) < 3:
304
- print("Color.CSSNamedColor - Error: The input color parameter does not contain valid r, g, b values. Returning None.")
305
- return None
306
- color = color[0:3]
307
- for x in color:
308
- if not (0 <= x <= 255):
309
- print("Color.CSSNamedColor - Error: The input color parameter does not contain valid r, g, b values. Returning None.")
310
- return None
311
-
312
- def est_color(requested_color):
313
- min_colors = {}
314
- for key, name in webcolors.CSS3_HEX_TO_NAMES.items():
315
- r_c, g_c, b_c = webcolors.hex_to_rgb(key)
316
- rd = (r_c - requested_color[0]) ** 2
317
- gd = (g_c - requested_color[1]) ** 2
318
- bd = (b_c - requested_color[2]) ** 2
319
- min_colors[(rd + gd + bd)] = name
320
- return min_colors[min(min_colors.keys())]
321
-
322
- try:
323
- closest_color_name = webcolors.rgb_to_name(color)
324
- except ValueError:
325
- closest_color_name = est_color(color)
326
- return closest_color_name
327
-
328
- @staticmethod
329
- def CSSNamedColors():
330
- """
331
- Returns a list of all CSS named colors. See https://developer.mozilla.org/en-US/docs/Web/CSS/named-color
332
-
333
- Parameters
334
- ----------
335
-
336
- Returns
337
- -------
338
- list
339
- The list of all CSS named colors.
340
-
341
- """
342
- # List of CSS named colors
343
- css_named_colors = [
344
- "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige", "bisque", "black", "blanchedalmond",
345
- "blue", "blueviolet", "brown", "burlywood", "cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue",
346
- "cornsilk", "crimson", "cyan", "darkblue", "darkcyan", "darkgoldenrod", "darkgray", "darkgreen", "darkgrey",
347
- "darkkhaki", "darkmagenta", "darkolivegreen", "darkorange", "darkorchid", "darkred", "darksalmon",
348
- "darkseagreen", "darkslateblue", "darkslategray", "darkslategrey", "darkturquoise", "darkviolet", "deeppink",
349
- "deepskyblue", "dimgray", "dimgrey", "dodgerblue", "firebrick", "floralwhite", "forestgreen", "fuchsia",
350
- "gainsboro", "ghostwhite", "gold", "goldenrod", "gray", "green", "greenyellow", "grey", "honeydew", "hotpink",
351
- "indianred", "indigo", "ivory", "khaki", "lavender", "lavenderblush", "lawngreen", "lemonchiffon", "lightblue",
352
- "lightcoral", "lightcyan", "lightgoldenrodyellow", "lightgray", "lightgreen", "lightgrey", "lightpink",
353
- "lightsalmon", "lightseagreen", "lightskyblue", "lightslategray", "lightslategrey", "lightsteelblue",
354
- "lightyellow", "lime", "limegreen", "linen", "magenta", "maroon", "mediumaquamarine", "mediumblue",
355
- "mediumorchid", "mediumpurple", "mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise",
356
- "mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin", "navajowhite", "navy", "oldlace",
357
- "olive", "olivedrab", "orange", "orangered", "orchid", "palegoldenrod", "palegreen", "paleturquoise",
358
- "palevioletred", "papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue", "purple", "rebeccapurple",
359
- "red", "rosybrown", "royalblue", "saddlebrown", "salmon", "sandybrown", "seagreen", "seashell", "sienna",
360
- "silver", "skyblue", "slateblue", "slategray", "slategrey", "snow", "springgreen", "steelblue", "tan",
361
- "teal", "thistle", "tomato", "turquoise", "violet", "wheat", "white", "whitesmoke", "yellow", "yellowgreen"
362
- ]
363
-
364
- return css_named_colors
365
-
366
- @staticmethod
367
- def PlotlyColor(color, alpha=1.0, useAlpha=False):
368
- """
369
- Returns a plotly color string based on the input list of [r, g, b] or [r, g, b, a]. If your list is [r, g, b], you can optionally specify an alpha value
370
-
371
- Parameters
372
- ----------
373
- color : list
374
- The input color list. This is assumed to be in the format [r, g, b] or [r, g, b, a]
375
- alpha : float , optional
376
- The transparency value. 0.0 means the color is fully transparent, 1.0 means the color is fully opaque. The default is 1.0.
377
- useAlpha : bool , optional
378
- If set to True, the returns list includes the alpha value as a fourth element in the list.
379
-
380
- Returns
381
- -------
382
- str
383
- The plotly color string.
384
-
385
- """
386
- if not isinstance(color, list):
387
- print("Color.PlotlyColor - Error: The input color parameter is not a valid list. Returning None.")
388
- return None
389
- if len(color) < 3:
390
- print("Color.PlotlyColor - Error: The input color parameter contains less than the minimum three elements. Returning None.")
391
- return None
392
- if len(color) == 4:
393
- alpha = color[3]
394
- alpha = min(max(alpha, 0), 1)
395
- if alpha < 1:
396
- useAlpha = True
397
- if useAlpha:
398
- return "rgba("+str(color[0])+","+str(color[1])+","+str(color[2])+","+str(alpha)+")"
399
- return "rgb("+str(color[0])+","+str(color[1])+","+str(color[2])+")"
400
-
401
- @staticmethod
402
- def RGBToHex(rgb):
403
- """
404
- Converts RGB color values to a hexadecimal color string.
405
-
406
- Parameters
407
- ----------
408
- rgb : tuple
409
- A tuple containing three integers representing the RGB values.
410
-
411
- Returns
412
- -------
413
- str
414
- A hexadecimal color string in the format '#RRGGBB'.
415
- """
416
- if not isinstance(rgb, list):
417
- print("Color.RGBToHex - Error: The input rgb parameter is not a valid list. Returning None.")
418
- return None
419
- r, g, b = rgb
420
- hex_value = "#{:02x}{:02x}{:02x}".format(r, g, b)
421
- return hex_value.upper()
422
-
423
-
1
+ # Copyright (C) 2024
2
+ # Wassim Jabi <wassim.jabi@gmail.com>
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify it under
5
+ # the terms of the GNU Affero General Public License as published by the Free Software
6
+ # Foundation, either version 3 of the License, or (at your option) any later
7
+ # version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful, but WITHOUT
10
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
+ # FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
12
+ # details.
13
+ #
14
+ # You should have received a copy of the GNU Affero General Public License along with
15
+ # this program. If not, see <https://www.gnu.org/licenses/>.
16
+
17
+ import plotly.colors
18
+ import math
19
+
20
+ class Color:
21
+ @staticmethod
22
+ def ByCSSNamedColor(color, alpha: float = None):
23
+ """
24
+ Creates a Color from a CSS named color string. See https://developer.mozilla.org/en-US/docs/Web/CSS/named-color
25
+
26
+ Parameters
27
+ ----------
28
+ color : str
29
+ A CSS named color.
30
+ alpha : float , optional
31
+ THe desired alpha (transparency value). The default is None which means no alpha value will be included in the returned list.
32
+
33
+ Returns
34
+ -------
35
+ list
36
+ The color expressed as an [r, g, b] or an [r, g, b, a] list.
37
+ """
38
+ import warnings
39
+ import os
40
+ try:
41
+ import webcolors
42
+ except:
43
+ print("Color.ByCSSNamedColor - Information: Installing required webcolors library.")
44
+ try:
45
+ os.system("pip install webcolors")
46
+ except:
47
+ os.system("pip install webcolors --user")
48
+ try:
49
+ import webcolors
50
+ print("Color.ByCSSNamedColor - Information: webcolors library installed correctly.")
51
+ except:
52
+ warnings.warn("Color.ByCSSNamedColor - Error: Could not import webcolors library. Please manually install webcolors. Returning None.")
53
+ return None
54
+
55
+ if not alpha == None:
56
+ if not 0.0 <= alpha <= 1.0:
57
+ print("Color.ByCSSNamedColor - Error: alpha is not within the valid range of 0 to 1. Returning None.")
58
+ return None
59
+ try:
60
+ # Get RGB values from the named CSS color
61
+ rgbList = list(webcolors.name_to_rgb(color))
62
+ if not alpha == None:
63
+ rgbList.append(alpha)
64
+ return rgbList
65
+
66
+ except ValueError:
67
+ print(f"Color.ByCSSNamedColor - Error: '{color}' is not a valid named CSS color. Returning None.")
68
+ return None
69
+
70
+ @staticmethod
71
+ def ByHEX(hex: str, alpha: float = None):
72
+ """
73
+ Converts a hexadecimal color string to RGB color values.
74
+
75
+ Parameters
76
+ ----------
77
+ hex : str
78
+ A hexadecimal color string in the format '#RRGGBB'.
79
+ alpha : float , optional
80
+ The transparency value. 0.0 means the color is fully transparent, 1.0 means the color is fully opaque. The default is None
81
+ which means no transparency value will be included in the returned color.
82
+ Returns
83
+ -------
84
+ list
85
+ The color expressed as an [r, g, b] or an [r, g, b, a] list.
86
+
87
+ """
88
+ if not isinstance(hex, str):
89
+ print("Color.HEXtoRGB - Error: The input hex parameter is not a valid string. Returning None.")
90
+ return None
91
+ if not alpha == None:
92
+ if not 0.0 <= alpha <= 1.0:
93
+ print("Color.ByHEX - Error: alpha is not within the valid range of 0 to 1. Returning None.")
94
+ return None
95
+ hex = hex.lstrip('#')
96
+ if len(hex) != 6:
97
+ print("Color.HEXtoRGB - Error: Invalid hexadecimal color format. It should be a 6-digit hex value. Returning None.")
98
+ return None
99
+ r = int(hex[0:2], 16)
100
+ g = int(hex[2:4], 16)
101
+ b = int(hex[4:6], 16)
102
+ rgbList = [r, g, b]
103
+ if not alpha == None:
104
+ rgbList.append(alpha)
105
+ return rgbList
106
+
107
+ @staticmethod
108
+ def ByValueInRange(value: float = 0.5, minValue: float = 0.0, maxValue: float = 1.0, alpha: float = None, colorScale="viridis"):
109
+ """
110
+ Returns the r, g, b, (and optionally) a list of numbers representing the red, green, blue and alpha color elements.
111
+
112
+ Parameters
113
+ ----------
114
+ value : float , optional
115
+ The input value. The default is 0.5.
116
+ minValue : float , optional
117
+ the input minimum value. The default is 0.0.
118
+ maxValue : float , optional
119
+ The input maximum value. The default is 1.0.
120
+ alpha : float , optional
121
+ The alpha (transparency) value. 0.0 means the color is fully transparent, 1.0 means the color is fully opaque. The default is 1.0.
122
+ useAlpha : bool , optional
123
+ If set to True, the returns list includes the alpha value as a fourth element in the list.
124
+ colorScale : str , optional
125
+ The desired type of plotly color scales to use (e.g. "Viridis", "Plasma"). The default is "Viridis". For a full list of names, see https://plotly.com/python/builtin-colorscales/.
126
+
127
+ Returns
128
+ -------
129
+ list
130
+ The color expressed as an [r, g, b] or an [r, g, b, a] list.
131
+
132
+ """
133
+ if not alpha == None:
134
+ if not 0.0 <= alpha <= 1.0:
135
+ print("Color.ByValueInRange - Error: alpha is not within the valid range of 0 to 1. Returning None.")
136
+ return None
137
+ # Code based on: https://stackoverflow.com/questions/62710057/access-color-from-plotly-color-scale
138
+
139
+ def hex_to_rgb(value):
140
+ value = str(value)
141
+ value = value.lstrip('#')
142
+ lv = len(value)
143
+ returnValue = tuple(int(value[i:i + lv // 3], 16) for i in range(0, lv, lv // 3))
144
+ return str(returnValue)
145
+
146
+ def get_color(colorscale_name, loc):
147
+ from _plotly_utils.basevalidators import ColorscaleValidator
148
+ # first parameter: Name of the property being validated
149
+ # second parameter: a string, doesn't really matter in our use case
150
+ cv = ColorscaleValidator("colorscale", "")
151
+ # colorscale will be a list of lists: [[loc1, "rgb1"], [loc2, "rgb2"], ...]
152
+ colorscale = cv.validate_coerce(colorscale_name)
153
+ if hasattr(loc, "__iter__"):
154
+ return [get_continuous_color(colorscale, x) for x in loc]
155
+ color = get_continuous_color(colorscale, loc)
156
+ color = color.replace("rgb", "")
157
+ color = color.replace("(", "")
158
+ color = color.replace(")", "")
159
+ color = color.split(",")
160
+ final_colors = []
161
+ for c in color:
162
+ final_colors.append(math.floor(float(c)))
163
+ return final_colors
164
+
165
+ def get_continuous_color(colorscale, intermed):
166
+ """
167
+ Plotly continuous colorscales assign colors to the range [0, 1]. This function computes the intermediate
168
+ color for any value in that range.
169
+
170
+ Plotly doesn't make the colorscales directly accessible in a common format.
171
+ Some are ready to use:
172
+
173
+ colorscale = plotly.colors.PLOTLY_SCALES["Greens"]
174
+
175
+ Others are just swatches that need to be constructed into a colorscale:
176
+
177
+ viridis_colors, scale = plotly.colors.convert_colors_to_same_type(plotly.colors.sequential.Viridis)
178
+ colorscale = plotly.colors.make_colorscale(viridis_colors, scale=scale)
179
+
180
+ :param colorscale: A plotly continuous colorscale defined with RGB string colors.
181
+ :param intermed: value in the range [0, 1]
182
+ :return: color in rgb string format
183
+ :rtype: str
184
+ """
185
+
186
+ if len(colorscale) < 1:
187
+ raise ValueError("colorscale must have at least one color")
188
+ if intermed <= 0 or len(colorscale) == 1:
189
+ c = colorscale[0][1]
190
+ return c if c[0] != "#" else hex_to_rgb(c)
191
+ if intermed >= 1:
192
+ c = colorscale[-1][1]
193
+ return c if c[0] != "#" else hex_to_rgb(c)
194
+ for cutoff, color in colorscale:
195
+ if intermed > cutoff:
196
+ low_cutoff, low_color = cutoff, color
197
+ else:
198
+ high_cutoff, high_color = cutoff, color
199
+ break
200
+ if (low_color[0] == "#") or (high_color[0] == "#"):
201
+ # some color scale names (such as cividis) returns:
202
+ # [[loc1, "hex1"], [loc2, "hex2"], ...]
203
+ low_color = hex_to_rgb(low_color)
204
+ high_color = hex_to_rgb(high_color)
205
+ return plotly.colors.find_intermediate_color(
206
+ lowcolor=low_color,
207
+ highcolor=high_color,
208
+ intermed=((intermed - low_cutoff) / (high_cutoff - low_cutoff)),
209
+ colortype="rgb",
210
+ )
211
+
212
+ def get_color_default(ratio):
213
+ r = 0.0
214
+ g = 0.0
215
+ b = 0.0
216
+
217
+ finalRatio = ratio;
218
+ if (finalRatio < 0.0):
219
+ finalRatio = 0.0
220
+ elif(finalRatio > 1.0):
221
+ finalRatio = 1.0
222
+
223
+ if (finalRatio >= 0.0 and finalRatio <= 0.25):
224
+ r = 0.0
225
+ g = 4.0 * finalRatio
226
+ b = 1.0
227
+ elif (finalRatio > 0.25 and finalRatio <= 0.5):
228
+ r = 0.0
229
+ g = 1.0
230
+ b = 1.0 - 4.0 * (finalRatio - 0.25)
231
+ elif (finalRatio > 0.5 and finalRatio <= 0.75):
232
+ r = 4.0*(finalRatio - 0.5);
233
+ g = 1.0
234
+ b = 0.0
235
+ else:
236
+ r = 1.0
237
+ g = 1.0 - 4.0 * (finalRatio - 0.75)
238
+ b = 0.0
239
+
240
+ rcom = (max(min(r, 1.0), 0.0))
241
+ gcom = (max(min(g, 1.0), 0.0))
242
+ bcom = (max(min(b, 1.0), 0.0))
243
+
244
+ return [rcom,gcom,bcom]
245
+
246
+ if minValue > maxValue:
247
+ temp = minValue;
248
+ maxValue = minValue
249
+ maxValue = temp
250
+
251
+ val = value
252
+ val = max(min(val,maxValue), minValue) # bracket value to the min and max values
253
+ if (maxValue - minValue) != 0:
254
+ val = (val - minValue)/(maxValue - minValue)
255
+ else:
256
+ val = 0
257
+ if not colorScale or colorScale.lower() == "default":
258
+ rgbList = get_color_default(val)
259
+ else:
260
+ rgbList = get_color(colorScale, val)
261
+ if not alpha == None:
262
+ rgbList.append(alpha)
263
+ return rgbList
264
+
265
+ @staticmethod
266
+ def CSSNamedColor(color):
267
+ """
268
+ Returns the CSS Named color that most closely matches the input color. The input color is assumed to be
269
+ in the format [r, g, b]. See https://developer.mozilla.org/en-US/docs/Web/CSS/named-color
270
+
271
+ Parameters
272
+ ----------
273
+ color : list
274
+ The input color. This is assumed to be in the format [r, g, b]
275
+
276
+ Returns
277
+ -------
278
+ str
279
+ The CSS named color that most closely matches the input color.
280
+ """
281
+ import numbers
282
+ import warnings
283
+ import os
284
+ try:
285
+ import webcolors
286
+ except:
287
+ print("Color.CSSNamedColor - Information: Installing required webcolors library.")
288
+ try:
289
+ os.system("pip install webcolors")
290
+ except:
291
+ os.system("pip install webcolors --user")
292
+ try:
293
+ import webcolors
294
+ print("Color.CSSNamedColor - Information: webcolors library installed correctly.")
295
+ except:
296
+ warnings.warn("Color.CSSNamedColor - Error: Could not import webcolors library. Please manually install webcolors. Returning None.")
297
+ return None
298
+
299
+ if not isinstance(color, list):
300
+ print("Color.CSSNamedColor - Error: The input color parameter is not a valid list. Returning None.")
301
+ return None
302
+ color = [int(x) for x in color if isinstance(x, numbers.Real)]
303
+ if len(color) < 3:
304
+ print("Color.CSSNamedColor - Error: The input color parameter does not contain valid r, g, b values. Returning None.")
305
+ return None
306
+ color = color[0:3]
307
+ for x in color:
308
+ if not (0 <= x <= 255):
309
+ print("Color.CSSNamedColor - Error: The input color parameter does not contain valid r, g, b values. Returning None.")
310
+ return None
311
+
312
+ def est_color(requested_color):
313
+ min_colors = {}
314
+ for key, name in webcolors.CSS3_HEX_TO_NAMES.items():
315
+ r_c, g_c, b_c = webcolors.hex_to_rgb(key)
316
+ rd = (r_c - requested_color[0]) ** 2
317
+ gd = (g_c - requested_color[1]) ** 2
318
+ bd = (b_c - requested_color[2]) ** 2
319
+ min_colors[(rd + gd + bd)] = name
320
+ return min_colors[min(min_colors.keys())]
321
+
322
+ try:
323
+ closest_color_name = webcolors.rgb_to_name(color)
324
+ except ValueError:
325
+ closest_color_name = est_color(color)
326
+ return closest_color_name
327
+
328
+ @staticmethod
329
+ def CSSNamedColors():
330
+ """
331
+ Returns a list of all CSS named colors. See https://developer.mozilla.org/en-US/docs/Web/CSS/named-color
332
+
333
+ Parameters
334
+ ----------
335
+
336
+ Returns
337
+ -------
338
+ list
339
+ The list of all CSS named colors.
340
+
341
+ """
342
+ # List of CSS named colors
343
+ css_named_colors = [
344
+ "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige", "bisque", "black", "blanchedalmond",
345
+ "blue", "blueviolet", "brown", "burlywood", "cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue",
346
+ "cornsilk", "crimson", "cyan", "darkblue", "darkcyan", "darkgoldenrod", "darkgray", "darkgreen", "darkgrey",
347
+ "darkkhaki", "darkmagenta", "darkolivegreen", "darkorange", "darkorchid", "darkred", "darksalmon",
348
+ "darkseagreen", "darkslateblue", "darkslategray", "darkslategrey", "darkturquoise", "darkviolet", "deeppink",
349
+ "deepskyblue", "dimgray", "dimgrey", "dodgerblue", "firebrick", "floralwhite", "forestgreen", "fuchsia",
350
+ "gainsboro", "ghostwhite", "gold", "goldenrod", "gray", "green", "greenyellow", "grey", "honeydew", "hotpink",
351
+ "indianred", "indigo", "ivory", "khaki", "lavender", "lavenderblush", "lawngreen", "lemonchiffon", "lightblue",
352
+ "lightcoral", "lightcyan", "lightgoldenrodyellow", "lightgray", "lightgreen", "lightgrey", "lightpink",
353
+ "lightsalmon", "lightseagreen", "lightskyblue", "lightslategray", "lightslategrey", "lightsteelblue",
354
+ "lightyellow", "lime", "limegreen", "linen", "magenta", "maroon", "mediumaquamarine", "mediumblue",
355
+ "mediumorchid", "mediumpurple", "mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise",
356
+ "mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin", "navajowhite", "navy", "oldlace",
357
+ "olive", "olivedrab", "orange", "orangered", "orchid", "palegoldenrod", "palegreen", "paleturquoise",
358
+ "palevioletred", "papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue", "purple", "rebeccapurple",
359
+ "red", "rosybrown", "royalblue", "saddlebrown", "salmon", "sandybrown", "seagreen", "seashell", "sienna",
360
+ "silver", "skyblue", "slateblue", "slategray", "slategrey", "snow", "springgreen", "steelblue", "tan",
361
+ "teal", "thistle", "tomato", "turquoise", "violet", "wheat", "white", "whitesmoke", "yellow", "yellowgreen"
362
+ ]
363
+
364
+ return css_named_colors
365
+
366
+ @staticmethod
367
+ def PlotlyColor(color, alpha=1.0, useAlpha=False):
368
+ """
369
+ Returns a plotly color string based on the input list of [r, g, b] or [r, g, b, a]. If your list is [r, g, b], you can optionally specify an alpha value
370
+
371
+ Parameters
372
+ ----------
373
+ color : list
374
+ The input color list. This is assumed to be in the format [r, g, b] or [r, g, b, a]
375
+ alpha : float , optional
376
+ The transparency value. 0.0 means the color is fully transparent, 1.0 means the color is fully opaque. The default is 1.0.
377
+ useAlpha : bool , optional
378
+ If set to True, the returns list includes the alpha value as a fourth element in the list.
379
+
380
+ Returns
381
+ -------
382
+ str
383
+ The plotly color string.
384
+
385
+ """
386
+ if not isinstance(color, list):
387
+ print("Color.PlotlyColor - Error: The input color parameter is not a valid list. Returning None.")
388
+ return None
389
+ if len(color) < 3:
390
+ print("Color.PlotlyColor - Error: The input color parameter contains less than the minimum three elements. Returning None.")
391
+ return None
392
+ if len(color) == 4:
393
+ alpha = color[3]
394
+ alpha = min(max(alpha, 0), 1)
395
+ if alpha < 1:
396
+ useAlpha = True
397
+ if useAlpha:
398
+ return "rgba("+str(color[0])+","+str(color[1])+","+str(color[2])+","+str(alpha)+")"
399
+ return "rgb("+str(color[0])+","+str(color[1])+","+str(color[2])+")"
400
+
401
+ @staticmethod
402
+ def RGBToHex(rgb):
403
+ """
404
+ Converts RGB color values to a hexadecimal color string.
405
+
406
+ Parameters
407
+ ----------
408
+ rgb : tuple
409
+ A tuple containing three integers representing the RGB values.
410
+
411
+ Returns
412
+ -------
413
+ str
414
+ A hexadecimal color string in the format '#RRGGBB'.
415
+ """
416
+ if not isinstance(rgb, list):
417
+ print("Color.RGBToHex - Error: The input rgb parameter is not a valid list. Returning None.")
418
+ return None
419
+ r, g, b = rgb
420
+ hex_value = "#{:02x}{:02x}{:02x}".format(r, g, b)
421
+ return hex_value.upper()
422
+
423
+