Spaces:
Running
Running
Commit
·
26d5a6c
1
Parent(s):
bd0f333
- backend/main.py +16 -2
- frontend/package.json +1 -0
- frontend/src/components/ProjectDetails.tsx +66 -6
- frontend/src/hooks/types.ts +7 -0
backend/main.py
CHANGED
@@ -81,7 +81,7 @@ def get_projects(
|
|
81 |
cols = [
|
82 |
"id", "title", "status", "startDate", "endDate",
|
83 |
"ecMaxContribution", "acronym", "legalBasis", "objective",
|
84 |
-
"frameworkProgramme", "list_euroSciVocTitle", "list_euroSciVocPath",
|
85 |
]
|
86 |
for i in range(1, 7):
|
87 |
cols += [f"top{i}_feature", f"top{i}_shap"]
|
@@ -103,6 +103,15 @@ def get_projects(
|
|
103 |
if feat is not None and shap is not None:
|
104 |
explanations.append({"feature": feat, "shap": shap})
|
105 |
row["explanations"] = explanations
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
106 |
projects.append(row)
|
107 |
|
108 |
return projects
|
@@ -189,6 +198,11 @@ def get_project_organizations(project_id: str):
|
|
189 |
sel
|
190 |
.select([
|
191 |
pl.col("list_name").explode().alias("name"),
|
|
|
|
|
|
|
|
|
|
|
192 |
pl.col("list_country").explode().alias("country"),
|
193 |
pl.col("list_geolocation").explode().alias("geoloc"),
|
194 |
])
|
@@ -201,7 +215,7 @@ def get_project_organizations(project_id: str):
|
|
201 |
pl.col("latlon").list.get(1).cast(pl.Float64).alias("longitude"),
|
202 |
])
|
203 |
.filter(pl.col("name").is_not_null())
|
204 |
-
.select(["name", "country", "latitude", "longitude"])
|
205 |
)
|
206 |
|
207 |
return orgs_df.to_dicts()
|
|
|
81 |
cols = [
|
82 |
"id", "title", "status", "startDate", "endDate",
|
83 |
"ecMaxContribution", "acronym", "legalBasis", "objective",
|
84 |
+
"frameworkProgramme", "list_euroSciVocTitle", "list_euroSciVocPath","totalCost","list_isPublishedAs"
|
85 |
]
|
86 |
for i in range(1, 7):
|
87 |
cols += [f"top{i}_feature", f"top{i}_shap"]
|
|
|
103 |
if feat is not None and shap is not None:
|
104 |
explanations.append({"feature": feat, "shap": shap})
|
105 |
row["explanations"] = explanations
|
106 |
+
# 2) transform list_publications into a { type: count } map
|
107 |
+
raw_pubs = row.pop("list_publications", None) or []
|
108 |
+
pub_counts: dict[str, int] = {}
|
109 |
+
for entry in raw_pubs:
|
110 |
+
# assuming entry is a string like "paper" or "peer reviewed paper"
|
111 |
+
pub_counts[entry] = pub_counts.get(entry, 0) + 1
|
112 |
+
|
113 |
+
row["publications"] = pub_counts
|
114 |
+
|
115 |
projects.append(row)
|
116 |
|
117 |
return projects
|
|
|
198 |
sel
|
199 |
.select([
|
200 |
pl.col("list_name").explode().alias("name"),
|
201 |
+
pl.col("list_city").explode().alias("city"),
|
202 |
+
pl.col("list_SME").explode().alias("sme"),
|
203 |
+
pl.col("list_role").explode().alias("role"),
|
204 |
+
pl.col("list_ecContribution").explode().alias("contribution"),
|
205 |
+
pl.col("list_activityType").explode().alias("activityType"),
|
206 |
pl.col("list_country").explode().alias("country"),
|
207 |
pl.col("list_geolocation").explode().alias("geoloc"),
|
208 |
])
|
|
|
215 |
pl.col("latlon").list.get(1).cast(pl.Float64).alias("longitude"),
|
216 |
])
|
217 |
.filter(pl.col("name").is_not_null())
|
218 |
+
.select(["name", "city", "sme","role","contribution","activityType","country", "latitude", "longitude"])
|
219 |
)
|
220 |
|
221 |
return orgs_df.to_dicts()
|
frontend/package.json
CHANGED
@@ -10,6 +10,7 @@
|
|
10 |
"preview": "vite preview"
|
11 |
},
|
12 |
"dependencies": {
|
|
|
13 |
"@chakra-ui/react": "^2.7.1",
|
14 |
"@chakra-ui/slider": "^2.1.0",
|
15 |
"@emotion/react": "^11.14.0",
|
|
|
10 |
"preview": "vite preview"
|
11 |
},
|
12 |
"dependencies": {
|
13 |
+
"@chakra-ui/icons": "^2.2.4",
|
14 |
"@chakra-ui/react": "^2.7.1",
|
15 |
"@chakra-ui/slider": "^2.1.0",
|
16 |
"@emotion/react": "^11.14.0",
|
frontend/src/components/ProjectDetails.tsx
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
import { useEffect, useState } from "react"
|
2 |
import {
|
3 |
Box,
|
4 |
Flex,
|
@@ -10,12 +10,17 @@ import {
|
|
10 |
Wrap,
|
11 |
Tag,
|
12 |
Divider,
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
|
|
|
|
17 |
Avatar,
|
|
|
|
|
18 |
} from "@chakra-ui/react";
|
|
|
19 |
import {
|
20 |
ResponsiveContainer,
|
21 |
BarChart,
|
@@ -122,6 +127,10 @@ export default function ProjectDetails({
|
|
122 |
<Text fontWeight="bold">Funding (EC max)</Text>
|
123 |
<Text>€{project.ecMaxContribution.toLocaleString()}</Text>
|
124 |
</Box>
|
|
|
|
|
|
|
|
|
125 |
<Box>
|
126 |
<Text fontWeight="bold">Legal Basis</Text>
|
127 |
<Text>{project.legalBasis}</Text>
|
@@ -160,8 +169,59 @@ export default function ProjectDetails({
|
|
160 |
)}
|
161 |
|
162 |
<Divider my={6} />
|
163 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
164 |
<Heading size="md" mb={3}>Participating Organizations</Heading>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
165 |
{loadingOrgs ? (
|
166 |
<Spinner />
|
167 |
) : (
|
|
|
1 |
+
import { useEffect, useState } from "react";
|
2 |
import {
|
3 |
Box,
|
4 |
Flex,
|
|
|
10 |
Wrap,
|
11 |
Tag,
|
12 |
Divider,
|
13 |
+
Table,
|
14 |
+
Thead,
|
15 |
+
Tbody,
|
16 |
+
Tr,
|
17 |
+
Th,
|
18 |
+
Td,
|
19 |
Avatar,
|
20 |
+
Icon,
|
21 |
+
HStack,
|
22 |
} from "@chakra-ui/react";
|
23 |
+
import { CheckIcon, CloseIcon } from '@chakra-ui/icons';
|
24 |
import {
|
25 |
ResponsiveContainer,
|
26 |
BarChart,
|
|
|
127 |
<Text fontWeight="bold">Funding (EC max)</Text>
|
128 |
<Text>€{project.ecMaxContribution.toLocaleString()}</Text>
|
129 |
</Box>
|
130 |
+
<Box>
|
131 |
+
<Text fontWeight="bold">Total Cost</Text>
|
132 |
+
<Text>€{project.totalCost?.toLocaleString() || '-'}</Text>
|
133 |
+
</Box>
|
134 |
<Box>
|
135 |
<Text fontWeight="bold">Legal Basis</Text>
|
136 |
<Text>{project.legalBasis}</Text>
|
|
|
169 |
)}
|
170 |
|
171 |
<Divider my={6} />
|
172 |
+
{project.publications && Object.keys(project.publications).length > 0 && (
|
173 |
+
<Box mb={6}>
|
174 |
+
<Heading size="md" mb={2}>Publications</Heading>
|
175 |
+
<Table size="sm" variant="simple">
|
176 |
+
<Thead>
|
177 |
+
<Tr>
|
178 |
+
<Th>Type</Th>
|
179 |
+
<Th isNumeric>Count</Th>
|
180 |
+
</Tr>
|
181 |
+
</Thead>
|
182 |
+
<Tbody>
|
183 |
+
{Object.entries(project.publications).map(([type, count]) => (
|
184 |
+
<Tr key={type}>
|
185 |
+
<Td>{type}</Td>
|
186 |
+
<Td isNumeric>{count}</Td>
|
187 |
+
</Tr>
|
188 |
+
))}
|
189 |
+
</Tbody>
|
190 |
+
</Table>
|
191 |
+
</Box>
|
192 |
+
)}
|
193 |
+
|
194 |
<Heading size="md" mb={3}>Participating Organizations</Heading>
|
195 |
+
{loadingOrgs ? (
|
196 |
+
<Spinner />
|
197 |
+
) : (
|
198 |
+
<Table size="sm" variant="simple" mb={6}>
|
199 |
+
<Thead><Tr>
|
200 |
+
<Th>Name</Th>
|
201 |
+
<Th>City</Th>
|
202 |
+
<Th>Country</Th>
|
203 |
+
<Th>SME</Th>
|
204 |
+
<Th>Role</Th>
|
205 |
+
<Th isNumeric>Contribution (€)</Th>
|
206 |
+
<Th>Activity Type</Th>
|
207 |
+
</Tr></Thead>
|
208 |
+
<Tbody>
|
209 |
+
{orgLocations.map((o, i) => (
|
210 |
+
<Tr key={i}>
|
211 |
+
<Td>{o.name}</Td>
|
212 |
+
<Td>{o.city || '-'}</Td>
|
213 |
+
<Td>{o.country}</Td>
|
214 |
+
<Td>
|
215 |
+
{o.sme ? <Icon as={CheckIcon} /> : <Icon as={CloseIcon} />}
|
216 |
+
</Td>
|
217 |
+
<Td>{o.role}</Td>
|
218 |
+
<Td isNumeric>€{o.contribution?.toLocaleString() || '-'}</Td>
|
219 |
+
<Td>{o.activityType}</Td>
|
220 |
+
</Tr>
|
221 |
+
))}
|
222 |
+
</Tbody>
|
223 |
+
</Table>
|
224 |
+
)}
|
225 |
{loadingOrgs ? (
|
226 |
<Spinner />
|
227 |
) : (
|
frontend/src/hooks/types.ts
CHANGED
@@ -15,6 +15,8 @@ export interface Project {
|
|
15 |
explanations: Array<{ feature: string; shap: number }>;
|
16 |
predicted_label: number;
|
17 |
predicted_prob: number;
|
|
|
|
|
18 |
}
|
19 |
|
20 |
export interface ProjectDetailsProps {
|
@@ -40,6 +42,11 @@ export interface OrganizationLocation {
|
|
40 |
country: string;
|
41 |
latitude: number;
|
42 |
longitude: number;
|
|
|
|
|
|
|
|
|
|
|
43 |
}
|
44 |
|
45 |
export interface FilterState {
|
|
|
15 |
explanations: Array<{ feature: string; shap: number }>;
|
16 |
predicted_label: number;
|
17 |
predicted_prob: number;
|
18 |
+
totalCost: number | null;
|
19 |
+
publications:{ [type: string]: number };
|
20 |
}
|
21 |
|
22 |
export interface ProjectDetailsProps {
|
|
|
42 |
country: string;
|
43 |
latitude: number;
|
44 |
longitude: number;
|
45 |
+
sme: boolean;
|
46 |
+
city: string;
|
47 |
+
role: string;
|
48 |
+
contribution: number;
|
49 |
+
activityType: string;
|
50 |
}
|
51 |
|
52 |
export interface FilterState {
|