Linguistic Landscapes
Language in Culture and Community
Spoken language has consistently proven a difficult entity to research because it——like a cultural value——is highly untangible.
This intangible component of society is referred to as a ‘mentifact.’
Mentifact (noun): the intangible, ideological components of a culture such as its shared ideas, values, beliefs, attitudes, preferences, and knowledge. A mentifact is one of three subcategories that can be combined to sum up the traits of a culture (Three Components of Culutre). These three components of culture include mentifacts, sociofacts, and artifacts.
Methods have been developed to study spoken language, but all of these methods involve quantifying the concrete, physical component of spoken language, which is sound, but sound is transient and bound completely to the construct of time. There is, however, a more persistent manifestation of language: the written word.
Writing, unlike spoken language, is an artifact of society. It is tangible. It can stay static across time, and it can quite literally be held, etched, and erased.
The sum of the writing in an environment is referred to as a linguistic landscape.
Linguistic landscapes are often studied because——with the proper analysis——they are reflections of the diversity, culture, practices, perceptions, and values of a society. Linguistic landscapes are defined as “‘The language of public road signs, advertising billboards, street names, place names, commercial shop signs, and public signs on government buildings combines to form the linguistic landscape of a given territory, region, or urban agglomeration’” (Landry & Bourhis,1997, p. 25, qtd. in SemiotiX, 2020).
Much reseach has been done into linguistic landscapes, and much research has been done into humanistic geography and the distribution of spoken language, but less research has been done into geosemiotics and geographical distributions of written language. Although linguistic landscapes likely function differently from spoken language, there are many parallels to be drawn. This paper proceeds with the hopefully not too optimistic assumption that linguistic theories that have been applied exclusively to spoken language are at least somewhat applicable to the patterns and behaviors of linguistic landscapes.
LLBert: Linguistic Landscape Coordinate Regressor
LLBert is an experiment in using natural language processing to estimate the geographic coordinates associated with text found on signs. The project README documents its data, model, workflow, and interactive predictor.
LLBert: Linguistic Landscape Coordinate Regressor
This project fine-tunes a sentence-transformer model to predict a latitude and longitude pair from text observed on signs at an intersection.
The name LLBert is shorthand for Linguistic Landscape BERT (and, conveniently, Latitude Longitude BERT), a playful reference to the inputs and outputs of the sentence-transformer encoder at the center of the project.
The model is an experiment in predicting geographic coordinates from linguistic Landscape data, or the language people encounter in public space.
What is a Linguistic Landscape?
In simple terms, a linguistic landscape is the sum of all of the written language in an environment.
Writing, unlike spoken language, is an artifact of society. It extends across time.
The sum of the writing in an environment (especially a public environment) is referred to as a linguistic landscape.
Linguistic landscapes are often studied because—with the proper analysis—they are reflections of the diversity, culture, practices, perceptions, and values of a society.
Linguistic landscapes can be further defined as:
“‘The language of public road signs, advertising billboards, street names, place names, commercial shop signs, and public signs on government buildings combines to form the linguistic landscape of a given territory, region, or urban agglomeration’” (Landry & Bourhis,1997, p. 25, qtd. in SemiotiX, 2020).
As an example, let’s look at an image of this sign from the University of Colorado Anschutz:
There is a lot of data, or information, in this photo. Here, we can see the sign itself, pavement, a mulched garden bed, a road, buildings in the back, and more.
But if we were to ask: “what linguistic landscape data is in this image?” we could likely transcribe it as:
CU University of Colorado ANSCHUTZ MEDICAL CAMPUS ANSCHUTZ HEALTH SCIENCES BUILDING 1890 NORTH REVER COURT
So, the “linguistic landscape” data of this view of this region contains that information.
For further clarification, let’s look at another sign on the building:
Here, we can read two pieces of linguistic data. First, there is the sign itself, which reads:
ANSCHUTZ HEALTH SCIENCES BUILDING
Then, although they are flipped in orientation, there are the two exit signs, which read:
EXIT EXIT
There is also a subtle reflection of text that appears to read
ANSCHUTZ HEALTH SCIENCES VATORS
Which presumably mentions something about the elevators.
So, if we were to hypothetically say this was all of the linguistic landscape text outside this building (it’s not, but for example), we could say the sum of the linguistic landscape outside of this building was:
CU University of Colorado ANSCHUTZ MEDICAL CAMPUS ANSCHUTZ HEALTH SCIENCES BUILDING 1890 NORTH REVER COURT ANSCHUTZ HEALTH SCIENCES BUILDING EXIT EXIT ANSCHUTZ HEALTH SCIENCES VATORS
Notice that there is repetition, and that is good information. Repetition is very common in languauage.
Much reseach has been done into linguistic landscapes, and much research has been done into humanistic geography and the distribution of spoken language, but less research has been done into geosemiotics and geographical distributions of written language.
This project aims to better understand whether a Machine Learning method of Natural Language Processing (NLP) can accurately predict a geographical coordinate set (latitude, longitude) based on the linguistic landscape data surrounding an intesrsection.
For the time being, the project will focus on the greater Denver Metro Area.
Inspiration for Project
In high school, I loved playing a game called Hostage. The game began with two teams, with one designated home base.
Each team would have two sets of people: drivers/navigators, and hostages.
At the beginning of the game, you would set a timer for generally 10-20 minutes. Each team would have that much time to take the other team’s players to an unfamiliar location and drop them off.
The dropped-off hostages then had to work together to figure out where they were and, without using their GPS apps, call their drivers/navigators and explain to them ahd to get to them to pick them up.
Whichever team made it back to home base with their full team first won.
The game turned navigation into a kind of collaborative investigation. Street names, businesses, and public signs were some of the most useful clues because they gave us concrete information about our surroundings. A road sign could tell us the name of a place, a business could identify a neighborhood or intersection, and a cluster of signs could suggest the language, culture, or commercial character of an area. I was relying on the linguistic landscape around me to orient myself, even though I did not have that vocabulary for the process at the time.
More recently, while playing the GeoGuessr app, I realized that one of my primary methods for predicting my location was also based on linguistic landscape data. I would look at street names, storefronts, advertisements, public notices, and other written signs, then combine those observations with the visual character of the surrounding area. Recognizing this pattern made me reflect on my own cognitive processes: how was I turning fragments of written language into a geographic intuition?
These experiences led me to wonder whether linguistic data alone could be enough to predict geographical location.
LLBert is an attempt to investigate that question computationally. Rather than treating the model only as a geolocation system, I see it as a model of cognitive analysis: a way to examine whether the kinds of linguistic clues people use to orient themselves can be represented, learned, and used to estimate where a scene might be located.
Model Training Data
The raw dataset is expected at training_data_raw.csv. It may include the
pandas-exported index column; the preprocessing script only uses:
intersectiontext_on_sign_exactlatitudelongitude
The project can also build this raw dataset directly from the source
spreadsheets. Put the exported workbooks in ll_sheets/ and place the
intersection coordinate lookup at coordinate_dict10.xlsx. The lookup’s DMS
coordinate strings are converted to decimal latitude and longitude during
aggregation.
Workflow
From source spreadsheets
Run the complete data-preparation flow from the project root:
source .venv/bin/activate
python prepare_training_data.py \
--from-ll-sheets \
--sheet-dir ll_sheets \
--coord-file coordinate_dict10.xlsx \
--input-file training_data_raw.csv \
--output-file training.csv
This command reads every .xlsx file in ll_sheets/, cleans and combines the
sign records, joins each intersection to coordinate_dict10.xlsx, and writes
the two training stages:
training_data_raw.csv: cleaned sign-level records with coordinates.training.csv: deterministic bootstrap bags used by the model trainer.
The default command creates 100 samples per intersection, with 8 sign texts in
each sample. Use --bag-size, --samples-per-intersection, and --seed to
change those settings. To reuse an existing raw CSV instead, omit
--from-ll-sheets and run the preparation command below.
Prepare bootstrapped training rows:
source .venv/bin/activate
python prepare_training_data.py --seed 1992 --bag-size 5 --samples-per-intersection 50
This writes training.csv with rows shaped like:
intersection,sample_id,text,latitude,longitude,unique_sign_count,raw_sign_count
Each row is a deterministic bootstrap sample of sign texts from one intersection, joined into a single text field. This trains on “some signs seen at this coordinate” instead of one sign or every sign at that coordinate.
Train the model:
python train.py
Evaluate and write predictions:
python eval.py
This writes predictions.csv and a map-style diagnostic plot:

