earthUI is a graphical user interface for the R
earth package, which implements Multivariate Adaptive
Regression Splines (MARS). It runs as a local Shiny application — no
login, no server, no accounts. You launch it from R, import a dataset
(CSV or Excel), configure your model, and fit it interactively.
When you launch earthUI, a Purpose radio button at the top of the sidebar lets you choose one of three modes:
earthUI supports international number, date, and CSV formatting conventions through a country-based locale system. The Country dropdown in Section 1 of the sidebar (below the file upload) selects a preset for 31 supported countries. Each preset configures:
,) for
US/UK/Japan or semicolon (;) for most of Europe, where the
comma is used as a decimal mark..) or comma
(,).Below the country selector, four override dropdowns let you change individual settings without switching countries:
When you change the country, all overrides reset to that country’s defaults. Changing an override only affects that one setting.
Click Save as my default to store your locale preferences globally. These defaults apply to all future sessions regardless of which data file you load. Per-file settings (target, predictors, parameters) are saved separately in the browser’s local storage, but locale defaults persist across all files via an SQLite database.
For real estate workflows, your input data typically comes from an
MLS export. earthUI accepts CSV and Excel files. On import, column names
are automatically converted to snake_case, e.g. “Area ID”
gets converted to “area_id”. The CSV separator and decimal mark used
during import are determined by the locale settings (see “Locale &
Regional Settings” above).
The full appraisal workflow (RCA + Sales Grid) benefits from these columns:
| Column | Special Type | Purpose |
|---|---|---|
| Sale Price (or equivalent wording) | (target) | Response variable |
| Contract Date | contract_date |
Computes sale_age from effective date |
| Listing Date | listing_date |
Fallback DOM = contract date - listing date |
| Days on Market | dom |
Displayed in Sales Grid |
| Concessions | concessions |
Net SP = Sale Price - Concessions |
| Living Area (SF) | living_area |
Per-SF residuals (residual_sf,
cqa_sf) |
| Lot Size | lot_size |
Grouped in “Site Size” row |
| Site Dimensions | site_dimensions |
Grouped with lot size |
| Latitude | latitude |
Rounded to 3 dp; proximity calc; Location group |
| Longitude | longitude |
Rounded to 3 dp; proximity calc; Location group |
| Area ID | area |
Grouped in “Location” row |
| Actual Age | actual_age |
Grouped in “Age” row |
| Effective Age | effective_age |
Grouped with actual age |
| Address | display_only |
Shown in grid; excluded from model |
Spreadsheet column names can be in a foreign language, the “special” names are in English so that the R program can give them special treatment. Otherwise, the given column names show up in the regression models, graphs and, if doing appraisals, the Intermediate Sales Grid.
Not all columns are required. earthUI adapts — if a column is missing, the corresponding feature is simply omitted. However, that being said, for real estate pricing models certain columns are highly recommended to achieve acceptable fit:
“Sale Age,” which is the number of days between the contract sale date and the effective date of the appraisal or analysis. If multi-year sales history is being used, especially for periods over 5 years, sale_age often plays a central role in estimating the sale price. In fact it is often so important that without it, earthUI fails to provide any model at all.
“Living Area” which also goes by names such as “Living Sqft,” “GLA” (gross living area) and so on. This is also another leading determinant of sale price.
“Total Bath Count” is the total number of full, quarter, half and 3/4 bathrooms. For example, two full baths and one half-bath would be a value of 2.5.
“Garage Bays” or “Garage Area” — the number of garage spaces or the garage square footage.
“Lot Size” — the land area of the property, typically in square feet or acres.
“Longitude,” “Latitude,” and if available “Area ID.” Adjustments for these will be combined under a single Location adjustment in the Sales Grid.
2025-06-15).In Appraisal mode, row 1 must be the subject property. In Market mode, placing the subject in row 1 is optional (use the “Skip first row” checkbox). In General mode, all rows are treated equally.
Each column is listed with:
In appraisal and market modes, each predictor can be assigned a special type:
Date & Time:
contract_date — triggers sale_age
computationlisting_date — fallback for DOM calculationdom — Days on Market columnMonetary:
concessions — used in Net SP formula (Sale Price -
Concessions)Size & Location:
latitude / longitude — rounded to 3 dp;
proximity and Location grouparea — grouped with lat/lon in Location rowliving_area — enables per-SF residualslot_size / site_dimensions — grouped in
Site Size rowAge:
actual_age / effective_age — grouped in
Age rowDisplay:
display_only — in exports but excluded from model
(multiple allowed)Only one column per special type (except display_only).
A blue badge shows the assigned type next to each variable name.
After fitting, download an Excel file with predictions and
diagnostics. This output is used in Step 7 (RCA) to assign a CQA
(Condition/Quality/Appeal) rating to the subject property. The output is
sorted by residual_sf and cqa_sf to help you
assess where the subject falls in the ranking. If the model is good
quality, then the properties should be ranked from lowest appealing to
most appealing based on residual features that did not go into the
regression. The middle value should be approximately 0, the lower half
negative values and the upper half positive values. You should find the
worst quality homes, or “fixers” near the bottom of the ranking and the
nicest homes at the top. There will usually be exceptions for anomalies
such as foreclosures, short sales, probate (inheritance related) sales,
and quick sales needed for job change or other reasons.
Investigation of anomalies usually turns up a pertinent reason for the
price anomaly.
| Column | Description |
|---|---|
est_<target> |
Model prediction (e.g.,
est_sale_price) |
residual |
Actual - predicted |
cqa |
Comparative Quality Analysis score (0-10 scale) |
residual_sf |
Residual / living area (if designated) |
cqa_sf |
CQA calculated from ranking via residual_sf |
<var>_contribution |
Per-g-function contribution |
basis |
Intercept value contribution (same for all properties) |
calc_residual |
Verification column |
The ranking columns are placed leftmost: residual_sf,
cqa_sf, residual, cqa. Excel
formatting:
residual_sf — numeric, 2 decimal placescqa_sf — numeric, 2 decimal placesresidual — numeric, 0 decimal placescqa — numeric, 2 decimal placesCQA ranks each row’s residual against all others on a 0–10 scale:
In appraisal/market modes, rows are sorted by
residual_sf descending.
On every successful fit with degree <= 2, earthUI
automatically saves the full result object as an .rds file
to the Project Output Folder. The filename follows the pattern
<datafile>_earthUI_result_<YYYYMMDD_HHMMSS>.rds.
This file can be loaded by mgcvUI (a companion Shiny
app for GAM modeling) using readRDS(). mgcvUI uses the
earth model’s knot locations and basis functions as starting points for
GAM smooth terms, enabling a seamless transition from MARS to GAM
modeling.
Models with degree > 2 are skipped because mgcvUI
only supports pairwise interactions. A manual Export for
mgcvUI button is also available in the sidebar for on-demand
export.
| Column | Description |
|---|---|
subject_value |
Model prediction + interpolated residual |
<var>_adjustment |
Subject contribution - comp contribution |
residual_adjustment |
Subject residual - comp residual |
net_adjustments |
Sum of all adjustments |
gross_adjustments |
Sum of absolute adjustments |
adjusted_sale_price |
Comp sale price + net adjustments |
The Sales Grid is a multi-sheet Excel workbook with the subject and
selected comparables in a structured format. Excel formulas compute
adjustments and adjusted sale prices. Output:
SalesGrid_<timestamp>.xlsx.
A modal dialog shows:
Each sheet has 20 columns: subject + 3 comps (5 columns each). Rows from top to bottom:
Sheets are protected. Only the residual feature VC input cells (light yellow background) under CQA|Residual are unlocked for appraiser entry. All formulas, data values, and labels are locked.
Three formats via Quarto:
.docx for editing and
distributionReports include: dataset description, model specification, allowed interactions, summary metrics, model equation, coefficients, variable importance, g-function plots, correlation matrix, diagnostics, ANOVA, and raw earth output.
earthUI includes a demo MLS dataset for exploring the appraisal workflow. Load it with:
demo_file <- system.file("extdata", "Appraisal_1.csv", package = "earthUI")
df <- import_data(demo_file)Or import it directly through the Shiny app file upload.
The file contains 1,502 residential sales (plus 1 subject property in row 1) from a simulated MLS export. The data represents single-family home sales in a multi-area market with a range of property sizes, ages, and locations.
This is not real data, but is based on a realistic neighborhood in Northern California. All identification information has been altered or removed.
| Column | Type | Special Type | Description |
|---|---|---|---|
weight |
numeric | — | Observation weight (0 = exclude from fitting) |
id |
numeric | display_only |
Internal record ID |
property_id |
numeric | display_only |
MLS property identifier |
listing_id |
character | display_only |
MLS listing number |
parcel_number |
character | display_only |
County assessor parcel number (APN) |
street_address |
character | display_only |
Property address |
city_name |
character | display_only |
City |
postal_code |
character | display_only |
ZIP code |
county_name |
character | display_only |
County |
contract_date |
Date | contract_date |
Sale contract date (computes
sale_age) |
sale_age |
numeric | — | Days from contract date to effective date (pre-computed) |
coe_date |
Date | display_only |
Close of escrow date |
listing_status |
character | display_only |
Listing status (e.g., “Sold”) |
sale_price |
numeric | (target) | Sale price — response variable |
rent |
numeric | — | Monthly rent (for multi-target models) |
list_price |
numeric | display_only |
Listing price |
original_list_price |
numeric | display_only |
Original listing price |
living_sqft |
numeric | living_area |
Gross living area in square feet |
beds_total |
integer | — | Number of bedrooms |
baths_total |
numeric | — | Total bath count (e.g., 2.5 = 2 full + 1 half) |
lot_size |
numeric | lot_size |
Lot size in square feet |
area_id |
integer | area |
MLS area identifier |
area_text |
character | display_only |
Area name |
age |
numeric | actual_age |
Property age in years |
year_built |
integer | display_only |
Year of construction |
latitude |
numeric | latitude |
Latitude (rounded to 3 dp for model) |
longitude |
numeric | longitude |
Longitude (rounded to 3 dp for model) |
latitude6 |
numeric | display_only |
Full-precision latitude |
longitude6 |
numeric | display_only |
Full-precision longitude |
garage_spaces |
integer | — | Number of garage bays |
fp_count |
integer | — | Number of fireplaces |
no_of_stories |
numeric | — | Number of stories |
style |
character | — | Architectural style |
view |
character | — | View type (e.g., “Neighborhood”, “Hills”) |
days_on_market |
integer | dom |
Days on market |
listing_date |
Date | listing_date |
Listing date |
sale_concessions |
numeric | concessions |
Seller concessions |
earthUI::launch()Appraisal_1.csv via the file uploadsale_price as the targetsale_age, living_sqft,
baths_total, lot_size, area_id
(as factor), age, latitude,
longitude, garage_spaces