Public
Edited
Jan 18, 2023
1 star
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
d3.sum(stats_all, d => d.count)
Insert cell
d3.sum(stats_all.filter(d => d.source != "Diffusion mail"), d => d.count)
Insert cell
d3.sum(stats_all.filter(d => d.source != "Diffusion mail"), d => d.count) / d3.sum(stats_all, d => d.count)
Insert cell
Insert cell
Insert cell
d3.sum(
stats_all.filter(d => d.domain == "INSEE"), d => d.count
) / d3.sum(
stats_all, d => d.count
)
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
html`<script async defer src="https://buttons.github.io/buttons.js"></script>`
Insert cell
Insert cell
api_stars=`https://ghbtns.com/github-btn.html?user=${githubrepo.split("/")[0]}&repo=${githubrepo.split("/")[1]}&type=star&count=true&size=large`
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
point_to_anchor_start = data.filter(d => d.date >= d3.utcParse("%Y-%m-%d")("2022-06-13")).map(d => d.count)[0]
Insert cell
point_to_anchor_end = data.filter(d => d.date <= d3.utcParse("%Y-%m-%d")("2022-12-15")).map(d => d.count).at(-1)
Insert cell
Insert cell
Insert cell
configuredClient = {
const client = await DuckDBClient.of();
await client.sql`
SET s3_endpoint='minio.lab.sspcloud.fr'
`;
return client;
}

Insert cell
url_latest = 's3://lgaliana/ssphub/files/retrospective2022-observable/list_contacts_latest.parquet'
Insert cell
url_latest2 = 's3://lgaliana/ssphub/files/retrospective2022-observable/series_nombre_contact.parquet'
Insert cell
db = {
await configuredClient.query(`
CREATE VIEW latest AS
SELECT * FROM read_parquet('${url_latest}') ;
`);
await configuredClient.query(`
CREATE VIEW serie AS
SELECT * FROM read_parquet('${url_latest2}') ;
`);
return configuredClient
}
Insert cell
serie_contacts = db.sql`
SELECT date, CAST(SUM(mail) AS int) AS mail
FROM serie
GROUP BY date
`
Insert cell
serie_contacts_domain = db.sql`
SELECT date, domain, CAST(mail AS int) AS mail
FROM serie
`
Insert cell
stats_tchap_vs_outlook = db.sql`
SELECT source, domain, CAST(COUNT(*) AS int) AS count
FROM latest
WHERE domain IN (SELECT domain
FROM latest
GROUP BY domain
HAVING COUNT(*) > 10)
GROUP BY source, domain
`
Insert cell
stats_all = db.sql`
SELECT source, domain, CAST(COUNT(*) AS int) AS count
FROM latest
GROUP BY source, domain
`
Insert cell
Insert cell
Insert cell
Plot = require('@observablehq/plot@0.6.1/dist/plot.umd.min.js')
Insert cell
import { style as faStyle, fa, fas } from "@airbornemint/fontawesome"
Insert cell
import {Treemap} from "@d3/treemap"
Insert cell
import {SummaryTable} from "@observablehq/summary-table"
Insert cell
import {addTooltips} from "@mkfreeman/plot-tooltip"
Insert cell
import {disposal} from "@mbostock/disposal"
Insert cell
Insert cell
pie = (data, { value, ...options }) => {
const cs = d3.cumsum(data, (d) => d[value]);
const r = 360 / cs[cs.length - 1];
for (let i = 0; i < cs.length; ++i) cs[i] *= r;
for (const d of data)
return Plot.geo(
{
type: "GeometryCollection",
geometries: data.map((d, i) => {
const a = -(cs[i - 1] || 0);
const b = -cs[i];
return {
type: "Polygon",
...d,
coordinates: [
[
[0, 90],
[a, 0],
[(2 * a + b) / 3, 0], // add intermediate points for sectors larger than a half-circle
[(a + 2 * b) / 3, 0],
[b, 0],
[0, 90]
]
]
};
})
},
{ ...options }
);
}
Insert cell
order_domain_all = d3.groupSort(
stats_tchap_vs_outlook,
(g) => d3.sum(g, (d) => -d.count),
(d) => d.domain
)
Insert cell
Insert cell
faStyle({regular: true, solid: true, brands: true})
Insert cell
html`<style>
.slidecontainer {
width: 100%;
}

.slider {
-webkit-appearance: none;
width: 100%;
height: 15px;
border-radius: 5px;
background: #d3d3d3;
outline: none;
opacity: 0.7;
-webkit-transition: .2s;
transition: opacity .2s;
}

.slider:hover {
opacity: 1;
}

.slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 25px;
height: 25px;
border-radius: 50%;
background: #4CAF50;
cursor: pointer;
}

.slider::-moz-range-thumb {
width: 25px;
height: 25px;
border-radius: 50%;
background: #4CAF50;
cursor: pointer;
}
</style>`
Insert cell
Insert cell
parseDate = d3.utcParse("%Y-%m-%d"); //function to parse dates
Insert cell
startDate = parseDate("2022-06-30");
Insert cell
endDate = parseDate("2022-09-05");
Insert cell
daysBetween = d3.utcDay.count(startDate, endDate);
Insert cell
middleDate = d3.utcDay.offset(startDate, Math.floor(daysBetween / 2));
Insert cell
dateFormat = d3.utcFormat("%Y-%m-%d")
Insert cell
subset = serie_contacts_domain.filter(d => dateFormat(d.date) == dateFormat(input_date))
Insert cell
order_domain = d3.groupSort(
serie_contacts_domain,
(g) => d3.max(g, (d) => d.mail),
(d) => d.domain
)
Insert cell
array1 = ssp.concat(autres_ssp)

