Feature: add image leaderboard

This commit is contained in:
Pieter Vander Vennet 2023-10-17 13:31:06 +02:00
parent 590495fbbc
commit d10760b8cb
3 changed files with 85 additions and 1 deletions

View file

@ -4,6 +4,7 @@ import { RegexTag } from "../src/Logic/Tags/RegexTag"
import { ImmutableStore } from "../src/Logic/UIEventSource" import { ImmutableStore } from "../src/Logic/UIEventSource"
import { BBox } from "../src/Logic/BBox" import { BBox } from "../src/Logic/BBox"
import * as fs from "fs" import * as fs from "fs"
import { writeFileSync } from "fs"
import { Feature } from "geojson" import { Feature } from "geojson"
import ScriptUtils from "./ScriptUtils" import ScriptUtils from "./ScriptUtils"
import { Imgur } from "../src/Logic/ImageProviders/Imgur" import { Imgur } from "../src/Logic/ImageProviders/Imgur"
@ -30,7 +31,6 @@ export default class GenerateImageAnalysis extends Script {
[], [],
Constants.defaultOverpassUrls[0], //"https://overpass.kumi.systems/api/interpreter", Constants.defaultOverpassUrls[0], //"https://overpass.kumi.systems/api/interpreter",
new ImmutableStore(500), new ImmutableStore(500),
undefined,
false false
) )
console.log("Starting query...") console.log("Starting query...")
@ -291,6 +291,9 @@ export default class GenerateImageAnalysis extends Script {
console.log(countsPerAuthor) console.log(countsPerAuthor)
countsPerAuthor.sort() countsPerAuthor.sort()
const median = countsPerAuthor[Math.floor(countsPerAuthor.length / 2)] const median = countsPerAuthor[Math.floor(countsPerAuthor.length / 2)]
const json: {leaderboard: {rank: number, account: string, name: string, nrOfImages: number}[]} = {
leaderboard: []
}
for (let i = 0; i < 100; i++) { for (let i = 0; i < 100; i++) {
let maxAuthor: string = undefined let maxAuthor: string = undefined
let maxCount = 0 let maxCount = 0
@ -301,6 +304,12 @@ export default class GenerateImageAnalysis extends Script {
maxCount = count maxCount = count
} }
} }
json.leaderboard.push({
rank: i+1,
name: maxAuthor,
account: "https://openstreetmap.org/user/"+maxAuthor.replace(/ /g, "%20"),
nrOfImages: maxCount
})
console.log( console.log(
"|", "|",
i + 1, i + 1,
@ -315,9 +324,11 @@ export default class GenerateImageAnalysis extends Script {
const totalAuthors = byAuthor.size const totalAuthors = byAuthor.size
let totalLicensedImages = 0 let totalLicensedImages = 0
json["totalAuthors"] = totalAuthors
for (const license in byLicenseCount) { for (const license in byLicenseCount) {
totalLicensedImages += byLicenseCount[license] totalLicensedImages += byLicenseCount[license]
} }
json["byLicense"] = {}
for (const license in byLicenseCount) { for (const license in byLicenseCount) {
const total = byLicenseCount[license] const total = byLicenseCount[license]
const authors = licenseByAuthorCount[license] const authors = licenseByAuthorCount[license]
@ -328,6 +339,9 @@ export default class GenerateImageAnalysis extends Script {
Math.floor((1000 * authors) / totalAuthors) / 10 Math.floor((1000 * authors) / totalAuthors) / 10
}%), ${Math.floor(total / authors)} images/author` }%), ${Math.floor(total / authors)} images/author`
) )
json["byLicense"] = {
license, total, authors
}
} }
const nonDefaultAuthors = [ const nonDefaultAuthors = [
@ -348,6 +362,9 @@ export default class GenerateImageAnalysis extends Script {
nonDefaultAuthors.length nonDefaultAuthors.length
) )
console.log("Median contributions per author:", median) console.log("Median contributions per author:", median)
json["median"] = median
json["date"] = new Date().toISOString()
writeFileSync("../../git/MapComplete-data/picture-leaderboard.json", JSON.stringify(json), "utf8")
} }
async main(args: string[]): Promise<void> { async main(args: string[]): Promise<void> {

63
src/UI/Leaderboard.svelte Normal file
View file

@ -0,0 +1,63 @@
<script lang="ts">
import { Utils } from "../Utils"
import { Store, UIEventSource } from "../Logic/UIEventSource"
import Loading from "./Base/Loading.svelte"
import { OsmConnection } from "../Logic/Osm/OsmConnection"
const osmConnection = new OsmConnection({
attemptLogin: true
})
let loggedInContributor: Store<string> = osmConnection.userDetails.map(ud => ud.name)
export let source = "https://raw.githubusercontent.com/pietervdvn/MapComplete-data/main/picture-leaderboard.json"
let data: Store<undefined | {
leaderboard: {
rank: number,
name: string,
account: string,
nrOfImages: number
}[],
median: number,
totalAuthors: number,
byLicense: {
license: string, total: number, authors: string[]
},
date: string
}> = UIEventSource.FromPromise(Utils.downloadJsonCached(source))
</script>
<h1>Contributed images with MapComplete: leaderboard</h1>
{#if $data}
<table>
<tr>
<th>Rank</th>
<th>Contributor</th>
<th>Number of images contributed</th>
</tr>
{#each $data.leaderboard as contributor}
<tr>
<td>
{contributor.rank}
</td>
<td>
{#if $loggedInContributor === contributor.name}
<a class="thanks" href="{contributor.account}">{contributor.name}</a>
{:else}
<a href="{contributor.account}">{contributor.name}</a>
{/if}
</td>
<td>
<b>{contributor.nrOfImages}</b> total images
</td>
</tr>
{/each}
</table>
Statistics generated on {$data.date}
{:else}
<Loading />
{/if}
<div>
Logged in as {$loggedInContributor}
</div>

4
src/leaderboard.ts Normal file
View file

@ -0,0 +1,4 @@
import SvelteUIElement from "./UI/Base/SvelteUIElement"
import Leaderboard from "./UI/Leaderboard.svelte"
new SvelteUIElement(Leaderboard, {}).AttachTo("main")