GTK and python. How convert RGBA to HEX? - python

# a colorbutton (which opens a dialogue window in
# which we choose a color)
self.button_err_bg = Gtk.ColorButton()
# with a default color (blue, in this instance)
color_bg = Gdk.RGBA()
color_bg.red = 0.5
color_bg.green = 0.4
color_bg.blue = 0.3
color_bg.alpha = 1.0
color_error_background = self.button_err_bg.set_rgba(color_bg)
# choosing a color in the dialogue window emits a signal
self.button_err_bg.connect("color-set", self.on_color_fg_error_chosen)
and method
def on_color_fg_error_chosen(self, user_data):
print("You chose the color: " + self.button_err_bg.get_rgba().to_string())
color_rgba = self.button.get_rgba().to_string()
color_rgba_bracket = color_rgba[color_rgba.find("(")+1:color_rgba.find(")")]
color_hex = '#{:02x}{:02x}{:02x}'.format(color_rgba_bracket)
print(color_hex)
color_hex :color_hex = '#{:02x}{:02x}{:02x}'.format(color_rgba_bracket)
ValueError: Unknown format code 'x' for object of type 'str'

Based on your code, I'm going to assume that self.button.get_rgba() returns a tuple.
Since you convert the assumed tuple to a string (for some reason), the format fails because, as your error shows, it doesn't know how to convert a string to hex. Additionally, even if it did have an x format for a string, it would fail with IndexError: tuple index out of range because it's expecting 3 items and you're only passing 1.
If you skip the string conversion altogether, and unpack the tuple, you should get a proper format:
def on_color_fg_error_chosen(self, user_data):
print("You chose the color: " + self.button_err_bg.get_rgba().to_string())
color_rgba = self.button.get_rgba()
color_hex = '#{:02x}{:02x}{:02x}'.format(*color_rgba)
print(color_hex)
Using a basic example:
>>> color_rgba = (12, 28, 200, 28) # R, G, B, Alpha
>>> '#{:02x}{:02x}{:02x}'.format(*color_rgba) # 4th item is ignored because only looking for 3 items
'#0c1cc8'

Related

I need to make a map (literally not the function) in which i should print a 20*20 map with pluses(+) but mark some of the coordinates

I need to make a map (literally not the function) in which I should print a 20*20 map with pluses(+) but mark some of the coordinates which are inputs with #
first, I ask how many coordinates the user wants to give me
second, I get the coordinates and print the map with said coordinates marked on it
e.g. :
input:
2
(10,11)
(10,12)
output :
# + + + + + + +
c= ( 10 , 11)
a=c\[0\]
b=c\[1\]
for y in range (20):
if y == a :
for x in range (20):
if x==b:
print('#' , end= ' ')
else :
print('+' , end = ' ')
else:
for x in range (20):
print('+' , end= ' ')
print()
This should do the trick:
from typing import List
ROWS = COLS = 20
# Define a function to create rows
def create_row(num_cols: int, default_char: str = "+")->List[str]:
return [default_char for i in range(num_cols)]
# Define a function to create the map using function for row creation
# Make the arguments keyword only, it does matter which int is rows, which is cols (as long as your matrix is not necessarily n x n, but n x m (in general)
def create_map(*,rows:int, cols:int, default_char:str = "+")->List[List[str]]:
char_map = []
for i in range(rows):
char_map.append(create_row(num_cols=cols, default_char=default_char))
return char_map
# Create the map
plus_map = create_map(rows=ROWS, cols=COLS)
# This is just an example of user input coordinates
hashtag_coordinates = [(1,2), (3,4)] # I'll leave this part for you, populate it as you wish (using input function or whatever, file reading etc.), just keep it in a form of list of tuples
# Substitute the default "+" with "#" for user input coordinates
for x,y in hashtag_coordinates:
plus_map[x][y] = "#"
# Print your map row by row
for r in plus_map:
print(r)
add docstrings, docstrings are cool...
think of good variable names, those above are ok'ish, probably can be better / more descriptive
[OPTIONAL] wrap the substitution of "+" into "#" in another function
[OPTIONAL] write your own print function if the output is not what you expect it to be
do not name variables "a", "b", cause that means nothing
if you repeat the same magic number in a few places like in range(20) and so on name it, all caps if it's a constant

