citation-map 4.2__tar.gz → 4.4__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-4.2 → citation-map-4.4}/PKG-INFO +47 -8
- {citation-map-4.2 → citation-map-4.4}/README.md +46 -7
- {citation-map-4.2 → citation-map-4.4}/citation_map/citation_map.py +121 -78
- {citation-map-4.2 → citation-map-4.4}/citation_map/scholarly_support.py +47 -30
- {citation-map-4.2 → citation-map-4.4}/citation_map.egg-info/PKG-INFO +47 -8
- {citation-map-4.2 → citation-map-4.4}/setup.py +1 -1
- {citation-map-4.2 → citation-map-4.4}/LICENSE.md +0 -0
- {citation-map-4.2 → citation-map-4.4}/citation_map/__init__.py +0 -0
- {citation-map-4.2 → citation-map-4.4}/citation_map.egg-info/SOURCES.txt +0 -0
- {citation-map-4.2 → citation-map-4.4}/citation_map.egg-info/dependency_links.txt +0 -0
- {citation-map-4.2 → citation-map-4.4}/citation_map.egg-info/requires.txt +0 -0
- {citation-map-4.2 → citation-map-4.4}/citation_map.egg-info/top_level.txt +0 -0
- {citation-map-4.2 → citation-map-4.4}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: citation-map
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.4
|
|
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
|
|
@@ -16,10 +16,11 @@ License-File: LICENSE.md
|
|
|
16
16
|
|
|
17
17
|
# Google Scholar Citation World Map
|
|
18
18
|
|
|
19
|
+
[](https://www.techrxiv.org/users/809001/articles/1213717-citationmap-a-python-tool-to-identify-and-visualize-your-google-scholar-citations-around-the-world)
|
|
20
|
+
[](https://openreview.net/pdf?id=BqJgCgl1IA)
|
|
19
21
|
[](https://pypi.org/project/citation-map/)
|
|
20
22
|
[](https://pypistats.org/packages/citation-map)
|
|
21
23
|
[](https://pypistats.org/packages/citation-map)
|
|
22
|
-
[](https://www.python.org/)
|
|
23
24
|
[![CC BY-NC-SA 4.0][cc-by-nc-sa-shield]][cc-by-nc-sa]
|
|
24
25
|
[![CC BY-NC-SA 4.0][cc-by-nc-sa-image]][cc-by-nc-sa]
|
|
25
26
|
|
|
@@ -27,13 +28,14 @@ License-File: LICENSE.md
|
|
|
27
28
|
[cc-by-nc-sa-image]: https://licensebuttons.net/l/by-nc-sa/4.0/88x31.png
|
|
28
29
|
[cc-by-nc-sa-shield]: https://img.shields.io/badge/License-CC%20BY--NC--SA%204.0-lightgrey.svg
|
|
29
30
|
|
|
30
|
-
[Chen Liu](https://
|
|
31
|
+
[Chen Liu](https://chenliu-1996.github.io/), CS PhD Candidate at Yale University.
|
|
31
32
|
|
|
32
33
|
Research areas: Machine Learning, Spatial-Temporal Modeling, Medical Vision, AI4Science.
|
|
33
34
|
|
|
35
|
+
|
|
34
36
|
## News
|
|
35
37
|
**[Asking for advice]**
|
|
36
|
-
1. This is my first time dealing with webscraping/crawling. Users have reported stability issues, and I suspect the major problems are (1) being caught by CAPTCHA or robot check, and (2) being flagged for blacklist by Google Scholar. If you are experienced in these areas and have good advice, I would highly appreciate a GitHub issue or a pull request
|
|
38
|
+
1. This is my first time dealing with webscraping/crawling. Users have reported stability issues, and I suspect the major problems are (1) being caught by CAPTCHA or robot check, and (2) being flagged for blacklist by Google Scholar. If you are experienced in these areas and have good advice, I would highly appreciate a **GitHub issue or a pull request**.
|
|
37
39
|
|
|
38
40
|
[Aug 2, 2024] Version 4.0 released >>> Logic update. A new input argument `affiliation_conservative`. If set to True, we will use **a very conservative approach to identify affiliations** which leads to **much higher precision and lower recall**. Many thanks to [Zhijian Liu](https://github.com/zhijian-liu) for the [helpful discussion](https://github.com/ChenLiu-1996/CitationMap/issues/8).
|
|
39
41
|
|
|
@@ -63,6 +65,29 @@ Besides, there will be a **CSV file** recording citation information (citing aut
|
|
|
63
65
|
|
|
64
66
|
**NOTE:** **Now you can trade off between affiliation precision and recall** with the `affiliation_conservative` option. If set to True, we will use the Google Scholar verified official organization name from the citing authors. This is a very conservative approach, since (1) the author needs to self-report it in the affiliation panel, (2) the author needs to verify with the matching email address, and (3) the organization needs to be recorded by Google Scholar. For example, Meta (the company) is not in the list. Many thanks to [Zhijian Liu](https://github.com/zhijian-liu) for the [helpful discussion](https://github.com/ChenLiu-1996/CitationMap/issues/8).
|
|
65
67
|
|
|
68
|
+
## Citation
|
|
69
|
+
BibTeX
|
|
70
|
+
```
|
|
71
|
+
@article{citationmap,
|
|
72
|
+
title={CitationMap: A Python Tool to Identify and Visualize Your Google Scholar Citations Around the World},
|
|
73
|
+
author={Liu, Chen},
|
|
74
|
+
journal={Authorea Preprints},
|
|
75
|
+
year={2024},
|
|
76
|
+
publisher={Authorea}
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
MLA
|
|
80
|
+
```
|
|
81
|
+
Liu, Chen. "CitationMap: A Python Tool to Identify and Visualize Your Google Scholar Citations Around the World." Authorea Preprints (2024).
|
|
82
|
+
```
|
|
83
|
+
APA
|
|
84
|
+
```
|
|
85
|
+
Liu, C. (2024). CitationMap: A Python Tool to Identify and Visualize Your Google Scholar Citations Around the World. Authorea Preprints.
|
|
86
|
+
```
|
|
87
|
+
Chicago
|
|
88
|
+
```
|
|
89
|
+
Liu, Chen. "CitationMap: A Python Tool to Identify and Visualize Your Google Scholar Citations Around the World." Authorea Preprints (2024).
|
|
90
|
+
```
|
|
66
91
|
|
|
67
92
|
## User Guide
|
|
68
93
|
0. If you are new to Python, you probably want to start with a distribution of Python that also helps with environment management (such as [anaconda](https://www.anaconda.com/)). Once you have set up your environment (for example, when you reach the stage of `conda activate env39` in [this tutorial](https://www.youtube.com/watch?v=MUZtVEDKXsk&t=242s)), you can move on to the next step.
|
|
@@ -90,6 +115,8 @@ Besides, there will be a **CSV file** recording citation information (citing aut
|
|
|
90
115
|
generate_citation_map(scholar_id)
|
|
91
116
|
```
|
|
92
117
|
|
|
118
|
+
Note that in Version 4.4, we support manual edit of the csv. You can run `generate_citation_map` first, and get the csv and HTML. Then, you can manually modify the csv content, and generate an updated HTML by running `generate_citation_map` again with `parse_csv=True`.
|
|
119
|
+
|
|
93
120
|
Note that in Version 4.0, we will cache the results before identifying affiliations. So if you want to rerun the same author from scratch, you need to delete the cache (default location is 'cache').
|
|
94
121
|
|
|
95
122
|
More input arguments are shown in [the demo script](https://github.com/ChenLiu-1996/CitationMap/blob/main/demo/demo.py).
|
|
@@ -140,10 +167,12 @@ Besides, there will be a **CSV file** recording citation information (citing aut
|
|
|
140
167
|
- Some authors citing you do not have Google Scholar profiles.
|
|
141
168
|
- Some authors citing you do not report their affiliations.
|
|
142
169
|
2. Webscraping is performed, and CAPTCHA or robot check can often get us, especially if we crawl frequently. This is more often seen in highly cited users. Unless you are blocked by Google Scholar, at worst you will end up with missing several citing authors, which is not likely a huge deal for highly cited users anyways.
|
|
143
|
-
3.
|
|
144
|
-
-
|
|
145
|
-
-
|
|
146
|
-
-
|
|
170
|
+
3. Affiliation identification and geolocating issues. This is a joint effect between affiliation identification and geolocating. The number of citing affiliations will be:
|
|
171
|
+
- Underestimated if some affiliations are not found by `geopy.geocoders`.
|
|
172
|
+
- Underestimated if we experience communication errors with `geopy.geocoders`.
|
|
173
|
+
- (Aggressive approach only) Overestimated if non-affiliation phrases are incorrectly identified as locations by `geopy.geocoders`.
|
|
174
|
+
- (Conservative approach only) Underestimated if the citer did not verify with an email address under a matching affiliation domain.
|
|
175
|
+
- (Conservative approach only) Underestimated because all non-primary (with verified email address) affiliations are ignored.
|
|
147
176
|
|
|
148
177
|
**Please raise an issue or submit a pull request if you have some good idea to better process the affiliation string. Note that currently I am not considering any paid service or tools that pose extra burden on the users, such as GPT API.**
|
|
149
178
|
|
|
@@ -176,6 +205,16 @@ Besides, there will be a **CSV file** recording citation information (citing aut
|
|
|
176
205
|
```
|
|
177
206
|
|
|
178
207
|
## Changelog
|
|
208
|
+
<details>
|
|
209
|
+
<summary>Version 4.4 (Dec 6, 2024)</summary>
|
|
210
|
+
<br>
|
|
211
|
+
|
|
212
|
+
1. **Support manual edit of the csv.** Note you do need to manually correct the coordinates too if you choose to use this functionality. You can run `generate_citation_map` first, and get the csv and HTML. Then, you can manually modify the csv content, and generate an updated HTML by running `generate_citation_map` again with `parse_csv=True`.
|
|
213
|
+
2. Slight optimization on caching.
|
|
214
|
+
|
|
215
|
+
</details>
|
|
216
|
+
|
|
217
|
+
|
|
179
218
|
<details>
|
|
180
219
|
<summary>Version 4.0 (Aug 2, 2024)</summary>
|
|
181
220
|
<br>
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
# Google Scholar Citation World Map
|
|
2
2
|
|
|
3
|
+
[](https://www.techrxiv.org/users/809001/articles/1213717-citationmap-a-python-tool-to-identify-and-visualize-your-google-scholar-citations-around-the-world)
|
|
4
|
+
[](https://openreview.net/pdf?id=BqJgCgl1IA)
|
|
3
5
|
[](https://pypi.org/project/citation-map/)
|
|
4
6
|
[](https://pypistats.org/packages/citation-map)
|
|
5
7
|
[](https://pypistats.org/packages/citation-map)
|
|
6
|
-
[](https://www.python.org/)
|
|
7
8
|
[![CC BY-NC-SA 4.0][cc-by-nc-sa-shield]][cc-by-nc-sa]
|
|
8
9
|
[![CC BY-NC-SA 4.0][cc-by-nc-sa-image]][cc-by-nc-sa]
|
|
9
10
|
|
|
@@ -11,13 +12,14 @@
|
|
|
11
12
|
[cc-by-nc-sa-image]: https://licensebuttons.net/l/by-nc-sa/4.0/88x31.png
|
|
12
13
|
[cc-by-nc-sa-shield]: https://img.shields.io/badge/License-CC%20BY--NC--SA%204.0-lightgrey.svg
|
|
13
14
|
|
|
14
|
-
[Chen Liu](https://
|
|
15
|
+
[Chen Liu](https://chenliu-1996.github.io/), CS PhD Candidate at Yale University.
|
|
15
16
|
|
|
16
17
|
Research areas: Machine Learning, Spatial-Temporal Modeling, Medical Vision, AI4Science.
|
|
17
18
|
|
|
19
|
+
|
|
18
20
|
## News
|
|
19
21
|
**[Asking for advice]**
|
|
20
|
-
1. This is my first time dealing with webscraping/crawling. Users have reported stability issues, and I suspect the major problems are (1) being caught by CAPTCHA or robot check, and (2) being flagged for blacklist by Google Scholar. If you are experienced in these areas and have good advice, I would highly appreciate a GitHub issue or a pull request
|
|
22
|
+
1. This is my first time dealing with webscraping/crawling. Users have reported stability issues, and I suspect the major problems are (1) being caught by CAPTCHA or robot check, and (2) being flagged for blacklist by Google Scholar. If you are experienced in these areas and have good advice, I would highly appreciate a **GitHub issue or a pull request**.
|
|
21
23
|
|
|
22
24
|
[Aug 2, 2024] Version 4.0 released >>> Logic update. A new input argument `affiliation_conservative`. If set to True, we will use **a very conservative approach to identify affiliations** which leads to **much higher precision and lower recall**. Many thanks to [Zhijian Liu](https://github.com/zhijian-liu) for the [helpful discussion](https://github.com/ChenLiu-1996/CitationMap/issues/8).
|
|
23
25
|
|
|
@@ -47,6 +49,29 @@ Besides, there will be a **CSV file** recording citation information (citing aut
|
|
|
47
49
|
|
|
48
50
|
**NOTE:** **Now you can trade off between affiliation precision and recall** with the `affiliation_conservative` option. If set to True, we will use the Google Scholar verified official organization name from the citing authors. This is a very conservative approach, since (1) the author needs to self-report it in the affiliation panel, (2) the author needs to verify with the matching email address, and (3) the organization needs to be recorded by Google Scholar. For example, Meta (the company) is not in the list. Many thanks to [Zhijian Liu](https://github.com/zhijian-liu) for the [helpful discussion](https://github.com/ChenLiu-1996/CitationMap/issues/8).
|
|
49
51
|
|
|
52
|
+
## Citation
|
|
53
|
+
BibTeX
|
|
54
|
+
```
|
|
55
|
+
@article{citationmap,
|
|
56
|
+
title={CitationMap: A Python Tool to Identify and Visualize Your Google Scholar Citations Around the World},
|
|
57
|
+
author={Liu, Chen},
|
|
58
|
+
journal={Authorea Preprints},
|
|
59
|
+
year={2024},
|
|
60
|
+
publisher={Authorea}
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
MLA
|
|
64
|
+
```
|
|
65
|
+
Liu, Chen. "CitationMap: A Python Tool to Identify and Visualize Your Google Scholar Citations Around the World." Authorea Preprints (2024).
|
|
66
|
+
```
|
|
67
|
+
APA
|
|
68
|
+
```
|
|
69
|
+
Liu, C. (2024). CitationMap: A Python Tool to Identify and Visualize Your Google Scholar Citations Around the World. Authorea Preprints.
|
|
70
|
+
```
|
|
71
|
+
Chicago
|
|
72
|
+
```
|
|
73
|
+
Liu, Chen. "CitationMap: A Python Tool to Identify and Visualize Your Google Scholar Citations Around the World." Authorea Preprints (2024).
|
|
74
|
+
```
|
|
50
75
|
|
|
51
76
|
## User Guide
|
|
52
77
|
0. If you are new to Python, you probably want to start with a distribution of Python that also helps with environment management (such as [anaconda](https://www.anaconda.com/)). Once you have set up your environment (for example, when you reach the stage of `conda activate env39` in [this tutorial](https://www.youtube.com/watch?v=MUZtVEDKXsk&t=242s)), you can move on to the next step.
|
|
@@ -74,6 +99,8 @@ Besides, there will be a **CSV file** recording citation information (citing aut
|
|
|
74
99
|
generate_citation_map(scholar_id)
|
|
75
100
|
```
|
|
76
101
|
|
|
102
|
+
Note that in Version 4.4, we support manual edit of the csv. You can run `generate_citation_map` first, and get the csv and HTML. Then, you can manually modify the csv content, and generate an updated HTML by running `generate_citation_map` again with `parse_csv=True`.
|
|
103
|
+
|
|
77
104
|
Note that in Version 4.0, we will cache the results before identifying affiliations. So if you want to rerun the same author from scratch, you need to delete the cache (default location is 'cache').
|
|
78
105
|
|
|
79
106
|
More input arguments are shown in [the demo script](https://github.com/ChenLiu-1996/CitationMap/blob/main/demo/demo.py).
|
|
@@ -124,10 +151,12 @@ Besides, there will be a **CSV file** recording citation information (citing aut
|
|
|
124
151
|
- Some authors citing you do not have Google Scholar profiles.
|
|
125
152
|
- Some authors citing you do not report their affiliations.
|
|
126
153
|
2. Webscraping is performed, and CAPTCHA or robot check can often get us, especially if we crawl frequently. This is more often seen in highly cited users. Unless you are blocked by Google Scholar, at worst you will end up with missing several citing authors, which is not likely a huge deal for highly cited users anyways.
|
|
127
|
-
3.
|
|
128
|
-
-
|
|
129
|
-
-
|
|
130
|
-
-
|
|
154
|
+
3. Affiliation identification and geolocating issues. This is a joint effect between affiliation identification and geolocating. The number of citing affiliations will be:
|
|
155
|
+
- Underestimated if some affiliations are not found by `geopy.geocoders`.
|
|
156
|
+
- Underestimated if we experience communication errors with `geopy.geocoders`.
|
|
157
|
+
- (Aggressive approach only) Overestimated if non-affiliation phrases are incorrectly identified as locations by `geopy.geocoders`.
|
|
158
|
+
- (Conservative approach only) Underestimated if the citer did not verify with an email address under a matching affiliation domain.
|
|
159
|
+
- (Conservative approach only) Underestimated because all non-primary (with verified email address) affiliations are ignored.
|
|
131
160
|
|
|
132
161
|
**Please raise an issue or submit a pull request if you have some good idea to better process the affiliation string. Note that currently I am not considering any paid service or tools that pose extra burden on the users, such as GPT API.**
|
|
133
162
|
|
|
@@ -160,6 +189,16 @@ Besides, there will be a **CSV file** recording citation information (citing aut
|
|
|
160
189
|
```
|
|
161
190
|
|
|
162
191
|
## Changelog
|
|
192
|
+
<details>
|
|
193
|
+
<summary>Version 4.4 (Dec 6, 2024)</summary>
|
|
194
|
+
<br>
|
|
195
|
+
|
|
196
|
+
1. **Support manual edit of the csv.** Note you do need to manually correct the coordinates too if you choose to use this functionality. You can run `generate_citation_map` first, and get the csv and HTML. Then, you can manually modify the csv content, and generate an updated HTML by running `generate_citation_map` again with `parse_csv=True`.
|
|
197
|
+
2. Slight optimization on caching.
|
|
198
|
+
|
|
199
|
+
</details>
|
|
200
|
+
|
|
201
|
+
|
|
163
202
|
<details>
|
|
164
203
|
<summary>Version 4.0 (Aug 2, 2024)</summary>
|
|
165
204
|
<br>
|
|
@@ -14,14 +14,15 @@ from geopy.geocoders import Nominatim
|
|
|
14
14
|
from multiprocessing import Pool
|
|
15
15
|
from scholarly import scholarly, ProxyGenerator
|
|
16
16
|
from tqdm import tqdm
|
|
17
|
-
from typing import Any,
|
|
17
|
+
from typing import Any, List, Tuple
|
|
18
18
|
|
|
19
19
|
from .scholarly_support import get_citing_author_ids_and_citing_papers, get_organization_name
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
def find_all_citing_authors(scholar_id: str, num_processes: int = 16) -> List[Tuple[str]]:
|
|
23
23
|
'''
|
|
24
|
-
Step 1. Find all
|
|
24
|
+
Step 1. Find all publications of the given Google Scholar ID.
|
|
25
|
+
Step 2. Find all citing authors.
|
|
25
26
|
'''
|
|
26
27
|
# Find Google Scholar Profile using Scholar ID.
|
|
27
28
|
author = scholarly.search_author_id(scholar_id)
|
|
@@ -70,7 +71,7 @@ def find_all_citing_affiliations(all_citing_author_paper_tuple_list: List[Tuple[
|
|
|
70
71
|
num_processes: int = 16,
|
|
71
72
|
affiliation_conservative: bool = False):
|
|
72
73
|
'''
|
|
73
|
-
Step
|
|
74
|
+
Step 3. Find all citing affiliations.
|
|
74
75
|
'''
|
|
75
76
|
if affiliation_conservative:
|
|
76
77
|
__affiliations_from_authors = __affiliations_from_authors_conservative
|
|
@@ -96,7 +97,7 @@ def find_all_citing_affiliations(all_citing_author_paper_tuple_list: List[Tuple[
|
|
|
96
97
|
|
|
97
98
|
def clean_affiliation_names(author_paper_affiliation_tuple_list: List[Tuple[str]]) -> List[Tuple[str]]:
|
|
98
99
|
'''
|
|
99
|
-
Step
|
|
100
|
+
Optional Step. Clean up the names of affiliations from the authors' affiliation tab on their Google Scholar profiles.
|
|
100
101
|
NOTE: This logic is very naive. Please send an issue or pull request if you have any idea how to improve it.
|
|
101
102
|
Currently we will not consider any paid service or tools that pose extra burden on the users, such as GPT API.
|
|
102
103
|
'''
|
|
@@ -177,9 +178,32 @@ def affiliation_text_to_geocode(author_paper_affiliation_tuple_list: List[Tuple[
|
|
|
177
178
|
coordinates_and_info = [item for item in coordinates_and_info if item is not None] # Filter out empty entries.
|
|
178
179
|
return coordinates_and_info
|
|
179
180
|
|
|
181
|
+
def export_dict_to_csv(coordinates_and_info: List[Tuple[str]], csv_output_path: str) -> None:
|
|
182
|
+
'''
|
|
183
|
+
Step 5.1: Export csv file recording citation information.
|
|
184
|
+
'''
|
|
185
|
+
|
|
186
|
+
citation_df = pd.DataFrame(coordinates_and_info,
|
|
187
|
+
columns=['citing author name', 'citing paper title', 'cited paper title',
|
|
188
|
+
'affiliation', 'latitude', 'longitude',
|
|
189
|
+
'county', 'city', 'state', 'country'])
|
|
190
|
+
|
|
191
|
+
citation_df.to_csv(csv_output_path)
|
|
192
|
+
return
|
|
193
|
+
|
|
194
|
+
def read_csv_to_dict(csv_path: str) -> None:
|
|
195
|
+
'''
|
|
196
|
+
Step 5.1: Read csv file recording citation information.
|
|
197
|
+
Only relevant if `read_from_csv` is True.
|
|
198
|
+
'''
|
|
199
|
+
|
|
200
|
+
citation_df = pd.read_csv(csv_path, index_col=0)
|
|
201
|
+
coordinates_and_info = list(citation_df.itertuples(index=False, name=None))
|
|
202
|
+
return coordinates_and_info
|
|
203
|
+
|
|
180
204
|
def create_map(coordinates_and_info: List[Tuple[str]], pin_colorful: bool = True):
|
|
181
205
|
'''
|
|
182
|
-
Step 5.
|
|
206
|
+
Step 5.2: Create the Citation World Map.
|
|
183
207
|
|
|
184
208
|
For authors under the same affiliations, they will be displayed in the same pin.
|
|
185
209
|
'''
|
|
@@ -217,18 +241,6 @@ def create_map(coordinates_and_info: List[Tuple[str]], pin_colorful: bool = True
|
|
|
217
241
|
folium.Marker([lat, lon], popup='%s (%s)' % (affiliation_name, ' & '.join(author_name_list))).add_to(citation_map)
|
|
218
242
|
return citation_map
|
|
219
243
|
|
|
220
|
-
def export_csv(coordinates_and_info: List[Tuple[str]], csv_output_path: str) -> None:
|
|
221
|
-
'''
|
|
222
|
-
Step 5.2: Export csv file recording citation information.
|
|
223
|
-
'''
|
|
224
|
-
|
|
225
|
-
citation_df = pd.DataFrame(coordinates_and_info,
|
|
226
|
-
columns=['citing author name', 'citing paper title', 'cited paper title',
|
|
227
|
-
'affiliation', 'latitude', 'longitude',
|
|
228
|
-
'county', 'city', 'state', 'country'])
|
|
229
|
-
|
|
230
|
-
citation_df.to_csv(csv_output_path)
|
|
231
|
-
return
|
|
232
244
|
|
|
233
245
|
def __fill_publication_metadata(pub):
|
|
234
246
|
time.sleep(random.uniform(1, 5)) # Random delay to reduce risk of being blocked.
|
|
@@ -328,6 +340,7 @@ def load_cache(fpath: str) -> Any:
|
|
|
328
340
|
def generate_citation_map(scholar_id: str,
|
|
329
341
|
output_path: str = 'citation_map.html',
|
|
330
342
|
csv_output_path: str = 'citation_info.csv',
|
|
343
|
+
parse_csv: bool = False,
|
|
331
344
|
cache_folder: str = 'cache',
|
|
332
345
|
affiliation_conservative: bool = False,
|
|
333
346
|
num_processes: int = 16,
|
|
@@ -347,6 +360,9 @@ def generate_citation_map(scholar_id: str,
|
|
|
347
360
|
csv_output_path: str
|
|
348
361
|
(default is 'citation_info.csv')
|
|
349
362
|
The path to the output csv file.
|
|
363
|
+
parse_csv: bool
|
|
364
|
+
(default is False)
|
|
365
|
+
If True, will directly jump to Step 5.2, using the information loaded from the csv.
|
|
350
366
|
cache_folder: str
|
|
351
367
|
(default is 'cache')
|
|
352
368
|
The folder to save intermediate results, after finding (author, paper) but before finding the affiliations.
|
|
@@ -372,83 +388,110 @@ def generate_citation_map(scholar_id: str,
|
|
|
372
388
|
If true, print the list of citing affiliations (affiliations of citing authors).
|
|
373
389
|
'''
|
|
374
390
|
|
|
375
|
-
if
|
|
376
|
-
pg = ProxyGenerator()
|
|
377
|
-
pg.FreeProxies()
|
|
378
|
-
scholarly.use_proxy(pg)
|
|
379
|
-
print('Using proxy.')
|
|
391
|
+
if not parse_csv:
|
|
380
392
|
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
393
|
+
if use_proxy:
|
|
394
|
+
pg = ProxyGenerator()
|
|
395
|
+
pg.FreeProxies()
|
|
396
|
+
scholarly.use_proxy(pg)
|
|
397
|
+
print('Using proxy.')
|
|
385
398
|
|
|
386
|
-
|
|
387
|
-
|
|
399
|
+
if cache_folder is not None:
|
|
400
|
+
cache_path = os.path.join(cache_folder, scholar_id, 'all_citing_author_paper_tuple_list.pkl')
|
|
401
|
+
else:
|
|
402
|
+
cache_path = None
|
|
388
403
|
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
num_processes=num_processes)
|
|
392
|
-
print('A total of %d citing authors recorded.\n' % len(all_citing_author_paper_tuple_list))
|
|
393
|
-
if cache_path is not None and len(all_citing_author_paper_tuple_list) > 0:
|
|
394
|
-
save_cache(all_citing_author_paper_tuple_list, cache_path)
|
|
395
|
-
print('Saved to cache: %s.\n' % cache_path)
|
|
404
|
+
if cache_path is None or not os.path.exists(cache_path):
|
|
405
|
+
print('No cache found for this author. Finding citing authors from scratch.\n')
|
|
396
406
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
407
|
+
# NOTE: Step 1. Find all publications of the given Google Scholar ID.
|
|
408
|
+
# Step 2. Find all citing authors.
|
|
409
|
+
all_citing_author_paper_tuple_list = find_all_citing_authors(scholar_id=scholar_id,
|
|
410
|
+
num_processes=num_processes)
|
|
411
|
+
print('A total of %d citing authors recorded.\n' % len(all_citing_author_paper_tuple_list))
|
|
412
|
+
if cache_path is not None and len(all_citing_author_paper_tuple_list) > 0:
|
|
413
|
+
save_cache(all_citing_author_paper_tuple_list, cache_path)
|
|
414
|
+
print('Saved to cache: %s.\n' % cache_path)
|
|
415
|
+
|
|
416
|
+
else:
|
|
417
|
+
print('Cache found. Loading author paper information from cache.\n')
|
|
418
|
+
all_citing_author_paper_tuple_list = load_cache(cache_path)
|
|
419
|
+
print('Loaded from cache: %s.\n' % cache_path)
|
|
420
|
+
print('A total of %d citing authors loaded.\n' % len(all_citing_author_paper_tuple_list))
|
|
421
|
+
|
|
422
|
+
if cache_folder is not None:
|
|
423
|
+
cache_path = os.path.join(cache_folder, scholar_id, 'author_paper_affiliation_tuple_list.pkl')
|
|
424
|
+
else:
|
|
425
|
+
cache_path = None
|
|
426
|
+
|
|
427
|
+
if cache_path is None or not os.path.exists(cache_path):
|
|
428
|
+
print('No cache found for this author. Finding citing affiliations from scratch.\n')
|
|
429
|
+
|
|
430
|
+
# NOTE: Step 2. Find all citing affiliations.
|
|
431
|
+
print('Identifying affiliations using the %s approach.' % ('conservative' if affiliation_conservative else 'aggressive'))
|
|
432
|
+
author_paper_affiliation_tuple_list = find_all_citing_affiliations(all_citing_author_paper_tuple_list,
|
|
433
|
+
num_processes=num_processes,
|
|
434
|
+
affiliation_conservative=affiliation_conservative)
|
|
435
|
+
print('\nA total of %d citing affiliations recorded.\n' % len(author_paper_affiliation_tuple_list))
|
|
436
|
+
# Take unique tuples.
|
|
437
|
+
author_paper_affiliation_tuple_list = list(set(author_paper_affiliation_tuple_list))
|
|
438
|
+
|
|
439
|
+
# NOTE: Step 3. Clean the affiliation strings (optional, only used if taking the aggressive approach).
|
|
440
|
+
if print_citing_affiliations:
|
|
441
|
+
if affiliation_conservative:
|
|
442
|
+
print('Taking the conservative approach. Will not need to clean the affiliation names.')
|
|
443
|
+
print('List of all citing authors and affiliations:\n')
|
|
444
|
+
else:
|
|
445
|
+
print('Taking the aggressive approach. Cleaning the affiliation names.')
|
|
446
|
+
print('List of all citing authors and affiliations before cleaning:\n')
|
|
447
|
+
__print_author_and_affiliation(author_paper_affiliation_tuple_list)
|
|
448
|
+
if not affiliation_conservative:
|
|
449
|
+
cleaned_author_paper_affiliation_tuple_list = clean_affiliation_names(author_paper_affiliation_tuple_list)
|
|
450
|
+
if print_citing_affiliations:
|
|
451
|
+
print('List of all citing authors and affiliations after cleaning:\n')
|
|
452
|
+
__print_author_and_affiliation(cleaned_author_paper_affiliation_tuple_list)
|
|
453
|
+
# Use the merged set to maximize coverage.
|
|
454
|
+
author_paper_affiliation_tuple_list += cleaned_author_paper_affiliation_tuple_list
|
|
455
|
+
# Take unique tuples.
|
|
456
|
+
author_paper_affiliation_tuple_list = list(set(author_paper_affiliation_tuple_list))
|
|
457
|
+
|
|
458
|
+
if cache_path is not None and len(author_paper_affiliation_tuple_list) > 0:
|
|
459
|
+
save_cache(author_paper_affiliation_tuple_list, cache_path)
|
|
460
|
+
print('Saved to cache: %s.\n' % cache_path)
|
|
413
461
|
|
|
414
|
-
# NOTE: Step 3. Clean the affiliation strings (optional, only used if taking the aggressive approach).
|
|
415
|
-
if print_citing_affiliations:
|
|
416
|
-
if affiliation_conservative:
|
|
417
|
-
print('Taking the conservative approach. Will not need to clean the affiliation names.')
|
|
418
|
-
print('List of all citing authors and affiliations:\n')
|
|
419
462
|
else:
|
|
420
|
-
print('
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
__print_author_and_affiliation(cleaned_author_paper_affiliation_tuple_list)
|
|
428
|
-
# Use the merged set to maximize coverage.
|
|
429
|
-
author_paper_affiliation_tuple_list += cleaned_author_paper_affiliation_tuple_list
|
|
463
|
+
print('Cache found. Loading author paper and affiliation information from cache.\n')
|
|
464
|
+
author_paper_affiliation_tuple_list = load_cache(cache_path)
|
|
465
|
+
print('List of all citing authors and affiliations loaded:\n')
|
|
466
|
+
__print_author_and_affiliation(author_paper_affiliation_tuple_list)
|
|
467
|
+
|
|
468
|
+
# NOTE: Step 4. Convert affiliations in plain text to Geocode.
|
|
469
|
+
coordinates_and_info = affiliation_text_to_geocode(author_paper_affiliation_tuple_list)
|
|
430
470
|
# Take unique tuples.
|
|
431
|
-
|
|
471
|
+
coordinates_and_info = list(set(coordinates_and_info))
|
|
432
472
|
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
coordinates_and_info = list(set(coordinates_and_info))
|
|
473
|
+
# NOTE: Step 5.1. Export csv file recording citation information.
|
|
474
|
+
export_dict_to_csv(coordinates_and_info, csv_output_path)
|
|
475
|
+
print('\nCitation information exported to %s.' % csv_output_path)
|
|
437
476
|
|
|
438
|
-
|
|
477
|
+
else:
|
|
478
|
+
print('\nDirectly parsing the csv. Skipping all previous steps.')
|
|
479
|
+
assert os.path.isfile(csv_output_path), '`csv_output_path` is not a file.'
|
|
480
|
+
coordinates_and_info = read_csv_to_dict(csv_output_path)
|
|
481
|
+
print('\nCitation information loaded from %s.' % csv_output_path)
|
|
482
|
+
|
|
483
|
+
# NOTE: Step 5.2. Create the citation world map.
|
|
439
484
|
citation_map = create_map(coordinates_and_info, pin_colorful=pin_colorful)
|
|
440
485
|
citation_map.save(output_path)
|
|
441
|
-
print('\
|
|
442
|
-
|
|
443
|
-
# NOTE: Step 5.2. Export csv file recording citation information.
|
|
444
|
-
export_csv(coordinates_and_info, csv_output_path)
|
|
445
|
-
print('\nCitation information exported to %s.' % csv_output_path)
|
|
486
|
+
print('\nHTML map created and saved at %s.\n' % output_path)
|
|
446
487
|
return
|
|
447
488
|
|
|
448
489
|
|
|
449
490
|
if __name__ == '__main__':
|
|
450
491
|
# Replace this with your Google Scholar ID.
|
|
451
492
|
scholar_id = '3rDjnykAAAAJ'
|
|
452
|
-
generate_citation_map(scholar_id, output_path='citation_map.html',
|
|
493
|
+
generate_citation_map(scholar_id, output_path='citation_map.html',
|
|
494
|
+
csv_output_path='citation_info.csv',
|
|
495
|
+
parse_csv=False,
|
|
453
496
|
cache_folder='cache', affiliation_conservative=True, num_processes=16,
|
|
454
497
|
use_proxy=False, pin_colorful=True, print_citing_affiliations=True)
|
|
@@ -7,6 +7,35 @@ from bs4 import BeautifulSoup
|
|
|
7
7
|
from typing import List
|
|
8
8
|
|
|
9
9
|
|
|
10
|
+
def get_html_per_citation_page(soup) -> List[str]:
|
|
11
|
+
'''
|
|
12
|
+
Utility to query each page containing results for
|
|
13
|
+
cited work.
|
|
14
|
+
Parameters
|
|
15
|
+
--------
|
|
16
|
+
soup: Beautiful Soup object pointing to current page.
|
|
17
|
+
'''
|
|
18
|
+
citing_authors_and_citing_papers = []
|
|
19
|
+
|
|
20
|
+
for result in soup.find_all('div', class_='gs_ri'):
|
|
21
|
+
title_tag = result.find('h3', class_='gs_rt')
|
|
22
|
+
if title_tag:
|
|
23
|
+
paper_parsed = False
|
|
24
|
+
author_links = result.find_all('a', href=True)
|
|
25
|
+
title_text = title_tag.get_text()
|
|
26
|
+
title = title_text.replace('[HTML]', '').replace('[PDF]', '')
|
|
27
|
+
for link in author_links:
|
|
28
|
+
if 'user=' in link['href']:
|
|
29
|
+
author_id = link['href'].split('user=')[1].split('&')[0]
|
|
30
|
+
citing_authors_and_citing_papers.append((author_id, title))
|
|
31
|
+
paper_parsed = True
|
|
32
|
+
if not paper_parsed:
|
|
33
|
+
print("[WARNING!] Could not find author links for ", title)
|
|
34
|
+
else:
|
|
35
|
+
continue
|
|
36
|
+
return citing_authors_and_citing_papers
|
|
37
|
+
|
|
38
|
+
|
|
10
39
|
def get_citing_author_ids_and_citing_papers(paper_url: str) -> List[str]:
|
|
11
40
|
'''
|
|
12
41
|
Find the (Google Scholar IDs of authors, titles of papers) who cite a given paper on Google Scholar.
|
|
@@ -15,7 +44,6 @@ def get_citing_author_ids_and_citing_papers(paper_url: str) -> List[str]:
|
|
|
15
44
|
--------
|
|
16
45
|
paper_url: URL of the paper BEING cited.
|
|
17
46
|
'''
|
|
18
|
-
|
|
19
47
|
citing_authors_and_citing_papers = []
|
|
20
48
|
|
|
21
49
|
headers = requests.utils.default_headers()
|
|
@@ -44,36 +72,25 @@ def get_citing_author_ids_and_citing_papers(paper_url: str) -> List[str]:
|
|
|
44
72
|
|
|
45
73
|
# Loop through the citation results and find citing authors and papers.
|
|
46
74
|
current_page_number = 1
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
if page_number_str and page_number_str.isnumeric() and int(page_number_str) == current_page_number + 1:
|
|
65
|
-
# Found the correct button for next page.
|
|
66
|
-
current_page_number += 1
|
|
67
|
-
next_url = 'https://scholar.google.com' + navigation['href']
|
|
68
|
-
time.sleep(random.uniform(1, 5)) # Random delay to reduce risk of being blocked.
|
|
69
|
-
response = requests.get(next_url, headers=headers)
|
|
70
|
-
if response.status_code != 200:
|
|
71
|
-
break
|
|
72
|
-
soup = BeautifulSoup(response.text, 'html.parser')
|
|
73
|
-
else:
|
|
74
|
-
continue
|
|
75
|
+
citing_authors_and_citing_papers += get_html_per_citation_page(soup)
|
|
76
|
+
|
|
77
|
+
# Find the page navigation.
|
|
78
|
+
navigation_buttons = soup.find_all('a', class_='gs_nma')
|
|
79
|
+
for navigation in navigation_buttons:
|
|
80
|
+
page_number_str = navigation.text
|
|
81
|
+
if page_number_str and page_number_str.isnumeric() and int(page_number_str) == current_page_number + 1:
|
|
82
|
+
# Found the correct button for next page.
|
|
83
|
+
current_page_number += 1
|
|
84
|
+
next_url = 'https://scholar.google.com' + navigation['href']
|
|
85
|
+
time.sleep(random.uniform(1, 5)) # Random delay to reduce risk of being blocked.
|
|
86
|
+
|
|
87
|
+
response = requests.get(next_url, headers=headers)
|
|
88
|
+
if response.status_code != 200:
|
|
89
|
+
break
|
|
90
|
+
soup = BeautifulSoup(response.text, 'html.parser')
|
|
91
|
+
citing_authors_and_citing_papers += get_html_per_citation_page(soup)
|
|
75
92
|
else:
|
|
76
|
-
|
|
93
|
+
continue
|
|
77
94
|
|
|
78
95
|
return citing_authors_and_citing_papers
|
|
79
96
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: citation-map
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.4
|
|
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
|
|
@@ -16,10 +16,11 @@ License-File: LICENSE.md
|
|
|
16
16
|
|
|
17
17
|
# Google Scholar Citation World Map
|
|
18
18
|
|
|
19
|
+
[](https://www.techrxiv.org/users/809001/articles/1213717-citationmap-a-python-tool-to-identify-and-visualize-your-google-scholar-citations-around-the-world)
|
|
20
|
+
[](https://openreview.net/pdf?id=BqJgCgl1IA)
|
|
19
21
|
[](https://pypi.org/project/citation-map/)
|
|
20
22
|
[](https://pypistats.org/packages/citation-map)
|
|
21
23
|
[](https://pypistats.org/packages/citation-map)
|
|
22
|
-
[](https://www.python.org/)
|
|
23
24
|
[![CC BY-NC-SA 4.0][cc-by-nc-sa-shield]][cc-by-nc-sa]
|
|
24
25
|
[![CC BY-NC-SA 4.0][cc-by-nc-sa-image]][cc-by-nc-sa]
|
|
25
26
|
|
|
@@ -27,13 +28,14 @@ License-File: LICENSE.md
|
|
|
27
28
|
[cc-by-nc-sa-image]: https://licensebuttons.net/l/by-nc-sa/4.0/88x31.png
|
|
28
29
|
[cc-by-nc-sa-shield]: https://img.shields.io/badge/License-CC%20BY--NC--SA%204.0-lightgrey.svg
|
|
29
30
|
|
|
30
|
-
[Chen Liu](https://
|
|
31
|
+
[Chen Liu](https://chenliu-1996.github.io/), CS PhD Candidate at Yale University.
|
|
31
32
|
|
|
32
33
|
Research areas: Machine Learning, Spatial-Temporal Modeling, Medical Vision, AI4Science.
|
|
33
34
|
|
|
35
|
+
|
|
34
36
|
## News
|
|
35
37
|
**[Asking for advice]**
|
|
36
|
-
1. This is my first time dealing with webscraping/crawling. Users have reported stability issues, and I suspect the major problems are (1) being caught by CAPTCHA or robot check, and (2) being flagged for blacklist by Google Scholar. If you are experienced in these areas and have good advice, I would highly appreciate a GitHub issue or a pull request
|
|
38
|
+
1. This is my first time dealing with webscraping/crawling. Users have reported stability issues, and I suspect the major problems are (1) being caught by CAPTCHA or robot check, and (2) being flagged for blacklist by Google Scholar. If you are experienced in these areas and have good advice, I would highly appreciate a **GitHub issue or a pull request**.
|
|
37
39
|
|
|
38
40
|
[Aug 2, 2024] Version 4.0 released >>> Logic update. A new input argument `affiliation_conservative`. If set to True, we will use **a very conservative approach to identify affiliations** which leads to **much higher precision and lower recall**. Many thanks to [Zhijian Liu](https://github.com/zhijian-liu) for the [helpful discussion](https://github.com/ChenLiu-1996/CitationMap/issues/8).
|
|
39
41
|
|
|
@@ -63,6 +65,29 @@ Besides, there will be a **CSV file** recording citation information (citing aut
|
|
|
63
65
|
|
|
64
66
|
**NOTE:** **Now you can trade off between affiliation precision and recall** with the `affiliation_conservative` option. If set to True, we will use the Google Scholar verified official organization name from the citing authors. This is a very conservative approach, since (1) the author needs to self-report it in the affiliation panel, (2) the author needs to verify with the matching email address, and (3) the organization needs to be recorded by Google Scholar. For example, Meta (the company) is not in the list. Many thanks to [Zhijian Liu](https://github.com/zhijian-liu) for the [helpful discussion](https://github.com/ChenLiu-1996/CitationMap/issues/8).
|
|
65
67
|
|
|
68
|
+
## Citation
|
|
69
|
+
BibTeX
|
|
70
|
+
```
|
|
71
|
+
@article{citationmap,
|
|
72
|
+
title={CitationMap: A Python Tool to Identify and Visualize Your Google Scholar Citations Around the World},
|
|
73
|
+
author={Liu, Chen},
|
|
74
|
+
journal={Authorea Preprints},
|
|
75
|
+
year={2024},
|
|
76
|
+
publisher={Authorea}
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
MLA
|
|
80
|
+
```
|
|
81
|
+
Liu, Chen. "CitationMap: A Python Tool to Identify and Visualize Your Google Scholar Citations Around the World." Authorea Preprints (2024).
|
|
82
|
+
```
|
|
83
|
+
APA
|
|
84
|
+
```
|
|
85
|
+
Liu, C. (2024). CitationMap: A Python Tool to Identify and Visualize Your Google Scholar Citations Around the World. Authorea Preprints.
|
|
86
|
+
```
|
|
87
|
+
Chicago
|
|
88
|
+
```
|
|
89
|
+
Liu, Chen. "CitationMap: A Python Tool to Identify and Visualize Your Google Scholar Citations Around the World." Authorea Preprints (2024).
|
|
90
|
+
```
|
|
66
91
|
|
|
67
92
|
## User Guide
|
|
68
93
|
0. If you are new to Python, you probably want to start with a distribution of Python that also helps with environment management (such as [anaconda](https://www.anaconda.com/)). Once you have set up your environment (for example, when you reach the stage of `conda activate env39` in [this tutorial](https://www.youtube.com/watch?v=MUZtVEDKXsk&t=242s)), you can move on to the next step.
|
|
@@ -90,6 +115,8 @@ Besides, there will be a **CSV file** recording citation information (citing aut
|
|
|
90
115
|
generate_citation_map(scholar_id)
|
|
91
116
|
```
|
|
92
117
|
|
|
118
|
+
Note that in Version 4.4, we support manual edit of the csv. You can run `generate_citation_map` first, and get the csv and HTML. Then, you can manually modify the csv content, and generate an updated HTML by running `generate_citation_map` again with `parse_csv=True`.
|
|
119
|
+
|
|
93
120
|
Note that in Version 4.0, we will cache the results before identifying affiliations. So if you want to rerun the same author from scratch, you need to delete the cache (default location is 'cache').
|
|
94
121
|
|
|
95
122
|
More input arguments are shown in [the demo script](https://github.com/ChenLiu-1996/CitationMap/blob/main/demo/demo.py).
|
|
@@ -140,10 +167,12 @@ Besides, there will be a **CSV file** recording citation information (citing aut
|
|
|
140
167
|
- Some authors citing you do not have Google Scholar profiles.
|
|
141
168
|
- Some authors citing you do not report their affiliations.
|
|
142
169
|
2. Webscraping is performed, and CAPTCHA or robot check can often get us, especially if we crawl frequently. This is more often seen in highly cited users. Unless you are blocked by Google Scholar, at worst you will end up with missing several citing authors, which is not likely a huge deal for highly cited users anyways.
|
|
143
|
-
3.
|
|
144
|
-
-
|
|
145
|
-
-
|
|
146
|
-
-
|
|
170
|
+
3. Affiliation identification and geolocating issues. This is a joint effect between affiliation identification and geolocating. The number of citing affiliations will be:
|
|
171
|
+
- Underestimated if some affiliations are not found by `geopy.geocoders`.
|
|
172
|
+
- Underestimated if we experience communication errors with `geopy.geocoders`.
|
|
173
|
+
- (Aggressive approach only) Overestimated if non-affiliation phrases are incorrectly identified as locations by `geopy.geocoders`.
|
|
174
|
+
- (Conservative approach only) Underestimated if the citer did not verify with an email address under a matching affiliation domain.
|
|
175
|
+
- (Conservative approach only) Underestimated because all non-primary (with verified email address) affiliations are ignored.
|
|
147
176
|
|
|
148
177
|
**Please raise an issue or submit a pull request if you have some good idea to better process the affiliation string. Note that currently I am not considering any paid service or tools that pose extra burden on the users, such as GPT API.**
|
|
149
178
|
|
|
@@ -176,6 +205,16 @@ Besides, there will be a **CSV file** recording citation information (citing aut
|
|
|
176
205
|
```
|
|
177
206
|
|
|
178
207
|
## Changelog
|
|
208
|
+
<details>
|
|
209
|
+
<summary>Version 4.4 (Dec 6, 2024)</summary>
|
|
210
|
+
<br>
|
|
211
|
+
|
|
212
|
+
1. **Support manual edit of the csv.** Note you do need to manually correct the coordinates too if you choose to use this functionality. You can run `generate_citation_map` first, and get the csv and HTML. Then, you can manually modify the csv content, and generate an updated HTML by running `generate_citation_map` again with `parse_csv=True`.
|
|
213
|
+
2. Slight optimization on caching.
|
|
214
|
+
|
|
215
|
+
</details>
|
|
216
|
+
|
|
217
|
+
|
|
179
218
|
<details>
|
|
180
219
|
<summary>Version 4.0 (Aug 2, 2024)</summary>
|
|
181
220
|
<br>
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|