Survey Helper Utilities
Advanced utilities for manipulating surveys.
Question Renaming
Rename a question and automatically update ALL references throughout the survey:
python
from edsl import Survey
survey = Survey([q1, q2, q3])
survey = survey.add_rule("q1", "{{ q1.answer }} == 'yes'", "q2")
# Rename q1 to "intro_question"
# All rules, memory, piping references are updated automatically
new_survey = survey.with_renamed_question("q1", "intro_question")
# Now the rule expression is: "{{ intro_question.answer }} == 'yes'"
What gets updated:
- •Question name in the question object
- •Rule expressions (both
q1.answerand{{ q1.answer }}formats) - •Memory plan (focal and prior question names)
- •Piping references in question text (
{{ q1.answer }}becomes{{ intro_question.answer }}) - •Piping in question options
- •Instruction text references
- •Question groups
Matrix Combiner
Combine multiple multiple-choice questions with the same options into a single matrix question:
python
from edsl import Survey, QuestionMultipleChoice
from edsl.surveys.survey_helpers.matrix_combiner import combine_multiple_choice_to_matrix
# Questions with same options
q1 = QuestionMultipleChoice(
question_name="trust_freelancer",
question_text="How much would you trust: A freelancer without AI",
question_options=["High", "Medium", "Low"]
)
q2 = QuestionMultipleChoice(
question_name="trust_ai",
question_text="How much would you trust: A freelancer with AI",
question_options=["High", "Medium", "Low"]
)
q3 = QuestionMultipleChoice(
question_name="trust_agency",
question_text="How much would you trust: An agency",
question_options=["High", "Medium", "Low"]
)
survey = Survey([q1, q2, q3])
# Combine into matrix - auto-infers question text from common prefix
new_survey = combine_multiple_choice_to_matrix(
survey=survey,
question_names=["trust_freelancer", "trust_ai", "trust_agency"],
matrix_question_name="trust_matrix"
)
# Creates QuestionMatrix with:
# - question_text: "How much would you trust"
# - question_items: ["A freelancer without AI", "A freelancer with AI", "An agency"]
# - question_options: ["High", "Medium", "Low"]
With Explicit Text
python
new_survey = combine_multiple_choice_to_matrix(
survey=survey,
question_names=["satisfaction_work", "satisfaction_pay"],
matrix_question_name="satisfaction_matrix",
matrix_question_text="How satisfied are you with each aspect?",
remove_original_questions=True, # Default: removes originals
index=0 # Position in survey (default: end)
)
Requirements
- •All questions must be
QuestionMultipleChoice - •All questions must have identical
question_options
Follow-up Questions
Auto-generate conditional follow-up questions for each option in a multiple choice question:
python
from edsl import Survey, QuestionMultipleChoice, QuestionFreeText
# Main question
q_restaurant = QuestionMultipleChoice(
question_name="restaurants",
question_text="Which restaurant do you prefer?",
question_options=["Italian", "Chinese", "Mexican"]
)
# Follow-up template - uses {{ restaurants.answer }} placeholder
q_followup = QuestionFreeText(
question_name="why_restaurant",
question_text="Why do you like {{ restaurants.answer }}?"
)
# Create survey and add follow-ups
survey = Survey([q_restaurant])
survey = survey.add_followup_questions("restaurants", q_followup)
# Creates 4 questions total:
# 1. restaurants (original)
# 2. why_restaurant_restaurants_0 ("Why do you like Italian?")
# 3. why_restaurant_restaurants_1 ("Why do you like Chinese?")
# 4. why_restaurant_restaurants_2 ("Why do you like Mexican?")
# Each follow-up has skip logic:
# - why_restaurant_restaurants_0 skipped unless answer == "Italian"
# - why_restaurant_restaurants_1 skipped unless answer == "Chinese"
# - etc.
How It Works
- •Creates one follow-up question per option
- •Substitutes
{{ question_name.answer }}with each option value - •Adds skip logic so each follow-up only appears for its option
- •Maintains proper survey flow
CSS Styling (for HTML Export)
Customize CSS for HTML survey rendering:
python
from edsl.surveys.survey_helpers.survey_css import SurveyCSS, CSSRule
# Create custom styles
css = SurveyCSS()
css.update_style("survey_container", "width", "100%")
css.update_style("survey_container", "max-width", "800px")
css.update_style("question_text", "font-size", "20px")
css.update_style("question_text", "font-weight", "bold")
# Remove a style
css.remove_style("survey_container", "max-width")
# Generate CSS string
css_string = css.generate_css()
print(css_string)
# Get default styles
default_css = SurveyCSS.default_style()
Default CSS Selectors
| Selector | Purpose |
|---|---|
survey_container | Main survey wrapper |
survey_question | Individual question container |
question_text | Question text styling |
question_options | Options list styling |
question_options li | Individual option items |
Delete Questions
python
# Delete a question by name
survey = survey.delete_question("question_name")
# Delete by index
survey = survey.delete_question(survey.questions[2])
Move Questions
python
# Move question to new position
survey = survey.move_question("question_name", new_index=0)
Quick Reference
| Task | Method |
|---|---|
| Rename question | survey.with_renamed_question(old, new) |
| Combine to matrix | combine_multiple_choice_to_matrix(survey, names, new_name) |
| Add follow-ups | survey.add_followup_questions(ref_q, template) |
| Delete question | survey.delete_question(name) |
| Move question | survey.move_question(name, new_index) |
| Custom CSS | SurveyCSS().update_style(selector, prop, value) |