diff options
| -rw-r--r-- | client/applet.js | 6 | ||||
| -rw-r--r-- | client/chart/constants.js | 33 | ||||
| -rw-r--r-- | client/chart/countriesByYear.chart.js (renamed from client/chart/chart.container.js) | 38 | ||||
| -rw-r--r-- | client/chart/index.js | 6 | ||||
| -rw-r--r-- | client/chart/pie.charts.js | 167 | ||||
| -rw-r--r-- | site/content/pages/test/index.md | 1 | ||||
| -rw-r--r-- | site/content/pages/test/pie_chart.md | 19 | ||||
| -rw-r--r-- | site/public/test/index.html | 1 | ||||
| -rw-r--r-- | site/public/test/pie_chart/index.html | 51 |
9 files changed, 283 insertions, 39 deletions
diff --git a/client/applet.js b/client/applet.js index cd73925c..21e1e4fa 100644 --- a/client/applet.js +++ b/client/applet.js @@ -4,7 +4,7 @@ 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 { Container as ChartContainer } from './chart' +import { CountriesByYear, PieCharts } from './chart' export default class Applet extends Component { render() { @@ -19,7 +19,9 @@ export default class Applet extends Component { case 'dataset_list': return <DatasetListContainer {...this.props} /> case 'chart': - return <ChartContainer {...this.props} /> + return <CountriesByYear {...this.props} /> + case 'piechart': + return <PieCharts {...this.props} /> default: return <pre style={{ color: '#0f0' }}>{'Megapixels'}</pre> } diff --git a/client/chart/constants.js b/client/chart/constants.js new file mode 100644 index 00000000..295b9232 --- /dev/null +++ b/client/chart/constants.js @@ -0,0 +1,33 @@ +export const rainbow = [ + '#9e0142', + '#d53e4f', + '#f46d43', + '#fdae61', + '#fee08b', + '#ffffbf', + '#e6f598', + '#abdda4', + '#66c2a5', + '#3288bd', + '#5e4fa2', + // '#888888', +] + +export const colorblindSafeRainbow = [ + '#a50026', + '#d73027', + '#f46d43', + '#fdae61', + '#fee090', + '#ffffbf', + '#e0f3f8', + '#abd9e9', + '#74add1', + '#4575b4', + '#313695', + // '#888888', +] + +export const topCountryCount = 10 + +export const otherCountriesLabel = 'Other Countries' diff --git a/client/chart/chart.container.js b/client/chart/countriesByYear.chart.js index aa80100e..c846fd0f 100644 --- a/client/chart/chart.container.js +++ b/client/chart/countriesByYear.chart.js @@ -6,41 +6,9 @@ import C3Chart from 'react-c3js' import 'c3/c3.css' import './chart.css' -const rainbow = [ - '#9e0142', - '#d53e4f', - '#f46d43', - '#fdae61', - '#fee08b', - '#ffffbf', - '#e6f598', - '#abdda4', - '#66c2a5', - '#3288bd', - '#5e4fa2', - // '#888888', -] +import { rainbow, colorblindSafeRainbow, topCountryCount, otherCountriesLabel } from './constants' -const colorblindSafeRainbow = [ - '#a50026', - '#d73027', - '#f46d43', - '#fdae61', - '#fee090', - '#ffffbf', - '#e0f3f8', - '#abd9e9', - '#74add1', - '#4575b4', - '#313695', - // '#888888', -] - -const topCountryCount = 10 - -const otherCountriesLabel = 'Other Countries' - -class ChartContainer extends Component { +class CountriesByYearChart extends Component { render() { const { payload } = this.props const { paper, citations } = payload.data @@ -196,4 +164,4 @@ class ChartContainer extends Component { } } -export default ChartContainer +export default CountriesByYearChart diff --git a/client/chart/index.js b/client/chart/index.js index e9d3322d..27650020 100644 --- a/client/chart/index.js +++ b/client/chart/index.js @@ -1,5 +1,7 @@ -import Container from './chart.container' +import CountriesByYear from './countriesByYear.chart' +import PieCharts from './pie.charts' export { - Container, + CountriesByYear, + PieCharts, } diff --git a/client/chart/pie.charts.js b/client/chart/pie.charts.js new file mode 100644 index 00000000..998d6758 --- /dev/null +++ b/client/chart/pie.charts.js @@ -0,0 +1,167 @@ +import React, { Component } from 'react' +import { bindActionCreators } from 'redux' +import { connect } from 'react-redux' +import { toArray } from '../util' +import C3Chart from 'react-c3js' +import 'c3/c3.css' +import './chart.css' + +import { rainbow, colorblindSafeRainbow, topCountryCount, otherCountriesLabel } from './constants' + +class PieCharts extends Component { + render() { + const { payload } = this.props + const { paper, citations } = payload.data + if (!citations.length) return null + const years = {} + const countries = {} + citations.forEach(citation => { + let { year, addresses } = citation + if (!year || !parseInt(year)) return + year = parseInt(year) + years[year] = years[year] || {} + addresses.forEach(address => { + const { country } = address + if (!country) return + if (!(country in countries)) { + countries[country] = 1 + } else { + countries[country] += 1 + } + if (country in years[year]) { + years[year][country] += 1 + } else { + years[year][country] = 1 + countries[country] = true + } + }) + }) + let yearList = Object.keys(years).map(year => parseInt(year)).sort() + for (let i = yearList[0]; i < yearList[-1]; i++) { + if (!(i in years)) { + years[i] = {} + } + } + yearList = Object.keys(years).map(year => parseInt(year)).sort() + + Object.keys(countries).forEach(country => { + yearList.forEach(year => { + if (!(country in years[year])) years[year][country] = 0 + }) + }) + + // figure out the top N countries in the dataset + const countriesByCount = Object.keys(countries).sort((a,b) => countries[b] - countries[a]) + // console.log(countriesByCount) + let topCountries = countriesByCount.slice(0, topCountryCount) + let otherCountries = countriesByCount.slice(topCountryCount) + + let citationCountsByYear = + [ ['x'].concat(yearList.map(year => String(year))) ] + .concat( + topCountries + .map(country => + [country] + .concat( + yearList + .map(year => years[year][country]) + ) + ) + ) + + citationCountsByYear.push( + [otherCountriesLabel].concat( + yearList.map(year => otherCountries.reduce((a,b) => (a + years[year][b]), 0)) + ) + ) + + let maxCitationsInAYear = 0 + let currentSum = 0 + // for each year... + for (let j = 1; j < citationCountsByYear[0].length; j++) { + // for each country + currentSum = 0 + for (let i = 1; i < citationCountsByYear.length; i++) { + currentSum += citationCountsByYear[i][j] + } + maxCitationsInAYear = Math.max(currentSum, maxCitationsInAYear) + } + + let ticks = [] + for (let i = 0; i < maxCitationsInAYear; i += 50) { + ticks.push(i) + } + if (ticks[ticks.length - 1] < maxCitationsInAYear) { + ticks.push('') + } + + const colorPattern = rainbow + + return ( + <div className='chart'> + <C3Chart + data={{ + x: 'x', + columns: citationCountsByYear, + type: 'bar', + groups: [ topCountries.concat(otherCountriesLabel) ], + }} + axis={{ + x: { + type: 'category' // this needed to load string x value + }, + y: { + show: false, + }, + y2: { + tick: { + values: ticks, + }, + default: [ 0, maxCitationsInAYear * 286 / 261 ], + show: true, + } + }} + legend={{ + position: 'right' + }} + color={{ + pattern: colorPattern + }} + tooltip={{ + contents: function (d, defaultTitleFormat, defaultValueFormat, color) { + const countriesByYearLookup = years[yearList[d[0].x]] + let countriesByYear = Object.keys(countriesByYearLookup).map(country => [country, countriesByYearLookup[country]]).sort((a,b) => b[1] - a[1]) + let topCountriesForThisYear = countriesByYear.slice(0, topCountryCount) + let bottomTotal = countriesByYear.slice(topCountryCount).reduce((a,b) => (a + b[1]), 0) + // console.log(topCountriesForThisYear) + topCountriesForThisYear.push([otherCountriesLabel, bottomTotal]) + const tableRows = topCountriesForThisYear.filter(pair => !!pair[1]).map(([country, total]) => { + let colorIndex = topCountries.indexOf(country) + if (colorIndex < 0) colorIndex = colorPattern.length - 1 + const color = colorPattern[ colorIndex ] + return [ + "<tr>", + "<td>", + "<span style='background-color:" + color + "' class='swatch'></span>", + country, + "</td>", + "<td>", + total, + "</td>", + "</tr>", + ].join('') + }) + return [ + "<table class='c3-tooltip'>", + ...tableRows, + "</table>", + ].join('') + } + }} + /> + </div> + ) + } +} + +export default PieCharts diff --git a/site/content/pages/test/index.md b/site/content/pages/test/index.md index 7d77c3d4..da9db049 100644 --- a/site/content/pages/test/index.md +++ b/site/content/pages/test/index.md @@ -20,4 +20,5 @@ authors: Megapixels - [Face search](/test/face_search/index.html) - [Name search](/test/name_search/index.html) - [Chart](/test/chart/index.html) +- [Pie Chart](/test/pie_chart/index.html) - [Modal image gallery](/test/gallery/index.html) diff --git a/site/content/pages/test/pie_chart.md b/site/content/pages/test/pie_chart.md new file mode 100644 index 00000000..f3d0250a --- /dev/null +++ b/site/content/pages/test/pie_chart.md @@ -0,0 +1,19 @@ +------------ + +status: published +title: Pie Chart +desc: Pie Chart Test +slug: pie-chart-test +published: 2018-12-04 +updated: 2018-12-04 +authors: Megapixels + +------------ + +# Pie Chart + +### [← Back to test index](/test/) + +``` +piechart lfw +``` diff --git a/site/public/test/index.html b/site/public/test/index.html index 8a4ec3fb..0fc839d0 100644 --- a/site/public/test/index.html +++ b/site/public/test/index.html @@ -36,6 +36,7 @@ <li><a href="/test/face_search/index.html">Face search</a></li> <li><a href="/test/name_search/index.html">Name search</a></li> <li><a href="/test/chart/index.html">Chart</a></li> +<li><a href="/test/pie_chart/index.html">Pie Chart</a></li> <li><a href="/test/gallery/index.html">Modal image gallery</a></li> </ul> </section> diff --git a/site/public/test/pie_chart/index.html b/site/public/test/pie_chart/index.html new file mode 100644 index 00000000..2ef15a9c --- /dev/null +++ b/site/public/test/pie_chart/index.html @@ -0,0 +1,51 @@ +<!doctype html> +<html> +<head> + <title>MegaPixels</title> + <meta charset="utf-8" /> + <meta name="author" content="Megapixels" /> + <meta name="description" content="Pie Chart Test" /> + <meta name="referrer" content="no-referrer" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" /> + <link rel='stylesheet' href='/assets/css/fonts.css' /> + <link rel='stylesheet' href='/assets/css/tabulator.css' /> + <link rel='stylesheet' href='/assets/css/css.css' /> + <link rel='stylesheet' href='/assets/css/leaflet.css' /> + <link rel='stylesheet' href='/assets/css/applets.css' /> +</head> +<body> + <header> + <a class='slogan' href="/"> + <div class='logo'></div> + <div class='site_name'>MegaPixels</div> + </a> + <div class='links'> + <a href="/datasets/">Datasets</a> + <a href="/about/">About</a> + </div> + </header> + <div class="content content-"> + + <section><h1>Pie Chart</h1> +<h3><a href="/test/">← Back to test index</a></h3> +</section><section class='applet_container'><div class='applet' data-payload='{"command": "piechart lfw"}'></div></section> + + </div> + <footer> + <div> + <a href="/">MegaPixels.cc</a> + <a href="/about/disclaimer/">Disclaimer</a> + <a href="/about/terms/">Terms of Use</a> + <a href="/about/privacy/">Privacy</a> + <a href="/about/">About</a> + <a href="/about/team/">Team</a> + </div> + <div> + MegaPixels ©2017-19 Adam R. Harvey / + <a href="https://ahprojects.com">ahprojects.com</a> + </div> + </footer> +</body> + +<script src="/assets/js/dist/index.js"></script> +</html>
\ No newline at end of file |
