Methodology & data
How every score is worked out
110
automatic tests
53 on the data, 57 on the website
0.94
ranking stability
1,000 random weightings, 1 = identical
0.93
lowest when one ingredient is removed
still almost the same ranking
5
decimals
the website's maths must match Python's
How each score is calculated
Concentration (Gini)
Are visits spread across the country, or piled into a few states? 0 = every state gets the same. 1 = one state gets everything.
- 1Sort the 16 states from fewest visitors to most.
- 2Give them weights from −15 (smallest) up to +15 (biggest), in steps of 2.
- 3Multiply each state's visitors by its weight and add everything up.
- 4Divide by (16 × total visitors).
Malaysia 2025
Gini = 0.294. The top 3 (Selangor, Kuala Lumpur, Perak) take 32.8% of 290.1M visits. The 8 least-visited states share only 29.8%. The Lorenz curve is the same thing drawn: the further it sags below the diagonal, the more uneven.Opportunity score
Which states have a lot to offer but few visitors? Opportunity = what it can offer − how visited it already is.
- 1Score every ingredient from 0 to 100: (state − lowest state) ÷ (highest − lowest) × 100.
- 2Counts (rooms, attractions, visitor measures) are logged first, so Kuala Lumpur's size does not flatten everyone else.
- 3Offer = average of 7 scores. Visited = average of 3. Equal weights unless you move the sliders.
- 4Opportunity = Offer − Visited. Above 0 is untapped, below 0 is crowded.
Johor 2025
Spare capacity (100 - occupancy %): (45.8 − 23.7) ÷ (60.6 − 23.7) × 100 = 59.9Accommodation supply (rooms)84.5Spare capacity (100 - occupancy %)59.9Spend per visitor (RM)43.5Average length of stay (nights)10.2Household basic amenities access (%)97.2Attractions, nature & heritage sites (OSM)91.8JomRasa Experience Score26.5Offer (average)59.1Share of national domestic visitors74.3Visitors per resident (intensity)0.0Visitors per km2 (density)24.7Visited (average)33.059.1 − 33.0 = +26.1, rank 2 of 16.Bottleneck Diagnoser
What holds a state back: getting there (access), being known (awareness), or places to stay (amenities)? Four ingredients each.
- 1For each ingredient, find the typical state: the median of the 16.
- 2Typical spread = the median distance from that median × 1.4826.
- 3Distance = (state − median) ÷ typical spread, limited to −3 … +3.
- 4Pillar score = 50 + (average of its 4 distances) × 50 ÷ 3. 50 = the typical state.
- 5Bottleneck = the lowest pillar, flagged only if it is below 50.
Johor 2025
Tourists from other states (%): (65.2 − 86.4) ÷ 14.3 = -1.48Awareness: average distance -0.57, so 50 + (-0.57 × 16.67) = 40.4Access 41.1 · Awareness 40.4 · Amenities 47.2. Bottleneck: Awareness.Room to grow
How many more visitors can the hotels that already exist take, without building anything?
- 1Spare room-nights = rooms × 365 × (75% − occupancy). The ceiling is yours to change in the Simulator.
- 2Room-nights one visitor needs = overnight share × paid accommodation share × nights ÷ 2 per room.
- 3Extra visitors = step 1 ÷ step 2.
Johor 2025
36,034 × 365 × (75% − 54.2%) = 2,735,701 spare room-nights0.54 × 0.30 × 2.18 ÷ 2 = 0.175 per visitor2,735,701 ÷ 0.175 = 15.6M extra visitorsSimulator
What changes if some visitors go to another state instead? A what-if calculator, not a forecast.
- 1Visitors moved = the crowded state's visitors × the chosen %.
- 2Split them across the destinations. None takes more than its room to grow; the overflow goes to the others.
- 3Gained = moved × destination's spend per visitor. Lost = moved × origin's spend per visitor. Net = gained − lost.
- 4Gini, top-3 share and hotel occupancy are recalculated.
10% of Selangor to Johor, Sarawak, Sabah
3.6M moved, all fit.RM 1.49bn gained − RM 1.46bn lost = +RM 26MGini 0.294 to 0.287.Traveller scores (JomRasa)
How do real travellers describe each state? The only part that uses AI, and only to label text.
- 1A ready-made model (Gemini 2.5 Flash Lite) tags each post from fixed lists: real trip or not, place, topic (1 of 11), negative / mixed / positive.
- 2The "real trip?" question is asked twice; a post is kept only on two yeses: 7,561 posts.
- 3Negative = 0, mixed = 50, positive = 100. Average per state and topic.
- 4Few mentions? The average is pulled towards the national average: (mentions × state average + k × national average) ÷ (mentions + k).
- 5Experience Score = average of the adjusted topic scores.
Johor
Safety: only 12 mentions averaging 62.5, adjusted to 50.5.Food: 208 mentions averaging 94.5, adjusted to 93.8 (plenty of evidence, so it hardly moves).Experience Score = 82.0 from 458 posts.Trip planner
- Places, eateries and hotels are real listings from Wikivoyage and OpenStreetMap. Descriptions are trimmed, never rewritten.
- A language model picks and orders places from that list only. Anything not on the list is dropped.
- Limits like "no pork" or "with kids" are enforced by our code before and after the model answers.
- Clock times, travel legs and the nearest hotel are calculated by us, never guessed by the model.
- If the model is down, a rule-based planner takes over: k-means groups sights into days, then the shortest route is found.
- When to go comes from ten years of daily rainfall (Open-Meteo, 2015-2024) for each town.
Which year each number is from
- Visitors, where tourists come from, hotel rooms and occupancy are from the year you pick.
- DOSM publishes state spending only up to 2023. For 2024 and 2025, spend per visitor and nights stayed are the 2023 figures, labelled on screen.
- Receipts for 2024 and 2025 are therefore estimates. 2023 is the fully matched year.
References
- Concentration: Gini and Lorenz curve, as used for tourism by Fernández-Morales et al. (2016) and Lau & Koo (2022).
- Opportunity: normalise-then-average composite index (OECD/JRC Handbook, 2008); visited side follows tourism intensity and density (McElroy & de Albuquerque; Eurostat).
- Bottleneck Diagnoser: Buhalis's (2000) destination "As". Small samples: empirical-Bayes shrinkage (Efron & Morris, 1975).
- Optional economic multiplier: Malaysian input-output range 1.20-1.82 (Mazumder et al., 2009). Off by default.
Data sources
| Source | Used for | Years | Level | Accessed |
|---|---|---|---|---|
| DOSM Domestic Tourism Survey 2025 (national workbook) | Visitors by state 2018-2025 (Table 9); tourists by origin × destination (Table 10); top destinations & districts (Tables 8A-8B); national key statistics | 2018-2025 | State | 2026-09-17 |
| DOSM Domestic Tourism Survey 2024 (national workbook) | 2017 visitors by state; 2024 origin × destination matrix | 2017-2024 | State | 2026-09-17 |
| DOSM Domestic Tourism Survey by State 2023 (16 workbooks) | Receipts, trips, spend per visitor / trip, length of stay, tourist vs excursionist split, transport mode, accommodation type, NAPIC hotel stock | 2017-2023 | State | 2026-09-17 |
| Tourism Malaysia - Paid Accommodation Survey (public Power BI) | Hotels & rooms by state; average occupancy rate by state and quarter; domestic & foreign hotel guests | 2018 - Q1 2026 | State | 2026-09-17 |
| data.gov.my / OpenDOSM - population_state | Mid-year population by state | 2015-2026 | State | 2026-09-17 |
| data.gov.my / OpenDOSM - HIES: hh_access_amenities, hh_income_state, hh_poverty_state | Piped water, sanitation, electricity access; household income; poverty | 2016-2024 | District / state | 2026-09-17 |
| data.gov.my / OpenDOSM - gdp_state_real_supply | Real GDP by state | 2016-2025 | State | 2026-09-17 |
| data.gov.my - arrivals_soe | Foreign arrivals by state of entry (context only - entry point, not destination; ends Oct 2024) | 2020-2024 | State | 2026-09-17 |
| geoBoundaries MYS ADM1 (simplified) | State boundaries | current | Polygon | 2026-09-17 |
| OpenStreetMap via Overpass API | Attractions, nature & heritage sites, airports with IATA codes, rail stations - assigned to states by point-in-polygon | current | Point | 2026-09-17 |
| Exa search API | Public travel blogs, forums and articles per state in Malay, English and Mandarin (TripAdvisor and Google Maps excluded); text passages only, no author data | recent | Text | 2026-09-17 |
| YouTube Data API v3 | Public comments on per-state travel videos; comment text only, no usernames or channel ids stored | recent | Text | 2026-09-17 |
Indicators behind each score
Potential index
- Accommodation supply (rooms)logTourism Malaysia PAS
- Spare capacity (100 - occupancy %)Tourism Malaysia PAS
- Spend per visitor (RM)DOSM DTS by state
- Average length of stay (nights)DOSM DTS by state
- Household basic amenities access (%)DOSM HIES / data.gov.my
- Attractions, nature & heritage sites (OSM)logOpenStreetMap
- JomRasa Experience ScoreJomRasa
Actual index
- Share of national domestic visitorslogDOSM DTS
- Visitors per resident (intensity)logDOSM DTS + population
- Visitors per km2 (density)logDOSM DTS + area
Pillar · Access
- Population within reach (distance-decayed)logDOSM population + coordinates
- Airports with IATA code within 100 kmOpenStreetMap
- Intercity / commuter rail stationslogOpenStreetMap
- Traveller sentiment: access & transportJomRasa
Pillar · Awareness
- Tourists from other states (%)DOSM DTS Table 10
- Diversity of origin states (1 - HHI)DOSM DTS Table 10
- Foreign share of hotel guests (%)Tourism Malaysia PAS
- Online travel mentions collectedlogJomRasa
Pillar · Amenities
- Rooms per 1,000 overnight touristslogTourism Malaysia PAS + DOSM
- Rooms per 1,000 residents (Defert-type)logTourism Malaysia PAS + DOSM
- Household basic amenities access (%)DOSM HIES
- Traveller sentiment: accommodation, food, cleanlinessJomRasa
Assumptions and limitations
- Access is proxy-based (distance-decayed population reach, airports with an IATA code within 100 km, rail stations). No open road, flight-frequency or travel-time data exist; great-circle distance understates the sea crossing to Sabah, Sarawak and Labuan.
- OpenStreetMap coverage is uneven between states; site counts are log-scaled and carry one-seventh of the Potential index by default.
- Hotel capacity covers registered paid accommodation in Tourism Malaysia's survey; homestays and short-term rentals outside it are not counted, so capacity is conservative.
- Labuan, Putrajaya and Perlis are very small units; their scores move a lot with small absolute changes. Read them with the sensitivity intervals.
- JomRasa scores come from public online text, not a representative survey. They are an indicator of traveller experience, never an official statistic.
- The trip planner covers only towns that travellers have documented on Wikivoyage, and coverage is uneven: Kuala Lumpur, Penang, Johor Bahru and Ipoh are rich, parts of Kelantan, Perlis and Terengganu are thin, especially for food. Opening hours and eateries change; the app says so and links every stop to a map. A short town is given fewer days rather than padded.