Skip to content

Commit 10f993f

Browse files
Merge pull request #3 from cosbidev/v2.0.4
Update v2.0.4
2 parents 34c0ba5 + 2564f4d commit 10f993f

File tree

9 files changed

+73
-22
lines changed

9 files changed

+73
-22
lines changed

docs/source/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
author = 'Matteo Tortora'
2525

2626
# The full version, including alpha/beta/rc tags
27-
release = '2.0.3'
27+
release = '2.0.4'
2828

2929
# -- General configuration ---------------------------------------------------
3030

pytrack/analytics/visualization.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -211,11 +211,10 @@ def draw_candidates(self, candidates, radius):
211211
popup = f"coord: {cand} \n edge_osmid: {label}"
212212
if cand_type:
213213
folium.Circle(location=cand, popup=popup, radius=2, color="yellow", fill=True,
214-
fill_opacity=1).add_to(
215-
fg_cands)
214+
fill_opacity=1).add_to(fg_cands)
216215
else:
217-
folium.Circle(location=cand, popup=popup, radius=1, color="red", fill=True, fill_opacity=1).add_to(
218-
fg_cands)
216+
folium.Circle(location=cand, popup=popup, radius=1, color="orange", fill=True,
217+
fill_opacity=1).add_to(fg_cands)
219218

220219
del self._children[next(k for k in self._children.keys() if k.startswith('layer_control'))]
221220
self.add_child(folium.LayerControl())

pytrack/graph/download.py

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,27 +20,44 @@ def get_filters(network_type='drive'):
2020
'elevator|escalator|footway|path|pedestrian|planned|platform|proposed|raceway|steps|track"]'
2121
'["service"!~"emergency_access|parking|parking_aisle|private"]')
2222

23+
osm_filters['bicycle'] = ('["highway"]["area"!~"yes"]["access"!~"private"]'
24+
'["highway"!~"abandoned|bridleway|footway|bus_guideway|construction|corridor|elevator|'
25+
'escalator|planned|platform|proposed|raceway|steps|footway"]'
26+
'["service"!~"private"]["bicycle"!~"no"])')
27+
28+
osm_filters['service'] = ('["highway"]["area"!~"yes"]["access"!~"private"]["highway"!~"abandoned|bridleway|'
29+
'construction|corridor|platform|cycleway|elevator|escalator|footway|path|planned|'
30+
'proposed|raceway|steps|track"]["service"!~"emergency_access|parking|'
31+
'parking_aisle|private"]["psv"!~"no"]["footway"!~"yes"]')
32+
2333
return osm_filters[network_type]
2434

2535

26-
def osm_download(bbox, network_type=None):
36+
def osm_download(bbox, network_type='drive', custom_filter=None):
2737
""" Get the OpenStreetMap response.
2838
2939
Parameters
3040
----------
3141
bbox: tuple
3242
bounding box within N, S, E, W coordinates.
33-
network_type: str or None, optional, default: None
43+
network_type: str, optional, default: 'drive'
3444
Type of street network to obtain.
45+
custom_filter: str or None, optional, default: None
46+
Custom filter to be used instead of the predefined ones to query the Overpass API.
47+
An example of a custom filter is the following '[highway][!"footway"]'.
48+
For more information visit https://overpass-turbo.eu and https://taginfo.openstreetmap.org.
49+
3550
Returns
3651
-------
3752
response: json
3853
Response of the OpenStreetMao API service.
3954
"""
40-
# TODO: add network_type statement
4155
north, south, west, east = bbox
4256

43-
osm_filters = get_filters(network_type='drive')
57+
if custom_filter is not None:
58+
osm_filter = custom_filter
59+
else:
60+
osm_filter = get_filters(network_type=network_type)
4461

4562
url_endpoint = 'https://maps.mail.ru/osm/tools/overpass/api/interpreter'
4663

@@ -49,7 +66,7 @@ def osm_download(bbox, network_type=None):
4966

5067
overpass_settings = f'[out:{out_resp}][timeout:{timeout}]'
5168

52-
query_str = f'{overpass_settings};(way{osm_filters}({south}, {west}, {north}, {east});>;);out;'
69+
query_str = f'{overpass_settings};(way{osm_filter}({south}, {west}, {north}, {east});>;);out;'
5370

5471
response_json = requests.post(url_endpoint, data={'data': query_str})
5572

pytrack/graph/graph.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ def _simplification(G, response_json):
102102

103103
junction = [False, False]
104104
if is_oneway:
105-
junction[1:1] = [True if G.degree[node] > 3 else False for node in nodes[1:-1]]
105+
junction[1:1] = [True if G.degree[node] > 2 else False for node in nodes[1:-1]] # Changed >3 to >2 V2.0.4
106106
else:
107107
junction[1:1] = [True if G.degree[node] > 4 else False for node in nodes[1:-1]]
108108

