interactive-crime yunusserhat commited on
Commit
c6b286b
0 Parent(s):

Duplicate from yunusserhat/Crime-Map

Browse files

Co-authored-by: Yunus Serhat Bıçakçı <yunusserhat@users.noreply.huggingface.co>

.gitattributes ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tflite filter=lfs diff=lfs merge=lfs -text
29
+ *.tgz filter=lfs diff=lfs merge=lfs -text
30
+ *.wasm filter=lfs diff=lfs merge=lfs -text
31
+ *.xz filter=lfs diff=lfs merge=lfs -text
32
+ *.zip filter=lfs diff=lfs merge=lfs -text
33
+ *.zst filter=lfs diff=lfs merge=lfs -text
34
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
.gitignore ADDED
@@ -0,0 +1,132 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ # *.html
6
+ private/
7
+ .vscode/
8
+
9
+ # C extensions
10
+ *.so
11
+
12
+ # Distribution / packaging
13
+ .Python
14
+ build/
15
+ develop-eggs/
16
+ dist/
17
+ downloads/
18
+ eggs/
19
+ .eggs/
20
+ lib/
21
+ lib64/
22
+ parts/
23
+ sdist/
24
+ var/
25
+ wheels/
26
+ pip-wheel-metadata/
27
+ share/python-wheels/
28
+ *.egg-info/
29
+ .installed.cfg
30
+ *.egg
31
+ MANIFEST
32
+
33
+ # PyInstaller
34
+ # Usually these files are written by a python script from a template
35
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
36
+ *.manifest
37
+ *.spec
38
+
39
+ # Installer logs
40
+ pip-log.txt
41
+ pip-delete-this-directory.txt
42
+
43
+ # Unit test / coverage reports
44
+ htmlcov/
45
+ .tox/
46
+ .nox/
47
+ .coverage
48
+ .coverage.*
49
+ .cache
50
+ nosetests.xml
51
+ coverage.xml
52
+ *.cover
53
+ *.py,cover
54
+ .hypothesis/
55
+ .pytest_cache/
56
+
57
+ # Translations
58
+ *.mo
59
+ *.pot
60
+
61
+ # Django stuff:
62
+ *.log
63
+ local_settings.py
64
+ db.sqlite3
65
+ db.sqlite3-journal
66
+
67
+ # Flask stuff:
68
+ instance/
69
+ .webassets-cache
70
+
71
+ # Scrapy stuff:
72
+ .scrapy
73
+
74
+ # Sphinx documentation
75
+ docs/_build/
76
+
77
+ # PyBuilder
78
+ target/
79
+
80
+ # Jupyter Notebook
81
+ .ipynb_checkpoints
82
+
83
+ # IPython
84
+ profile_default/
85
+ ipython_config.py
86
+
87
+ # pyenv
88
+ .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ #Pipfile.lock
96
+
97
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow
98
+ __pypackages__/
99
+
100
+ # Celery stuff
101
+ celerybeat-schedule
102
+ celerybeat.pid
103
+
104
+ # SageMath parsed files
105
+ *.sage.py
106
+
107
+ # Environments
108
+ .env
109
+ .venv
110
+ env/
111
+ venv/
112
+ ENV/
113
+ env.bak/
114
+ venv.bak/
115
+
116
+ # Spyder project settings
117
+ .spyderproject
118
+ .spyproject
119
+
120
+ # Rope project settings
121
+ .ropeproject
122
+
123
+ # mkdocs documentation
124
+ /site
125
+
126
+ # mypy
127
+ .mypy_cache/
128
+ .dmypy.json
129
+ dmypy.json
130
+
131
+ # Pyre type checker
132
+ .pyre/
.idea/.gitignore ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ # Default ignored files
2
+ /shelf/
3
+ /workspace.xml
4
+ # Editor-based HTTP Client requests
5
+ /httpRequests/
6
+ # Datasource local storage ignored files
7
+ /dataSources/
8
+ /dataSources.local.xml
.idea/Crime-Map.iml ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <module type="PYTHON_MODULE" version="4">
3
+ <component name="NewModuleRootManager">
4
+ <content url="file://$MODULE_DIR$">
5
+ <excludeFolder url="file://$MODULE_DIR$/venv" />
6
+ </content>
7
+ <orderEntry type="jdk" jdkName="Python 3.9 (venv)" jdkType="Python SDK" />
8
+ <orderEntry type="sourceFolder" forTests="false" />
9
+ </component>
10
+ <component name="PyDocumentationSettings">
11
+ <option name="format" value="PLAIN" />
12
+ <option name="myDocStringFormat" value="Plain" />
13
+ </component>
14
+ </module>
.idea/inspectionProfiles/profiles_settings.xml ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ <component name="InspectionProjectProfileManager">
2
+ <settings>
3
+ <option name="USE_PROJECT_PROFILE" value="false" />
4
+ <version value="1.0" />
5
+ </settings>
6
+ </component>
.idea/misc.xml ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.9 (venv)" project-jdk-type="Python SDK" />
4
+ </project>
.idea/modules.xml ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="ProjectModuleManager">
4
+ <modules>
5
+ <module fileurl="file://$PROJECT_DIR$/.idea/Crime-Map.iml" filepath="$PROJECT_DIR$/.idea/Crime-Map.iml" />
6
+ </modules>
7
+ </component>
8
+ </project>
.idea/vcs.xml ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="VcsDirectoryMappings">
4
+ <mapping directory="" vcs="Git" />
5
+ </component>
6
+ </project>
Application.py ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import leafmap.foliumap as leafmap
3
+
4
+ st.set_page_config(layout="wide")
5
+
6
+ st.sidebar.info(
7
+ """
8
+ - Web App URL: <https://interactive-crime-map.hf.space/>
9
+ - HuggingFace repository: <https://huggingface.co/spaces/interactive-crime/map/tree/main>
10
+ """
11
+ )
12
+
13
+ st.sidebar.title("Contact")
14
+ st.sidebar.info(
15
+ """
16
+ Yunus Serhat Bıçakçı at [yunusserhat.com](https://yunusserhat.com) | [GitHub](https://github.com/yunusserhat) | [Twitter](https://twitter.com/yunusserhat) | [LinkedIn](https://www.linkedin.com/in/yunusserhat)
17
+ """
18
+ )
19
+
20
+ st.title("Interactive Crime Map Application")
21
+
22
+ st.subheader(
23
+ """
24
+ This interactive crime map apps created using [streamlit](https://streamlit.io) and open-source mapping libraries and repositories, such as [leafmap](https://leafmap.org), [geopandas](https://geopandas.org), [streamlit-geospatial](https://huggingface.co/spaces/giswqs/Streamlit) ,and [folium](https://python-visualization.github.io/folium/).
25
+ """
26
+ )
27
+
28
+ st.info("Click on the left sidebar menu to navigate to the different apps.")
29
+
LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Yunus Serhat Bicakci
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
README.md ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Streamlit
3
+ emoji: 🔥
4
+ colorFrom: indigo
5
+ colorTo: green
6
+ sdk: streamlit
7
+ sdk_version: 1.17.0
8
+ app_file: Application.py
9
+ pinned: false
10
+ license: mit
11
+ duplicated_from: yunusserhat/Crime-Map
12
+ ---
13
+
14
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
pages/2_↔️_Comparision.py ADDED
@@ -0,0 +1,146 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import leafmap.foliumap as leafmap
3
+ import json
4
+ import requests
5
+
6
+
7
+ # Functions to dynamically fetch columns
8
+ def get_columns_from_geojson(geojson_data):
9
+ """Retrieve column names from a GeoJSON data."""
10
+ if "features" in geojson_data:
11
+ properties = geojson_data["features"][0]["properties"]
12
+ return list(properties.keys())
13
+ return []
14
+
15
+
16
+ def get_columns_from_url(url):
17
+ """Retrieve column names from a GeoJSON URL."""
18
+ response = requests.get(url)
19
+ geojson_data = response.json()
20
+ return get_columns_from_geojson(geojson_data)
21
+
22
+
23
+ st.set_page_config(layout="wide")
24
+
25
+ # Sidebar Information
26
+ st.sidebar.info(
27
+ '''
28
+ - Web App URL: <https://interactive-crime-map.hf.space/>
29
+ - HuggingFace repository: <https://huggingface.co/spaces/interactive-crime/map/tree/main>
30
+ '''
31
+ )
32
+
33
+ st.sidebar.title("Contact")
34
+ st.sidebar.info(
35
+ '''
36
+ Yunus Serhat Bıçakçı at [yunusserhat.com](https://yunusserhat.com) | [GitHub](https://github.com/yunusserhat) | [Twitter](https://twitter.com/yunusserhat) | [LinkedIn](https://www.linkedin.com/in/yunusserhat)
37
+ '''
38
+ )
39
+
40
+ # Title and Description
41
+ st.title("Interactive Analysis of Hate Metrics in London & Custom Dataset Visualization")
42
+
43
+ st.markdown(
44
+ '''
45
+ Dive into an interactive analysis of hate metrics in London, exploring the disparities and correlations between hate-related tweets and reported crimes in boroughs. This platform offers a comparative visualization based on data from X and the London Metropolitan Police Service as of December 2022.
46
+
47
+ Additionally, users can upload and visualize their own GeoJSON datasets, facilitating personalized analysis and insights. Delve deeper into the patterns of hate sentiment, understand how online behavior might mirror real-world incidents, or uncover patterns in your own data.
48
+ '''
49
+ )
50
+
51
+ # File Uploader
52
+ uploaded_file = st.file_uploader("Upload a GeoJSON file", type=["geojson"])
53
+ uploaded_geojson = None
54
+
55
+ # Map URLs
56
+ map_1 = "https://raw.githubusercontent.com/yunusserhat/data/main/data/boroughs_count_df_2022_dec.geojson"
57
+ map_2 = "https://raw.githubusercontent.com/yunusserhat/data/main/data/mps_hate_2022_dec_count.geojson"
58
+ map_3 = "https://raw.githubusercontent.com/yunusserhat/data/main/data/mps2022dec_count.geojson"
59
+
60
+ if uploaded_file:
61
+ try:
62
+ uploaded_geojson = json.load(uploaded_file)
63
+ if "features" not in uploaded_geojson:
64
+ st.warning("The uploaded file does not seem to be a valid GeoJSON format.")
65
+ uploaded_geojson = None
66
+ else:
67
+ st.success("GeoJSON file uploaded successfully!")
68
+ except json.JSONDecodeError:
69
+ st.error("Failed to decode the uploaded file. Please ensure it's a valid GeoJSON format.")
70
+
71
+ # Map Selection
72
+ map_choices = ["Hate Tweets", "MPS Hate Crime Data", "MPS All Crime Data"]
73
+ if uploaded_geojson:
74
+ map_choices.append("Uploaded GeoJSON")
75
+
76
+ selected_map_1 = st.selectbox("Select data for Map 1", map_choices)
77
+
78
+ # Determine the columns based on the selected dataset for Map 1
79
+ if selected_map_1 == "Uploaded GeoJSON" and uploaded_geojson:
80
+ available_columns_1 = get_columns_from_geojson(uploaded_geojson)
81
+ elif selected_map_1 == "Hate Tweets":
82
+ available_columns_1 = get_columns_from_url(map_1)
83
+ elif selected_map_1 == "MPS Hate Crime Data":
84
+ available_columns_1 = get_columns_from_url(map_2)
85
+ elif selected_map_1 == "MPS All Crime Data":
86
+ available_columns_1 = get_columns_from_url(map_3)
87
+
88
+ selected_column_1 = st.selectbox("Select column for Map 1 visualization", available_columns_1)
89
+
90
+ selected_map_2 = st.selectbox("Select data for Map 2", map_choices)
91
+
92
+ # Determine the columns based on the selected dataset for Map 2
93
+ if selected_map_2 == "Uploaded GeoJSON" and uploaded_geojson:
94
+ available_columns_2 = get_columns_from_geojson(uploaded_geojson)
95
+ elif selected_map_2 == "Hate Tweets":
96
+ available_columns_2 = get_columns_from_url(map_1)
97
+ elif selected_map_2 == "MPS Hate Crime Data":
98
+ available_columns_2 = get_columns_from_url(map_2)
99
+ elif selected_map_2 == "MPS All Crime Data":
100
+ available_columns_2 = get_columns_from_url(map_3)
101
+
102
+ selected_column_2 = st.selectbox("Select column for Map 2 visualization", available_columns_2)
103
+
104
+ # Display Maps
105
+ row1_col1, row1_col2 = st.columns([1, 1])
106
+
107
+ with row1_col1:
108
+ m1 = leafmap.Map(center=[51.50, -0.1], zoom=10)
109
+ if selected_map_1 == "Uploaded GeoJSON":
110
+ m1.add_data(uploaded_geojson, column=selected_column_1)
111
+ elif selected_map_1 == "Hate Tweets":
112
+ m1.add_data(map_1, column=selected_column_1)
113
+ elif selected_map_1 == "MPS Hate Crime Data":
114
+ m1.add_data(map_2, column=selected_column_1)
115
+ else:
116
+ m1.add_data(map_3, column=selected_column_1)
117
+
118
+ with row1_col2:
119
+ m2 = leafmap.Map(center=[51.50, -0.1], zoom=10)
120
+ if selected_map_2 == "Uploaded GeoJSON":
121
+ m2.add_data(uploaded_geojson, column=selected_column_2)
122
+ elif selected_map_2 == "Hate Tweets":
123
+ m2.add_data(map_1, column=selected_column_2)
124
+ elif selected_map_2 == "MPS Hate Crime Data":
125
+ m2.add_data(map_2, column=selected_column_2)
126
+ else:
127
+ m2.add_data(map_3, column=selected_column_2)
128
+
129
+ # Zoom
130
+ longitude = -0.1
131
+ latitude = 51.50
132
+ zoomlevel = st.number_input("Zoom", 0, 20, 10)
133
+
134
+ row2_col1, row2_col2 = st.columns([1, 1])
135
+
136
+ with row2_col1:
137
+ m1.set_center(longitude, latitude, zoomlevel)
138
+ with row2_col2:
139
+ m2.set_center(longitude, latitude, zoomlevel)
140
+
141
+ row3_col1, row3_col2 = st.columns([1, 1])
142
+
143
+ with row3_col1:
144
+ m1.to_streamlit()
145
+ with row3_col2:
146
+ m2.to_streamlit()
pages/3_😡_Hate_Tweets.py ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import leafmap.foliumap as leafmap
3
+ import whitebox
4
+
5
+
6
+ st.set_page_config(layout="wide")
7
+
8
+ st.sidebar.info(
9
+ """
10
+ - Web App URL: <https://interactive-crime-map.hf.space/>
11
+ - HuggingFace repository: <https://huggingface.co/spaces/interactive-crime/map/tree/main>
12
+ """
13
+ )
14
+
15
+ st.sidebar.title("Contact")
16
+ st.sidebar.info(
17
+ """
18
+ Yunus Serhat Bıçakçı at [yunusserhat.com](https://yunusserhat.com) | [GitHub](https://github.com/yunusserhat) | [Twitter](https://twitter.com/yunusserhat) | [LinkedIn](https://www.linkedin.com/in/yunusserhat)
19
+ """
20
+ )
21
+
22
+ st.title("Hate Speech Interactive Map Application")
23
+
24
+ please_note = '<p style="color:Red; font-weight:bold;">Please note that the information displayed may contain sentences containing hateful content. Kindly keep this in mind before reviewing the details.</p>'
25
+
26
+
27
+ st.markdown(
28
+ """
29
+ The interactive map illustrate a hate crime tweets in London boroughs for the month of December 2022. Model 1 is the latest model from [TweetNLP](https://arxiv.org/pdf/2206.14774.pdf) and [CardiffNLP](https://huggingface.co/cardiffnlp/twitter-roberta-base-hate-multiclass-latest), and Model 2 is an older version of Model 1, owned by [Dimosthenis Antypas](https://huggingface.co/antypasd/). Both models have been utilized for hate speech detection.
30
+ """
31
+ )
32
+ st.markdown(please_note, unsafe_allow_html=True)
33
+ st.markdown(
34
+ """
35
+
36
+ """
37
+ )
38
+
39
+ # add whitebox tools to the map
40
+ m = leafmap.Map(center=[51.50, -0.1], zoom=10)
41
+ tweets2 = 'https://raw.githubusercontent.com/yunusserhat/data/main/data/London2022DecHateTweetsLatLong.csv'
42
+ borough2 = 'https://raw.githubusercontent.com/yunusserhat/data/main/data/londonborough.geojson'
43
+
44
+ tweets = 'https://raw.githubusercontent.com/yunusserhat/data/main/data/multiclass_latest_latlng.csv'
45
+ borough = 'https://raw.githubusercontent.com/yunusserhat/data/main/data/londonborough.geojson'
46
+
47
+ map_option = st.selectbox('Choose a Map', ('Model 1', 'Model 2'))
48
+ palette_model_1 = ["red", "blue", "green", "yellow", "purple", "orange"]
49
+ palette_model_2 = ["red", "blue", "green", "yellow", "purple"]
50
+
51
+ if map_option == 'Model 1':
52
+ m.add_geojson(borough, layer_name='London Boroughs')
53
+ m.add_points_from_xy(
54
+ tweets,
55
+ x="Longitude",
56
+ y="Latitude",
57
+ color_column='Hate Prediction',
58
+ palette=palette_model_1,
59
+ spin=True,
60
+ add_legend=True
61
+ )
62
+ else:
63
+ m.add_geojson(borough2, layer_name='London Boroughs 2')
64
+ m.add_points_from_xy(
65
+ tweets2,
66
+ x="Longitude",
67
+ y="Latitude",
68
+ color_column='Hate Prediction',
69
+ palette=palette_model_2,
70
+ spin=True,
71
+ add_legend=True
72
+ )
73
+
74
+ m.to_streamlit()
pages/4_Test.py ADDED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import leafmap.foliumap as leafmap
3
+ import json
4
+ import requests
5
+
6
+ # Functions to dynamically fetch columns
7
+ def get_columns_from_geojson(geojson_data):
8
+ """Retrieve column names from a GeoJSON data."""
9
+ if "features" in geojson_data:
10
+ properties = geojson_data["features"][0]["properties"]
11
+ return list(properties.keys())
12
+ return []
13
+
14
+ def get_columns_from_url(url):
15
+ """Retrieve column names from a GeoJSON URL."""
16
+ response = requests.get(url)
17
+ geojson_data = response.json()
18
+ return get_columns_from_geojson(geojson_data)
19
+
20
+ st.set_page_config(layout="wide")
21
+
22
+ # Sidebar Information
23
+ st.sidebar.info(
24
+ '''
25
+ - Web App URL: <https://interactive-crime-map.hf.space/>
26
+ - HuggingFace repository: <https://huggingface.co/spaces/interactive-crime/map/tree/main>
27
+ '''
28
+ )
29
+
30
+ st.sidebar.title("Contact")
31
+ st.sidebar.info(
32
+ '''
33
+ Yunus Serhat Bıçakçı at [yunusserhat.com](https://yunusserhat.com) | [GitHub](https://github.com/yunusserhat) | [Twitter](https://twitter.com/yunusserhat) | [LinkedIn](https://www.linkedin.com/in/yunusserhat)
34
+ '''
35
+ )
36
+
37
+ # Title and Description
38
+ st.title("Interactive Analysis of Hate Metrics in London & Custom Dataset Visualization")
39
+
40
+ st.markdown(
41
+ '''
42
+ Dive into an interactive analysis of hate metrics in London, exploring the disparities and correlations between hate-related tweets and reported crimes in boroughs. This platform offers a comparative visualization based on data from X and the London Metropolitan Police Service as of December 2022.
43
+
44
+ Additionally, users can upload and visualize their own GeoJSON datasets, facilitating personalized analysis and insights. Delve deeper into the patterns of hate sentiment, understand how online behavior might mirror real-world incidents, or uncover patterns in your own data.
45
+ '''
46
+ )
47
+
48
+ # File Uploader
49
+ uploaded_file = st.file_uploader("Upload a GeoJSON file", type=["geojson"])
50
+ uploaded_geojson = None
51
+
52
+ # Map URLs
53
+ map_1 = "https://raw.githubusercontent.com/yunusserhat/data/main/data/boroughs_count_df_2022_dec.geojson"
54
+ map_2 = "https://raw.githubusercontent.com/yunusserhat/data/main/data/mps_hate_2022_dec_count.geojson"
55
+ map_3 = "https://raw.githubusercontent.com/yunusserhat/data/main/data/mps2022dec_count.geojson"
56
+
57
+ if uploaded_file:
58
+ try:
59
+ uploaded_geojson = json.load(uploaded_file)
60
+ if "features" not in uploaded_geojson:
61
+ st.warning("The uploaded file does not seem to be a valid GeoJSON format.")
62
+ uploaded_geojson = None
63
+ else:
64
+ st.success("GeoJSON file uploaded successfully!")
65
+ except json.JSONDecodeError:
66
+ st.error("Failed to decode the uploaded file. Please ensure it's a valid GeoJSON format.")
67
+
68
+ # Map Selection
69
+ map_choices = ["Hate Tweets", "MPS Hate Crime Data", "MPS All Crime Data"]
70
+ if uploaded_geojson:
71
+ map_choices.append("Uploaded GeoJSON")
72
+
73
+ selected_map_1 = st.selectbox("Select data for Map 1", map_choices)
74
+
75
+ # Determine the columns based on the selected dataset for Map 1
76
+ if selected_map_1 == "Uploaded GeoJSON" and uploaded_geojson:
77
+ available_columns_1 = get_columns_from_geojson(uploaded_geojson)
78
+ elif selected_map_1 == "Hate Tweets":
79
+ available_columns_1 = get_columns_from_url(map_1)
80
+ elif selected_map_1 == "MPS Hate Crime Data":
81
+ available_columns_1 = get_columns_from_url(map_2)
82
+ elif selected_map_1 == "MPS All Crime Data":
83
+ available_columns_1 = get_columns_from_url(map_3)
84
+
85
+ selected_column_1 = st.selectbox("Select column for Map 1 visualization", available_columns_1)
86
+
87
+ selected_map_2 = st.selectbox("Select data for Map 2", map_choices)
88
+
89
+ # Determine the columns based on the selected dataset for Map 2
90
+ if selected_map_2 == "Uploaded GeoJSON" and uploaded_geojson:
91
+ available_columns_2 = get_columns_from_geojson(uploaded_geojson)
92
+ elif selected_map_2 == "Hate Tweets":
93
+ available_columns_2 = get_columns_from_url(map_1)
94
+ elif selected_map_2 == "MPS Hate Crime Data":
95
+ available_columns_2 = get_columns_from_url(map_2)
96
+ elif selected_map_2 == "MPS All Crime Data":
97
+ available_columns_2 = get_columns_from_url(map_3)
98
+
99
+ selected_column_2 = st.selectbox("Select column for Map 2 visualization", available_columns_2)
100
+
101
+ # Display Maps
102
+ row1_col1, row1_col2 = st.columns([1, 1])
103
+
104
+ with row1_col1:
105
+ m1 = leafmap.Map(center=[51.50, -0.1], zoom=10)
106
+ if selected_map_1 == "Uploaded GeoJSON":
107
+ m1.add_data(uploaded_geojson, column=selected_column_1)
108
+ elif selected_map_1 == "Hate Tweets":
109
+ m1.add_data(map_1, column=selected_column_1)
110
+ elif selected_map_1 == "MPS Hate Crime Data":
111
+ m1.add_data(map_2, column=selected_column_1)
112
+ else:
113
+ m1.add_data(map_3, column=selected_column_1)
114
+
115
+ with row1_col2:
116
+ m2 = leafmap.Map(center=[51.50, -0.1], zoom=10)
117
+ if selected_map_2 == "Uploaded GeoJSON":
118
+ m2.add_data(uploaded_geojson, column=selected_column_2)
119
+ elif selected_map_2 == "Hate Tweets":
120
+ m2.add_data(map_1, column=selected_column_2)
121
+ elif selected_map_2 == "MPS Hate Crime Data":
122
+ m2.add_data(map_2, column=selected_column_2)
123
+ else:
124
+ m2.add_data(map_3, column=selected_column_2)
125
+
126
+ # Zoom
127
+ longitude = -0.1
128
+ latitude = 51.50
129
+ zoomlevel = st.number_input("Zoom", 0, 20, 10)
130
+
131
+ row2_col1, row2_col2 = st.columns([1, 1])
132
+
133
+ with row2_col1:
134
+ m1.set_center(longitude, latitude, zoomlevel)
135
+ with row2_col2:
136
+ m2.set_center(longitude, latitude, zoomlevel)
137
+
138
+ row3_col1, row3_col2 = st.columns([1, 1])
139
+
140
+ with row3_col1:
141
+ m1.to_streamlit()
142
+ with row3_col2:
143
+ m2.to_streamlit()
postBuild ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ # enable nbserverproxy
2
+ jupyter serverextension enable --sys-prefix nbserverproxy
3
+ # streamlit launches at startup
4
+ mv streamlit_call.py ${NB_PYTHON_PREFIX}/lib/python*/site-packages/
5
+ # enable streamlit extension
6
+ jupyter serverextension enable --sys-prefix streamlit_call
requirements.txt ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --find-links=https://girder.github.io/large_image_wheels GDAL
2
+ # cartopy
3
+ folium==0.13.0
4
+ # ipywidgets<8.0.5
5
+ geemap
6
+ ffmpeg-python
7
+ geopandas
8
+ # jupyter-server-proxy
9
+ # keplergl
10
+ leafmap>=0.18.6
11
+ # localtileserver
12
+ # nbserverproxy
13
+ owslib
14
+ palettable
15
+ plotly
16
+ streamlit
17
+ streamlit-bokeh-events
18
+ streamlit-folium
19
+ # streamlit-keplergl
20
+ # tropycal
21
+ # git+https://github.com/giswqs/leafmap
22
+ # git+https://github.com/giswqs/geemap
23
+ altair<5
24
+ mapclassify
setup.sh ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # sudo add-apt-repository ppa:ubuntugis/ppa && sudo apt-get update
2
+ # sudo apt-get update
3
+ # sudo apt-get install python3-dev
4
+ # sudo apt-get install gdal-bin
5
+ # sudo apt-get install libgdal-dev
6
+ # export CPLUS_INCLUDE_PATH=/usr/include/gdal
7
+ # export C_INCLUDE_PATH=/usr/include/gdal
8
+ # gdal-config --version
9
+ # pip install GDAL==$(gdal-config --version | awk -F'[.]' '{print $1"."$2}') localtileserver
10
+
11
+ mkdir -p ~/.streamlit/
12
+ echo "\
13
+ [server]\n\
14
+ headless = true\n\
15
+ port = $PORT\n\
16
+ enableCORS = false\n\
17
+ \n\
18
+ " > ~/.streamlit/config.toml