Visual Analytics · Tolerant-Pareto MCDA

From Idea to Prototype in an Afternoon:
Scaffolded, AI-Assisted Rapid Prototyping in Visual Analytics

Gennady Andrienko & Natalia Andrienko

Fraunhofer Institute IAIS, Sankt Augustin · City St George’s, University of London · Lamarr Institute for ML and AI

SoftSky is a tolerant approach to spatial multi-criteria decision analysis. It relaxes the Pareto frontier with a per-criterion tolerance — a soft sky — so that near-optimal options are admitted rather than discarded, and then groups the survivors into a few interpretable, named types — constellations. This page accompanies a Visualization Viewpoints article on how the method went from a long-held idea to a running prototype in an afternoon, using a workflow language (ATWL) as a design scaffold and an AI assistant as a build engine.

The ATWL workflow

The complete workflow — Context-Aware Tolerant-Pareto decision analysis (CATP) — is a graph of typed artifacts joined by transforms across seven stages, with refinement loops and feedback paths. Novelty-bearing steps are marked [NOVEL].

SoftSky — Tolerant-Pareto Workflow with Constellations (ATWL) Schematic with refinement loops and cross-loop feedback · dashed red = feedback (specification updates) machine human hybrid artifact specification knowledge data flow feedback STAGE 1 · SPATIAL FOCUSING D_offers 268k offers Compute distance, reach view F_distance · V_reach Fix spatial focus S_focus Select candidates D_cand STAGE 2 · REDUNDANCY-AWARE CRITERIA SELECTION Correlation & distribution views F_corr · V_attrs Choose criteria & directions S_criteria incl. distance STAGE 3 · UTILITY ELICITATION ⟳ L_utility · refine value functions until preferences are expressed Define utility functions over histograms · S_util Apply utilities F_util Utility views V_util Assess adequacy refine S_util STAGE 4 · UTILITY-SCALE TOLERANCE cross-wave duplicates in D_offers Estimate per-criterion noise optional · F_noise optional noise default Set tolerance fraction of utility scale S_tol NOVEL STAGE 5 · CONSTELLATIONS (NMF) — machine proposes, human names ⟳ L_context · iterate until constellations are interpretable and covering Propose groups NMF over levels · M_topics Name from terms F_ctx · top terms Edit & name constellations NOVEL S_ctx NOVEL Partition into constellations D_ctx · F_ctx_label Constellation views V_ctx · map + facets Assess constellations re-propose / re-edit STAGE 6 · TOLERANT DOMINANCE, RANKING & SENSITIVITY ⟳ L_rank · iterate until the frontier is informative and stable ε-tolerant dominance one global soft sky incl. distance · missing-value bounds NOVEL F_robust NOVEL F_front_status Map + ranking views V_rank Frontier stability view V_stab Assess frontier Adjust specifications S_tol · S_util · S_ctx inputs: S_criteria · F_util · S_tol · S_ctx · F_distance feedback to S_ctx feedback to S_tol feedback to S_util STAGE 7 · INTERPRETATION & DECISION Interpret trade-offs P_trade K_decision · robust shortlists + sensitivity
The complete ATWL workflow for SoftSky (CATP): typed artifacts and transforms across seven stages, with refinement loops and feedback from the frontier back to the settings.

The workflow supports staged spatial multi-criteria decision analysis over a large set of imperfect real-world options. The analyst first focuses the option space spatially (geo centre + distance threshold), then selects numeric criteria with redundancy awareness and defines utility functions over visualized value distributions. Two extensions of traditional MCDA follow. (1) Decision contexts: machine-proposed groupings (NMF / archetypal analysis) are translated into human-readable predicates, which the analyst edits into named, persistent, rule-based decision contexts (e.g., "studios", "family flats"); dominance is computed only within contexts, eliminating semantically meaningless cross-type domination. (2) Tolerant Pareto optimality: per-criterion tolerance thresholds are derived from measured data imperfection (value variation among cross-wave duplicate listings); the binary frontier is replaced by a graded robustness margin per option (the smallest tolerance change that flips its frontier membership), with optimistic/pessimistic bounding for records with missing values. Coordinated map / ranking / stability views support interactive sensitivity analysis over tolerances, utilities, and context definitions. The outcome is a per-context shortlist of robust options with explicit sensitivity statements and a cross-context comparison.