@@ -259,7 +259,7 @@ def _oneway_path_values(path):
259259
ret: dict
260260
Indicates whether an OSM path is oneway.
261261
"""
262-
return {path[key] for key in path.keys() if key.startswith("oneway") and path[key] == "no"}
262+
return {path[key] for key in path.keys() if key.startswith("oneway")} # Removed 'and path[key] == "no"' v2.0.4
263263

264264

265265
def _is_oneway(path, bidirectional):

pytrack/matching/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# This lets you use package.module.Class as package.Class in your code.
2+
from .candidate import Candidate
3+
4+
# This lets Sphinx know you want to document package.module.Class as package.Class.
5+
__all__ = ['Candidate']

pytrack/matching/candidate.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,12 @@ def get_candidates(G, points, interp_dist=1, closest=True, radius=10):
105105
"candidate_type": np.full(len(nodes.index[idx]), False),
106106
"dists": list(dist)} for i, (point, idx, dist) in enumerate(zip(points, idxs, dists))}
107107

108+
no_cands = [node_id for node_id, cand in results.items() if not cand["candidates"]]
109+
110+
if no_cands:
111+
for cand in no_cands:
112+
del results[cand]
113+
print(f"A total of {len(no_cands)} points has no candidates: {*no_cands,}")
108114
return G, results
109115

110116

pytrack/matching/mpmatching.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from collections import deque
2+
import math
23

34
from . import mpmatching_utils
45

@@ -40,12 +41,12 @@ def viterbi_search(G, trellis, start="start", target="target", beta=mpmatching_u
4041
# Initialize joint probability for each node
4142
joint_prob = {}
4243
for u_name in trellis.nodes():
43-
joint_prob[u_name] = 0
44+
joint_prob[u_name] = -float('inf')
4445
predecessor = {}
4546
queue = deque()
4647

4748
queue.append(start)
48-
joint_prob[start] = mpmatching_utils.emission_prob(trellis.nodes[start]["candidate"], sigma)
49+
joint_prob[start] = math.log10(mpmatching_utils.emission_prob(trellis.nodes[start]["candidate"], sigma))
4950
predecessor[start] = None
5051

5152
while queue:
@@ -58,8 +59,11 @@ def viterbi_search(G, trellis, start="start", target="target", beta=mpmatching_u
5859
for v_name in trellis.successors(u_name):
5960
v = trellis.nodes[v_name]["candidate"]
6061

61-
new_prob = joint_prob[u_name] * mpmatching_utils.transition_prob(G, u, v, beta) * \
62-
mpmatching_utils.emission_prob(v, sigma)
62+
try:
63+
new_prob = joint_prob[u_name] + math.log10(mpmatching_utils.transition_prob(G, u, v, beta)) + \
64+
math.log10(mpmatching_utils.emission_prob(v, sigma))
65+
except Exception as e:
66+
print(e)
6367

6468
if joint_prob[v_name] < new_prob:
6569
joint_prob[v_name] = new_prob

pytrack/matching/mpmatching_utils.py

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,27 @@
88
from pytrack.matching import candidate
99

1010
SIGMA_Z = 4.07
11-
BETA = 20
11+
BETA = 3
12+
13+
14+
def _emission_prob(dist, sigma=SIGMA_Z):
15+
""" Compute emission probability of a node
16+
17+
Parameters
18+
----------
19+
dist: float
20+
Distance between a real GPS point and a candidate node.
21+
sigma: float, optional, default: SIGMA_Z
22+
It is an estimate of the magnitude of the GPS error. See https://www.ismll.uni-hildesheim.de/lehre/semSpatial-10s/script/6.pdf
23+
for a more detailed description of its calculation.
24+
25+
Returns
26+
-------
27+
ret: float
28+
Emission probability of a node.
29+
"""
30+
c = 1 / (sigma * math.sqrt(2 * math.pi))
31+
return c * math.exp(-(dist / sigma) ** 2)
1232

1333

1434
# A gaussian distribution
@@ -17,9 +37,9 @@ def emission_prob(u, sigma=SIGMA_Z):
1737
1838
Parameters
1939
----------
20-
u: dict
40+
u: pytrack.matching.Candidate
2141
Node of the graph.
22-
sigma: float
42+
sigma: float, optional, default: SIGMA_Z
2343
It is an estimate of the magnitude of the GPS error. See https://www.ismll.uni-hildesheim.de/lehre/semSpatial-10s/script/6.pdf
2444
for a more detailed description of its calculation.
2545
@@ -56,13 +76,13 @@ def transition_prob(G, u, v, beta=BETA):
5676
ret: float
5777
Transition probability between node u and v.
5878
"""
59-
c = 1 / BETA
79+
c = 1 / beta
6080

6181
if u.great_dist and v.great_dist:
6282
delta = abs(
6383
nx.shortest_path_length(G, u.node_id, v.node_id, weight="length", method='dijkstra')
6484
- distance.haversine_dist(*u.coord, *v.coord))
65-
return c * math.exp(-delta / BETA) * 1e5
85+
return c * math.exp(-delta / beta)
6686
else:
6787
return 1
6888

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ def reqs(*f):
1616

1717
setuptools.setup(
1818
name='PyTrack-lib',
19-
version='2.0.3',
19+
version='2.0.4',
2020
packages=setuptools.find_packages(),
2121
# namespace_packages=['pytrack'],
2222
url='https://github.com/cosbidev/PyTrack',

0 commit comments

Comments
 (0)