Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
D
df-aggregator
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Oleksandr Barabash
df-aggregator
Commits
bde56baa
Commit
bde56baa
authored
Nov 05, 2020
by
Corey Koval
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'webui'
parents
a8bfae97
00bf94e5
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
392 additions
and
38 deletions
+392
-38
.gitignore
.gitignore
+1
-0
README.md
README.md
+2
-0
df-aggregator.py
df-aggregator.py
+142
-38
style.css
static/style.css
+166
-0
cesium.tpl
views/cesium.tpl
+49
-0
index.tpl
views/index.tpl
+32
-0
No files found.
.gitignore
View file @
bde56baa
...
...
@@ -6,3 +6,4 @@ CesiumJS/
test*
*.db
*.txt
*.czml
README.md
View file @
bde56baa
...
...
@@ -4,6 +4,8 @@
-
[
numpy
](
https://numpy.org/install/
)
-
[
scikit-learn
](
https://scikit-learn.org/stable/install.html
)
-
[
python-geojson
](
https://python-geojson.readthedocs.io/en/latest/
)
-
[
czml3
](
https://pypi.org/project/czml3/
)
-
[
geojson
](
https://pypi.org/project/geojson/
)
## Usage: df-aggregator.py [options]
...
...
df-aggregator.py
View file @
bde56baa
...
...
@@ -5,12 +5,17 @@ import numpy as np
import
math
import
time
import
sqlite3
import
threading
import
signal
from
optparse
import
OptionParser
from
os
import
system
,
name
from
os
import
system
,
name
,
kill
,
getpid
from
lxml
import
etree
from
sklearn.cluster
import
DBSCAN
from
sklearn.preprocessing
import
StandardScaler
from
geojson
import
Point
,
MultiPoint
,
Feature
,
FeatureCollection
from
czml3
import
Packet
,
Document
,
Preamble
from
bottle
import
route
,
run
,
request
,
get
,
post
,
redirect
,
template
,
static_file
d
=
40000
#meters
...
...
@@ -65,7 +70,6 @@ class receiver:
confidence
=
0
doa_time
=
0
def
plot_polar
(
lat_a
,
lon_a
,
lat_a2
,
lon_a2
):
# Convert points in great circle 1, degrees to radians
p1_lat1_rad
=
math
.
radians
(
lat_a
)
...
...
@@ -133,14 +137,14 @@ def process_data(database_name, outfile, eps, min_samp):
c
.
execute
(
"SELECT COUNT(*) FROM intersects"
)
n_intersects
=
int
(
c
.
fetchone
()[
0
])
#print(n_intersects)
c
.
execute
(
"SELECT latitude, longitude FROM intersects"
)
c
.
execute
(
"SELECT latitude, longitude
, num_parents
FROM intersects"
)
intersect_array
=
np
.
array
(
c
.
fetchall
())
# print(intersect_array)
likely_location
=
[]
best_point
=
[]
weighted_location
=
[]
if
intersect_array
.
size
!=
0
:
if
eps
>
0
:
X
=
StandardScaler
()
.
fit_transform
(
intersect_array
)
X
=
StandardScaler
()
.
fit_transform
(
intersect_array
[:,
0
:
2
]
)
# Compute DBSCAN
db
=
DBSCAN
(
eps
=
eps
,
min_samples
=
min_samp
)
.
fit
(
X
)
...
...
@@ -149,59 +153,154 @@ def process_data(database_name, outfile, eps, min_samp):
labels
=
db
.
labels_
intersect_array
=
np
.
column_stack
((
intersect_array
,
labels
))
# print(intersect_array)
# Number of clusters in labels, ignoring noise if present.
n_clusters_
=
len
(
set
(
labels
))
-
(
1
if
-
1
in
labels
else
0
)
n_noise_
=
list
(
labels
)
.
count
(
-
1
)
clear
()
clear
(
debugging
)
print
(
'Number of clusters:
%
d'
%
n_clusters_
)
print
(
'Outliers Removed:
%
d'
%
n_noise_
)
# print(intersect_array)
for
x
in
range
(
n_clusters_
):
cluster
=
np
.
array
([])
.
reshape
(
0
,
2
)
cluster
=
np
.
array
([])
.
reshape
(
0
,
3
)
for
y
in
range
(
len
(
intersect_array
)):
if
intersect_array
[
y
][
2
]
==
x
:
cluster
=
np
.
concatenate
((
cluster
,
[
intersect_array
[
y
][
0
:
2
]]),
axis
=
0
)
likely_location
.
append
(
Reverse
(
np
.
mean
(
cluster
,
axis
=
0
)
.
tolist
()
))
best_point
=
Feature
(
properties
=
best_pt_style
,
geometry
=
MultiPoint
(
tuple
(
likely_location
)
))
if
intersect_array
[
y
][
-
1
]
==
x
:
cluster
=
np
.
concatenate
((
cluster
,
[
intersect_array
[
y
][
0
:
-
1
]]),
axis
=
0
)
weighted_location
.
append
(
np
.
average
(
cluster
[:,
0
:
2
],
weights
=
cluster
[:,
2
],
axis
=
0
)
.
tolist
(
))
likely_location
.
append
(
np
.
mean
(
cluster
[:,
0
:
2
],
axis
=
0
)
.
tolist
(
))
for
x
in
likely_location
:
print
(
Reverse
(
x
))
print
(
x
)
else
:
likely_location
=
None
for
x
in
intersect_array
:
try
:
if
x
[
2
]
>=
0
:
if
x
[
-
1
]
>=
0
:
intersect_list
.
append
(
Reverse
(
x
[
0
:
2
]
.
tolist
()))
except
IndexError
:
intersect_list
.
append
(
Reverse
(
x
.
tolist
()))
#print(intersect_list)
all_the_points
=
Feature
(
properties
=
all_pt_style
,
geometry
=
MultiPoint
(
tuple
(
intersect_list
)))
#
all_the_points = Feature(properties = all_pt_style, geometry = MultiPoint(tuple(intersect_list)))
with
open
(
outfile
,
"w"
)
as
file1
:
if
eps
>
0
:
return
likely_location
,
intersect_list
,
weighted_location
else
:
print
(
"No Intersections."
)
return
None
def
write_geojson
(
best_point
,
all_the_points
):
if
all_the_points
!=
None
:
all_the_points
=
Feature
(
properties
=
all_pt_style
,
geometry
=
MultiPoint
(
tuple
(
all_the_points
)))
with
open
(
geofile
,
"w"
)
as
file1
:
if
best_point
!=
None
:
best_point
=
Feature
(
properties
=
best_pt_style
,
geometry
=
MultiPoint
(
tuple
(
best_point
)))
file1
.
write
(
str
(
FeatureCollection
([
best_point
,
all_the_points
])))
else
:
file1
.
write
(
str
(
FeatureCollection
([
all_the_points
])))
print
(
f
"Wrote file {geofile}"
)
else
:
print
(
"No Intersections."
)
def
write_czml
(
best_point
,
all_the_points
,
weighted_point
):
print
(
best_point
)
point_properties
=
{
"pixelSize"
:
5.0
,
"heightReference"
:
"RELATIVE_TO_GROUND"
,
"color"
:
{
"rgba"
:
[
255
,
0
,
0
,
255
],
}
}
best_point_properties
=
{
"pixelSize"
:
20.0
,
"heightReference"
:
"RELATIVE_TO_GROUND"
,
"color"
:
{
"rgba"
:
[
0
,
255
,
0
,
255
],
}
}
weighted_properties
=
{
"pixelSize"
:
20.0
,
"heightReference"
:
"RELATIVE_TO_GROUND"
,
"color"
:
{
"rgba"
:
[
0
,
0
,
255
,
255
],
}
}
top
=
Preamble
(
name
=
"Geolocation Data"
)
all_point_packets
=
[]
best_point_packets
=
[]
weighted_point_packets
=
[]
if
all_the_points
!=
None
:
for
x
in
all_the_points
:
all_point_packets
.
append
(
Packet
(
id
=
str
(
x
[
1
])
+
", "
+
str
(
x
[
0
]),
point
=
point_properties
,
position
=
{
"cartographicDegrees"
:
[
x
[
0
],
x
[
1
],
5
]}))
if
best_point
!=
None
:
for
x
in
best_point
:
best_point_packets
.
append
(
Packet
(
id
=
str
(
x
[
0
])
+
", "
+
str
(
x
[
1
]),
point
=
best_point_properties
,
position
=
{
"cartographicDegrees"
:
[
x
[
1
],
x
[
0
],
15
]}))
if
weighted_point
!=
None
:
for
x
in
weighted_point
:
weighted_point_packets
.
append
(
Packet
(
id
=
str
(
x
[
0
])
+
", "
+
str
(
x
[
1
]),
point
=
weighted_properties
,
position
=
{
"cartographicDegrees"
:
[
x
[
1
],
x
[
0
],
15
]}))
with
open
(
"static/output.czml"
,
"w"
)
as
file1
:
if
best_point
and
weighted_point
!=
None
:
file1
.
write
(
str
(
Document
([
top
]
+
best_point_packets
+
weighted_point_packets
+
all_point_packets
)))
elif
best_point
!=
None
:
file1
.
write
(
str
(
Document
([
top
]
+
best_point_packets
+
all_point_packets
)))
else
:
file1
.
write
(
str
(
Document
([
top
]
+
all_point_packets
)))
def
Reverse
(
lst
):
lst
.
reverse
()
return
lst
def
clear
():
def
clear
(
debugging
):
if
not
debugging
:
# for windows
if
name
==
'nt'
:
_
=
system
(
'cls'
)
# for mac and linux(here, os.name is 'posix')
else
:
_
=
system
(
'clear'
)
if
name
==
'nt'
:
_
=
system
(
'cls'
)
# for mac and linux(here, os.name is 'posix')
else
:
_
=
system
(
'clear'
)
with
open
(
'accesstoken.txt'
,
"r"
)
as
tokenfile
:
access_token
=
tokenfile
.
read
()
.
replace
(
'
\n
'
,
''
)
@route
(
'/static/<filepath:path>'
,
name
=
'static'
)
def
server_static
(
filepath
):
return
static_file
(
filepath
,
root
=
'./static'
)
@get
(
'/'
)
@get
(
'/index'
)
@get
(
'/cesium'
)
def
cesium
():
write_czml
(
*
process_data
(
database_name
,
geofile
,
eps
,
min_samp
))
return
template
(
'cesium.tpl'
,
{
'access_token'
:
access_token
,
'epsilon'
:
eps
*
100
})
@post
(
'/'
)
@post
(
'/index'
)
@post
(
'/cesium'
)
def
update_cesium
():
global
eps
eps
=
float
(
request
.
forms
.
get
(
'epsilonValue'
))
/
100
print
(
eps
)
return
redirect
(
'cesium'
)
def
start_server
(
ipaddr
=
"127.0.0.1"
):
run
(
host
=
ipaddr
,
port
=
8080
,
quiet
=
True
,
debug
=
False
,
server
=
'paste'
)
if
__name__
==
'__main__'
:
# ipaddr = "127.0.0.1"
web
=
threading
.
Thread
(
target
=
start_server
,)
web
.
daemon
=
True
web
.
start
()
usage
=
"usage:
%
prog [options]"
parser
=
OptionParser
(
usage
=
usage
)
parser
.
add_option
(
"-g"
,
"--geofile"
,
dest
=
"geofile"
,
help
=
"GeoJSON Output File"
,
metavar
=
"FILE"
)
...
...
@@ -217,6 +316,8 @@ if __name__ == '__main__':
metavar
=
"Number"
,
type
=
"int"
,
default
=
20
)
parser
.
add_option
(
"--dist-from-reference"
,
dest
=
"mdfr"
,
help
=
"Max distance in km from intersection with strongest signal."
,
metavar
=
"Number"
,
type
=
"int"
,
default
=
500
)
parser
.
add_option
(
"--debugging"
,
dest
=
"debugging"
,
help
=
"Does not clear the screen. Useful for seeing errors and warnings."
,
action
=
"store_true"
)
(
options
,
args
)
=
parser
.
parse_args
()
mandatories
=
[
'geofile'
,
'rx_file'
,
'database_name'
]
...
...
@@ -234,13 +335,14 @@ if __name__ == '__main__':
min_power
=
options
.
pwr
max_dist_from_ref
=
options
.
mdfr
min_samp
=
options
.
minsamp
debugging
=
False
if
not
options
.
debugging
else
True
try
:
clear
()
clear
(
debugging
)
dots
=
0
conn
=
sqlite3
.
connect
(
database_name
)
c
=
conn
.
cursor
()
c
.
execute
(
"CREATE TABLE IF NOT EXISTS intersects (time INTEGER, latitude REAL, longitude REAL)"
)
c
.
execute
(
"CREATE TABLE IF NOT EXISTS intersects (time INTEGER, latitude REAL, longitude REAL
, num_parents INTEGER
)"
)
receivers
=
[]
with
open
(
rx_file
,
"r"
)
as
file2
:
...
...
@@ -254,8 +356,11 @@ if __name__ == '__main__':
receiving
=
True
while
receiving
:
print
(
"Receiving"
+
dots
*
'.'
)
print
(
"Press Control+C to process data and exit."
)
if
not
debugging
:
print
(
"Receiving"
+
dots
*
'.'
)
print
(
"Press Control+C to process data and exit."
)
intersect_list
=
np
.
array
([])
.
reshape
(
0
,
3
)
for
x
in
range
(
len
(
receivers
)):
for
y
in
range
(
x
):
...
...
@@ -295,9 +400,9 @@ if __name__ == '__main__':
# print("Deleted Bad Intersection")
avg_coord
=
np
.
mean
(
intersect_list
,
axis
=
0
)
to_table
=
[
receivers
[
x
]
.
doa_time
,
avg_coord
[
0
],
avg_coord
[
1
]]
to_table
=
[
receivers
[
x
]
.
doa_time
,
avg_coord
[
0
],
avg_coord
[
1
]
,
len
(
intersect_list
)
]
# print(to_table)
c
.
execute
(
"INSERT INTO intersects VALUES (?,?,?)"
,
to_table
)
c
.
execute
(
"INSERT INTO intersects VALUES (?,?,?
,?
)"
,
to_table
)
conn
.
commit
()
for
rx
in
receivers
:
...
...
@@ -307,13 +412,12 @@ if __name__ == '__main__':
dots
=
1
else
:
dots
+=
1
clear
()
clear
(
debugging
)
except
KeyboardInterrupt
:
clear
(
)
print
(
"Processing, please wait."
)
# clear(debugging
)
#
print("Processing, please wait.")
conn
.
commit
()
conn
.
close
()
process_data
(
database_name
,
geofile
,
eps
,
min_samp
)
quit
()
#write_geojson(*process_data(database_name, geofile, eps, min_samp)[:2])
kill
(
getpid
(),
signal
.
SIGTERM
)
static/style.css
0 → 100644
View file @
bde56baa
body
{
font-size
:
12pt
;
font-family
:
'Courier New'
,
Courier
,
monospace
;
background-color
:
#ecebeb
;
}
input
{
margin
:
3px
;
}
h1
,
h2
,
h3
,
h4
{
margin-top
:
10px
;
margin-bottom
:
5px
;
}
p
,
ul
{
margin-top
:
5px
;
margin-bottom
:
5px
;
}
span
{
display
:
inline-block
;
}
.header
{
list-style-type
:
none
;
margin
:
0
;
padding
:
0
;
overflow
:
hidden
;
background-color
:
#333
;
}
/*.header li:last-child {
border-right: none;
border-left: 1px solid #bbb;
}*/
/* Change the link color to #111 (black) on hover */
.header
a
:hover
{
background-color
:
#111
;
}
.active
{
background-color
:
#4CAF50
;
}
.header
{
font-size
:
18pt
;
font-family
:
'Courier New'
,
Courier
,
monospace
;
}
.main_text
{
width
:
80%
;
float
:
left
;
padding
:
10px
;
}
.navbar
{
overflow
:
hidden
;
background-color
:
#333
;
}
/*.header a {
display: block;
}*/
.navbar
a
{
float
:
left
;
font-size
:
18px
;
color
:
white
;
text-align
:
center
;
padding
:
17px
16px
;
text-decoration
:
none
;
border-left
:
1px
solid
#bbb
;
}
/* Dropdown Button */
.dropbtn
{
background-color
:
#333
;
color
:
white
;
padding
:
16px
;
font-size
:
18px
;
border
:
none
;
border-left
:
1px
solid
#bbb
;
font-family
:
'Courier New'
,
Courier
,
monospace
;
}
/* The container <div> - needed to position the dropdown content */
.dropdown
{
/*position: relative;*/
display
:
inline-block
;
}
/* Dropdown Content (Hidden by Default) */
.dropdown-content
{
display
:
none
;
position
:
absolute
;
background-color
:
#e4e1e1
;
box-shadow
:
0px
8px
16px
0px
rgba
(
0
,
0
,
0
,
0.2
);
z-index
:
1
;
}
/* Links inside the dropdown */
.dropdown-content
a
{
color
:
black
;
padding
:
12px
16px
;
font-size
:
16px
;
text-decoration
:
none
;
display
:
block
;
}
/* Change color of dropdown links on hover */
.dropdown-content
a
:hover
{
background-color
:
#ccc
;}
/* Show the dropdown menu on hover */
.dropdown
:hover
.dropdown-content
{
display
:
block
;}
/* Change the background color of the dropdown button when the dropdown content is shown */
.dropdown
:hover
.dropbtn
{
background-color
:
#111
;}
/*Slider Stuff*/
.slidecontainer
{
width
:
100%
;
/* Width of the outside container */
}
.slidespan
{
width
:
80%
;
/* Width of the outside container */
padding
:
10px
;
}
/* The slider itself */
.slider
{
-webkit-appearance
:
none
;
/* Override default CSS styles */
appearance
:
none
;
vertical-align
:
middle
;
width
:
100%
;
height
:
25px
;
/* Specified height */
background
:
#d3d3d3
;
/* Grey background */
outline
:
none
;
/* Remove outline */
opacity
:
0.7
;
/* Set transparency (for mouse-over effects on hover) */
-webkit-transition
:
.2s
;
/* 0.2 seconds transition on hover */
transition
:
opacity
.2s
;
}
/* Mouse-over effects */
.slider
:hover
{
opacity
:
1
;
/* Fully shown on mouse-over */
}
/* The slider handle (use -webkit- (Chrome, Opera, Safari, Edge) and -moz- (Firefox) to override default look) */
.slider
::-webkit-slider-thumb
{
-webkit-appearance
:
none
;
/* Override default look */
appearance
:
none
;
width
:
25px
;
/* Set a specific slider handle width */
height
:
25px
;
/* Slider handle height */
background
:
#333
;
cursor
:
pointer
;
/* Cursor on hover */
}
.slider
::-moz-range-thumb
{
width
:
25px
;
/* Set a specific slider handle width */
height
:
25px
;
/* Slider handle height */
background
:
#333
;
cursor
:
pointer
;
/* Cursor on hover */
}
views/cesium.tpl
0 → 100644
View file @
bde56baa
<!DOCTYPE html>
<html
lang=
"en"
>
<head>
<meta
charset=
"utf-8"
>
<!-- Include the CesiumJS JavaScript and CSS files -->
<script
src=
"https://cesium.com/downloads/cesiumjs/releases/1.75/Build/Cesium/Cesium.js"
></script>
<link
href=
"https://cesium.com/downloads/cesiumjs/releases/1.75/Build/Cesium/Widgets/widgets.css"
rel=
"stylesheet"
>
<link
href=
"/static/style.css"
rel=
"stylesheet"
>
</head>
<body>
<h2>
DF Aggregator
</h2>
<div
id=
"cesiumContainer"
style=
"height: 800px"
></div>
<script>
// Your access token can be found at: https://cesium.com/ion/tokens.
Cesium
.
Ion
.
defaultAccessToken
=
'{
{
access_token
}
}'
;
var
viewer
=
new
Cesium
.
Viewer
(
'cesiumContainer'
,
{
terrainProvider
:
Cesium
.
createWorldTerrain
()
});
var
dataSourcePromise
=
Cesium
.
CzmlDataSource
.
load
(
'/static/output.czml'
);
viewer
.
dataSources
.
add
(
dataSourcePromise
);
viewer
.
zoomTo
(
dataSourcePromise
);
// Add Cesium OSM Buildings, a global 3D buildings layer.
const
buildingTileset
=
viewer
.
scene
.
primitives
.
add
(
Cesium
.
createOsmBuildings
());
</script>
</div>
<div
class=
"slidecontainer"
>
<form
action=
"/"
method=
"post"
>
<span><h4>
epsilon:
</h4></span>
<span
class=
"slidespan"
><input
name=
"epsilonValue"
type=
"range"
min=
"0"
max=
"100"
value=
"{
{
epsilon
}
}"
class=
"slider"
id=
"epsilonRange"
></span>
<span><p><input
value=
"Update"
type=
"submit"
style=
"height:40px;"
/></p></span>
</form>
<p>
Value:
<span
id=
"epsilon"
></span></p>
</div>
<script>
var
slider
=
document
.
getElementById
(
"epsilonRange"
);
var
output
=
document
.
getElementById
(
"epsilon"
);
output
.
innerHTML
=
slider
.
value
/
100
;
// Display the default slider value
// Update the current slider value (each time you drag the slider handle)
slider
.
oninput
=
function
()
{
output
.
innerHTML
=
this
.
value
/
100
;
}
</script>
<h4>
Buttons here in the future!
</h4>
</body>
</html>
views/index.tpl
0 → 100644
View file @
bde56baa
<!DOCTYPE html>
<html>
<head>
<link
rel=
"stylesheet"
href=
"https://unpkg.com/leaflet@1.7.1/dist/leaflet.css"
integrity=
"sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A=="
crossorigin=
""
/>
<script
src=
"https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"
integrity=
"sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA=="
crossorigin=
""
></script>
</head>
<body>
<p>
Test
</p>
<div
style=
"height: 700px"
id=
"map"
></div>
<script>
// initialize Leaflet
var
map
=
L
.
map
(
'map'
).
setView
(
{
lon
:
-
76.3
,
lat
:
39.1
}
,
8
);
// add the OpenStreetMap tiles
L
.
tileLayer
(
'https://
{
s
}
.tile.openstreetmap.org/
{
z
}
/
{
x
}
/
{
y
}
.png'
,
{
maxZoom
:
19
,
attribution
:
'© <a href="https://openstreetmap.org/copyright">OpenStreetMap contributors</a>'
}).
addTo
(
map
);
// show the scale bar on the lower left corner
L
.
control
.
scale
().
addTo
(
map
);
</script>
</body>
</html>
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment