Skip to content

Commit

Permalink
feat(graphs): new graph of publications evolution per language
Browse files Browse the repository at this point in the history
  • Loading branch information
ahonestla committed Sep 18, 2024
1 parent 787c177 commit bf11978
Show file tree
Hide file tree
Showing 8 changed files with 243 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import Axios from 'axios';
import { useCallback, useEffect, useState } from 'react';
import { useIntl } from 'react-intl';

import { ES_API_URL, HEADERS } from '../../../../../config/config';
import getFetchOptions from '../../../../../utils/chartFetchOptions';

function useGetData(observationSnap, domain) {
const intl = useIntl();
const [allData, setData] = useState({});
const [isLoading, setLoading] = useState(true);
const [isError, setError] = useState(false);

const getDataForLastObservationSnap = useCallback(
async (lastObservationSnap) => {
const query = getFetchOptions({
key: 'publicationsByYear',
domain,
parameters: [lastObservationSnap, 'lang.keyword'],
objectType: ['publications'],
});
const res = await Axios.post(ES_API_URL, query, HEADERS);
const data = res.data.aggregations.by_year.buckets;
data.sort((a, b) => a.key - b.key); // Tri pour avoir les années dans l'ordre d'affichage du graphe

const categories = Object.values(data).map((d) => d.key); // Elements d'abscisse

const dataByLang = {};
data.forEach((year) => year.by_custom.buckets.forEach((lang) => {
dataByLang[lang.key] = [
...(dataByLang?.[lang.key] ?? []),
{ year: year.key, count: lang.doc_count },
];
}));

const dataGraph = Object.entries(dataByLang).map(([key, values]) => ({
name: intl.formatMessage({ id: `app.lang.${key}` }),
data: values.map((v) => ({
name: v.year,
y: v.count,
lang: intl.formatMessage({ id: `app.lang.${key}` }),
})),
}));

const sum = (array) => array.reduce((acc, value) => acc + value, 0);
dataGraph.sort(
(a, b) => sum(b.data.map(({ y }) => y)) - sum(a.data.map(({ y }) => y)),
);

return {
categories,
dataGraph: dataGraph.slice(0, 5),
};
},
[domain, intl],
);

useEffect(() => {
async function getData() {
try {
const dataGraph = await getDataForLastObservationSnap(observationSnap);
setData(dataGraph);
} catch (e) {
// eslint-disable-next-line no-console
console.error(e);
setError(true);
} finally {
setLoading(false);
}
}
getData();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [observationSnap]);

return { allData, isError, isLoading };
}
export default useGetData;
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import Highcharts from 'highcharts';
import HCExportingData from 'highcharts/modules/export-data';
import HCExporting from 'highcharts/modules/exporting';
import HighchartsReact from 'highcharts-react-official';
import PropTypes from 'prop-types';
import React, { useEffect, useRef, useState } from 'react';
import { useIntl } from 'react-intl';

import customComments from '../../../../../utils/chartComments';
import { chartOptions } from '../../../../../utils/chartOptions';
import { domains, graphIds } from '../../../../../utils/constants';
import { getObservationLabel, withDomain } from '../../../../../utils/helpers';
import useGlobals from '../../../../../utils/Hooks/useGetGlobals';
import WrapperChart from '../../../../WrapperChart';
import GraphComments from '../../../graph-comments';
import useGetData from './get-data';

HCExporting(Highcharts);
HCExportingData(Highcharts);

const Chart = ({ domain, hasComments, hasFooter, id }) => {
const [chartComments, setChartComments] = useState('');
const chartRef = useRef();
const intl = useIntl();
const { beforeLastObservationSnap, lastObservationSnap } = useGlobals();
const { allData, isError, isLoading } = useGetData(
lastObservationSnap,
domain,
);
const { dataGraph, categories } = allData;
const dataTitle = {
publicationYear: getObservationLabel(beforeLastObservationSnap, intl),
};
const idWithDomain = withDomain(id, domain);
const optionsGraph = chartOptions[id].getOptions(
idWithDomain,
intl,
categories,
dataGraph,
dataTitle,
);

useEffect(() => {
setChartComments(customComments(allData, idWithDomain, intl));
}, [allData, idWithDomain, intl]);

return (
<WrapperChart
chartRef={chartRef}
dataTitle={dataTitle}
domain={domain}
hasComments={false}
hasFooter={hasFooter}
id={id}
isError={isError}
isLoading={isLoading || !dataGraph || !categories}
>
<HighchartsReact
highcharts={Highcharts}
id={idWithDomain}
options={optionsGraph}
ref={chartRef}
/>
{hasComments && chartComments && (
<GraphComments comments={chartComments} hasFooter={hasFooter} />
)}
</WrapperChart>
);
};

Chart.defaultProps = {
domain: '',
hasComments: true,
hasFooter: true,
id: 'publi.general.langues.chart-publications-by-year',
};
Chart.propTypes = {
domain: PropTypes.oneOf(domains),
hasComments: PropTypes.bool,
hasFooter: PropTypes.bool,
id: PropTypes.oneOf(graphIds),
};

export default Chart;
4 changes: 4 additions & 0 deletions src/pages/BaroNational/NationalPublications/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,10 @@ export default function NationalPublications() {
anchorId='general.langues-ouverture'
>
<BSOChart id='publi.general.langues-ouverture.chart-repartition-publications' />
<BSOChart
id='publi.general.langues.chart-publications-by-year'
isDisplayed={!isInProduction()}
/>
</QuestionSection>
<QuestionSection
anchorId='general.hal'
Expand Down
2 changes: 2 additions & 0 deletions src/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -732,6 +732,7 @@
"app.health-publi.general.langues-ouverture.chart-repartition-publications.title": "Open access rate by language of publications {commentsName} in health, publications from {publicationYear}",
"app.national-publi.general.langues-ouverture.chart-repartition-publications.comments": "This graph shows the open access rate of publications {commentsName} released in {publicationYear} according to their language of publication, while specifying the open access routes. The language data was extracted from PubMed metadata if available, or inferred from the title and abstract in the remaining cases. <linebreak></linebreak>In particular, we note that among publications published in {publicationYear}, there are {publicationsEnglishTotal} publications in English of which {publicationsEnglishOpen} are open and {publicationsEnglishClosed} are closed (i.e. an open access rate of {publicationsEnglishRate}%), and {publicationsFrenchTotal} publications in French of which {publicationsFrenchOpen} are open and {publicationsFrenchClosed} closed (i.e. a rate of {publicationsFrenchRate}%). French-language publications are therefore less open than English-language publications. Publications in Spanish, German and Portuguese represent smaller numbers, statistically less significant.",
"app.health-publi.general.langues-ouverture.chart-repartition-publications.comments": "This graph shows the open access rate of publications {commentsName} in health released in {publicationYear} according to their language of publication, while specifying the open access routes. The language data was extracted from PubMed metadata if available, or inferred from the title and abstract in the remaining cases. <linebreak></linebreak>In particular, we note that among publications published in {publicationYear}, there are {publicationsEnglishTotal} publications in English of which {publicationsEnglishOpen} are open and {publicationsEnglishClosed} are closed (i.e. an open access rate of {publicationsEnglishRate}%), and {publicationsFrenchTotal} publications in French of which {publicationsFrenchOpen} are open and {publicationsFrenchClosed} closed (i.e. a rate of {publicationsFrenchRate}%). French-language publications are therefore less open than English-language publications. Publications in Spanish, German and Portuguese represent smaller numbers, statistically less significant.",
"app.national-publi.general.langues.chart-publications-by-year.title": "Evolution of the number of publications {commentsName} according to their language of publication",
"app.national-publi.general.voies-ouverture.description": "Open access to scientific publications can be achieved through several routes: natively open access publication by the publisher on a dissemination platform or deposit by the author in an <glossary0>app.glossary.archive-ouverte-min</glossary0>. These two routes are not exclusive, as a publication may be hosted both on an open repository and on the publisher's publishing platform. This simultaneity, which tends to increase over time, is a factor of resilience since it makes it possible to offer editorial quality and guarantee the durability of access to French scientific publications.",
"app.health-publi.general.voies-ouverture.description": "Open access to scientific publications can be achieved through several routes: natively open access publication by the publisher on a dissemination platform or deposit by the author in an <glossary0>app.glossary.archive-ouverte-min</glossary0>. These two routes are not exclusive, as a publication may be hosted both on an open repository and on the publisher's publishing platform. This simultaneity, which tends to increase over time, is a factor of resilience since it makes it possible to offer editorial quality and guarantee the durability of access to French scientific publications.",
"app.national-publi.general.voies-ouverture.chart-evolution-taux.tooltip": "<b>Publication year {point.x}</b><br>• Open access rate<br>with hosting {series.name}:<br>{point.y:.2f}% ({point.y_abs} / {point.y_tot})<br>• Total open access rate:<br>{point.stackTotal:.2f}% ({point.y_oa} / {point.y_tot})",
Expand Down Expand Up @@ -1015,6 +1016,7 @@
"app.publi.general.genres-ouverture.chart-repartition-genres.tooltip": "<b>{point.name} published in {point.publicationDate} ({point.bsoDomain})</b><br>{point.value} in {point.oaType}<br>i.e. {point.percentage:.2f}% of the total of the publications of {point.publicationDate}",
"app.publi.general.genres-ouverture.chart-repartition-taux.tooltip": "<b>{point.x_val} ({point.bsoDomain})</b><br>• Open access rate<br>with hosting {series.name}:<br>{point.y:.2f}% ({point.y_abs} / {point.y_tot})<br>• Total open access rate: {point.stacktotal:.2f}%",
"app.publi.general.langues-ouverture.chart-repartition-publications.tooltip": "<b>{point.name} published in {point.publicationDate} ({point.bsoDomain})</b><br>{point.value} in {point.oaType}<br>that is {point.percentage:.2f}% of the total publications of {point.publicationDate}",
"app.publi.general.langues.chart-publications-by-year.tooltip": "<b>{point.lang}: {point.y} publications in {point.name}</br>",
"app.publi.navigation.go-to-page": "Go to page",
"app.publi.navigation.affiliation.dynamique": "The opening trends by type of affiliation",
"app.publi.navigation.affiliation.impact": "Impact of affiliate countries",
Expand Down
2 changes: 2 additions & 0 deletions src/translations/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -932,6 +932,7 @@
"app.health-publi.general.langues-ouverture.chart-repartition-publications.title": "Taux d'accès ouvert par langue de publications {commentsName} dans le domaine de la santé, publications de {publicationYear}",
"app.national-publi.general.langues-ouverture.chart-repartition-publications.comments": "Ce graphique montre le taux d'accès ouvert des publications {commentsName} parues en {publicationYear} en fonction de leur langue de publication, tout en précisant les voies de l'ouverture. La donnée concernant la langue a été extraite des métadonnées de PubMed si disponible, ou inférée à partir du titre et du résumé dans le reste des cas.<linebreak></linebreak>On remarque notamment que, parmi les publications parues en {publicationYear}, on dénombre {publicationsEnglishTotal} publications en anglais dont {publicationsEnglishOpen} ouvertes et {publicationsEnglishClosed} fermées (soit un taux d'accès ouvert de {publicationsEnglishRate} %), et {publicationsFrenchTotal} publications en français dont {publicationsFrenchOpen} ouvertes et {publicationsFrenchClosed} fermées (soit un taux de {publicationsFrenchRate} %). Les publications en langue française sont donc moins ouvertes que les publications en langue anglaise. Les publications en espagnol, allemand et portugais représentent de plus petits effectifs, statistiquement moins significatifs.",
"app.health-publi.general.langues-ouverture.chart-repartition-publications.comments": "Ce graphique montre le taux d'accès ouvert des publications {commentsName} en santé parues en {publicationYear} en fonction de leur langue de publication, tout en précisant les voies de l'ouverture. La donnée concernant la langue a été extraite des métadonnées de PubMed si disponible, ou inférée à partir du titre et du résumé dans le reste des cas.<linebreak></linebreak>On remarque notamment que, parmi les publications parues en {publicationYear}, on dénombre {publicationsEnglishTotal} publications en anglais dont {publicationsEnglishOpen} ouvertes et {publicationsEnglishClosed} fermées (soit un taux d'accès ouvert de {publicationsEnglishRate} %), et {publicationsFrenchTotal} publications en français dont {publicationsFrenchOpen} ouvertes et {publicationsFrenchClosed} fermées (soit un taux de {publicationsFrenchRate} %). Les publications en langue française sont donc moins ouvertes que les publications en langue anglaise. Les publications en espagnol, allemand et portugais représentent de plus petits effectifs, statistiquement moins significatifs.",
"app.national-publi.general.langues.chart-publications-by-year.title": "Évolution du nombre de publications {commentsName} par langue de publication",
"app.national-publi.general.voies-ouverture.description": "L'accès ouvert aux publications scientifiques peut se faire par plusieurs voies : la publication nativement en accès ouvert par l'éditeur sur une plateforme de publication ou le dépôt par l'auteur dans une <glossary0>app.glossary.archive-ouverte-min</glossary0>. Ces deux voies ne sont pas exclusives, une publication pouvant être à la fois hébergée sur une archive ouverte et sur la plateforme de publication de l'éditeur. Cette simultanéité, qui tend à s'accroître au cours du temps, est un facteur de résilience puisqu'elle permet à la fois d'offrir la qualité éditoriale et de garantir la pérennité de l'accès aux publications scientifiques françaises.",
"app.health-publi.general.voies-ouverture.description": "L'accès ouvert aux publications scientifiques peut se faire par plusieurs voies : la publication nativement en accès ouvert par l'éditeur sur une plateforme de publication ou le dépôt par l'auteur dans une <glossary0>app.glossary.archive-ouverte-min</glossary0>. Ces deux voies ne sont pas exclusives, une publication pouvant être à la fois hébergée sur une archive ouverte et sur la plateforme de publication de l'éditeur. Cette simultanéité, qui tend à s'accroître au cours du temps, est un facteur de résilience puisqu'elle permet à la fois d'offrir la qualité éditoriale et de garantir la pérennité de l'accès aux publications scientifiques françaises.",
"app.national-publi.general.voies-ouverture.chart-evolution-taux.tooltip": "<b>Année de publication {point.x}</b><br>• Taux d'accès ouvert<br>avec hébergement {series.name} :<br>{point.y:.2f} % ({point.y_abs} / {point.y_tot})<br>• Taux d'accès ouvert total :<br>{point.stackTotal:.2f} % ({point.y_oa} / {point.y_tot})",
Expand Down Expand Up @@ -1195,6 +1196,7 @@
"app.publi.general.genres-ouverture.chart-repartition-genres.tooltip": "<b>{point.name} publiés en {point.publicationDate} ({point.bsoDomain})</b><br>{point.value} en {point.oaType}<br>soit {point.percentage:.2f} % du total des publications de {point.publicationDate}",
"app.publi.general.genres-ouverture.chart-repartition-taux.tooltip": "<b>{point.x_val} ({point.bsoDomain})</b><br>• Taux d'accès ouvert<br>avec hébergement {series.name} :<br>{point.y:.2f} % ({point.y_abs} / {point.y_tot})<br>• Taux d'accès ouvert total :<br>{point.stackTotal:.2f} % ({point.y_oa} / {point.y_tot})",
"app.publi.general.langues-ouverture.chart-repartition-publications.tooltip": "<b>{point.name} publiés en {point.publicationDate} ({point.bsoDomain})</b><br>{point.value} en {point.oaType}<br>soit {point.percentage:.2f} % du total des publications de {point.publicationDate}",
"app.publi.general.langues.chart-publications-by-year.tooltip": "<b>{point.lang}: {point.y} publications en {point.name}</b>",
"app.publi.navigation.go-to-page": "Aller à la page",
"app.publi.navigation.affiliation.dynamique": "La dynamique d'ouverture par type d'affiliation",
"app.publi.navigation.affiliation.impact": "Impact des pays d'affiliation",
Expand Down
4 changes: 4 additions & 0 deletions src/utils/chartComponents.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ const ChartRepartitionTauxFinancement = lazy(() => import(
const ChartLanguesOuverture = lazy(() => import(
'../components/Charts/publications/general/langues-ouverture/langues-ouverture'
));
const ChartLanguesByYear = lazy(() => import(
'../components/Charts/publications/general/langues-evolution/langues-by-year'
));
const ChartRepartitionPublications = lazy(() => import(
'../components/Charts/publications/general/voies-ouverture/chart-repartition-publications'
));
Expand Down Expand Up @@ -336,6 +339,7 @@ const chartComponents = {
ChartRepartitionPublications,
'publi.general.langues-ouverture.chart-repartition-publications':
ChartLanguesOuverture,
'publi.general.langues.chart-publications-by-year': ChartLanguesByYear,
'publi.general.impact-financement.chart-taux-ouverture':
ChartTauxOuvertureFinancement,
'publi.general.impact-financement.chart-business-model':
Expand Down
38 changes: 38 additions & 0 deletions src/utils/chartFetchOptions.js
Original file line number Diff line number Diff line change
Expand Up @@ -2217,6 +2217,44 @@ export default function getFetchOptions({
},
},
}),
publicationsByYear: ([
lastObservationSnap,
customField,
minPublicationDate = 2013,
]) => ({
size: 0,
query: {
bool: {
filter: [
{
range: {
year: {
gte: minPublicationDate,
lte: getPublicationYearFromObservationSnap(
lastObservationSnap,
),
},
},
},
],
},
},
aggs: {
by_year: {
terms: {
field: 'year',
size: 15,
},
aggs: {
by_custom: {
terms: {
field: customField,
},
},
},
},
},
}),
retractionsByYear: ([lastObservationSnap, minPublicationDate = 2013]) => ({
size: 0,
query: {
Expand Down
32 changes: 32 additions & 0 deletions src/utils/chartOptions.js
Original file line number Diff line number Diff line change
Expand Up @@ -963,6 +963,38 @@ export const chartOptions = {
return options;
},
},
'publi.general.langues.chart-publications-by-year': {
getOptions: (id, intl, categories, data, dataTitle) => {
const options = getGraphOptions({ id, intl, dataTitle });
options.chart.type = 'spline';
options.xAxis = {
categories,
title: { text: intl.formatMessage({ id: 'app.publication-year' }) },
};
options.yAxis = {
type: 'logarithmic',
title: {
text: intl.formatMessage({ id: 'app.publi.nb-publications' }),
},
};
options.legend.title.text = intl.formatMessage({
id: 'app.publication-lang',
});
options.tooltip.pointFormat = intl.formatMessage({
id: 'app.publi.general.langues.chart-publications-by-year.tooltip',
});
options.plotOptions = {
spline: {
dataLabels: {
enabled: false,
},
},
};
options.series = data;

return options;
},
},
'publi.general.impact-financement.chart-taux-ouverture': {
getOptions: (id, intl, categories, data, agency) => {
const options = getGraphOptions({ id, intl });
Expand Down

1 comment on commit bf11978

@annelhote
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #313

Please sign in to comment.