gps_streamlit / 1_🚚_Completez.py
guzz01's picture
Upload 3 files
e854590
raw
history blame
No virus
9.54 kB
import pandas as pd
import psycopg2
import numpy as np
import streamlit as st
from streamlit_folium import st_folium
import folium
from folium import plugins
import json
import geopandas as gp
import altair as alt
from datetime import date, timedelta
from geojson import Feature, Point, FeatureCollection
import matplotlib
import os
import h3
st.set_page_config(page_title="GPS Blau", layout="wide", page_icon="🛰️")
def coneccion_db():
conn = psycopg2.connect(**st.secrets["postgres"])
return conn
@st.cache_data
def db_gps_data(fecha:str):
q = f"""
SELECT device_id
, array_agg(
json_build_object(
'type', 'Feature',
'geometry', st_asgeojson(lineas)::jsonb,
'properties', json_build_object('times', ARRAY[time_first, time_second])
)
) AS info_gps
FROM (
SELECT device_id
, time_first
, time_second
, st_difference(lineas, st_geomfromtext('POLYGON ((-102.7103698 20.0650677, -102.7107507 20.0638433, -102.7105093 20.0626087, -102.7074301 20.062639, -102.707237 20.0650173, -102.7103698 20.0650677))', 4326)) AS lineas
FROM (
SELECT device_id
, st_makeline(points, LEAD(points) OVER (ORDER BY device_id, saved_at)) AS lineas
, saved_at AS time_first
,LEAD(saved_at) OVER (ORDER BY device_id, saved_at) AS time_second
FROM (
SELECT device_id
,st_setsrid(st_makepoint(lng, lat), 4326) AS points
, saved_at
FROM (
SELECT ((received_json -> 'position') ->> 'device_id') :: NUMERIC AS device_id
,((received_json -> 'position') ->> 'lat') :: NUMERIC AS lat
,((received_json -> 'position') ->> 'lng') :: NUMERIC AS lng
,(saved_at AT time ZONE 'utc' AT TIME ZONE 'cst') AS saved_at
FROM json_dump jd
WHERE (saved_at AT time ZONE 'utc' AT TIME ZONE 'cst') :: date = '{fecha}'
)a
ORDER BY device_id, saved_at DESC
)b
GROUP BY device_id, points, saved_at
)c
)d
WHERE NOT st_isempty(lineas)
GROUP BY device_id
"""
conn = coneccion_db()
df = pd.read_sql_query(q, conn)
conn.close()
return df
@st.cache_data
def perc_recorrido(fecha:str, fecha2:str):
q1 = f"""
SELECT json_build_object(
'type', 'Feature',
'geometry', st_asgeojson(ruta_cubierta)::jsonb,
'properties', json_build_object('style', json_build_object('color', 'green'))
) AS route_cover,
json_build_object(
'type', 'Feature',
'geometry', st_asgeojson(ruta_no_cubierta)::jsonb,
'properties', json_build_object('style', json_build_object('color', 'red'))
) AS route_not_cover,
st_asgeojson(ruta) :: json AS route_plan,
st_asgeojson(driver_position) :: json AS driver_position,
st_asgeojson(poligono) :: json AS poligono,
ROUND((st_length(ruta_cubierta :: geography) / 1000):: NUMERIC, 2) AS km_cover,
ROUND((st_length(ruta_no_cubierta :: geography) / 1000) :: NUMERIC, 2) AS km_not_cover,
ROUND((st_length(ruta :: geography) /1000 ):: NUMERIC, 2) AS km_theory,
nombre_poligono,
device_id,
CASE WHEN device_id::int = 14 THEN 'Camion 14'
WHEN device_id::int = 15 THEN 'Camion 15'
ELSE NULL END AS vehiculo,
fecha
FROM (
SELECT device_id,
nombre_poligono,
st_intersection(truck_path, poligono) AS ruta_cubierta,
st_difference(streets, st_buffer(st_intersection( truck_path, poligono), 0.00011)) AS ruta_no_cubierta,
streets AS ruta,
poligono,
fecha,
st_endpoint(truck_path) AS driver_position
FROM (
SELECT st_intersection(st_collect(geometry), poligono) AS streets
,poligono
,nombre AS nombre_poligono
, id_device
FROM osmnx_sahuayo_info
CROSS JOIN geocerca
GROUP BY poligono, nombre, id_device)a
LEFT JOIN (
SELECT device_id
, fecha
, st_makeline(points ORDER BY saved_at) AS truck_path
FROM (
SELECT device_id
,st_setsrid(st_makepoint(lng, lat), 4326) AS points
, saved_at
, saved_at :: date AS fecha
FROM (
SELECT ((received_json -> 'position') ->> 'device_id') :: NUMERIC AS device_id
,((received_json -> 'position') ->> 'lat') :: NUMERIC AS lat
,((received_json -> 'position') ->> 'lng') :: NUMERIC AS lng
,(saved_at AT time ZONE 'utc' AT TIME ZONE 'cst') AS saved_at
FROM json_dump jd
WHERE (saved_at AT time ZONE 'utc' AT TIME ZONE 'cst') :: date BETWEEN '{fecha2}' AND '{fecha}'
)x
)y
GROUP BY device_id, fecha
)b
ON b.device_id = a.id_device
)c
"""
q2 = f"""
SELECT st_asgeojson(st_Difference(truck_path , st_union(poligono))) :: json AS truck_path
,id_device
FROM geocerca g
LEFT JOIN (
SELECT device_id
, st_makeline(points ORDER BY saved_at) AS truck_path
FROM (
SELECT device_id
,st_setsrid(st_makepoint(lng, lat), 4326) AS points
, saved_at
FROM (
SELECT ((received_json -> 'position') ->> 'device_id') :: NUMERIC AS device_id
,((received_json -> 'position') ->> 'lat') :: NUMERIC AS lat
,((received_json -> 'position') ->> 'lng') :: NUMERIC AS lng
,(saved_at AT time ZONE 'utc' AT TIME ZONE 'cst') AS saved_at
FROM json_dump jd
WHERE (saved_at AT time ZONE 'utc' AT TIME ZONE 'cst') :: date = '{fecha}'
)x
)y
GROUP BY device_id
)a
ON g.id_device = a.device_id
GROUP BY truck_path, id_device
"""
conn = coneccion_db()
df = pd.read_sql_query(q1, conn)
df_path = pd.read_sql(q2,conn)
conn.close()
return df, df_path
def mapa():
m = folium.Map(location=[20.068181841083025, -102.70672195476091], zoom_start=15)
return m
m = mapa()
st.markdown("# Recorrido realizado")
with st.sidebar:
st.markdown("### Filtros de animacion")
with st.form(key="form"):
fecha = st.date_input(label="Fecha")
vehiculo = st.selectbox(label="Seleccione un vehiculo:", options=[13, 14, 15])
#poligonos = st.multiselect("Selecciones las geocercas:", options=["Ruta 3 - San Miguel", "Ruta 3 - San Isidro", "RUTA 10 - Forestal", "Ruta 10", "Ruta 6"], default=None)
col1_side, col2_side = st.columns(2)
animacion = col1_side.form_submit_button("Animación")
perc_completez = col2_side.form_submit_button("Completez")
fecha2 = fecha - timedelta(days=7)
fecha2_str = fecha2.strftime("%Y-%m-%d")
fecha_str = fecha.strftime("%Y-%m-%d")
df_gps_data = db_gps_data(fecha_str)
df_perc_recorrido, df_camino = perc_recorrido(fecha_str, fecha2_str)
df_gps_vehiculo = df_gps_data.query("device_id == @vehiculo")["info_gps"]
if perc_completez and not df_perc_recorrido.empty:
style_no_cubierto = {"color": "red"}
style_cubierto = {"color": "green"}
group_name = {14: "Camion 14", 15: "Camion 15"}
for id in group_name:
feature_group = folium.FeatureGroup(group_name[id])
df_group = df_perc_recorrido.query("device_id == @id and fecha == @fecha").reset_index()
df_camino_group = df_camino.query("id_device == @id").reset_index()
for i in range(len(df_group)):
ruta_no_cubierta = folium.GeoJson(df_group["route_not_cover"].iloc[i], style_function=lambda x:style_no_cubierto)
ruta_no_cubierta.add_to(feature_group)
ruta_cubierta = folium.GeoJson(df_group["route_cover"].iloc[i], style_function=lambda x:style_cubierto)
ruta_cubierta.add_to(feature_group)
poligono = folium.GeoJson(df_group["poligono"].iloc[i])
poligono.add_to(feature_group)
fuera_poligono = folium.GeoJson(df_camino_group["truck_path"].iloc[0])
fuera_poligono.add_to(feature_group)
feature_group.add_to(m)
folium.LayerControl(collapsed=False).add_to(m)
elif animacion and not df_gps_vehiculo.empty:
info_gps = df_gps_vehiculo.iloc[0]
ultimo_elemento = info_gps.pop()
plugins.TimestampedGeoJson({
"type": "FeatureCollection",
"features": info_gps,
},
period="PT1M",
add_last_point=False,
auto_play=True
).add_to(m)
elif animacion or perc_completez:
with st.sidebar:
st.error("No se cuenta con registros")
if not df_perc_recorrido.empty:
col1, col2 = st.columns([0.6, 0.4])
df_graph = df_perc_recorrido.groupby(["vehiculo", "fecha"], as_index=False).agg(km_cubiertos=("km_cover", "sum"), km_no_cubiertos=("km_not_cover", "sum"), km=("km_theory", "sum"))
df_graph["Porcentaje de completez"] = df_graph["km_cubiertos"] * 100 / df_graph["km"]
df_graph["Porcentaje de completez"] = df_graph["Porcentaje de completez"].round(2)
df_graph["Porcentaje de completez"] = np.where(df_graph["Porcentaje de completez"] > 100, 100, df_graph["Porcentaje de completez"])
highlight = alt.selection_point(on='mouseover', fields=["vehiculo"], nearest=True)
base = alt.Chart(df_graph).mark_line().encode(
x=alt.X("fecha:T", axis=alt.Axis(format="%Y-%m-%d")),
y="Porcentaje de completez",
color="vehiculo"
)
puntos = base.mark_circle().encode(
opacity=alt.value(0)
).add_params(
highlight
).properties(
width=600
)
lineas = base.mark_line().encode(
size=alt.condition(~highlight, alt.value(1), alt.value(3))
)
chart = lineas + puntos
with col1:
col1.altair_chart(chart, use_container_width=True)
#vehiculo = st.selectbox(label="Seleccione un vehiculo:", options=[14, 15])
with col2:
df_perc_recorrido["Porcentaje de completez"] = df_perc_recorrido["km_cover"] / df_perc_recorrido["km_theory"]
df_perc_recorrido["Porcentaje de completez"] = df_perc_recorrido["Porcentaje de completez"].map('{:.2%}'.format)
df_perc_recorrido.rename(columns={"fecha": "Fecha", "vehiculo": "Vehiculo", "nombre_poligono": "Geocerca"}, inplace=True)
df_perc_recorrido.sort_values(["Fecha", "Vehiculo", "Geocerca"], inplace=True, ascending=True, axis=0)
col2.dataframe(df_perc_recorrido[["Fecha", "Vehiculo", "Geocerca", "Porcentaje de completez"]], hide_index=True)
st_data = st_folium(m, width=800, returned_objects=[])