Folium - add larger pop ups with data from XML file - python

I would like to create a table-like pop-up for my folium map but don't know how to do it (I'm a novice).
My data comes from an XML file that contains the gps coordinates, name, sales, etc. of stores.
Right now I can display the name of the stores in the pop-up, but I would also like to display the sales and other information below the name.
I reckon I should maybe use GeoJson but I don't know how to implement it in the code I already have (which contains clusterization) :
xml_data = 'Data Stores.xml'
tree = ElementTree.parse(xml_data)
counter = tree.find('counter')
name = counter.find('Name')
counter.find('Latitude').text
name = []
latitude = []
longitude = []
for c in tree.findall('counter'):
name.append(c.find('Name').text)
latitude.append(c.find('Latitude').text)
longitude.append(c.find('Longitude').text)
df_counters = pd.DataFrame(
{'Name' : name,
'Latitude' : latitude,
'Longitude' : longitude,
})
df_counters.head()
locations = df_counters[['Latitude', 'Longitude']]
locationlist = locations.values.tolist()
map3 = folium.Map(location=[31.1893,121.2781], tiles='CartoDB positron', zoom_start=6)
marker_cluster = folium.plugins.MarkerCluster().add_to(map3)
for point in range(0, len(locationlist)):
popup=folium.Popup(df_counters['Name'][point], max_width=300,min_width=300)
folium.Marker(locationlist[point],
popup=popup,
icon=folium.Icon(color='blue', icon_color='white',
icon='fa-shopping-bag', angle=0, prefix='fa')
).add_to(marker_cluster)
map3.save("WorldMap.html")`
Right now I have 4 other columns in my XML file besides 'Name' that have the information that I want to appear in the popup as well, kinda like this :
example popup
Thank you for your help
Edit :
I did some digging and changed my code a little bit by adding the folium.features.GeoJsonPopup instead of the simple folium.Popup that I had before :
for point in range(0, len(locationlist)):
popup=folium.features.GeoJsonPopup(
fields=[['Name'],['Opening']],
aliases=['Name','Opening'])
folium.Marker(locationlist[point],
popup=popup,
icon=folium.Icon(color='blue', icon_color='white',
icon='fa-shopping-bag', angle=0, prefix='fa')
).add_to(marker_cluster)
I added the 'Opening' data, however I don't know how to transfer it into the pop up along with the 'Name' since it comes from a panda DataFrame. Right now my popups are empty.

I have done something similar, steps were:
create an IFrame with the content you want to display (coded in HTML)
use this IFrame in a popup
connect this popup with your marker
htmlstr = ... # Here you can add your table, use HTML
# 1. iframe
iframe = folium.IFrame(htmlstr, # places your content in the iframe
width=200,
height=200 # adjust size to your needs
)
# 2. popup
fpop = folium.Popup(iframe)
# 3. marker
mrk = folium.Marker(location=latlng,
popup=fpop,
)
mrk.add_to( ... )

Related

How to uploading duplicate tags at some picture for azure custom vision?

I have a question for azure custom vision. I have a custom vision project for object detection.
And I use the python SDK to create the project (see that: https://learn.microsoft.com/en-us/azure/cognitive-services/custom-vision-service/python-tutorial-od).
But I found something wrong in the process of uploading.
For example, there is a picture that has 3 persons in this picture. So I tag 3 same class “person” in this picture. But after uploading, I just found 1 "person" tagged in this picture at the custom vision website.
But the other class is fine, such as can also have "person", "car", and "scooter" at this picture. It looks like that can only have single same class at the picture.
I tried to use python SDK (see that: https://learn.microsoft.com/en-us/azure/cognitive-services/custom-vision-service/python-tutorial-od) to upload my picture and tag information.
A0_tag = trainer.create_tag(project.id, "A0")
A1_tag = trainer.create_tag(project.id, "A1")
A2_tag = trainer.create_tag(project.id, "A2")
A0_image_regions={
"0001.jpg":[0.432291667,0.28125,0.080729167,0.09765625],
"0001.jpg":[0.34765625,0.385742188,0.131510417,0.135742188],
"0001.jpg":[0.479166667,0.385742188,0.130208333,0.135742188],
"0003.jpg":[0.19921875,0.158203125,0.083333333,0.099609375]
}
The above code can see that I uploaded three "A0" class in 0001.jpg. But in the GUI interface on the website, I can only see that one "A0" class exists above 0001.jpg finally. Is there anything solution that can solve this problem?
Based on cthrash code. I made some changes to the code to make it work.
Here is the modified code:
A0_tag = trainer.create_tag(project.id, "TestA")
A1_tag = trainer.create_tag(project.id, "TestB")
A2_tag = trainer.create_tag(project.id, "TestC")
A0_image_regions = {
A0_tag.id : [
("2300.png",[0.787109375,0.079681275,0.068359375,0.876494024]),
("0920.png",[0.2109375,0.065737052,0.059570313,0.892430279]),
("0920.png",[0.291015625,0.061752988,0.05859375,0.894422311]),
]
}
A1_image_regions = {
A1_tag.id : [
("2000.png",[0.067382813,0.073705179,0.030273438,0.878486056]),
("2000.png",[0.126953125,0.075697211,0.030273438,0.878486056]),
("2000.png",[0.184570313,0.079681275,0.030273438,0.878486056]),
("2000.png",[0.232421875,0.079681275,0.030273438,0.878486056]),
],
}
A2_image_regions = {
A2_tag.id : [
("1400.png",[0.649414063,0.065737052,0.104492188,0.894422311]),
("2300.png",[0.602539063,0.061752988,0.106445313,0.892430279]),
("0920.png",[0.634765625,0.067729084,0.124023438,0.88247012]),
("0800.png",[0.579101563,0.06374502,0.04296875,0.888446215]),
],
}
regions_map = {}
for tag_id in A0_image_regions:
for filename,[x,y,w,h] in A0_image_regions[tag_id]:
regions = regions_map.get(filename,[])
regions.append(Region(tag_id=A0_tag.id, left=x, top=y, width=w, height=h))
regions_map[filename] = regions
for tag_id in A1_image_regions:
for filename,[x,y,w,h] in A1_image_regions[tag_id]:
regions = regions_map.get(filename,[])
regions.append(Region(tag_id=A1_tag.id, left=x, top=y, width=w, height=h))
regions_map[filename] = regions
for tag_id in A2_image_regions:
for filename,[x,y,w,h] in A2_image_regions[tag_id]:
regions = regions_map.get(filename,[])
regions.append(Region(tag_id=A2_tag.id, left=x, top=y, width=w, height=h))
regions_map[filename] = regions
tagged_images_with_regions = []
for filename in regions_map:
regions = regions_map[filename]
with open("<your path>" + filename, mode="rb") as image_contents:
tagged_images_with_regions.append(ImageFileCreateEntry(name=filename, contents=image_contents.read(), regions=regions))
upload_result = trainer.create_images_from_files(project.id, images=tagged_images_with_regions)
You've created A0_image_regions but are overriding the key whenever you have more than one bounding box for any given image. So that's not going to work.
But perhaps more importantly, you need to call the trainer with the image as the primary objects, with all the associated image regions lumped together. In other words, in you're example 0001.jpg has three instances of A0, but it may also have instances of A1 and/or A2, and this would neet to be a single ImageFile entry. So I'd modify the sample along the lines of the following:
A0_tag = trainer.create_tag(project.id, "A0")
A1_tag = trainer.create_tag(project.id, "A1")
A2_tag = trainer.create_tag(project.id, "A2")
image_regions = {
A0_tag.id : [
("0001.jpg", [0.432291667,0.28125,0.080729167,0.09765625]),
("0001.jpg", [0.34765625,0.385742188,0.131510417,0.135742188]),
("0001.jpg", [0.479166667,0.385742188,0.130208333,0.135742188]),
("0003.jpg", [0.19921875,0.158203125,0.083333333,0.099609375])
],
A1_tag.id : [] # add images/bounding boxes for A1
A2_tag.id : [] # add images/bounding boxes for A2
}
regions_map = {}
for tag_id in image_regions:
for filename,[x,y,w,h] in image_regions[tag_id]:
regions = regions_map.get(filename,[])
regions.append(Region(tag_id, left=x, top=y, width=w, height=h))
regions_map[filename] = regions
tagged_images_with_regions = []
for filename in regions_map:
regions = regions_map[filename]
with open(base_image_url + filename, mode="rb") as image_contents:
tagged_images_with_regions.append(ImageFileCreateEntry(name=filename, contents=image_contents.read(), regions=regions))
upload_result = trainer.create_images_from_files(project.id, images=tagged_images_with_regions)
It sounds like you want to mark only one tag person for 3 persons in a picture, but it's no sense, not an issue. Actually, the tag is marked to the picture, not to a pixel area shown a person in the picture.
Therefore, the tag person just helps to detect a fact there is one person at least after trained the model, not car or scooter. If you want to detect different person, the requires that you need to add three tags like person1, person2 and person3 for the three different persons in a picture.
Please refer to the wiki page Object detection and its reference links to know more details about the principle of machine learning and deep learning.
If you did not change anything else in the sample code, then it is trying to upload image "0.001.jpg" with the one bounding box three times, and the last two uploading fails, because they are duplicate images with your first uploaded image.
Please upload the "0.001.jpg" just once with three bounding boxes, or upload the image first and then the three boxes.

How to edit editable pdf using the pdfrw library?

I been doing research on how to edit PDF using Python and i have found this article:
How to Populate Fillable PDF's with Python
However there is a problem once the program runs and you open the PDF the document is not populated only when you click on the tags it shows the data and when you click away it disappears again. This is code that can be found online that someone else has written.
#! /usr/bin/python
import os
import pdfrw
INVOICE_TEMPLATE_PATH = 'invoice_template.pdf'
INVOICE_OUTPUT_PATH = 'invoice.pdf'
ANNOT_KEY = '/Annots'
ANNOT_FIELD_KEY = '/T'
ANNOT_VAL_KEY = '/V'
ANNOT_RECT_KEY = '/Rect'
SUBTYPE_KEY = '/Subtype'
WIDGET_SUBTYPE_KEY = '/Widget'
def write_fillable_pdf(input_pdf_path, output_pdf_path, data_dict):
template_pdf = pdfrw.PdfReader(input_pdf_path)
annotations = template_pdf.pages[0][ANNOT_KEY]
for annotation in annotations:
if annotation[SUBTYPE_KEY] == WIDGET_SUBTYPE_KEY:
if annotation[ANNOT_FIELD_KEY]:
key = annotation[ANNOT_FIELD_KEY][1:-1]
if key in data_dict.keys():
annotation.update(
pdfrw.PdfDict(V='{}'.format(data_dict[key]))
)
pdfrw.PdfWriter().write(output_pdf_path, template_pdf)
data_dict = {
'business_name_1': 'Bostata',
'customer_name': 'company.io',
'customer_email': 'joe#company.io',
'invoice_number': '102394',
'send_date': '2018-02-13',
'due_date': '2018-03-13',
'note_contents': 'Thank you for your business, Joe',
'item_1': 'Data consulting services',
'item_1_quantity': '10 hours',
'item_1_price': '$200/hr',
'item_1_amount': '$2000',
'subtotal': '$2000',
'tax': '0',
'discounts': '0',
'total': '$2000',
'business_name_2': 'Bostata LLC',
'business_email_address': 'hi#bostata.com',
'business_phone_number': '(617) 930-4294'
}
if __name__ == '__main__':
write_fillable_pdf(INVOICE_TEMPLATE_PATH, INVOICE_OUTPUT_PATH, data_dict)
I figure out that if you add NeedAppearances param you will solve your problem:
template_pdf = pdfrw.PdfReader(TEMPLATE_PATH)
template_pdf.Root.AcroForm.update(pdfrw.PdfDict(NeedAppearances=pdfrw.PdfObject('true')))
Updating the write function to have keys AP and V fixed the problem for me in preview
pdfrw.PdfDict(AP=data_dict[key], V=data_dict[key])
The error is because no appearance stream is associated with the field, but you've created it in a wrong way. You've just assigned and stream to AP dictionary. What you need to do is to assign an indirect Xobject to /N in /AP dictionary; and you need to crate Xobject from scratch.
The code should be something like the following:
from pdfrw import PdfWriter, PdfReader, IndirectPdfDict, PdfName, PdfDict
INVOICE_TEMPLATE_PATH = 'untitled.pdf'
INVOICE_OUTPUT_PATH = 'untitled-output.pdf'
field1value = 'im field_1 value'
template_pdf = PdfReader(INVOICE_TEMPLATE_PATH)
template_pdf.Root.AcroForm.Fields[0].V = field1value
#this depends on page orientation
rct = template_pdf.Root.AcroForm.Fields[0].Rect
hight = round(float(rct[3]) - float(rct[1]),2)
width =(round(float(rct[2]) - float(rct[0]),2)
#create Xobject
xobj = IndirectPdfDict(
BBox = [0, 0, width, hight],
FormType = 1,
Resources = PdfDict(ProcSet = [PdfName.PDF, PdfName.Text]),
Subtype = PdfName.Form,
Type = PdfName.XObject
)
#assign a stream to it
xobj.stream = '''/Tx BMC
BT
/Helvetica 8.0 Tf
1.0 5.0 Td
0 g
(''' + field1value + ''') Tj
ET EMC'''
#put all together
template_pdf.Root.AcroForm.Fields[0].AP = PdfDict(N = xobj)
#output to new file
PdfWriter().write(INVOICE_OUTPUT_PATH, template_pdf)
Note: FYI: /Type, /FormType, /Resorces are optional (/Resources is strongly recomended).
To expand on Sergio's answer above, the following line:
template_pdf.Root.AcroForm.update(pdfrw.PdfDict(NeedAppearances=pdfrw.PdfObject('true')))
Should be put after this line in the example code from OP:
template_pdf = pdfrw.PdfReader(input_pdf_path)
In case someone has dropdown fields on the form you want to populate with data you can use the code below. (Might save someone the hassle I went through)
if key in data_dict.keys():
#see if its a dropdown
if('/I' in annotation.keys()):
#field is a dropdown
#Check if value is in preset list of dropdown, and at what value
if data_dict[key] in annotation['/Opt']:
#Value is in dropdown list,select value from list
annotation.update(pdfrw.PdfDict(I='[{}]'.format(annotation['/Opt'].index(data_dict[key]))))
else:
#Value is not in dropdown list, add as 'free input'
annotation.update(pdfrw.PdfDict(I='{}'.format(None)))
annotation.update(pdfrw.PdfDict(V='{}'.format(data_dict[key])))
else:
#update the textfieldvalue
annotation.update(pdfrw.PdfDict(V='{}'.format(data_dict[key])))
also not that the OP code only works for the first page due to
template_pdf.pages[0]

Python Folium MarkerCluster Color Customization

I'm creating a leaflet map in folium using MarkerCluster. I have been all over the documentation and searched for examples, but I cannot figure out how to customize the color for a given MarkerCluster or FeatureGroup (e.g., one set in green rather than default blue).
I tried creating the markers individually and iteratively adding them to the MarkerCluster, and that gave me the color I wanted, but then the iFrame html table woudn't function properly, and the popups were not appearing.
The code I've written works flawlessly (an html table used for popups is not supplied), but I'd really like to be able to change the color for one set of markers and retain the popups using the methods in my code. Any guidance would be greatly appreciated!
or_map = folium.Map(location=OR_COORDINATES, zoom_start=8)
res_popups, res_locations = [], []
com_popups, com_locations = [], []
for idx, row in geo.iterrows():
if row['Type'] == 'Residential':
res_locations.append([row['geometry'].y, row['geometry'].x])
property_type = row['Type']
property_name = row['Name']
address = row['address']
total_units = row['Total Unit']
iframe = folium.IFrame(table(property_type, property_name,
address, total_units), width=width,
height=height)
res_popups.append(iframe)
else:
com_locations.append([row['geometry'].y, row['geometry'].x])
property_type = row['Type']
property_name = row['Name']
address = row['address']
total_units = row['Total Unit']
iframe = folium.IFrame(table(property_type, property_name, address,
total_units), width=width,
height=height)
com_popups.append(iframe)
r = folium.FeatureGroup(name='UCPM Residential Properties')
r.add_child(MarkerCluster(locations=res_locations, popups=res_popups))
or_map.add_child(r)
c = folium.FeatureGroup(name='UCPM Commercial Properties')
c.add_child(MarkerCluster(locations=com_locations, popups=com_popups))
or_map.add_child(c)
display(or_map)
Instead of just dumping all your locations into the Cluster, you could loop over them and create a Marker for each of them - that way you can set the Marker's color. After creation, you can add the Marker to the desired MarkerCluster.
for com_location, com_popup in zip(com_locations, com_popups):
folium.Marker(com_location,
popup=com_popup
icon=folium.Icon(color='red', icon='info-sign')
).add_to(cluster)
A different approach would be to modify the style function, as shown here (In[4] and In[5]).

Update dropdown based on selection of another dropdown in ipywidgets

I have a dropdown menu that shows soms posssible 'cycles'. These are actually .csv files containing some data. Then I have another dropdown that should show all the variables in this .csv file. So this second dropdown should update according to the file selected in the first dropdown. I found a similar
question and tried to implement this, but it did not work. The second dropdown remains empty. Note that I use pyspark to read the .csv files.
Cycles is a tuple containing all the .csv files in my working directory.
scW1 = widgets.Dropdown(description = 'Select file',options = cycles)
scW2 = widgets.Dropdown(description = 'Select variable')
def plotvar(sender):
df=sc.textFile(str(scW1.value)).map(lambda x: x.split(','))
header = tuple(df.first())
print(header)
with scW2.hold_trait_notifications():
scW2.options = header
display(scW1)
display(scW2)
What goes wrong?
Lol 4 years, but I've been looking for this...
from IPython.display import display
from ipywidgets import Dropdown
def dropdown_eventhandler(change):
determine(dropdown.value)
# print(change.new)
option_list = (1, 2)
dep_1 = (1, 1)
dep_2 = (2, 2)
def determine(x):
if x == 1:
dropdown_dep.options = dep_1
else:
dropdown_dep.options = dep_2
dropdown = Dropdown(description="Choose one:", options=option_list)
dropdown_dep = Dropdown(description="Choose one:")
dropdown.observe(dropdown_eventhandler, names='value')
display(dropdown, dropdown_dep)

Bokeh - get information about points that have been selected

I have a several points that I plot into scatter plot and show in web browser window (using Bokeh).
For selection, I use PolySelectTool or BoxSelectTool.
There are two things I would like to do:
1) Get information about points that have been selected in order to calculate some additional information.
2) As points represent URLs, I would like the chart to open a new browser tab and load a particular URL whenever I click a point (representing URL).
I don't think the code is important. But to make my question complete, here it is ...
Y = my_data
urls = get_urls(my_data)
TOOLS="pan,wheel_zoom,reset,hover,poly_select,box_select"
p = figure(title = "My chart", tools=TOOLS)
p.xaxis.axis_label = 'X'
p.yaxis.axis_label = 'Y'
source = ColumnDataSource(
data=dict(
xvals=list(Y[:,0]),
yvals=list(Y[:,1]),
url=urls
)
)
p.scatter("xvals", "yvals",source=source,fill_alpha=0.2, size=5)
hover = p.select(dict(type=HoverTool))
hover.snap_to_data = False
hover.tooltips = OrderedDict([
("(x,y)", "($x, $y)"),
("url", "#url"),
])
select_tool = p.select(dict(type=BoxSelectTool))
#
# I guess perhaps something should be done with select_tool
#
show(p)
You can get information with the source.selected property, if you want to be notified of every change you must create a callback, it would be something like this:
def callback(obj, attr, old, new):
...
source.on_change('selected', callback)
See this example for more details.

Categories