gismap 0.2.2__py3-none-any.whl → 0.4.0__py3-none-any.whl
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.
- gismap/__init__.py +2 -0
- gismap/build.py +4 -0
- gismap/gisgraphs/__init__.py +0 -0
- gismap/gisgraphs/builder.py +105 -0
- gismap/{lab → gisgraphs}/graph.py +70 -66
- gismap/gisgraphs/groups.py +70 -0
- gismap/gisgraphs/js.py +190 -0
- gismap/gisgraphs/options.py +37 -0
- gismap/gisgraphs/style.py +119 -0
- gismap/gisgraphs/widget.py +145 -0
- gismap/lab/__init__.py +0 -4
- gismap/lab/egomap.py +6 -7
- gismap/lab/expansion.py +7 -6
- gismap/lab/filters.py +1 -1
- gismap/lab/lab_author.py +50 -6
- gismap/lab/labmap.py +7 -6
- gismap/lab_examples/__init__.py +0 -0
- gismap/lab_examples/cedric.py +46 -0
- gismap/lab_examples/lamsade.py +43 -0
- gismap/{lab → lab_examples}/lincs.py +2 -2
- gismap/{lab → lab_examples}/toulouse.py +20 -3
- gismap/sources/dblp.py +16 -18
- gismap/sources/dblp_ttl.py +168 -0
- gismap/sources/hal.py +19 -10
- gismap/sources/ldb.py +501 -0
- gismap/sources/models.py +7 -0
- gismap/sources/multi.py +25 -17
- gismap/utils/common.py +15 -10
- gismap/utils/logger.py +2 -0
- gismap/utils/requests.py +6 -2
- gismap/utils/zlist.py +68 -0
- {gismap-0.2.2.dist-info → gismap-0.4.0.dist-info}/METADATA +37 -8
- gismap-0.4.0.dist-info/RECORD +43 -0
- {gismap-0.2.2.dist-info → gismap-0.4.0.dist-info}/WHEEL +1 -1
- gismap/lab/vis.py +0 -329
- gismap-0.2.2.dist-info/RECORD +0 -30
- /gismap/{lab → lab_examples}/lip6.py +0 -0
- {gismap-0.2.2.dist-info → gismap-0.4.0.dist-info}/licenses/AUTHORS.md +0 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
from string import Template
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
# language=css
|
|
5
|
+
default_style = Template("""
|
|
6
|
+
|
|
7
|
+
#box-$uid {
|
|
8
|
+
position: relative;
|
|
9
|
+
width: 100% !important;
|
|
10
|
+
height: 80vh !important;
|
|
11
|
+
max-width: 100vw !important;
|
|
12
|
+
max-height: 80vh !important;
|
|
13
|
+
min-height: 80vh;
|
|
14
|
+
color: #111;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
#vis-$uid {
|
|
18
|
+
height: 100%; /* Make the inner div fill the parent */
|
|
19
|
+
width: 100%; /* Make the inner div fill the parent */
|
|
20
|
+
box-sizing: border-box;
|
|
21
|
+
border: 1px solid #444;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
html[data-theme="dark"] #vis-$uid {
|
|
25
|
+
background-color: var(--pst-color-background, #14181e);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.modal {
|
|
29
|
+
display: none;
|
|
30
|
+
position: fixed;
|
|
31
|
+
z-index: 1000;
|
|
32
|
+
left: 0;
|
|
33
|
+
top: 0;
|
|
34
|
+
width: 100%;
|
|
35
|
+
height: 100%;
|
|
36
|
+
overflow: auto;
|
|
37
|
+
background-color: rgba(10, 10, 10, 0.85);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.modal-content {
|
|
41
|
+
background-color: #f4f4f7;
|
|
42
|
+
color: #222235;
|
|
43
|
+
margin: 10% auto;
|
|
44
|
+
padding: 24px;
|
|
45
|
+
border: 1px solid #888;
|
|
46
|
+
width: 50%;
|
|
47
|
+
border-radius: 8px;
|
|
48
|
+
box-shadow: 0 5px 15px rgba(0, 0, 0, .6);
|
|
49
|
+
}
|
|
50
|
+
.modal a {color: #2958d7;}
|
|
51
|
+
.modal a:visited {color: #8435a8;}
|
|
52
|
+
|
|
53
|
+
.close {
|
|
54
|
+
color: #777;
|
|
55
|
+
float: right;
|
|
56
|
+
font-size: 28px;
|
|
57
|
+
font-weight: bold;
|
|
58
|
+
cursor: pointer;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.close:hover, .close:focus {
|
|
62
|
+
color: #aaa;
|
|
63
|
+
text-decoration: none;
|
|
64
|
+
cursor: pointer;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.watermark {
|
|
68
|
+
position: absolute;
|
|
69
|
+
text-decoration: none;
|
|
70
|
+
color: #888;
|
|
71
|
+
font-size: min(2vw, 10px);
|
|
72
|
+
z-index: 10;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.gislink {
|
|
76
|
+
left: 10px;
|
|
77
|
+
bottom: 10px;
|
|
78
|
+
pointer-events: auto;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.button {
|
|
82
|
+
background: none;
|
|
83
|
+
border: none;
|
|
84
|
+
padding: 0;
|
|
85
|
+
margin: 0;
|
|
86
|
+
cursor: pointer;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.redraw {
|
|
90
|
+
left: 10px;
|
|
91
|
+
top: 10px;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.fullscreen {
|
|
95
|
+
bottom: 10px;
|
|
96
|
+
right: 10px;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.legend {
|
|
100
|
+
display: inline-block;
|
|
101
|
+
padding: 10px 16px;
|
|
102
|
+
border-radius: 8px;
|
|
103
|
+
box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.10);
|
|
104
|
+
border: 1px solid var(--legend-border, #bbb);
|
|
105
|
+
background: var(--jp-layout-color1, #f5f5fa);
|
|
106
|
+
background-color: var(--legend-bg, rgba(240, 240, 245, 0.95));
|
|
107
|
+
position: absolute;
|
|
108
|
+
top: 12px;
|
|
109
|
+
right: 12px;
|
|
110
|
+
z-index: 20;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.legend-entry {
|
|
114
|
+
display: flex;
|
|
115
|
+
margin-right: 10px;
|
|
116
|
+
align-items: center;
|
|
117
|
+
cursor: pointer;
|
|
118
|
+
}
|
|
119
|
+
""")
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import re
|
|
2
|
+
import unicodedata
|
|
3
|
+
import base64
|
|
4
|
+
from IPython.display import display, HTML
|
|
5
|
+
import ipywidgets as widgets
|
|
6
|
+
from contextlib import contextmanager
|
|
7
|
+
|
|
8
|
+
from gismap.lab.egomap import EgoMap
|
|
9
|
+
from gismap.lab.labmap import ListMap
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@contextmanager
|
|
13
|
+
def dummy_context():
|
|
14
|
+
yield
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def safe_filename(name):
|
|
18
|
+
"""
|
|
19
|
+
Parameters
|
|
20
|
+
----------
|
|
21
|
+
name: :class:`str`
|
|
22
|
+
Pretty much anything.
|
|
23
|
+
|
|
24
|
+
Returns
|
|
25
|
+
-------
|
|
26
|
+
:class:`str`
|
|
27
|
+
GisMap filename.
|
|
28
|
+
"""
|
|
29
|
+
normalized = unicodedata.normalize("NFKD", name)
|
|
30
|
+
ascii_only = normalized.encode("ascii", "ignore").decode("ascii")
|
|
31
|
+
ascii_only = ascii_only.replace(" ", "_")
|
|
32
|
+
safe_str = re.sub(r"[^a-zA-Z0-9_]", "", ascii_only)
|
|
33
|
+
return f"gismap-{safe_str[:60]}.html"
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
place_holder = "Diego Perino, The-Dang Huynh, François Durand (hal: fradurand, ldb: 38/11269), Rim Kaddah, Leonardo Linguaglossa, Céline Comte"
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class GismapWidget:
|
|
40
|
+
"""
|
|
41
|
+
A simple widget to test the production of LabMaps and EgoMaps.
|
|
42
|
+
|
|
43
|
+
Examples
|
|
44
|
+
--------
|
|
45
|
+
|
|
46
|
+
This is a doctest example. Use a notebook to play with the widget.
|
|
47
|
+
|
|
48
|
+
>>> gw = GismapWidget() # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
|
|
49
|
+
VBox(children=(HTML(value=''), Output(), HBox(children=(Textarea(value='', ...
|
|
50
|
+
>>> gw.names.value = "Fabien Mathieu"
|
|
51
|
+
>>> gw.dbs.value = "HAL"
|
|
52
|
+
>>> gw.size.value = 3
|
|
53
|
+
>>> gw.compute_function(gw.compute, show=False)
|
|
54
|
+
>>> gw.save_link.value[:30]
|
|
55
|
+
"<a href='data:text/html;base64"
|
|
56
|
+
>>> gw.names.value = "Diego Perino, Laurent Viennot"
|
|
57
|
+
>>> gw.compute_function(gw.compute, show=False)
|
|
58
|
+
>>> gw.save_link.value[:30]
|
|
59
|
+
"<a href='data:text/html;base64"
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
def __init__(self):
|
|
63
|
+
self.names = widgets.Textarea(
|
|
64
|
+
placeholder=place_holder,
|
|
65
|
+
description="Name(s):",
|
|
66
|
+
layout=widgets.Layout(width="50%", height="100px"),
|
|
67
|
+
)
|
|
68
|
+
self.dbs = widgets.RadioButtons(
|
|
69
|
+
options=["HAL", "LDB", "Both"],
|
|
70
|
+
description="DB(s):",
|
|
71
|
+
layout=widgets.Layout(width="80px", max_width="20%"),
|
|
72
|
+
)
|
|
73
|
+
self.size = widgets.IntSlider(
|
|
74
|
+
value=10,
|
|
75
|
+
min=1,
|
|
76
|
+
max=150,
|
|
77
|
+
step=1,
|
|
78
|
+
description="Size",
|
|
79
|
+
layout=widgets.Layout(width="250px"),
|
|
80
|
+
)
|
|
81
|
+
self.compute = widgets.Button(
|
|
82
|
+
description="Map!", layout=widgets.Layout(width="120px", max_width="140px")
|
|
83
|
+
)
|
|
84
|
+
self._col = widgets.VBox(
|
|
85
|
+
[self.size, self.compute],
|
|
86
|
+
layout=widgets.Layout(
|
|
87
|
+
align_items="center", max_width="27%", overflow="hidden"
|
|
88
|
+
),
|
|
89
|
+
)
|
|
90
|
+
self.save_link = widgets.HTML(value="")
|
|
91
|
+
self.compute.on_click(self.compute_function)
|
|
92
|
+
self.out = widgets.Output()
|
|
93
|
+
self.widget = widgets.VBox(
|
|
94
|
+
[self.save_link, self.out, widgets.HBox([self.names, self._col, self.dbs])]
|
|
95
|
+
)
|
|
96
|
+
display(self.widget)
|
|
97
|
+
self.show = True
|
|
98
|
+
|
|
99
|
+
def html(self):
|
|
100
|
+
dbs = (
|
|
101
|
+
"hal"
|
|
102
|
+
if self.dbs.value == "HAL"
|
|
103
|
+
else "ldb"
|
|
104
|
+
if self.dbs.value == "LDB"
|
|
105
|
+
else ["hal", "ldb"]
|
|
106
|
+
)
|
|
107
|
+
name = self.names.value
|
|
108
|
+
pattern = r",\s*(?![^()]*\))"
|
|
109
|
+
names = [n.strip() for n in re.split(pattern, name)]
|
|
110
|
+
self.save_link.value = ""
|
|
111
|
+
ctx = self.out if self.show else dummy_context()
|
|
112
|
+
if len(names) > 1:
|
|
113
|
+
lab = ListMap(names, dbs=dbs, name="planet")
|
|
114
|
+
if self.show:
|
|
115
|
+
self.out.clear_output()
|
|
116
|
+
with ctx:
|
|
117
|
+
lab.update_authors()
|
|
118
|
+
lab.update_publis()
|
|
119
|
+
extra = self.size.value - len(lab.authors)
|
|
120
|
+
if extra > 0:
|
|
121
|
+
lab.expand(target=extra)
|
|
122
|
+
else:
|
|
123
|
+
lab = EgoMap(names[0], dbs=dbs)
|
|
124
|
+
if self.show:
|
|
125
|
+
self.out.clear_output()
|
|
126
|
+
with ctx:
|
|
127
|
+
lab.build(target=self.size.value)
|
|
128
|
+
return lab.html()
|
|
129
|
+
|
|
130
|
+
def compute_function(self, b, show=True):
|
|
131
|
+
self.show = show
|
|
132
|
+
full = self.html()
|
|
133
|
+
b64 = base64.b64encode(
|
|
134
|
+
f"<html><body>{full}</body></html>".encode("utf8")
|
|
135
|
+
).decode("utf8")
|
|
136
|
+
payload = f"data:text/html;base64,{b64}"
|
|
137
|
+
savename = safe_filename(self.names.value)
|
|
138
|
+
link_html = (
|
|
139
|
+
f"<a href='{payload}' download='{savename}'>Download the Map!</a>"
|
|
140
|
+
)
|
|
141
|
+
self.save_link.value = link_html
|
|
142
|
+
if show:
|
|
143
|
+
self.out.clear_output()
|
|
144
|
+
with self.out:
|
|
145
|
+
display(HTML(full))
|
gismap/lab/__init__.py
CHANGED
|
@@ -2,9 +2,5 @@ from gismap.lab.labmap import (
|
|
|
2
2
|
LabMap as Map,
|
|
3
3
|
ListMap as ListMap,
|
|
4
4
|
)
|
|
5
|
-
from gismap.lab.lip6 import Lip6Full as Lip6Full, Lip6Map as Lip6
|
|
6
|
-
from gismap.lab.toulouse import SolaceMap as Solace, LaasMap as Laas
|
|
7
|
-
from gismap.lab.graph import lab2graph as lab2graph
|
|
8
|
-
from gismap.lab.vis import generate_html as generate_html
|
|
9
5
|
from gismap.lab.egomap import EgoMap as EgoMap
|
|
10
6
|
from gismap.lab.lab_author import LabAuthor as LabAuthor
|
gismap/lab/egomap.py
CHANGED
|
@@ -15,15 +15,15 @@ class EgoMap(LabMap):
|
|
|
15
15
|
|
|
16
16
|
>>> dang = EgoMap("The-Dang Huynh", dbs="hal")
|
|
17
17
|
>>> dang.build(target=10)
|
|
18
|
-
>>> sorted(a.name for a in dang.authors.values()) # doctest: +NORMALIZE_WHITESPACE
|
|
19
|
-
['Bruno Kauffmann', 'Chung Shue Chen', 'Fabien Mathieu'
|
|
20
|
-
'Siu-Wai Ho', 'Sébastien Tixeuil', 'The-Dang Huynh', 'Yannick Carlinet']
|
|
18
|
+
>>> sorted(a.name for a in dang.authors.values()) # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS
|
|
19
|
+
['Bruno Kauffmann', 'Chung Shue Chen', 'Fabien Mathieu',...
|
|
21
20
|
"""
|
|
22
21
|
|
|
23
22
|
def __init__(self, star, *args, **kwargs):
|
|
24
23
|
if isinstance(star, str):
|
|
25
24
|
star = LabAuthor(star)
|
|
26
25
|
star.metadata.position = (0, 0)
|
|
26
|
+
star.metadata.group = "star"
|
|
27
27
|
self.star = star
|
|
28
28
|
super().__init__(*args, **kwargs)
|
|
29
29
|
|
|
@@ -32,11 +32,10 @@ class EgoMap(LabMap):
|
|
|
32
32
|
|
|
33
33
|
def build(self, **kwargs):
|
|
34
34
|
target = kwargs.pop("target", 50)
|
|
35
|
-
group = kwargs.pop("group", "moon")
|
|
36
35
|
self.update_authors(desc="Star metadata")
|
|
37
36
|
self.update_publis(desc="Star publications")
|
|
38
37
|
kwargs["target"] = target - len(self.authors)
|
|
39
|
-
self.expand(group=
|
|
40
|
-
kwargs
|
|
38
|
+
self.expand(group="planet", desc="Planets", **kwargs)
|
|
39
|
+
kwargs["target"] = target - len(self.authors)
|
|
41
40
|
if kwargs["target"] > 0:
|
|
42
|
-
self.expand(desc="Moons", **kwargs)
|
|
41
|
+
self.expand(group="moon", desc="Moons", **kwargs)
|
gismap/lab/expansion.py
CHANGED
|
@@ -73,8 +73,8 @@ def count_prospect_entries(lab):
|
|
|
73
73
|
count_publications.append(a.key)
|
|
74
74
|
else:
|
|
75
75
|
lab_authors.add(a.key)
|
|
76
|
-
for
|
|
77
|
-
count_coauthors[
|
|
76
|
+
for a in lab_authors:
|
|
77
|
+
count_coauthors[a].update(new_authors)
|
|
78
78
|
|
|
79
79
|
count_coauthors = Counter(
|
|
80
80
|
k for new_authors in count_coauthors.values() for k in new_authors
|
|
@@ -222,12 +222,13 @@ def proper_prospects(
|
|
|
222
222
|
locs = [j for j in np.where(jc[i, :] > threshold)[0] if not done[j]]
|
|
223
223
|
done[locs] = True
|
|
224
224
|
sources = sort_author_sources([prospects[j].author for j in locs])
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
225
|
+
if sources:
|
|
226
|
+
strength = sum(prospects[j].score for j in locs)
|
|
227
|
+
new_author = LabAuthor.from_sources(sources)
|
|
228
|
+
new_lab.append((strength, new_author))
|
|
228
229
|
|
|
229
230
|
# Extract top prospects
|
|
230
|
-
new_lab = [
|
|
231
|
+
new_lab = [a[1] for a in sorted(new_lab, key=lambda a: a[0], reverse=True)][
|
|
231
232
|
:max_new
|
|
232
233
|
]
|
|
233
234
|
new_rosetta = {s.key: a for a in new_lab for s in a.sources}
|
gismap/lab/filters.py
CHANGED
|
@@ -3,7 +3,7 @@ import re
|
|
|
3
3
|
# editorials = re.compile(r"ditorial|foreword", re.IGNORECASE)
|
|
4
4
|
# charlatans = re.compile(r"Raoult|Kofman|Buob")
|
|
5
5
|
|
|
6
|
-
editorials = ["ditorial", "Foreword", "Brief Announcement"]
|
|
6
|
+
editorials = ["ditorial", "Foreword", "Brief Announcement", "Preface", "Préface"]
|
|
7
7
|
charlatans = ["Raoult", "Kofman", "Buob"]
|
|
8
8
|
|
|
9
9
|
|
gismap/lab/lab_author.py
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
from dataclasses import dataclass, field
|
|
2
|
+
import re
|
|
2
3
|
|
|
3
|
-
from gismap import get_classes
|
|
4
|
-
from gismap.sources.models import DB
|
|
4
|
+
from gismap import get_classes
|
|
5
|
+
from gismap.sources.models import DB, db_class_to_auth_class
|
|
5
6
|
from gismap.sources.multi import SourcedAuthor, sort_author_sources
|
|
6
7
|
from gismap.utils.common import LazyRepr, list_of_objects
|
|
7
8
|
from gismap.utils.logger import logger
|
|
8
9
|
|
|
9
10
|
db_dict = get_classes(DB, key="db_name")
|
|
10
|
-
default_dbs = [
|
|
11
|
+
default_dbs = ["hal", "ldb"]
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
@dataclass(repr=False)
|
|
@@ -36,6 +37,25 @@ class AuthorMetadata(LazyRepr):
|
|
|
36
37
|
|
|
37
38
|
@dataclass(repr=False)
|
|
38
39
|
class LabAuthor(SourcedAuthor):
|
|
40
|
+
"""
|
|
41
|
+
Examples
|
|
42
|
+
---------
|
|
43
|
+
The metadata and DB key(s) of an author can be entered in parentheses using key/values.
|
|
44
|
+
|
|
45
|
+
Improper key/values are ignored (with a warning).
|
|
46
|
+
|
|
47
|
+
>>> dummy= LabAuthor("My Name(img: https://my.url.img, group:me,url:https://mysite.org,hal:key1,ldb:toto,badkey:hello,no_colon_separator)")
|
|
48
|
+
>>> dummy.metadata
|
|
49
|
+
AuthorMetadata(url='https://mysite.org', img='https://my.url.img', group='me')
|
|
50
|
+
>>> dummy.sources
|
|
51
|
+
[HALAuthor(name='My Name', key='key1'), LDBAuthor(name='My Name', key='toto')]
|
|
52
|
+
|
|
53
|
+
You can enter multiple keys for the same DB. HAL key types are automatically detected.
|
|
54
|
+
|
|
55
|
+
>>> dummy2= LabAuthor("My Name (hal:key1,hal:123456,hal: My Other Name )")
|
|
56
|
+
>>> dummy2.sources
|
|
57
|
+
[HALAuthor(name='My Name', key='key1'), HALAuthor(name='My Name', key='123456', key_type='pid'), HALAuthor(name='My Name', key='My Other Name', key_type='fullname')]
|
|
58
|
+
"""
|
|
39
59
|
metadata: AuthorMetadata = field(default_factory=AuthorMetadata)
|
|
40
60
|
|
|
41
61
|
def auto_img(self):
|
|
@@ -45,6 +65,30 @@ class LabAuthor(SourcedAuthor):
|
|
|
45
65
|
self.metadata.img = img
|
|
46
66
|
break
|
|
47
67
|
|
|
68
|
+
def __post_init__(self):
|
|
69
|
+
pattern = r"\s*([^,(]+)\s*(?:\(([^)]*)\))?\s*$"
|
|
70
|
+
match = re.match(pattern, self.name)
|
|
71
|
+
if match:
|
|
72
|
+
self.name = match.group(1).strip()
|
|
73
|
+
content = match.group(2)
|
|
74
|
+
if content:
|
|
75
|
+
for kv in content.split(","):
|
|
76
|
+
if ":" not in kv:
|
|
77
|
+
logger.warning(f"I don't know what to do with {kv}.")
|
|
78
|
+
continue
|
|
79
|
+
k, v = kv.split(":", 1)
|
|
80
|
+
k = k.strip().lower()
|
|
81
|
+
v = v.strip()
|
|
82
|
+
if k in db_dict:
|
|
83
|
+
DBAuthor = db_class_to_auth_class(db_dict[k])
|
|
84
|
+
self.sources.append(DBAuthor(name=self.name, key=v))
|
|
85
|
+
elif k in ["url", "img", "group"]:
|
|
86
|
+
setattr(self.metadata, k, v)
|
|
87
|
+
else:
|
|
88
|
+
logger.warning(f"I don't know what to do with {kv}.")
|
|
89
|
+
else:
|
|
90
|
+
self.name = self.name.strip()
|
|
91
|
+
|
|
48
92
|
def auto_sources(self, dbs=None):
|
|
49
93
|
"""
|
|
50
94
|
Automatically populate the sources based on author's name.
|
|
@@ -63,9 +107,9 @@ class LabAuthor(SourcedAuthor):
|
|
|
63
107
|
for db in dbs:
|
|
64
108
|
source = db.search_author(self.name)
|
|
65
109
|
if len(source) == 0:
|
|
66
|
-
logger.
|
|
110
|
+
logger.info(f"{self.name} not found in {db.db_name}")
|
|
67
111
|
elif len(source) > 1:
|
|
68
|
-
logger.
|
|
112
|
+
logger.info(f"Multiple entries for {self.name} in {db.db_name}")
|
|
69
113
|
sources += source
|
|
70
114
|
if len(sources) > 0:
|
|
71
115
|
self.sources = sort_author_sources(sources)
|
|
@@ -74,7 +118,7 @@ class LabAuthor(SourcedAuthor):
|
|
|
74
118
|
def labify_author(author, rosetta):
|
|
75
119
|
if isinstance(author, LabAuthor):
|
|
76
120
|
return author
|
|
77
|
-
return rosetta.get(author.key, author)
|
|
121
|
+
return rosetta.get(author.key, rosetta.get(author.name, author))
|
|
78
122
|
|
|
79
123
|
|
|
80
124
|
def labify_publications(pubs, rosetta):
|
gismap/lab/labmap.py
CHANGED
|
@@ -23,7 +23,7 @@ from gismap.lab.filters import (
|
|
|
23
23
|
publication_size_filter,
|
|
24
24
|
publication_oneword_filter,
|
|
25
25
|
)
|
|
26
|
-
from gismap.
|
|
26
|
+
from gismap.gisgraphs.builder import make_vis
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
class LabMap(MixInIO):
|
|
@@ -38,7 +38,7 @@ class LabMap(MixInIO):
|
|
|
38
38
|
----------
|
|
39
39
|
name: :class:`str`
|
|
40
40
|
Name of the lab. Can be set as class or instance attribute.
|
|
41
|
-
dbs: :class:`list`, default=[:class:`~gismap.sources.hal.HAL`, :class:`~gismap.sources.
|
|
41
|
+
dbs: :class:`list`, default=[:class:`~gismap.sources.hal.HAL`, :class:`~gismap.sources.ldb.LDB`]
|
|
42
42
|
List of DB sources to use.
|
|
43
43
|
|
|
44
44
|
|
|
@@ -57,8 +57,7 @@ class LabMap(MixInIO):
|
|
|
57
57
|
def __init__(self, name=None, dbs=None):
|
|
58
58
|
if name is not None:
|
|
59
59
|
self.name = name
|
|
60
|
-
|
|
61
|
-
self.dbs = list_of_objects(dbs, db_dict, default=default_dbs)
|
|
60
|
+
self.dbs = dbs
|
|
62
61
|
self.author_selectors = [author_taboo_filter()]
|
|
63
62
|
self.publication_selectors = [
|
|
64
63
|
publication_size_filter(),
|
|
@@ -92,11 +91,13 @@ class LabMap(MixInIO):
|
|
|
92
91
|
if not all(f(author) for f in self.author_selectors):
|
|
93
92
|
continue
|
|
94
93
|
if len(author.sources) == 0:
|
|
95
|
-
author.auto_sources(dbs=self.dbs)
|
|
94
|
+
author.auto_sources(dbs=list_of_objects(self.dbs, db_dict, default=default_dbs))
|
|
96
95
|
if author.sources:
|
|
97
96
|
self.authors[author.key] = author
|
|
98
97
|
if author.metadata.img is None:
|
|
99
98
|
author.auto_img()
|
|
99
|
+
if author.metadata.group is None:
|
|
100
|
+
author.metadata.group = self.name
|
|
100
101
|
|
|
101
102
|
def update_publis(self, desc="Publications information"):
|
|
102
103
|
"""
|
|
@@ -151,7 +152,7 @@ class LabMap(MixInIO):
|
|
|
151
152
|
return None
|
|
152
153
|
|
|
153
154
|
def html(self, **kwargs):
|
|
154
|
-
return
|
|
155
|
+
return make_vis(self, **kwargs)
|
|
155
156
|
|
|
156
157
|
def save_html(self, name=None, **kwargs):
|
|
157
158
|
if name is None:
|
|
File without changes
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
from bs4 import BeautifulSoup as Soup
|
|
3
|
+
from gismap.lab.labmap import LabMap
|
|
4
|
+
from gismap.lab.lab_author import AuthorMetadata, LabAuthor
|
|
5
|
+
from gismap.utils.requests import get
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class CedricMap(LabMap):
|
|
9
|
+
"""
|
|
10
|
+
Class for handling a CNAM Cedric team from its name.
|
|
11
|
+
Default to `roc` team.
|
|
12
|
+
"""
|
|
13
|
+
name = "roc"
|
|
14
|
+
base_url = "https://cedric.cnam.fr"
|
|
15
|
+
|
|
16
|
+
def _author_iterator(self):
|
|
17
|
+
soup = Soup(get(f"{self.base_url}/equipes/{self.name}/"), features="lxml")
|
|
18
|
+
searchers = [li.a for ul in soup.find('div', {'id': 'annuaire'})('ul')[:3] for li in ul('li')]
|
|
19
|
+
done = set()
|
|
20
|
+
for searcher in searchers:
|
|
21
|
+
name = searcher.text.split('(')[0].strip()
|
|
22
|
+
if name in done:
|
|
23
|
+
continue
|
|
24
|
+
url = f"{self.base_url}{searcher['href']}"
|
|
25
|
+
sousoup = Soup(get(url), features="lxml")
|
|
26
|
+
img = sousoup.find('img', {'class': 'photo'})['src']
|
|
27
|
+
response = requests.head(img, allow_redirects=True)
|
|
28
|
+
if int(response.headers.get("Content-Length")) < 3000:
|
|
29
|
+
img = None
|
|
30
|
+
done.add(name)
|
|
31
|
+
yield LabAuthor(name=name, metadata=AuthorMetadata(url=url, img=img, group=self.name.upper()))
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class CedricFull(LabMap):
|
|
35
|
+
"""
|
|
36
|
+
Class for handling all CNAM Cedric teams using `https://cedric.cnam.fr/equipes` to get team names.
|
|
37
|
+
"""
|
|
38
|
+
name = "Cedric"
|
|
39
|
+
|
|
40
|
+
def _author_iterator(self):
|
|
41
|
+
base = "https://cedric.cnam.fr/equipes/"
|
|
42
|
+
soup = Soup(get(base), features="lxml")
|
|
43
|
+
teams = {a['href'].split('/')[-2] for a in soup('a') if base in a.get('href', "") and len(a['href'])>len(base)}
|
|
44
|
+
for team in teams:
|
|
45
|
+
for author in CedricMap(name=team)._author_iterator():
|
|
46
|
+
yield author
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
from bs4 import BeautifulSoup as Soup
|
|
2
|
+
|
|
3
|
+
from gismap.lab import LabAuthor
|
|
4
|
+
from gismap.lab.lab_author import AuthorMetadata
|
|
5
|
+
from gismap.lab.labmap import LabMap
|
|
6
|
+
from gismap.utils.requests import get
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def lamsade_parse(div):
|
|
10
|
+
"""
|
|
11
|
+
Parameters
|
|
12
|
+
----------
|
|
13
|
+
div: :class:`~bs4.BeautifulSoup`
|
|
14
|
+
Soup of the div of one researcher
|
|
15
|
+
|
|
16
|
+
Returns
|
|
17
|
+
-------
|
|
18
|
+
:class:`tuple`
|
|
19
|
+
name, image url (or None), webpage (or None)
|
|
20
|
+
"""
|
|
21
|
+
img = div.img['src'] if div.img else None
|
|
22
|
+
url = div.a['href'] if div.a else None
|
|
23
|
+
name = div.h2.text.strip().title()
|
|
24
|
+
name = " ".join(name.split(" ", 1)[::-1])
|
|
25
|
+
return name, img, url
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class Lamsade(LabMap):
|
|
29
|
+
"""
|
|
30
|
+
Class for handling the Lamsade team (Dauphine).
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
name = "Lamsade"
|
|
34
|
+
base_url = "https://www.lamsade.dauphine.fr/"
|
|
35
|
+
directory = "fr/personnes/enseignants-chercheurs-et-chercheurs.html"
|
|
36
|
+
|
|
37
|
+
def _author_iterator(self):
|
|
38
|
+
soup = Soup(get(self.base_url+self.directory), features="lxml")
|
|
39
|
+
for a in soup('div', class_="dauphinecv-item"):
|
|
40
|
+
name, img, url = lamsade_parse(a)
|
|
41
|
+
img = self.base_url+img if img else None
|
|
42
|
+
url = self.base_url+url if url else None
|
|
43
|
+
yield LabAuthor(name=name, metadata=AuthorMetadata(url=url, img=img, group=self.name))
|
|
@@ -22,7 +22,7 @@ class LINCS(Map):
|
|
|
22
22
|
name = "LINCS"
|
|
23
23
|
|
|
24
24
|
def _author_iterator(self):
|
|
25
|
-
soup = Soup(get("https://www.lincs.fr/people/"))
|
|
25
|
+
soup = Soup(get("https://www.lincs.fr/people/"), features="lxml")
|
|
26
26
|
for entry in soup.main("div", class_="trombinoscope-row"):
|
|
27
27
|
cols = entry("div")
|
|
28
28
|
name = cols[1].text
|
|
@@ -36,7 +36,7 @@ class LINCS(Map):
|
|
|
36
36
|
if group:
|
|
37
37
|
group = group[-1].text
|
|
38
38
|
else:
|
|
39
|
-
group =
|
|
39
|
+
group = "External"
|
|
40
40
|
author = LabAuthor(name)
|
|
41
41
|
author.metadata.img = img
|
|
42
42
|
author.metadata.group = group
|
|
@@ -29,7 +29,21 @@ class LaasMap(LabMap):
|
|
|
29
29
|
if "public_avatar" in a.img["class"]
|
|
30
30
|
else None
|
|
31
31
|
)
|
|
32
|
-
yield LabAuthor(name=name, metadata=AuthorMetadata(url=url, img=img))
|
|
32
|
+
yield LabAuthor(name=name, metadata=AuthorMetadata(url=url, img=img, group=self.name.upper()))
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class LaasFull(LabMap):
|
|
36
|
+
"""
|
|
37
|
+
Class for handling all LAAS teams using `https://www.laas.fr/fr/equipes/` to get team names.
|
|
38
|
+
"""
|
|
39
|
+
name = "LAAS"
|
|
40
|
+
|
|
41
|
+
def _author_iterator(self):
|
|
42
|
+
soup = Soup(get("https://www.laas.fr/fr/equipes/"), features="lxml")
|
|
43
|
+
teams = [a['href'].split('/')[-2] for a in soup('a', {'class': "badge"})]
|
|
44
|
+
for team in teams:
|
|
45
|
+
for author in LaasMap(name=team)._author_iterator():
|
|
46
|
+
yield author
|
|
33
47
|
|
|
34
48
|
|
|
35
49
|
class SolaceMap(LabMap):
|
|
@@ -41,8 +55,11 @@ class SolaceMap(LabMap):
|
|
|
41
55
|
regex = re.compile(r"<li>(.*?)(,| \(|</li>)")
|
|
42
56
|
|
|
43
57
|
def _author_iterator(self):
|
|
44
|
-
html = get("https://solace.cnrs.fr/people.html")
|
|
58
|
+
html = get("https://solace.cnrs.fr/people.html", verify=False)
|
|
45
59
|
for name, _ in self.regex.findall(html):
|
|
46
60
|
soup = Soup(name, features="lxml")
|
|
47
61
|
url = soup.a["href"] if soup.a else None
|
|
48
|
-
yield LabAuthor(
|
|
62
|
+
yield LabAuthor(
|
|
63
|
+
name=soup.text.strip(),
|
|
64
|
+
metadata=AuthorMetadata(url=url, group=self.name.upper()),
|
|
65
|
+
)
|