Show the complete workflow expressed in ATWL
workflow context-tolerant-pareto
template: characterise (distance)  visualise  generate-knowledge (spatial focus) 
    define-unit (spatial selection) 
    characterise (correlations)  visualise (distributions) 
    generate-knowledge (criteria choice) 
    loop(generate-knowledge (utility functions)  characterise (utilities) 
         visualise  assess) 
    characterise (noise estimation)  generate-knowledge (tolerances) 
    loop(model (group proposal)  abstract (rule description) 
         generate-knowledge (decision contexts)  define-unit (partition) 
         visualise  assess) 
    loop(characterise (tolerant dominance, robustness)  contextualise (map) 
         visualise  assess  generate-knowledge (adjust specifications)) 
    abstract (trade-off interpretation)  generate-knowledge (decision)
description: "Staged spatial MCDA over imperfect data: spatial focusing,
    criteria and utility elicitation, predicate-based decision contexts
    bridging machine grouping and human definition, and graded tolerant-Pareto
    ranking with data-grounded tolerances and interactive sensitivity analysis"

# ============================================================================
# INPUT: Rental offers and analyst focus
# ============================================================================

artifact D_offers : entities
  origin: given
  internal structure: elementary
  embedment: {set, space}
  features:
    - id: f_location
      value structure: atomic
      value type: spatial
      description: "Geographic position of the offered apartment"
    - id: f_numeric_attrs
      value structure: vector
      value type: numeric
      description: "Numeric attributes: base rent, total rent, service charge,
                    living space, number of rooms, floor, year constructed,
                    picture count, etc."
    - id: f_scrape_wave
      value structure: atomic
      value type: temporal
      description: "Scraping wave identifier (Sep 2018 / May 2019 / Oct 2019);
                    enables duplicate-based noise estimation"
  description: "Apartment rental offers scraped from a real-estate platform;
                imperfect: outliers, missing values, cross-wave duplicates"

artifact S_center : specification
  origin: given
  representation form: "parameter settings"
  description: "Analyst-selected geographic centre of interest (point)"

# ============================================================================
# STAGE 1: SPATIAL FOCUSING
# ============================================================================

transform T_distance :
  intent: characterise
  manner: "compute spatial distance to centre"
  input: D_offers, S_center
  output: F_distance
  actor: machine
  description: "Compute distance of every offer to the selected centre"

artifact F_distance : feature(D_offers)
  value structure: atomic
  value type: numeric
  description: "Distance (km) from offer location to centre of interest"

transform T_vis_reach :
  intent: visualise
  manner: "cumulative distribution plot"
  input: F_distance
  output: V_reach
  actor: machine
  description: "Show number of available offers as a function of distance
                threshold to support choice of spatial focus"

artifact V_reach : visualisation(F_distance)
  layout: "distance axis"
  form: "cumulative count curve"
  encoding: "x: distance threshold; y: number of offers within threshold"
  description: "Reach diagram: option supply vs. spatial extent"

transform T_fix_focus :
  intent: generate-knowledge
  manner: "select distance threshold"
  input: V_reach
  output: S_focus
  actor: human
  description: "Analyst fixes the maximal acceptable distance, balancing
                option supply against spatial relevance"

artifact S_focus : specification
  representation form: "parameter settings"
  description: "Maximal distance threshold (e.g., 50 km) defining the
                spatial scope of analysis"

transform T_select :
  intent: define-unit
  manner: "select by spatial distance threshold"
  input: D_offers, F_distance, S_focus
  output: D_cand
  actor: machine
  description: "Select candidate options within the spatial focus"

artifact D_cand : entities
  internal structure: elementary
  embedment: {set, space}
  features:
    - id: f_numeric_attrs
      value structure: vector
      value type: numeric
      description: "Numeric attributes inherited from D_offers"
  description: "Candidate decision options within the spatial focus"

