How to stick scrollbar in label tkinter - python

this is what i got
And only when I maximize the window I can see the scroll bar
I want to stick the scrollbar (horizontal and vertical) in treeview. regardless of the window size.
I'm trying to add scrollbar to label with treeview regardless of the window size.
this is my code:
def mainGUI():
root = tk.Tk()
root.geometry("700x300")
root.title("test")
root.columnconfigure(0, weight=1)
data = [["this is a long text","this is a long text","this is a long text","this is a long text","this is a long text","this is a long text"],
["this is a long text","this is a long text","this is a long text","this is a long text","this is a long text","this is a long text"],
["this is a long text","this is a long text","this is a long text","this is a long text","this is a long text","this is a long text"],
["this is a long text","this is a long text","this is a long text","this is a long text","this is a long text","this is a long text"],
["this is a long text","this is a long text","this is a long text","this is a long text","this is a long text","this is a long text"],
["this is a long text","this is a long text","this is a long text","this is a long text","this is a long text","this is a long text"],
["this is a long text","this is a long text","this is a long text","this is a long text","this is a long text","this is a long text"],
["this is a long text","this is a long text","this is a long text","this is a long text","this is a long text","this is a long text"],
["this is a long text","this is a long text","this is a long text","this is a long text","this is a long text","this is a long text"],
["this is a long text","this is a long text","this is a long text","this is a long text","this is a long text","this is a long text"],
["this is a long text","this is a long text","this is a long text","this is a long text","this is a long text","this is a long text"],
["this is a long text","this is a long text","this is a long text","this is a long text","this is a long text","this is a long text"],
["this is a long text","this is a long text","this is a long text","this is a long text","this is a long text","this is a long text"],
["this is a long text","this is a long text","this is a long text","this is a long text","this is a long text","this is a long text"]]
results_lf = ttk.LabelFrame(root, text="Results:")
results_lf.grid(row=1, column=0, padx=20, pady=0, sticky='ew')
resultsLabel = Label(results_lf)
resultsLabel.pack(fill='x',expand=True, side=LEFT)
columnsHeader = ["1", "2", "3", "4", "5", "6"]
tree = ttk.Treeview(resultsLabel, columns=columnsHeader, show='headings')
tree.heading('1', text='1')
tree.heading('2', text='2')
tree.heading('3', text='3')
tree.heading('4', text='4')
tree.heading('5', text='5')
tree.heading('6', text='6')
for line in data:
tree.insert('', tk.END, values=line)
tree.pack(side=LEFT)
sb_v = Scrollbar(resultsLabel, orient=VERTICAL)
sb_v.pack(side=RIGHT, fill=Y)
sb_h = Scrollbar(resultsLabel, orient=HORIZONTAL)
sb_h.pack(side=BOTTOM, fill=X)
tree.config(yscrollcommand=sb_v.set)
sb_v.config(command=tree.yview)
sb_h.config(command=tree.xview)
root.mainloop()
mainGUI()

When using pack, the order in which you add widgets matters. pack will allocate an entire side of the available space for each widget that is added.
When you pack the tree on the left, the packer allocates the entire left side for that widget. That means that things added to the top, right, or bottom will all be to the right of what was packed to the left. So, when you later pack the horizontal scrollbar it will be to the right of everything that is on the left.
The simple solution is to pack the two scrollbars before packing the tree. Personally I find it best to group together all calls to pack or place for children with a common parent. It makes visualizing the layout easier, and makes it easier to make changes like this.
So, if you move all of the calls to pack for these three widgets to the end of the function, it should look like this:
sb_v.pack(side=RIGHT, fill=Y)
sb_h.pack(side=BOTTOM, fill=X)
tree.pack(side=LEFT)
For an answer with images that describe how the packer works, see this answer to the question Tkinter pack method confusion

In line 29, change results_lf.grid(row=1, to
results_lf.grid(row=0,
In line 31, change ttk.LabelFrame(root, to ttk.Label(results_lf,
in line 32, change to pack to grid and row to
resultsLabel.grid(row=0, column=0, padx=5,pady=0, sticky='w')
in line 36, ttk.Treeview(resultsLabel, to
ttk.Treeview(results_lf,
in line 47, change to pack to grid and row to
tree.grid(row=1,column=0,padx=5,pady=10, sticky='nw')
In line 49, change Scrollbar(resultsLabel to
ttk.Scrollbar(results_lf, #Vertical
in line 50 change to pack to grid and row to
sb_v.grid(row=1,column=1, sticky='ns')
in line change Scrollbar(resultsLabel, to
ttk.Scrollbar(results_lf, #HORIZPNTAL
in line 53 change to pack to grid and row to sb_h.grid(row=2,column=0,
sticky='we')
Code:
import tkinter as tk
from tkinter import ttk
def mainGUI():
root = tk.Tk()
root.geometry("700x300")
root.title("test")
root.rowconfigure(0, weight=2)
data = [["this is a long text","this is a long text","this is a long text","this is a long text","this is a long text","this is a long text"],
["this is a long text","this is a long text","this is a long text","this is a long text","this is a long text","this is a long text"],
["this is a long text","this is a long text","this is a long text","this is a long text","this is a long text","this is a long text"],
["this is a long text","this is a long text","this is a long text","this is a long text","this is a long text","this is a long text"],
["this is a long text","this is a long text","this is a long text","this is a long text","this is a long text","this is a long text"],
["this is a long text","this is a long text","this is a long text","this is a long text","this is a long text","this is a long text"],
["this is a long text","this is a long text","this is a long text","this is a long text","this is a long text","this is a long text"],
["this is a long text","this is a long text","this is a long text","this is a long text","this is a long text","this is a long text"],
["this is a long text","this is a long text","this is a long text","this is a long text","this is a long text","this is a long text"],
["this is a long text","this is a long text","this is a long text","this is a long text","this is a long text","this is a long text"],
["this is a long text","this is a long text","this is a long text","this is a long text","this is a long text","this is a long text"],
["this is a long text","this is a long text","this is a long text","this is a long text","this is a long text","this is a long text"],
["this is a long text","this is a long text","this is a long text","this is a long text","this is a long text","this is a long text"],
["this is a long text","this is a long text","this is a long text","this is a long text","this is a long text","this is a long text"]]
results_lf = ttk.LabelFrame(root, text="Results:")
results_lf.grid(row=0, column=0, sticky='nw')
resultsLabel = ttk.Label(results_lf, text='hello')
resultsLabel.grid(row=0, column=0, padx=5,pady=0, sticky='w')
columnsHeader = ["1", "2", "3", "4", "5", "6"]
tree = ttk.Treeview(results_lf, columns=columnsHeader, show='headings')
tree.heading('1', text='1')
tree.heading('2', text='2')
tree.heading('3', text='3')
tree.heading('4', text='4')
tree.heading('5', text='5')
tree.heading('6', text='6')
for line in data:
tree.insert('', tk.END, values=line)
tree.grid(row=1,column=0,padx=5,pady=10, sticky='nw')
sb_v = ttk.Scrollbar(results_lf, orient=tk.VERTICAL)
sb_v.grid(row=1,column=1, sticky='ns')
sb_h = ttk.Scrollbar(results_lf, orient=tk.HORIZONTAL)
sb_h.grid(row=2,column=0, sticky='we')
tree.config(yscrollcommand=sb_v.set)
sb_v.config(command=tree.yview)
sb_h.config(command=tree.xview)
root.mainloop()
mainGUI()
Screenshot: you Label is visible on top left:

Related

How can I use batch embeddings using OpenAI's API?

I am using the OpenAI API to get embeddings for a bunch of sentences. And by a bunch of sentences, I mean a bunch of sentences, like thousands. Is there a way to make it faster or make it do the embeddings concurrently or something?
I tried Looping through and sending a request for each sentence but that was super slow, but so is sending a list of the sentences. For both cases I used this code : '''
response = requests.post(
"https://api.openai.com/v1/embeddings",
json={
"model": "text-embedding-ada-002",
"input": ["text:This is a test", "text:This is another test", "text:This is a third test", "text:This is a fourth test", "text:This is a fifth test", "text:This is a sixth test", "text:This is a seventh test", "text:This is a eighth test", "text:This is a ninth test", "text:This is a tenth test", "text:This is a eleventh test", "text:This is a twelfth test", "text:This is a thirteenth test", "text:This is a fourteenth test", "text:This is a fifteenth test", "text:This is a sixteenth test", "text:This is a seventeenth test", "text:This is a eighteenth test", "text:This is a nineteenth test", "text:This is a twentieth test", "text:This is a twenty first test", "text:This is a twenty second test", "text:This is a twenty third test", "text:This is a twenty fourth test", "text:This is a twenty fifth test", "text:This is a twenty sixth test", "text:This is a twenty seventh test", "text:This is a twenty eighth test", "text:This is a twenty ninth test", "text:This is a thirtieth test", "text:This is a thirty first test", "text:This is a thirty second test", "text:This is a thirty third test", "text:This is a thirty fourth test", "text:This is a thirty fifth test", "text:This is a thirty sixth test", "text:This is a thirty seventh test", "text:This is a thirty eighth test", "text:This is a thirty ninth test", "text:This is a fourtieth test", "text:This is a forty first test", "text:This is a forty second test", "text:This is a forty third test", "text:This is a forty fourth test", "text:This is a forty fifth test", "text:This is a forty sixth test", "text:This is a forty seventh test", "text:This is a forty eighth test", "text:This is a forty ninth test", "text:This is a fiftieth test", "text:This is a fifty first test", "text:This is a fifty second test", "text:This is a fifty third test"],
},
headers={
"Authorization": f"Bearer {key}"
}
)
For the first test I did a bunch of those requests one by one, and the second one I sent a list. Should I send individual requests in parallel? Would that help? Thanks!
According to OpenAi's Create Embeddings API, you should be able to do this:
To get embeddings for multiple inputs in a single request, pass an array of strings or array of token arrays. Each input must not exceed 8192 tokens in length.
https://beta.openai.com/docs/api-reference/embeddings/create

Convert number inside a string to english words

I'm currently working on neural text to speech, and to process the data I need several steps. One step is convert the numeric in string into english character words instead of numeral. The closest thing I can found is num2words, but I'm not sure how to apply it to an existing string. Here's my use case :
I have list of string like this
list_string = ['I spent 140 dollar yesterday','I have 3 brothers and 2 sisters']
I wanted to convert into :
output_string = ['I spent one hundred forty dollar yesterday','I have three brothers and two sisters']
The struggle is one text might consist of several number, and even if I can get the numeric using re.match, I'm not sure how to put the number back to the string.
No need to worry about floating number or year for now since I don't have that kind of number inside my string.
Thanks
There is a very quick way to do it in one line using regex to match digits and replace them in string:
from num2words import num2words
import re
list_string = ['I spent 140 dollar yesterday','I have 3 brothers and 2 sisters']
output_string = [re.sub('(\d+)', lambda m: num2words(m.group()), sentence) for sentence in list_string]
Otherwise, you can iterate through the words contained in each sentence and replace them in case they are numbers. Please see the code below:
from num2words import num2words
list_string = ['I spent 140 dollar yesterday','I have 3 brothers and 2 sisters']
output_string = []
for sentence in list_string:
output_sentence = []
for word in sentence.split():
if word.isdigit():
output_sentence.append(num2words(word))
else:
output_sentence.append(word)
output_string.append(' '.join(output_sentence))
print(output_string)
# Output
# ['I spent one hundred and forty dollar yesterday', 'I have three brothers and two sisters']
I have tried it doing it in bash, the script looks like this.
file name be conver2words.sh , invoke this from your python script.
digits=(
"" one two three four five six seven eight nine
ten eleven twelve thirteen fourteen fifteen sixteen seventeen eightteen nineteen
)
tens=("" "" twenty thirty forty fifty sixty seventy eighty ninety)
units=("" thousand million billion trillion)
number2words() {
local -i number=$((10#$1))
local -i u=0
local words=()
local group
while ((number > 0)); do
group=$(hundreds2words $((number % 1000)) )
[[ -n "$group" ]] && group="$group ${units[u]}"
words=("$group" "${words[#]}")
((u++))
((number = number / 1000))
done
echo "${words[*]}"
}
hundreds2words() {
local -i num=$((10#$1))
if ((num < 20)); then
echo "${digits[num]}"
elif ((num < 100)); then
echo "${tens[num / 10]} ${digits[num % 10]}"
else
echo "${digits[num / 100]} hundred $("$FUNCNAME" $((num % 100)) )"
fi
}
with_commas() {
# sed -r ':a;s/^([0-9]+)([0-9]{3})/\1,\2/;ta' <<<"$1"
# or, with just bash
while [[ $1 =~ ^([0-9]+)([0-9]{3})(.*) ]]; do
set -- "${BASH_REMATCH[1]},${BASH_REMATCH[2]}${BASH_REMATCH[3]}"
done
echo "$1"
}
for arg; do
[[ $arg == *[^0-9]* ]] && result="NaN" || result=$(number2words "$arg")
printf "%s\t%s\n" "$(with_commas "$arg")" "$result"
done
In action:
$ bash ./num2text.sh 9 98 987
9 nine
98 ninety eight
987 nine hundred eighty seven
you can check if the string has the number and call this script to get the words of it.
Adding the python code for this, this is a draft you will get an idea
list_string = ['I spent 140 dollar yesterday','I have 3 brothers and 2 sisters']
for str in list_string:
str_split = str.split(" ");
for word in str_split:
if word.isnumeric():
// now you know this is numberic and call the bash script from here and read the output you can also use os.system if it works instead of sub process
out = subprocess.call(['bash','conver2words.sh',word])
line = out.stdout.readline()
print(line);
else:
print(word);

Extracting multiple digits from pandas non-uniform column with classification

df with a text column 'DescCol' that has been entered variously with no consistent but, somewhat similar patterns. I need to:
(a) extract all substrings within parentheses
(b) if the extracted substring contains numbers then:
(b.i) if (b) the beginning text is in ('Up to', '<', 'Tolerance') - so mark a boolean column 'isToleranceSpec' Yes for 'Tolerance', No otherwise
(b.ii) extract the digit following the beginning text of the substring (which may or may not have comma separator) into a column called 'BandLimit'
(b.iii) then check if there is further follow-on text ('thereafter' AFAIK)
(b.iv) if (b.iii) then extract the number following 'thereafter' into a column called 'Marginal' else continue
(c) if not (b): continue
So the result df will look like below ('Remarks' columns highlights some of the peculiarities I've noticed in the data so far):
df = pd.DataFrame({"DescCol":["beginning text (Up to 1,234 days, thereafter 11d each) ending text",
"beginning text (Up to 1234 days, thereafter 11d each) ending text",
"beginning text (Tolerance 4,567 days, thereafter 12d each) ending text",
"beginning text (Tolerance 4567 days, thereafter 12d each) ending text",
"beginning text (Tolerance 891011 days) ending text",
"beginning text (<1,112 days, thereafter 13d each) ending text",
"beginning text (no numbers within parentheses) ending text"],
"Remarks": ["comma in number",
"no comma in number",
"tolerance with thereafter, comma in large number",
"tolerance with thereafter, no comma in large number",
"tolerance without thereafter",
"less than sign used + comma in number",
"non-relevant row"],
"isToleranceSpec": ["No", "No", "Yes", "Yes", "Yes", "No", ''],
"BandLimit": [1234, 1234, 4567, 4567, 891011, 1112, ''],
"Marginal": [11, 11, 12, 12, '', 13, '']})
I can uppercase DescCol and extract the sub-string b/w '(' and ')', any pithy solutions post that v welcome. Thanks
Not sure this is what you want, but here is a pity solution:
def extract_infos(row):
# check numbers in parentheses
m = re.findall('\(.*\d.*\)', row.DescCol)
if len(m) != 1:
return
t = m[0][1:-1] # strip the ()
# tolerance and bandlimit
row['isToleranceSpec'] = 'Yes' if any(t.startswith(x) for x in ('Up to', '<', 'Tolerance')) else 'No'
row['BandLimit'] = int(re.findall('\d+,?\d*', t)[0].replace(',', ''))
# marginal
m = re.search('thereafter (\d+)', t)
if m is not None:
row['Marginal'] = int(m.groups()[0])
return row
This method can then be used like this:
# start with a DataFrame that has only DescCol
start = your_example_df[['DescCol']].copy()
# add default column values
for c in ['isToleranceSpec', 'BandLimit', 'Marginal']:
start[c] = '' # weird to have empty strings in int columns, but...
# Do the magic !
_ = start.apply(extract_infos, axis=1)
It does work for your example, but you might want to add some additional checks (e.g.: I suppose that if there is a thereafter, there is necessarily a number after, etc.)

Python RegEx to replace string

How do I use RegEx (or something else in Python) for the following requirement?
I need to:
Remove the word "dream" (including all its stems)
Remove All previous words (i.e. all words behind the word "dream")
Remove the Word next to it (in front of it/to the right of "dream")
Remove the word "to" from all phrases.
Input:
text = ["Dream of a car",
"Dream to live in a world",
"Dream about 8am every morning",
"stopped dreaming today",
"still dreaming of a car",
"One more dream to come late tomorrow",
"Dream coming to hope tomorrow"]
Required Output:
["a car",
"live in a world",
"8am every morning",
" ",
"a car",
"come late tomorrow",
"hope tomorrow"]
I tried:
result = [re.sub('Dream', '', a) for a in text]
# MyOutput
[' of a car', ' to live in a world', ' about 8am every morning', 'stopped dreaming today', 'still dreaming of a car', 'One more dream to come late tomorrow', ' coming to hope tomorrow']
This gives your required output
result = [re.sub(r'\bto\b *', '', re.sub(r'^.*Dream[^ ]* *[^ ]* *', '', a, flags=re.I)) for a in text]
If you only want to remove the to at the front
result = [re.sub(r'^.*Dream[^ ]* *[^ ]* *(\bto\b)? *', '', a, flags=re.I) for a in text]

how to return numbers in word format from a string in python

EDIT: The "already answered" is not talking about what I am. My string already comes out in word format. I need to strip those words from my string into a list
I'm trying to work with phrase manipulation for a voice assistant in python.
When I speak something like:
"What is 15,276 divided by 5?"
It comes out formatted like this:
"what is fifteen thousand two hundred seventy six divided by five"
I already have a way to change a string to an int for the math part, so is there a way to somehow get a list like this from the phrase?
['fifteen thousand two hundred seventy six','five']
Go through the list of words and check each one for membership in a set of numerical words. Add adjacent words to a temporary list. When you find a non-number word, create a new list. Remember to account for non-number words at the beginning of the sentence and number words at the end of the sentence.
result = []
group = []
nums = set('one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty thirty forty fifty sixty seventy eighty ninety hundred thousand million billion trillion quadrillion quintillion'.split())
for word in "what is fifteen thousand two hundred seventy six divided by five".split():
if word in nums:
group.append(word)
else:
if group:
result.append(group)
group = []
if group:
result.append(group)
Result:
>>> result
[['fifteen', 'thousand', 'two', 'hundred', 'seventy', 'six'], ['five']]
To join each sublist into a single string:
>>> list(map(' '.join, result))
['fifteen thousand two hundred seventy six', 'five']

Categories

Resources