Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

uodate #1

Open
wants to merge 24 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -4,3 +4,4 @@ example_georouting.ipynb
arc_layer.html
arc_layer.json
test.py
.ipynb_checkpoints/routing_app-checkpoint.ipynb
9,020 changes: 9,020 additions & 0 deletions 10k_us_routing_test.csv

Large diffs are not rendered by default.

44,981 changes: 44,981 additions & 0 deletions 4.5k_test_data.csv

Large diffs are not rendered by default.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -2,9 +2,9 @@ FROM condaforge/mambaforge
COPY environment.yml environment.yml
RUN mamba env update -n base -f environment.yml

COPY routing_app.ipynb routing_app.ipynb
COPY routing_app.py routing_app.py
# RUN my app panel serve --port 5006 --address 0.0.0.0 --allow-websocket-origin=199.94.60.108:5006 routing_app.ipynb
CMD ["panel", "serve", "--port", "5006", "--address", "0.0.0.0", "--allow-websocket-origin","routing-ui-gis-data-science-big-data-projects-at-cga.apps.shift.nerc.mghpcc.org", "routing_app.ipynb"]
CMD ["panel", "serve", "--port", "5006", "--address", "0.0.0.0", "--num-threads", "10", "--allow-websocket-origin","routing-ui-gis-data-science-big-data-projects-at-cga.apps.shift.nerc.mghpcc.org", "routing_app.py"]
# expose the port 5006
EXPOSE 5006

Binary file added output.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
82 changes: 48 additions & 34 deletions readme.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,46 @@



## Create a env
# Routing App

## How to run locally

### Create a env
```bash
conda env create --file environment.yml
```
## Run the App
### Run the App

```bash
conda activate routing_app
# panel serve testing_app.ipynb
panel serve --port 5006 --address 0.0.0.0 --allow-websocket-origin=199.94.60.108:5006 testing_app.ipynb
panel serve --port 5006 routing_app.py
```

## Docker deployment
## How to run using docker

### build and run the docker image

change CMD commands in Dockerfile and run,

```bash
docker build -t routing_app:0.1 .
docker run -p 5006:5006 routing_app:0.1
```

## backend
### build and push the docker image to docker hub

push to docker hub, please change the happybeetles to your own user name, you need login to Dockerhub both in your terminal, you need create a repo called routing_app in your docker hub.

```bash
docker build --platform=linux/amd64 -t routing_app:1.3 .
docker tag routing_app:1.3 happybeetles/routing_app
docker push happybeetles/routing_app
```

## About the backend

For the whole planet service, you can following these steps,

