Published
Edited
Apr 29, 2021
Importers
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Build = ({
CORE: "Core build",
FULL: "Full build"
})
Insert cell
Setting = ({
SHOW_ALL_PACKAGES: "Show all packages",
ADJUST_STYLING: "Adjust styling"
})
Insert cell
Insert cell
downloadsByPackage = dataSource.fetchDownloadCounts(methodNames)
Insert cell
viewof dataSource = {
const sources = [
{
name: "gist.github.com",
fetchDownloadCounts: _.memoize(gist.fetchDownloadCounts)
},
{
name: "api.npmjs.org",
fetchDownloadCounts: _.memoize(npm.fetchDownloadCounts)
}
];
const options = {
label: "Source:",
format: source => source.name,
value: _.head(sources)
};
return Radio(sources, options);
}
Insert cell
_ = require("lodash@4")
Insert cell
// see: https://gist.github.com/nikita-sharov/67376c726555665fe261f066d30fa4cb
gist = {
const d3 = await require("d3-fetch@2");
const fetchDownloadCounts = async (methodNames) => {
const url = "https://gist.githubusercontent.com/nikita-sharov/67376c726555665fe261f066d30fa4cb/raw/76197a0bc725ca1748abd958598f4fa8825b5ef8/downloads-by-package_2021-04-21.csv"; // yes, way too long
const converter = row => ({package: row.package, downloads: +row.downloads});
const downloadsByPackage = await d3.csv(url, converter);
const packageNames = _.map(methodNames, getPotentialPackageName);
return _.filter(downloadsByPackage, d => _.includes(packageNames, d.package));
};
return {fetchDownloadCounts};
}
Insert cell
// see: https://github.com/npm/registry/blob/master/docs/download-counts.md
npm = {
const getDownloadCountUrl = (packageName) => {
// actually, the last 30 days is the maximum we can get
return `https://api.npmjs.org/downloads/point/last-month/${packageName}`;
};
const fetchDownloads = async (methodName) => {
const packageName = getPotentialPackageName(methodName);
const url = getDownloadCountUrl(packageName);
return fetch(url).then(response => response.json());
};
const fetchDownloadCounts = async (methodNames) => {
const requests = _.map(methodNames, fetchDownloads);
const responses = await Promise.all(requests);
const existingPackages = _.filter(responses, d => _.isUndefined(d.error));
return _.map(existingPackages, d => ({package: d.package, downloads: d.downloads}));
};
return {fetchDownloadCounts};
}
Insert cell
getPotentialPackageName = (methodName) => `lodash.${_.toLower(methodName)}`;
Insert cell
methodNames = _.eq(build, Build.CORE) ? coreBuildMethodNames : _.map(methodInfos, "name")
Insert cell
// see: https://lodash.com/custom-builds
// see also: https://github.com/lodash/lodash/wiki/Build-Differences
coreBuildMethodNames = ["assignIn", "before", "bind", "chain", "clone", "compact", "concat", "create", "defaults", "defer", "delay", "each", "escape", "every", "filter", "find", "flatten", "flattenDeep", "forEach", "has", "head", "identity", "indexOf", "isArguments", "isArray", "isBoolean", "isDate", "isEmpty", "isEqual", "isFinite", "isFunction", "isNaN", "isNull", "isNumber", "isObject", "isRegExp", "isString", "isUndefined", "iteratee", "keys", "last", "map", "matches", "max", "min", "mixin", "negate", "noConflict", "noop", "once", "pick", "reduce", "result", "size", "slice", "some", "sortBy", "tap", "thru", "toArray", "uniqueId", "value", "values"]
Insert cell
Insert cell
Insert cell
ranking = {
const ordering = _.orderBy(downloadsByPackage, "downloads", "desc");
return _.map(ordering, (d, i) => ({rank: i + 1, name: d.package, downloads: d.downloads}));
}
Insert cell
packageInfos = {
if (_.includes(settings, Setting.SHOW_ALL_PACKAGES)) {
return _.map(ranking, createPackageInfo);
}

const sliceSize = 10;
const mostPopularPackages = _.map(_.take(ranking, sliceSize), createPackageInfo);
const leastPopularPackages = _.map(_.takeRight(ranking, sliceSize), createPackageInfo);
return _.concat(mostPopularPackages, _.stubObject(), leastPopularPackages);
}
Insert cell
createPackageInfo = (rankedPackage) => {
const methodName = getMethodName(rankedPackage.name);
return {
methodName,
documentationUrl: getDocumentationUrl(methodName),
downloads: rankedPackage.downloads,
percentage: getPercentage(rankedPackage.downloads),
rank: rankedPackage.rank
};
}
Insert cell
getMethodName = (packageName) =>
_.find(methodNames, methodName => _.eq(packageName, getPotentialPackageName(methodName)))
Insert cell
getDocumentationUrl = (methodName, majorVersion = 4) => `https://lodash.com/docs/${majorVersion}#${methodName}`
Insert cell
getPercentage = (downloads) => downloads / totalDownloads * 100
Insert cell
totalDownloads = _.sumBy(downloadsByPackage, "downloads")
Insert cell
chunks = {
const chunkSize = _.ceil(ranking.length / 10);
return _.chunk(ranking, chunkSize);
}
Insert cell
percentages = _.map(chunks, chunk => getPercentage(_.sumBy(chunk, d => d.downloads)))
Insert cell
distribution = {
const endIndices = _.range(1, 11);
const shares = _.map(endIndices, endIndex => getShare(percentages, endIndex));
return _.takeWhile(shares, share => share < 100);
}
Insert cell
getShare = (values, endIndex) => {
const slice = _.slice(values, 0, endIndex);
return _.round(_.sum(slice));
}
Insert cell
Insert cell
table = (className, packageInfos) => html`<table class="${className}">
${head()}
${body(packageInfos)}
</table>`
Insert cell
Insert cell
body = (packageInfos) => `<tbody>${_.join(_.map(packageInfos, row), _.stubString())}</tbody>`
Insert cell
row = (packageInfo) => {
if (_.isEmpty(packageInfo)) {
return separator();
}
return `<tr>
<td class="number">${packageInfo.rank}</td>
<td>${formatPackage(packageInfo)}</td>
<td class="number">${formatDownloads(packageInfo.downloads)}</td>
<td class="number">${formatPercentage(packageInfo.percentage)}</td>
</tr>`;
}
Insert cell
separator = (cellCount = 4) => `<tr>${_.repeat("<td/>", cellCount)}</tr>` // an empty row
Insert cell
formatPackage = (info) => `<a href="${info.documentationUrl}"><strong>${info.methodName}</strong></a>`
Insert cell
formatDownloads = (value) => value.toLocaleString()
Insert cell
formatPercentage = (value, precision = 8, digitsAfterDecimalPoint = 6) =>
_.round(value, precision).toFixed(digitsAfterDecimalPoint)
Insert cell
// based on https://observablehq.com/@tmcw/tables
html`<style>
.funky {
width: unset;
}

.funky th {
text-transform: uppercase;
font-weight: 500;
}

.funky th,
.funky td {
padding-left: 1em;
}

.funky th.number,
.funky td.number {
text-align: right;
vertical-align: top;
}

.funky td.number {
font-family: Menlo, Consolas, monospace;
font-size: .9em;
}`;
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more