It also writes a coordinate calibration plot:

Or run the full pipeline:
make
Try the model in a web app
Once output/ contains a trained model, launch the interactive predictor:
make serve
Open prediction lets you enter a bundle of sign text, provide your own
latitude and longitude estimate, and compare it with LLBert’s prediction. The
Random round mode selects a held-out-style row from training.csv, hides
its coordinates, and scores both your guess and the model. The frontend is
plain HTML and JavaScript, served by FastAPI, so it can be embedded directly
in Hugo or deployed as a small app on its own.
Hosting and Hugo embedding
The recommended architecture is a static Hugo site plus this small FastAPI service. You have two deployment options:
- Direct Hugo integration: copy
web/index.htmlinto a Hugo page or shortcode, and setwindow.LLBERT_API_URLbefore the app script to the API’s HTTPS URL. - Subdomain: deploy the whole app and API together at something like
llbert.example.com, then embed that URL in Hugo with an iframe.
For a first deployment, Render or Fly.io are a better fit than a static host because the model needs Python, PyTorch, and a long-lived process:
- Push this repository to GitHub, including
app.py,web/,requirements.txt, and the trainedoutput/directory. - Configure the service command as
uvicorn app:app --host 0.0.0.0 --port $PORT. - Set
LLBERT_ALLOWED_ORIGINSto the Hugo site’s origin when the frontend is hosted separately.runtime.txtselects Python 3.10.
For a Hugo page, the smallest embed is:
<iframe
src="https://llbert.example.com"
title="LLBert linguistic landscape coordinate predictor"
loading="lazy"
style="width:100%; min-height:900px; border:0;"
></iframe>
The app reads LLBERT_MODEL_PATH, LLBERT_DATA_PATH, and
LLBERT_ALLOWED_ORIGINS when set, which is
useful for a container or another host. Keep the model service separate from
Hugo: Hugo is static, while prediction requires Python, PyTorch, and the
sentence-transformer model. The model’s predictions are approximate and should
not be treated as precise geolocation.
Command-line options and defaults
All of the project scripts accept command-line flags, and each one has a default value that is used when you do not pass an override. The defaults are intentionally documented here so it is clear which behavior can be customized.
prepare_training_data.py
Creates the bootstrapped training CSV from the raw sign data.
| Argument | Default | Description |
|---|---|---|
-i, --input-file | training_data_raw.csv | Raw pandas-exported CSV to read. |
-o, --output-file | training.csv | Prepared training dataset written by the script. |
--from-ll-sheets | False | Build the raw input from all .xlsx files in --sheet-dir and the coordinate workbook. |
--sheet-dir | ll_sheets | Directory containing source spreadsheet exports. |
--coord-file | coordinate_dict10.xlsx | Intersection-to-coordinate lookup workbook. |
--seed | 1992 | Random seed used for deterministic bootstrapping. |
--bag-size | 8 | Number of sign texts to combine into each training row. |
--samples-per-intersection | 100 | Number of bootstrap bags generated for each intersection. |
--separator | `" | “` |
Example:
python prepare_training_data.py \
--input-file training_data_raw.csv \
--output-file training.csv \
--seed 1992 \
--bag-size 5 \
--samples-per-intersection 50 \
--separator " | "
To rebuild both files from the source spreadsheets, use:
python prepare_training_data.py \
--from-ll-sheets \
--sheet-dir ll_sheets \
--coord-file coordinate_dict10.xlsx
train.py
Trains the sentence-transformer encoder and coordinate regression head.
| Argument | Default | Description |
|---|---|---|
--data-file | training.csv | Training dataset path. |
--output-path | output | Directory where model artifacts are written. |
--model-name | sentence-transformers/all-MiniLM-L6-v2 | Base sentence-transformer model to fine-tune. |
--device | None | Optional explicit device such as cpu, cuda, or mps; if omitted, CUDA is used when available and otherwise CPU is used. |
--seed | 1992 | Random seed for reproducibility. |
--epochs | 10 | Number of training epochs. |
--batch-size | 64 | Batch size for training. |
--num-workers | 2 | DataLoader worker processes. |
--save-every-epochs | 5 | Save the best checkpoint every N epochs (and at final epoch). |
--learning-rate | 1e-4 | Learning rate for the encoder. |
--head-learning-rate | 5e-2 | Learning rate for the coordinate head. |
--weight-decay | 0.001 | Weight decay for optimization. |
--test-size | 0.2 | Fraction of rows used for the validation/test split. |
--hidden-dim | 256 | Hidden dimension in the coordinate regressor. |
--dropout | 0.1 | Dropout used inside the regression head. |
--freeze-encoder | False | If set, only the coordinate head is trained and the encoder stays fixed. |
--freeze-transformer-layers | 0 | Freeze the first N transformer layers in the encoder. |
--freeze-attention | False | Freeze self-attention parameters while leaving other encoder parameters trainable. |
Example:
python train.py \
--data-file training.csv \
--output-path output \
--model-name sentence-transformers/all-MiniLM-L6-v2 \
--device cuda \
--epochs 20 \
--batch-size 32 \
--learning-rate 2e-5 \
--head-learning-rate 1e-2 \
--hidden-dim 512 \
--dropout 0.15
eval.py
Loads a trained model and writes predictions and diagnostics.
| Argument | Default | Description |
|---|---|---|
--data-file | training.csv | Dataset to score. |
--model-path | output | Directory containing the trained model artifacts. |
--output-file | predictions.csv | CSV path for predicted coordinates and error metrics. |
--plot-file | plots/prediction_map.png | Path to the map-style prediction error plot. |
--scatter-plot-file | plots/predicted_vs_actual.png | Path to the predicted-vs-actual scatter plot. |
--device | None | Optional explicit device override; otherwise CUDA is used when available, else CPU. |
--batch-size | 64 | Batch size used for inference. |
--seed | 1992 | Must match the training seed for the same test split. |
--test-size | 0.2 | Must match the training split size. |
Example:
python eval.py \
--data-file training.csv \
--model-path output \
--output-file predictions.csv \
--plot-file plots/prediction_map.png \
--scatter-plot-file plots/predicted_vs_actual.png \
--batch-size 128
generate_data.py
Generates city-distance data used for computing distances between cities.
| Argument | Default | Description |
|---|---|---|
-c, --country | US | Country code to use when searching cities. |
-w, --workers | 1 | Number of worker threads used for computation. |
-s, --chunk-size | 1000 | Batch size for chunking distance calculations. |
-o, --output-file | distances.csv | Output CSV path for generated distances. |
--shuffle | False | If set, shuffle the combinations before processing. |
Example:
python generate_data.py \
--country US \
--workers 4 \
--chunk-size 2000 \
--output-file distances.csv \
--shuffle
Outputs
training.csv: prepared bootstrapped dataset.output/: saved sentence-transformer encoder, coordinate head, and coordinate normalization metadata.predictions.csv: evaluation rows with predicted coordinates anderror_km.plots/prediction_map.png: actual vs predicted coordinates with line segments showing the prediction error.plots/predicted_vs_actual.png: predicted vs actual latitude and longitude scatter plots.
References
Ernst, P. (1969). The tongues of Italy: prehistory and history. Greenwood Press.
Google (2020). Google Maps. Google. https://www.google.com/maps
Huisman, J. L. A., Majid, A., & van Hout, R. (2019). The geographical configuration of a language area influences linguistic diversity. Public Libary of Science. 14(6).
Metro Denver (2020). Communities. MetroDenver Economic Development Coorporation. *http://www.metrodenver.org/do-business/communities/
SemiotiX (2020). The sociolinguisics of space and semiotic landscapes: An introduction. SemiotiX: A global information magazine. https://semioticon.com/semiotix/2013/05/the-sociolinguistics-of-space-and-semiotic-landscapes-an-introduction/
Trudgill, P. (2000). “Chapter 5: Language and Context,” Sociolinguistics: An introduction to language and society. (4th ed., pp. 81-104). Penguin Books.