Skip to content
This repository has been archived by the owner on Jul 19, 2022. It is now read-only.

Commit

Permalink
feat(number of libraries): add pie char for number of libraries used
Browse files Browse the repository at this point in the history
  • Loading branch information
Raphaël Benitte committed Dec 3, 2017
1 parent c19a10f commit c0fa423
Show file tree
Hide file tree
Showing 32 changed files with 561 additions and 132 deletions.
61 changes: 47 additions & 14 deletions cli/lib/collector/reporter.js
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ exports.experienceByUsers = async (
*/
exports.distributionByNumberOfToolsUsed = async tools => {
const totalScript = `
def fields = ['${tools.join('\', \'')}'];
def fields = ['${tools.join("', '")}'];
def total = 0; for (int i = 0; i < fields.length; i++) {
if(doc[fields[i]][0] == "I've USED it before, and WOULD use it again") {
Expand All @@ -240,24 +240,27 @@ exports.distributionByNumberOfToolsUsed = async tools => {
index: config.get('elastic.index'),
size: 0,
body: {
query: {match_all: {}},
aggs: {
query: { match_all: {} },
aggs: {
by_count: {
terms: {
script: {
lang: 'painless',
source: totalScript
}
}
}
}
}
source: totalScript,
},
},
},
},
},
})

return sortBy(result.aggregations.by_count.buckets.map(bucket => ({
...bucket,
key: Number(bucket.key),
})), 'key')
return sortBy(
result.aggregations.by_count.buckets.map(bucket => ({
...bucket,
key: Number(bucket.key),
})),
'key'
)
}

/**
Expand Down Expand Up @@ -358,7 +361,9 @@ exports.frontend = async () => {
const experienceByUsers = await exports.experienceByUsers(reportConfig.frontend.keys)
const others = await elastic.termsAgg(reportConfig.frontend.freeform, OTHERS_AGG_SIZE)
const countries = await exports.distributionByCountry(reportConfig.frontend.keys)
const numberOfToolsUsed = await exports.distributionByNumberOfToolsUsed(reportConfig.frontend.keys)
const numberOfToolsUsed = await exports.distributionByNumberOfToolsUsed(
reportConfig.frontend.keys
)

return {
keys: reportConfig.frontend.keys,
Expand All @@ -374,12 +379,16 @@ exports.flavor = async () => {
const experience = await elastic.termsAggs(reportConfig.flavors.keys)
const experienceByUsers = await exports.experienceByUsers(reportConfig.flavors.keys)
const countries = await exports.distributionByCountry(reportConfig.flavors.keys)
const numberOfToolsUsed = await exports.distributionByNumberOfToolsUsed(
reportConfig.flavors.keys
)

return {
keys: reportConfig.flavors.keys,
experience: dto.aggregations(experience.aggregations),
experienceByUsers,
countries,
numberOfToolsUsed,
}
}

Expand All @@ -388,13 +397,17 @@ exports.state = async () => {
const experienceByUsers = await exports.experienceByUsers(reportConfig.stateManagement.keys)
const others = await elastic.termsAgg(reportConfig.stateManagement.freeform, OTHERS_AGG_SIZE)
const countries = await exports.distributionByCountry(reportConfig.stateManagement.keys)
const numberOfToolsUsed = await exports.distributionByNumberOfToolsUsed(
reportConfig.stateManagement.keys
)

return {
keys: reportConfig.stateManagement.keys,
experience: dto.aggregations(experience.aggregations),
experienceByUsers,
countries,
others: others.aggregations[reportConfig.stateManagement.freeform],
numberOfToolsUsed,
}
}

Expand All @@ -403,13 +416,17 @@ exports.style = async () => {
const experienceByUsers = await exports.experienceByUsers(reportConfig.styleManagement.keys)
const others = await elastic.termsAgg(reportConfig.styleManagement.freeform, OTHERS_AGG_SIZE)
const countries = await exports.distributionByCountry(reportConfig.styleManagement.keys)
const numberOfToolsUsed = await exports.distributionByNumberOfToolsUsed(
reportConfig.styleManagement.keys
)

return {
keys: reportConfig.styleManagement.keys,
experience: dto.aggregations(experience.aggregations),
experienceByUsers,
countries,
others: others.aggregations[reportConfig.styleManagement.freeform],
numberOfToolsUsed,
}
}

Expand All @@ -418,13 +435,17 @@ exports.backend = async () => {
const experienceByUsers = await exports.experienceByUsers(reportConfig.backend.keys)
const others = await elastic.termsAgg(reportConfig.backend.freeform, OTHERS_AGG_SIZE)
const countries = await exports.distributionByCountry(reportConfig.backend.keys)
const numberOfToolsUsed = await exports.distributionByNumberOfToolsUsed(
reportConfig.backend.keys
)

return {
keys: reportConfig.backend.keys,
experience: dto.aggregations(experience.aggregations),
experienceByUsers,
countries,
others: others.aggregations[reportConfig.backend.freeform],
numberOfToolsUsed,
}
}

Expand All @@ -433,13 +454,17 @@ exports.testing = async () => {
const experienceByUsers = await exports.experienceByUsers(reportConfig.testing.keys)
const others = await elastic.termsAgg(reportConfig.testing.freeform, OTHERS_AGG_SIZE)
const countries = await exports.distributionByCountry(reportConfig.testing.keys)
const numberOfToolsUsed = await exports.distributionByNumberOfToolsUsed(
reportConfig.testing.keys
)

return {
keys: reportConfig.testing.keys,
experience: dto.aggregations(experience.aggregations),
experienceByUsers,
countries,
others: others.aggregations[reportConfig.testing.freeform],
numberOfToolsUsed,
}
}

Expand All @@ -448,13 +473,17 @@ exports.build = async () => {
const experienceByUsers = await exports.experienceByUsers(reportConfig.buildTools.keys)
const others = await elastic.termsAgg(reportConfig.buildTools.freeform, OTHERS_AGG_SIZE)
const countries = await exports.distributionByCountry(reportConfig.buildTools.keys)
const numberOfToolsUsed = await exports.distributionByNumberOfToolsUsed(
reportConfig.buildTools.keys
)

return {
keys: reportConfig.buildTools.keys,
experience: dto.aggregations(experience.aggregations),
experienceByUsers,
others: others.aggregations[reportConfig.buildTools.freeform],
countries,
numberOfToolsUsed,
}
}

Expand All @@ -463,13 +492,17 @@ exports.mobile = async () => {
const experienceByUsers = await exports.experienceByUsers(reportConfig.mobile.keys)
const others = await elastic.termsAgg(reportConfig.mobile.freeform, OTHERS_AGG_SIZE)
const countries = await exports.distributionByCountry(reportConfig.mobile.keys)
const numberOfToolsUsed = await exports.distributionByNumberOfToolsUsed(
reportConfig.mobile.keys
)

return {
keys: reportConfig.mobile.keys,
experience: dto.aggregations(experience.aggregations),
experienceByUsers,
others: others.aggregations[reportConfig.mobile.freeform],
countries,
numberOfToolsUsed,
}
}

Expand Down
11 changes: 8 additions & 3 deletions src/components/blocks/ExperienceBlock.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@ export default class ExperienceBlock extends Component {

const allKeys = sortBy(['Aggregated', ...tools], key => data[key].by_experience.average)

const averages = allKeys
.map(tool => ({tool, value: `${data[tool].by_experience.average} years`}))
const averages = allKeys.map(tool => ({
tool,
value: `${data[tool].by_experience.average} years`,
}))

const yearsOfExperienceData = allKeys.map(tool => {
const toolYearsOfExperience = { tool }
Expand All @@ -41,7 +43,10 @@ export default class ExperienceBlock extends Component {
<div className="block block--chart block--experience">
<h3 className="block__title">Years of Experience</h3>
<div className="block__description">
<p>Per-library breakdown of developers according to years of experience (average value highlighted).</p>
<p>
Per-library breakdown of developers according to years of experience
(average value highlighted).
</p>
</div>
<div className="block__contents">
<div className="block__contents__inner">
Expand Down
17 changes: 14 additions & 3 deletions src/components/blocks/NumberOfLibrariesBlock.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,30 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import NumbersOfLibrariesPie from '../charts/NumbersOfLibrariesPie'

export default class NumberOfLibrariesBlock extends Component {
static propTypes = {
data: PropTypes.array.isRequired,
keys: PropTypes.arrayOf(PropTypes.string.isRequired).isRequired,
data: PropTypes.arrayOf(
PropTypes.shape({
key: PropTypes.number.isRequired,
doc_count: PropTypes.number.isRequired,
})
).isRequired,
}

render() {
const { keys, data } = this.props

return (
<div className="block block--chart block--numberoflibs">
<h3 className="block__title">Number of Libraries Used</h3>
<div className="block__description">
<p>How many different libraries have developers used?</p>
<p>How many different libraries are developers using?</p>
</div>
<div style={{ height: '500px' }}>
<NumbersOfLibrariesPie keys={keys} data={data} />
</div>
<img src="https://d3vv6lp55qjaqc.cloudfront.net/items/3r3H092K1I0B17111t2b/Screen%20Shot%202017-11-23%20at%2014.48.50.png?X-CloudApp-Visitor-Id=f25ee64a8f9b32be400086060540ffac&v=92889c34" />
</div>
)
}
Expand Down
11 changes: 7 additions & 4 deletions src/components/blocks/SalariesBlock.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,11 @@ export default class SalariesBlock extends Component {
const { data, tools, section } = this.props

const allKeys = sortBy(['Aggregated', ...tools], key => data[key].by_salary.average)
const averages = allKeys.map(tool => ({tool, value: formatMoney(data[tool].by_salary.average * 1000)}))

const averages = allKeys.map(tool => ({
tool,
value: formatMoney(data[tool].by_salary.average * 1000),
}))

const salariesData = allKeys.map(tool => {
const toolSalaries = { tool }
const buckets = data[tool].by_salary.buckets
Expand All @@ -43,13 +46,13 @@ export default class SalariesBlock extends Component {
return toolSalaries
})


return (
<div className="block block--chart block--salaries">
<h3 className="block__title">Salary Ranges</h3>
<div className="block__description">
<p>
Per-library breakdown of developers according to salary range (average value highlighted)
Per-library breakdown of developers according to salary range (average value
highlighted)
{/*
(restrict to{' '}
<a className="salaries__selector" href="#">
Expand Down
25 changes: 15 additions & 10 deletions src/components/blocks/TextBlock.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,21 @@ import addParagraphs from '../../helpers/paragraphs'
import parseBold from '../../helpers/bold'

const TextBlock = ({ text, title, children }) => {
if (children) {
return <div className="block block--text">{children}</div>
} else {
return (
<div className="block block--text">
{title && <h3 className="block__title">{title}</h3>}
{text && <div className="block__contents" dangerouslySetInnerHTML={{__html: parseBold(addParagraphs(text))}}/>}
</div>
)
}
if (children) {
return <div className="block block--text">{children}</div>
} else {
return (
<div className="block block--text">
{title && <h3 className="block__title">{title}</h3>}
{text && (
<div
className="block__contents"
dangerouslySetInnerHTML={{ __html: parseBold(addParagraphs(text)) }}
/>
)}
</div>
)
}
}

export default TextBlock
6 changes: 2 additions & 4 deletions src/components/blocks/WorldwideBlock.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ export default class WorldwideBlock extends Component {
<div className="block__description">
<p>
Library usage by country (defined as respondents who picked “have used
before and would use again”). Red indicates higher compared to worldwide average, blue
indicates lower usage compared to worldwide average.
before and would use again”). Red indicates higher compared to worldwide
average, blue indicates lower usage compared to worldwide average.
</p>
<p>
Note: only countries which received over {lowerResponseCount} total entries
Expand All @@ -52,8 +52,6 @@ export default class WorldwideBlock extends Component {
}}
/>
<div className="worldwide__grid">


<div className="worldwide__grid__item">
<div className="worldwide__chart">
<CountryBubble
Expand Down
65 changes: 65 additions & 0 deletions src/components/charts/NumbersOfLibrariesPie.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { ResponsivePie } from 'nivo'
import { scaleLinear } from 'd3-scale'

const margin = {
top: 40,
right: 100,
bottom: 40,
left: 100,
}

const getSliceLabel = d => {
if (d.id === '0') return 'none'
if (d.id === '1') return 'one lib'
return `${d.id} libs`
}

const getRadialLabel = d => {
if (d.id === '0') return 'Satisfied with none of them'
if (d.id === '1') return 'Only using one library'
return `Using ${d.id} libraries`
}

export default class NumbersOfLibrariesPie extends Component {
static propTypes = {
keys: PropTypes.arrayOf(PropTypes.string.isRequired).isRequired,
data: PropTypes.arrayOf(
PropTypes.shape({
key: PropTypes.number.isRequired,
doc_count: PropTypes.number.isRequired,
})
).isRequired,
}

render() {
const { keys, data } = this.props

const colorScale = scaleLinear()
.domain([0, 1, keys.length])
.range(['#dadada', '#9688e4', '#ea2149'])

const getColor = ({ id }) => colorScale(Number(id))

return (
<ResponsivePie
data={data.map(({ key, doc_count }) => ({
id: `${key}`,
label: `${key}`,
value: doc_count,
}))}
colorBy={getColor}
margin={margin}
innerRadius={0.6}
padAngle={0.6}
cornerRadius={3}
radialLabelsSkipAngle={10}
radialLabel={getRadialLabel}
radialLabelsLinkColor="inherit"
slicesLabelsSkipAngle={10}
sliceLabel={getSliceLabel}
/>
)
}
}

0 comments on commit c0fa423

Please sign in to comment.