Arxiu de la categoria: Programació

Bot de Twitter de català revifat

Comença un nou curs, i projectes nous. Durant 10 anys he estat recopilant informació de paraules que m’agrades, i que malauradament estan caient en desús. A més, el Jordi Badia acaba de publicar el llibre Salvem els Mots que precisament va sobre aquesta problemàtica.

Ja feia temps que em rondava fer un bot de Twitter. Així doncs, el que he fet és agafar la informació que tinc, i estructurar-la en una base de dades (recordem: informació > coneixement). I utilitzant el paquet Tweepy de Python, i registrant-te a Tweeter com a desenvolupador, després d’un procés més o menys ràpid, ja tinc el meu bot de Twitter en marxa.

Es tracta de moment d’enviar un missatge dia si dia no, amb un contingut humorístic i picant, relacionat amb paraules i expressions del català que ens agradaria recuperades i normalitzades. El compte de Twitter és @CatalaRevifat

Referències:

RutesGPS, nova versió

S’ha publicat la nova versió de les meves rutes amb bici. De la v5 a la v7 hi ha molts canvis significatius: canvi total del disseny, responsive, Javascript amb mòduls, Openlayers v6 en la part de mapes, s’ha eliminat tota la part de PHP (és una webapp).

La llista de rutes s’havia fet molt llarga, i per tant ara les rutes s’agrupen per zones geogràfiques, que és un desplegable. Podem filtrar per les rutes que s’han fet, i distingir-les de les rutes ToDo, que són les que volem fer properament, si tot va bé. Les capes de render que s’han triat són el estàndard de OSM, el TOPOTRESC, la OrtoFoto del ICGC, i el estàndard del ICGC.
La única funcionalitat que queda per implementar és la Cerca de rutes, a veure si ho puc fer abans de les vacances.

Tot el codi està penjat en el github. En la foto es pot apreciar el canvi de disseny de la versió anterior a l’actual. Una altra millora important que s’ha implementat és l’automatització del desplegament al servidor, de manera que ara és més fàcil i està més documentat publicar els canvis en la nova versió.

Referències:

Municipis de Catalunya (Openlayers)

Hem agafat de l’IDESCAT les dades dels municipis de més de 20.000 habitants de Catalunya (una setantena de municipis), i els hem geolocalitzat.
El que volia practicar en aquesta ocasió era la selecció de capes, i ho volia fer tot amb mòduls (imports) de Javascript, i el codi el més net possible.
Es pot veure el resultat en aquest video.

Col·lecció de rutes BTT

Estic programant amb OpenLayers, últimament he fet els projectes de Catalunya Màgica i Quintana. Aprofitant que a OpenLayers és fàcil pintar una ruta GPX, volia posar totes les rutes BTT que he anat fent en un mateix mapa, i així dóna la idea d’activitat. Bé, no totes les rutes són de BTT, també n’hi ha de senderisme, i tampoc són totes les rutes que he fet, però dóna una idea.
El següent pas serà posar unes capes que es puguin activar/desactivar, per seleccionar BTT/senderisme, o bé per zona geogràfica.

Catalunya Màgica

S’ha publicat la web de la Catalunya Màgica: dimonis, infern, bruixes i diables, amb informació agafada de OpenStreetMap.

Hem utiltizat OpenLayers 6.5.0 (amb el paradigma de imports), i les tiles estàndard de OSM i també TRESC, una capa de visualització que m’agrada molt. Les dades que s’obtenen poden ser nodes o vies, i hi ha hagut una feina prèvia de netejar una mica les dades, però tot plegat ha sigut un procés molt ràpid.

Referències:

Segments de ciclisme amb la API de Strava

De la API de Strava m’interessa sobretot la part de segments, que són trossos de rutes en què la gent es cronometra i es publica els rankings. Malauradament, sense una subscripció Premium no es pot accedir a tota la informació. Jugant una estona amb la API de Strava he arribat a poder veure els segments que hi ha en una zona geogràfica, i poder veure els punts d’aquest segment, que es poden representar en qualsevol mapa.

Per accedir a la informació d’un segment:

$ curl -X GET https://www.strava.com/api/v3/segments/229781 -H 'Authorization: Bearer *******************'

I el resultat:

{"id":229781,"resource_state":3,"name":"Hawk Hill","activity_type":"Ride","distance":2684.82,"average_grade":5.8,"maximum_grade":10.9,"elevation_high":247.2,"elevation_low":92.0,"start_latlng":[37.833112,-122.483436],"end_latlng":[37.828072,-122.498139],"elevation_profile":"https://d3o5xota0a1fcr.cloudfront.net/v6/charts/KO5P7GCFLK5P5NF5GNUX3D6IVFLIEYRYD6JRBEGMXHOCPENJUQZXD5IIEJOYINQE2HX3XLZMYRTF5GHG5JLQ====","start_latitude":37.833112,"start_longitude":-122.483436,"end_latitude":37.828072,"end_longitude":-122.498139,"climb_category":1,"city":"San Francisco","state":"CA","country":"United States","private":false,"hazardous":false,"starred":false,"created_at":"2009-09-21T20:29:41Z","updated_at":"2021-03-13T09:01:33Z","total_elevation_gain":155.2,

"map":{"id":"s229781","polyline":"}g|eFnpqjVl@En@Md@HbAd@d@^h@Xx@VbARjBDh@OPQf@w@d@k@XKXDFPF\\CbGT`AV`@v@|@NTNb@?XOb@cAxAWLuE@eAFMBoAv@eBt@q@b@}@tAeAt@i@dAC`AFZj@dBA~@Yh@MbAVn@b@b@\\d@Ef@Qd@_@d@eB|@c@h@YfBI|AMpA?VF\\\\t@f@t@h@j@|@b@hCb@b@XTd@Bl@GtA?jAL`ALp@Tr@RXd@Rx@Pn@^Zh@Tx@Zf@`@FTCzDy@f@Yx@m@n@Op@VJr@","resource_state":3},

"effort_count":556805,"athlete_count":49100,"star_count":5022,"athlete_segment_stats":{"pr_elapsed_time":null,"pr_date":null,"pr_activity_id":null,"effort_count":0},"xoms":{"kom":"5:37","qom":"6:42","destination":{"href":"strava://segments/229781/leaderboard","type":"overall","name":"All-Time"}},"local_legend":{"athlete_id":54312907,"title":"Dalton Nonweiler","profile":"https://dgalywyr863hv.cloudfront.net/pictures/athletes/54312907/14907176/5/large.jpg","effort_description":"86 efforts in the last 90 days","effort_count":"86","effort_counts":{"overall":"86 efforts","female":"41 efforts"},"destination":"strava://segments/229781/local_legend?categories%5B%5D=overall"}}

Veiem que la polilínia està codificada en una cadena de text. La podem decodificar i obtenir-ne les coordenades:

$ pip3 install polyline

$ python3
>> import polyline
>> #polyline.decode(summary_polyline)
>> polyline.decode("gxu{Fem|Kc@fAq@fAoApAMR[ZMXw@v@a@VQZi@j@sAhAk@hA_@f@oDxCiAhA_@j@a@~@{@pCC`@EFD^H`B?`@BNNZV@JGDMEqA@q@H]NOFSLo@t@eB^i@d@i@t@m@n@Yz@EHBR\\`AdDFdEJ`@RNHIVGf@ATH`At@VXDl@GJU@WY[e@YSKC_@GgA@YMKMc@eBYeBSWg@AUTSVa@|@[tAAPDb@Nr@@TCb@[bACd@BNJ^Xh@N^BNB`@Nn@DJTNZ\\Rn@?\\c@zAA^B\\JZHHh@NZDVHTRHJBNAb@I|@B\\Th@PTVf@F`@Cl@Sj@WJ{Ae@{@OKBSPOr@IvA[z@UTw@JWE_@]QUUKKCu@Hs@NMEIIi@kAOUGE]OUMGIGY?y@XiB@]E]U[SGU?c@XcA`Aw@|@i@~@WbASPK?IC_Au@q@_@SAI@g@Lo@XK?YB[MYOQSQYi@Y_@AK@CDg@X]Bg@KUMi@e@[k@GU@MHQb@a@DIFU@WIYg@u@]y@IqAP{ABq@Is@e@iB}@wAw@oBk@aAa@g@g@w@Km@Q{AYkB_AmCc@eB?]H]NWxAiBZq@JYFm@@m@C[G]OWa@k@eAu@o@k@iBkCm@k@SKc@CK@]LS@e@]]]E@GDEH@`@PZJd@CHEFI?OSMe@Uk@")

[(41.40436, 2.11683), (41.40454, 2.11647), (41.40479, 2.11611), (41.40519, 2.1157), (41.40526, 2.1156), (41.4054, 2.11546), (41.40547, 2.11533), 
...
(41.41868, 2.11667), (41.41859, 2.11653), (41.41853, 2.11634), (41.41855, 2.11629), (41.41858, 2.11625), (41.41863, 2.11625), (41.41871, 2.11635), (41.41878, 2.11654), (41.41889, 2.11676)]

Referències:

Gràfics interactius amb Jupyter Notebooks: tir parabòlic

Ara que ja he començat a fer proves amb Jupyter Notebook, el següent pas que vull provar és fer gràfics interactius. Doncs ha resultat ser més fàcil i ràpid del que pensava.

Parteixo d’un script python que simula les dades experimentals d’una trajectòria parabòlica, i calcula la paràbola que millor s’hi ajusta (regressió quadràtica). A partir de l’equació de la paràbola es pot deduir la constant g (=9,81 m/s2). Simulo les dades experimentals introduïnt un error de soroll en les dades teòriques. Doncs bé, amb el meu gràfic interactiu puc jugar amb el nivell de soroll, i amb el número de punts de mostreig, tal com es veu en el video. El codi queda de la següent manera:

%matplotlib inline
from ipywidgets import interactive
import numpy as np
import pylab as plt
from IPython.display import display, Math, Latex

# tir parabòlic: y = vy*t - .5gt^2
vy = 10 # 10m/s
g = 9.81 # m/s^2
t_max = 2*vy/g

