pySimpleGUI : a way to build tooltip for a table on a per row or per cell basis? - row

I'm trying to have the last column of my table readable. Already struggled with the column element encapsulating the table to have horizontal scroll bar to be displayed on my table (nested in a tab). But it doesn't really help as I can't get the last column width with the right width. (The whole table is populated through csv extraction.)
So I thought I could handle this through tooltips. I managed to update one for the whole table with data extracted from the first row but it is obviously not what I need. I need the tooltip to be built iterally on each row, at least.
Any idea ?
subsidiary question : reading the pySimplegui doc, it talks about textwrap but I can't find doc to this lib. any link ?
here below my code, hope it's not too dirty I'm not fluent...
code :
i =3 #skippin the first lines
for row in range (0, len(window.FindElement('pronos_table').Values)):
el = pdata[i]
if len(el[3]) > 50 :
str_inf = el[3][0:50]+"\r\n"+el[3][50:] #TODO refine this later with textwrap or something
window['pronos_table'].set_tooltip(str_inf) #tried many things here,
else:
window['pronos_table'].set_tooltip(el[3]) #...and here : got only this to work
i = i + 1

Tooltip for row maybe not work for you, and it let things more complex, how about use an extra element to show your long column.
Example here, data accessed from web site, maybe take a little time to start GUI.
import requests
from bs4 import BeautifulSoup
import PySimpleGUI as sg
url = 'https://medium.com/#EmEmbarty/31-of-the-best-and-most-famous-short-classic-poems-of-all-time-e445986e6df'
response = requests.get(url)
if response.status_code != 200:
print('Failed to access data from website !')
quit()
html = response.text
soup = BeautifulSoup(html, features='html.parser')
headings = ['Title', 'Auther']
data = []
poem_lst = []
poems = []
for tag in soup.findAll(['h1', 'p'])[7:-12]:
name = tag.name
if name == 'h1':
if poem_lst:
poem = '\n'.join(poem_lst[:-1])
data.append([title, auther])
poems.append(poem)
text = tag.a.text
index1 = text.index('“')
index2 = text.index('” by ')
title, auther = text[index1+1:index2], text[index2+5:]
poem_lst = []
elif name == 'p':
poem_lst.append(tag.text)
poem = '\n'.join(poem_lst[:-1])
data.append([title, auther])
poems.append(poem)
# ---------- GUI start from here ---------
sg.theme('DarkBlue')
sg.set_options(font=('Courier New', 12))
col_widths = [max(map(lambda x:len(x[0])+1, data)), max(map(lambda x:len(x[0]), data))+1]
layout = [
[sg.Table(data, headings=headings, enable_events=True,
justification='left', select_mode=sg.TABLE_SELECT_MODE_BROWSE,
auto_size_columns=False, col_widths=col_widths, key='-TABLE-')],
[sg.Multiline('', size=(50, 10),
text_color='white', background_color=sg.theme_background_color(),
key='-MULTILINE-'),],
]
window = sg.Window("Table", layout, finalize=True)
multiline = window['-MULTILINE-']
multiline.expand(expand_x=True)
multiline.Widget.configure(spacing1=3, spacing2=1, spacing3=3)
while True:
event, values = window.read()
if event == sg.WINDOW_CLOSED:
break
elif event == '-TABLE-':
selection = values[event][0]
text = poems[selection]
multiline.update(value=text)
window.close()