Python: Pseudo-random color from a string

I am doing some data visualization with Python in Blender and I need to assign colors to the data being represented. There is too much data to spend time hand-picking colors for each, so I want to generate the colors pseudo-randomly - I would like a given string to always result in the same color. That way, if it appears more than once, it will be clear that it is the same item.
For example, given a list like ['Moose', 'Frog', 'Your Mother'], let's say Moose would always be maroon.
The colors are specified in RGB, where each channel is a float from 0.0 to 1.0.
Here's what I've tried so far that isn't working:
import random
import hashlib
def norm(x, min, max): # this normalization function has a problem
normalized = ( x - min(x) ) / (max(x) - min(x) )
return normalized
def r(string, val):
h = hash(string)
print(h)
if h < 0:
h = h * -1
rs = random.seed( int(h) + int(val) )
output = norm(rs, 0.0, 1.0)
return output
my_list = ['Moose', 'Frog', 'Your Mother']
item = my_list[0]
color = [ r(item,1), r(item,2), (item,1) ]
print(color)
It results in TypeError: 'float' object is not callable but I don't know why. I'm trying to normalize the way this answer demonstrates.
It might be best to have a list of possible colors, as it allows for control over the palette. Either way, I need a pseudo-random float in the range of 0.0 ~ 0.1.
You can try with this function. It returns a rgb value for the name by using the 3 first letters.
def name_color(name):
color = [(ord(c.lower())-97)*8 for c in name[:3]]
return color
It turns out I didn't need to normalize or do anything fancy. random() returns a range between 0.0 ~ 1.0 as it is. I just needed to take a closer look at how random.seed() is supposed to be used.
Here's my solution:
import random
import hashlib
def r(string, int): # pseudo-randomization function
h = hash( string + str(int) ) # hash string and int together
if h < 0: # ensure positive number
h = h * -1
random.seed(h) # set the seed to use for randomization
output = random.random() # produce random value in range 0.0 ~ 1.0
output = round(output, 6) # round to 6 decimal places (optional)
return output
my_list = ['Toyota', 'Tesla', 'Mercedes-Benz']
item = my_list[0] # choose which list item
color = [ r(item,0), r(item,1), r(item,2) ] # R,G,B values
print(item, color)
Output: Toyota [0.049121, 0.383824, 0.635146]
I may try the list approach later.

Regarding the behavior of string padding using str.ljust in python

