From 1baad9f85a48857532b192ebe8c9f817148138f8 Mon Sep 17 00:00:00 2001 From: Chris Wilkinson <c.wilkinson@elifesciences.org> Date: Thu, 20 Jun 2024 12:24:32 +0100 Subject: [PATCH] Group the requests by preprint language --- package-lock.json | 11 ++++++++++- package.json | 3 ++- src/data/requests.json.ts | 8 +++++++- src/lib/LanguageCode.ts | 10 ++++++++++ src/requests.md | 16 ++++++++++++++-- 5 files changed, 43 insertions(+), 5 deletions(-) create mode 100644 src/lib/LanguageCode.ts diff --git a/package-lock.json b/package-lock.json index 139901f..7f5c7e8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,8 @@ "@observablehq/framework": "^1.9.0", "d3-dsv": "^3.0.1", "d3-time-format": "^4.1.0", - "effect": "^3.3.5" + "effect": "^3.3.5", + "iso-639-1": "^3.1.2" }, "devDependencies": { "@trivago/prettier-plugin-sort-imports": "^4.3.0", @@ -2562,6 +2563,14 @@ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, + "node_modules/iso-639-1": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/iso-639-1/-/iso-639-1-3.1.2.tgz", + "integrity": "sha512-Le7BRl3Jt9URvaiEHJCDEdvPZCfhiQoXnFgLAWNRhzFMwRFdWO7/5tLRQbiPzE394I9xd7KdRCM7S6qdOhwG5A==", + "engines": { + "node": ">=6.0" + } + }, "node_modules/isoformat": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/isoformat/-/isoformat-0.2.1.tgz", diff --git a/package.json b/package.json index 41f56a2..b8bf856 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,8 @@ "@observablehq/framework": "^1.9.0", "d3-dsv": "^3.0.1", "d3-time-format": "^4.1.0", - "effect": "^3.3.5" + "effect": "^3.3.5", + "iso-639-1": "^3.1.2" }, "devDependencies": { "@trivago/prettier-plugin-sort-imports": "^4.3.0", diff --git a/src/data/requests.json.ts b/src/data/requests.json.ts index 3685d8e..3188166 100644 --- a/src/data/requests.json.ts +++ b/src/data/requests.json.ts @@ -2,9 +2,15 @@ import { HttpClient, Terminal } from '@effect/platform' import { NodeTerminal } from '@effect/platform-node' import { Schema } from '@effect/schema' import { Effect } from 'effect' +import * as LanguageCode from '../lib/LanguageCode.js' import * as Temporal from '../lib/Temporal.js' -const Requests = Schema.Array(Schema.Struct({ timestamp: Temporal.InstantFromStringSchema })) +const Requests = Schema.Array( + Schema.Struct({ + timestamp: Temporal.InstantFromStringSchema, + language: Schema.optional(LanguageCode.LanguageCodeSchema, { nullable: true }), + }), +) const program = Effect.gen(function* () { const terminal = yield* Terminal.Terminal diff --git a/src/lib/LanguageCode.ts b/src/lib/LanguageCode.ts new file mode 100644 index 0000000..ac06991 --- /dev/null +++ b/src/lib/LanguageCode.ts @@ -0,0 +1,10 @@ +import { Schema } from '@effect/schema' +import type { Predicate } from 'effect' +import iso6391, { type LanguageCode } from 'iso-639-1' + +export { type LanguageCode } from 'iso-639-1' + +export const isLanguageCode: Predicate.Refinement<unknown, LanguageCode> = (u): u is LanguageCode => + typeof u === 'string' && iso6391.validate(u) + +export const LanguageCodeSchema: Schema.Schema<LanguageCode, string> = Schema.String.pipe(Schema.filter(isLanguageCode)) diff --git a/src/requests.md b/src/requests.md index cef0662..76d854e 100644 --- a/src/requests.md +++ b/src/requests.md @@ -8,6 +8,7 @@ toc: false ```js const parseTimestamp = d3.utcParse('%Y-%m-%dT%H:%M:%S.%LZ') +const languageNames = new Intl.DisplayNames(['en-US'], { type: 'language' }) const requests = FileAttachment('./data/requests.json') .json() @@ -27,13 +28,24 @@ function requestsTimeline({ width } = {}) { title: 'Requests per week', width: Math.max(width, 600), height: 400, - color: {}, + color: { + legend: true, + tickFormat: d => (d ? languageNames.of(d) : 'Not yet detected'), + }, y: { grid: true, label: 'Requests' }, x: { label: '' }, marks: [ Plot.rectY( requests, - Plot.binX({ y: 'count' }, { x: 'timestamp', interval: d3.utcWeek, fill: 'var(--theme-foreground-focus)' }), + Plot.binX( + { y: 'count' }, + { + x: 'timestamp', + interval: d3.utcWeek, + fill: 'language', + order: ['en', 'es', 'pt'], + }, + ), ), Plot.ruleY([0]), ],