# ============================================================================
# STAGE 2: CRITERIA SELECTION (redundancy-aware)
# ============================================================================

transform T_correlate :
  intent: characterise
  manner: "pairwise rank correlation of numeric attributes"
  input: D_cand
  output: F_corr
  actor: machine
  description: "Quantify redundancy among candidate criteria
                (e.g., base rent vs. total rent, space vs. rooms)"

artifact F_corr : feature(D_cand)
  value structure: matrix
  value type: numeric
  representation form: "pairwise correlation matrix"
  description: "Attribute redundancy structure"

transform T_vis_attrs :
  intent: visualise
  manner: "histograms with correlation overview"
  input: D_cand, F_corr
  output: V_attrs
  actor: machine
  description: "Show value distributions of all numeric attributes
                (percentile-clipped against outliers) and their correlations"

artifact V_attrs : visualisation(D_cand, F_corr)
  layout: "small multiples + matrix"
  form: "histograms; coloured matrix cells"
  encoding: "histogram per attribute; cell colour: correlation strength"
  description: "Attribute overview supporting informed, non-redundant
                criteria selection"

transform T_choose_criteria :
  intent: generate-knowledge
  manner: "select criteria and optimization directions"
  input: V_attrs
  output: S_criteria
  actor: human
  description: "Analyst selects the numeric criteria of interest and their
                directions (minimise/maximise), warned about redundant pairs"

artifact S_criteria : specification
  representation form: "criteria"
  description: "Selected criteria subset with optimisation directions;
                distance (F_distance) is always included as a criterion"

# ============================================================================
# STAGE 3: UTILITY ELICITATION OVER DISTRIBUTIONS
# ============================================================================

loop L_utility:
  purpose: "Define and refine per-criterion utility functions against the
            background of empirical value distributions"
  until: "Utility functions adequately express analyst preferences"
  body:

    transform T_define_util :
      intent: generate-knowledge
      manner: "interactive specification of piecewise-linear value functions"
      input: V_attrs, S_criteria
      output: S_util
      actor: human
      description: "Analyst draws/edits utility functions (possibly
                    non-monotonic, e.g., ideal floor) over distribution
                    histograms shown as background"

    artifact S_util : specification
      representation form: "parameter settings"
      description: "Piecewise-linear utility function per criterion"

    transform T_apply_util :
      intent: characterise
      manner: "apply utility functions"
      input: D_cand, S_util, S_criteria
      output: F_util
      actor: machine
      description: "Compute per-criterion utility values for all candidates"

    artifact F_util : feature(D_cand)
      value structure: vector
      value type: numeric
      description: "Utility value per selected criterion per option"

    transform T_vis_util :
      intent: visualise
      manner: "utility curves over histograms"
      input: V_attrs, S_util, F_util
      output: V_util
      actor: machine
      description: "Overlay utility functions and resulting utility
                    distributions on attribute histograms"

    artifact V_util : visualisation(S_util, F_util)
      layout: "small multiples per criterion"
      form: "curves over histograms"
      encoding: "x: attribute value; bars: frequency; curve: utility"
      description: "Visual feedback on utility specifications"

    transform T_assess_util :
      intent: assess
      manner: "judge adequacy of utility functions"
      input: V_util
      output: util_assessment
      actor: human
      description: "Analyst checks whether utilities reflect preferences;
                    decides on refinement"

    artifact util_assessment : knowledge(S_util)
      representation form: "quality judgment"
      description: "Adequacy judgment of current utility functions"

    if util_assessment indicates refinement needed:
      then: continue loop L_utility
      else: exit loop L_utility
end loop L_utility

# ============================================================================
# STAGE 4: DATA-GROUNDED TOLERANCE DERIVATION            # [NOVEL]
# ============================================================================

transform T_noise :
  intent: characterise
  manner: "estimate per-criterion value uncertainty from cross-wave
           duplicate listings and value reporting granularity"
  input: D_offers
  output: F_noise
  actor: machine
  description: "Measure empirical value variation of identical offers
                re-scraped in different waves; yields a defensible noise
                magnitude per criterion"                  # [NOVEL]