I have a use case in which I am setting the labels for
matplotlib.colorbar
and I want to distribute the description evenly using the code below
temp = ""
for section in range(total_section_len):
temp.ljust(60//(total_section_len * 5))
temp += "stream 0"
temp.ljust(60//(total_section_len * 5))
temp += "stream 1"
temp.ljust(60//(total_section_len * 5))
print temp
I am expecting something like
" stream0 stream1 "
but instead what I get is
"stream0stream1"
Why does
str.ljust
behavior in such fashion?
Thanks
The parameter to ljust is the "minimum" length of the string. It will only pad with spaces if this value is longer than the current length of the string.
Unless total_section_len is only 1, 60//(total_section_len * 5) will be less than the length of your strings, so no padding is taking place.
Also, it doesn't modify the string in place as strings are immutable. You need to use the return value, i.e. temp = temp.ljust(...)
ljust(width, fillchr) returns a left justified string by width specified and fills it with fillchr, whose default is empty space.
So
a = ''
b = a.ljust(10)
print(a)
>>> ''
print(b)
>>> ' '
It returns a left justified string to variable b and variable a is not modified.
and So this piece of code should work:
a = ''
a += ''.ljust(10) + 'stream0'
a += ''.ljust(10) + 'stream1'
print(a)
>>> ' stream0 stream1'

I want my parser to return a list of strings, but it returns a blank list

I have a parser that reads in a long octet string, and I want it to print out smaller strings based on the parsing details. It reads in a hexstring which is as follows
The string will be in a format like so:
01046574683001000004677265300000000266010000
The format of the interface contained in the hex is like so:
version:length_of_name:name:op_status:priority:reserved_byte
==
01:04:65746830:01:00:00
== (when converted from hex)
01:04:eth0:01:00:00
^ this is 1 segment of the string , represents eth0 (I inserted the : to make it easier to read). At the minute, however, my code returns a blank list, and I don't know why. Can somebody help me please!
def octetChop(long_hexstring, from_ssh_):
startpoint_of_interface_def=0
# As of 14/8/13 , the network operator has not been implemented
network_operator_implemented=False
version_has_been_read = False
position_of_interface=0
chopped_octet_list = []
#This while loop moves through the string of the interface, based on the full length of the container
try:
while startpoint_of_interface_def < len(long_hexstring):
if version_has_been_read == True:
pass
else:
if startpoint_of_interface_def == 0:
startpoint_of_interface_def = startpoint_of_interface_def + 2
version_has_been_read = True
endpoint_of_interface_def = startpoint_of_interface_def+2
length_of_interface_name = long_hexstring[startpoint_of_interface_def:endpoint_of_interface_def]
length_of_interface_name_in_bytes = int(length_of_interface_name) * 2 #multiply by 2 because its calculating bytes
end_of_interface_name_point = endpoint_of_interface_def + length_of_interface_name_in_bytes
hex_name = long_hexstring[endpoint_of_interface_def:end_of_interface_name_point]
text_name = hex_name.decode("hex")
print "the text_name is " + text_name
operational_status_hex = long_hexstring[end_of_interface_name_point:end_of_interface_name_point+2]
startpoint_of_priority = end_of_interface_name_point+2
priority_hex = long_hexstring[startpoint_of_priority:startpoint_of_priority+2]
#Skip the reserved byte
network_operator_length_startpoint = startpoint_of_priority+4
single_interface_string = long_hexstring[startpoint_of_interface_def:startpoint_of_priority+4]
print single_interface_string + " is chopped from the octet string"# - keep for possible debugging
startpoint_of_interface_def = startpoint_of_priority+4
if network_operator_implemented == True:
network_operator_length = long_hexstring[network_operator_length_startpoint:network_operator_length_startpoint+2]
network_operator_length = int(network_operator_length) * 2
network_operator_start_point = network_operator_length_startpoint+2
network_operator_end_point = network_operator_start_point + network_operator_length
network_operator = long_hexstring[network_operator_start_point:network_operator_end_point]
#
single_interface_string = long_hexstring[startpoint_of_interface_def:network_operator_end_point]
#set the next startpoint if there is one
startpoint_of_interface_def = network_operator_end_point+1
else:
self.network_operator = None
print single_interface_string + " is chopped from the octet string"# - keep for possible debugging
#This is where each individual interface is stored, in a list for comparison.
chopped_octet_list.append(single_interface_string)
finally:
return chopped_octet_list
The reason your code is returning a blank list is the following: In this line:
else:
self.network_operator = None
self is not defined so you get a NameError exception. This means that the try jumps directly to the the finally clause without ever executing the part where you:
chopped_octet_list.append(single_interface_string)
As a consequence the list remains empty. In any case the code is overly complicated for such a task, I would follow one of the other answers.
I hope I got you right. You got a hex-string which contains various interface definition. Inside each interface definition the second octet describes the length of the name of the interface.
Lets say the string contains the interfaces eth0 and eth01 and looks like this (length 4 for eth0 and length 5 for eth01):
01046574683001000001056574683031010000
Then you can split it like this:
def splitIt (s):
tokens = []
while s:
length = int (s [2:4], 16) * 2 + 10 #name length * 2 + 10 digits for rest
tokens.append (s [:length] )
s = s [length:]
return tokens
This yields:
['010465746830010000', '01056574683031010000']
To add onto Hyperboreus's answer, here's a simple way to parse the interface strings once you split them:
def parse(s):
version = int(s[:2], 16)
name_len = int(s[2:4], 16)
name_end = 4 + name_len * 2
name = s[4:name_end].decode('hex')
op_status = int(s[name_end:name_end+2], 16)
priority = int(s[name_end+2:name_end+4], 16)
reserved = s[name_end+4:name_end+6]
return version, name_len, name, op_status, priority, reserved
Here's the output:
>>> parse('010465746830010000')
(1, 4, 'eth0', 1, 0, '00')
Check if the following helps. Call parse method below and pass a string stream into it, then iterate to get card infos (hope I got you right :)) parse will return you tuple(s) of the desired info.
>>> def getbytes(hs):
"""Returns a generator of bytes from a hex string"""
return (int(hs[i:i+2],16) for i in range(0,len(hs)-1,2))
>>> def get_single_card_info(g):
"""Fetches a single card info from a byte generator"""
v = g.next()
l = g.next()
name = "".join(chr(x) for x in map(lambda y: y.next(),[g]*l))
return (str(v),name,g.next(),g.next(),g.next())
>>> def parse(hs):
"""Parses a hex string stream and returns a generator of card infos"""
bs = getbytes(hs)
while True:
yield get_single_card_info(bs)
>>> c = 1
>>> for card in parse("01046574683001000001056574683031010000"):
print "Card:{0} -> Version:{1}, Id:{2}, Op_stat:{3}, priority:{4}, reserved:{5} bytes".format(c,*card)
c = c + 1
Card:1 -> Version:1, Id:eth0, Op_stat:1, priority:0, reserved:0 bytes
Card:2 -> Version:1, Id:eth01, Op_stat:1, priority:0, reserved:0 bytes
Pyparsing includes a built-in expression for parsing a counted array of elements, so this would take care of your 'name' field nicely. Here's the whole parser:
from pyparsing import Word,hexnums,countedArray
# read in 2 hex digits, convert to integer at parse time
octet = Word(hexnums,exact=2).setParseAction(lambda t:int(t[0],16))
# read in a counted array of octets, convert to string
nameExpr = countedArray(octet, intExpr=octet)
nameExpr.setParseAction(lambda t: ''.join(map(chr,t[0])))
# define record expression, with named results
recordExpr = (octet('version') + nameExpr('name') + octet('op_status') +
octet('priority') #+ octet('reserved'))
Parsing your sample:
sample = "01046574683001000004677265300000000266010000"
for rec in recordExpr.searchString(sample):
print rec.dump()
Gives:
[1, 'eth0', 1, 0]
- name: eth0
- op_status: 1
- priority: 0
- version: 1
[0, 'gre0', 0, 0]
- name: gre0
- op_status: 0
- priority: 0
- version: 0
[0, 'f\x01', 0, 0]
- name: f
- op_status: 0
- priority: 0
- version: 0
The dump() method shows results names that you can use to access the individually parsed bits, like rec.name or rec.version.
(I commented out the reserved byte, else the second entry wouldn't parse correctly. Also, the third entry contains a name with a \x01 byte.)

Generating a Random Hex Color in Python

For a Django App, each "member" is assigned a color to help identify them. Their color is stored in the database and then printed/copied into the HTML when it is needed. The only issue is that I am unsure how to generate random Hex colors in python/django. It's easy enough to generate RGB colors, but to store them I would either need to a) make three extra columns in my "Member" model or b) store them all in the same column and use commas to separate them, then, later, parse the colors for the HTML. Neither of these are very appealing, so, again, I'm wondering how to generate random Hex colors in python/django.
import random
r = lambda: random.randint(0,255)
print('#%02X%02X%02X' % (r(),r(),r()))
Here is a simple way:
import random
color = "%06x" % random.randint(0, 0xFFFFFF)
To generate a random 3 char color:
import random
color = "%03x" % random.randint(0, 0xFFF)
%x in C-based languages is a string formatter to format integers as hexadecimal strings while 0x is the prefix to write numbers in base-16.
Colors can be prefixed with "#" if needed (CSS style)
little late to the party,
import random
chars = '0123456789ABCDEF'
['#'+''.join(random.sample(chars,6)) for i in range(N)]
Store it as a HTML color value:
Updated: now accepts both integer (0-255) and float (0.0-1.0) arguments. These will be clamped to their allowed range.
def htmlcolor(r, g, b):
def _chkarg(a):
if isinstance(a, int): # clamp to range 0--255
if a < 0:
a = 0
elif a > 255:
a = 255
elif isinstance(a, float): # clamp to range 0.0--1.0 and convert to integer 0--255
if a < 0.0:
a = 0
elif a > 1.0:
a = 255
else:
a = int(round(a*255))
else:
raise ValueError('Arguments must be integers or floats.')
return a
r = _chkarg(r)
g = _chkarg(g)
b = _chkarg(b)
return '#{:02x}{:02x}{:02x}'.format(r,g,b)
Result:
In [14]: htmlcolor(250,0,0)
Out[14]: '#fa0000'
In [15]: htmlcolor(127,14,54)
Out[15]: '#7f0e36'
In [16]: htmlcolor(0.1, 1.0, 0.9)
Out[16]: '#19ffe5'
This has been done before. Rather than implementing this yourself, possibly introducing errors, you may want to use a ready library, for example Faker. Have a look at the color providers, in particular hex_digit.
In [1]: from faker import Factory
In [2]: fake = Factory.create()
In [3]: fake.hex_color()
Out[3]: u'#3cae6a'
In [4]: fake.hex_color()
Out[4]: u'#5a9e28'
Just store them as an integer with the three channels at different bit offsets (just like they are often stored in memory):
value = (red << 16) + (green << 8) + blue
(If each channel is 0-255). Store that integer in the database and do the reverse operation when you need to get back to the distinct channels.
import random
def hex_code_colors():
a = hex(random.randrange(0,256))
b = hex(random.randrange(0,256))
c = hex(random.randrange(0,256))
a = a[2:]
b = b[2:]
c = c[2:]
if len(a)<2:
a = "0" + a
if len(b)<2:
b = "0" + b
if len(c)<2:
c = "0" + c
z = a + b + c
return "#" + z.upper()
So many ways to do this, so here's a demo using "colorutils".
pip install colorutils
It is possible to generate random values in (RGB, HEX, WEB, YIQ, HSV).
# docs and downloads at
# https://pypi.python.org/pypi/colorutils/
from colorutils import random_web
from tkinter import Tk, Button
mgui = Tk()
mgui.geometry('150x28+400+200')
def rcolor():
rn = random_web()
print(rn) # for terminal watchers
cbutton.config(text=rn)
mgui.config(bg=rn)
cbutton = Button(text="Click", command=rcolor)
cbutton.pack()
mgui.mainloop()
I certainly hope that was helpful.
import secrets
# generate 4 sets of 2-digit hex chars for a color with transparency
rgba = f"#{secrets.token_hex(4)}" # example return: "#ffff0000"
# generate 3 sets of 2-digit hex chars for a non-alpha color
rgb = f"#{secrets.token_hex(3)}" # example return: "#ab12ce"
import random
def generate_color():
color = '#{:02x}{:02x}{:02x}'.format(*map(lambda x: random.randint(0, 255), range(3)))
return color
Basically, this will give you a hashtag, a randint that gets converted to hex, and a padding of zeroes.
from random import randint
color = '#{:06x}'.format(randint(0, 256**3))
#Use the colors wherever you need!
For generating random anything, take a look at the random module
I would suggest you use the module to generate a random integer, take it's modulo 2**24, and treat the top 8 bits as R, that middle 8 bits as G and the bottom 8 as B.
It can all be accomplished with div/mod or bitwise operations.
hex_digits = ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f']
digit_array = []
for i in xrange(6):
digit_array.append(hex_digits[randint(0,15)])
joined_digits = ''.join(digit_array)
color = '#' + joined_digits
import random
def get_random_hex:
random_number = random.randint(0,16777215)
# convert to hexadecimal
hex_number = str(hex(random_number))
# remove 0x and prepend '#'
return'#'+ hex_number[2:]
Would like to improve upon this solution as I found that it could generate color codes that have less than 6 characters. I also wanted to generate a function that would create a list that can be used else where such as for clustering in matplotlib.
import random
def get_random_hex:
random_number = random.randint(0,16777215)
# convert to hexadecimal
hex_number = str(hex(random_number))
# remove 0x and prepend '#'
return'#'+ hex_number[2:]
My proposal is :
import numpy as np
def color_generator (no_colors):
colors = []
while len(colors) < no_colors:
random_number = np.random.randint(0,16777215)
hex_number = format(random_number, 'x')
if len(hex_number) == 6:
hex_number = '#'+ hex_number
colors.append (hex_number)
return colors
Here's a simple code that I wrote based on what hexadecimal color notations represent:
import random
def getRandomCol():
r = hex(random.randrange(0, 255))[2:]
g = hex(random.randrange(0, 255))[2:]
b = hex(random.randrange(0, 255))[2:]
random_col = '#'+r+g+b
return random_col
The '#' in the hexadecimal color code just represents that the number represented is just a hexadecimal number. What's important is the next 6 digits. Pairs of 2 digits in those 6 hexadecimal digits represent the intensity of RGB (Red, Green, and Blue) each. The intensity of each color ranges between 0-255 and a combination of different intensities of RGB produces different colors.
For example, in #ff00ff, the first ff is equivalent to 255 in decimal, the next 00 is equivalent to 0 in decimal, and the last ff is equivalent to 255 in decimal. Therefore, #ff00ff in hexadecimal color coding is equivalent to RGB(255, 0, 255).
With this concept, here's the explanation of my approach:
Generated intensities of random numbers for each of r, g
and b
Converted those intensities into hexadecimal
Ignored the first 2 characters of each hexadecimal value '0x'
Concatenated '#' with the hexadecimal values r, g and b
intensities.
Feel free to refer to this link if you wanna know more about how colors work: https://hackernoon.com/hex-colors-how-do-they-work-d8cb935ac0f
Cheers!
Hi, maybe i could help with the next function that generate random Hex colors :
from colour import Color
import random as random
def Hex_color():
L = '0123456789ABCDEF'
return Color('#'+ ''.join([random.choice(L) for i in range(6)][:]))
from random import randbytes
randbytes(3).hex()
output
f5f2c9
There are a lot of complex answers here, this is what I used for a code of mine using one import line and one line to get a random code:
import random
color = '#' + ''.join(random.choices('0123456789ABCDEF', k=6))
print(color)
The output will be something like:
#3F67CD
If you want to make a list of color values, let's say, of 10 random colors, you can do the following:
import random as r
hex_chars = '0123456789ABCDEF'
num_colors = 10
colors = ['#' + ''.join(r.choices(hex_chars, k=6)) for _ in range(num_colors)]
print(colors)
And the output will be a list containing ten different random colors:
['#3DBEA2', '#0B3B64', '#31D196', '#6A98C2', '#9C1712', '#73AFFE', '#9F5E0D', '#A2F07E', '#EB6407', '#7E8FB6']
I hope that helps!

Categories

Resources