1. Download the planet.osm.pbf file from [here](https://download.bbbike.org/osm/planet/)
2. follow the instruction [here](https://github.com/Project-OSRM/osrm-backend)
@@ -31,47 +51,41 @@ wget https://download.bbbike.org/osm/planet/planet-latest.osm.pbf
```

```bash
# install docker in ubuntu
sudo apt-get update
sudo apt-get install ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
echo \
"deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
"$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin

# docker-compose-plugin

sudo apt-get update
# sudo apt-get install docker-compose-plugin

sudo docker run hello-world
# docker compose version

# it may take a while
# sudo docker run -t -v "${PWD}:/data" ghcr.io/project-osrm/osrm-backend osrm-extract -p /opt/car.lua /data/planet-latest.osm.pbf || echo "osrm-extract failed"
```

## Deployment in openshift

```bash
# it may take a while
# sudo docker run -t -v "${PWD}:/data" ghcr.io/project-osrm/osrm-backend osrm-extract -p /opt/car.lua /data/planet-latest.osm.pbf || echo "osrm-extract failed"
1. Deploy the backend first, you can do it using the Openshift web portal to deploy the backend from [this Github repo](https://github.com/wybert/routing_app_service).
2. Please find the backend service ip address in the Openshift web portal by click on the pod's name, and update the backend service ip address in the `routing_app.py` file. change the following line in the `routing_app.py` file.

```python

# create a router object
router = OSRMRouter(mode="driving",
base_url="http://<ip_address_of_the_backend_service>:5000"
)

```

use the this url for openshift deployment
3. Build the Docker image and push it to the docker hub. You can use the following command to build the docker image.

```bash
routing-ui-gis-data-science-big-data-projects-at-cga.apps.shift.nerc.mghpcc.org
docker build --platform=linux/amd64 -t routing_app:1.3 .
docker tag routing_app:1.3 happybeetles/routing_app
docker push happybeetles/routing_app
```

You need to login to your own docker hub account before you can push the image to the docker hub. My docker hub account is `happybeetles`, you need to change it to your own docker hub account.

4. Deploy the frontend using the Openshift web portal from the Docker image you just pushed to the docker hub. For Openshift setting, you need use this url `routing-ui-gis-data-science-big-data-projects-at-cga.apps.shift.nerc.mghpcc.org` for the frontend service

5. Once done, visit the frontend service url `routing-ui-gis-data-science-big-data-projects-at-cga.apps.shift.nerc.mghpcc.org`, you should be able to see the frontend.

## Tips

Create a biger swap file, please refer to [here](https://webapp.chatgpt4google.com/s/MTk2Njgw)
If you don't have enough memory, you may need to create a swap file. Create a biger swap file, please refer to [here](https://webapp.chatgpt4google.com/s/MTk2Njgw)


## To do

- [ ] add the backend
172 changes: 172 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
affine @ file:///home/conda/feedstock_root/build_artifacts/affine_1674245120525/work
ansible==8.5.0
ansible-core==2.15.5
anyio @ file:///home/conda/feedstock_root/build_artifacts/anyio_1717693030552/work
appnope @ file:///home/conda/feedstock_root/build_artifacts/appnope_1707233003401/work
argon2-cffi @ file:///home/conda/feedstock_root/build_artifacts/argon2-cffi_1692818318753/work
argon2-cffi-bindings @ file:///Users/runner/miniforge3/conda-bld/argon2-cffi-bindings_1695386618041/work
arrow @ file:///home/conda/feedstock_root/build_artifacts/arrow_1696128962909/work
asttokens==2.4.1
async-lru @ file:///home/conda/feedstock_root/build_artifacts/async-lru_1690563019058/work
attrs @ file:///home/conda/feedstock_root/build_artifacts/attrs_1704011227531/work
Babel @ file:///home/conda/feedstock_root/build_artifacts/babel_1702422572539/work
beautifulsoup4 @ file:///home/conda/feedstock_root/build_artifacts/beautifulsoup4_1705564648255/work
bleach @ file:///home/conda/feedstock_root/build_artifacts/bleach_1696630167146/work
bokeh @ file:///home/conda/feedstock_root/build_artifacts/bokeh_1712901085037/work
branca @ file:///home/conda/feedstock_root/build_artifacts/branca_1714071803448/work
Brotli @ file:///Users/runner/miniforge3/conda-bld/brotli-split_1695989934239/work
cached-property @ file:///home/conda/feedstock_root/build_artifacts/cached_property_1615209429212/work
certifi @ file:///home/conda/feedstock_root/build_artifacts/certifi_1718025014955/work/certifi
cffi @ file:///Users/runner/miniforge3/conda-bld/cffi_1696001836291/work
charset-normalizer @ file:///home/conda/feedstock_root/build_artifacts/charset-normalizer_1698833585322/work
click @ file:///home/conda/feedstock_root/build_artifacts/click_1692311806742/work
click-plugins==1.1.1
cligj @ file:///home/conda/feedstock_root/build_artifacts/cligj_1633637764473/work
colorama @ file:///home/conda/feedstock_root/build_artifacts/colorama_1666700638685/work
comm @ file:///home/conda/feedstock_root/build_artifacts/comm_1710320294760/work
contourpy @ file:///Users/runner/miniforge3/conda-bld/contourpy_1712429967442/work
cycler @ file:///home/conda/feedstock_root/build_artifacts/cycler_1696677705766/work
debugpy @ file:///Users/runner/miniforge3/conda-bld/debugpy_1707444580667/work
decorator==5.1.1
defusedxml @ file:///home/conda/feedstock_root/build_artifacts/defusedxml_1615232257335/work
entrypoints @ file:///home/conda/feedstock_root/build_artifacts/entrypoints_1643888246732/work
exceptiongroup @ file:///home/conda/feedstock_root/build_artifacts/exceptiongroup_1704921103267/work
executing==2.0.1
fastjsonschema @ file:///home/conda/feedstock_root/build_artifacts/python-fastjsonschema_1703780968325/work/dist
fiona @ file:///Users/runner/miniforge3/conda-bld/fiona_1716309384790/work
folium @ file:///home/conda/feedstock_root/build_artifacts/folium_1709209270269/work
fonttools @ file:///Users/runner/miniforge3/conda-bld/fonttools_1717209203186/work
fqdn @ file:///home/conda/feedstock_root/build_artifacts/fqdn_1638810296540/work/dist
GDAL @ file:///Users/runner/miniforge3/conda-bld/gdal-split_1717860743402/work/build/swig/python
geopandas @ file:///home/conda/feedstock_root/build_artifacts/geopandas_1697031985100/work
georouting @ file:///home/conda/feedstock_root/build_artifacts/georouting_1678989447936/work
googlemaps @ file:///home/conda/feedstock_root/build_artifacts/googlemaps_1712366543757/work
h11 @ file:///home/conda/feedstock_root/build_artifacts/h11_1664132893548/work
h2 @ file:///home/conda/feedstock_root/build_artifacts/h2_1634280454336/work
hpack==4.0.0
httpcore @ file:///home/conda/feedstock_root/build_artifacts/httpcore_1711596990900/work
httpx @ file:///home/conda/feedstock_root/build_artifacts/httpx_1708530890843/work
hyperframe @ file:///home/conda/feedstock_root/build_artifacts/hyperframe_1619110129307/work
idna @ file:///home/conda/feedstock_root/build_artifacts/idna_1713279365350/work
igraph @ file:///Users/runner/miniforge3/conda-bld/python-igraph_1718350614200/work
importlib_metadata @ file:///home/conda/feedstock_root/build_artifacts/importlib-metadata_1710971335535/work
importlib_resources @ file:///home/conda/feedstock_root/build_artifacts/importlib_resources_1711040877059/work
ipykernel @ file:///Users/runner/miniforge3/conda-bld/ipykernel_1717717537056/work
ipython==8.22.1
ipywidgets @ file:///home/conda/feedstock_root/build_artifacts/ipywidgets_1716897651763/work
isoduration @ file:///home/conda/feedstock_root/build_artifacts/isoduration_1638811571363/work/dist
jedi==0.19.1
Jinja2 @ file:///home/conda/feedstock_root/build_artifacts/jinja2_1715127149914/work
joblib @ file:///home/conda/feedstock_root/build_artifacts/joblib_1714665484399/work
json5 @ file:///home/conda/feedstock_root/build_artifacts/json5_1712986206667/work
jsonpointer @ file:///Users/runner/miniforge3/conda-bld/jsonpointer_1718283413196/work
jsonschema @ file:///home/conda/feedstock_root/build_artifacts/jsonschema-meta_1714573116818/work
jsonschema-specifications @ file:///tmp/tmpkv1z7p57/src
jupyter @ file:///home/conda/feedstock_root/build_artifacts/jupyter_1696255489086/work
jupyter-console @ file:///home/conda/feedstock_root/build_artifacts/jupyter_console_1678118109161/work
jupyter-events @ file:///home/conda/feedstock_root/build_artifacts/jupyter_events_1710805637316/work
jupyter-lsp @ file:///home/conda/feedstock_root/build_artifacts/jupyter-lsp-meta_1712707420468/work/jupyter-lsp
jupyter_bokeh @ file:///home/conda/feedstock_root/build_artifacts/jupyter_bokeh_1717410525108/work
jupyter_client @ file:///home/conda/feedstock_root/build_artifacts/jupyter_client_1716472197302/work
jupyter_core @ file:///Users/runner/miniforge3/conda-bld/jupyter_core_1710257334907/work
jupyter_server @ file:///home/conda/feedstock_root/build_artifacts/jupyter_server_1717122053158/work
jupyter_server_terminals @ file:///home/conda/feedstock_root/build_artifacts/jupyter_server_terminals_1710262634903/work
jupyterlab @ file:///home/conda/feedstock_root/build_artifacts/jupyterlab_1718030272761/work
jupyterlab_pygments @ file:///home/conda/feedstock_root/build_artifacts/jupyterlab_pygments_1707149102966/work
jupyterlab_server @ file:///home/conda/feedstock_root/build_artifacts/jupyterlab_server-split_1716433953404/work
jupyterlab_widgets @ file:///home/conda/feedstock_root/build_artifacts/jupyterlab_widgets_1716891641122/work
kiwisolver @ file:///Users/runner/miniforge3/conda-bld/kiwisolver_1695380058985/work
linkify-it-py @ file:///home/conda/feedstock_root/build_artifacts/linkify-it-py_1707129103613/work
mapclassify @ file:///home/conda/feedstock_root/build_artifacts/mapclassify_1696563523338/work
Markdown @ file:///home/conda/feedstock_root/build_artifacts/markdown_1710435156458/work
markdown-it-py @ file:///home/conda/feedstock_root/build_artifacts/markdown-it-py_1686175045316/work
MarkupSafe @ file:///Users/runner/miniforge3/conda-bld/markupsafe_1706900210234/work
matplotlib @ file:///Users/runner/miniforge3/conda-bld/matplotlib-suite_1715976190777/work
matplotlib-inline==0.1.6
mdit-py-plugins @ file:///home/conda/feedstock_root/build_artifacts/mdit-py-plugins_1715570196093/work
mdurl @ file:///home/conda/feedstock_root/build_artifacts/mdurl_1704317613764/work
mistune @ file:///home/conda/feedstock_root/build_artifacts/mistune_1698947099619/work
munkres==1.1.4
nbclient @ file:///home/conda/feedstock_root/build_artifacts/nbclient_1710317608672/work
nbconvert @ file:///home/conda/feedstock_root/build_artifacts/nbconvert-meta_1718135430380/work
nbformat @ file:///home/conda/feedstock_root/build_artifacts/nbformat_1712238998817/work
nest_asyncio @ file:///home/conda/feedstock_root/build_artifacts/nest-asyncio_1705850609492/work
networkx @ file:///home/conda/feedstock_root/build_artifacts/networkx_1712540363324/work
notebook @ file:///home/conda/feedstock_root/build_artifacts/notebook_1717767745914/work
notebook_shim @ file:///home/conda/feedstock_root/build_artifacts/notebook-shim_1707957777232/work
numpy==1.26.4
osmnx @ file:///home/conda/feedstock_root/build_artifacts/osmnx_1714607798464/work
overrides @ file:///home/conda/feedstock_root/build_artifacts/overrides_1706394519472/work
packaging @ file:///home/conda/feedstock_root/build_artifacts/packaging_1718189413536/work
pandas @ file:///Users/runner/miniforge3/conda-bld/pandas_1715897646986/work
pandocfilters @ file:///home/conda/feedstock_root/build_artifacts/pandocfilters_1631603243851/work
panel @ file:///home/conda/feedstock_root/build_artifacts/panel_1717330154395/work
param @ file:///home/conda/feedstock_root/build_artifacts/param_1711102884605/work
parso==0.8.3
pexpect==4.9.0
pickleshare @ file:///home/conda/feedstock_root/build_artifacts/pickleshare_1602536217715/work
pillow @ file:///Users/runner/miniforge3/conda-bld/pillow_1712154828646/work
pkgutil_resolve_name @ file:///home/conda/feedstock_root/build_artifacts/pkgutil-resolve-name_1694617248815/work
platformdirs @ file:///home/conda/feedstock_root/build_artifacts/platformdirs_1715777629804/work
polyline @ file:///home/conda/feedstock_root/build_artifacts/polyline_1707840342902/work
prometheus_client @ file:///home/conda/feedstock_root/build_artifacts/prometheus_client_1707932675456/work
prompt-toolkit==3.0.43
psutil @ file:///Users/runner/miniforge3/conda-bld/psutil_1705722524070/work
ptyprocess==0.7.0
pure-eval==0.2.2
pycparser @ file:///home/conda/feedstock_root/build_artifacts/pycparser_1711811537435/work
pydeck @ file:///home/conda/feedstock_root/build_artifacts/pydeck_1667589451974/work
Pygments==2.17.2
pyobjc-core @ file:///Users/runner/miniforge3/conda-bld/pyobjc-core_1710590539120/work
pyobjc-framework-Cocoa @ file:///Users/runner/miniforge3/conda-bld/pyobjc-framework-cocoa_1710597222858/work
pyparsing @ file:///home/conda/feedstock_root/build_artifacts/pyparsing_1709721012883/work
pyproj @ file:///Users/runner/miniforge3/conda-bld/pyproj_1717792595780/work
PySocks @ file:///home/conda/feedstock_root/build_artifacts/pysocks_1661604839144/work
python-dateutil==2.8.2
python-json-logger @ file:///home/conda/feedstock_root/build_artifacts/python-json-logger_1677079630776/work
pytz==2024.1
pyviz_comms @ file:///home/conda/feedstock_root/build_artifacts/pyviz_comms_1715168266915/work
PyYAML @ file:///Users/runner/miniforge3/conda-bld/pyyaml_1695373486380/work
pyzmq @ file:///Users/runner/miniforge3/conda-bld/pyzmq_1715024416831/work
qtconsole @ file:///home/conda/feedstock_root/build_artifacts/qtconsole-base_1714942934316/work
QtPy @ file:///home/conda/feedstock_root/build_artifacts/qtpy_1698112029416/work
rasterio @ file:///Users/runner/miniforge3/conda-bld/rasterio_1717805662187/work
referencing @ file:///home/conda/feedstock_root/build_artifacts/referencing_1714619483868/work
requests @ file:///home/conda/feedstock_root/build_artifacts/requests_1717057054362/work
resolvelib==1.0.1
rfc3339-validator @ file:///home/conda/feedstock_root/build_artifacts/rfc3339-validator_1638811747357/work
rfc3986-validator @ file:///home/conda/feedstock_root/build_artifacts/rfc3986-validator_1598024191506/work
rpds-py @ file:///Users/runner/miniforge3/conda-bld/rpds-py_1715090021953/work
Rtree @ file:///Users/runner/miniforge3/conda-bld/rtree_1718099355235/work
scikit-learn @ file:///Users/runner/miniforge3/conda-bld/scikit-learn_1716489819945/work/dist/scikit_learn-1.5.0-cp311-cp311-macosx_11_0_arm64.whl#sha256=bb3914400d18d942dcd04ea91b396d2d8a07c8ad6fa9b34806f1d98ac269a53d
scipy @ file:///Users/runner/miniforge3/conda-bld/scipy-split_1716470269703/work/dist/scipy-1.13.1-cp311-cp311-macosx_11_0_arm64.whl#sha256=0e992411e098e6c56acf32e04ea202871e054f8704758df24c8626bddcd00250
Send2Trash @ file:///Users/runner/miniforge3/conda-bld/send2trash_1712585336584/work
shapely @ file:///Users/runner/miniforge3/conda-bld/shapely_1715876483406/work
six==1.16.0
sniffio @ file:///home/conda/feedstock_root/build_artifacts/sniffio_1708952932303/work
snuggs==1.4.7
soupsieve @ file:///home/conda/feedstock_root/build_artifacts/soupsieve_1693929250441/work
stack-data==0.6.3
stata_setup==0.1.3
terminado @ file:///Users/runner/miniforge3/conda-bld/terminado_1710263781917/work
texttable @ file:///home/conda/feedstock_root/build_artifacts/texttable_1696407540773/work
threadpoolctl @ file:///home/conda/feedstock_root/build_artifacts/threadpoolctl_1714400101435/work
tinycss2 @ file:///home/conda/feedstock_root/build_artifacts/tinycss2_1713974937325/work
tomli @ file:///home/conda/feedstock_root/build_artifacts/tomli_1644342247877/work
tornado @ file:///Users/runner/miniforge3/conda-bld/tornado_1717722724710/work
tqdm @ file:///home/conda/feedstock_root/build_artifacts/tqdm_1691671248568/work
traitlets==5.14.1
types-python-dateutil @ file:///home/conda/feedstock_root/build_artifacts/types-python-dateutil_1710589910274/work
typing-utils @ file:///home/conda/feedstock_root/build_artifacts/typing_utils_1622899189314/work
typing_extensions @ file:///home/conda/feedstock_root/build_artifacts/typing_extensions_1717802530399/work
tzdata==2024.1
uc-micro-py @ file:///home/conda/feedstock_root/build_artifacts/uc-micro-py_1707507364877/work
uri-template @ file:///home/conda/feedstock_root/build_artifacts/uri-template_1688655812972/work/dist
urllib3 @ file:///home/conda/feedstock_root/build_artifacts/urllib3_1708239446578/work
wcwidth==0.2.13
webcolors @ file:///home/conda/feedstock_root/build_artifacts/webcolors_1717667289718/work
webencodings @ file:///home/conda/feedstock_root/build_artifacts/webencodings_1694681268211/work
websocket-client @ file:///home/conda/feedstock_root/build_artifacts/websocket-client_1713923384721/work
widgetsnbextension @ file:///home/conda/feedstock_root/build_artifacts/widgetsnbextension_1716891659446/work
xyzservices @ file:///home/conda/feedstock_root/build_artifacts/xyzservices_1717752109663/work
zipp @ file:///home/conda/feedstock_root/build_artifacts/zipp_1718013267051/work
710 changes: 0 additions & 710 deletions routing_app.ipynb

This file was deleted.

297 changes: 297 additions & 0 deletions routing_app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,297 @@
import panel as pn
import pandas as pd
import numpy as np
import json

pn.extension('deckgl')
import pydeck as pdk
file_input = pn.widgets.FileInput(accept='.csv', name='Upload CSV')
GREEN_RGB = [0, 255, 0, 90]
RED_RGB = [240, 100, 0, 90]
MAPBOX_KEY = "pk.eyJ1Ijoid3liZXJ0IiwiYSI6ImNrYjk0bnpkdjBhczAycm84OWczMGFseDcifQ.icmgMlugfJ8erQ-JKmovWQ"
# geoview
arc_layer = pdk.Layer(
"ArcLayer",
# data=df,
# get_width="S000 * 60",
get_width="2",
# set arc width

# get_source_position=["origin_lon", "origin_lat"],
# get_target_position=["dest_lon", "dest_lat"],
get_tilt=15,
get_source_color=RED_RGB,
get_target_color=GREEN_RGB,
pickable=True,
auto_highlight=True,
)
r = pdk.Deck(arc_layer)
json_spec = json.loads(r.to_json())
deck_gl = pn.pane.DeckGL(json_spec, mapbox_api_key=MAPBOX_KEY,
sizing_mode='stretch_width',
# sizing_mode='stretch_both',
height=660
)

def load_csv(data):
import io
if data is not None:
global df
df = pd.read_csv(io.BytesIO(data))
return pn.Column("There are %d od pairs that need to be calculated"%df.shape[0])

active_load_csv = pn.bind(load_csv, file_input.param.value)


from bokeh.models import TextInput, Tooltip
from bokeh.models.dom import HTML
html_tooltip = Tooltip(content=HTML("""<p>The input CSV must have at least 4 columns named:</p>
<ul>
<li><code>origin_lon</code></li>
<li><code>origin_lat</code></li>
<li><code>dest_lon</code></li>
<li><code>dest_lat</code> </li>
</ul>
<p>for origin and destination longitude and latitude respectively.</p>
<p>a sample can be found <a href="https://raw.githubusercontent.com/wybert/routing_app/main/sample_3.csv">here</a></p>
"""), position="right")

# html_tooltip = """<p>The input CSV must have at least 4 columns named <code>origin_lon</code>, <code>origin_lat</code>, <code>dest_lon</code>, <code>dest_lat</code> for origin and destination longitude and latitude respectively, a sample can be found <a href="https://raw.githubusercontent.com/spatial-data-lab/data/main/sample_3.csv">here</a></p>
# """
input_data_tool_tips = pn.widgets.TooltipIcon(value=html_tooltip)


sel_data_desc = pn.pane.Markdown("""## 1. Upload the CSV file
The input CSV must have at least 4 columns named `origin_lon`,`origin_lat`,`dest_lon` and `dest_lat` for origin and destination longitude and latitude respectively, a small sample can be found [here](https://raw.githubusercontent.com/spatial-data-lab/data/main/sample_3.csv).""")
data_upload_view = pn.Column(pn.Row(sel_data_desc),file_input,active_load_csv)


from georouting.routers import OSRMRouter
from panel.widgets import Tqdm
tqdm = Tqdm(width=300)
# create a router object
router = OSRMRouter(mode="driving",
# base_url="http://172.30.232.152:5000"
)

def calculate_distance(run):
if not run:
yield "> 💡 Once the calulation is done, you can download the result here :)"
return
# import gevent
for k,v in tqdm(df.iterrows(), total=df.shape[0],colour='#408558'):
origin = ( v["origin_lat"],v["origin_lon"])
destination = ( v["dest_lat"],v["dest_lon"])
route = router.get_route(origin, destination)
df.loc[k, 'distance (m)'] = route.get_distance()
df.loc[k, 'duration (s)'] = route.get_duration()

final_table = pn.pane.DataFrame(df.head(3),
sizing_mode='stretch_width'
)

import numpy as np
if df.shape[0] > 10000:
df_map = df.sample(10000, random_state=36)
else:
df_map = df
v1 = df_map[["origin_lon", "origin_lat"]].values
v2 = df_map[["dest_lon", "dest_lat"]].values
v = np.concatenate([v1, v2])
v_df_map = pd.DataFrame(v, columns=["lon", "lat"])
data_view = pdk.data_utils.compute_view(v_df_map[["lon", "lat"]])
view_state = pdk.ViewState(
longitude=data_view.longitude, latitude=data_view.latitude, zoom= data_view.zoom, bearing=0, pitch=45
)
arc_layer = pdk.Layer(
"ArcLayer",
data=df_map,
# get_width="S000 * 60",
get_width="2",
# set arc width

get_source_position=["origin_lon", "origin_lat"],
get_target_position=["dest_lon", "dest_lat"],
get_tilt=15,
get_source_color=RED_RGB,
get_target_color=GREEN_RGB,
pickable=True,
auto_highlight=True,
)
TOOLTIP_TEXT = {"html": "<br /> Source location in red; Destination location in green"}
r = pdk.Deck(arc_layer, initial_view_state=view_state, tooltip=TOOLTIP_TEXT,description="<h2>Taxi Trip Type</h2>")

json_spec = json.loads(r.to_json())
deck_gl.object = json_spec
deck_gl.param.trigger('object')


from io import StringIO
sio = StringIO()
df.to_csv(sio)
sio.seek(0)
download_view = pn.widgets.FileDownload(sio,
embed=True,
filename='results.csv',
# sizing_mode='stretch_width',
button_type='success',
# text = "Download the result",
# colour='#408558',
# height=34,

)
results_desc = pn.pane.Markdown("""## 2. Downlaod the result
The output is a CSV with added `distance (m)` and `duration (s)` columns for route distance in meters and drive time in seconds. The table below shows the first 3 rows of the result. """,sizing_mode='stretch_width')


from bokeh.models import TextInput, Tooltip
from bokeh.models.dom import HTML
html_tooltip = Tooltip(content=HTML("""<p>The output is a CSV with added </p>
<ul>
<li><code>distance (m)</code></li>
<li><code>duration (s)</code> </li>
</ul>
<p>columns for route distance in meters and drive time in seconds.</p>
<p>We use <a href="http://project-osrm.org/">OSRM</a> with a Multi-Level Dijkstra algorithm to find the route</p>
<p>The table below shows the first 3 rows of the result</p>
"""), position="right")

# html_tooltip = """<p>The input CSV must have at least 4 columns named <code>origin_lon</code>, <code>origin_lat</code>, <code>dest_lon</code>, <code>dest_lat</code> for origin and destination longitude and latitude respectively, a sample can be found <a href="https://raw.githubusercontent.com/spatial-data-lab/data/main/sample_3.csv">here</a></p>
# """
output_data_tool_tips = pn.widgets.TooltipIcon(value=html_tooltip)


table_download_view = pn.Column(results_desc,final_table,download_view)

yield table_download_view


run = pn.widgets.Button(name="Calculate",
# button_type='primary',
# button_type='warning',
# button_type='success',
button_type='danger',

)

run_and_download = pn.Column(run, tqdm, pn.bind(calculate_distance, run))


intro = pn.pane.Markdown("""<center>
<img src="https://raw.githubusercontent.com/wybert/routing_app/main/DALL·E%202023-10-21%2010.53.23%20-%20Photo%20logo%20with%20a%20clear%20image%20of%20the%20earth.%20Circling%20the%20globe%20is%20a%20blazing%20comet%2C%20emphasizing%20rapid%20movement.%20Two%20distinct%20points%20on%20the%20globe%20mark%20t.png" alt="drawing" style="width:123px;"/>
This app computes distance and duration between two points from a CSV with origin and destination longitudes and latitudes using [OSRM](http://project-osrm.org/).
</center>
""",
sizing_mode='stretch_width'
)



from bokeh.models import TextInput, Tooltip
from bokeh.models.dom import HTML
html_tooltip = Tooltip(content=HTML("""<p>We use <a href="http://project-osrm.org/">OSRM</a> with a Multi-Level Dijkstra algorithm to find the route. </p>
<p>For comparison with other routing engines, like </p>
<ul>
<li>Google Maps</li>
<li>Bing Maps</li>
<li>ESRI Routing service</li>
</ul>
<p>please check <a href="https://isprs-archives.copernicus.org/articles/XLVIII-4-W7-2023/53/2023/">our paper</a> on FOSS4G 2023. </p>
"""), position="right")

# html_tooltip = """<p>The input CSV must have at least 4 columns named <code>origin_lon</code>, <code>origin_lat</code>, <code>dest_lon</code>, <code>dest_lat</code> for origin and destination longitude and latitude respectively, a sample can be found <a href="https://raw.githubusercontent.com/spatial-data-lab/data/main/sample_3.csv">here</a></p>
# """
cite_tool_tips = pn.widgets.TooltipIcon(value=html_tooltip)


cite_text = pn.pane.Markdown("""👉 Please cite [our paper](https://isprs-archives.copernicus.org/articles/XLVIII-4-W7-2023/53/2023/) if you use this app for your research, for comparison with other routing engines, like Google Maps, Bing Maps, ESRI Routing service etc., please check [our paper](https://isprs-archives.copernicus.org/articles/XLVIII-4-W7-2023/53/2023/) on FOSS4G 2023.
""",
sizing_mode='stretch_width'
)

cite = pn.Row(cite_tool_tips,cite_text)

acknowledge = pn.pane.Markdown("""❤️ This app is built with [OSRM](http://project-osrm.org/), [Panel](https://panel.holoviz.org/), [Georouting](https://github.com/wybert/georouting), [Pydeck.gl](https://pydeck.gl/) and hosted in [New England Research Cloud (NERC)](https://nerc.mghpcc.org/). The road network data is from [OpenStreetMap](https://www.openstreetmap.org/).""")


green = pn.Spacer(styles=dict(background='#408558'),width=33,height=16,align='center')
red = pn.Spacer(styles=dict(background='#CB444A'),width=33,height=16,align='center')
map_legend = pn.Column(
# pn.pane.Markdown("### The arc map of the source and destination points, The map can only show 10000 rows at most",align='end'),
pn.Row(red,"Source locations",
green,"Destination locations"),
# pn.pane.Markdown("The arc map of the source and destination points, The map can only show 10000 rows at most",align='end'),
align='end'
)


contribute_contacts = pn.Row(pn.pane.Markdown("""©️ This app is developed by [Xiaokang Fu](https://gis.harvard.edu/people/xiaokang-fu) and [Devika Jain](https://gis.harvard.edu/people/devika-kakkar) from Harvard CGA. &nbsp;&nbsp; ✉️ Please contact [Harvard CGA](mailto:kakkar@fas.harvard.edu) for any questions.
"""),
# pn.layout.Spacer(), align='start',
# height=15,
)



app = pn.Column(
intro,
data_upload_view,
run_and_download,
# cite
)


cga_logo = pn.pane.PNG(
'https://gis.harvard.edu/sites/projects.iq.harvard.edu/files/gis/files/cga_pin_logo_grayback.png',
link_url='https://gis.harvard.edu/', height=43, align='center'
)

iqss_logo = pn.pane.PNG(
'https://www.iq.harvard.edu/files/harvard-iqss/files/iq-logo-white_alt.png',
link_url='https://www.iq.harvard.edu/', height=33, align='center'
)

# theme_switcher = pn.widgets.Switch(name='theme')
logos = pn.Row(pn.layout.HSpacer(),cga_logo)

main_view = pn.Column(
# pn.Row(pn.layout.HSpacer(),pn.pane.Markdown("## The arc map of the source and destination points, it only show 10000 rows at most"),pn.layout.HSpacer()),
# deck_gl,
pn.Row(pn.pane.Markdown("### The arc map of the source and destination points. It shows 10000 rows at most"), pn.layout.HSpacer(),map_legend),
deck_gl,
# pn.layout.Divider(),
contribute_contacts,
# acknowledge

# sizing_mode='stretch_height'
)
# Instantiate the template with widgets displayed in the sidebar
# template = pn.template.GoldenTemplate(
# template = pn.template.FastListTemplate(
# template = pn.template.ReactTemplate(
# template = pn.template.BootstrapTemplate(
# template = pn.template.SlidesTemplate(
# template = pn.template.VanillaTemplate(
template = pn.template.MaterialTemplate(
title='RapidRoute',
# logo='https://dssg.fas.harvard.edu/wp-content/uploads/2017/12/CGA_logo_globe_400x400.jpg',
favicon = 'https://dssg.fas.harvard.edu/wp-content/uploads/2017/12/CGA_logo_globe_400x400.jpg',
header_background = '#212121',
# header_background = '#222529',
# header_background = '#35363A',
header_color = '#2F6DAA',
# header_color = '#408558',
# neutral_color = '#408558',
# accent_base_color = '#408558',s
header=[logos],
sidebar=[app,cite_text,acknowledge],
main=main_view,
theme="dark"
# sidebar_footer = """Xiao""",
# busy_indicator=pn.indicators.BooleanStatus(value=False)

)

template.servable()
8 changes: 4 additions & 4 deletions sample_3.csv
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
,OID_,AHA_ID_lon,AHA_ID_lat,ZIP_lon,ZIP_lat,GIS_ID,Google Map,Bing Map,ESRI,OSRM
6010,3127,-73.91651806999998,42.81997773,-72.605400453,42.376239033,3127,113.43333333333334,109.7667,117.13012960361718,143.99666666666664
5333,988,-72.68278784,41.75384063,-72.967189321,42.293923206,988,76.96666666666667,72.7833,84.36433677944086,92.51
7678,1701,-74.21249992,40.70932005,-72.58532499999998,42.15852,1701,170.98333333333332,158.2333,194.62996530488303,205.22333333333333
OID_,dest_lon,dest_lat,origin_lon,origin_lat,GIS_ID
3127,-73.91651806999998,42.81997773,-72.605400453,42.376239033,3127
988,-72.68278784,41.75384063,-72.967189321,42.293923206,988
1701,-74.21249992,40.70932005,-72.58532499999998,42.15852,1701