From 85d044df094cf72285993765eb15cbd045d63e51 Mon Sep 17 00:00:00 2001 From: esikkala <esko.ikkala@aalto.fi> Date: Mon, 4 Oct 2021 18:48:06 +0300 Subject: [PATCH] Prepare data handling for BarChartRace --- .../components/facet_results/BarChartRace.js | 109 ++++++++++-------- .../perspectives/sampo/Perspective1.js | 8 +- src/client/reducers/sampo/perspective1.js | 1 + src/server/sparql/Mappers.js | 29 ++++- src/server/sparql/SparqlApi.js | 4 +- .../sparql/sampo/BackendSearchConfig.js | 14 ++- .../SparqlQueriesPerspective1.js | 16 ++- 7 files changed, 129 insertions(+), 52 deletions(-) diff --git a/src/client/components/facet_results/BarChartRace.js b/src/client/components/facet_results/BarChartRace.js index 59f81767..15ff47aa 100644 --- a/src/client/components/facet_results/BarChartRace.js +++ b/src/client/components/facet_results/BarChartRace.js @@ -380,26 +380,46 @@ const allData = { const stepDuration = 2000 -let year = 2002 +let year = 1100 class BarChartRace extends React.Component { componentDidMount = () => { + this.props.fetchData({ + resultClass: this.props.resultClass, + facetClass: this.props.facetClass + }) + this.initChart() + } + + componentDidUpdate = prevProps => { + if (prevProps.resultUpdateID !== this.props.resultUpdateID) { + this.playAnimation() + } + } + + componentWillUnmount () { + if (this.chart) { + this.chart.dispose() + } + } + + initChart = () => { // Create root element // https://www.amcharts.com/docs/v5/getting-started/#Root_element const root = am5.Root.new('chartdiv') - root.numberFormatter.setAll({ - numberFormat: '#a', + // root.numberFormatter.setAll({ + // numberFormat: '#a', - // Group only into M (millions), and B (billions) - bigNumberPrefixes: [ - { number: 1e6, suffix: 'M' }, - { number: 1e9, suffix: 'B' } - ], + // // Group only into M (millions), and B (billions) + // bigNumberPrefixes: [ + // { number: 1e6, suffix: 'M' }, + // { number: 1e9, suffix: 'B' } + // ], - // Do not use small number prefixes at all - smallNumberPrefixes: [] - }) + // // Do not use small number prefixes at all + // smallNumberPrefixes: [] + // }) // Set themes // https://www.amcharts.com/docs/v5/concepts/themes/ @@ -479,7 +499,7 @@ class BarChartRace extends React.Component { }) this.label = chart.plotContainer.children.push(am5.Label.new(root, { - text: '2002', + text: '10', fontSize: '8em', opacity: 0.2, x: am5.p100, @@ -488,40 +508,12 @@ class BarChartRace extends React.Component { centerX: am5.p100 })) - // update data with values each 1.5 sec - const interval = setInterval(() => { - year++ - - if (year > 2018) { - clearInterval(interval) - clearInterval(this.sortInterval) - } - - this.updateData() - }, stepDuration) - - this.setInitialData() - setTimeout(() => { - year++ - this.updateData() - }, 50) - - // Make stuff animate on load - // https://www.amcharts.com/docs/v5/concepts/animations/ - this.series.appear(1000) - chart.appear(1000, 100) - this.chart = chart } - componentWillUnmount () { - if (this.chart) { - this.chart.dispose() - } - } - setInitialData = () => { - const d = allData[year] + // const d = allData[year] + const d = this.props.results[year] for (const n in d) { this.series.data.push({ network: n, value: d[n] }) @@ -531,13 +523,13 @@ class BarChartRace extends React.Component { updateData = () => { let itemsWithNonZero = 0 - - if (allData[year]) { + // if (allData[year]) { + if (this.props.results[year]) { this.label.set('text', year.toString()) am5.array.each(this.series.dataItems, dataItem => { const category = dataItem.get('categoryY') - const value = allData[year][category] + const value = this.props.results[year][category] if (value > 0) { itemsWithNonZero++ @@ -561,6 +553,33 @@ class BarChartRace extends React.Component { } } + playAnimation = () => { + // update data with values each 1.5 sec + const interval = setInterval(() => { + // year++ + year += 10 + + if (year > 2018) { + clearInterval(interval) + clearInterval(this.sortInterval) + } + + this.updateData() + }, stepDuration) + + this.setInitialData() + setTimeout(() => { + // year++ + year += 10 + this.updateData() + }, 50) + + // Make stuff animate on load + // https://www.amcharts.com/docs/v5/concepts/animations/ + this.series.appear(1000) + this.chart.appear(1000, 100) + } + // Get series item by category getSeriesItem = category => { for (let i = 0; i < this.series.dataItems.length; i++) { diff --git a/src/client/components/perspectives/sampo/Perspective1.js b/src/client/components/perspectives/sampo/Perspective1.js index a46d024e..62116052 100644 --- a/src/client/components/perspectives/sampo/Perspective1.js +++ b/src/client/components/perspectives/sampo/Perspective1.js @@ -265,7 +265,13 @@ const Perspective1 = props => { <Route path={`${rootUrl}/${perspective.id}/faceted-search/bar_chart_race`} render={() => - <BarChartRace />} + <BarChartRace + fetchData={props.fetchResults} + resultClass='productionsByDecadeAndCountry' + facetClass='perspective1' + resultUpdateID={props.perspectiveState.resultUpdateID} + results={props.perspectiveState.results} + />} /> <Route path={`${rootUrl}/${perspective.id}/faceted-search/network`} diff --git a/src/client/reducers/sampo/perspective1.js b/src/client/reducers/sampo/perspective1.js index 6425548a..48b3ca7d 100644 --- a/src/client/reducers/sampo/perspective1.js +++ b/src/client/reducers/sampo/perspective1.js @@ -286,6 +286,7 @@ const resultClasses = new Set([ 'placesMsMigrations', 'placesMsMigrationsDialog', 'productionTimespanLineChart', + 'productionsByDecadeAndCountry', 'eventLineChart', 'manuscriptInstancePageNetwork', 'manuscriptFacetResultsNetwork', diff --git a/src/server/sparql/Mappers.js b/src/server/sparql/Mappers.js index 6e5a9426..96c6ab02 100644 --- a/src/server/sparql/Mappers.js +++ b/src/server/sparql/Mappers.js @@ -129,7 +129,7 @@ export const mapMultipleLineChart = ({ sparqlBindings, config }) => { if (config && config.fillEmptyValues) { // fill the missing years with zeroes const valmax = Math.max(...category) - for (var i = Math.min(...category); i <= valmax; i++) { + for (let i = Math.min(...category); i <= valmax; i++) { for (const p in res) { if (p !== 'category') { res[p][i] = 0 @@ -149,7 +149,7 @@ export const mapMultipleLineChart = ({ sparqlBindings, config }) => { // sort by year and remove empty sequence at start and end for (const p in res) { - var arr = Object.entries(res[p]) + const arr = Object.entries(res[p]) .map(p => [parseFloat(p[0]), p[1]]) .sort((a, b) => ((a[0] < b[0]) ? -1 : ((a[0] > b[0]) ? 1 : 0))) res[p] = trimResult(arr) @@ -242,3 +242,28 @@ const recursiveSortAndSelectChildren = nodes => { }) return nodes } + +export const toBarChartRaceFormat = ({ data }) => { + const object = data.reduce((obj, item) => { + if (Array.isArray(item.productionPlaceCountry)) { + const countries = item.productionPlaceCountry.reduce((obj, item) => { + return { + ...obj, + [item.id]: parseInt(item.manuscriptCount) + } + }, {}) + return { + ...obj, + [item.id]: countries + } + } else { + return { + ...obj, + [item.id]: { + [item.productionPlaceCountry.id]: parseInt(item.productionPlaceCountry.manuscriptCount) + } + } + } + }, {}) + return object +} diff --git a/src/server/sparql/SparqlApi.js b/src/server/sparql/SparqlApi.js index d4a0aec9..af8ff875 100644 --- a/src/server/sparql/SparqlApi.js +++ b/src/server/sparql/SparqlApi.js @@ -33,11 +33,11 @@ export const runSelectQuery = async ({ if (resultMapper) { } - const mappedResults = resultMapperConfig + let mappedResults = resultMapperConfig ? resultMapper({ sparqlBindings: response.data.results.bindings, config: resultMapperConfig }) : resultMapper(response.data.results.bindings) if (postprocess) { - postprocess.func({ data: mappedResults, config: postprocess.config }) + mappedResults = postprocess.func({ data: mappedResults, config: postprocess.config }) } return { data: mappedResults, diff --git a/src/server/sparql/sampo/BackendSearchConfig.js b/src/server/sparql/sampo/BackendSearchConfig.js index b83863a7..3d1bb319 100644 --- a/src/server/sparql/sampo/BackendSearchConfig.js +++ b/src/server/sparql/sampo/BackendSearchConfig.js @@ -13,6 +13,7 @@ import { expressionProperties, collectionProperties, productionsByDecadeQuery, + productionsByDecadeAndCountryQuery, eventsByDecadeQuery, manuscriptInstancePageNetworkLinksQuery, manuscriptFacetResultsNetworkLinksQuery, @@ -60,7 +61,8 @@ import { mapPlaces, mapLineChart, mapMultipleLineChart, - linearScale + linearScale, + toBarChartRaceFormat } from '../Mappers' export const backendSearchConfig = { @@ -186,6 +188,16 @@ export const backendSearchConfig = { fillEmptyValues: false } }, + productionsByDecadeAndCountry: { + perspectiveID: 'perspective1', + q: productionsByDecadeAndCountryQuery, + filterTarget: 'manuscript', + resultMapper: makeObjectList, + postprocess: { + func: toBarChartRaceFormat, + config: null + } + }, eventLineChart: { perspectiveID: 'perspective1', q: eventsByDecadeQuery, diff --git a/src/server/sparql/sampo/sparql_queries/SparqlQueriesPerspective1.js b/src/server/sparql/sampo/sparql_queries/SparqlQueriesPerspective1.js index b6ae656a..e6fd9310 100644 --- a/src/server/sparql/sampo/sparql_queries/SparqlQueriesPerspective1.js +++ b/src/server/sparql/sampo/sparql_queries/SparqlQueriesPerspective1.js @@ -528,12 +528,26 @@ export const migrationsDialogQuery = ` export const productionsByDecadeQuery = ` SELECT ?category (COUNT (DISTINCT ?instance) as ?count) WHERE { - <FILTER> + ?instance ^crm:P108_has_produced/crm:P4_has_time-span/mmm-schema:decade ?category . } GROUP BY ?category ORDER BY ?category ` + +export const productionsByDecadeAndCountryQuery = ` + SELECT ?id ?productionPlaceCountry__id ?productionPlaceCountry__prefLabel (count(?manuscript) as ?productionPlaceCountry__manuscriptCount) WHERE { + <FILTER> + [] crm:P108_has_produced ?manuscript ; + crm:P7_took_place_at/gvp:broaderPreferred* ?productionPlaceCountry__id ; + crm:P4_has_time-span/mmm-schema:decade ?id . + ?productionPlaceCountry__id gvp:placeTypePreferred "nations" ; + skos:prefLabel ?productionPlaceCountry__prefLabel . + } + GROUP BY ?id ?productionPlaceCountry__id ?productionPlaceCountry__prefLabel + # ORDER BY ?id +` + export const eventsByDecadeQuery = ` SELECT DISTINCT ?category (COUNT(?production) AS ?productionCount) -- GitLab