citation-map 2.0__tar.gz → 3.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {citation-map-2.0 → citation-map-3.1}/PKG-INFO +22 -3
- {citation-map-2.0 → citation-map-3.1}/README.md +21 -2
- {citation-map-2.0 → citation-map-3.1}/citation_map/citation_map.py +79 -35
- {citation-map-2.0 → citation-map-3.1}/citation_map.egg-info/PKG-INFO +22 -3
- {citation-map-2.0 → citation-map-3.1}/setup.py +1 -1
- {citation-map-2.0 → citation-map-3.1}/LICENSE.md +0 -0
- {citation-map-2.0 → citation-map-3.1}/citation_map/__init__.py +0 -0
- {citation-map-2.0 → citation-map-3.1}/citation_map.egg-info/SOURCES.txt +0 -0
- {citation-map-2.0 → citation-map-3.1}/citation_map.egg-info/dependency_links.txt +0 -0
- {citation-map-2.0 → citation-map-3.1}/citation_map.egg-info/requires.txt +0 -0
- {citation-map-2.0 → citation-map-3.1}/citation_map.egg-info/top_level.txt +0 -0
- {citation-map-2.0 → citation-map-3.1}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: citation-map
|
|
3
|
-
Version:
|
|
3
|
+
Version: 3.1
|
|
4
4
|
Summary: A simple tool to generate your Google Scholar citation world map.
|
|
5
5
|
Home-page: https://github.com/ChenLiu-1996/CitationMap
|
|
6
6
|
Author: Chen Liu
|
|
@@ -39,8 +39,6 @@ If you open it on a browser, you will see your own version of the following cita
|
|
|
39
39
|
|
|
40
40
|
<img src = "assets/citation_world_map.png" width=800>
|
|
41
41
|
|
|
42
|
-
## News
|
|
43
|
-
`citation-map` has been upgraded to version 2.0! I finally managed to drastically speed up the process using multiprocessing (without being blocked by Google Scholar). On my personal computer, processing my profile with 100 citations took 1 hour with version 1.0 while it's now taking 5 minutes with version 2.0.
|
|
44
42
|
|
|
45
43
|
## Usage
|
|
46
44
|
1. Install the package.
|
|
@@ -88,6 +86,27 @@ If you open it on a browser, you will see your own version of the following cita
|
|
|
88
86
|
If true, print the list of citing institutions (affiliations of citing authors).
|
|
89
87
|
```
|
|
90
88
|
|
|
89
|
+
## Changelog
|
|
90
|
+
|
|
91
|
+
### Version 3.0
|
|
92
|
+
I realized a problem with how I used `geopy.geocoders`. A majority of the authors' self-entered affiliations are not successfully found in the system and hence are not converted to geographic coordinates on the world map. For example, the string "Yale University" is a much better entry than "Assistant Professor at Yale University".
|
|
93
|
+
|
|
94
|
+
I applied a simple fix with some rule-based language processing. This helps us identify many missing citing locations.
|
|
95
|
+
|
|
96
|
+
### Version 2.0
|
|
97
|
+
I finally managed to **drastically speed up** the process using multiprocessing, in a way that avoids being blocked by Google Scholar.
|
|
98
|
+
|
|
99
|
+
On my personal computer, processing my profile with 100 citations took 1 hour with version 1.0 while it's now taking 5 minutes with version 2.0.
|
|
100
|
+
|
|
101
|
+
With that said, please be careful and do not run this tool frequently. I can easily get on Google Scholar's blacklist after a few runs.
|
|
102
|
+
|
|
103
|
+
### Version 1.0
|
|
104
|
+
Very basic functionality.
|
|
105
|
+
|
|
106
|
+
This script is a bit slow. On my personal computer, it takes half a minute to process each citation. If you have thousands of citations, it may or may not be a good idea to use this script.
|
|
107
|
+
|
|
108
|
+
I tried to use multiprocessing, but unfortunately the excessive visits get me blocked by Google Scholar.
|
|
109
|
+
|
|
91
110
|
## Dependencies
|
|
92
111
|
Dependencies (`scholarly`, `geopy`, `folium`, `tqdm`) are already taken care of when you install via pip.
|
|
93
112
|
|
|
@@ -23,8 +23,6 @@ If you open it on a browser, you will see your own version of the following cita
|
|
|
23
23
|
|
|
24
24
|
<img src = "assets/citation_world_map.png" width=800>
|
|
25
25
|
|
|
26
|
-
## News
|
|
27
|
-
`citation-map` has been upgraded to version 2.0! I finally managed to drastically speed up the process using multiprocessing (without being blocked by Google Scholar). On my personal computer, processing my profile with 100 citations took 1 hour with version 1.0 while it's now taking 5 minutes with version 2.0.
|
|
28
26
|
|
|
29
27
|
## Usage
|
|
30
28
|
1. Install the package.
|
|
@@ -72,6 +70,27 @@ If you open it on a browser, you will see your own version of the following cita
|
|
|
72
70
|
If true, print the list of citing institutions (affiliations of citing authors).
|
|
73
71
|
```
|
|
74
72
|
|
|
73
|
+
## Changelog
|
|
74
|
+
|
|
75
|
+
### Version 3.0
|
|
76
|
+
I realized a problem with how I used `geopy.geocoders`. A majority of the authors' self-entered affiliations are not successfully found in the system and hence are not converted to geographic coordinates on the world map. For example, the string "Yale University" is a much better entry than "Assistant Professor at Yale University".
|
|
77
|
+
|
|
78
|
+
I applied a simple fix with some rule-based language processing. This helps us identify many missing citing locations.
|
|
79
|
+
|
|
80
|
+
### Version 2.0
|
|
81
|
+
I finally managed to **drastically speed up** the process using multiprocessing, in a way that avoids being blocked by Google Scholar.
|
|
82
|
+
|
|
83
|
+
On my personal computer, processing my profile with 100 citations took 1 hour with version 1.0 while it's now taking 5 minutes with version 2.0.
|
|
84
|
+
|
|
85
|
+
With that said, please be careful and do not run this tool frequently. I can easily get on Google Scholar's blacklist after a few runs.
|
|
86
|
+
|
|
87
|
+
### Version 1.0
|
|
88
|
+
Very basic functionality.
|
|
89
|
+
|
|
90
|
+
This script is a bit slow. On my personal computer, it takes half a minute to process each citation. If you have thousands of citations, it may or may not be a good idea to use this script.
|
|
91
|
+
|
|
92
|
+
I tried to use multiprocessing, but unfortunately the excessive visits get me blocked by Google Scholar.
|
|
93
|
+
|
|
75
94
|
## Dependencies
|
|
76
95
|
Dependencies (`scholarly`, `geopy`, `folium`, `tqdm`) are already taken care of when you install via pip.
|
|
77
96
|
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import re
|
|
1
2
|
import random
|
|
2
3
|
import time
|
|
3
4
|
import itertools
|
|
5
|
+
|
|
6
|
+
from typing import List, Tuple
|
|
4
7
|
from scholarly import scholarly, ProxyGenerator
|
|
5
8
|
from geopy.geocoders import Nominatim
|
|
6
9
|
import folium
|
|
@@ -8,7 +11,7 @@ from tqdm import tqdm
|
|
|
8
11
|
from multiprocessing import Pool
|
|
9
12
|
|
|
10
13
|
|
|
11
|
-
def fetch_google_scholar_profile(scholar_id):
|
|
14
|
+
def fetch_google_scholar_profile(scholar_id: str):
|
|
12
15
|
'''
|
|
13
16
|
Step 1: Fetch Google Scholar Profile using Scholar ID.
|
|
14
17
|
'''
|
|
@@ -16,49 +19,73 @@ def fetch_google_scholar_profile(scholar_id):
|
|
|
16
19
|
author = scholarly.fill(author, sections=['publications'])
|
|
17
20
|
return author
|
|
18
21
|
|
|
19
|
-
def find_all_citing_institutions(publications, num_processes: int = 16):
|
|
22
|
+
def find_all_citing_institutions(publications, num_processes: int = 16) -> List[Tuple[str]]:
|
|
20
23
|
'''
|
|
21
24
|
Step 2. Final all citing institutions (i.e., insitutions of citing authors).
|
|
22
25
|
'''
|
|
23
|
-
|
|
24
26
|
# Fetch metadata for all publications, in parallel.
|
|
25
27
|
with Pool(processes=num_processes) as pool:
|
|
26
|
-
all_publications = list(tqdm(pool.imap(__fill_publication_metadata, publications),
|
|
28
|
+
all_publications = list(tqdm(pool.imap(__fill_publication_metadata, publications),
|
|
29
|
+
desc='Filling metadata for all publications...',
|
|
30
|
+
total=len(publications)))
|
|
27
31
|
|
|
28
32
|
# Find all citing papers from all publications, in parallel.
|
|
29
33
|
with Pool(processes=num_processes) as pool:
|
|
30
|
-
all_citing_papers_nested = list(tqdm(pool.imap(__citing_papers_from_publication, all_publications),
|
|
34
|
+
all_citing_papers_nested = list(tqdm(pool.imap(__citing_papers_from_publication, all_publications),
|
|
35
|
+
desc='Finding all citations...',
|
|
36
|
+
total=len(all_publications)))
|
|
31
37
|
all_citing_papers = list(itertools.chain(*all_citing_papers_nested))
|
|
32
38
|
|
|
33
39
|
# Find all citing authors from all citing papers, in parallel.
|
|
34
40
|
with Pool(processes=num_processes) as pool:
|
|
35
|
-
all_citing_authors_nested = list(tqdm(pool.imap(__authors_from_papers, all_citing_papers),
|
|
41
|
+
all_citing_authors_nested = list(tqdm(pool.imap(__authors_from_papers, all_citing_papers),
|
|
42
|
+
desc='Finding all citing authors...',
|
|
43
|
+
total=len(all_citing_papers)))
|
|
36
44
|
all_citing_authors = list(itertools.chain(*all_citing_authors_nested))
|
|
37
45
|
|
|
38
46
|
# Find all citing insitutions from all citing authors, in parallel.
|
|
39
47
|
with Pool(processes=num_processes) as pool:
|
|
40
|
-
|
|
48
|
+
author_institution_tuple_list = list(tqdm(pool.imap(__institutions_from_authors, all_citing_authors),
|
|
49
|
+
desc='Finding all citing institutions...',
|
|
50
|
+
total=len(all_citing_authors)))
|
|
41
51
|
|
|
42
|
-
return
|
|
52
|
+
return author_institution_tuple_list
|
|
43
53
|
|
|
44
|
-
def
|
|
54
|
+
def clean_institution_names(author_institution_tuple_list: List[Tuple[str]]) -> List[Tuple[str]]:
|
|
45
55
|
'''
|
|
46
|
-
Step 3
|
|
56
|
+
Step 3. Clean up the name of institutions from the author's self-entered Google Scholar affiliation.
|
|
47
57
|
'''
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
58
|
+
cleaned_author_institution_tuple_list = []
|
|
59
|
+
for author_name, institution_string in author_institution_tuple_list:
|
|
60
|
+
# Use a regular expression to split the string by ',', ';', or 'and'.
|
|
61
|
+
substring_list = [part.strip() for part in re.split(r'[;,]|\band\b', institution_string)]
|
|
62
|
+
for substring in substring_list:
|
|
63
|
+
# Use a regular expression to remove anything before 'at', or '@'.
|
|
64
|
+
cleaned_institution = re.sub(r'.*?\bat\b|.*?@', '', substring, flags=re.IGNORECASE).strip()
|
|
65
|
+
# Use a regular expression to check if the string is a common weird string.
|
|
66
|
+
is_common_weird_string = re.search(
|
|
67
|
+
re.compile(
|
|
68
|
+
r'\b(director|manager|chair|engineer|programmer|scientist|professor|lecturer|phd|student|ph\.d|department of)\b',
|
|
69
|
+
re.IGNORECASE),
|
|
70
|
+
substring)
|
|
71
|
+
if not is_common_weird_string:
|
|
72
|
+
cleaned_author_institution_tuple_list.append((author_name, cleaned_institution))
|
|
73
|
+
return cleaned_author_institution_tuple_list
|
|
74
|
+
|
|
75
|
+
def institution_text_to_geocode(author_institution_tuple_list: List[Tuple[str]], num_processes: int = 16) -> List[Tuple[str]]:
|
|
76
|
+
'''
|
|
77
|
+
Step 4: Convert institutions in plain text to Geocode.
|
|
78
|
+
'''
|
|
79
|
+
with Pool(processes=num_processes) as pool:
|
|
80
|
+
coordinates = list(tqdm(pool.imap(__text_to_geocode, author_institution_tuple_list),
|
|
81
|
+
desc='Finding all geographic coordinates...',
|
|
82
|
+
total=len(author_institution_tuple_list)))
|
|
83
|
+
coordinates = [item for item in coordinates if item is not None] # Filter out empty coordinates.
|
|
57
84
|
return coordinates
|
|
58
85
|
|
|
59
|
-
def create_map(coordinates, pin_colorful: bool = True):
|
|
86
|
+
def create_map(coordinates: List[Tuple[str]], pin_colorful: bool = True):
|
|
60
87
|
'''
|
|
61
|
-
Step
|
|
88
|
+
Step 5: Create the Citation World Map.
|
|
62
89
|
'''
|
|
63
90
|
citation_map = folium.Map(location=[20, 0], zoom_start=2)
|
|
64
91
|
if pin_colorful:
|
|
@@ -66,12 +93,12 @@ def create_map(coordinates, pin_colorful: bool = True):
|
|
|
66
93
|
'lightred', 'beige', 'darkblue', 'darkgreen', 'cadetblue',
|
|
67
94
|
'darkpurple', 'pink', 'lightblue', 'lightgreen',
|
|
68
95
|
'gray', 'black', 'lightgray']
|
|
69
|
-
for lat, lon, location in coordinates:
|
|
96
|
+
for lat, lon, author_name, location in coordinates:
|
|
70
97
|
color = random.choice(colors)
|
|
71
|
-
folium.Marker([lat, lon], popup=location, icon=folium.Icon(color=color)).add_to(citation_map)
|
|
98
|
+
folium.Marker([lat, lon], popup='%s (%s)' % (location, author_name), icon=folium.Icon(color=color)).add_to(citation_map)
|
|
72
99
|
else:
|
|
73
|
-
for lat, lon, location in coordinates:
|
|
74
|
-
folium.Marker([lat, lon], popup=location).add_to(citation_map)
|
|
100
|
+
for lat, lon, author_name, location in coordinates:
|
|
101
|
+
folium.Marker([lat, lon], popup='%s (%s)' % (location, author_name)).add_to(citation_map)
|
|
75
102
|
return citation_map
|
|
76
103
|
|
|
77
104
|
def __fill_publication_metadata(pub):
|
|
@@ -97,9 +124,19 @@ def __institutions_from_authors(author_id):
|
|
|
97
124
|
citing_author = scholarly.search_author_id(author_id)
|
|
98
125
|
citing_author = scholarly.fill(citing_author)
|
|
99
126
|
if 'affiliation' in citing_author:
|
|
100
|
-
return citing_author['affiliation']
|
|
127
|
+
return (citing_author['name'], citing_author['affiliation'])
|
|
101
128
|
return []
|
|
102
129
|
|
|
130
|
+
def __text_to_geocode(author_institution_tuple):
|
|
131
|
+
geolocator = Nominatim(user_agent='citation_mapper')
|
|
132
|
+
try:
|
|
133
|
+
author_name, institution_name = author_institution_tuple
|
|
134
|
+
geo_location = geolocator.geocode(institution_name)
|
|
135
|
+
if geo_location:
|
|
136
|
+
return (geo_location.latitude, geo_location.longitude, author_name, institution_name)
|
|
137
|
+
except:
|
|
138
|
+
return None
|
|
139
|
+
|
|
103
140
|
def generate_citation_map(scholar_id: str,
|
|
104
141
|
output_path: str = 'citation_map.html',
|
|
105
142
|
num_processes: int = 16,
|
|
@@ -141,20 +178,27 @@ def generate_citation_map(scholar_id: str,
|
|
|
141
178
|
author_profile = fetch_google_scholar_profile(scholar_id)
|
|
142
179
|
print('\nAuthor profile found, with %d publications.\n' % len(author_profile['publications']))
|
|
143
180
|
|
|
144
|
-
|
|
145
|
-
print('\nA total of %d citing institutions recorded
|
|
181
|
+
author_institution_tuple_list = find_all_citing_institutions(author_profile['publications'], num_processes=num_processes)
|
|
182
|
+
print('\nA total of %d citing institutions recorded.\n' % len(author_institution_tuple_list))
|
|
146
183
|
|
|
147
|
-
|
|
184
|
+
if print_citing_institutions:
|
|
185
|
+
print('\nList of all citing authors and institutions before cleaning:\n')
|
|
186
|
+
for item in sorted(author_institution_tuple_list):
|
|
187
|
+
print(item)
|
|
188
|
+
|
|
189
|
+
cleaned_author_institution_tuple_list = clean_institution_names(author_institution_tuple_list)
|
|
190
|
+
|
|
191
|
+
if print_citing_institutions:
|
|
192
|
+
print('\nList of all citing authors and institutions after cleaning:\n')
|
|
193
|
+
for item in sorted(cleaned_author_institution_tuple_list):
|
|
194
|
+
print(item)
|
|
195
|
+
|
|
196
|
+
coordinates = institution_text_to_geocode(author_institution_tuple_list + cleaned_author_institution_tuple_list)
|
|
148
197
|
print('\nConverted the institutions to Geocodes.')
|
|
149
198
|
|
|
150
199
|
citation_map = create_map(coordinates, pin_colorful=pin_colorful)
|
|
151
200
|
citation_map.save(output_path)
|
|
152
|
-
print('\nMap created and saved
|
|
153
|
-
|
|
154
|
-
if print_citing_institutions:
|
|
155
|
-
print('\nList of all citing institutions:\n')
|
|
156
|
-
for institution in institutions:
|
|
157
|
-
print(institution)
|
|
201
|
+
print('\nMap created and saved at %s.' % output_path)
|
|
158
202
|
return
|
|
159
203
|
|
|
160
204
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: citation-map
|
|
3
|
-
Version:
|
|
3
|
+
Version: 3.1
|
|
4
4
|
Summary: A simple tool to generate your Google Scholar citation world map.
|
|
5
5
|
Home-page: https://github.com/ChenLiu-1996/CitationMap
|
|
6
6
|
Author: Chen Liu
|
|
@@ -39,8 +39,6 @@ If you open it on a browser, you will see your own version of the following cita
|
|
|
39
39
|
|
|
40
40
|
<img src = "assets/citation_world_map.png" width=800>
|
|
41
41
|
|
|
42
|
-
## News
|
|
43
|
-
`citation-map` has been upgraded to version 2.0! I finally managed to drastically speed up the process using multiprocessing (without being blocked by Google Scholar). On my personal computer, processing my profile with 100 citations took 1 hour with version 1.0 while it's now taking 5 minutes with version 2.0.
|
|
44
42
|
|
|
45
43
|
## Usage
|
|
46
44
|
1. Install the package.
|
|
@@ -88,6 +86,27 @@ If you open it on a browser, you will see your own version of the following cita
|
|
|
88
86
|
If true, print the list of citing institutions (affiliations of citing authors).
|
|
89
87
|
```
|
|
90
88
|
|
|
89
|
+
## Changelog
|
|
90
|
+
|
|
91
|
+
### Version 3.0
|
|
92
|
+
I realized a problem with how I used `geopy.geocoders`. A majority of the authors' self-entered affiliations are not successfully found in the system and hence are not converted to geographic coordinates on the world map. For example, the string "Yale University" is a much better entry than "Assistant Professor at Yale University".
|
|
93
|
+
|
|
94
|
+
I applied a simple fix with some rule-based language processing. This helps us identify many missing citing locations.
|
|
95
|
+
|
|
96
|
+
### Version 2.0
|
|
97
|
+
I finally managed to **drastically speed up** the process using multiprocessing, in a way that avoids being blocked by Google Scholar.
|
|
98
|
+
|
|
99
|
+
On my personal computer, processing my profile with 100 citations took 1 hour with version 1.0 while it's now taking 5 minutes with version 2.0.
|
|
100
|
+
|
|
101
|
+
With that said, please be careful and do not run this tool frequently. I can easily get on Google Scholar's blacklist after a few runs.
|
|
102
|
+
|
|
103
|
+
### Version 1.0
|
|
104
|
+
Very basic functionality.
|
|
105
|
+
|
|
106
|
+
This script is a bit slow. On my personal computer, it takes half a minute to process each citation. If you have thousands of citations, it may or may not be a good idea to use this script.
|
|
107
|
+
|
|
108
|
+
I tried to use multiprocessing, but unfortunately the excessive visits get me blocked by Google Scholar.
|
|
109
|
+
|
|
91
110
|
## Dependencies
|
|
92
111
|
Dependencies (`scholarly`, `geopy`, `folium`, `tqdm`) are already taken care of when you install via pip.
|
|
93
112
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|