def f(nivell_soroll, num_punts):
    t = np.linspace(0, t_max, num_punts)
    y_or = vy*t - .5*g*t**2
    noise = np.random.normal(0, nivell_soroll, num_punts) # simulem dades experimentals
    y = y_or + noise

    # ajustament a una paràbola
    z = np.polyfit(t, y, 2)
    g_exp = 2.0*z[0]

    t_ = np.linspace(0, t_max, 100)
    y_ = z[0]*t_**2 + z[1]*t_ + z[2]

    fig, ax = plt.subplots()
    plt.plot(t_, y_, t, y, 'bo')
    plt.suptitle("Tir parabòlic. Regressió quadràtica")
    plt.title("y = " + str(round(z[0],3)) + "t^2 + " + str(round(z[1],3)) + "t + " + str(round(z[2],3)) + " -> g exp = " + str(round(g_exp,3)) + " m/s^2")
    ax.set(xlabel='temps (s)', ylabel='y (m)')
    ax.grid()
    plt.show()
    
interactive_plot = interactive(f, nivell_soroll=(0.0, 2.0),  num_punts=(10, 50))
interactive_plot

Una altra cosa que m’interessa és la manera d’exportar aquests Jupyter Notebooks a una web, conservant les gràfiques i les fórmules en format Latex (encara que es perdi la interacció amb les gràfiques). Això s’aconsegueix directament exportant el Notebook a html:

$ jupyter nbconvert --execute tir_parabolic.ipynb --to html

i integrant aquest codi en una web on hi hagi més text i explicacions, i amb la llibreria Bootstrap.

Introducció a Jupyter Notebooks

Ja feia temps que tenia ganes de mirar què és això de Jupyter Notebook, que se n’està parlant i cada cop se’n parlarà més. Aquest és el primer exemple que faig, la solució de l’equació de 2n grau amb python i la llibreria sympy, que he agafat d’una pàgina que m’agrada molt: arachnoid.com.

El següent pas serà mirar Jupyter Lab, que és una interfície més moderna, i tinc ganes de jugar amb widgets i sliders per poder fer coses més interactives. Ara que estic programant bastant amb Python per preparar exemples per les classes de CNED a la UPC, fer-ho amb les Notebooks de Jupyter seria una manera molt puntera de fer classes interactives.

Referències:

Extreure informació d’un track gpx

Estava fent un petit script amb NodeJS per extreure la informació dels meus tracks de BTT. Aquesta és la informació bàsica que es pot extreure:

$ node xml_stats.js ../rutesgps/montnegreopenmtb_32.gpx
track: ../rutesgps/montnegreopenmtb_32.gpx
2020-11-05
29.4 Km (distància total)
02:25:40 (temps en moviment)
02:58:01 (temps total)
1121 m (desnivell acumulat)
886 m (desnivell acumulat amb filtre)
143m -> 650m (altitud min and max)

La dificultat principal està en entendre què significa i com es calcula el desnivell acumulat. Posem per cas una excursió bastant planera com fer tot el Passeig de les Aigües de Barcelona. Tenint en compte que la resolució del meu GPS és de 1 metre (sense decimals), el fet de recórrer una superfície plana fa que es vagi acumulant els metres de desnivell d’una manera exagerada (encara que el GPS tingués més resolució també passaria). El primer que hauríem de fer és recalcular les elevacions del meu track amb algun servei online que doni les altures exactes, i amb algun decimal. Després, la solució passa per filtrar les dades, fer un suavitzat, és a dir, fer una mitjana. Per exemple, per cada punt agafem el valor de l’elevació fent la mitjana entre el punt actual i els punts anterior i posterior. Seria una mitjana de tres punts. Com que cada punt es grava als 4 segons, seria una mitjana de 12 segons. Ara bé, puc fer filtrats de 5, 7, 9 o 11 punts, i dóna com a resultat valors de pendent acumulat cada vegada més petits. Quin criteri seguir? El cas és que els diferents sistemes (el meu GPS, el wikiloc, etc…) donen valors diferents. Això fa que la mesura de l’elevació acumulada en una excursió no sigui una mesura massa fiable. Aquest efecte no és massa problemàtic en les excursions amb baixades i pujades llargues i constants. Per contra, amb excursions amb zones planes i terreny irregular l’efecte s’acumula més.

Tots aquests càlculs donen peu a programar un altre script per calcular pujades on podem definir unes cronoescalades, pujades que es van repetint en els entrenaments i es podrà extreure informació per comparar. En parlarem en el proper post…

La Casa de Papel: aplicació web

Aquest és un exemple que he fet mano a mano amb el Pere, ara que estem confinats per la COVID-19 i estem a la meitat de la 3a temporada de La Casa de Papel.

Per a mi també ha servit per fer una aplicació OpenLayers amb codi Node, que sembla ser que tot anirà cap aquí. Tot està explicat a la wiki i als enllaços a què fa referència.

La renderització que s’ha fet del mapa amb blanc i negre és l’estil toner de Stamen. A mi particularment m’agrada molt, i crec que hem aconseguit una bona integració amb el disseny propi de la sèrie, que juga amb els colors negre i vermell.
Enllaços: