From cc7a1add8ace893ad73835a33877b34c490c42ae Mon Sep 17 00:00:00 2001 From: samibtorres Date: Wed, 6 May 2026 00:22:52 +0200 Subject: [PATCH 01/18] updated welcome page and general UI improvements --- eu_fact_force/dash-app/app.py | 61 +++-- eu_fact_force/dash-app/pages/graph.py | 246 +++++++---------- eu_fact_force/dash-app/pages/ingest.py | 8 +- eu_fact_force/dash-app/pages/readme.py | 131 ++++++++- eu_fact_force/dash-app/utils/colors.py | 18 +- eu_fact_force/dash-app/utils/graph.py | 358 ++++++++----------------- 6 files changed, 387 insertions(+), 435 deletions(-) diff --git a/eu_fact_force/dash-app/app.py b/eu_fact_force/dash-app/app.py index f5f4883..e94deae 100644 --- a/eu_fact_force/dash-app/app.py +++ b/eu_fact_force/dash-app/app.py @@ -29,7 +29,7 @@ ) # Dash params -DASHBOARD_NAME = "EU Fact Force" +DASHBOARD_NAME = "EU Health Fact Force" # Custom dash app tab and logo app.title = DASHBOARD_NAME @@ -37,10 +37,10 @@ # App pages pages = { - "Readme": {"href": "/", "content": readme}, - "Ingestion": {"href": "/ingest", "content": ingest}, - "Graph": {"href": "/graph", "content": graph}, - "PGP Dashboard": {"href": "/pgp", "content": pgp}, + "Our purpose": {"href": "/", "content": readme}, + "Upload your research": {"href": "/ingest", "content": ingest}, + "Explore the science": {"href": "/graph", "content": graph}, + "PGP Data integration": {"href": "/pgp", "content": pgp}, } # Header and navigation @@ -48,16 +48,21 @@ dbc.NavLink( page, href=pages[page]["href"], - style={"color": EUPHAColors.white}, + style={ + "color": EUPHAColors.white, + "font-weight": "500", + "font-family": "system-ui, -apple-system, sans-serif", + "margin": "0 5px" + }, active="exact", ) for page in pages ] nav_col = dbc.Col( - [dbc.Nav(nav_pages, vertical=False, pills=True, justified=True)], - width=4, - align="center", + [dbc.Nav(nav_pages, vertical=False, pills=True)], + width="auto", + className="d-flex justify-content-center", style={"padding": "0rem"}, ) @@ -69,9 +74,9 @@ [ html.Img( src="assets/logo-eupha-white.png", - alt="image", - height=50, - style={"padding-right": "10px"}, + alt="EUPHA logo", + height=45, + style={"padding-right": "15px"}, ), html.H1( DASHBOARD_NAME, @@ -80,16 +85,18 @@ "font-weight": "bold", "margin": "0", "padding": "0", + "font-size": "24px", + "white-space": "nowrap", + "font-family": "system-ui, -apple-system, sans-serif" }, ), ], style={ "display": "flex", "alignItems": "center", - "gap": "0px", }, ), - width=4, + width="auto", ), nav_col, dbc.Col( @@ -97,39 +104,42 @@ [ html.Img( src="assets/logo-d4g.png", - alt="image", - height=50, - style={"padding-right": "10px"}, + alt="Data for Good logo", + height=45, ) ], style={ "display": "flex", "alignItems": "center", - "gap": "0px", }, ), - width=4, - className="d-grid gap-2 d-md-flex justify-content-md-end", + width="auto", + className="d-flex justify-content-end", ), ], className="g-0", + align="center", + justify="between" ), style={ - "padding": "1rem", - "background-color": EUPHAColors.dark_blue, + "padding": "15px 30px", + "background-color": EUPHAColors.primary, "position": "fixed", + "top": "O", "width": "100%", "zIndex": 1000, + "box-shadow": "0 4px 6px -1px rgba(0,0,0,0.1)" }, ) # Content content = html.Div( style={ - "margin-left": "1rem", - "margin-right": "1rem", + "margin-left": "auto", + "margin-right": "auto", + "max-width": "1600px", "padding": "1rem", - "padding-top": "120px", + "padding-top": "110px", }, id="page-content", ) @@ -501,6 +511,7 @@ def toggle_offcanvas(node_data, is_open): ] + # -------------------- # Callbacks - Ingest # -------------------- diff --git a/eu_fact_force/dash-app/pages/graph.py b/eu_fact_force/dash-app/pages/graph.py index 3d87667..e187e64 100644 --- a/eu_fact_force/dash-app/pages/graph.py +++ b/eu_fact_force/dash-app/pages/graph.py @@ -5,197 +5,155 @@ from utils.colors import EUPHAColors from utils.graph import stylesheet, dict_node_type_colors +# Reusable label style for the sidebar +def _sidebar_label(text): + return html.Label(text, style={"fontSize": "12px", "fontWeight": "600", "textTransform": "uppercase", "color": EUPHAColors.text_muted, "marginTop": "15px", "marginBottom": "5px"}) def make_layout(): - # Search bar search_bar = html.Div( - children=[ - dbc.Row( - [ - dbc.Col( - html.H5("Search", style={"margin-bottom": "2px"}), width="auto" - ), - dbc.Col( - dcc.Dropdown( - id="search-input", - options=[ - {"label": "vaccine_autism", "value": "vaccine_autism"}, - ], - ) - ), - dbc.Col( - dbc.Button( - "Search", - id="search-button", - color="primary", - className="me-1", - n_clicks=0, - disabled=True, - ), - width="auto", - ), - ], - align="center", - ), - ], + dbc.Row( + [ + dbc.Col(html.H5("Semantic Search", style={"margin": "0", "color": EUPHAColors.text_dark, "fontWeight": "600"}), width="auto", className="pe-4"), + dbc.Col( + dcc.Dropdown( + id="search-input", + options=[{"label": "vaccines and autism correlation", "value": "vaccine_autism"}], + placeholder="Enter keywords to explore the science...", + style={"border": "none"} + ) + ), + dbc.Col( + dbc.Button("Search", id="search-button", color="primary", className="px-4", n_clicks=0, disabled=True), + width="auto", + ), + ], + align="center", + ), id="search", style={ - "border-radius": "15px", - "padding": "20px", - "background-color": EUPHAColors.white, + "borderRadius": "12px", + "padding": "20px 25px", + "backgroundColor": EUPHAColors.white, + "boxShadow": "0 2px 4px rgba(0,0,0,0.04)", + "border": f"1px solid {EUPHAColors.border_color}" }, ) - # Graph + legend_items = [ + html.Div( + [ + html.Div(style={"width": "12px", "height": "12px", "borderRadius": "50%", "backgroundColor": color, "marginRight": "8px"}), + html.Span(label.capitalize(), style={"fontSize": "13px", "color": EUPHAColors.text_muted, "fontWeight": "500"}) + ], + style={"display": "flex", "alignItems": "center"} + ) + for label, color in dict_node_type_colors.items() + ] + + graph_legend = html.Div( + legend_items, + style={ + "display": "flex", "gap": "20px", "padding": "12px 20px", + "backgroundColor": EUPHAColors.light_bg, + "borderBottom": f"1px solid {EUPHAColors.border_color}", + "borderTopLeftRadius": "12px", "borderTopRightRadius": "12px" + } + ) + graph_results = html.Div( id="graph", children=[ cyto.Cytoscape( id="graph-cytoscape", stylesheet=stylesheet, - layout={"name": "cose"}, - style={"width": "100%", "height": "450px"}, + layout={"name": "cose", "padding": 40}, + style={"width": "100%", "height": "550px", "backgroundColor": EUPHAColors.white}, zoomingEnabled=True, userZoomingEnabled=True, wheelSensitivity=0.1, ), ], - style={ - "border-radius": "15px", - "padding": "20px", - "background-color": EUPHAColors.light_blue, - "display": "none", - }, - ) - - # Graph legend - graph_legend = html.Div( - dbc.Row( - [ - dbc.Col( - [ - dbc.Row( - html.Div( - style={ - "width": "20px", - "height": "20px", - "borderRadius": "50%", - "backgroundColor": dict_node_type_colors[x], - "padding": "0", - "border": "none", - "boxSizing": "border-box", - "display": "block", - "flex": "0 0 20px", - }, - ), - align="center", - justify="center", - ), - dbc.Row(x, align="center", justify="center"), - ] - ) - for x in dict_node_type_colors - ] - ) + style={"display": "none"}, ) - # Graph offcanevas - offcanevas = dbc.Offcanvas( - id="offcanvas", - title="Focus", - is_open=False, - placement="end" - ) + offcanevas = dbc.Offcanvas(id="offcanvas", title="Entity Details", is_open=False, placement="end") - # List list_results = html.Div( id="list", - children=[html.Div(id="list-elements")], - style={ - "border-radius": "15px", - "padding": "20px", - "background-color": EUPHAColors.white, - }, - ) - - # Filters - - # > Nodes - node_type_filter = dbc.Row( - [ - html.H6("Nodes"), - dcc.Dropdown(id="filter_node_types", multi=True, searchable=False), - ] - ) - - # > Chunk types - chunk_type_filter = dbc.Row( - [ - html.H6("Chunk types"), - dcc.Dropdown(id="filter_chunk_types", multi=True, searchable=False), - ] - ) - - # > Keywords - keyword_filter = dbc.Row( - [html.H6("Keywords"), dcc.Dropdown(id="filter_keywords", multi=True)] - ) - - # > Document filters - document_filter = dbc.Row( - [ - html.H6("Documents"), - html.P("Date", style={"margin-bottom": 0, "margin-top": "5px"}), - dcc.DatePickerRange(id="filter_dates", updatemode="singledate", clearable=True), - html.P("Journal", style={"margin-bottom": 0, "margin-top": "5px"}), - dcc.Dropdown(id="filter_journals", multi=True), - html.P("Authors", style={"margin-bottom": 0, "margin-top": "5px"}), - dcc.Dropdown(id="filter_authors", multi=True), - html.P("Documents", style={"margin-bottom": 0, "margin-top": "5px"}), - dcc.Dropdown(id="filter_documents", multi=True), - ] + children=[html.Div(id="list-elements", style={"padding": "20px"})], + style={"backgroundColor": EUPHAColors.white}, ) filter_results = html.Div( id="filters", children=[ - html.H5("Filters"), - node_type_filter, - html.Br(), - keyword_filter, - html.Br(), - chunk_type_filter, - html.Br(), - document_filter, - html.Br(), + html.H5("Filters", style={"color": EUPHAColors.text_dark, "fontWeight": "600", "marginBottom": "20px"}), + + _sidebar_label("Entity Types"), + dcc.Dropdown(id="filter_node_types", multi=True, searchable=False, placeholder="All nodes"), + + _sidebar_label("Extracted Keywords"), + dcc.Dropdown(id="filter_keywords", multi=True, placeholder="Filter by keyword..."), + + _sidebar_label("Content Chunk Types"), + dcc.Dropdown(id="filter_chunk_types", multi=True, searchable=False, placeholder="All types"), + + html.Hr(style={"borderColor": EUPHAColors.border_color, "margin": "25px 0"}), + + html.H6("Document Meta", style={"color": EUPHAColors.text_dark, "fontWeight": "600", "fontSize": "14px"}), + + _sidebar_label("Publication Date"), + dcc.DatePickerRange(id="filter_dates", updatemode="singledate", clearable=True, className="w-100"), + + _sidebar_label("Journals"), + dcc.Dropdown(id="filter_journals", multi=True, placeholder="Select journals..."), + + _sidebar_label("Authors"), + dcc.Dropdown(id="filter_authors", multi=True, placeholder="Select authors..."), + + _sidebar_label("Specific Documents"), + dcc.Dropdown(id="filter_documents", multi=True, placeholder="Select docs by ID..."), ], + style={ + "backgroundColor": EUPHAColors.light_bg, + "padding": "25px", + "borderRadius": "12px", + "border": f"1px solid {EUPHAColors.border_color}", + "height": "100%" + } ) - # Tabs - tab_graph = dbc.Card(dbc.CardBody([graph_results, graph_legend, offcanevas])) + tab_graph = dbc.Card( + [graph_legend, graph_results, offcanevas], + style={"border": f"1px solid {EUPHAColors.border_color}", "borderTop": "none", "borderBottomLeftRadius": "12px", "borderBottomRightRadius": "12px"} + ) tab_list = dbc.Card( - dbc.CardBody([list_results]), + [list_results], + style={"border": f"1px solid {EUPHAColors.border_color}", "borderTop": "none", "borderBottomLeftRadius": "12px", "borderBottomRightRadius": "12px"} ) tabs = dbc.Tabs( [ - dbc.Tab(tab_graph, label="Graph"), - dbc.Tab(tab_list, label="List"), - ] + dbc.Tab(tab_graph, label="Network Graph", tab_style={"cursor": "pointer"}), + dbc.Tab(tab_list, label="List View", tab_style={"cursor": "pointer"}), + ], ) - # Results results = html.Div( id="results", children=dbc.Row( [ dbc.Col(filter_results, width=3), dbc.Col(tabs, width=9), - ] + ], + className="g-4" ), - style={"display": "none"}, + style={"display": "none", "marginTop": "20px"}, ) - return html.Div([search_bar, html.Br(), results, offcanevas]) + return html.Div( + [search_bar, results], + style={"fontFamily": "system-ui, -apple-system, sans-serif"} + ) \ No newline at end of file diff --git a/eu_fact_force/dash-app/pages/ingest.py b/eu_fact_force/dash-app/pages/ingest.py index 4bc34a0..fffe46e 100644 --- a/eu_fact_force/dash-app/pages/ingest.py +++ b/eu_fact_force/dash-app/pages/ingest.py @@ -18,7 +18,7 @@ def make_layout(): "fontWeight": "700", "fontSize": "1.9rem", "marginBottom": "20px", - "color": EUPHAColors.dark_blue + "color": EUPHAColors.primary } ), @@ -122,7 +122,7 @@ def make_layout(): 'lineHeight': '80px', 'borderWidth': '2px', 'borderStyle': 'dashed', - 'borderColor': EUPHAColors.dark_blue, + 'borderColor': EUPHAColors.primary, 'textAlign': 'center', 'borderRadius': '10px', 'marginBottom': '20px', @@ -228,8 +228,8 @@ def make_layout(): size="lg", className="w-100 mb-4", style={ - "backgroundColor": EUPHAColors.dark_blue, - "borderColor": EUPHAColors.dark_blue, + "backgroundColor": EUPHAColors.light_bg, + "borderColor": EUPHAColors.primary, "color": "white", "fontWeight": "600", "borderRadius": "10px" diff --git a/eu_fact_force/dash-app/pages/readme.py b/eu_fact_force/dash-app/pages/readme.py index 6dfdf01..04c3205 100644 --- a/eu_fact_force/dash-app/pages/readme.py +++ b/eu_fact_force/dash-app/pages/readme.py @@ -1,15 +1,132 @@ from dash import dcc, html +from utils.colors import EUPHAColors -from utils.colors import EUPHAColors +def make_layout(): + return html.Div( + [ + html.Div( + [ + html.H1( + "Welcome to the FactForce Hub", + style={"color": EUPHAColors.text_main, "fontWeight": "800", "marginBottom": "10px", "fontSize": "36px"} + ), + html.H3( + "Stand up for science. Reclaiming trust in public health.", + style={"color": EUPHAColors.primary, "fontStyle": "normal", "fontWeight": "500", "marginTop": "0px", "fontSize": "22px"} + ), + html.P( + "A long-term collaborative project led by EUPHA in collaboration with WHO/Europe, " + "technical partners, researchers, and civil society actors to detect, analyze, and " + "respond collectively to health misinformation.", + style={ + "fontSize": "17px", + "color": EUPHAColors.text_main, + "marginTop": "20px", + "lineHeight": "1.6", + "maxWidth": "800px", + "margin": "20px auto 0 auto" + } + ) + ], + style={"textAlign": "center", "marginBottom": "50px"} + ), + html.Div( + html.H4( + "\"Health misinformation is not only a problem of facts, but a problem of power, trust, and scale.\"", + style={"textAlign": "center", "color": EUPHAColors.text_dark, "margin": "0", "fontWeight": "500", "fontStyle": "italic", "fontSize": "20px"} + ), + style={ + "backgroundColor": EUPHAColors.light_bg, + "padding": "35px", + "borderRadius": "12px", + "marginBottom": "60px", + "border": f"1px solid {EUPHAColors.border_color}", + "boxShadow": "0 2px 4px rgba(0,0,0,0.02)" + } + ), -def make_layout(): + html.Div( + [ + html.Div( + [ + html.H4("The Infodemic Context", style={"color": EUPHAColors.primary, "fontSize": "22px", "marginBottom": "15px", "fontWeight": "600"}), + html.P( + "Health misinformation has reached an unprecedented scale, driven by political " + "polarization, commercial interests, and geopolitical strategies. Traditional " + "public health systems are struggling to monitor and respond to these false narratives " + "in a timely, coordinated way. The FactForce transforms fragmented reactions into " + "proactive, unified public-health communication.", + style={"lineHeight": "1.7", "color": EUPHAColors.text_main} + ) + ], + style={"flex": "1"} + ), + + html.Div( + [ + html.H4("Beyond Automated Fact-Checking", style={"color": EUPHAColors.primary, "fontSize": "22px", "marginBottom": "15px", "fontWeight": "600"}), + html.P( + "Rather than relying solely on automated counter-messaging, the FactForce prioritizes " + "human coordination, collective intelligence, and solidarity. We focus on bridging " + "science, lived experience, and community insight to meet people where they are, " + "equipping trusted local messengers with evidence-based content.", + style={"lineHeight": "1.7", "color": EUPHAColors.text_main} + ) + ], + style={"flex": "1"} + ), + ], + style={"display": "flex", "flexDirection": "row", "gap": "60px", "marginBottom": "50px"} + ), - return html.Div( - [html.H2("Readme"), dcc.Markdown("Readme text to be completed here...")], + html.Hr(style={"borderTop": f"1px solid {EUPHAColors.border_color}", "marginBottom": "50px", "opacity": "1"}), + + html.H3("What the Hub Delivers", style={"color": EUPHAColors.text_dark, "marginBottom": "30px", "fontSize": "28px", "fontWeight": "700", "textAlign": "center"}), + html.Div( + [ + _create_pillar_card( + title="1. Observatory", + description="Detect and analyze emerging health misinformation narratives across languages and platforms. Document patterns, trends, and drivers ethically and transparently.", + color=EUPHAColors.primary + ), + _create_pillar_card( + title="2. Coordination", + description="Connect misinformation narratives with scientific evidence. Support rapid, coordinated responses by public health actors through shared playbooks and early-warning models.", + color=EUPHAColors.primary + ), + _create_pillar_card( + title="3. Community Hub", + description="Allow the fragmented public health workforce to register, connect, and receive tailored, evidence-informed content directly through channels they use (e.g., WhatsApp).", + color=EUPHAColors.primary + ), + ], + style={"display": "flex", "gap": "30px"} + ) + ], style={ - "border-radius": "15px", - "padding": "20px", - "background-color": EUPHAColors.white, + "borderRadius": "16px", + "padding": "60px", + "backgroundColor": EUPHAColors.white, + "color": EUPHAColors.text_main, + "boxShadow": "0 10px 15px -3px rgba(0,0,0,0.05), 0 4px 6px -2px rgba(0,0,0,0.025)", + "fontFamily": "system-ui, -apple-system, sans-serif" }, ) + +def _create_pillar_card(title, description, color): + return html.Div( + [ + html.H4(title, style={"color": color, "marginTop": "0", "fontSize": "20px", "fontWeight": "600"}), + html.P(description, style={"fontSize": "15px", "lineHeight": "1.6", "margin": "0", "color": EUPHAColors.text_muted}) + ], + style={ + "flex": "1", + "backgroundColor": EUPHAColors.white, + "border": f"1px solid {EUPHAColors.border_color}", + "borderTop": f"4px solid {color}", + "borderRadius": "12px", + "padding": "30px", + "boxShadow": "0 2px 4px rgba(0,0,0,0.02)" + } + ) \ No newline at end of file diff --git a/eu_fact_force/dash-app/utils/colors.py b/eu_fact_force/dash-app/utils/colors.py index 5210883..0ac5407 100644 --- a/eu_fact_force/dash-app/utils/colors.py +++ b/eu_fact_force/dash-app/utils/colors.py @@ -1,8 +1,20 @@ class EUPHAColors: - dark_blue = "#2d61a4" - light_blue = "#7fa7d3" - white = "#ffffff" + # Brand Colors + primary = '#1A5A96' + secondary = '#5D90C5' dark_green = "#60733d" light_green = "#a0c063" orange = "#f29f05" + + # UI Text Colors + text_dark = '#2c3e50' + text_main = '#334155' + text_muted = '#64748B' + + # UI Backgrounds & Borders + light_bg = '#F8FAFC' + border_color = '#E2E8F0' + + # Base black = "#161616" + white = '#FFFFFF' \ No newline at end of file diff --git a/eu_fact_force/dash-app/utils/graph.py b/eu_fact_force/dash-app/utils/graph.py index 53af19c..30f5901 100644 --- a/eu_fact_force/dash-app/utils/graph.py +++ b/eu_fact_force/dash-app/utils/graph.py @@ -1,16 +1,14 @@ import os - import requests from dash import dcc, html import dash_bootstrap_components as dbc - from .colors import EUPHAColors dict_node_type_colors = { "chunk": EUPHAColors.light_green, "document": EUPHAColors.orange, - "author": EUPHAColors.light_blue, - "journal": EUPHAColors.dark_blue, + "author": EUPHAColors.secondary, + "journal": EUPHAColors.primary, "keyword": EUPHAColors.dark_green, } @@ -20,345 +18,201 @@ "style": { "label": "data(label)", "text-valign": "center", - "color": "black", + "text-halign": "center", + "color": "#2c3e50", "font-size": 10, + "text-wrap": "wrap", + "text-max-width": 80, }, }, + + # KEYWORD (most important) { - "selector": 'node[type="chunk"]', + "selector": 'node[type="keyword"]', "style": { - "background-color": dict_node_type_colors["chunk"], - "width": "60px", - "height": "60px", - "font-size": "20px", + "background-color": dict_node_type_colors["keyword"], + "width": "90px", + "height": "90px", + "font-size": "16px", + "border-width": 3, + "border-color": "#1b5e20", }, }, + + # DOCUMENT { "selector": 'node[type="document"]', "style": { "background-color": dict_node_type_colors["document"], - "width": "80px", - "height": "80px", - "font-size": "25px", + "width": "75px", + "height": "75px", + "font-size": "13px", }, }, + + # CHUNK { - "selector": 'node[type="author"]', + "selector": 'node[type="chunk"]', "style": { - "background-color": dict_node_type_colors["author"], - "width": "30px", - "height": "30px", + "background-color": dict_node_type_colors["chunk"], + "width": "55px", + "height": "55px", + "font-size": "11px", + "opacity": 0.9, }, }, + + # AUTHOR { - "selector": 'node[type="journal"]', + "selector": 'node[type="author"]', "style": { - "background-color": dict_node_type_colors["journal"], + "background-color": dict_node_type_colors["author"], "width": "30px", "height": "30px", + "opacity": 0.7, }, }, + + # JOURNAL (least important) { - "selector": 'node[type="keyword"]', + "selector": 'node[type="journal"]', "style": { - "background-color": dict_node_type_colors["keyword"], - "width": "30px", - "height": "30px", + "background-color": dict_node_type_colors["journal"], + "width": "25px", + "height": "25px", + "opacity": 0.5, }, }, + { "selector": "edge", "style": { "width": 1, - "line-color": "black", + "line-color": "#999", + "opacity": 0.4, }, }, ] - class BackendGraph: """Graph object loaded from backend API.""" - def __init__(self, keyword): self.keyword = keyword self.load_search_results() self.stylesheet = stylesheet def load_search_results(self): - """Load JSON from backend route.""" base_url = os.getenv("BACKEND_URL", "http://127.0.0.1:8000") url = f"{base_url}/ingestion/search/{self.keyword}/" - - response = requests.get(url, timeout=30) - response.raise_for_status() - self.search_results = response.json() + try: + response = requests.get(url, timeout=30) + response.raise_for_status() + self.search_results = response.json() + except Exception: + # Fallback/Mock data if backend is down (to prevent app crash during design) + self.search_results = {"chunks": [], "documents": {}, "authors": {}} def transform(self): - """Parse JSON and create nodes (dict), edges (list) and filters (dict).""" nodes = {} edges = [] authors_dict = self.search_results.get("authors", {}) filters = { - "node_types": [ - x["selector"].split('type="')[1].split('"')[0] - for x in self.stylesheet - if "type" in x["selector"] - ], - "chunk_types": [], - "documents": [], - "journal": [], - "keywords": [], - "authors": [], - "date": [], + "node_types": list(dict_node_type_colors.keys()), + "chunk_types": [], "documents": [], "journal": [], + "keywords": [], "authors": [], "date": [], } - # chunks - for i, chunk in enumerate(self.search_results["chunks"]): + for i, chunk in enumerate(self.search_results.get("chunks", [])): chunk_id = f"chunk_{i}" document_id = str(chunk["metadata"]["document_id"]) - document_metadata = self.search_results["documents"][str(document_id)] - filters["chunk_types"].append(chunk["type"]) + document_metadata = self.search_results["documents"].get(document_id, {}) + + filters["chunk_types"].append(chunk.get("type")) filters["documents"].append(document_id) if document_metadata.get("date"): filters["date"].append(document_metadata["date"]) - author_names = [ - authors_dict.get(str(a_id), {}).get("name") - for a_id in document_metadata.get("author_ids", []) - ] + + author_names = [authors_dict.get(str(a_id), {}).get("name") for a_id in document_metadata.get("author_ids", [])] document_metadata["author_names"] = [name for name in author_names if name] nodes[chunk_id] = { - "data": { - "id": chunk_id, - "label": chunk_id.replace("_", " ").capitalize(), - "type": "chunk", - "metadata": chunk, - "document_metadata": document_metadata, - } + "data": {"id": chunk_id, "label": chunk_id.replace("_", " ").capitalize(), "type": "chunk", "metadata": chunk, "document_metadata": document_metadata} } if str(document_id) not in nodes: - document_label = document_metadata.get("title", document_id) - max_label_size = 25 - if len(document_label) > max_label_size: - document_label = document_label[:max_label_size] + "..." + document_label = document_metadata.get("title", f"Doc {document_id}") + if len(document_label) > 25: + document_label = document_label[:25] + "..." nodes[str(document_id)] = { - "data": { - "id": str(document_id), - "label": document_label, - "type": "document", - "metadata": document_metadata, - } + "data": {"id": str(document_id), "label": document_label, "type": "document", "metadata": document_metadata} } - edges.append( - { - "data": { - "source": chunk_id, - "target": str(document_id), - } - } - ) + edges.append({"data": {"source": chunk_id, "target": str(document_id)}}) - # journal if document_metadata.get("journal"): journal_id = f"journal_{document_metadata['journal']}" filters["journal"].append(document_metadata["journal"]) - if journal_id not in nodes: - nodes[journal_id] = { - "data": { - "id": journal_id, - "label": document_metadata["journal"], - "type": "journal", - } - } - - edges.append( - { - "data": { - "source": str(document_id), - "target": journal_id, - } - } - ) + nodes[journal_id] = {"data": {"id": journal_id, "label": document_metadata["journal"], "type": "journal"}} + edges.append({"data": {"source": str(document_id), "target": journal_id}}) - # authors for author_id in document_metadata.get("author_ids", []): - author_data = authors_dict.get(author_id, {}) - author_name = author_data.get("name", f"author_{author_id}") + author_data = authors_dict.get(str(author_id), {}) + author_name = author_data.get("name", f"Author {author_id}") node_id = f"author_{author_id}" - filters["authors"].append(author_name) - if node_id not in nodes: - nodes[node_id] = { - "data": { - "id": node_id, - "label": author_name, - "type": "author", - "metadata": author_data, - } - } + nodes[node_id] = {"data": {"id": node_id, "label": author_name, "type": "author", "metadata": author_data}} + edges.append({"data": {"source": str(document_id), "target": node_id}}) - edges.append( - { - "data": { - "source": str(document_id), - "target": node_id, - } - } - ) - - # keywords for keyword in document_metadata.get("keywords", []): keyword_id = f"keyword_{keyword}" filters["keywords"].append(keyword) - if keyword_id not in nodes: - nodes[keyword_id] = { - "data": {"id": keyword_id, "label": keyword, "type": "keyword"} - } - - edges.append( - { - "data": { - "source": str(document_id), - "target": keyword_id, - } - } - ) + nodes[keyword_id] = {"data": {"id": keyword_id, "label": keyword, "type": "keyword"}} + edges.append({"data": {"source": str(document_id), "target": keyword_id}}) return nodes, edges, filters - def format_node_metadata(node_data): - """Format node metadata into card content""" - - # Document nodes if node_data["type"] == "document": - return html.Div( - [ - dbc.Row( - dcc.Markdown(f"__{node_data['metadata']['title']}__"), - style={"font-size": "20px"}, - ), - dbc.Row( - dcc.Markdown( - ", ".join( - [f"_{x}_" for x in node_data["metadata"]["author_names"]] - ) - ) - ), - dbc.Row( - html.Span( - [ - dbc.Badge(x, color="secondary", className="me-1") - for x in node_data["metadata"]["keywords"] - ] - ) - ), - html.Br(), - dbc.Button( - "Access document ↗️", - href=f"http://doi.org/{node_data['metadata']['doi']}", - target="_blank", - color="primary", - className="me-1", - ), - ] - ) + return html.Div([ + html.H4(node_data['metadata'].get('title', 'Untitled'), className="fw-bold mb-2", style={"color": EUPHAColors.text_dark}), + html.P(", ".join(node_data["metadata"].get("author_names", [])), className="text-muted fst-italic mb-3"), + html.Div([dbc.Badge(x, color="light", text_color="dark", className="me-1 border") for x in node_data["metadata"].get("keywords", [])], className="mb-4"), + dbc.Button("Access Source Document ↗", href=f"http://doi.org/{node_data['metadata'].get('doi', '')}", target="_blank", color="primary", outline=True, size="sm") + ]) - # Chunk nodes elif node_data["type"] == "chunk": - return html.Div( - [ - dbc.Row( - dcc.Markdown( - f"__{node_data['label']}__ (score: {round(node_data['metadata']['score'], 2)})" - ), - style={"font-size": "20px"}, - ), - dbc.Row( - node_data["metadata"]["content"], - style={ - "font-style": "italic", - "border-radius": "15px", - "padding": "20px", - "background-color": EUPHAColors.light_green, - }, - ), - html.Hr(), - dbc.Row( - dcc.Markdown(f"__{node_data['document_metadata']['title']}__"), - style={"font-size": "20px"}, - ), - dbc.Row( - dcc.Markdown( - ", ".join( - [ - f"_{x}_" - for x in node_data["document_metadata"]["author_names"] - ] - ) - ) - ), - dbc.Row( - html.Span( - [ - dbc.Badge(x, color="secondary", className="me-1") - for x in node_data["document_metadata"]["keywords"] - ] - ) - ), - html.Br(), - # dbc.Row( - # dcc.Markdown(f"Page: {node_data['metadata']['metadata']['page']}"), - # style={"font-size": "16px"}, - # ), # TODO: Use this when real page numbers available - dbc.Button( - "Access document ↗️", - href=f"http://doi.org/{node_data['document_metadata']['doi']}", - target="_blank", - color="primary", - className="me-1", - ), - ] - ) + score = round(node_data['metadata'].get('score', 0), 2) + return html.Div([ + html.H5(f"Extracted Segment", className="fw-bold mb-1", style={"color": EUPHAColors.text_dark}), + html.P(f"Relevance Score: {score}", className="text-muted small mb-3"), + + html.Div( + node_data["metadata"].get("content", ""), + style={"fontStyle": "italic", "borderRadius": "8px", "padding": "15px", "backgroundColor": EUPHAColors.light_bg, "border": f"1px solid {EUPHAColors.border_color}", "fontSize": "14px", "color": EUPHAColors.text_main}, + className="mb-4" + ), + + html.Hr(style={"borderColor": EUPHAColors.border_color}), + html.H6("Source Document", className="fw-bold mt-4 mb-2"), + html.P(node_data['document_metadata'].get('title', 'Unknown Title'), className="small mb-1"), + html.P(", ".join(node_data["document_metadata"].get("author_names", [])), className="text-muted small fst-italic mb-3"), + dbc.Button("Access Source Document ↗", href=f"http://doi.org/{node_data['document_metadata'].get('doi', '')}", target="_blank", color="primary", size="sm", className="w-100") + ]) - # Author nodes elif node_data["type"] == "author": - return html.Div( - [ - dbc.Row( - dcc.Markdown(f"__{node_data['metadata']['name']}__"), - style={"font-size": "20px"}, - ), - dbc.Row( - dcc.Markdown(f"ORCID: {node_data['metadata']['orcid']}"), - style={"font-size": "16px"}, - ), - ] - ) + return html.Div([ + html.H4(node_data['metadata'].get('name', 'Unknown'), className="fw-bold mb-2", style={"color": EUPHAColors.text_dark}), + html.P(f"ORCID: {node_data['metadata'].get('orcid', 'N/A')}", className="text-muted") + ]) - # Keyword nodes elif node_data["type"] == "keyword": - return html.Div( - [ - dbc.Row( - dcc.Markdown(f"__{node_data['label']}__"), - style={"font-size": "20px"}, - ), - ] - ) - else: - return dcc.Markdown( - "\n".join( - [ - f"- {key.capitalize()} : __{node_data[key]}__" - for key in node_data - if key != "timeStamp" - ] - ) - ) + return html.Div([ + html.H4(node_data.get('label', ''), className="fw-bold mb-2", style={"color": EUPHAColors.text_dark}), + html.P("Keyword Extracted", className="text-muted") + ]) + + return html.Div("No metadata available.") \ No newline at end of file From 97149426ee34afff16b2326579e9ae9c9aed1267 Mon Sep 17 00:00:00 2001 From: samibtorres Date: Wed, 6 May 2026 00:38:11 +0200 Subject: [PATCH 02/18] updated text of welcome page --- eu_fact_force/dash-app/pages/readme.py | 27 +++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/eu_fact_force/dash-app/pages/readme.py b/eu_fact_force/dash-app/pages/readme.py index 04c3205..a19f18c 100644 --- a/eu_fact_force/dash-app/pages/readme.py +++ b/eu_fact_force/dash-app/pages/readme.py @@ -7,17 +7,17 @@ def make_layout(): html.Div( [ html.H1( - "Welcome to the FactForce Hub", + "Welcome to EU Health Fact Force", style={"color": EUPHAColors.text_main, "fontWeight": "800", "marginBottom": "10px", "fontSize": "36px"} ), html.H3( - "Stand up for science. Reclaiming trust in public health.", + "Stand up for science. A Hub for reclaiming trust in public health.", style={"color": EUPHAColors.primary, "fontStyle": "normal", "fontWeight": "500", "marginTop": "0px", "fontSize": "22px"} ), html.P( - "A long-term collaborative project led by EUPHA in collaboration with WHO/Europe, " - "technical partners, researchers, and civil society actors to detect, analyze, and " - "respond collectively to health misinformation.", + "A long-term collaborative project led by EUPHA in collaboration with Data for Good and The Public Good Projects" + "to bring together technical experts, researchers, and civil society actors" + "to detect, analyze, and respond collectively to health misinformation.", style={ "fontSize": "17px", "color": EUPHAColors.text_main, @@ -52,11 +52,12 @@ def make_layout(): [ html.H4("The Infodemic Context", style={"color": EUPHAColors.primary, "fontSize": "22px", "marginBottom": "15px", "fontWeight": "600"}), html.P( - "Health misinformation has reached an unprecedented scale, driven by political " - "polarization, commercial interests, and geopolitical strategies. Traditional " - "public health systems are struggling to monitor and respond to these false narratives " - "in a timely, coordinated way. The FactForce transforms fragmented reactions into " - "proactive, unified public-health communication.", + "Health misinformation has reached an unprecedented scale" + "driven by political polarization, commercial interests, and geopolitical strategies." + "Traditional public health systems are struggling to monitor" + "and respond to these false narratives in a timely, coordinated way." + "The EU Health Fact Force hub transforms fragmented reactions" + "into proactive, unified public-health communication.", style={"lineHeight": "1.7", "color": EUPHAColors.text_main} ) ], @@ -67,9 +68,9 @@ def make_layout(): [ html.H4("Beyond Automated Fact-Checking", style={"color": EUPHAColors.primary, "fontSize": "22px", "marginBottom": "15px", "fontWeight": "600"}), html.P( - "Rather than relying solely on automated counter-messaging, the FactForce prioritizes " - "human coordination, collective intelligence, and solidarity. We focus on bridging " - "science, lived experience, and community insight to meet people where they are, " + "Rather than relying solely on automated counter-messaging," + "the EUHFF Hub prioritizes human coordination, collective intelligence, and solidarity." + "We focus on bridging science, lived experience, and community insight to meet people where they are," "equipping trusted local messengers with evidence-based content.", style={"lineHeight": "1.7", "color": EUPHAColors.text_main} ) From 93170be0c4000caaa3d2a6da09caabf413b0a3c9 Mon Sep 17 00:00:00 2001 From: samibtorres Date: Wed, 6 May 2026 09:30:00 +0200 Subject: [PATCH 03/18] Changed font color (white) for keywords nodes so that the text stands out + changed color of edges --- eu_fact_force/dash-app/utils/graph.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/eu_fact_force/dash-app/utils/graph.py b/eu_fact_force/dash-app/utils/graph.py index 30f5901..d143c95 100644 --- a/eu_fact_force/dash-app/utils/graph.py +++ b/eu_fact_force/dash-app/utils/graph.py @@ -34,6 +34,7 @@ "width": "90px", "height": "90px", "font-size": "16px", + "color": EUPHAColors.white, "border-width": 3, "border-color": "#1b5e20", }, @@ -88,7 +89,7 @@ "selector": "edge", "style": { "width": 1, - "line-color": "#999", + "line-color": EUPHAColors.primary, "opacity": 0.4, }, }, From 48534296437a6bd66543997eefda7c7400873973 Mon Sep 17 00:00:00 2001 From: samibtorres Date: Wed, 6 May 2026 09:30:18 +0200 Subject: [PATCH 04/18] Updated defaut_search.json to have a bit more data in it --- .../data_collection/default_search.json | 336 ++++++++++++------ 1 file changed, 230 insertions(+), 106 deletions(-) diff --git a/eu_fact_force/ingestion/data_collection/default_search.json b/eu_fact_force/ingestion/data_collection/default_search.json index 1242405..874a82d 100644 --- a/eu_fact_force/ingestion/data_collection/default_search.json +++ b/eu_fact_force/ingestion/data_collection/default_search.json @@ -6,192 +6,316 @@ "chunks": [ { "type": "text", - "content": "There has been enormous debate regarding the possibility of a link between childhood vaccinations and the subsequent development of autism. This has in recent times become a major public health issue with vaccine preventable diseases increasing in the community due to the fear of a 'link' between vaccinations and autism. We performed a meta-analysis to summarise available evidence from case-control and cohort studies on this topic (MEDLINE, PubMed, EMBASE, Google Scholar up to April, 2014). Eligible studies assessed the relationship between vaccine administration and the subsequent development of autism or autism spectrum disorders (ASD). Two reviewers extracted data on study characteristics, methods, and outcomes. Disagreement was resolved by consensus with another author. Five cohort studies involving 1,256,407 children, and five case-control studies involving 9,920 children were included in this analysis. The cohort data revealed no relationship between vaccination and autism (OR: 0.99; 95% CI: 0.92 to 1.06) or ASD (OR: 0.91; 95% CI: 0.68 to 1.20), nor was there a relationship between autism and MMR (OR: 0.84; 95% CI: 0.70 to 1.01), or thimerosal (OR: 1.00; 95% CI: 0.77 to 1.31)", - "score": 0.1126598648631637, + "content": "Several hypotheses were posited on the relationship between vaccination and autism development. The first theory relates to immune system dysfunction, organic acid synthesis, the effects of gliamorphin on cerebral", + "score": 0.10291147232055664, "metadata": { - "document_id": 5, - "page": 5 + "document_id": 14, + "page": -1 } }, { "type": "text", - "content": "- [27] Kimmel SR, Burns IT, Wolfe RM, Zimmerman RK. Addressing immunization barriers, benefits, and risks. J Fam Pract 2007;56(Suppl. 2 vaccines): S61-9.\n\n- [28] [Klein KC, Diehl EB. Relationship between MMR vaccine and autism. Ann Pharmacother 2004;38(7-8):1297-300.](http://refhub.elsevier.com/S0264-410X(14)00636-7/sbref0155)\n\n- [29] Mutter J, Naumann J, Schneider R, Walach H, Haley B. Mercury and autism: accelerating evidence? Neuro Endocrinol Lett 2005;26(5):439-46.\n\n- [30] \u00d6rtqvist \u00c5, Blennow M, Carlsson R-M, et al. Vaccination of children-a systematic review. Acta Paediatr 2010;99(461):1-192.\n\n- [31] Parker SK, Schwartz B, Todd J, Pickering LK. Thimerosal-containing vaccines and autistic spectrum disorder: a critical review of published original data. Pediatrics 2004;114(3):793-804.\n\n- [32] Ratajczak HV. Theoretical aspects of autism: causes-a review. J Immunotoxicol 2011;8(1):68-79.\n\n- [33] Rutter M. Aetiology of autism: findings and questions. J Intellect Disabil Res 2005;49(4):231-8.", - "score": 0.11575097535556256, + "content": "TABLE 1: The result of the initial search.\n\n\n\n| Keywords/MeSH keywords | Google Scholar | PubMed | |----------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------|----------| | Autism | 1,590 | 9 | | Immunization | 189,000 | 9 | | Autism OR autistic disorder OR echolalia OR scripting OR perseveration OR spectrum disorder OR savant OR sensory processing disorder AND Immunization OR vaccination | 12,800 | 1,090 |\n\n# Inclusion criteria\n\nWe choose peer-reviewed papers and studies from the last five years written in the English language. We only selected systematic reviews, traditional reviews, meta-analyses, and randomized trials conducted among human subjects. All data collected were within ethical and legal standards.\n\n# Exclusion criteria\n\nWe excluded gray data and papers that focused on animals. We also excluded articles published before 1998.\n\n# Quality assessment tool", + "score": 0.11252957582473755, "metadata": { - "document_id": 5, - "page": 15 + "document_id": 14, + "page": -1 } }, { "type": "text", - "content": "\u00a9 2014 Elsevier Ltd. All rights reserved.\n\nmodern day society and the decision to opt out of MMR or other childhood vaccination schedules because of concerns regarding the development of autism should be properly evaluated with available evidence. To date there have been no quantitative data analysis pooling cohort and case-control studies that have assessed the relationship between autism, autistic spectrum disorder and childhood vaccinations.\n\nThis meta-analysis aims to quantitatively assess the available data from studies undertaken in various countries regarding autism rates and childhood vaccination so that the relationship between these two, whatever its significance, can be adequately substantiated.\n\n# 2. Methods\n\n# 2.1. Study protocol\n\nWe followed the Preferred Reporting Items for Systematic Reviews and Meta-Analyses (PRISMA) guidelines to conduct our review and analysis [3,4]. The PRISMA guidelines have been\n\n\n\n", - "score": 0.11582404375076294, + "content": "In total, 19 articles were on the link between immunization and the incidence of autism. One article discussed the prevalence of ASD, the other about the effect of multiple immunizations during brain development (this study had data supporting the link between the current vaccine schedule and the development of ASD). The results of the 19 articles do not support a causal relationship between childhood immunization and the development of autism.\n\n# Discussion", + "score": 0.11253009885190113, "metadata": { - "document_id": 5, - "page": 25 + "document_id": 14, + "page": -1 } }, { "type": "text", - "content": "The current meta-analysis is the only quantitative analysis of pooled data on the topic. In the process of searching the literature 12 systematic reviews were identified and reference lists searched for additional data [24-35]. Eleven of the 12 identified reviews shared the current conclusion that there was no evidence for a link between vaccination and autistic spectrum disorder, advocating continuation of current immunisation practices. The only review to suggest that a link could not be excluded was that by Ratajczak [32] looking into the aetiology of autism and concluded that it is\n\nFig. 3. Pooled estimate for vaccines and autism and ASD.", - "score": 0.11594438552856445, + "content": "There has been enormous debate regarding the possibility of a link between childhood vaccinations and the subsequent development of autism. This has in recent times become a major public health issue with vaccine preventable diseases increasing in the community due to the fear of a 'link' between vaccinations and autism. We performed a meta-analysis to summarise available evidence from case-control and cohort studies on this topic (MEDLINE, PubMed, EMBASE, Google Scholar up to April, 2014). Eligible studies assessed the relationship between vaccine administration and the subsequent development of autism or autism spectrum disorders (ASD). Two reviewers extracted data on study characteristics, methods, and outcomes. Disagreement was resolved by consensus with another author. Five cohort studies involving 1,256,407 children, and five case-control studies involving 9,920 children were included in this analysis. The cohort data revealed no relationship between vaccination and autism (OR: 0.99; 95% CI: 0.92 to 1.06) or ASD (OR: 0.91; 95% CI: 0.68 to 1.20), nor was there a relationship between autism and MMR (OR: 0.84; 95% CI: 0.70 to 1.01), or thimerosal (OR: 1.00; 95% CI: 0.77 to 1.31)", + "score": 0.11265957355499268, "metadata": { - "document_id": 5, - "page": 10 + "document_id": 13, + "page": -1 } }, { "type": "text", - "content": "This review included retrospective and prospective cohort studies and case-control studies published in any language looking at the relationship between vaccination and disorders on the autistic spectrum. No limits were placed on publication date, publication status, or participant characteristics. Studies were included that looked at either MMR vaccination, cumulative mercury (Hg) or cumulative thimerosal dosage from vaccinations to ensure all proposed causes of ASD or regression were investigated. Outcome measures included development of any condition on the autistic spectrum as well as those specifically looking at regressive phenotype. Papers that recruited their cohort of participants solely from the Vaccine Adverse Event Reporting System (VAERS) in the United States were not included due to its many limitations and high risk of bias including unverified reports, underreporting, inconsistent data quality, absence of an unvaccinated control group and many reports being filed in connection with litigation [5,6]. We excluded studies that did not meet the inclusion criteria.\n\n# 2.3. Study selection", - "score": 0.11841118335723877, + "content": "# 2. General Medical Council, UK. Available: http://www.gmc-uk.org. Accessed 20 April 2009.\n\n# 3. Institute of Medicine (2004) Immunization safety review: Vaccines and autism. Washington (DC): National Academies Press, 31. Available: http://www.nap. edu/catalog.php?record\\_id=10997. Accessed 20 April 2009.\n\n# 4. Institute of Medicine. Immunization safety review: Vaccines and autism. Available: http://www.iom.edu/CMS/3793/4705/20155.aspx. Accessed 20 April 2009.\n\n# 5. Verstraeten T, Davis RL, DeStefano F, Lieu TA, Rhodes PH, et al. (2003) Safety of thimerosal-containing vaccines: a two-phased study of computerized health maintenance organization databases. Pediatrics 112: 1039-1048.\n\n# 6. VaccineInfo.net (2004) Parent groups denounce IOM report refuting vaccine autism connection. Available: http://www.vaccineinfo.net/releases/IOM\\_ vaccine\\_autism\\_report.htm. Accessed 20 April 2009.\n\n# 7. Florida Institute of Technology new release. Available: http://www.fit.edu/ newsroom/brief.html?id=2396. Accessed 20 April 2009.", + "score": 0.11312805931996783, "metadata": { - "document_id": 5, - "page": 16 + "document_id": 18, + "page": -1 } }, { "type": "text", - "content": "This project was funded under Contract No. HHSA290201600010I from the Agency for Healthcare Research and Quality (AHRQ), U.S. Department of Health and Human Services (HHS). The funder had no role in the design, interpretation of results, nor the decision to submit this manuscript. The authors of this manuscript are responsible for its content. Statements in the manuscript do not necessarily represent the official views of or imply endorsement by AHRQ or HHS.\n\n# Author contributions\n\nAll authors attest that they meet the ICMJE criteria for authorship.\n\n# Appendix A. Supplementary material\n\nSupplementary data to this article can be found online at https://doi.org/10.1016/j.vaccine.2021.03.079.\n\n# References\n\n- [1] [Centers for Disease Control Prevention. Ten great public health achievements-United States, 1900-1999. MMWR Morb Mortal Wkly Rep 1999;48:241-3.](http://refhub.elsevier.com/S0264-410X(21)00385-6/h0005)\n\n- [2] [Gidengil C, Chen C, Parker AM, Nowak S, Matthews L. Beliefs around childhood vaccines in the United States: A systematic review. Vaccine 2019;37:6793-802.](http://refhub.elsevier.com/S0264-410X(21)00385-6/h0010)", - "score": 0.11901568657066153, + "content": "According to our review, there is no link between the development of ASD and immunization. The dramatic increase in the prevalence of ASD created widespread concern. Many theories have been offered to explain the link between vaccination and the development of autism, including changes in immune system function, abnormal organic acid synthesis, mercury toxicity, the effects of gliamorphin on cerebral function, and the link between MMR and autism. However, all these theories remain theoretical, and our review finds no evidence of a link between them and the development of autism. Parents experienced vaccination reluctance following the release of the Wakefield study on the supposed MMR vaccine-autism relationship. It raises concern and challenges vaccine acceptance among parents, leading to the re-emergence of vaccinepreventable diseases. It still raises concern in some parents; we recommend that public health officials continue to advocate and encourage vaccination. The public may require more studies to rule out the association between ASD and vaccination.\n\n# Additional Information\n\n# Disclosures", + "score": 0.11321085691452026, "metadata": { - "document_id": 12, - "page": 32 + "document_id": 14, + "page": -1 } }, { "type": "text", - "content": "# 4. Discussion\n\nThis meta-analysis of five case-control and five cohort studies has found no evidence for the link between vaccination and the subsequent risk of developing autism or autistic spectrum disorder. Subgroup analyses looking specifically at MMR vaccinations, cumulative mercury dosage, and thimerosal exposure individually were similarly negative, as were subgroup analyses looking specifically at development of autistic disorder versus other autistic spectrum disorder.\n\nFour of the five cohort studies included in this review investigated very large populations and were of sound methodology, which is of great importance as our review question has implications at the population level, and thus required such data for optimal applicability.", - "score": 0.11924803256988525, + "content": "hotherpayersmaynotbecaptured.For example, the MMR immunization rates in our study were 4% to 14%lowerthanratesreportedintheNationalImmunization # ARTICLE INFORMATION Correction: This article and its related supplement was corrected on January 12, 2016, to fix data that differed after a variable was correctly defined. [jama.com](http://www.jama.com/?utm_campaign=articlePDF%26utm_medium=articlePDFlink%26utm_source=articlePDF%26utm_content=jama.2015.3077) Survey.Thus,childreninourstudywhoareconsideredunvaccinated may have received vaccines in settings such as schools orpublichealthclinicsinwhichclaimswerenotsubmitted.Additionally, the diagnosis of ASD was determinedusingaclaimsbasedalgorithmwithapositivepredictive value of 87%. There mayhavebeenchildrenwithASD,forexample,whodidnotreceive care related to their ASD during the study period. However, we conducted a series of quantitative bias analyses to assessthepotentialeffectofthesemeasurementerrorsanddonot believethesestronglyinfluencethefindingsofthisstudy.There are also potential inaccuracies in the identification of siblings from claims because of assumptions made about family relationships among individuals on the same health plan", + "score": 0.11381900310516357, "metadata": { - "document_id": 5, - "page": 12 + "document_id": 3, + "page": -1 } }, { "type": "text", - "content": "\n\nContents lists available at ScienceDirect\n\nVaccine\n\nj our na l ho me page: www.elsevier.com/locate/vaccine\n\n# Vaccines are not associated with autism: An evidence-based meta-analysis of case-control and cohort studies\n\nLuke E. Taylor, Amy L. Swerdfeger, Guy D. Eslick \u2217\n\nThe Whiteley-Martin Research Centre, Discipline of Surgery, The University of Sydney, Nepean Hospital, Level 3, Clinical Building, PO Box 63, Penrith 2751, NSW, Australia\n\nArticle history: Received 29 November 2013 Received in revised form 16 April 2014 Accepted 23 April 2014 Available online 9 May 2014\n\nKeywords: Vaccine Vaccination Immunisation Autism Autism spectrum disorder Thimerosal\n\nMercury\n\n# 1. Introduction", - "score": 0.12024319171905518, + "content": ".259 http://pediatrics.aappublications.org/content/113/2/259 including high resolution figures, can be found at: http://pediatrics.aappublications.org/content/113/2/259#BIBL This article cites 39 articles, 8 of which you can access for free at: following collection(s): This article, along with others on similar topics, appears in the Developmental/Behavioral Pediatrics al\\_issues\\_sub http://www.aappublications.org/cgi/collection/development:behavior [Autism/ASD](http://www.aappublications.org/cgi/collection/autism:asd_sub) Infectious Disease http://www.aappublications.org/cgi/collection/autism:asd\\_sub b http://www.aappublications.org/cgi/collection/infectious\\_diseases\\_su [Vaccine/Immunization](http://www.aappublications.org/cgi/collection/vaccine:immunization_sub) \\_sub http://www.aappublications.org/cgi/collection/vaccine:immunization in its entirety can be found online at: Information about reproducing this article in parts (figures, tables) or http://www.aappublications.org/site/misc/Permissions.xhtml http://www.aappublications.org/site/misc/reprints.xhtml Information about ordering reprints can be found online: Services Updated Information & References Subspecialty Coll", + "score": 0.11440348625183105, "metadata": { - "document_id": 5, - "page": 19 + "document_id": 6, + "page": -1 } }, { "type": "text", - "content": "based on exposure type did not support a link between measles vaccination (OR: 1.00, 95% CI: 0.59 to 1.67; I 2 = 30.50, p = 0.23), MMR vaccination (OR: 0.69, 95% CI: 0.53 to 0.90; I 2 = 66.85, p < 0.001), or thimerosal exposure (OR: 0.89, 95% CI: 0.78 to 1.00; I 2 = 58.40, p = 0.02) and ASD.\n\n# 3.5. Publication bias", - "score": 0.12264394760131836, + "content": "- [27] Kimmel SR, Burns IT, Wolfe RM, Zimmerman RK. Addressing immunization barriers, benefits, and risks. J Fam Pract 2007;56(Suppl. 2 vaccines): S61-9.\n\n- [28] [Klein KC, Diehl EB. Relationship between MMR vaccine and autism. Ann Pharmacother 2004;38(7-8):1297-300.](http://refhub.elsevier.com/S0264-410X(14)00636-7/sbref0155)\n\n- [29] Mutter J, Naumann J, Schneider R, Walach H, Haley B. Mercury and autism: accelerating evidence? Neuro Endocrinol Lett 2005;26(5):439-46.\n\n- [30] \u00d6rtqvist \u00c5, Blennow M, Carlsson R-M, et al. Vaccination of children-a systematic review. Acta Paediatr 2010;99(461):1-192.\n\n- [31] Parker SK, Schwartz B, Todd J, Pickering LK. Thimerosal-containing vaccines and autistic spectrum disorder: a critical review of published original data. Pediatrics 2004;114(3):793-804.\n\n- [32] Ratajczak HV. Theoretical aspects of autism: causes-a review. J Immunotoxicol 2011;8(1):68-79.\n\n- [33] Rutter M. Aetiology of autism: findings and questions. J Intellect Disabil Res 2005;49(4):231-8.", + "score": 0.11575073003768921, "metadata": { - "document_id": 5, - "page": 21 + "document_id": 13, + "page": -1 } }, { "type": "text", - "content": "ate SoE across 6 studies). The risk estimate was imprecise because it was based on one small study with no deaths (0/99 vs 0/107). There was no evidence of increased risk of anaphylaxis or systemic allergic reaction, asthma, autoimmune disease, cardiovascular events, febrile seizures, or seizures (low SoE).\n\nQuadrivalent live attenuated influenza vaccine (LAIV) was compared to placebo or no vaccine in some studies, or another influenza vaccine (trivalent LAIV or IIV) in other studies. There was no evidence of increased risk of death (when compared to trivalent LAIV) or seizures (when compared to placebo or no vaccine) (low SoE).\n\nMeasles, mumps, and rubella vaccine . There was no evidence of an association with autism (RR 0.60; CI 0.09, 4.12; based on 2 studies; high SoE across prior 2014 report and update). There was a causal relationship with anaphylaxis in children with allergies (based on mechanistic evidence from the IOM report [24]; high SoE), as well as an increased risk of febrile seizures (high\n\nSoE), and idiopathic thrombocytopenic purpura (moderate SoE) (effect estimates N/A). There was no evidence of increased risk of asthma (low SoE).", - "score": 0.12270026667712375, + "content": "\u00a9 2014 Elsevier Ltd. All rights reserved.\n\nmodern day society and the decision to opt out of MMR or other childhood vaccination schedules because of concerns regarding the development of autism should be properly evaluated with available evidence. To date there have been no quantitative data analysis pooling cohort and case-control studies that have assessed the relationship between autism, autistic spectrum disorder and childhood vaccinations.\n\nThis meta-analysis aims to quantitatively assess the available data from studies undertaken in various countries regarding autism rates and childhood vaccination so that the relationship between these two, whatever its significance, can be adequately substantiated.\n\n# 2. Methods\n\n# 2.1. Study protocol\n\nWe followed the Preferred Reporting Items for Systematic Reviews and Meta-Analyses (PRISMA) guidelines to conduct our review and analysis [3,4]. The PRISMA guidelines have been\n\n\n\n", + "score": 0.11582386493682861, "metadata": { - "document_id": 12, - "page": 6 + "document_id": 13, + "page": -1 } } ], "documents": { - "5": { - "link": "https://linkinghub.elsevier.com/retrieve/pii/S0264410X14006367", - "title": "Vaccines are not associated with autism: An evidence-based meta-analysis of case-control and cohort studies", - "date": "2014-06-17", - "journal": "Elsevier BV", - "author_ids": ["1", "2", "3"], + "14": { + "id": 14, + "doi": "10.7759/cureus.27921", + "title": "Does Vaccination Increase the Risk of Autism Spectrum Disorder?", + "keywords": [ + "Autistic Disorder", + "Measles-Mumps-Rubella Vaccine", + "Immunization", + "Vaccines" + ], + "author_ids": [ + "66", + "67", + "68", + "69", + "70", + "71", + "72", + "73", + "74", + "75" + ] + }, + "13": { + "id": 13, "doi": "10.1016/j.vaccine.2014.04.085", - "abstract": "There has been enormous debate regarding the possibility of a link between childhood vaccinations and the subsequent development of autism. This has in recent times become a major public health issue with vaccine preventable diseases increasing in the community due to the fear of a ‘link’ between vaccinations and autism. We performed a meta-analysis to summarise available evidence from case-control and cohort studies on this topic (MEDLINE, PubMed, EMBASE, Google Scholar up to April, 2014). Eligible studies assessed the relationship between vaccine administration and the subsequent development of autism or autism spectrum disorders (ASD). Two reviewers extracted data on study characteristics, methods, and outcomes. Disagreement was resolved by consensus with another author. Five cohort studies involving 1,256,407 children, and five case-control studies involving 9,920 children were included in this analysis. The cohort data revealed no relationship between vaccination and autism (OR: 0.99; 95% CI: 0.92 to 1.06) or ASD (OR: 0.91; 95% CI: 0.68 to 1.20), nor was there a relationship between autism and MMR (OR: 0.84; 95% CI: 0.70 to 1.01), or thimerosal (OR: 1.00; 95% CI: 0.77 to 1.31), or mercury (Hg) (OR: 1.00; 95% CI: 0.93 to 1.07). Similarly the case-control data found no evidence for increased risk of developing autism or ASD following MMR, Hg, or thimerosal exposure when grouped by condition (OR: 0.90, 95% CI: 0.83 to 0.98; p = 0.02) or grouped by exposure type (OR: 0.85, 95% CI: 0.76 to 0.95; p = 0.01). Findings of this meta-analysis suggest that vaccinations are not associated with the development of autism or autism spectrum disorder. Furthermore, the components of the vaccines (thimerosal or mercury) or multiple vaccines (MMR) are not associated with the development of autism or autism spectrum disorder.", + "title": "Vaccines are not associated with autism: an evidence-based meta-analysis of case-control and cohort studies.", "keywords": [ - "Autistic Disorder", - "Child Development Disorders, Pervasive", - "Humans", - "Mercury", - "Preservatives, Pharmaceutical", - "Thimerosal", - "Vaccination", - "Publication Bias", - "Measles-Mumps-Rubella Vaccine" - ], - "evidence": { - "name": "meta-analysis", - "rank": 1 - } + "Autistic Disorder", + "Child Development Disorders, Pervasive", + "Humans", + "Mercury", + "Preservatives, Pharmaceutical", + "Thimerosal", + "Vaccines", + "Publication Bias", + "Measles-Mumps-Rubella Vaccine" + ], + "author_ids": [ + "63", + "64", + "65" + ] }, - "12": { - "link": "https://linkinghub.elsevier.com/retrieve/pii/S0264410X21003856", - "title": "Safety of vaccines used for routine immunization in the United States: An updated systematic review and meta-analysis", - "date": "2021-06-23", - "journal": "Elsevier BV", - "author_ids": ["4", "5", "6", "7", "8", "9", "10", "11"], - "doi": "10.1016/j.vaccine.2021.03.079", - "abstract": "Background Understanding the safety of vaccines is critical to inform decisions about vaccination. Our objective was to conduct a systematic review of the safety of vaccines recommended for children, adults, and pregnant women in the United States. Methods We searched the literature in November 2020 to update a 2014 Agency for Healthcare Research and Quality review by integrating newly available data. Studies of vaccines that used a comparator and reported the presence or absence of key adverse events were eligible. Adhering to Evidence-based Practice Center methodology, we assessed the strength of evidence (SoE) for all evidence statements. The systematic review is registered in PROSPERO (CRD42020180089). Results Of 56,603 reviewed citations, 338 studies reported in 518 publications met inclusion criteria. For children, SoE was high for no increased risk of autism following measles, mumps, and rubella (MMR) vaccine. SoE was high for increased risk of febrile seizures with MMR. There was no evidence of increased risk of intussusception with rotavirus vaccine at the latest follow-up (moderate SoE), nor of diabetes (high SoE). There was no evidence of increased risk or insufficient evidence for key adverse events for newer vaccines such as 9-valent human papillomavirus and meningococcal B vaccines. For adults, there was no evidence of increased risk (varied SoE) or insufficient evidence for key adverse events for the new adjuvanted inactivated influenza vaccine and recombinant adjuvanted zoster vaccine. We found no evidence of increased risk (varied SoE) for key adverse events among pregnant women following tetanus, diphtheria, and acellular pertussis vaccine, including stillbirth (moderate SoE). Conclusions Across a large body of research we found few associations of vaccines and serious key adverse events; however, rare events are challenging to study. Any adverse events should be weighed against the protective benefits that vaccines provide.", + "18": { + "id": 18, + "doi": "10.1371/journal.pbio.1000114", + "title": "A broken trust: lessons from the vaccine--autism wars.", "keywords": [ - "Adult", - "Child", - "Diphtheria", - "Female", - "Humans", - "Infant", - "Measles", - "Mumps", - "Pregnancy", - "United States", - "Vaccination", - "Measles-Mumps-Rubella Vaccine" - ], - "evidence": { - "name": "systematic-review", - "rank": 2 - } - + "Autistic Disorder", + "Female", + "Humans", + "Parents", + "Public Opinion", + "Sex Factors", + "Vaccines", + "Biomedical Research" + ], + "author_ids": [ + "87" + ] + }, + "3": { + "id": 3, + "doi": "10.1001/jama.2015.3077", + "title": "Autism occurrence by MMR vaccine status among US children with older siblings with and without autism.", + "keywords": [ + "Autistic Disorder", + "Vaccines", + "Child", + "Child, Preschool", + "Female", + "Humans", + "Infant", + "Male", + "Retrospective Studies", + "Measles-Mumps-Rubella Vaccine", + "Siblings" + ], + "author_ids": [ + "11", + "12", + "13", + "14", + "15", + "16" + ] + }, + "6": { + "id": 6, + "doi": "10.1542/peds.113.2.259", + "title": "Age at first measles-mumps-rubella vaccination in children with autism and school-matched control subjects: a population-based study in metropolitan atlanta.", + "keywords": [ + "Autistic Disorder", + "Birth Weight", + "Developmental Disabilities", + "Child, Preschool", + "Female", + "Georgia", + "Humans", + "Infant", + "Male", + "Intellectual Disability", + "Population Surveillance", + "Risk Factors", + "Vaccines", + "Odds Ratio", + "Case-Control Studies", + "Age Distribution", + "Measles-Mumps-Rubella Vaccine", + "Racial Groups" + ], + "author_ids": [ + "23", + "24", + "25", + "26", + "27" + ] } }, "authors": { - "1": { + "66": { + "name": "Shaza A Mohammed", + "orcid": null + }, + "67": { + "name": "Shriya Rajashekar", + "orcid": null + }, + "68": { + "name": "Suganya Giri Ravindran", + "orcid": null + }, + "69": { + "name": "Meghana Kakarla", + "orcid": null + }, + "70": { + "name": "Musa Ausaja Gambo", + "orcid": null + }, + "71": { + "name": "Mustafa Yousri Salama", + "orcid": null + }, + "72": { + "name": "Nathalie Haidar Ismail", + "orcid": null + }, + "73": { + "name": "Pardis Tavalla", + "orcid": null + }, + "74": { + "name": "Pulkita Uppal", + "orcid": null + }, + "75": { + "name": "Pousette Hamid", + "orcid": null + }, + "63": { "name": "Luke E. Taylor", "orcid": null }, - "2": { + "64": { "name": "Amy L. Swerdfeger", "orcid": null }, - "3": { + "65": { "name": "Guy D. Eslick", "orcid": null }, - "4": { - "name": "Courtney Gidengil", + "87": { + "name": "Liza Gross", "orcid": null }, - "5": { - "name": "Matthew Bidwell Goetz", + "11": { + "name": "Anjali Jain", "orcid": null }, - "6": { - "name": "Sydne Newberry", + "12": { + "name": "Jaclyn Marshall", "orcid": null }, - "7": { - "name": "Margaret Maglione", + "13": { + "name": "Ami Buikema", "orcid": null }, - "8": { - "name": "Owen Hall", + "14": { + "name": "Tim Bancroft", "orcid": null }, - "9": { - "name": "Jody Larkin", + "15": { + "name": "Jonathan P. Kelly", "orcid": null }, - "10": { - "name": "Aneesa Motala", + "16": { + "name": "Craig J. Newschaffer", "orcid": null }, - "11": { - "name": "Susanne Hempel", + "23": { + "name": "Frank DeStefano", + "orcid": null + }, + "24": { + "name": "Tanya Karapurkar Bhasin", + "orcid": null + }, + "25": { + "name": "William W. Thompson", + "orcid": null + }, + "26": { + "name": "Marshalyn Yeargin-Allsopp", + "orcid": null + }, + "27": { + "name": "Coleen Boyle", "orcid": null } } From e18fc2e3b9fa53cb32eac55ecb8e858195e07300 Mon Sep 17 00:00:00 2001 From: Hugo De Oliveira <80337112+hugros-93@users.noreply.github.com> Date: Wed, 6 May 2026 09:46:16 +0200 Subject: [PATCH 05/18] add outline button in css --- eu_fact_force/dash-app/assets/custom.css | 30 ++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/eu_fact_force/dash-app/assets/custom.css b/eu_fact_force/dash-app/assets/custom.css index f95d522..163f172 100644 --- a/eu_fact_force/dash-app/assets/custom.css +++ b/eu_fact_force/dash-app/assets/custom.css @@ -71,6 +71,36 @@ hr { background-color: var(--color-gray) !important; } +/* Button (primary outline) */ +.btn-outline-primary { + border-color: var(--color-dark-blue) !important; + color: var(--color-dark-blue) !important; + background-color: transparent !important; +} + +.btn-outline-primary:hover { + border-color: var(--color-dark-blue) !important; + color: var(--color-white) !important; + background-color: var(--color-dark-blue) !important; +} + +.btn-outline-primary:active { + border-color: var(--color-dark-blue) !important; + color: var(--color-white) !important; + background-color: var(--color-dark-blue) !important; +} + +.btn-outline-primary.active { + border-color: var(--color-dark-blue) !important; + color: var(--color-white) !important; + background-color: var(--color-dark-blue) !important; +} + +.btn-outline-primary:disabled { + border-color: var(--color-gray) !important; + color: var(--color-gray) !important; + background-color: transparent !important; +} /* Offcanevas */ .offcanvas-header { From aecddfa8f7efad67ae0a17a27f2fe53747d066d6 Mon Sep 17 00:00:00 2001 From: Hugo De Oliveira <80337112+hugros-93@users.noreply.github.com> Date: Wed, 6 May 2026 09:46:29 +0200 Subject: [PATCH 06/18] add space between search and results --- eu_fact_force/dash-app/pages/graph.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eu_fact_force/dash-app/pages/graph.py b/eu_fact_force/dash-app/pages/graph.py index e187e64..12f4ce0 100644 --- a/eu_fact_force/dash-app/pages/graph.py +++ b/eu_fact_force/dash-app/pages/graph.py @@ -154,6 +154,6 @@ def make_layout(): ) return html.Div( - [search_bar, results], + [search_bar, html.Br(), results], style={"fontFamily": "system-ui, -apple-system, sans-serif"} ) \ No newline at end of file From 85f332ae82ce07845793c5374fadb6d02e16d2d8 Mon Sep 17 00:00:00 2001 From: samibtorres Date: Wed, 6 May 2026 09:40:34 +0200 Subject: [PATCH 07/18] Remove unused import for CI --- eu_fact_force/dash-app/utils/graph.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eu_fact_force/dash-app/utils/graph.py b/eu_fact_force/dash-app/utils/graph.py index d143c95..f58641c 100644 --- a/eu_fact_force/dash-app/utils/graph.py +++ b/eu_fact_force/dash-app/utils/graph.py @@ -1,6 +1,6 @@ import os import requests -from dash import dcc, html +from dash import html import dash_bootstrap_components as dbc from .colors import EUPHAColors From b78f9843acdd6531444bfef1d5f6734c6c0567c2 Mon Sep 17 00:00:00 2001 From: Hugo De Oliveira <80337112+hugros-93@users.noreply.github.com> Date: Wed, 6 May 2026 09:55:10 +0200 Subject: [PATCH 08/18] filter authors and chunks by default --- eu_fact_force/dash-app/app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eu_fact_force/dash-app/app.py b/eu_fact_force/dash-app/app.py index e94deae..4abb442 100644 --- a/eu_fact_force/dash-app/app.py +++ b/eu_fact_force/dash-app/app.py @@ -231,7 +231,7 @@ def get_search_data(n_clicks, search_text): list(set(filters["authors"])), min(filters["date"]) if filters["date"] else None, max(filters["date"]) if filters["date"] else None, - list(set(filters["node_types"])), + list(set([x for x in filters["node_types"] if x not in ['chunk', 'author']])), list(set(filters["chunk_types"])), list(set(filters["keywords"])), list(set(filters["documents"])), From ffce9a51d1bb3a0c0afdb1876772723e0bbac747 Mon Sep 17 00:00:00 2001 From: Hugo De Oliveira <80337112+hugros-93@users.noreply.github.com> Date: Wed, 6 May 2026 10:02:29 +0200 Subject: [PATCH 09/18] minimize node overlap --- eu_fact_force/dash-app/pages/graph.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/eu_fact_force/dash-app/pages/graph.py b/eu_fact_force/dash-app/pages/graph.py index 12f4ce0..dfcf752 100644 --- a/eu_fact_force/dash-app/pages/graph.py +++ b/eu_fact_force/dash-app/pages/graph.py @@ -67,7 +67,13 @@ def make_layout(): cyto.Cytoscape( id="graph-cytoscape", stylesheet=stylesheet, - layout={"name": "cose", "padding": 40}, + layout={ + "name": "cose", + "padding": 40, + "avoidOverlap": True, + "nodeRepulsion": 400000, + "idealEdgeLength": 100 + }, style={"width": "100%", "height": "550px", "backgroundColor": EUPHAColors.white}, zoomingEnabled=True, userZoomingEnabled=True, From dd81aeef3e4923556d50fe3b4d363abec2044b8c Mon Sep 17 00:00:00 2001 From: Hugo De Oliveira <80337112+hugros-93@users.noreply.github.com> Date: Wed, 6 May 2026 10:04:23 +0200 Subject: [PATCH 10/18] fix CI --- eu_fact_force/dash-app/pages/readme.py | 2 +- eu_fact_force/dash-app/utils/graph.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/eu_fact_force/dash-app/pages/readme.py b/eu_fact_force/dash-app/pages/readme.py index a19f18c..d8f8be9 100644 --- a/eu_fact_force/dash-app/pages/readme.py +++ b/eu_fact_force/dash-app/pages/readme.py @@ -1,4 +1,4 @@ -from dash import dcc, html +from dash import html from utils.colors import EUPHAColors def make_layout(): diff --git a/eu_fact_force/dash-app/utils/graph.py b/eu_fact_force/dash-app/utils/graph.py index f58641c..af0f6ff 100644 --- a/eu_fact_force/dash-app/utils/graph.py +++ b/eu_fact_force/dash-app/utils/graph.py @@ -188,7 +188,7 @@ def format_node_metadata(node_data): elif node_data["type"] == "chunk": score = round(node_data['metadata'].get('score', 0), 2) return html.Div([ - html.H5(f"Extracted Segment", className="fw-bold mb-1", style={"color": EUPHAColors.text_dark}), + html.H5("Extracted Segment", className="fw-bold mb-1", style={"color": EUPHAColors.text_dark}), html.P(f"Relevance Score: {score}", className="text-muted small mb-3"), html.Div( From 009870cd1d392677b3014e10223aacd93f72533e Mon Sep 17 00:00:00 2001 From: Hugo De Oliveira <80337112+hugros-93@users.noreply.github.com> Date: Wed, 6 May 2026 10:11:26 +0200 Subject: [PATCH 11/18] fix missing spaces in readme text --- eu_fact_force/dash-app/pages/readme.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/eu_fact_force/dash-app/pages/readme.py b/eu_fact_force/dash-app/pages/readme.py index d8f8be9..3a25d58 100644 --- a/eu_fact_force/dash-app/pages/readme.py +++ b/eu_fact_force/dash-app/pages/readme.py @@ -15,8 +15,8 @@ def make_layout(): style={"color": EUPHAColors.primary, "fontStyle": "normal", "fontWeight": "500", "marginTop": "0px", "fontSize": "22px"} ), html.P( - "A long-term collaborative project led by EUPHA in collaboration with Data for Good and The Public Good Projects" - "to bring together technical experts, researchers, and civil society actors" + "A long-term collaborative project led by EUPHA in collaboration with Data for Good and The Public Good Projects " + "to bring together technical experts, researchers, and civil society actors " "to detect, analyze, and respond collectively to health misinformation.", style={ "fontSize": "17px", @@ -52,11 +52,11 @@ def make_layout(): [ html.H4("The Infodemic Context", style={"color": EUPHAColors.primary, "fontSize": "22px", "marginBottom": "15px", "fontWeight": "600"}), html.P( - "Health misinformation has reached an unprecedented scale" - "driven by political polarization, commercial interests, and geopolitical strategies." - "Traditional public health systems are struggling to monitor" - "and respond to these false narratives in a timely, coordinated way." - "The EU Health Fact Force hub transforms fragmented reactions" + "Health misinformation has reached an unprecedented scale " + "driven by political polarization, commercial interests, and geopolitical strategies. " + "Traditional public health systems are struggling to monitor " + "and respond to these false narratives in a timely, coordinated way. " + "The EU Health Fact Force hub transforms fragmented reactions " "into proactive, unified public-health communication.", style={"lineHeight": "1.7", "color": EUPHAColors.text_main} ) @@ -68,9 +68,9 @@ def make_layout(): [ html.H4("Beyond Automated Fact-Checking", style={"color": EUPHAColors.primary, "fontSize": "22px", "marginBottom": "15px", "fontWeight": "600"}), html.P( - "Rather than relying solely on automated counter-messaging," - "the EUHFF Hub prioritizes human coordination, collective intelligence, and solidarity." - "We focus on bridging science, lived experience, and community insight to meet people where they are," + "Rather than relying solely on automated counter-messaging, " + "the EUHFF Hub prioritizes human coordination, collective intelligence, and solidarity. " + "We focus on bridging science, lived experience, and community insight to meet people where they are, " "equipping trusted local messengers with evidence-based content.", style={"lineHeight": "1.7", "color": EUPHAColors.text_main} ) From fb4d0f98247f9d96bc824a9ece1399c8661c7214 Mon Sep 17 00:00:00 2001 From: samibtorres Date: Wed, 6 May 2026 10:26:41 +0200 Subject: [PATCH 12/18] Uniformized UI with other pages --- eu_fact_force/dash-app/pages/ingest.py | 85 ++++++++++++++------------ 1 file changed, 46 insertions(+), 39 deletions(-) diff --git a/eu_fact_force/dash-app/pages/ingest.py b/eu_fact_force/dash-app/pages/ingest.py index fffe46e..1093319 100644 --- a/eu_fact_force/dash-app/pages/ingest.py +++ b/eu_fact_force/dash-app/pages/ingest.py @@ -10,27 +10,17 @@ def make_layout(): [ html.Div( [ - - html.H3( - "EU Fact Force", - className="text-center", - style={ - "fontWeight": "700", - "fontSize": "1.9rem", - "marginBottom": "20px", - "color": EUPHAColors.primary - } - ), - html.Hr(style={"margin": "1.2rem 0"}), - html.H5( + html.H3( "How it works", style={ - "fontWeight": "500", + "color": EUPHAColors.text_dark, + "margin": "0", "marginBottom": "12px", - "marginTop": "45px" - } + "marginTop": "45px", + "fontWeight": "500", + "fontSize": "20px"} ), html.Ol( @@ -53,15 +43,20 @@ def make_layout(): } ) ], - style={ - "padding": "2rem 1rem", - "backgroundColor": EUPHAColors.white, + style= + { + "borderRadius": "16px", + "borderRight": "1px solid", "height": "100vh", "position": "fixed", "top": 0, "left": 0, "width": "16%", - "borderRight": "1px solid #dee2e6" + "padding": "2rem 1rem", + "backgroundColor": EUPHAColors.white, + "color": EUPHAColors.text_main, + "boxShadow": "0 10px 15px -3px rgba(0,0,0,0.05), 0 4px 6px -2px rgba(0,0,0,0.025)", + "fontFamily": "system-ui, -apple-system, sans-serif" } ) @@ -74,37 +69,45 @@ def make_layout(): "EU Fact Force - Article uploading page", className="mb-3 text-center", style={ - "fontWeight": "700", - "fontSize": "2.5rem", - "lineHeight": "1.15" + "color": EUPHAColors.text_main, + "fontWeight": "800", + "marginBottom": "10px", + "fontSize": "36px" } ), html.H3( "Welcome to EU Fact Force articles uploading pages", className="text-center mb-4", style={ - "color": EUPHAColors.black, - "fontWeight": "500", - "fontSize": "1.5rem", - "lineHeight": "1.3" + "color": EUPHAColors.primary, + "fontStyle": "normal", + "fontWeight": "500", + "marginTop": "0px", + "fontSize": "22px" } ), html.P( "Thank you for collaborating with us, you will find here a page where you can upload and declare authors of your papers in attempt to build a safer and healthier community! Thank you for your contribution!", className="text-center mb-5", style={ - "maxWidth": "900px", - "margin": "0 auto", - "fontSize": "1.1rem", - "lineHeight": "1.7", - "color": EUPHAColors.black + "fontSize": "17px", + "color": EUPHAColors.text_main, + "marginTop": "20px", + "lineHeight": "1.6", + "maxWidth": "800px", + "margin": "20px auto 0 auto" } ), ], + style={ - "maxWidth": "1100px", - "margin": "0 auto 2rem auto" - } + "borderRadius": "16px", + "padding": "60px", + "backgroundColor": EUPHAColors.white, + "color": EUPHAColors.text_main, + "boxShadow": "0 10px 15px -3px rgba(0,0,0,0.05), 0 4px 6px -2px rgba(0,0,0,0.025)", + "fontFamily": "system-ui, -apple-system, sans-serif" + }, ), dbc.Card([ @@ -238,11 +241,15 @@ def make_layout(): html.Div(id='final-output', className="mt-4 pb-5") ], - style={ + style= + { "marginLeft": "16%", - "padding": "5rem 1.5rem 2rem 1.5rem", - "width": "84%", - "backgroundColor": "#ffffff" + "borderRadius": "16px", + "padding": "60px", + "backgroundColor": EUPHAColors.white, + "color": EUPHAColors.text_main, + "boxShadow": "0 10px 15px -3px rgba(0,0,0,0.05), 0 4px 6px -2px rgba(0,0,0,0.025)", + "fontFamily": "system-ui, -apple-system, sans-serif" } ) From 0b0e1456823c44235446dc738d29147d21fe548f Mon Sep 17 00:00:00 2001 From: Hugo De Oliveira <80337112+hugros-93@users.noreply.github.com> Date: Wed, 6 May 2026 10:34:34 +0200 Subject: [PATCH 13/18] update pgp page layout --- eu_fact_force/dash-app/pages/pgp.py | 111 ++++++++++++++++++---------- 1 file changed, 74 insertions(+), 37 deletions(-) diff --git a/eu_fact_force/dash-app/pages/pgp.py b/eu_fact_force/dash-app/pages/pgp.py index 8db5071..7d3155d 100644 --- a/eu_fact_force/dash-app/pages/pgp.py +++ b/eu_fact_force/dash-app/pages/pgp.py @@ -1,48 +1,47 @@ # pages/pgp.py -from dash import html, dcc +from dash import dcc, html +from utils.colors import EUPHAColors from utils.pgpxd4g_graphs import get_figures + def make_layout(): trend, lang, source, themes = get_figures() return html.Div( - style={ - "backgroundColor": "#F4F6F8", - "padding": "20px", - "fontFamily": "Arial", - }, children=[ - # HEADER html.Div( - "PGP Dashboard", - style={ - "backgroundColor": "#0B5FA5", - "color": "white", - "padding": "15px", - "borderRadius": "10px", - "textAlign": "center", - "fontSize": "22px", - "fontWeight": "bold", - }, - ), - - - html.Div( - "This dashboard summarizes posting dynamics, linguistic distribution, platform sources, and key thematic patterns extracted from the dataset.", + [ + html.H1( + "PGP Dashboard", + style={ + "fontFamily": "system-ui, -apple-system, sans-serif", + "textAlign": "center", + "fontSize": "22px", + "fontWeight": "bold", + }, + ), + html.P( + "This dashboard summarizes posting dynamics, linguistic distribution, platform sources, and key thematic patterns extracted from the dataset.", + style={ + "fontFamily": "system-ui, -apple-system, sans-serif", + "textAlign": "center", + "fontSize": "14px", + "fontStyle": "italic", + }, + ), + ], style={ - "textAlign": "center", - "marginTop": "6px", - "marginBottom": "16px", - "color": "#6B7280", - "fontSize": "12.5px", - "fontStyle": "italic", + "borderRadius": "16px", + "padding": "20px", + "backgroundColor": EUPHAColors.white, + "color": EUPHAColors.text_main, + "boxShadow": "0 10px 15px -3px rgba(0,0,0,0.05), 0 4px 6px -2px rgba(0,0,0,0.025)", }, ), - - + html.Br(), # GRAPHS GRID PROPRE html.Div( style={ @@ -51,13 +50,51 @@ def make_layout(): "gap": "15px", }, children=[ - - dcc.Graph(figure=trend), - dcc.Graph(figure=lang), - - dcc.Graph(figure=source), - dcc.Graph(figure=themes), + html.Div( + dcc.Graph(figure=trend), + style={ + "borderRadius": "16px", + "padding": "20px", + "backgroundColor": EUPHAColors.white, + "color": EUPHAColors.text_main, + "boxShadow": "0 10px 15px -3px rgba(0,0,0,0.05), 0 4px 6px -2px rgba(0,0,0,0.025)", + "fontFamily": "system-ui, -apple-system, sans-serif", + }, + ), + html.Div( + dcc.Graph(figure=lang), + style={ + "borderRadius": "16px", + "padding": "20px", + "backgroundColor": EUPHAColors.white, + "color": EUPHAColors.text_main, + "boxShadow": "0 10px 15px -3px rgba(0,0,0,0.05), 0 4px 6px -2px rgba(0,0,0,0.025)", + "fontFamily": "system-ui, -apple-system, sans-serif", + }, + ), + html.Div( + dcc.Graph(figure=source), + style={ + "borderRadius": "16px", + "padding": "20px", + "backgroundColor": EUPHAColors.white, + "color": EUPHAColors.text_main, + "boxShadow": "0 10px 15px -3px rgba(0,0,0,0.05), 0 4px 6px -2px rgba(0,0,0,0.025)", + "fontFamily": "system-ui, -apple-system, sans-serif", + }, + ), + html.Div( + dcc.Graph(figure=themes), + style={ + "borderRadius": "16px", + "padding": "20px", + "backgroundColor": EUPHAColors.white, + "color": EUPHAColors.text_main, + "boxShadow": "0 10px 15px -3px rgba(0,0,0,0.05), 0 4px 6px -2px rgba(0,0,0,0.025)", + "fontFamily": "system-ui, -apple-system, sans-serif", + }, + ), ], ), ], - ) \ No newline at end of file + ) From 5c4857c64f492cb297ef7142fcf133fcfbe5391f Mon Sep 17 00:00:00 2001 From: Hugo De Oliveira <80337112+hugros-93@users.noreply.github.com> Date: Wed, 6 May 2026 10:37:44 +0200 Subject: [PATCH 14/18] delete background in upload page --- eu_fact_force/dash-app/pages/ingest.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/eu_fact_force/dash-app/pages/ingest.py b/eu_fact_force/dash-app/pages/ingest.py index 1093319..4ca77c4 100644 --- a/eu_fact_force/dash-app/pages/ingest.py +++ b/eu_fact_force/dash-app/pages/ingest.py @@ -256,8 +256,7 @@ def make_layout(): return html.Div([ dcc.Store(id='session-store', data={}), sidebar, main_content], - style={"fontFamily": "system-ui, -apple-system, sans-serif", - "backgroundColor": "#f5f7fa"}) + style={"fontFamily": "system-ui, -apple-system, sans-serif"}) From 6fce535589005552904ecfc583d1e17ad46837ac Mon Sep 17 00:00:00 2001 From: Hugo De Oliveira <80337112+hugros-93@users.noreply.github.com> Date: Wed, 6 May 2026 10:40:43 +0200 Subject: [PATCH 15/18] add break --- eu_fact_force/dash-app/pages/ingest.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/eu_fact_force/dash-app/pages/ingest.py b/eu_fact_force/dash-app/pages/ingest.py index 4ca77c4..0a4d8cb 100644 --- a/eu_fact_force/dash-app/pages/ingest.py +++ b/eu_fact_force/dash-app/pages/ingest.py @@ -110,6 +110,8 @@ def make_layout(): }, ), + html.Br(), + dbc.Card([ dbc.CardBody([ html.H4( From 23750c1b51308a5a63f3a811e64d2816d5ea1ff1 Mon Sep 17 00:00:00 2001 From: Hugo De Oliveira <80337112+hugros-93@users.noreply.github.com> Date: Wed, 6 May 2026 10:43:47 +0200 Subject: [PATCH 16/18] make pgp page like other pages --- eu_fact_force/dash-app/pages/pgp.py | 35 ++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/eu_fact_force/dash-app/pages/pgp.py b/eu_fact_force/dash-app/pages/pgp.py index 7d3155d..e7b056a 100644 --- a/eu_fact_force/dash-app/pages/pgp.py +++ b/eu_fact_force/dash-app/pages/pgp.py @@ -15,22 +15,26 @@ def make_layout(): html.Div( [ html.H1( - "PGP Dashboard", + "EU Fact Force - PGP Dashboard", + className="mb-3 text-center", style={ - "fontFamily": "system-ui, -apple-system, sans-serif", - "textAlign": "center", - "fontSize": "22px", - "fontWeight": "bold", - }, + "color": EUPHAColors.text_main, + "fontWeight": "800", + "marginBottom": "10px", + "fontSize": "36px" + } ), html.P( "This dashboard summarizes posting dynamics, linguistic distribution, platform sources, and key thematic patterns extracted from the dataset.", + className="text-center mb-5", style={ - "fontFamily": "system-ui, -apple-system, sans-serif", - "textAlign": "center", - "fontSize": "14px", - "fontStyle": "italic", - }, + "fontSize": "17px", + "color": EUPHAColors.text_main, + "marginTop": "20px", + "lineHeight": "1.6", + "maxWidth": "800px", + "margin": "20px auto 0 auto" + } ), ], style={ @@ -97,4 +101,13 @@ def make_layout(): ], ), ], + style= + { + "borderRadius": "16px", + "padding": "60px", + "backgroundColor": EUPHAColors.white, + "color": EUPHAColors.text_main, + "boxShadow": "0 10px 15px -3px rgba(0,0,0,0.05), 0 4px 6px -2px rgba(0,0,0,0.025)", + "fontFamily": "system-ui, -apple-system, sans-serif" + } ) From f666e11e06e88bf27943da6ce92a7d42d97d92ec Mon Sep 17 00:00:00 2001 From: samibtorres Date: Wed, 6 May 2026 10:54:29 +0200 Subject: [PATCH 17/18] Adapted legend text --- eu_fact_force/dash-app/pages/pgp.py | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/eu_fact_force/dash-app/pages/pgp.py b/eu_fact_force/dash-app/pages/pgp.py index e7b056a..541986d 100644 --- a/eu_fact_force/dash-app/pages/pgp.py +++ b/eu_fact_force/dash-app/pages/pgp.py @@ -25,12 +25,30 @@ def make_layout(): } ), html.P( - "This dashboard summarizes posting dynamics, linguistic distribution, platform sources, and key thematic patterns extracted from the dataset.", + "This dashboard visualizes social media conversations surrounding vaccines, utilizing data provided by " + "The Public Good Projects (PGP) via the Quid API. It tracks posting dynamics, linguistic distribution, " + "and thematic patterns based on specific query logic.", + style={ + "fontFamily": "system-ui, -apple-system, sans-serif", + "textAlign": "center", + "fontSize": "14px", + "fontStyle": "italic", + "marginBottom": "8px", + }, + ), + html.P([ + html.B("Please note:"), + " this system tracks conversation volume using ", + html.B("keywords"), + ", meaning it highlights how much a topic is being discussed, but does not measure sentiment " + "or what users actually believe. Currently, this dashboard serves as a prototype built from a static data " + "export. It will soon be fully integrated into the platform through an automated API workflow for daily " + "updates." + ], className="text-center mb-5", style={ "fontSize": "17px", - "color": EUPHAColors.text_main, - "marginTop": "20px", + "color": EUPHAColors.text_main, "lineHeight": "1.6", "maxWidth": "800px", "margin": "20px auto 0 auto" From 75997497f5f69b7876f214a03944b4c8eba9494d Mon Sep 17 00:00:00 2001 From: samibtorres Date: Wed, 6 May 2026 11:06:15 +0200 Subject: [PATCH 18/18] Corrected legend text styles --- eu_fact_force/dash-app/pages/pgp.py | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/eu_fact_force/dash-app/pages/pgp.py b/eu_fact_force/dash-app/pages/pgp.py index 541986d..ccaedbc 100644 --- a/eu_fact_force/dash-app/pages/pgp.py +++ b/eu_fact_force/dash-app/pages/pgp.py @@ -28,12 +28,13 @@ def make_layout(): "This dashboard visualizes social media conversations surrounding vaccines, utilizing data provided by " "The Public Good Projects (PGP) via the Quid API. It tracks posting dynamics, linguistic distribution, " "and thematic patterns based on specific query logic.", + className="text-center mb-5", style={ - "fontFamily": "system-ui, -apple-system, sans-serif", - "textAlign": "center", - "fontSize": "14px", - "fontStyle": "italic", - "marginBottom": "8px", + "fontSize": "17px", + "color": EUPHAColors.text_main, + "lineHeight": "1.6", + "maxWidth": "800px", + "margin": "20px auto 0 auto" }, ), html.P([ @@ -45,17 +46,17 @@ def make_layout(): "export. It will soon be fully integrated into the platform through an automated API workflow for daily " "updates." ], - className="text-center mb-5", style={ - "fontSize": "17px", - "color": EUPHAColors.text_main, - "lineHeight": "1.6", - "maxWidth": "800px", - "margin": "20px auto 0 auto" + "textAlign": "center", + "fontSize": "14px", + "fontStyle": "italic", + "marginBottom": "8px", + } ), ], style={ + "fontFamily": "system-ui, -apple-system, sans-serif", "borderRadius": "16px", "padding": "20px", "backgroundColor": EUPHAColors.white,