This is runnable code. Can't get better !
#!/usr/bin/env python3
# coding: utf-8
import re
import PySimpleGUI as sg
bigD = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
headings = [f'headings {col:>2d}' for col in range(3)]
vals = [["|"+str(row)+"- "+bigD if col==2 else f'data {row*10+col:>2d}' for col in range(3)] for row in range(50)]
sg.theme("DarkBlue3")
sg.set_options(font=("Courier New", 16))
table_layout = [[sg.Table(values=vals, headings=headings, num_rows=50,
auto_size_columns=False, key='pronos_table', alternating_row_color='Grey', col_widths=list(map(lambda x:len(x)+1, headings)),
hide_vertical_scroll=True)]]
layout = [[sg.Column(table_layout, scrollable=True, size=(420, 500))]]
window = sg.Window('Sample excel file', layout, finalize=True)
window.bind('<FocusIn>', '+ROW FOCUS+')
window.bind('<Enter>', '+TABLE ENTER+')
window.bind('<Leave>', '+TABLE LEAVE+')
str_inf = 'Select a row'
while True:
event, values = window.read()
#window.enable()
#window.BringToFront()
print(event,values['pronos_table'])
if event == '+TABLE LEAVE+':
if len(values['pronos_table'])!=0:
el = vals[int(str(values['pronos_table'][0])) if len(values['pronos_table']) != 0 else 0]
el[2] = str(el[2]).strip().replace('None','')
str_inf = re.sub("(.{64})", "\\1\r", el[2], 0, re.DOTALL)
#str_inf = "\n".join(textwrap.wrap(el[3], width=64))
print(len(values['pronos_table']))
window['pronos_table'].set_tooltip(str_inf)
window.close()

Related

Expanding abbreviations using regex

I have a dictionary of abbreviations, I would like to expand. I would like to use these to go through a text and expand all abbreviations.
The defined dictionary is as follows:
contractions_dict = {
"kl\.": "klokken",
}
The text I which to expand is as follows:
text = 'Gl. Syd- og Sønderjyllands Politi er måske kl. 18 kløjes landets mest aktive politikreds på Twitter med over 27.000, som følger med.'
I use the following function:
def expand_contractions(s, contractions_dict, contractions_re):
def replace(match):
return contractions_dict[match.group(0)]
return contractions_re.sub(replace, s)
contractions_re = re.compile("(%s)"%"|".join(contractions_dict.keys()))
text = expand_contractions(text, contractions_dict, contractions_re)
print(text)
I have tried a range of different keys in the dictionary to capture the abbreviations, but nothing have worked. Any suggestions?
Try:
import re
contractions_dict = {
"kl.": "klokken",
}
pat = re.compile(r'\b' + r'|'.join(re.escape(k) for k in contractions_dict))
text = "Gl. Syd- og Sønderjyllands Politi er måske kl. 18 kløjes landets mest aktive politikreds på Twitter med over 27.000, som følger med."
text = pat.sub(lambda g: contractions_dict[g.group(0)], text)
print(text)
Prints:
Gl. Syd- og Sønderjyllands Politi er måske klokken 18 kløjes landets mest aktive politikreds på Twitter med over 27.000, som følger med.

Dart - Extract number from list

I have a List that contains lottery numbers
List image
How can I separate number and text, and after that list them in the below list: for example:
List<String> n = ["ABC23", "21A23", "12A312","32141A"];
Thank you!
You can do it by using forEach like below:
List<String> n = ["23", "2123", "12312","32141"];
n.forEach((element) =>
print(element)
);
And to separate number and text you can use the following code:
const text = '''
Lorem Ipsum is simply dummy text of the 123.456 printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an 12:30 unknown printer took a galley of type and scrambled it to make a
23.4567
type specimen book. It has 445566 survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
''';
final intRegex = RegExp(r'\s+(\d+)\s+', multiLine: true);
final doubleRegex = RegExp(r'\s+(\d+\.\d+)\s+', multiLine: true);
final timeRegex = RegExp(r'\s+(\d{1,2}:\d{2})\s+', multiLine: true);
void main() {
print(intRegex.allMatches(text).map((m) => m.group(0)));
print(doubleRegex.allMatches(text).map((m) => m.group(0)));
print(timeRegex.allMatches(text).map((m) => m.group(0)));
}
Please refer to this link for more information.
To do something with each element:
List<String> n = ["23", "2123", "12312","32141"];
n.forEach((element) {
int number = int.parse(element);
...
}
);
To do create list of ints:
List<String> n = ["23", "2123", "12312","32141"];
final intList = n.map((element) => int.parse(element)).toList();