Insert cell
array2 = subset.map(d => d.domain)

Insert cell
hors_ssp_all = serie_contacts_domain.map(d => d.domain).filter(d => !array1.includes(d))

Insert cell
hors_ssp = [... new Set(hors_ssp_all)]
Insert cell
colors_hors_ssp = Array(hors_ssp.length).fill("#fb9a99")
Insert cell
ssp = [
'INSEE', 'Santé', 'Développement Durable', 'Agriculture', 'Finances', 'Travail', 'Intérieur', 'Recherche'
]

Insert cell
autres_ssp = ['Justice', 'Culture', "Collectivités Locales", "Enseignement Supérieur",
"Jeunesse Sports", "Défense"]

Insert cell
colors_autres_ssp = Array(6).fill("orange")
Insert cell
Insert cell
data = {
// Start with an empty array of results; we'll yield it repeatedly as more results come in
const S = [];
yield S;

// Get total number of pages from response headers
let pages = await fetchGithubResponse(`/repos/${githubrepo}/stargazers`, {per_page: 100}, fetchOptions)
.then(d => [...d.headers].find(d => d[0] === "link")?.[1].split(/,/).pop().match(/&page=(\d+)/)?.[1] || 1);

let l = Math.min(maxPages, pages);
mutable pages_remaining = l;

// Fetch the first page, last page, and then remaining pages shuffled
for (const page of new Set([1, +pages].concat(d3.shuffle(d3.range(2, +pages))))) {
const s = await fetchGithub(`/repos/${githubrepo}/stargazers`, {per_page: 100, page}, fetchOptions);

// If there's an error, return
if (!s) return;
if (s.message) return mutable error_message = s.message;

// Push a transformed version of the stargazer response, sort it, and yield it
s.forEach((u, i) => {
S.push({
login: u.user.login,
id: u.user.id,
date: new Date(u.starred_at),
count: 100 * (page - 1) + i + 1,
githubrepo
});
});
S.sort((a, b) => a.count - b.count);
yield S;

// Decrement log of remaining pages
mutable pages_remaining = --l;
if (l === 0) break;

// Wait before next request
await Promises.delay(150);
}

// Final results
yield S;
}
Insert cell
tags = {
const tags = await fetchGithub(`/repos/${githubrepo}/tags`);
for (const tag of tags) {
const commit = await fetchGithub(`/repos/${githubrepo}/commits/${tag.commit.sha}`);
tag.commit = commit;
tag.date = new Date(commit.commit.author.date);
}
return tags;
}
Insert cell
dates = {
const D = [];
const max = data[data.length - 1].count;
let i = 0;
for (let count = 1; count <= max; count++) {
while (data[i].count < count) i++;
const date =
data[i].count === count
? data[i].date
: d3.interpolate(
data[i - 1].date,
data[i].date
)((count - data[i - 1].count) / (data[i].count - data[i - 1].count));
D.push(date);
}
return D;
}
Insert cell
topDays = d3.groups(data, d => d3.utcDay.floor(d.date)).sort((a, b) => d3.descending(a[1].length, b[1].length))
Insert cell
milestones = d3
.range(Math.ceil(Math.log10(data[data.length - 1].count)))
.map((n) => 10 ** n)
.map((n) => [n, data.find((d) => d.count === n)])
Insert cell
fetchOptions = ({
headers: {
accept: "application/vnd.github.v3.star+json" // necessary to get the starred_at field
}
})
Insert cell
import {
fetchGithub,
fetchGithubResponse,
hasApiKey,
apiKeyStatus,
rateLimitSummary
} from "@observablehq/github-actions-workflows-api"
Insert cell
import {maxPages} from "@observablehq/github-stargazer-history"
Insert cell
mutable error_message = {}
Insert cell
mutable pages_remaining = null
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