Display bug when label contain a expression - python-3.x

I have this function who supposed to change the label of polygon (code below), where "nom_com" and "statutpro" are fields in a layer.
def ETIQUETAGE(self):
layer = self.COUCHE_DEPARTEMENT_SELECTIONNEE() #return a vector layer
deco = QgsPalLayerSettings()
deco.enabled = True
isExpression = True
if self.ChoixEtiquetage.currentText() == "COMMUNE":
deco.fieldName = '\'nom :\' +"nom_com"'
if self.ChoixEtiquetage.currentText() == "COMMUNE ET STATUT PROSPECTION":
deco.fieldName = '"nom_com" + \'\\n\' +"statutpro"'
labeler = QgsVectorLayerSimpleLabeling(deco)
layer.setLabeling(labeler)
layer.setLabelsEnabled(True)
layer.triggerRepaint()
When I run it everything ok (i don't have any error), the problem is for the display. The function change the label charateristic in the properties window but there is no display until I press aply in the properties window.
When I put only one argument the display work perfectly. for example
deco.fieldName = "nom_com"
Is there a particular syntax when it's a expression ?

I just see where my error was, it was a syntaxe error.
If the label is expression based we must put
deco.isExpression
for the plugin to display something in the canvas
def ETIQUETAGE(self):
layer = self.COUCHE_DEPARTEMENT_SELECTIONNEE() #return a vector layer
deco = QgsPalLayerSettings()
deco.enabled = True
deco.isExpression = True
if self.ChoixEtiquetage.currentText() == "COMMUNE":
deco.fieldName = "concat('nom : ', nom_com)"
if self.ChoixEtiquetage.currentText() == "COMMUNE ET STATUT PROSPECTION":
deco.fieldName = "concat('nom : ', nom_com, '\\n', 'Statut prospection : ', statutpro)"'
labeler = QgsVectorLayerSimpleLabeling(deco)
layer.setLabeling(labeler)
layer.setLabelsEnabled(True)
layer.triggerRepaint()
hope it will help people

Related

Can't get the text from LineEdit to pass to a function

Context:
I click on a button -> a WindowDialogue appears -> there are 2 LineEdit Nodes and a button
Supposed procedure:
I fill these LineEdits, press the button, and the function tied to the button receives the texts from the LineEdits (and creates a dictionary key-value pair).
Problem:
The texts from the LineEdits do not pass down to the function (through connect()).
I tried passing the text directly with LineEdit.text. I tried writing it in a different variable and passing the variable. The debug shows the function is getting executed (no problem with that), but the strings passed from the LineEdits are always empty. Somehow, it worked for some time when I explicitly pressed ENTER after filling the LineEdits. But after I tried to fix the aforementioned problem, it stopped working altogether.
P.S. Everything I mentioned is created dynamically through the code, if that matters.
Code:
#Declaring the variables
var temp_text_key = ""
var temp_text_value = ""
#Function to show up a dialogue window with LineEdits and Confirm button
func _on_add_new_property(dict: Dictionary):
temporal_window_dialogue = WindowDialog.new()
temporal_window_dialogue.rect_min_size = Vector2(410,90)
temporal_window_dialogue.resizable = true
temporal_window_dialogue.popup_exclusive = true
temporal_window_dialogue.window_title = "Adding new property to %s" % get_dict_name_by_id(professions, dict["id"])
var le_key = LineEdit.new()
le_key.placeholder_text = "Name of the property"
le_key.hint_tooltip = "Name of the property"
le_key.connect("text_changed", self, "_on_add_new_prop_text_entered", ["key"])
var le_value = LineEdit.new()
le_value.expand_to_text_length = true
le_value.placeholder_text = "Value of the property"
le_value.set("custom_constants/minimum_spaces", 36)
le_value.hint_tooltip = "Value of the property"
le_value.connect("text_changed", self, "_on_add_new_prop_text_entered", ["value"])
var lab = Label.new()
lab.text = "Should the Value become a Dictionary?"
var check_bt = CheckBox.new()
var vbox = VBoxContainer.new()
var grid_container = GridContainer.new()
grid_container.columns = 2
var accept_bt = Button.new()
accept_bt.text = "Confirm"
temporal_window_dialogue.add_child(vbox)
vbox.add_child(grid_container)
grid_container.add_child(le_key)
grid_container.add_child(le_value)
grid_container.add_child(lab)
grid_container.add_child(check_bt)
vbox.add_child(accept_bt)
grid_container.set("custom_constants/vseparation", 5)
grid_container.set("custom_constants/hseparation", 5)
check_bt.connect("pressed", self, "_on_check_dict_pressed")
popup_window.add_child(temporal_window_dialogue)
temporal_window_dialogue.connect("popup_hide", self, "_on_close_specific_codegenerated_popup", [temporal_window_dialogue])
temporal_window_dialogue.popup_centered()
accept_bt.connect("pressed", self, "_on_add_new_property_confirmation", [dict, temp_text_key, temp_text_value])
#Function to create a new key/value pair in a dictionary
func _on_add_new_property_confirmation(dict: Dictionary, prop_name: String, prop_value: String):
if prop_name == "" or prop_value == "":
send_message_to_console("Neither of the two can be empty", 3)
return
if add_dictionary_flag:
dict[prop_name] = {
prop_value: {
"id": get_free_local_id_for_dict(dict)
}
}
elif !add_dictionary_flag:
if keywords_for_dictionaries.has(prop_name):
send_message_to_console("Only Dictionary items can become %s" % prop_name)
dict[prop_name] = prop_value
temp_text_key = ""
temp_text_value = ""
#Optional function to write the text from LineEdits to the variables
func _on_add_new_prop_text_entered(new_text, key_or_value):
if key_or_value == "key":
temp_text_key = new_text
elif key_or_value == "value":
temp_text_value = new_text
You mentioned using 'LineEdit.text', but have you tried the following?
var text = LineEdit.get_text()
If this doesn't help, please update your original post to include code examples.

Validate WTF Flask Form Input Values

I have the following form in my flask app. I'd like to ensure that the input value is actually an integer and also if the value entered in token > k here k can be some number it spits an error message to the screen. The IntegerField doesn't seem to enforce integer values, e.g., if the user enters 2.3 it passes that to my function which fails because it expects an integer.
Can this type of error message happen in the form or do I need to program that inside my flask app once the value is passed from the form to the server?
class Form(FlaskForm):
token = IntegerField('Token Size', [DataRequired()], default = 2)
submit = SubmitField('Submit')
EDIT
Per the comment below, updating this with my revised Form and the route
class Form(FlaskForm):
token = IntegerField('Token Size', validators=[DataRequired(), NumberRange(min=1, max=10, message='Something')], default = 2)
ngram_method = SelectField('Method', [DataRequired()],
choices=[('sliding', 'Sliding Window Method'),
('adjacent', 'Adjacent Text Method')])
rem_stop = BooleanField('Remove Stop Words', render_kw={'checked': True})
rem_punc = BooleanField('Remove Punctuation', default = True)
text2use = SelectField('Text To Use for Word Tree', [DataRequired()],
choices=[('clean', 'Clean/Processed Text'),
('original', 'Original Text String')])
pivot_word = TextField('Pivot Word for Word Tree', [DataRequired()])
submit = SubmitField('Submit')
And the route in which the form is used
#word_analyzer.route('/text', methods=('GET', 'POST'))
def text_analysis():
form = Form()
result = '<table></table>'
ngrams = '<table></table>'
orig_text = '<table></table>'
text = ""
if request.method == 'POST':
tmp_filename = tempfile.gettempdir()+'\\input.txt'
if request.files:
txt_upload = request.files.get('text_file')
if txt_upload:
f = request.files['text_file']
f.save(tmp_filename)
if os.path.exists(tmp_filename):
file = open(tmp_filename, 'r', encoding="utf8")
theText = [line.rstrip('\n') for line in file]
theText = str(theText)
token_size = form.token.data
stops = form.rem_stop.data
punc = form.rem_punc.data
ngram_method = form.ngram_method.data
text_result = text_analyzer(theText, token_size = token_size, remove_stop = stops, remove_punctuation = punc, method = ngram_method)
result = pd.DataFrame.from_dict(text_result, orient='index', columns = ['Results'])[:-3].to_html(classes='table table-striped table-hover', header = "true", justify = "center")
ngrams = pd.DataFrame.from_dict(text_result['ngrams'], orient='index', columns = ['Frequency']).to_html(classes='table table-striped table-hover', header = "true", justify = "center")
if form.pivot_word.data == None:
top_word = json.dumps(text_result['Top Word'])
else:
top_word = json.dumps(form.pivot_word.data)
if form.text2use.data == 'original':
text = json.dumps(text_result['original_text'])
else:
text = json.dumps(text_result['clean_text'])
if form.validate_on_submit():
return render_template('text.html', results = [result], ngrams = [ngrams], form = form, text=text, top_word = top_word)
return render_template('text.html', form = form, results = [result],ngrams = [ngrams], text=text, top_word='')
Use the NumberRange validator from wtforms.validators.NumberRange. You can pass an optional Min and Max value along with the error message. More info here
Update
# Form Class
class Form(FlaskForm):
token = FloatField('Token Size', validators=[DataRequired(), NumberRange(min=1, max=10, message='Something')])
# Route
if form.validate_on_submit():
print(form.name.data)
Here is an example that should work, make sure your form class field looks similar and also that in your route you use form.validate_on_submit():.

Why doesn't my font.name property affect the fonts on ppt made using Python-pptx? I always get arial font

So I'm trying to write some program to convert html to pptx using Python.
I'm using some code to parse through the file and then format text at run level.
I am using 2 textframes on a blank slide to work, the first textframe is used for title and 2nd one is used for rendering the body of html.
But no matter what I do (Paragraph.font.name or run.font.name), I am always getting Arial font in my 2nd textframe.
I've tried to update the fontnames by looping over tf.paragraphs and also by looping over all runs (paragraph.runs) nothing seems to work.
Here is my function which I use for setting the font
def setFont(font,tags,fontStyle,size):
font.language_id = MSO_LANGUAGE_ID.HEBREW
font.size = Pt(size)
font.name = fontStyle
for tag in tags:
if tag == 'b':
font.bold = True
elif tag == 'i':
font.italic = True
elif tag == 'u':
font.underline = True
return font
and here is my main calling function (I've removed some other calls which are not directly related to python-pptx)
def makeSlide(prs,title,body,fontStyle,titleSize,bodySize):
#Add title Slide
blank_slide_layout = prs.slide_layouts[6]
slide = prs.slides.add_slide(blank_slide_layout)
width = height = Inches(8)
txBox = slide.shapes.add_textbox(Inches(1), Inches(0.5), Inches(8), Inches(1))
tf = txBox.text_frame
tf.text = title
tf.paragraphs[0].font.size=Pt(titleSize)
tf.paragraphs[0].font.bold = True
tf.paragraphs[0].font.color.rgb = RGBColor(255,0,0)
tf.paragraphs[0].font.name = fontStyle
tf.paragraphs[0].alignment = PP_ALIGN.CENTER
styles = MY_CUSTOM_HTML_BODY_PARSER() #Removed this part from here, its just a parser which gives output in a desired format
#Start 2nd textbox for body
txBox2 = slide.shapes.add_textbox(Inches(0.5), Inches(1.7), Inches(9), Inches(5.5))
tf = txBox2.text_frame
tf.clear()
tf.word_wrap = True
tf.paragraphs[0].text = ''
tf.paragraphs[0].font.name = fontStyle
paragraph = tf.add_paragraph()
paragraph.alignment = alignment
#Loop over styles (Tag info and render pptx accordingly)
new_line = True
level = 0
number = 0
for _ in styles:
#Can ignore this part, I'm just checking to see if I have to go on a new line or not
if _ == '\n':
paragraph = tf.add_paragraph()
paragraph.alignment = alignment
new_line = True
else:
tags = _[1]
#Can also ignore this, I'm checking to see if I have to be on next level in lists or not
#(I use custom bullet function, since python-pptx doesn't have a function for numbered bullets.
if _[1].count('ul') > 1 or _[1].count('ol') > 1 or _[1].count('ul') + _[1].count('ol') > 1:
level = 1
if new_line:
paragraph.level = level
level = 0
else:
paragraph = tf.add_paragraph()
paragraph.alignment = alignment
paragraph.level = level
level = 0
new_line = True
if new_line:
run = paragraph.add_run()
#Custom bullet function as u can see I send in fontStyle here and apply style inside function
run,number = addBullets(run,tags,bodySize-3,number,fontStyle)
new_line = False
run = paragraph.add_run()
run.text = parser.words_styles[_[0]][0]
font = run.font
#SetFont function Defined above
font = setFont(font,tags,fontStyle,bodySize)
new_line = False
for paragraph in tf.paragraphs:
paragraph.font.name = fontStyle
for run in paragraph.runs:
if run.font.name != fontStyle:
print(run.text)
#return slide
return slide
I'm not quite sure where I am doing wrong, would appreciate any help, I can clean up code more if that's needed.

Assign Class attributes from list elements

I'm not sure if the title accurately describes what I'm trying to do. I have a Python3.x script that I wrote that will issue flood warning to my facebook page when the river near my home has reached it's lowest flood stage. Right now the script works, however it only reports data from one measuring station. I would like to be able to process the data from all of the stations in my county (total of 5), so I was thinking that maybe a class method may do the trick but I'm not sure how to implement it. I've been teaching myself Python since January and feel pretty comfortable with the language for the most part, and while I have a good idea of how to build a class object I'm not sure how my flow chart should look. Here is the code now:
#!/usr/bin/env python3
'''
Facebook Flood Warning Alert System - this script will post a notification to
to Facebook whenever the Sabine River # Hawkins reaches flood stage (22.3')
'''
import requests
import facebook
from lxml import html
graph = facebook.GraphAPI(access_token='My_Access_Token')
river_url = 'http://water.weather.gov/ahps2/river.php?wfo=SHV&wfoid=18715&riverid=203413&pt%5B%5D=147710&allpoints=143204%2C147710%2C141425%2C144668%2C141750%2C141658%2C141942%2C143491%2C144810%2C143165%2C145368&data%5B%5D=obs'
ref_url = 'http://water.weather.gov/ahps2/river.php?wfo=SHV&wfoid=18715&riverid=203413&pt%5B%5D=147710&allpoints=143204%2C147710%2C141425%2C144668%2C141750%2C141658%2C141942%2C143491%2C144810%2C143165%2C145368&data%5B%5D=all'
def checkflood():
r = requests.get(river_url)
tree = html.fromstring(r.content)
stage = ''.join(tree.xpath('//div[#class="stage_stage_flow"]//text()'))
warn = ''.join(tree.xpath('//div[#class="current_warns_statmnts_ads"]/text()'))
stage_l = stage.split()
level = float(stage_l[2])
#check if we're at flood level
if level < 22.5:
pass
elif level == 37:
major_diff = level - 23.0
major_r = ('The Sabine River near Hawkins, Tx has reached [Major Flood Stage]: #', stage_l[2], 'Ft. ', str(round(major_diff, 2)), ' Ft. \n Please click the link for more information.\n\n Current Warnings and Alerts:\n ', warn)
major_p = ''.join(major_r)
graph.put_object(parent_object='me', connection_name='feed', message = major_p, link = ref_url)
<--snip-->
checkflood()
Each station has different 5 different catagories for flood stage: Action, Flood, Moderate, Major, each different depths per station. So for Sabine river in Hawkins it will be Action - 22', Flood - 24', Moderate - 28', Major - 32'. For the other statinos those depths are different. So I know that I'll have to start out with something like:
class River:
def __init__(self, id, stage):
self.id = id #station ID
self.stage = stage #river level'
#staticmethod
def check_flood(stage):
if stage < 22.5:
pass
elif stage.....
but from there I'm not sure what to do. Where should it be added in(to?) the code, should I write a class to handle the Facebook postings as well, is this even something that needs a class method to handle, is there any way to clean this up for efficiency? I'm not looking for anyone to write this up for me, but some tips and pointers would sure be helpful. Thanks everyone!
EDIT Here is what I figured out and is working:
class River:
name = ""
stage = ""
action = ""
flood = ""
mod = ""
major = ""
warn = ""
def checkflood(self):
if float(self.stage) < float(self.action):
pass
elif float(self.stage) >= float(self.major):
<--snip-->
mineola = River()
mineola.name = stations[0]
mineola.stage = stages[0]
mineola.action = "13.5"
mineola.flood = "14.0"
mineola.mod = "18.0"
mineola.major = "21.0"
mineola.alert = warn[0]
hawkins = River()
hawkins.name = stations[1]
hawkins.stage = stages[1]
hawkins.action = "22.5"
hawkins.flood = "23.0"
hawkins.mod = "32.0"
hawkins.major = "37.0"
hawkins.alert = warn[1]
<--snip-->
So from here I'm tring to stick all the individual river blocks into one block. What I have tried so far is this:
class River:
... name = ""
... stage = ""
... def testcheck(self):
... return self.name, self.stage
...
>>> for n in range(num_river):
... stations[n] = River()
... stations[n].name = stations[n]
... stations[n].stage = stages[n]
...
>>> for n in range(num_river):
... stations[n].testcheck()
...
<__main__.River object at 0x7fbea469bc50> 4.13
<__main__.River object at 0x7fbea46b4748> 20.76
<__main__.River object at 0x7fbea46b4320> 22.13
<__main__.River object at 0x7fbea46b4898> 16.08
So this doesn't give me the printed results that I was expecting. How can I return the string instead of the object? Will I be able to define the Class variables in this manner or will I have to list them out individually? Thanks again!
After reading many, many, many articles and tutorials on class objects I was able to come up with a solution for creating the objects using list elements.
class River():
def __init__(self, river, stage, flood, action):
self.river = river
self.stage = stage
self.action = action
self.flood = flood
self.action = action
def alerts(self):
if float(self.stage < self.flood):
#alert = "The %s is below Flood Stage (%sFt) # %s Ft. \n" % (self.river, self.flood, self.stage)
pass
elif float(self.stage > self.flood):
alert = "The %s has reached Flood Stage(%sFt) # %sFt. Warnings: %s \n" % (self.river, self.flood, self.stage, self.action)
return alert
'''this is the function that I was trying to create
to build the class objects automagically'''
def riverlist():
river_list = []
for n in range(len(rivers)):
station = River(river[n], stages[n], floods[n], warns[n])
river_list.append(station)
return river_list
if __name__ == '__main__':
for x in riverlist():
print(x.alerts())

PyQt4 QTextCursor change selectable character

How can I change the selectable characters of a QTextCursor, like adding a dot?
For example entering "MyClass" in a QPlainTextEdit the stanza
tc = self.textCursor()
tc.select(QtGui.QTextCursor.WordUnderCursor)
return tc.selectedText()
will returns "MyClass", but entering "MyClass." will returns an empty Qstring!
The problem continues, entering "MyClass.myMeth" will just returns "myMeth", but I need "MyClass.myMeth" :/
Thanks
Ok, I find a solution by replacing the call to WordUnderCursor by :
def textUnderCursor(self):
tc = self.textCursor()
isStartOfWord = False
if tc.atStart() or (tc.positionInBlock() == 0):
isStartOfWord = True
while not isStartOfWord:
tc.movePosition(QtGui.QTextCursor.PreviousCharacter, QtGui.QTextCursor.KeepAnchor)
if tc.atStart() or (tc.positionInBlock() == 0):
isStartOfWord = True
elif QtCore.QChar(tc.selectedText()[0]).isSpace():
isStartOfWord = True
return tc.selectedText().trimmed()

Resources