I need this program to print out the count of the words with the largest amount first. Then limit the list to only the top 20 words inserted

#include <bits/stdc++.h>
#include <map>
#include <string>
#include <algorithm>
#include <set>
#include <iostream>
//#include <functional>
using namespace std;
void printFrequency(string str)
{
map<string, int> freq;
string word = "";
for (int i = 0; i < str.size(); i++)
{
if (str[i] == ' ')
{
if (freq.find(word) == freq.end())
{
freq.insert(make_pair(word, 1));
word = "";
}
else
{
freq[word]++;
word = "";
}
}
else
word += str[i];
}
if (freq.find(word) == freq.end())
freq.insert(make_pair(word, 1));
else
freq[word]++;
for (map<string, int>::iterator itr = freq.begin(); itr != freq.end(); ++itr)
{
cout << setw(20)<<itr->first <<setw(20)<< itr->second<< endl;
}
};
int main()
{
string str = " ";
cout << "Enter your string: ";
getline(cin, str);
cout << endl;
printFrequency(str);
return 0;
}
...
I am trying to figure out how to print by the count of the words instead of the words themselves. Then limit the output to only the top 20 words and their corresponding count. I believe I have to add maybe a vector into the equation to compare the count somehow. Just not sure how. Thank you in advance.
My suggestions:
Keep an unordered_map<string,int> for counting words for better efficiency.
Create multimap<int,string> for key, value pairs while iterating over the first map and pick first 20 elements.
a reference:
How can I sort an STL map by value?
I would like to show to you a "more-modern" C++ approach by using existing algorithms from the standard C++ library.
We will also use a standard solution for this kind of question. Because, the basic, underlying question is, how to sort an associative container, like std::map or std::unordered_map by its value, and not by its key.
Sorting by value is of course not possible for these containers. Reason:
It is the basic property of a std::map that it is sorted by its key values.
And, the std::unordered_map, has the logical property that it is unordered and, addionally, has a "ForwardIterator" and not a "RandomAccessIterator", as required by sort-functions.
The answer and the standard solution is, to put the data into a different container and sort this instead.
I will now show you the code. The code contains your function "printFrequency" in a "modern-C++" style. Later, I will explain the code in detail, line by line.
#include <iostream>
#include <string>
#include <algorithm>
#include <regex>
#include <map>
#include <vector>
#include <utility>
#include <iomanip>
// Some test data
std::string testString
{ R"(Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy
eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam
voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet
clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy
eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.
At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren,
no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet,
consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et
dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo
dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est
Lorem ipsum dolor sit amet.)" };
// We want to output this number of lines
constexpr size_t NumberOfOutputLines = 20U;
// Some abbreviation for our pair to store a word and its associated counter
using CounterType = std::pair<std::string, size_t>;
// Enhance our pair with 2 new functionalities: Output and comparison (for sorting)
struct CTO : public CounterType {
friend std::ostream& operator << (std::ostream& os, const CTO& co) {
return os << std::setw(30) << co.first << " --> " << co.second << '\n';
}
friend bool operator < (const CTO& p1, const CTO& p2) { return p2.second < p1.second; }
};
// Regex Helpers
// Regex to find a word
static const std::regex reWord{ R"(\w+)" };
// Result of search for one word in the string
static std::smatch smWord;
void printFrequency(std::string& data) {
// Here we will store the result. The word and the associated "count"
std::map<std::string, size_t> counter{};
// Iterate over all words in the string with a simple for loop and increment counter
for (std::string s{ data }; std::regex_search(s, smWord, reWord); s = smWord.suffix())
counter[smWord[0]]++;
// Copy result into a vector and sort it
std::vector<CTO> countedWords(counter.begin(), counter.end());
std::sort(countedWords.begin(), countedWords.end());
// Handle special case, where there are less counts available than expected
const size_t oCount{ std::min(countedWords.size(),NumberOfOutputLines) };
// Output sorted result
std::copy_n(countedWords.begin(), oCount, std::ostream_iterator<CTO>(std::cout));
}
// Driver code
int main() {
printFrequency(testString);
return 0;
}
First, some words to the logical design of the function. Also for counting, we will use the standard approach with a std::map or std::unordered_map, use their index operator to either create or retrieve a key-value-pair and increment the value, so the counter.
For iterating over all words in the input string, we will use a std::regex. This will give us the maximum flexibility and is very easy to use.
Ok, then, we start with defining a constexpr to specify the number of requested output lines.
We define an alias for our "Counter Type", for easier typing and better understanding. This is a std::pair<std::string, size_t>, a std::string for the word and a size_t for the counter part.
Because the std::pair has no default output function and "less-than" operator needed for sorting, we create a new customized "CounterType" with the name CTO by deriving from our std::pair and add an output (inserter) operator and a less-than operator.
With that, we decouple functionality from the main software part and associate it with its type. That is the object oriented approach.
For the output operator (the inserter operator), we simply write the 2 parts of the std::pair in a nice way to the output stream. No big deal.
In the less-than operator, we compare p2 wit p1 (and not vice versa). With that we reverse the sorting direction and get values sorted from big to small.
For the regex we use the easiest definition for a word, which is \w+, so, one or many alpha numeric characters. In the std::smatch we store the result of the std::regex_matchor std::regex_search function.
In the function body we first define our "counter" variable, here a std::map. Words will be associated with the count of their occurence. I use a std::map here, because I do want to have a sorted output for values having the same count.
Then, we want to iterate over all words of the input string. For iterating over "things" in C++, we usually use a for loop. First, we initialize the "loop"-variable with our input string, then, we search for the next word (and continue, until no more word is available). Last, we point to the next position in the input string after the previously found word. So, a classical for loop. Please check the functionality of ```std::regex_search```` here.
In the loop body, we use the std::map's index operator. It will first either create a new word with default count 0 (if there was no such entry yet), or, it will search for an existing entry and find it. In any case, a reference to the value for the word is returned. That will be incremented. And so, we count occurences of words.
Now we will define a variable "countedWords" of type std::vector. We will use its "range"-constructor. See here, constructor number 5. This will define and initialize our variable with the contents of the std::map. Next, we will sort the std::vector and this will work, because our custom data type has a less-than-operator.
Basically now everything done, and just output is needed. We want to copy a certain number of results to std::cout. But it may be that there are less elements in the std::vector than we want to output. So we will take the minimum value of elements in the std::vector and the requested number and proceed with that.
For the output, we will use std::copy_n. It will take elements in the std::vector as source and send them to std::cout with the help of the std::ostream_iterator. The std::ostream_iterator will simply call the above defined inserter operator for the elements in the std::vector
At the end, we define a simple "main" function as driver code and use some test string as input data.
The result is a compact and easy to understand function. Straight forward and using "modern-C++"
Of course there are millions of other possible implementations.
If there are any questions, then I am happy to answer.

Dynamic String Masking in scala

Is there any simple way to do data masking in scala, can anyone please explain. I want to dynamically change the matching patterns to X with same keyword lengths
Example:
patterns to mask:
Narendra\s*Modi
Trump
JUN-\d\d
Input:
Narendra Modi pm of india 2020-JUN-03
Donald Trump president of USA
Ouput:
XXXXXXXX XXXX pm of india 2020-XXX-XX
Donald XXXXX president of USA
Note:Only characters should be masked, i want to retain space or hyphen in output for matching patterns
So you have an input String:
val input =
"Narendra Modi of India, 2020-JUN-03, Donald Trump of USA."
Masking off a given target with a given length is trivial.
input.replaceAllLiterally("abc", "XXX")
If you have many such targets of different lengths then it becomes more interesting.
"India|USA".r.replaceAllIn(input, "X" * _.matched.length)
//res0: String = Narendra Modi of XXXXX, 2020-JUN-03, Donald Trump of XXX.
If you have a mix of masked characters and kept characters, multiple targets can still be grouped together, but they must have the same number of sub-groups and the same pattern of masked-group to kept-group.
In this case the pattern is (mask)(keep)(mask).
raw"(Narendra)(\s+)(Modi)|(Donald)(\s+)(Trump)|(JUN)([-/])(\d+)".r
.replaceAllIn(input,{m =>
val List(a,b,c) = m.subgroups.flatMap(Option(_))
"X"*a.length + b + "X"*c.length
})
//res1: String = XXXXXXXX XXXX of India, 2020-XXX-XX, XXXXXX XXXXX of USA.
Something like that?
val pattern = Seq("Modi", "Trump", "JUN")
val str = "Narendra Modi pm of india 2020-JUN-03 Donald Trump president of USA"
def mask(pattern: Seq[String], str: String): String = {
var s = str
for (elem <- pattern) {
s = s.replaceAll(elem,elem.toCharArray.map(s=>"X").mkString)
}
s
}
print(mask(pattern,str))
out:
Narendra XXXX pm of india 2020-XXX-03 Donald XXXXX president of USA
scala> val pattern = Seq("Narendra\\s*Modi", "Trump", "JUN-\\d\\d", "Trump", "JUN")
pattern: Seq[String] = List(Narendra\s*Modi, Trump, JUN-\d\d, Trump, JUN)
scala> print(mask(pattern,str))
XXXXXXXXXXXXXXX pm of india 2020-XXXXXXXX Donald XXXXX president of USA
Yeah, It should work, try like above.
Please find the regex and code explanation inline
import org.apache.spark.sql.functions._
object RegExMasking {
def main(args: Array[String]): Unit = {
val spark = Constant.getSparkSess
import spark.implicits._
//Regex to fetch the word
val regEx : String = """(\s+[A-Z|a-z]+\s)""".stripMargin
//load your Dataframe
val df = List("Narendra Modi pm of india 2020-JUN-03",
"Donald Trump president of USA ").toDF("sentence")
df.withColumn("valueToReplace",
//Fetch the 1st word from the regex parse expression
regexp_extract(col("sentence"),regEx,0)
)
.map(row => {
val sentence = row.getString(0)
//Trim for extra spaces
val valueToReplace : String = row.getString(1).trim
//Create masked string of equal length
val replaceWith = List.fill(valueToReplace.length)("X").mkString
// Return sentence , masked sentence
(sentence,sentence.replace(valueToReplace,replaceWith))
}).toDF("sentence","maskedSentence")
.show()
}
}

Doxygen command paragraph (hanging) indentation limitations?

Are there any limits for how much indentation can be used on multi-line (paragraph) commands?
Consider a typical use-case of #details in the context of a function:
/**
* #brief Do foo.
* #details Lorem ipsum dolor sit amet, mentitum rationibus nec an.
* Usu magna eirmod et, aperiri discere volumus pri ex.
*
* Te pro alii vidit, cu nonumes mediocritatem duo.
* Paulo detracto tincidunt id vim, ad has oblique percipit.
*
* #tparam T The argument type.
* #param param1 The first parameter.
* #param param2 The second parameter.
* #return The return value.
*/
template< typename T >
inline
T foo( T const& param1, T const& param2 );
The long #details paragraphs have to be wrapped, which leads to the question of are there any restrictions on this indentation?
I know that Doxygen uses Markdown, which has specific indentation restrictions / uses, such as the "4 space indentation" for codeblocks. Would the indentation above confuse or conflict in cases where I wanted to insert code?
More generally, are there other indentation uses and possible conflicts I'm unaware of?
#thomas-matthews, this is a question about technical limitations, not aesthetic style.
Very crude suggestion, but this is what worked for me -
/**
* #brief Do foo.
* #details Lorem ipsum dolor sit amet, mentitum rationibus nec an.
*
* Usu magna eirmod et, aperiri discere volumus pri ex.
*
* Te pro alii vidit, cu nonumes mediocritatem duo.
* Paulo detracto tincidunt id vim, ad has oblique percipit.
*
* #tparam T The argument type.
* #param param1 The first parameter.
* #param param2 The second parameter.
* #return The return value.
*/