artifact F_noise : feature(D_offers)
  value structure: list
  value type: numeric
  description: "Estimated value uncertainty per criterion, in natural units
                (e.g., ±20 EUR rent, ±2 m2 living space)"

transform T_set_tolerance :
  intent: generate-knowledge
  manner: "set per-criterion tolerance thresholds seeded by noise estimates"
  input: F_noise, S_criteria
  output: S_tol
  actor: hybrid
  description: "Tolerances epsilon_i are initialised from measured noise and
                adjustable by the analyst in natural units"

artifact S_tol : specification
  representation form: "parameter settings"
  description: "Per-criterion tolerance thresholds for tolerant dominance"

# ============================================================================
# STAGE 5: DECISION CONTEXTS                              # [NOVEL]
# machine proposes groups -> machine describes as rules -> human legislates
# ============================================================================

artifact S_group_params : specification
  origin: given
  representation form: "parameter settings"
  description: "Number of archetypes/components, normalisation scheme"

loop L_context:
  purpose: "Establish interpretable, predicate-based decision contexts
            separating incommensurable option types
            (e.g., studios vs. family flats vs. premium objects)"
  until: "Contexts are interpretable, well-covering, and accepted by analyst"
  body:

    transform T_propose_groups :
      intent: model
      manner: "archetypal analysis / NMF over normalised criteria values"
      input: D_cand, S_criteria, S_group_params
      output: M_groups, F_member
      actor: machine
      description: "Identify candidate option archetypes; soft memberships
                    expose fuzzy boundaries between option types"

    artifact M_groups : model(D_cand)
      model type: "matrix factorisation / archetype model"
      representation form: "factor matrices (W,H) or archetype set"
      description: "Data-driven proposal of option groupings"

    artifact F_member : feature(D_cand)
      value structure: vector
      value type: numeric
      description: "Soft membership degrees of options in proposed groups"

    transform T_describe_groups :
      intent: abstract
      manner: "rule induction approximating group memberships"
      input: M_groups, F_member, D_cand
      output: P_rules
      actor: machine
      description: "Translate opaque factor/cluster structure into
                    human-readable predicates over criteria"   # [NOVEL]

    artifact P_rules : pattern(M_groups, F_member)
      representation form: "predicates over criteria"
      description: "Candidate group descriptions, e.g.,
                    'livingSpace > 120 AND noRooms >= 4'"

    transform T_define_contexts :
      intent: generate-knowledge
      manner: "edit, name, merge, split rule-based definitions"
      input: P_rules, V_attrs
      output: S_ctx
      actor: human
      description: "Analyst converts proposals into named, persistent,
                    editable decision-context definitions"     # [NOVEL]

    artifact S_ctx : specification
      representation form: "rules"
      description: "Named predicate-defined decision contexts
                    (e.g., 'studios', 'family flats', 'premium')"

    transform T_partition :
      intent: define-unit
      manner: "rule-based grouping into decision contexts"
      input: D_cand, S_ctx
      output: D_ctx, F_ctx_label
      actor: machine
      description: "Assign candidate options to decision contexts"

    artifact D_ctx : entities
      internal structure: group/cluster
      embedment: set
      features:
        - id: ctx_size
          value structure: atomic
          value type: numeric
          description: "Number of options in context"
      description: "Decision contexts as groups of candidate options"

    artifact F_ctx_label : feature(D_cand)
      value structure: atomic
      value type: categorical
      description: "Decision-context membership per option
                    (incl. 'unassigned' residual)"

    transform T_vis_contexts :
      intent: visualise
      manner: "map and feature-space small multiples per context"
      input: D_cand, F_ctx_label, F_member
      output: V_ctx
      actor: machine
      description: "Show spatial distribution and criteria profiles of
                    contexts; expose residuals and boundary options whose
                    soft memberships disagree with crisp rules"

    artifact V_ctx : visualisation(F_ctx_label, F_member)
      layout: "map + small multiples of histograms per context"
      form: "coloured point marks; histograms"
      encoding: "colour: context; saturation: membership confidence"
      description: "Context overview for validation and editing"

    transform T_assess_contexts :
      intent: assess
      manner: "evaluate coverage, overlap, interpretability"
      input: V_ctx, D_ctx
      output: ctx_assessment
      actor: human
      description: "Analyst judges whether contexts form a meaningful,
                    sufficiently covering decomposition"

    artifact ctx_assessment : knowledge(D_ctx)
      representation form: "quality judgment"
      description: "Judgment on context decomposition quality"

    if ctx_assessment indicates refinement needed:
      then:
        assign: S_group_params := S_group_params'   # or direct edit of S_ctx
      else:
        exit loop L_context
end loop L_context

# ============================================================================
# STAGE 6: TOLERANT DOMINANCE AND SENSITIVITY            # [NOVEL]
# ============================================================================

loop L_rank:
  purpose: "Compute graded tolerant-Pareto relevance per context and probe
            its sensitivity to tolerances, utilities, and context definitions"
  until: "Frontiers are informative (neither degenerate nor exploded) and
          stable under plausible specification variations"
  body:

    transform T_dominance :
      intent: characterise
      manner: "epsilon-tolerant dominance within each decision context over
               utility-transformed criteria including distance; robustness
               margin per option; optimistic/pessimistic bounding for
               missing values"
      input: D_cand, F_ctx_label, F_util, F_distance, S_criteria, S_tol
      output: F_robust, F_front_status
      actor: machine
      description: "Replace the binary Pareto set by a graded robustness
                    feature: the signed smallest tolerance change that flips
                    an option's frontier membership. Frontier defined as
                    'not tolerantly dominated by any option of the same
                    context' (well-defined despite non-transitivity).
                    Distance participates in the dominance relation.
                    Missing values yield a certain/possible/dominated
                    status via best/worst-case bounding"     # [NOVEL]

    artifact F_robust : feature(D_cand)
      value structure: atomic
      value type: numeric
      description: "Frontier robustness margin per option (graded relevance)"

    artifact F_front_status : feature(D_cand)
      value structure: atomic
      value type: categorical
      description: "certainly-on-frontier / possibly-on-frontier / dominated
                    (under missing-value bounding)"

    artifact D_geo : entities
      origin: given
      internal structure: elementary
      embedment: space
      description: "Geographic base map serving as spatial context"

    transform T_map :
      intent: contextualise
      manner: "geographic positioning"
      input: D_cand, D_geo
      output: A_map
      actor: machine
      description: "Arrange candidate options on the geographic map"

    artifact A_map : arrangement(D_cand)
      context: D_geo
      principle: "geographic coordinates"
      description: "Map arrangement of candidate options"

    transform T_vis_rank :
      intent: visualise
      manner: "coordinated map, parallel coordinates and ranking table"
      input: A_map, F_robust, F_front_status, F_ctx_label, F_util
      output: V_rank
      actor: machine
      description: "Coordinated views faceted by decision context;
                    robustness encoded continuously; interactive thresholding"

    artifact V_rank : visualisation(A_map, F_robust, F_front_status, F_util)
      layout: "map + parallel coordinates + table, faceted by context"
      form: "point marks; polylines; table rows"
      encoding: "position: map/axes; colour+opacity: robustness margin;
                 shape/outline: frontier status; facet: context"
      description: "Per-context tolerant frontiers with graded relevance"

    transform T_vis_stability :
      intent: visualise
      manner: "frontier stability curves"
      input: F_robust, S_tol, F_ctx_label
      output: V_stab
      actor: machine
      description: "Show frontier size and membership changes as functions
                    of tolerance scaling per context; sensitivity view"

    artifact V_stab : visualisation(F_robust, S_tol)
      layout: "tolerance scaling axis per context"
      form: "step curves with membership-change marks"
      encoding: "x: tolerance scale factor; y: frontier size;
                 marks: options entering/leaving"
      description: "Frontier stability under tolerance variation"

    transform T_assess_rank :
      intent: assess
      manner: "evaluate informativeness and stability of frontiers"
      input: V_rank, V_stab
      output: rank_assessment
      actor: human
      description: "Analyst judges whether frontiers discriminate usefully
                    and which specifications require adjustment"

    artifact rank_assessment : knowledge(F_robust)
      representation form: "quality judgment"
      description: "Judgment on frontier informativeness and stability"

    if rank_assessment indicates refinement needed:
      then:
        transform T_adjust :
          intent: generate-knowledge
          manner: "revise tolerances, utilities, or context definitions"
          input: rank_assessment, V_stab, S_tol, S_util, S_ctx
          output: S_tol', S_util', S_ctx'
          actor: human
          description: "Targeted specification adjustment; context edits
                        re-enter via L_context, utility edits via L_utility"
        assign:
          S_tol := S_tol'
          S_util := S_util'
          S_ctx := S_ctx'
      else:
        exit loop L_rank
