import pandas as pd
import numpy as np
import networkx as nx
import matplotlib.pyplot as plt
import geopandas as gpd
import requests
import os
from bokeh.io import show, output_notebook, save, output_file
from bokeh.models import GeoJSONDataSource, HoverTool, LinearColorMapper, ColumnDataSource, ColorBar, BasicTicker
from bokeh.plotting import figure
from bokeh.palettes import Viridis256, all_palettes, viridis
from bokeh.tile_providers import get_provider, Vendors
from bokeh.embed import file_html
from random import randint
from cartopy import crs as ccrs
os.environ['BOKEH_PHANTOMJS_PATH'] = 'D:/Descargas/phantomjs-2.1.1-windows/bin/phantomjs.exe'
from shapely.geometry import Point
#import plotly.plotly as py
import plotly.offline as py
import plotly.graph_objs as go
from plotly.io import to_html, write_image
import datashader as ds
import holoviews as hv
from colorcet import fire
from datashader.bundling import directly_connect_edges, hammer_bundle
from datashader.utils import export_image
from holoviews.operation.datashader import aggregate, shade, datashade, dynspread, rasterize
from holoviews.operation import decimate
from holoviews import opts
import geoviews as gv
import geoviews.tile_sources as gts
import plotly_express as px
import imageio
hv.notebook_extension('bokeh', 'matplotlib')
from dask.distributed import Client
client = Client()
decimate.max_samples=20000
dynspread.threshold=0.01
datashade.cmap=fire[40:]
sz = dict(width=150,height=150)
px.set_mapbox_access_token(open("credenciales/mapbox").read())
print(pd.__version__)
print(nx.__version__)
print(gpd.__version__)
print(ds.__version__)
print(hv.__version__)
print(gv.__version__)
%matplotlib inline
output_notebook()
py.init_notebook_mode()
dir_datos = 'datos'
dir_datos_d = 'D:/Datos/Ecobici'
dias = ['Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo']
meses = ["Enero", "Febrero", "Marzo", "Abril", "Mayo","Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"]
labels_edad = ['Hasta 20', 'Entre 21 y 30', 'Entre 31 y 40', 'Entre 41 y 50', 'Entre 51 y 60', 'Más de 60']
def getPolyCoords(row, geom, coord_type):
"""Returns the coordinates ('x' or 'y') of edges of a Polygon exterior"""
# Parse the exterior of the coordinate
exterior = row[geom].exterior
if coord_type == 'x':
# Get the x coordinates of the exterior
return list( exterior.coords.xy[0] )
elif coord_type == 'y':
# Get the y coordinates of the exterior
return list( exterior.coords.xy[1] )
# Viajes entre estaciones
df = pd.read_pickle(f'{dir_datos_d}/viajes_2019.pkl')\
.rename(columns={'Ciclo_Estacion_Arribo': 'est_arribo',
'Ciclo_Estacion_Retiro': 'est_retiro',
'Edad_Usuario': 'edad',
'Genero_Usuario': 'sexo'})\
.assign(est_arribo=lambda x: x['est_arribo'].pipe(pd.to_numeric, errors='coerce'))\
.dropna(subset=['est_arribo'])\
.astype({'est_arribo': int})\
df['date_retiro'] = df['time_retiro'].dt.date.pipe(pd.to_datetime)
df['date_arribo'] = df['time_arribo'].dt.date.pipe(pd.to_datetime)
# Mapa Colonias
cdmx = gpd.read_file(f'{dir_datos}/coloniascdmx.geojson')\
.astype({'id': int})\
.rename(columns={'id': 'id_colonia'})\
.pipe(gpd.GeoDataFrame)
est_geo = gpd.read_file(f'{dir_datos}/estaciones_ecobici.geojson')\
.rename(columns={'id': 'id_est'})
cdmx.crs = est_geo.crs
estaciones = gpd.sjoin(est_geo, cdmx, op='within', how='left')
dicc_nom_est = estaciones.set_index('id_est')['name'].to_dict()
#df_curso = df[['Bici', 'sexo', 'edad', 'grupo_edad', 'est_retiro', 'est_arribo', 'time_retiro', 'time_arribo', 'time', 'mes', 'dia', 'hora', 'momento']].sample(n=100000)
#df_curso.to_csv('C:/Users/lnppcide04/Dropbox (LNPP)/Otros/Talleres UCD/Escuela de metodos 2019/sesion_5/datos/ecobici.csv', index=False)
print('El número total de viajes es', df.shape[0])
df.groupby('mes')['Bici'].count()
viajes_mes = px.bar(mes_sexo_dia, x="mes", y="Bici", color="sexo", orientation="v",
labels={'sexo': 'Sexo', 'Bici': 'Viajes'},
category_orders={'mes': meses[0:9]},
title='Viajes por Mes, según sexo')
viajes_mes.update(data=[{'textfont': {'size': 1, 'color': '#636efa'},}])
with open('concurso/introduccion/viajes_por_mes.html', 'w') as htmlfile:
htmlfile.write(to_html(viajes_mes))
viajes_mes
df_sex_edad = df.groupby(['sexo', 'grupo_edad', 'edad'], as_index=False)[['Bici']].count()
df_piramide = df_sex_edad.query('edad<=80')\
.groupby(['sexo', 'edad']).sum()\
.unstack(level='sexo')['Bici']\
.assign(F=lambda x: -1*x['F'])\
.reset_index()
df_sex_edad.groupby('edad').Bici.sum()#/df_sex_edad.Bici.sum()
prop_muj = df_piramide.abs().assign(prop=lambda x: 100*x['F']/(x['F']+x['M'])).astype({'edad': int})\
viajes_mujeres = px.bar(prop_muj, x="edad", y="prop", orientation="v",
labels={'edad': 'Edad', 'prop': 'Porcentaje'},
title='Proporción de viajes realizados por mujeres, 2019')
viajes_mujeres.update(data=[{'textfont': {'size': 1, 'color': '#636efa'},}])
with open('concurso/introduccion/proporcion_mujeres.html', 'w') as htmlfile:
htmlfile.write(to_html(viajes_mujeres))
viajes_mujeres
plot_sexo_edad_barra = px.bar(df_sex_edad, x="Bici", y="sexo", orientation="h", color="grupo_edad", labels={'sexo': 'Sexo', 'Bici': 'Viajes', 'grupo_edad': 'Grupo etario'},
category_orders={'grupo_edad': labels_edad}, text='edad',
title='Viajes por sexo y grupo etario',)
with open('concurso/introduccion/viajes_por_sexo_edad_barras.html', 'w') as htmlfile:
htmlfile.write(to_html(plot_sexo_edad_barra))
plot_sexo_edad_barra
minrange, maxrange, steprange = -200000, 400000, 50000
layout = go.Layout(title='Viajes por sexo y edad',
yaxis=go.layout.YAxis(title='Edad'),
xaxis=go.layout.XAxis(
range=[minrange, maxrange],
tickvals=list(range(minrange, maxrange, steprange)),
ticktext=list(map(abs, list(range(minrange, maxrange, steprange)))),
title='Viajes'),
barmode='overlay',
bargap=0.1)
data = [go.Bar(y=df_piramide['edad'],
x=df_piramide['M'],
orientation='h',
name='Hombres',
hovertemplate='viajes: %{x}, edad: %{y}'
),
go.Bar(y=df_piramide['edad'],
x=df_piramide['F'],
orientation='h',
name='Mujeres',
text=-1 * df_piramide['F'].astype('int'),
hovertemplate='viajes: %{text}, edad: %{y}',
marker=dict(color='seagreen')
)]
plot_sexo_edad_piramide = dict(data=data, layout=layout)
with open('concurso/introduccion/viajes_por_sexo_edad_piramide.html', 'w') as htmlfile:
htmlfile.write(to_html(plot_sexo_edad_piramide))
py.iplot(plot_sexo_edad_piramide)
OD_colonias = df[['est_retiro', 'est_arribo', 'Bici', 'sexo', 'genero', 'edad', 'time']]\
.merge(estaciones[['id_colonia', 'nombre', 'id_est']].rename(columns={'nombre': 'colonia_retiro', 'id_colonia': 'id_colonia_retiro'}), left_on='est_retiro', right_on='id_est')\
.rename(columns={'id_est': 'id_est_retiro'})\
.merge(estaciones[['id_colonia', 'nombre', 'id_est']].rename(columns={'nombre': 'colonia_arribo', 'id_colonia': 'id_colonia_arribo'}), left_on='est_arribo', right_on='id_est')\
.rename(columns={'id_est': 'id_est_arribo'})\
# Por colonia de retiro
col_retiro = OD_colonias\
.groupby(['id_colonia_retiro', 'colonia_retiro'])\
.agg({'Bici': 'count', 'genero': 'mean', 'edad': 'mean', 'time': 'mean',
'colonia_arribo': lambda x: ','.join(x.value_counts().iloc[0:3].index)})\
.sort_values('Bici', ascending=False)\
.reset_index('colonia_retiro')\
.join(cdmx.set_index('id_colonia'), how='inner')\
.pipe(gpd.GeoDataFrame)
geosrc_arribo = GeoJSONDataSource(geojson=col_retiro.to_json())
#col_retiro.to_file('datos/colonias_ecobici/colonias_ecobici.shp')
cmap = LinearColorMapper(palette=Viridis256[::-1])
colorbar_retiro = ColorBar(color_mapper=cmap, location=(0, 0), ticker=BasicTicker())
hover_retiro = HoverTool(tooltips=[("viajes", "@Bici"),
("Colonia", "@colonia_retiro"),
('Edad promedio', '@edad'),
('Proporcíón mujeres', '@genero'),
('Tiempo promedio', '@time'),
('Destino más popular', '@colonia_arribo')])
tools_retiro = ['pan', 'wheel_zoom', 'reset', 'save', hover_retiro]
titulo = 'Viajes de Ecobici por colonia de retiro'
p_retiro = figure(title=titulo, tools=tools_retiro,
plot_width=600, plot_height=600, match_aspect=True)
p_retiro.patches('xs', 'ys', fill_alpha=0.7, fill_color={'field': 'Bici', 'transform': cmap},
line_color='black', line_width=0.5, source=geosrc_arribo)
p_retiro.add_layout(colorbar_retiro, 'right')
output_file(f"concurso/introduccion/{titulo}.html", title=titulo)
show(p_retiro)
col_retiro.sort_values('Bici', ascending=False).head(10)
# Por colonia de arribo
col_arribo = OD_colonias\
.groupby(['id_colonia_arribo', 'colonia_arribo'])\
.agg({'Bici': 'count', 'genero': 'mean', 'edad': 'mean', 'time':'mean',
'colonia_retiro': lambda x: ','.join(x.value_counts().iloc[0:3].index)})\
.sort_values('Bici', ascending=False)\
.reset_index('colonia_arribo')\
.join(cdmx.set_index('id_colonia'), how='inner')\
.pipe(gpd.GeoDataFrame)
geosrc_arribo = GeoJSONDataSource(geojson=col_arribo.to_json())
cmap = LinearColorMapper(palette=Viridis256[::-1])
colorbar_arribo = ColorBar(color_mapper=cmap, location=(0, 0), ticker=BasicTicker())
hover_arribo = HoverTool(tooltips=[("viajes", "@Bici"),
("Colonia", "@colonia_arribo"),
('Edad promedio', '@edad'),
('Proporcíón mujeres', '@genero'),
('Tiempo promedio', '@time'),
('Origen más popular', '@colonia_retiro')])
tools_arribo = ['pan', 'wheel_zoom', 'reset', 'save', hover_arribo]
titulo = 'Viajes de Ecobici por colonia de arribo'
p_arribo = figure(title=titulo, tools=tools_arribo,
plot_width=600, plot_height=600, match_aspect=True)
p_arribo.patches('xs', 'ys', fill_alpha=0.7, fill_color={'field': 'Bici', 'transform': cmap},
line_color='black', line_width=0.5, source=geosrc_arribo)
p_arribo.add_layout(colorbar_arribo, 'right')
output_file(f"concurso/introduccion/{titulo}.html", title=titulo)
show(p_arribo)
col_arribo.sort_values('Bici', ascending=False).head(10)
entre_colonias = OD_colonias.groupby(['colonia_retiro', 'colonia_arribo'])[['Bici']].count()\
.unstack(level='colonia_retiro')['Bici']
pct = [x/100 for x in range(0, 100, 3)] + [1]
decil = list(np.nanquantile(entre_colonias.values, q=pct)/np.nanmax(entre_colonias.values))
decil[0] = 0
paleta = viridis(len(pct))[::-1]
xtitle = 'Colonia de destino'
ytitle = 'Colonia de origen'
color = [y for x in [[[decil[i], c], [decil[i+1], c]] for i, c in zip(range(len(decil)-1), paleta)] for y in x]
trace = go.Heatmap(z=entre_colonias.values.tolist(),
x=entre_colonias.index.tolist(),
y=entre_colonias.keys().tolist(),
colorscale=color,
)
#hovertemplate='Origen: %{y} <br> destino: %{x} <br> Viajes %{z}')
data=[trace]
layout = go.Layout(
title='Viajes entre colonias',
height=1200,
yaxis =go.layout.YAxis(
title=ytitle,
automargin=True,
),
xaxis =go.layout.XAxis(
title=xtitle,
automargin=True,
)
)
fig = go.Figure(data=data, layout=layout)
#with open('concurso/introduccion/heatmap_viajes_entre_colonias.html', 'w') as htmlfile:
#htmlfile.write(to_html(fig))
py.iplot(fig, filename='heatmap')
entre_colonias.unstack().to_frame(name='viajes').sort_values('viajes', ascending=False).query('colonia_retiro!=colonia_arribo')
1392456.0/6395454.0
dia_hora = df.groupby(['dia', 'hora'])[['Bici']].count()\
.unstack(level='hora')['Bici']\
.loc[reversed(dias)]\
.drop([3, 4], axis=1)\
.rename(columns=lambda x: f'{x:.0f} a {x+1:.0f}')\
.loc[:, '5 a 6': '23 a 24']
trace = go.Heatmap(z=dia_hora.values.tolist(),
x=dia_hora.keys().tolist(),
y=dia_hora.index.tolist(),
hovertemplate='%{y} de %{x}: %{z} viajes',
colorscale='Viridis',
reversescale=True)
data=[trace]
layout = go.Layout(
title='Viajes por día y hora',
yaxis =go.layout.YAxis(
automargin=True,
),
xaxis =go.layout.XAxis(
title='Hora',
automargin=True,
)
)
fig = go.Figure(data=data, layout=layout)
with open('concurso/introduccion/heatmap_viajes_por_dia_hora.html', 'w') as htmlfile:
htmlfile.write(to_html(fig))
py.iplot(fig)
sexo_hora = df.groupby(['sexo', 'hora'])[['Bici']].count()\
.pipe(lambda y: 100*y/y.groupby(level='sexo').sum())\
.reset_index()
px.line(sexo_hora, x="hora", y="Bici", color="sexo", line_group="sexo", line_shape="spline",
title='Porcentaje de viajes, por hora del día y sexo', labels={'Bici': 'Porcentaje del total de viajes'})
sexo_edad_dia = df.groupby(['sexo', 'grupo_edad', 'dia'], as_index=False)[['Bici']].count()\
.assign(texto=lambda x: x.apply(lambda x: f'Sexo: {x["sexo"]} <br> Grupo edad: {x["grupo_edad"]} <br> Día: {x["dia"]} <br> Viajes: {x["Bici"]}', axis=1))
sexo_edad_dia.head()
b = px.bar(sexo_edad_dia, x="Bici", y="dia", color="sexo", orientation="h",
labels={'sexo': 'Sexo', 'Bici': 'Viajes', 'grupo_edad': 'Grupo etario'},
category_orders={"dia": dias}, text='grupo_edad', title='Viajes por día de la semana, según sexo y grupo de edad')
b.update(data=[{'textfont': {'size': 1, 'color': '#636efa'},}])
mes_sexo_dia = df.groupby(['mes', 'sexo'], as_index=False)[['Bici']].count()\
.query('mes!=["Diciembre", "Noviembre", "Octubre"]')
mes_sexo_dia.head()
viajes_mes = px.bar(mes_sexo_dia, x="mes", y="Bici", color="sexo", orientation="v",
labels={'sexo': 'Sexo', 'Bici': 'Viajes'},
category_orders={'mes': meses[0:9]},
title='Viajes por Mes, según sexo')
viajes_mes.update(data=[{'textfont': {'size': 1, 'color': '#636efa'},}])
with open('concurso/introduccion/viajes_por_mes.html', 'w') as htmlfile:
htmlfile.write(to_html(viajes_mes))
viajes_mes
time_prom = df.groupby(['dia', 'sexo', 'hora'], as_index=False)[['time']].mean()\
.query('hora>=5')\
.astype({'hora': int})
time_prom.head()
duracion = px.bar(time_prom, x="dia", y="time", color="sexo", orientation="v", barmode='group', animation_frame='hora',
category_orders={'dia': dias}, labels={'time': 'Tiempo promedio'},
title='Tiempo promedio de viaje, por sexo, día de la semana y hora')
with open('concurso/introduccion/duracion_viajes_por_dia_hora.html', 'w') as htmlfile:
htmlfile.write(to_html(duracion))
duracion
folder_gif = 'concurso/introduccion/duracion'
images = [imageio.imread(f'{folder_gif}/{h}.png') for h in range(5, 24)]
imageio.mimsave(f'{folder_gif}/duracion_viajes_x_dia_hora.gif', images, duration=0.5)
viajes_est_ret = df.groupby(['est_retiro', 'hora'])[['Bici']].count()\
.join(estaciones.rename(columns={'id_est': 'est_retiro'})
.set_index('est_retiro')[['nombre', 'location_lat', 'location_lon', 'nom_mun']], how='inner')\
.reset_index()\
.query('hora>=5')\
.astype({'hora': int})
viajes_est_ret.head()
viajes_est_arr = df.groupby(['est_arribo', 'hora'])[['Bici']].count()\
.join(estaciones.rename(columns={'id_est': 'est_arribo'})
.set_index('est_arribo')[['nombre', 'location_lat', 'location_lon', 'nom_mun']], how='inner')\
.reset_index()\
.query('hora>=5')\
.astype({'hora': int})
viajes_est_arr.head()
plot_est_ret = px.scatter_mapbox(viajes_est_ret, lat="location_lat", lon="location_lon", color="nom_mun", size="Bici", animation_frame='hora',
color_continuous_scale=px.colors.cyclical.IceFire, hover_name='est_retiro', size_max=50, zoom=12, height=850,
labels={'Bici': 'Viajes', 'nom_mun': 'Alcaldía'}, title='Viajes por estación de retiro, por hora del día')
with open('concurso/introduccion/viajes_por_estacion_retiro_x_hora_2019.html', 'w') as htmlfile:
htmlfile.write(to_html(plot_est_ret))
plot_est_ret
folder_gif = 'concurso/introduccion/por_estacion_retiro/'
images = [imageio.imread(f'{folder_gif}/{h}.png') for h in range(5, 24)]
imageio.mimsave(f'{folder_gif}/viajes_x_estacion_retiro.gif', images, duration=0.5)
# https://rawcdn.githack.com/jjsantos01/datosecobici/46e312fc9c01b81e2e4b9001d36f01cbe7532453/viajes_por_estacion_arribo_x_hora.html
plot_est_arr = px.scatter_mapbox(viajes_est_arr, lat="location_lat", lon="location_lon", color="nom_mun", size="Bici", animation_frame='hora',
color_continuous_scale=px.colors.cyclical.IceFire, hover_name='est_arribo', size_max=50, zoom=12, height=850,
labels={'Bici': 'Viajes', 'nom_mun': 'Alcaldía'}, title='Viajes por estación de arribo, por hora del día')
with open('concurso/introduccion/viajes_por_estacion_arribo_x_hora_2019.html', 'w') as htmlfile:
htmlfile.write(to_html(plot_est_arr))
plot_est_arr
folder_gif = 'concurso/introduccion/por_estacion_arribo/'
images = [imageio.imread(f'{folder_gif}/{h}.png') for h in range(5, 24)]
imageio.mimsave(f'{folder_gif}/viajes_x_estacion_arribo.gif', images, duration=0.5)
rutas_frecuentes = df.assign(Retiro=lambda x:x['est_retiro'].map(dicc_nom_est),
Arribo=lambda x:x['est_arribo'].map(dicc_nom_est))\
.groupby(['Retiro', 'Arribo'], as_index=False)[['Bici']].count().sort_values('Bici', ascending=False)\
.rename(columns={'Bici': 'Viajes'})
rutas_frecuentes.to_excel('concurso/dashboard/intro/ritas_frecuentes.xlsx', index=False)
# Estaciones de retiro más frecuentes
viajes_est_ret.assign(est_retiro=lambda x: x['est_retiro'].map(dicc_nom_est))\
.groupby('est_retiro')['Bici'].sum().sort_values(ascending=False)\
.to_frame('viajes')
# Estaciones de arribo más frecuentes
viajes_est_arr.assign(est_arribo=lambda x: x['est_arribo'].map(dicc_nom_est))\
.groupby('est_arribo')['Bici'].sum().sort_values(ascending=False)\
.to_frame('viajes')
# https://anaconda.org/jbednar/edge_bundling/notebook
edges = df.query('est_retiro<=480 & est_arribo<=480')[['est_retiro', 'est_arribo']]\
.rename(columns={'est_retiro': 'source', 'est_arribo': 'target'})\
.pipe(hv.Curve)
nodos = estaciones.set_index('id_est')[['location_lat', 'location_lon']]\
.rename(columns={'location_lat': 'y', 'location_lon': 'x'})\
.pipe(hv.Points)
connected_edges = directly_connect_edges(nodos.data, edges.data)
direct = hv.Curve(connected_edges)
red_viajes = datashade(direct)
red_viajes.opts(title=f'Viajes 2019', width=800, height=800, xaxis=None, yaxis=None, tools=['hover'])
horas = [0] + list(range(5, 24))
l_conn_edges = []
for h in horas:
edges = df.query('est_retiro<=480 & est_arribo<=480 & hora==@h')[['est_retiro', 'est_arribo']]\
.rename(columns={'est_retiro': 'source', 'est_arribo': 'target'})\
.pipe(hv.Curve)
nodos = estaciones.set_index('id_est')[['location_lat', 'location_lon']]\
.rename(columns={'location_lat': 'y', 'location_lon': 'x'})\
.pipe(hv.Points)
l_conn_edges += [directly_connect_edges(nodos.data, edges.data).assign(hora=h)]
connected_edges = pd.concat(l_conn_edges)
connected_edges.to_csv(f'{dir_datos_d}/connected_edges_2019.csv', index=False)
connected_edges = pd.read_csv(f'{dir_datos_d}/connected_edges_2019.csv')
connected_edges.head()
%%opts RGB [width=600 height=600]
das = hv.Dataset(connected_edges, kdims=['x'], vdims=['y'])\
.to(hv.Curve, groupby='hora', dynamic=True)
rasterized = rasterize(das).opts(clipping_colors={'NaN': (0, 0, 0, 0)})
horas = list(range(5, 24))+[0]
holo_dict = dict()
for h in horas:
ras = rasterized.get(h).opts(
opts.Image(title=f'Viajes entre estaciones de Ecobici a las {h}', width=600, height=500, logz=False, xaxis=None, yaxis=None,
tools=['hover'], colorbar=True, clim=(1, 1500), cmap='Viridis'))
holo_dict[h] = ras
hmap = hv.HoloMap(holo_dict, kdims='hora')
# rasterized.opts(opts.Image(width=600, height=500, logz=False, xaxis=None, yaxis=None, tools=['hover'], colorbar=True, clim=(1, 1500), cmap='Viridis', bgcolor=None), ) # Dynamic
gv.Dataset(connected_edges, kdims=['x', 'y'], vdims=['hora'])\
.to(gv.TriMesh, groupby='hora', dynamic=True)
%%opts Image [colorbar=True clipping_colors={'NaN': (0, 0, 0, 0)} clim=(1, 1500)] (cmap='viridis')
hv.Image(datashade(das).get(8))
gv.Image(gv.operation.convert_to_geotype(rasterize(das).get(8), crs=ccrs.PlateCarree())) * gts.Wikipedia
gv.Image(rasterize(das).get(0)).opts(colorbar=True, clim=(1, 100)) * gts.Wikipedia
col_ecobici = gv.Shape.from_shapefile('datos/colonias_ecobici/colonias_ecobici.shp', crs=ccrs.PlateCarree())
# %%opts Points (color="red") [tools=["hover"] width=900 height=650]
d = {h: gts.Wikipedia * gv.Image(holo_dict[h]).opts(cmap='Viridis', clim=(1, 1500), colorbar=True)
* col_ecobici.opts(bgcolor='black', color=None)
* gv.Points(est_geo) for h in horas[0:1]}
hv.HoloMap(d)
for h, ras in holo_dict.items():
hv.save(ras, f'graficas/red_x_hora/2019/{h}.png')
images = [imageio.imread(f'graficas/red_x_hora/2019/{h}.png') for h in range(5, 24)]
imageio.mimsave('graficas/red_x_hora/2019/red_x_hora_2019.gif', images, duration=0.5)
n_viajes_dia = df.groupby('date_retiro')[['Bici']].count().loc['2019-01-01':]
n_viajes_dia.to_csv('datos/viajes_x_dia_2019.csv')
pre_carto = df.loc[(df['Fecha_Retiro']=='02/04/2019') & (df['Fecha_Arribo']=='02/04/2019') & (df['hora']>=5) & (df['hora']<=23)]\
.assign(viaje=lambda x: range(len(x)))
carto = pre_carto[['Bici', 'est_retiro', 'time_retiro', 'viaje']].rename(columns=lambda x: x.replace('_retiro', ''))\
.append(
pre_carto[['Bici', 'est_arribo', 'time_arribo', 'viaje']].rename(columns=lambda x: x.replace('_arribo', ''))
)\
.merge(estaciones[['id_est', 'geometry']], left_on='est', right_on='id_est')\
.pipe(gpd.GeoDataFrame, geometry='geometry')
#carto.to_file('concurso/cartodb_20190402.geojson', driver='GeoJSON')
viaje = carto.query('viaje==0')
crea_rutas(viaje)
def crea_rutas(viaje):
rutas = []
try:
t0, t1 = viaje.time.to_list()
p0, p1 = viaje.geometry.to_list()
if p0==p1:
return rutas
m = (p0.y-p1.y)/(p0.x-p1.x)
b = (p0.x*p1.y - p1.x*p0.y)/(p0.x-p1.x)
d = (t1-t0).seconds/60
mx = (p1.x-p0.x)/d
rutas = [[viaje.index[0], t0+pd.to_timedelta(i, unit='m'),
Point(p0.x+i*mx, b + m*(p0.x+i*mx)), i+1 if i != int(d) else 100]
for i in range(0, int(d+1))]
except Exception as e:
print(e)
return rutas
resultado = dict()
for v, g in carto.sort_values(['viaje', 'time']).set_index('viaje').loc[30000:].groupby('viaje'):
if v not in resultado:
resultado[v] = crea_rutas(g)
ruta = gpd.GeoDataFrame(pd.Series((list(resultado.values()))).sum(), columns=['viaje', 'time', 'geometry', 'step'], geometry='geometry')
ruta_filename = 'concurso/cartodb/ruta_cartodb.geojson'
if os.path.exists(ruta_filename):
os.remove(ruta_filename)
ruta.to_file(ruta_filename, driver='GeoJSON')
viajes_colonias = pd.read_pickle('D:/datos/ecobici/viajes_2019.pkl') \
.rename(columns={'Ciclo_Estacion_Arribo': 'arribo', 'Ciclo_Estacion_Retiro': 'retiro'}) \
.groupby(['arribo', 'retiro']) \
.agg({'Bici': 'count', 'time': 'mean', 'genero': 'mean', 'Edad_Usuario': 'mean'}) \
.reset_index() \
.assign(arribo=lambda x: x['arribo'].pipe(pd.to_numeric, errors='coerce')) \
.dropna(subset=['arribo']) \
.astype({'arribo': int})
viajes_colonias.to_csv('D:/datos/ecobici/viajes_colonias_2019_app.csv', index=False)