diff options
Diffstat (limited to 'client')
| -rw-r--r-- | client/applet.js | 7 | ||||
| -rw-r--r-- | client/chart/constants.js | 4 | ||||
| -rw-r--r-- | client/chart/countriesByYear.chart.js | 1 | ||||
| -rw-r--r-- | client/chart/pie.charts.js | 5 | ||||
| -rw-r--r-- | client/index.js | 8 | ||||
| -rw-r--r-- | client/map/index.js | 81 | ||||
| -rw-r--r-- | client/table/citations.table.js | 63 | ||||
| -rw-r--r-- | client/table/file.table.js | 60 | ||||
| -rw-r--r-- | client/table/index.js | 11 | ||||
| -rw-r--r-- | client/table/tabulator.css | 26 | ||||
| -rw-r--r-- | client/tables.js | 96 |
11 files changed, 231 insertions, 131 deletions
diff --git a/client/applet.js b/client/applet.js index 21e1e4fa..db95168a 100644 --- a/client/applet.js +++ b/client/applet.js @@ -4,11 +4,12 @@ import { Container as FaceSearchContainer } from './faceSearch' import { Container as FaceAnalysisContainer } from './faceAnalysis' import { Container as NameSearchContainer } from './nameSearch' import { Container as DatasetListContainer } from './datasetList' +import { CitationsTable, FileTable } from './table' import { CountriesByYear, PieCharts } from './chart' export default class Applet extends Component { render() { - // console.log(this.props) + // console.log(this.props.payload.cmd) switch (this.props.payload.cmd) { case 'face_analysis': return <FaceAnalysisContainer {...this.props} /> @@ -22,6 +23,10 @@ export default class Applet extends Component { return <CountriesByYear {...this.props} /> case 'piechart': return <PieCharts {...this.props} /> + case 'citations': + return <CitationsTable {...this.props} /> + case 'load_file': + return <FileTable {...this.props} /> default: return <pre style={{ color: '#0f0' }}>{'Megapixels'}</pre> } diff --git a/client/chart/constants.js b/client/chart/constants.js index 70375ba3..b916cbd2 100644 --- a/client/chart/constants.js +++ b/client/chart/constants.js @@ -59,6 +59,6 @@ export const institutionOrder = { export const institutionLabels = { 'edu': 'Academic', 'company': 'Commercial', - 'gov': 'Government / Military', - 'mil': 'Government / Military', + 'gov': 'Military / Government', + 'mil': 'Military / Government', }
\ No newline at end of file diff --git a/client/chart/countriesByYear.chart.js b/client/chart/countriesByYear.chart.js index 4257748c..2284f774 100644 --- a/client/chart/countriesByYear.chart.js +++ b/client/chart/countriesByYear.chart.js @@ -158,6 +158,7 @@ class CountriesByYearChart extends Component { } }} /> + <div className='caption'>{paper.name}{' dataset citations by country per year'}</div> </div> ) } diff --git a/client/chart/pie.charts.js b/client/chart/pie.charts.js index 6e579537..84e85c3a 100644 --- a/client/chart/pie.charts.js +++ b/client/chart/pie.charts.js @@ -17,6 +17,7 @@ class PieCharts extends Component { render() { const { payload } = this.props const { paper, citations } = payload.data + console.log(this.props) if (!citations.length) return null const countries = {} @@ -83,9 +84,10 @@ class PieCharts extends Component { } }} size={{ - height: 336, + height: countryRows.length < 4 ? 316 : 336, }} /> + <span className='chartCaption'>{paper.name}{' dataset citations by country'}</span> </div> <div> <C3Chart @@ -105,6 +107,7 @@ class PieCharts extends Component { height: 316, }} /> + <span className='chartCaption'>{paper.name}{' dataset citations by organization type'}</span> </div> </div> ) diff --git a/client/index.js b/client/index.js index 5c8bc880..668aebfb 100644 --- a/client/index.js +++ b/client/index.js @@ -6,7 +6,6 @@ import { Provider } from 'react-redux' import { toArray } from './util' import Applet from './applet' import { store } from './store' -import appendTable from './tables' import appendMap from './map' function appendReactApplet(el, payload) { @@ -33,7 +32,8 @@ function appendApplets(applets) { case 'citations': case 'load_file': el.parentNode.classList.add('wide') - appendTable(el, payload) + appendReactApplet(el, payload) + el.classList.add('loaded') break case 'map': el.parentNode.classList.add('wide') @@ -87,9 +87,9 @@ function runApplets() { if (dataset === 'index.html') { dataset = path.pop() } - console.log('dataset from path:', dataset) + // console.log('dataset from path:', dataset) } else { - console.log('not on a dataset page') + // console.log('not on a dataset page') return [el, payload] } } diff --git a/client/map/index.js b/client/map/index.js index b35ffddb..475ba3c6 100644 --- a/client/map/index.js +++ b/client/map/index.js @@ -37,25 +37,31 @@ const redDot = L.icon({ popupAnchor: [0, -5] // point from which the popup should open relative to the iconAnchor }) -function addMarker(map, latlng, title, addresses, year, pdf) { +function addMarker(map, latlng, citations) { const marker = L.marker(latlng, { icon: redDot }).addTo(map) - let message = [ - "<b>", title, "</b>", - ] - if (pdf && pdf.length) { - message.unshift("<a href='" + pdf[0] + "' target='_blank'>") - message.push("</a>") - } + let message = citations.map(citation => { + const { title, addresses, year, pdf, doi } = citation + let rec = [ + "<b>", title, "</b>", + ] + if (pdf && pdf.length) { + rec.unshift("<a href='" + pdf[0] + "' target='_blank'>") + rec.push("</a>") + } + else if (doi && doi.length) { + rec.unshift("<a href='" + doi[0] + "' target='_blank'>") + rec.push("</a>") + } + if (year) { + rec.push(" (" + year + ")") + } + const addressString = addresses.map(addr => addr.name).join('<br/>') + rec.push("<br>") + rec.push(addressString) + return rec.join("") + }) - const addressString = addresses.map(addr => addr.name).join('<br/>') - message = message.concat([ - "<br>", - addressString, - ]) - if (year) { - message.push(" (" + year + ")") - } - marker.bindPopup(message.join('')) + marker.bindPopup(message.join('<br><br>')) return marker } @@ -73,7 +79,7 @@ function addArc(map, src, dest, arcStyle) { export default function append(el, payload) { const { data } = payload if (!data) return - let { paper, addresses, citations } = data + let { paper, citations } = data let source = [0, 0] let map = L.map(el).setView([25, 0], 2) @@ -87,30 +93,51 @@ export default function append(el, payload) { accessToken: 'pk.eyJ1IjoiZmFuc2FsY3kiLCJhIjoiY2pvN3I1czJwMHF5NDNrbWRoMWpteHlrdCJ9.kMpM5syQUhVjKkn1iVx9fg' }).addTo(map) - if (addresses && addresses.length) { - source = [address[0].lat, address[0].lng].map(n => (parseFloat(n) || 0)) + if (paper.addresses && paper.addresses.length) { + source = [paper.addresses[0].lat, paper.addresses[0].lng].map(n => (parseFloat(n) || 0)) } else { console.error("No address found for root paper") // console.log(data) } // group papers by address + let citationsByAddress = {} citations.forEach(citation => { - console.log(citation) if (!citation.addresses) { - console.log(citation) + // console.log(citation) return } - const citationAddress = citation.addresses[0] + // console.log(citation) + citation.addresses.forEach(address => { + if (!(address.name in citationsByAddress)) { + citationsByAddress[address.name] = { address, citations: []} + } + citationsByAddress[address.name].citations.push(citation) + }) + }) + + Object.keys(citationsByAddress).map(name => { + const { citations: citationList, address: citationAddress } = citationsByAddress[name] + // console.log(name, citationsByAddress[name]) + // console.log(citation) const latlng = [citationAddress.lat, citationAddress.lng].map(n => parseFloat(n)) if (Number.isNaN(latlng[0]) || Number.isNaN(latlng[1])) return - addMarker(map, latlng, citation.title, citation.addresses, citation.year, citation.pdf) - addArc(map, source, latlng, arcStyles[citationAddress.type]) + addMarker(map, latlng, citationList) + const style = { ...arcStyles[citationAddress.type] } + let weight = Math.min(citationList.length, 5) + let opacity = 0.5 + Math.min(citationList.length / 5, 0.5) + if (citationAddress.type !== 'edu') { + weight += 1 + opacity = 1 + } + style.weight = String(weight) + style.opacity = opacity + addArc(map, source, latlng, style) }) - console.log(paper) + // console.log(paper) - const rootMarker = addMarker(map, source, paper.title, addresses, paper.year) + const rootMarker = addMarker(map, source, [paper]) rootMarker.openPopup() // a transparent div to cover the map, so normal scroll events will not be eaten by leaflet diff --git a/client/table/citations.table.js b/client/table/citations.table.js new file mode 100644 index 00000000..f65998aa --- /dev/null +++ b/client/table/citations.table.js @@ -0,0 +1,63 @@ +import React, { Component } from 'react' +import { bindActionCreators } from 'redux' +import { connect } from 'react-redux' +import { ReactTabulator } from 'react-tabulator' +import { Loader } from '../common' +import { toArray, toTuples } from '../util' + +export const citationsColumns = [ + { title: 'Title', field: 'title', sorter: 'string' }, + { title: 'Institution', field: 'institution', sorter: 'string' }, + { title: 'Country', field: 'country', sorter: 'string', width: 140 }, + { title: 'Year', field: 'year', sorter: 'number', width: 70 }, + { title: 'PDF', field: 'pdf_text', formatter: 'link', + formatterParams: { target: "_blank", urlField: 'pdf_link', }, + sorter: 'string', width: 100 }, +] + +class CitationsTable extends Component { + render() { + const { payload } = this.props + const { paper, citations } = payload.data + + if (!citations.length) return <Loader /> + + const formattedCitations = citations.map(citation => { + const pdf_link = (citation.pdf && citation.pdf.length) + ? citation.pdf[0] + : (citation.doi && citation.doi.length) + ? citation.doi[0] + : 'https://www.semanticscholar.org/paper/' + citation.id + let pdf_text + const pdf_partz = pdf_link.split('/')[2].split('.') + if (pdf_partz.length > 2 && pdf_partz[pdf_partz.length - 2].length == 2) { + pdf_text = pdf_partz.slice(-3).join('.') + } else { + pdf_text = pdf_partz.slice(-2).join('.') + } + return { + title: citation.title, + institution: citation.addresses[0].name, + country: citation.addresses[0].country, + year: citation.year, + pdf_link, pdf_text, + } + }) + + // console.log(formattedCitations) + + return ( + <ReactTabulator + columns={citationsColumns} + data={formattedCitations} + options={{ + height: 311, + layout: 'fitColumns', + placeholder: 'No Data Set', + }} + /> + ) + } +} + +export default CitationsTable diff --git a/client/table/file.table.js b/client/table/file.table.js new file mode 100644 index 00000000..92f5cf72 --- /dev/null +++ b/client/table/file.table.js @@ -0,0 +1,60 @@ +import React, { Component } from 'react' +import { bindActionCreators } from 'redux' +import { connect } from 'react-redux' +import { toArray, toTuples } from '../util' + +import { Loader } from '../common' + +import csv from 'parse-csv' + +class FileTable extends Component { + state = { + data: [] + } + + componentDidMount() { + console.log(payload.url) + fetch(payload.url, { mode: 'cors' }) + .then(r => r.text()) + .then(text => { + try { + const data = csv.toJSON(text, { headers: { included: true } }) + this.setState({ data }) + } catch (e) { + console.error("error making json:", payload.url) + console.error(e) + } + }) + } + + getColumns(payload) { + let { cmd, url, fields } = payload + return ((fields && fields.length) ? fields[0] : '').split(', ').map(field => { + switch (field) { + default: + return { title: field, field: field.toLowerCase(), sorter: 'string' } + } + }) + } + + render() { + const { payload } = this.props + const { paper, citations } = payload.data + const columns = getColumns(payload) + if (!this.state.data.length) { + return <Loader /> + } + return ( + <ReactTabulator + columns={citationsColumns} + data={this.state.data} + options={{ + height: 311, + layout: 'fitColumns', + placeholder: 'No Data Set', + }} + /> + ) + } +} +export default FileTable diff --git a/client/table/index.js b/client/table/index.js new file mode 100644 index 00000000..c741f33e --- /dev/null +++ b/client/table/index.js @@ -0,0 +1,11 @@ +import 'react-tabulator/lib/styles.css' +import 'react-tabulator/lib/css/tabulator_midnight.css' +import './tabulator.css' + +import CitationsTable from './citations.table' +import FileTable from './file.table' + +export { + CitationsTable, + FileTable, +}
\ No newline at end of file diff --git a/client/table/tabulator.css b/client/table/tabulator.css new file mode 100644 index 00000000..24005368 --- /dev/null +++ b/client/table/tabulator.css @@ -0,0 +1,26 @@ +.tabulator { + border-left: 1px solid #333; + border-bottom: 1px solid #333; +} +.tabulator-row.tabulator-row-odd { + background-color: #222; +} +.tabulator-row.tabulator-row-even { + background-color: #333; +} +.desktop .tabulator-row.tabulator-selectable:hover { + background-color: #555; +} +.tabulator-row .tabulator-cell { + border-right: 1px solid #444; + padding: 8px; +} +.tabulator .tabulator-header { + border-bottom: 0; +} +.tabulator .tabulator-header .tabulator-col { + border-right: 1px solid #444; +} +.tabulator .tabulator-tableHolder .tabulator-table { + background-color: #333; +}
\ No newline at end of file diff --git a/client/tables.js b/client/tables.js deleted file mode 100644 index 3b53b5db..00000000 --- a/client/tables.js +++ /dev/null @@ -1,96 +0,0 @@ -import Tabulator from 'tabulator-tables' -import csv from 'parse-csv' - -const datasetColumns = [ - { title: 'Title', field: 'title', sorter: 'string' }, - { title: 'Images', field: 'images', sorter: 'number' }, - { title: 'People', field: 'people', sorter: 'number' }, - { title: 'Year', field: 'year', sorter: 'number' }, - { title: 'Citations', field: 'citations', sorter: 'number' }, - { title: 'Influenced', field: 'influenced', sorter: 'number' }, - // { title: 'Origin', field: 'origin', sorter: 'string' }, -] -const citationsColumns = [ - { title: 'Title', field: 'title', sorter: 'string' }, - { title: 'Institution', field: 'institution', sorter: 'string' }, - { title: 'Country', field: 'country', sorter: 'string', width: 140 }, - { title: 'Year', field: 'year', sorter: 'number', width: 70 }, - { title: 'PDF', field: 'pdf', formatter: 'link', - formatterParams: { target: "_blank", urlField: 'pdf', }, - sorter: 'string', width: 100 }, -] - -function getColumns(payload) { - let { cmd, url, fields } = payload - if (cmd === 'citations') { - return citationsColumns - } - if (url && url.match('datasets.csv')) { - return datasetColumns - } - return ((fields && fields.length) ? fields[0] : '').split(', ').map(field => { - switch (field) { - default: - return { title: field, field: field.toLowerCase(), sorter: 'string' } - } - }) -} - -function getCitations(dataset) { - // console.log(dataset.citations) - // console.log(dataset.citations.map(d => [d.pdf, d.doi])) - return dataset.citations.map(citation => ({ - title: citation.title, - institution: citation.addresses[0].name, - country: citation.addresses[0].country, - year: citation.year, - pdf: (citation.pdf && citation.pdf.length) - ? citation.pdf[0] - : (citation.doi && citation.doi.length) - ? citation.doi[0] - : "", - })) -} - -export default function append(el, payload) { - const columns = getColumns(payload) - // console.log(columns) - const table = new Tabulator(el, { - height: '311px', - layout: 'fitColumns', - placeholder: 'No Data Set', - columns, - }) - // let path = payload.opt - // console.log(path, columns) - - if (payload.cmd === 'citations') { - let { data } = payload - if (!data) return null - const citations = getCitations(data) - // console.log(citations) - table.setData(citations) - el.classList.add('loaded') - } else { - fetch(payload.url, { mode: 'cors' }) - .then(r => r.text()) - .then(text => { - try { - // console.log(text) - const data = csv.toJSON(text, { headers: { included: true } }) - // console.log(data) - table.setData(data) - el.classList.add('loaded') - } catch (e) { - - console.error("error making json:", payload.url) - console.error(e) - // console.log(text) - } - }) - } - - // if (fields && fields.length > 1 && fields[1].indexOf('filter')) { - // const filter = fields[1].split(' ') - // } -} |
