forked from MapComplete/MapComplete
		
	Improve script to generate series
This commit is contained in:
		
							parent
							
								
									e8ae315d1d
								
							
						
					
					
						commit
						0a5f56d57a
					
				
					 6 changed files with 140 additions and 429039 deletions
				
			
		| 
						 | 
					@ -1,13 +0,0 @@
 | 
				
			||||||
#! /usr/bin/env      bash
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ts-node GenerateSeries.ts
 | 
					 | 
				
			||||||
# Move to the root of the repo
 | 
					 | 
				
			||||||
cd ../..
 | 
					 | 
				
			||||||
cd ../MapComplete-data
 | 
					 | 
				
			||||||
git pull
 | 
					 | 
				
			||||||
cd -
 | 
					 | 
				
			||||||
ts-node scripts/slice.ts ./Docs/Tools/centerpoints.geojson 8 ../MapComplete-data/mapcomplete-changes/
 | 
					 | 
				
			||||||
cd -
 | 
					 | 
				
			||||||
git add mapcomplete-changes/*
 | 
					 | 
				
			||||||
git commit -am "New changeset data"
 | 
					 | 
				
			||||||
git push
 | 
					 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
					@ -184,7 +184,7 @@ class StatisticsForOverviewFile extends Combine {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default class StatisticsGUI extends VariableUiElement {
 | 
					export default class StatisticsGUI extends VariableUiElement {
 | 
				
			||||||
    private static readonly homeUrl =
 | 
					    private static readonly homeUrl =
 | 
				
			||||||
        "https://raw.githubusercontent.com/pietervdvn/MapComplete/develop/Docs/Tools/stats/"
 | 
					        "https://raw.githubusercontent.com/pietervdvn/MapComplete-data/main/changeset-metadata/"
 | 
				
			||||||
    private static readonly stats_files = "file-overview.json"
 | 
					    private static readonly stats_files = "file-overview.json"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constructor() {
 | 
					    constructor() {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -31,12 +31,11 @@
 | 
				
			||||||
    "generate:layeroverview": "ts-node scripts/generateLayerOverview.ts",
 | 
					    "generate:layeroverview": "ts-node scripts/generateLayerOverview.ts",
 | 
				
			||||||
    "generate:licenses": "ts-node scripts/generateLicenseInfo.ts --no-fail",
 | 
					    "generate:licenses": "ts-node scripts/generateLicenseInfo.ts --no-fail",
 | 
				
			||||||
    "query:licenses": "ts-node scripts/generateLicenseInfo.ts --query",
 | 
					    "query:licenses": "ts-node scripts/generateLicenseInfo.ts --query",
 | 
				
			||||||
    "generate:report": "cd Docs/Tools && ./compileStats.sh && git commit . -m 'New statistics ands graphs' && git push",
 | 
					 | 
				
			||||||
    "generate:contributor-list": "ts-node scripts/generateContributors.ts",
 | 
					    "generate:contributor-list": "ts-node scripts/generateContributors.ts",
 | 
				
			||||||
    "generate:schemas": "ts2json-schema -p Models/ThemeConfig/Json/ -o Docs/Schemas/ -t tsconfig.json -R . -m \".*ConfigJson\" && ts-node scripts/fixSchemas.ts ",
 | 
					    "generate:schemas": "ts2json-schema -p Models/ThemeConfig/Json/ -o Docs/Schemas/ -t tsconfig.json -R . -m \".*ConfigJson\" && ts-node scripts/fixSchemas.ts ",
 | 
				
			||||||
    "generate:service-worker": "tsc service-worker.ts && git_hash=$(git rev-parse HEAD) && sed -i'.bkp' \"s/GITHUB-COMMIT/$git_hash/\" service-worker.js && rm service-worker.js.bkp",
 | 
					    "generate:service-worker": "tsc service-worker.ts && git_hash=$(git rev-parse HEAD) && sed -i'.bkp' \"s/GITHUB-COMMIT/$git_hash/\" service-worker.js && rm service-worker.js.bkp",
 | 
				
			||||||
    "optimize-images": "cd assets/generated/ &&  find -name '*.png' -exec optipng '{}' \\; && echo 'PNGs are optimized'",
 | 
					    "optimize-images": "cd assets/generated/ &&  find -name '*.png' -exec optipng '{}' \\; && echo 'PNGs are optimized'",
 | 
				
			||||||
    "generate:graphs": "ts-node Docs/Tools/GenerateSeries.ts",
 | 
					    "generate:stats": "ts-node scripts/GenerateSeries.ts",
 | 
				
			||||||
    "reset:layeroverview": "echo {\\\"layers\\\":[], \\\"themes\\\":[]} > ./assets/generated/known_layers_and_themes.json && echo {\\\"layers\\\": []} > ./assets/generated/known_layers.json && rm -f ./assets/generated/layers/*.json && rm -f ./assets/generated/themes/*.json && npm run generate:layeroverview && ts-node scripts/generateLayerOverview.ts --force",
 | 
					    "reset:layeroverview": "echo {\\\"layers\\\":[], \\\"themes\\\":[]} > ./assets/generated/known_layers_and_themes.json && echo {\\\"layers\\\": []} > ./assets/generated/known_layers.json && rm -f ./assets/generated/layers/*.json && rm -f ./assets/generated/themes/*.json && npm run generate:layeroverview && ts-node scripts/generateLayerOverview.ts --force",
 | 
				
			||||||
    "generate": "mkdir -p ./assets/generated; npm run generate:licenses; npm run generate:images; npm run generate:charging-stations; npm run generate:translations; npm run reset:layeroverview; npm run generate:service-worker",
 | 
					    "generate": "mkdir -p ./assets/generated; npm run generate:licenses; npm run generate:images; npm run generate:charging-stations; npm run generate:translations; npm run reset:layeroverview; npm run generate:service-worker",
 | 
				
			||||||
    "generate:charging-stations": "cd ./assets/layers/charging_station && ts-node csvToJson.ts && cd -",
 | 
					    "generate:charging-stations": "cd ./assets/layers/charging_station && ts-node csvToJson.ts && cd -",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,8 +1,11 @@
 | 
				
			||||||
import { existsSync, mkdirSync, readdirSync, readFileSync, unlinkSync, writeFileSync } from "fs"
 | 
					import fs, { existsSync, readdirSync, readFileSync, unlinkSync, writeFileSync } from "fs"
 | 
				
			||||||
import ScriptUtils from "../../scripts/ScriptUtils"
 | 
					import ScriptUtils from "./ScriptUtils"
 | 
				
			||||||
import { Utils } from "../../Utils"
 | 
					import { Utils } from "../Utils"
 | 
				
			||||||
 | 
					import Script from "./Script"
 | 
				
			||||||
ScriptUtils.fixUtils()
 | 
					import TiledFeatureSource from "../Logic/FeatureSource/TiledFeatureSource/TiledFeatureSource"
 | 
				
			||||||
 | 
					import StaticFeatureSource from "../Logic/FeatureSource/Sources/StaticFeatureSource"
 | 
				
			||||||
 | 
					import { GeoOperations } from "../Logic/GeoOperations"
 | 
				
			||||||
 | 
					import { Feature, Polygon } from "geojson"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class StatsDownloader {
 | 
					class StatsDownloader {
 | 
				
			||||||
    private readonly urlTemplate =
 | 
					    private readonly urlTemplate =
 | 
				
			||||||
| 
						 | 
					@ -158,7 +161,7 @@ class StatsDownloader {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface ChangeSetData {
 | 
					interface ChangeSetData extends Feature<Polygon> {
 | 
				
			||||||
    id: number
 | 
					    id: number
 | 
				
			||||||
    type: "Feature"
 | 
					    type: "Feature"
 | 
				
			||||||
    geometry: {
 | 
					    geometry: {
 | 
				
			||||||
| 
						 | 
					@ -196,56 +199,130 @@ interface ChangeSetData {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async function main(): Promise<void> {
 | 
					class GenerateSeries extends Script {
 | 
				
			||||||
    if (!existsSync("graphs")) {
 | 
					    constructor() {
 | 
				
			||||||
        mkdirSync("graphs")
 | 
					        super("Downloads metadata about changesets made by MapComplete from OsmCha")
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const targetDir = "Docs/Tools/stats"
 | 
					    async main(args: string[]): Promise<void> {
 | 
				
			||||||
    let year = 2020
 | 
					        const targetDir = args[0] ?? "../MapComplete-data"
 | 
				
			||||||
    let month = 5
 | 
					 | 
				
			||||||
    let day = 1
 | 
					 | 
				
			||||||
    if (!isNaN(Number(process.argv[2]))) {
 | 
					 | 
				
			||||||
        year = Number(process.argv[2])
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (!isNaN(Number(process.argv[3]))) {
 | 
					 | 
				
			||||||
        month = Number(process.argv[3])
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!isNaN(Number(process.argv[4]))) {
 | 
					        await this.downloadStatistics(targetDir + "/changeset-metadata")
 | 
				
			||||||
        day = Number(process.argv[4])
 | 
					        await this.generateCenterPoints(
 | 
				
			||||||
    }
 | 
					            targetDir + "/changeset-metadata",
 | 
				
			||||||
 | 
					            targetDir + "/mapcomplete-changes/",
 | 
				
			||||||
    do {
 | 
					            {
 | 
				
			||||||
        try {
 | 
					                zoomlevel: 8,
 | 
				
			||||||
            await new StatsDownloader(targetDir).DownloadStats(year, month, day)
 | 
					            }
 | 
				
			||||||
            break
 | 
					 | 
				
			||||||
        } catch (e) {
 | 
					 | 
				
			||||||
            console.log(e)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    } while (true)
 | 
					 | 
				
			||||||
    const allPaths = readdirSync(targetDir).filter(
 | 
					 | 
				
			||||||
        (p) => p.startsWith("stats.") && p.endsWith(".json")
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
    let allFeatures: ChangeSetData[] = [].concat(
 | 
					 | 
				
			||||||
        ...allPaths.map(
 | 
					 | 
				
			||||||
            (path) => JSON.parse(readFileSync("Docs/Tools/stats/" + path, "utf-8")).features
 | 
					 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
    allFeatures = allFeatures.filter(
 | 
					 | 
				
			||||||
        (f) =>
 | 
					 | 
				
			||||||
            f?.properties !== undefined &&
 | 
					 | 
				
			||||||
            (f.properties.editor === null ||
 | 
					 | 
				
			||||||
                f.properties.editor.toLowerCase().startsWith("mapcomplete"))
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    allFeatures = allFeatures.filter((f) => f.properties.metadata?.theme !== "EMPTY CS")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (process.argv.indexOf("--no-graphs") >= 0) {
 | 
					 | 
				
			||||||
        return
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    const allFiles = readdirSync("Docs/Tools/stats").filter((p) => p.endsWith(".json"))
 | 
					
 | 
				
			||||||
    writeFileSync("Docs/Tools/stats/file-overview.json", JSON.stringify(allFiles))
 | 
					    private async downloadStatistics(targetDir: string) {
 | 
				
			||||||
 | 
					        let year = 2020
 | 
				
			||||||
 | 
					        let month = 5
 | 
				
			||||||
 | 
					        let day = 1
 | 
				
			||||||
 | 
					        if (!isNaN(Number(process.argv[2]))) {
 | 
				
			||||||
 | 
					            year = Number(process.argv[2])
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (!isNaN(Number(process.argv[3]))) {
 | 
				
			||||||
 | 
					            month = Number(process.argv[3])
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!isNaN(Number(process.argv[4]))) {
 | 
				
			||||||
 | 
					            day = Number(process.argv[4])
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        do {
 | 
				
			||||||
 | 
					            try {
 | 
				
			||||||
 | 
					                await new StatsDownloader(targetDir).DownloadStats(year, month, day)
 | 
				
			||||||
 | 
					                break
 | 
				
			||||||
 | 
					            } catch (e) {
 | 
				
			||||||
 | 
					                console.log(e)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } while (true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const allFiles = readdirSync(targetDir).filter((p) => p.endsWith(".json"))
 | 
				
			||||||
 | 
					        writeFileSync(targetDir + "file-overview.json", JSON.stringify(allFiles))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private generateCenterPoints(
 | 
				
			||||||
 | 
					        sourceDir: string,
 | 
				
			||||||
 | 
					        targetDir: string,
 | 
				
			||||||
 | 
					        options: {
 | 
				
			||||||
 | 
					            zoomlevel: number
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					        const allPaths = readdirSync(sourceDir).filter(
 | 
				
			||||||
 | 
					            (p) => p.startsWith("stats.") && p.endsWith(".json")
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        let allFeatures: ChangeSetData[] = [].concat(
 | 
				
			||||||
 | 
					            ...allPaths.map(
 | 
				
			||||||
 | 
					                (path) => JSON.parse(readFileSync(sourceDir + "/" + path, "utf-8")).features
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        allFeatures = allFeatures.filter(
 | 
				
			||||||
 | 
					            (f) =>
 | 
				
			||||||
 | 
					                f?.properties !== undefined &&
 | 
				
			||||||
 | 
					                (f.properties.editor === null ||
 | 
				
			||||||
 | 
					                    f.properties.editor.toLowerCase().startsWith("mapcomplete"))
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        allFeatures = allFeatures.filter(
 | 
				
			||||||
 | 
					            (f) => f.geometry !== null && f.properties.metadata?.theme !== "EMPTY CS"
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        allFeatures = allFeatures.filter(
 | 
				
			||||||
 | 
					            (f) =>
 | 
				
			||||||
 | 
					                f?.properties !== undefined &&
 | 
				
			||||||
 | 
					                (f.properties.editor === null ||
 | 
				
			||||||
 | 
					                    f.properties.editor.toLowerCase().startsWith("mapcomplete"))
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        allFeatures = allFeatures.filter((f) => f.properties.metadata?.theme !== "EMPTY CS")
 | 
				
			||||||
 | 
					        const centerpoints = allFeatures.map((f) => GeoOperations.centerpoint(f))
 | 
				
			||||||
 | 
					        console.log("Found", centerpoints.length, " changesets in total")
 | 
				
			||||||
 | 
					        const path = `${targetDir}/all_centerpoints.geojson`
 | 
				
			||||||
 | 
					        /*fs.writeFileSync(
 | 
				
			||||||
 | 
					            path,
 | 
				
			||||||
 | 
					            JSON.stringify(
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    type: "FeatureCollection",
 | 
				
			||||||
 | 
					                    features: centerpoints,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                null,
 | 
				
			||||||
 | 
					                "  "
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        )//*/
 | 
				
			||||||
 | 
					        TiledFeatureSource.createHierarchy(StaticFeatureSource.fromGeojson(centerpoints), {
 | 
				
			||||||
 | 
					            minZoomLevel: options.zoomlevel,
 | 
				
			||||||
 | 
					            maxZoomLevel: options.zoomlevel,
 | 
				
			||||||
 | 
					            maxFeatureCount: Number.MAX_VALUE,
 | 
				
			||||||
 | 
					            registerTile: (tile) => {
 | 
				
			||||||
 | 
					                const path = `${targetDir}/tile_${tile.z}_${tile.x}_${tile.y}.geojson`
 | 
				
			||||||
 | 
					                const features = tile.features.data.map((ff) => ff.feature)
 | 
				
			||||||
 | 
					                features.forEach((f) => {
 | 
				
			||||||
 | 
					                    delete f.bbox
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					                fs.writeFileSync(
 | 
				
			||||||
 | 
					                    path,
 | 
				
			||||||
 | 
					                    JSON.stringify(
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            type: "FeatureCollection",
 | 
				
			||||||
 | 
					                            features: features,
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                        null,
 | 
				
			||||||
 | 
					                        "  "
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					                ScriptUtils.erasableLog(
 | 
				
			||||||
 | 
					                    "Written ",
 | 
				
			||||||
 | 
					                    path,
 | 
				
			||||||
 | 
					                    "which has ",
 | 
				
			||||||
 | 
					                    tile.features.data.length,
 | 
				
			||||||
 | 
					                    "features"
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
main().then((_) => console.log("All done!"))
 | 
					new GenerateSeries().run()
 | 
				
			||||||
| 
						 | 
					@ -11,6 +11,13 @@ export default class ScriptUtils {
 | 
				
			||||||
        Utils.externalDownloadFunction = ScriptUtils.Download
 | 
					        Utils.externalDownloadFunction = ScriptUtils.Download
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Returns all files in a directory, recursively reads subdirectories.
 | 
				
			||||||
 | 
					     * The returned paths include the path given and subdirectories.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param path
 | 
				
			||||||
 | 
					     * @param maxDepth
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
    public static readDirRecSync(path, maxDepth = 999): string[] {
 | 
					    public static readDirRecSync(path, maxDepth = 999): string[] {
 | 
				
			||||||
        const result = []
 | 
					        const result = []
 | 
				
			||||||
        if (maxDepth <= 0) {
 | 
					        if (maxDepth <= 0) {
 | 
				
			||||||
| 
						 | 
					@ -46,13 +53,13 @@ export default class ScriptUtils {
 | 
				
			||||||
        process.stdout.write("\r " + text.join(" ") + "                \r")
 | 
					        process.stdout.write("\r " + text.join(" ") + "                \r")
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static sleep(ms) {
 | 
					    public static sleep(ms: number, text?: string) {
 | 
				
			||||||
        if (ms <= 0) {
 | 
					        if (ms <= 0) {
 | 
				
			||||||
            process.stdout.write("\r                                       \r")
 | 
					            process.stdout.write("\r                                       \r")
 | 
				
			||||||
            return
 | 
					            return
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return new Promise((resolve) => {
 | 
					        return new Promise((resolve) => {
 | 
				
			||||||
            process.stdout.write("\r Sleeping for " + ms / 1000 + "s \r")
 | 
					            process.stdout.write("\r" + (text ?? "") + " Sleeping for " + ms / 1000 + "s \r")
 | 
				
			||||||
            setTimeout(resolve, 1000)
 | 
					            setTimeout(resolve, 1000)
 | 
				
			||||||
        }).then(() => ScriptUtils.sleep(ms - 1000))
 | 
					        }).then(() => ScriptUtils.sleep(ms - 1000))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue