Analysis of OpenStreetMap contributions from organised teams (including corporations).
# Organised teams statistics per month
df = duckdb.sql("""
WITH monthly_total AS (
SELECT
year,
month,
CONCAT(year, '-', LPAD(CAST(month as VARCHAR), 2, '0')) as months,
COUNT(DISTINCT user_name) as total_contributors,
CAST(SUM(edit_count) as BIGINT) as total_edits
FROM '../changeset_data/year=*/month=*/*.parquet'
GROUP BY year, month
),
monthly_organised_team AS (
SELECT
year,
month,
CONCAT(year, '-', LPAD(CAST(month as VARCHAR), 2, '0')) as months,
COUNT(DISTINCT user_name) as team_contributors,
CAST(SUM(edit_count) as BIGINT) as team_edits
FROM '../changeset_data/year=*/month=*/*.parquet'
WHERE organised_team IS NOT NULL
GROUP BY year, month
)
SELECT
mt.months,
mt.total_contributors as "Total Contributors",
COALESCE(mot.team_contributors, 0) as "Organised Team Contributors",
mt.total_edits as "Total Edits",
COALESCE(mot.team_edits, 0) as "Organised Team Edits",
ROUND((COALESCE(mot.team_contributors, 0) * 100.0) / mt.total_contributors, 2) as "Percent Contributors from Organised Teams",
ROUND((COALESCE(mot.team_edits, 0) * 100.0) / mt.total_edits, 2) as "Percent Edits from Organised Teams"
FROM monthly_total mt
LEFT JOIN monthly_organised_team mot ON mt.year = mot.year AND mt.month = mot.month
ORDER BY mt.year, mt.month
""").df()
util.show_figure(
[
util.FigureConfig(
title="Percentage of Edits from Organised Teams",
label="Edits Percentage",
x_col="months",
y_col="Percent Edits from Organised Teams",
y_unit_hover_template="%",
query_or_df=df,
),
util.FigureConfig(
title="Monthly Edits from Organised Teams",
label="Edits",
x_col="months",
y_col="Organised Team Edits",
query_or_df=df,
),
util.FigureConfig(
title="Percentage of Contributors from Organised Teams",
label="Contributors Percentage",
x_col="months",
y_col="Percent Contributors from Organised Teams",
y_unit_hover_template="%",
query_or_df=df,
),
util.FigureConfig(
title="Monthly Contributors from Organised Teams",
label="Contributors",
x_col="months",
y_col="Organised Team Contributors",
query_or_df=df,
),
]
)
# Top 10 organised teams by contributors
df_top10 = duckdb.sql("""
WITH top_organised_teams AS (
SELECT organised_team
FROM (
SELECT
organised_team,
SUM(edit_count) as total_edits
FROM '../changeset_data/year=*/month=*/*.parquet'
WHERE organised_team IS NOT NULL
GROUP BY organised_team
ORDER BY total_edits DESC
LIMIT 10
)
),
user_first_appearance AS (
SELECT
user_name,
year,
month,
organised_team,
ROW_NUMBER() OVER (PARTITION BY user_name ORDER BY year, month) as rn
FROM (
SELECT DISTINCT user_name, year, month, organised_team
FROM '../changeset_data/year=*/month=*/*.parquet'
WHERE organised_team IN (SELECT organised_team FROM top_organised_teams)
)
),
first_appearances AS (
SELECT user_name, year, month, organised_team
FROM user_first_appearance
WHERE rn = 1
),
monthly_contributors AS (
SELECT
year,
month,
CONCAT(year, '-', LPAD(CAST(month as VARCHAR), 2, '0')) as months,
organised_team,
COUNT(DISTINCT user_name) as "Contributors",
CAST(SUM(edit_count) as BIGINT) as "Edits"
FROM '../changeset_data/year=*/month=*/*.parquet'
WHERE organised_team IN (SELECT organised_team FROM top_organised_teams)
GROUP BY year, month, organised_team
),
monthly_new_contributors AS (
SELECT
year,
month,
organised_team,
COUNT(DISTINCT user_name) as "New Contributors"
FROM first_appearances
GROUP BY year, month, organised_team
)
SELECT
mc.months,
mc.organised_team,
mc."Contributors",
COALESCE(mnc."New Contributors", 0) as "New Contributors",
mc."Edits"
FROM monthly_contributors mc
LEFT JOIN monthly_new_contributors mnc ON mc.year = mnc.year AND mc.month = mnc.month AND mc.organised_team = mnc.organised_team
ORDER BY mc.year, mc.month, mc.organised_team
""").df()
util.show_figure(
[
util.FigureConfig(
title="Monthly Edits by Top 10 Organised Teams",
label="Edits",
x_col="months",
y_col="Edits",
group_col="organised_team",
query_or_df=df_top10,
),
util.FigureConfig(
title="Monthly Contributors by Top 10 Organised Teams",
label="Contributors",
x_col="months",
y_col="Contributors",
group_col="organised_team",
query_or_df=df_top10,
),
util.FigureConfig(
title="Monthly New Contributors by Top 10 Organised Teams",
label="New Contributors",
x_col="months",
y_col="New Contributors",
group_col="organised_team",
query_or_df=df_top10,
),
]
)
query = """
WITH organised_team_totals AS (
SELECT
organised_team as "Organised Team",
CAST(SUM(edit_count) as BIGINT) as total_edits_all_time,
CAST(COUNT(DISTINCT user_name) as BIGINT) as total_contributors_all_time
FROM '../changeset_data/year=*/month=*/*.parquet'
WHERE organised_team IS NOT NULL
GROUP BY organised_team
),
yearly_metrics AS (
SELECT
d.year,
d.organised_team as "Organised Team",
CAST(SUM(d.edit_count) as BIGINT) as "Edits",
CAST(COUNT(DISTINCT d.user_name) as BIGINT) as "Contributors"
FROM '../changeset_data/year=*/month=*/*.parquet' d
WHERE d.organised_team IS NOT NULL
GROUP BY d.year, d.organised_team
)
SELECT
ym.year,
ym."Organised Team",
ym."Edits",
ym."Contributors",
ott.total_edits_all_time as "Total Edits",
ott.total_contributors_all_time as "Total Contributors"
FROM yearly_metrics ym
JOIN organised_team_totals ott ON ym."Organised Team" = ott."Organised Team"
ORDER BY year DESC, "Edits" DESC
"""
df_all = duckdb.sql(query).df()
table_configs = [
util.TableConfig(
title="Edits Per Organised Team by Year",
label="Edits",
query_or_df=df_all,
x_axis_col="year",
y_axis_col="Organised Team",
value_col="Edits",
center_columns=["Rank", "Organised Team"],
sum_col="Total Edits",
),
util.TableConfig(
title="Contributors Per Organised Team by Year",
label="Contributors",
query_or_df=df_all,
x_axis_col="year",
y_axis_col="Organised Team",
value_col="Contributors",
center_columns=["Rank", "Organised Team"],
sum_col="Total Contributors",
),
]
util.show_tables(table_configs)
| Rank | Organised Team | 2007 | 2008 | 2009 | 2010 | 2011 | 2012 | 2013 | 2014 | 2015 | 2016 | 2017 | 2018 | 2019 | 2020 | 2021 | 2022 | 2023 | 2024 | 2025 | Total Edits |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | Meta | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 78,815 | 4,296,035 | 20,247,234 | 28,957,510 | 50,673,799 | 83,060,907 | 51,973,945 | 25,494,310 | 1,074,076 | 1,431,748 | 267,288,379 |
| 2 | Kaart | 0 | 22,922 | 7,559 | 364,177 | 976,391 | 730,863 | 780,037 | 623,276 | 1,509,967 | 6,907,406 | 7,390,957 | 8,620,818 | 21,691,873 | 28,594,458 | 19,554,990 | 17,457,242 | 14,491,270 | 10,149,722 | 8,054,283 | 147,928,211 |
| 3 | Apple | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 601,578 | 3,974,945 | 13,770,839 | 17,215,025 | 8,878,281 | 13,050,921 | 10,308,898 | 5,385,095 | 1,893,899 | 75,079,481 |
| 4 | Amazon | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 68 | 1,171,512 | 15,006,820 | 29,407,768 | 19,940,677 | 1,456,200 | 1,034,876 | 76,744 | 99,663 | 68,194,328 |
| 5 | Mapbox | 0 | 0 | 45,339 | 130,377 | 336,422 | 1,812,554 | 2,975,135 | 5,001,072 | 10,364,605 | 7,176,557 | 6,020,903 | 5,478,908 | 1,058,384 | 1,549,755 | 1,151,670 | 1,848,191 | 1,427,806 | 1,787,103 | 3,532,847 | 51,697,628 |
| 6 | Microsoft | 0 | 0 | 846 | 7,795 | 0 | 184 | 0 | 0 | 0 | 987 | 44,465 | 3,308,373 | 9,463,749 | 6,588,507 | 7,790,014 | 2,157,361 | 2,245,106 | 933,667 | 2,841,323 | 35,382,377 |
| 7 | DigitalEgypt | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 7,815 | 4,835,241 | 4,385,173 | 3,475,331 | 4,657,479 | 4,054,066 | 3,732,908 | 1,988,295 | 27,136,308 |
| 8 | TomTom | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 13,356 | 904 | 14 | 256 | 5,163,115 | 5,383,053 | 5,994,057 | 5,209,686 | 4,006,421 | 25,770,862 |
| 9 | Grab | 0 | 0 | 0 | 0 | 0 | 0 | 61 | 10 | 360,575 | 158,382 | 1,122,025 | 847,285 | 3,077,576 | 2,958,667 | 8,916,251 | 3,993,110 | 538,887 | 377,096 | 607,807 | 22,957,732 |
| 10 | GeoCompas | 0 | 0 | 0 | 0 | 23,957 | 1,421,771 | 2,478,856 | 2,860,814 | 3,100,322 | 1,768,042 | 582,325 | 1,756,308 | 580,203 | 456,227 | 99,606 | 844,325 | 967,220 | 730,673 | 950,311 | 18,620,960 |
| 11 | Lyft | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 18,674 | 924,763 | 351,377 | 333,234 | 1,668,703 | 2,370,224 | 2,255,647 | 1,238,747 | 9,161,369 |
| 12 | VK_Maps | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 19 | 3,157 | 19,605 | 108,003 | 1,183,951 | 1,390,851 | 1,925,937 | 1,657,395 | 811,676 | 7,100,594 |
| 13 | Ola | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 381,080 | 3,535,451 | 1,838,614 | 625,017 | 6,380,162 |
| 14 | Lightcyphers | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 792,152 | 2,358,928 | 1,790,772 | 332,143 | 38 | 169 | 3,765 | 8 | 5,277,975 |
| 15 | Uber | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 15 | 3,313,575 | 651,199 | 84,620 | 18,454 | 4,134 | 1,415 | 3,258 | 2,303 | 4,078,973 |
| 16 | Wildberries Geo Team | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 107 | 9,810 | 95,944 | 654,015 | 599,785 | 840,244 | 721,364 | 871,917 | 3,793,186 |
| 17 | Telenav | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 58,334 | 303,600 | 892,891 | 1,053,569 | 384,426 | 105,963 | 50,794 | 70,937 | 1,696 | 2 | 0 | 2,922,212 |
| 18 | FixMyCity | 12 | 0 | 0 | 0 | 0 | 0 | 2,988 | 93,720 | 1,419 | 69,178 | 32,469 | 99,973 | 19,132 | 187,495 | 488,560 | 596,890 | 312,207 | 323,420 | 412,018 | 2,639,481 |
| 19 | Neshan | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 11 | 34 | 13 | 112,540 | 9 | 506,381 | 481,299 | 198,237 | 479,892 | 479,234 | 298,715 | 1,003 | 2,557,368 |
| 20 | Bolt | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 76,244 | 364,645 | 608,904 | 177,867 | 13,667 | 7,988 | 1,249,315 |
| 21 | Ozon | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 154 | 0 | 0 | 0 | 0 | 0 | 34,748 | 1,211,485 | 1,246,387 |
| 22 | Wonder | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 25,983 | 88,313 | 79,845 | 215,450 | 144,224 | 69,255 | 85,399 | 0 | 0 | 708,469 |
| 23 | Snapp | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1,447 | 0 | 44,429 | 166,913 | 52,062 | 83,623 | 98,455 | 104,044 | 64,201 | 25,311 | 640,485 |
| 24 | OpenSidewalks | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 18,654 | 80,592 | 10,728 | 88,443 | 196,028 | 130,770 | 105,387 | 630,602 |
| 25 | Rocketdata.io | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 11,827 | 71,556 | 140,653 | 178,608 | 154,610 | 53,745 | 610,999 |
| 26 | Snap | 0 | 0 | 0 | 0 | 211 | 914 | 645 | 526 | 10,196 | 65,937 | 23,805 | 8,679 | 34,762 | 34,214 | 325,971 | 10,619 | 422 | 344 | 2,981 | 520,226 |
| 27 | Graphmasters | 0 | 0 | 0 | 0 | 31 | 0 | 0 | 0 | 74 | 35 | 48 | 1,081 | 50,687 | 283,072 | 22,588 | 35,234 | 37,476 | 27,312 | 30,379 | 488,017 |
| 28 | Stackbox | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 4 | 0 | 293,886 | 159,794 | 4,376 | 20,409 | 478,469 |
| 29 | TIDBO | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 153,262 | 305,050 | 8,585 | 0 | 3,085 | 6,445 | 40 | 0 | 476,467 |
| 30 | TfNSW | 0 | 0 | 7 | 0 | 7 | 673 | 825 | 1,416 | 2,312 | 8,747 | 9,607 | 30,403 | 76,672 | 26,235 | 88,297 | 81,260 | 31,329 | 35,051 | 55,403 | 448,244 |
| 31 | NextBillion.AI | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 401,141 | 30 | 10 | 0 | 0 | 0 | 401,181 |
| 32 | AMAT | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 391 | 106 | 9 | 14,464 | 1,522 | 29,674 | 179,036 | 60,883 | 8,193 | 2,793 | 297,071 |
| 33 | Kontur | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2,632 | 282,941 | 766 | 0 | 0 | 286,339 |
| 34 | Geovelo | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 19,937 | 34,283 | 36,104 | 18,496 | 21,500 | 20,491 | 43,063 | 35,802 | 54,401 | 284,077 |
| 35 | Swiggy | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 695 | 7,196 | 207 | 1,021 | 111,108 | 79,923 | 26,781 | 226,931 |
| 36 | NNG | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 945 | 150,374 | 33,036 | 184,355 |
| 37 | Expedia | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 25,618 | 57,852 | 69,542 | 4,141 | 379 | 157,534 |
| 38 | Digiroad | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 905 | 56,027 | 1 | 0 | 0 | 2,067 | 44 | 0 | 59,044 |
| 39 | AppLogica | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 30,001 | 0 | 0 | 0 | 30,001 |
| 40 | GOAT | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 165 | 356 | 23,845 | 1,375 | 820 | 958 | 198 | 354 | 0 | 28,071 |
| 41 | Getpin | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 5,219 | 3,905 | 906 | 10,030 |
| 42 | WIGeoGIS | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 517 | 127 | 150 | 285 | 159 | 459 | 221 | 663 | 327 | 301 | 55 | 3,264 |
| 43 | Balad | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 8 | 2,649 | 0 | 29 | 18 | 18 | 0 | 0 | 2,722 |
| 44 | Komoot | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 142 | 400 | 173 | 122 | 443 | 616 | 1,896 |
| 45 | Gojek | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1,185 | 32 | 0 | 56 | 55 | 1,328 |
| 46 | TeleClinic | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 92 | 87 | 74 | 255 |
| 47 | Blitzer.de | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 27 | 99 | 104 | 230 |
| 48 | DINAclub | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 71 | 71 |