I am using the following code to extract the geolocation of an image taken with an iPhone:
from PIL import Image
from PIL.ExifTags import TAGS
def get_exif(fn):
ret = {}
i = Image.open(fn)
info = i._getexif()
for tag, value in info.items():
decoded = TAGS.get(tag, tag)
ret[decoded] = value
return ret
a = get_exif('photo2.jpg')
print a
This is the result that I am returned:
{
'YResolution': (4718592, 65536),
41986: 0,
41987: 0,
41990: 0,
'Make': 'Apple',
'Flash': 32,
'ResolutionUnit': 2,
'GPSInfo': {
1: 'N',
2: ((32, 1), (4571, 100), (0, 1)),
3: 'W',
4: ((117, 1), (878, 100), (0, 1)),
7: ((21, 1), (47, 1), (3712, 100))
},
'MeteringMode': 1,
'XResolution': (4718592, 65536),
'ExposureProgram': 2,
'ColorSpace': 1,
'ExifImageWidth': 1600,
'DateTimeDigitized': '2011:03:01 13:47:39',
'ApertureValue': (4281, 1441),
316: 'Mac OS X 10.6.6',
'SensingMethod': 2,
'FNumber': (14, 5),
'DateTimeOriginal': '2011:03:01 13:47:39',
'ComponentsConfiguration': '\x01\x02\x03\x00',
'ExifOffset': 254,
'ExifImageHeight': 1200,
'Model': 'iPhone 3G',
'DateTime': '2011:03:03 10:37:32',
'Software': 'QuickTime 7.6.6',
'Orientation': 1,
'FlashPixVersion': '0100',
'YCbCrPositioning': 1,
'ExifVersion': '0220'
}
So, I am wondering how I convert the GPSInfo values (DMS) to Decimal Degrees for actual coordinates? Also, there seems to be two Wests listed . . . ?
Here's a way to do it, adapted for a script I wrote some months ago using pyexiv2:
a = get_exif('photo2.jpg')
lat = [float(x)/float(y) for x, y in a['GPSInfo'][2]]
latref = a['GPSInfo'][1]
lon = [float(x)/float(y) for x, y in a['GPSInfo'][4]]
lonref = a['GPSInfo'][3]
lat = lat[0] + lat[1]/60 + lat[2]/3600
lon = lon[0] + lon[1]/60 + lon[2]/3600
if latref == 'S':
lat = -lat
if lonref == 'W':
lon = -lon
This gives me the following latitude and longitude for your picture: 32.7618333, -117.146333 (same results as Lance Lee).
The last entry of GPSInfo may be the heading of the picture. You could check this using a tool that gives proper names to the different EXIF values such as exiv2 or exiftools.
http://www.exiv2.org/tags.html
find the string 'Exif.GPSInfo.GPSLatitude' in that page.
It appears that you get 3 pairs (representing rationals) and the second number in the pair is the denominator.
I would expect the thing after Longitude to be altitude, however it is a better fit for GPS timestamp.
In this example:
32/1 + (4571 / 100)/60 + (0 / 1)/3600 = 32.761833 N
117/1 + (878 / 100)/60 + (0 / 1)/3600 = 117.146333 W
Was this picture taken near 4646 Park Blvd, San Diego, CA 92116? If not then ignore this answer.
Related
I am writing a small program to get the GPS info of a iphone jpg photo.
The library I am using is the PIL in python. Now I am able to get the GPSInfo, which is something like:
{1: 'N',
2: ((1, 1), (20, 1), (5365, 100)),
3: 'E',
4: ((103, 1), (41, 1), (1052, 100)),
5: 0,
6: (43, 1),
7: ((15, 1), (32, 1), (7, 1)),
16: 'T',
17: (77473, 452),
29: '2013:10:25'}
How can I interpret this? And I notice the tag is not continuous, so is there any cheating sheet which I can refer to in order to get a better understanding of all the number tags and what they mean? Thank you!
UPDATES
Sorry, I have figured it out. In the PIL lib, there is a GPSTAGS.get() function which can help me decode the key in gps info. Thank you guys!
gpsinfo = {}
for key in exif['GPSInfo'].keys():
decode = ExifTags.GPSTAGS.get(key,key)
gpsinfo[decode] = exif['GPSInfo'][key]
print gpsinfo
and here is the result
{'GPSTimeStamp': ((15, 1), (32, 1), (7, 1)),
'GPSImgDirectionRef': 'T',
'GPSImgDirection': (77473, 452),
'GPSLongitude': ((103, 1), (41, 1), (1052, 100)),
'GPSLatitudeRef': 'N', 29: '2013:10:25',
'GPSAltitude': (43, 1),
'GPSLatitude': ((1, 1), (20, 1), (5365, 100)),
'GPSLongitudeRef': 'E',
'GPSAltitudeRef': 0}
Use exifread module.
Here is a very helpful gist
import exifread as ef
# barrowed from
# https://gist.github.com/snakeye/fdc372dbf11370fe29eb
def _convert_to_degress(value):
"""
Helper function to convert the GPS coordinates stored in the EXIF to degress in float format
:param value:
:type value: exifread.utils.Ratio
:rtype: float
"""
d = float(value.values[0].num) / float(value.values[0].den)
m = float(value.values[1].num) / float(value.values[1].den)
s = float(value.values[2].num) / float(value.values[2].den)
return d + (m / 60.0) + (s / 3600.0)
def getGPS(filepath):
'''
returns gps data if present other wise returns empty dictionary
'''
with open(filepath, 'rb') as f:
tags = ef.process_file(f)
latitude = tags.get('GPS GPSLatitude')
latitude_ref = tags.get('GPS GPSLatitudeRef')
longitude = tags.get('GPS GPSLongitude')
longitude_ref = tags.get('GPS GPSLongitudeRef')
if latitude:
lat_value = _convert_to_degress(latitude)
if latitude_ref.values != 'N':
lat_value = -lat_value
else:
return {}
if longitude:
lon_value = _convert_to_degress(longitude)
if longitude_ref.values != 'E':
lon_value = -lon_value
else:
return {}
return {'latitude': lat_value, 'longitude': lon_value}
return {}
file_path = 'file path of the file'
gps = getGPS(file_path)
print gps
Late answer, but as of 2022 you can use GPSPhoto, i.e.:
from GPSPhoto import gpsphoto
# Get the data from image file and return a dictionary
data = gpsphoto.getGPSData('IMG_20181224_201933.jpg')
print(data['Latitude'], data['Longitude'])
Output:
38.71615498471598 -9.148730635643007
Installation:
pip3 install piexif
pip3 install gpsphoto
OP, has already posted a solution using PIL. If you wants to just get GPS info from Python, you can get it by using exifread
Install package using pip
$ pip install exifread
and get GPS data
In [10]: import exifread
In [11]: tags = exifread.process_file(open('./tests/demo-project/content/test.jpg', 'rb'))
In [12]: geo = {i:tags[i] for i in tags.keys() if i.startswith('GPS')}
In [13]: geo
Out[13]:
{'GPS GPSAltitude': (0x0006) Ratio=186188/239 # 898,
'GPS GPSAltitudeRef': (0x0005) Byte=0 # 722,
'GPS GPSDate': (0x001D) ASCII=2015:12:06 # 954,
'GPS GPSDestBearing': (0x0018) Ratio=43771/526 # 946,
'GPS GPSDestBearingRef': (0x0017) ASCII=T # 806,
'GPS GPSImgDirection': (0x0011) Ratio=43771/526 # 938,
'GPS GPSImgDirectionRef': (0x0010) ASCII=T # 782,
'GPS GPSLatitude': (0x0002) Ratio=[46, 3803/100, 0] # 850,
'GPS GPSLatitudeRef': (0x0001) ASCII=N # 674,
'GPS GPSLongitude': (0x0004) Ratio=[13, 2429/100, 0] # 874,
'GPS GPSLongitudeRef': (0x0003) ASCII=E # 698,
'GPS GPSSpeed': (0x000D) Ratio=139/50 # 930,
'GPS GPSSpeedRef': (0x000C) ASCII=K # 758,
'GPS GPSTimeStamp': (0x0007) Ratio=[10, 37, 33] # 906,
'GPS Tag 0x001F': (0x001F) Ratio=30 # 966}
I have a hard time formatting my csv files in a way easy to process in a pandas dataframe. I am using this https://figshare.com/articles/UMA_ADL_FALL_Dataset_zip/4214283 dataset of fall data to train a RNN model to detect people falling but the formatting is quite hard to clean up with the python csv reader and even with a more intelligent module clevercsv.
this is the code to itterate over the files and merge them into a Dataframe:
import pandas as pd
import zipfile
import clevercsv as csv
csv_list = []
directory = r"C:\Users\20191678\OneDrive - TU Eindhoven\Engineering Design"
for filename in os.listdir(directory):
if '.csv' in filename:
with open(filename, "r", newline="") as fp:
dialect = csv.Sniffer().sniff(fp.read(), verbose=True)
fp.seek(0)
reader = csv.reader(fp, dialect)
rows = list(reader)
csv_list.append(rows)
df = pd.DataFrame(csv_list)
Would be great if anyone can take the time to solve this and make a structured dataframe! Or come up with another idea of cleaning this up.
The csv file code itself:
% Universidad de Malaga - ETSI de Telecomunicacion (Spain)
% Date: 2017-04-14_23:38:23
% ID: Subject_01_ADL_Aplausing_1
% Name: Subject_01
% Age: 67
% Height(cm): 156
% Weight(Kg): 76
% Gender: F
% Type of Movement: ADL
% Type of Movement: FALSE
% Description of the movement: Aplausing
% Trial: 1
% Number of Sensors: 5
% Used Smartphone: LGE-lge-LG-H815-5.1
% Smartphone's Accelerometer: LGE Accelerometer - Vendor: BOSCH
% --> Version: 1
% --> Min - Max Delay: 5000us - 65535000us
% --> Maximum Range: 16.000000263891405 G
% --> Resolution: 1.2136514986004396E-4 G
% SensorTag's Accelerometer: MPU-9250 MEMS MotionTracking Device - Invensense
% --> Maximum Range: 16 G
% --> Resolution: 0.00024 G
% MAC Address; Sensor_ID; Position; Device Model
%f8:95:c7:f3:ba:82; 0; RIGHTPOCKET; lge-LG-H815-5.1
%C4:BE:84:71:A5:02; 2; WAIST; SensorTag
%C4:BE:84:70:0E:80; 3; WRIST; SensorTag
%B0:B4:48:B8:77:03; 4; ANKLE; SensorTag
%C4:BE:84:70:64:8A; 1; CHEST; SensorTag
% Sensor_Type:
% Accelerometer = 0
% Gyroscope = 1
% Magnetometer = 2
% TimeStamp; Sample No; X-Axis; Y-Axis; Z-Axis; Sensor Type; Sensor ID;
102;1;-0.1387496441602707;0.8868721723556519;0.3310287296772003;0;0
102;2;-0.1381397247314453;0.8865065574645996;0.3323715031147003;0;0
102;3;-0.1348443180322647;0.8895576596260071;0.3311501145362854;0;0
102;4;-0.1402153074741364;0.8866279125213623;0.3337142467498779;0;0
102;5;-0.1391168385744095;0.8862622380256653;0.3345684409141541;0;0
102;6;-0.138628289103508;0.8871164321899414;0.3346897959709168;0;0
102;7;-0.1367969810962677;0.8880935311317444;0.3412821888923645;0;0
102;8;-0.138628289103508;0.8883378505706787;0.3398165106773377;0;0
102;9;-0.1409481465816498;0.8901675939559937;0.3401837050914764;0;0
102;10;-0.1418023407459259;0.8891920447349548;0.3418920934200287;0;0
102;11;-0.1430221647024155;0.8882149457931519;0.3420134484767914;0;0
103;12;-0.143510714173317;0.8880935311317444;0.3422577381134033;0;0
103;13;-0.1439992785453796;0.8838210105895996;0.3379867672920227;0;0
103;14;-0.1431450843811035;0.8795484900474548;0.3353012502193451;0;0
103;15;-0.1438763588666916;0.8766187429428101;0.3331027626991272;0;0
103;16;-0.1429008096456528;0.8790599703788757;0.3321272134780884;0;0
103;17;-0.142656534910202;0.8779615163803101;0.3343241512775421;0;0
103;18;-0.1409481465816498;0.8801584243774414;0.3348127007484436;0;0
103;19;-0.1429008096456528;0.8816241025924683;0.3376195728778839;0;0
103;20;-0.1457076668739319;0.8821110725402832;0.3385966718196869;0;0
109;21;-0.1441206336021423;0.8832111358642578;0.3412821888923645;0;0
115;22;-0.1387496441602707;0.8832111358642578;0.3404279947280884;0;0
115;23;-0.1391168385744095;0.8822340369224548;0.3404279947280884;0;0
121;24;-0.1375298053026199;0.8843095898628235;0.3399394154548645;0;0
126;25;-0.1369199007749558;0.8868721723556519;0.337375283241272;0;0
133;26;-0.1375298053026199;0.8854080438613892;0.331394374370575;0;0
Something like this should get you going.
from pprint import pprint
def try_number(s):
try:
if "." in s:
return float(s)
return int(s, 10)
except ValueError:
return s
def read_umafall(fp):
header_lines = []
metadata = {}
data = []
for line in fp:
line = line.strip()
if line.startswith("%"):
if ": " in line:
key, _, value = line[1:].partition(": ")
metadata[key.strip()] = value
else:
header_lines.append(line)
elif ";" in line:
data.append([try_number(c) for c in line.split(";")])
elif line:
print("???", line)
return {
"header_lines": header_lines,
"metadata": metadata,
"data": data,
}
with open(
"UMAFall_Subject_01_ADL_HandsUp_2_2017-04-14_23-33-21.csv",
"r",
) as fp:
result = read_umafall(fp)
pprint(result["metadata"])
pprint(result["header_lines"])
pprint(result["data"][:10])
The output is e.g.
{'--> Maximum Range': '16 G',
'--> Min - Max Delay': '5000us - 65535000us',
'--> Resolution': '0.00024 G',
'--> Version': '1',
'Age': '67',
'Date': '2017-04-14_23:33:21',
'Description of the movement': 'HandsUp',
'Gender': 'F',
'Height(cm)': '156',
'ID': 'Subject_01_ADL_HandsUp_2',
'Name': 'Subject_01',
'Number of Sensors': '5',
"SensorTag's Accelerometer": 'MPU-9250 MEMS MotionTracking Device - '
'Invensense',
"Smartphone's Accelerometer": 'LGE Accelerometer - Vendor: BOSCH',
'Trial': '2',
'Type of Movement': 'FALSE',
'Used Smartphone': 'LGE-lge-LG-H815-5.1',
'Weight(Kg)': '76'}
['% Universidad de Malaga - ETSI de Telecomunicacion (Spain)',
'% MAC Address; Sensor_ID; Position; Device Model',
'%f8:95:c7:f3:ba:82; 0; RIGHTPOCKET; lge-LG-H815-5.1',
'%C4:BE:84:71:A5:02; 2; WAIST; SensorTag',
'%C4:BE:84:70:0E:80; 3; WRIST; SensorTag',
'%B0:B4:48:B8:77:03; 4; ANKLE; SensorTag',
'%C4:BE:84:70:64:8A; 1; CHEST; SensorTag',
'% Sensor_Type:',
'% Accelerometer = 0',
'% Gyroscope = 1',
'% Magnetometer = 2',
'% TimeStamp; Sample No; X-Axis; Y-Axis; Z-Axis; Sensor Type; Sensor ID;']
[[371, 1, -0.01265575457364321, 0.9133599400520325, -0.1938552260398865, 0, 0],
[371, 2, -0.01839394308626652, 0.9126286506652832, -0.1926354020833969, 0, 0],
[371, 3, -0.01802674867212772, 0.9129943251609802, -0.1948323398828507, 0, 0],
[371, 4, -0.02352065965533257, 0.9167782664299011, -0.1969063729047775, 0, 0],
[371, 5, -0.02315346524119377, 0.9209294319152832, -0.2019117176532745, 0, 0],
[371, 6, -0.01888094283640385, 0.9211721420288086, -0.203375831246376, 0, 0],
[371, 7, -0.0208351630717516, 0.9270316958427429, -0.2050857692956924, 0, 0],
[371, 8, -0.01924813725054264, 0.9303271174430847, -0.2070384472608566, 0, 0],
[371, 9, -0.01766111142933369, 0.9342340230941772, -0.2080155462026596, 0, 0],
[371, 10, -0.01265575457364321, 0.9388721585273743, -0.2115552425384522, 0, 0]]
```,
that is
* first the header lines that could be parsed as key-value pairs
* other header lines
* the data
You can hopefully trust each file to have the data in the same order (`TimeStamp; Sample No; X-Axis; Y-Axis; Z-Axis; Sensor Type; Sensor ID`).
I am trying to modify the fuzzywuzzy library. The module process returns the score and the array element. But I want it to return the index of the element along with the group of score,item,index.
Here is what I tried:
#!/usr/bin/env python
# encoding: utf-8
from fuzzywuzzy import fuzz
from fuzzywuzzy import utils
import heapq
import logging
from functools import partial
default_scorer = fuzz.WRatio
default_processor = utils.full_process
def extractWithoutOrder(query, choices, processor=default_processor, scorer=default_scorer, score_cutoff=0):
def no_process(x):
return x
try:
if choices is None or len(choices) == 0:
raise StopIteration
except TypeError:
pass
if processor is None:
processor = no_process
processed_query = processor(query)
if len(processed_query) == 0:
logging.warning(u"Applied processor reduces input query to empty string, "
"all comparisons will have score 0. "
"[Query: \'{0}\']".format(query))
# Don't run full_process twice
if scorer in [fuzz.WRatio, fuzz.QRatio,
fuzz.token_set_ratio, fuzz.token_sort_ratio,
fuzz.partial_token_set_ratio, fuzz.partial_token_sort_ratio,
fuzz.UWRatio, fuzz.UQRatio] \
and processor == utils.full_process:
processor = no_process
# Only process the query once instead of for every choice
if scorer in [fuzz.UWRatio, fuzz.UQRatio]:
pre_processor = partial(utils.full_process, force_ascii=False)
scorer = partial(scorer, full_process=False)
elif scorer in [fuzz.WRatio, fuzz.QRatio,
fuzz.token_set_ratio, fuzz.token_sort_ratio,
fuzz.partial_token_set_ratio, fuzz.partial_token_sort_ratio]:
pre_processor = partial(utils.full_process, force_ascii=True)
scorer = partial(scorer, full_process=False)
else:
pre_processor = no_process
processed_query = pre_processor(processed_query)
count = -1
try:
# See if choices is a dictionary-like object.
for key, choice in choices.items():
count = count + 1
processed = pre_processor(processor(choice))
score = scorer(processed_query, processed)
if score >= score_cutoff:
yield (choice, score, key,count)
except AttributeError:
# It's a list; just iterate over it.
for choice in choices:
count = count + 1
processed = pre_processor(processor(choice))
score = scorer(processed_query, processed)
if score >= score_cutoff:
yield (choice, score,count)
def extract(query, choices, processor=default_processor, scorer=default_scorer, limit=5):
sl = extractWithoutOrder(query, choices, processor, scorer)
return heapq.nlargest(limit, sl, key=lambda i: i[1]) if limit is not None else \
sorted(sl, key=lambda i: i[1], reverse=True)
When I tried to implement it, the result was what it was previously showing by fuzzywuzzy.
import process as p
box=['ness', 'apple','banana','carrot','duck','eagle','fish','gate','hitler']
p.extract('b',box)
[('banana', 90), ('apple', 0), ('carrot', 0), ('duck', 0), ('eagle', 0)]
But what I am expecting it to return is:
[('banana', 90, 2), ('apple', 0, 1), ('carrot', 0, 3), ('duck', 0, 4), ('eagle', 0, 5)]
Kindly let me know the suggestion.
As an alternative to FuzzyWuzzy you could use RapidFuzz (I am the author) which will return the index as well:
from rapidfuzz import process
box=['ness', 'apple','banana','carrot','duck','eagle','fish','gate','hitler']
p.extract('b',box)
which returns
[('banana', 90, 2), ('apple', 0, 1), ('carrot', 0, 3), ('duck', 0, 4), ('eagle', 0, 5)]
For those looking for the answer, can pass a dictionary to the process.
from fuzzywuzzy import fuzz
from fuzzywuzzy import process
box = ['apple','banana','carrot','duck','eagle']
box_dict = {i: val for i, val in enumerate(box)}
process.extract("b", box_dict, scorer=fuzz.WRatio)
# O/P -> [("banana", 90, 1), ('apple', 0, 0), ('carrot', 0, 2), ('duck', 0, 3), ('eagle', 0, 4)]
import json, os
def load_data(filepath):
if not os.path.exists(filepath):
return None
with open(filepath, 'r') as file:
return json.load(file)
def get_biggest_bar(data):
bars = []
for bar in data:
bars.append((bar['Cells']['SeatsCount'] , bar['Number']))
max_number = max(bars)[1]
(item for item in data if item['Number'] == max_number).__next__()
return item, max_number
def get_smallest_bar(data):
bars = []
for bar in data:
bars.append((bar['Cells']['SeatsCount'] , bar['Number']))
min_number = min(bars)[1]
(item for item in data if item['Number'] == min_number).__next__()
return item, min_number
def get_closest_bar(data, longitude, latitude):
coordinates = []
def get_distance(point, input_point):
return ((longitude-input_point[0])**2 + (latitude - input_point[1])**2)**1/2
for cell in data:
coordinates.append([cell['Cells']['geoData']['coordinates'],cell['Number']])
for coor in coordinates:
coor[0] = get_distance(point, coor[0])
closest_bar = min(coordinates)[1]
(item for item in data if item['Number'] == closest_bar).__next__()
return item, closest_bar
if __name__ == '__main__':
data = load_data("Bars.json")
print(get_smallest_bar(data))
print(get_biggest_bar(data))
print(get_closest_bar(data, 50.0, 50.0))
And it's output is:
(dict_values(['Семёновский переулок, дом 21', 'нет', 'район Соколиная Гора', 'Восточный административный округ', 'да', 177, {'type': 'Point', 'coordinates': [37.717115000077776, 55.78262800012168]}, 'СПБ', 272459722, [{'PublicPhone': '(916) 223-32-98'}], 'SПБ']), 37)
(dict_values(['Семёновский переулок, дом 21', 'нет', 'район Соколиная Гора', 'Восточный административный округ', 'да', 177, {'type': 'Point', 'coordinates': [37.717115000077776, 55.78262800012168]}, 'СПБ', 272459722, [{'PublicPhone': '(916) 223-32-98'}], 'SПБ']), 434)
(dict_values(['Семёновский переулок, дом 21', 'нет', 'район Соколиная Гора', 'Восточный административный округ', 'да', 177, {'type': 'Point', 'coordinates': [37.717115000077776, 55.78262800012168]}, 'СПБ', 272459722, [{'PublicPhone': '(916) 223-32-98'}], 'SПБ']), 170)
As you see, items are COMPLETLY identical, but they are diffrent(I tried to devide functions and run them seperatly, and they output diffrent items)! Also, you can see the second number in the fucntion's returns - they are diffrent! Whats the matter?!
You are using a generator to get item, but on the next line that variable is not what you think it is. Item from inside the generator is out of scope. I would prefer to return the actual generated value. Also, you are getting the closest bar to some point, but not the one you passed into the function.
Thus I think item and point are both global variables that you are using by mistake inside your functions.
I have python2.7, so the syntax to get the next value from the generator may be slightly different.
def load_data(filepath):
data = [
{'Number': 10, 'Cells': {'SeatsCount': 10, 'geoData': {'coordinates': (10, 10)}}},
{'Number': 50, 'Cells': {'SeatsCount': 50, 'geoData': {'coordinates': (50, 50)}}},
{'Number': 90, 'Cells': {'SeatsCount': 90, 'geoData': {'coordinates': (90, 90)}}}
]
return data
def get_biggest_bar(data):
bars = []
for bar in data:
bars.append((bar['Cells']['SeatsCount'] , bar['Number']))
max_number = max(bars)[1]
g = (item for item in data if item['Number'] == max_number)
return next(g), max_number
def get_smallest_bar(data):
bars = []
for bar in data:
bars.append((bar['Cells']['SeatsCount'] , bar['Number']))
min_number = min(bars)[1]
g = (item for item in data if item['Number'] == min_number)
return next(g), min_number
def get_closest_bar(data, longitude, latitude):
point = (longitude, latitude)
coordinates = []
def get_distance(point, input_point):
return ((longitude-input_point[0])**2 + (latitude - input_point[1])**2)**1/2
for cell in data:
coordinates.append([cell['Cells']['geoData']['coordinates'],cell['Number']])
for coor in coordinates:
coor[0] = get_distance(point, coor[0])
closest_bar = min(coordinates)[1]
g = (item for item in data if item['Number'] == closest_bar)
return next(g), closest_bar
if __name__ == '__main__':
data = load_data("Bars.json")
print("smallest", get_smallest_bar(data))
print("biggest", get_biggest_bar(data))
print("closest", get_closest_bar(data, 50.0, 50.0))
Output:
('smallest', ({'Cells': {'geoData': {'coordinates': (10, 10)}, 'SeatsCount': 10}, 'Number': 10}, 10))
('biggest', ({'Cells': {'geoData': {'coordinates': (90, 90)}, 'SeatsCount': 90}, 'Number': 90}, 90))
('closest', ({'Cells': {'geoData': {'coordinates': (50, 50)}, 'SeatsCount': 50}, 'Number': 50}, 50))
Assign the result of the call to __next__() before returning it, like this:
result = (item for item in data if item['Number'] == closest_bar).__next__()
return result, closest_bar
Answers what went wrong have been given. Im my opinion the code searching for min and max was not "pythonic". I'd like to suggest another approach:
(Using sample data from Kenny Ostrom's answer)
data = [ {'Number': 10, 'Cells': {'SeatsCount': 10, 'geoData': {'coordinates': (10, 10)}}},
{'Number': 50, 'Cells': {'SeatsCount': 50, 'geoData': {'coordinates': (50, 50)}}},
{'Number': 90, 'Cells': {'SeatsCount': 90, 'geoData': {'coordinates': (90, 90)}}} ]
biggest = max(data, key=lambda bar: bar['Cells']['SeatsCount'])
smallest = min(data, key=lambda bar: bar['Cells']['SeatsCount'])
for the closest bar a simple custom key function based on the get_distance from the original code is required, but you got the idea.
I have this code in views.py:
def pins_info(request):
if request.method == "GET":
getpin = request.GET.get('pin', None)
m = ButuanMaps.objects.filter(clandpin=getpin).
values_list('landproperty__ctaxdec')
n = ButuanMaps.objects.filter(clandpin=getpin).
values_list('ssectionid__sbrgyid__cbrgyname')
return HttpResponse(json.dumps({'taxdec': list(m),'brgy': list(n)}),
content_type='application/json')
I works fine, but it is not that effective when I want to get other values. I can access the result in my template like this:
success: function(data) {
taxdec = data['taxdec'];
brgy = data['brgy'];
var inputform = $('#forminput').val();
if( inputform == "Select Land PIN") {
alert('Please Select Land PIN')
}
else{
$('#status').append(
"<p>Tax Declaration: " + taxdec + "<br/>Barangay: " + brgy + "</p>"
);
}
}
How can I simplify my code to make it more effective like:
m = ButuanMaps.objects.filter(clandpin=getpin).
values_list('landproperty__ctaxdec','ssectionid__sbrgyid__cbrgyname')
But how do I pass it to my template?
If we take your m and n queries as:
m = range(5)
n = range(6, 11)
Then your single query of m = ButuanMaps.objects.filter(clandpin=getpin). values_list('landproperty__ctaxdec','ssectionid__sbrgyid__cbrgyname') is equivalent to the structure of:
new = zip(m, n)
#[(0, 6), (1, 7), (2, 8), (3, 9), (4, 10)]
So you can "transpose" that:
zip(*new)
# [(0, 1, 2, 3, 4), (6, 7, 8, 9, 10)]
Then build a dict from that and your keys:
results = dict(zip(['taxdec', 'brgy'], zip(*new))))
# {'brgy': (6, 7, 8, 9, 10), 'taxdec': (0, 1, 2, 3, 4)}
Then json.dumps results.
Or use an OrderedDict for your JSON name and column names values and generalise further:
from collections import OrderedDict
keyvals = OrderedDict([
('taxdec','landproperty__ctaxdec'),
('brgy', 'ssectionid__sbrgyid__cbrgyname')
])
m = ButuanMaps.objects.filter(clandpin=getpin).values_list(*keyvals.values())
result = dict(zip(keyvals, zip(*m)))
That way, you can add/remove columns to be selected and their associated JSON values in one place for the same query.