end loop L_rank

# ============================================================================
# STAGE 7: INTERPRETATION AND DECISION
# ============================================================================

transform T_tradeoffs :
  intent: abstract
  manner: "interpret characteristic trade-offs per context"
  input: V_rank, V_stab, F_robust
  output: P_trade
  actor: human
  description: "Identify recurring trade-off structures among robust options
                within each context (e.g., distance vs. rent vs. space)"

artifact P_trade : pattern(F_robust, F_ctx_label)
  representation form: "textual descriptions"
  description: "Characteristic trade-off patterns per decision context"

transform T_decide :
  intent: generate-knowledge
  manner: "formulate shortlist with sensitivity statements"
  input: P_trade, V_rank, V_stab
  output: K_decision
  actor: human
  description: "Synthesize per-context shortlists of robust options,
                cross-context comparison of best representatives, and
                explicit statements about result sensitivity to tolerances,
                utilities, and context definitions"

artifact K_decision : knowledge(P_trade, F_robust)
  representation form: "ranking and statements"
  description: "Robust per-context shortlists with documented sensitivity;
                cross-context comparison supporting the final choice"

Novelty Annotations (for paper positioning)

  1. Decision contexts as editable specifications (Stage 5). The chain model → abstract (rule induction) → generate-knowledge (human editing) → define-unit makes group definitions first-class, persistent, human-legislated artifacts. Closest library precedent: Utopian (human-steered NMF) steers the model; here the human steers predicate definitions derived from the model, and the model becomes disposable scaffolding. Related DB work (group-by skylines) has no interactive definition mechanism.

  2. Graded tolerant frontier (Stage 6, F_robust). Replaces the binary skyline with a per-option robustness margin; subsumes both relaxation directions (tolerance against frontier explosion and against false exclusion) under one continuous, thresholdable encoding. Direct descendant of the robustness-probing agenda of Andrienko & Andrienko (Inf. Vis. 2003), now applied to the dominance structure itself.

  3. Data-grounded tolerances (Stage 4, F_noise → S_tol). Tolerance thresholds are measured from cross-wave duplicate variation rather than assumed — an empirically defensible operationalisation of "tolerating Pareto optimality because of data imperfections".

  4. Missing-value bounding (F_front_status). Certain/possible frontier membership via optimistic/pessimistic completion addresses incompleteness without the non-transitivity pathologies of observed-subset dominance.

Deliberate Demonstrator Restrictions

  • Numeric criteria only; booleans/categoricals excluded (extension trivial via 0/1 and partial orders, noted as future work).
  • Crow-flies distance, not travel time (isochrones noted as future work).
  • Crisp context assignment for dominance; soft memberships used only diagnostically in V_ctx.
  • Single user, single session; no provenance capture beyond ATWL documentation.
  • Cross-context final comparison done visually (T_decide), not formalised.

Explore

Interactive demonstrator → Run the full workflow in your browser on real Leipzig rental offers: focus, utilities, tolerance, constellations, ranking. Demo walkthrough → A guided description of the demonstrator and what each stage shows. Coming soon. Scaffold experiment → The controlled 2×2 study of how an AI assistant designs this workflow with and without ATWL scaffolds, across two tasks — with full transcripts. Data: cleaning & reproducibility → Provenance, the full cleaning and geocoding pipeline, the output schema, and runnable code for the Leipzig table.