Fix demo family generation: add diverse events and fix missing event references
- Added 12 different event types (Baptism, Education, Occupation, etc.) - Fixed missing event references by storing and reusing original events - Made event generation deterministic with random seed - Updated gen_person to return both XML and tuple format for event reuse - All event references now properly defined and validated - Demo family now includes 240+ additional events for comprehensive testing
This commit is contained in:
parent
8be124f5e0
commit
0abe20849c
@ -608,7 +608,7 @@ class MyTimelineView(NavigationView):
|
|||||||
clicked_index = self.find_event_at_position(event.x, event.y)
|
clicked_index = self.find_event_at_position(event.x, event.y)
|
||||||
if clicked_index is not None:
|
if clicked_index is not None:
|
||||||
# Check if clicking on marker (for person selection) or label (for expansion)
|
# Check if clicking on marker (for person selection) or label (for expansion)
|
||||||
date_sort, date_obj, clicked_event, clicked_person, event_type, expanded, _ = self.events[clicked_index]
|
date_sort, date_obj, clicked_event, clicked_person, event_type, expanded, _y_pos = self.events[clicked_index]
|
||||||
|
|
||||||
# Check if click is on marker area (left side) or label area (right side)
|
# Check if click is on marker area (left side) or label area (right side)
|
||||||
timeline_x = TIMELINE_MARGIN_LEFT
|
timeline_x = TIMELINE_MARGIN_LEFT
|
||||||
@ -877,7 +877,7 @@ class MyTimelineView(NavigationView):
|
|||||||
# Calculate initial Y positions based on dates
|
# Calculate initial Y positions based on dates
|
||||||
events_with_y_pos = []
|
events_with_y_pos = []
|
||||||
for i, event_data in enumerate(self.events):
|
for i, event_data in enumerate(self.events):
|
||||||
date_sort, date_obj, event, person, event_type, expanded, _ = event_data
|
date_sort, date_obj, event, person, event_type, expanded, _y_pos = event_data
|
||||||
|
|
||||||
# Calculate Y position based on date
|
# Calculate Y position based on date
|
||||||
y_pos = TIMELINE_MARGIN_TOP + (
|
y_pos = TIMELINE_MARGIN_TOP + (
|
||||||
@ -1226,7 +1226,7 @@ class MyTimelineView(NavigationView):
|
|||||||
context.set_line_width(1.5)
|
context.set_line_width(1.5)
|
||||||
|
|
||||||
# Create a smooth curve through all points
|
# Create a smooth curve through all points
|
||||||
y_positions = [y for y, _ in person_events]
|
y_positions = [y for y, _event_data in person_events]
|
||||||
min_y = min(y_positions)
|
min_y = min(y_positions)
|
||||||
max_y = max(y_positions)
|
max_y = max(y_positions)
|
||||||
|
|
||||||
|
|||||||
2633
demo_family.gramps
2633
demo_family.gramps
File diff suppressed because it is too large
Load Diff
@ -6,13 +6,96 @@ Generate a huge demo family for Gramps testing
|
|||||||
import random
|
import random
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
# Set seed for deterministic event generation
|
||||||
|
random.seed(42)
|
||||||
|
|
||||||
# Generate unique handles
|
# Generate unique handles
|
||||||
def gen_handle(prefix, num):
|
def gen_handle(prefix, num):
|
||||||
return f"_{prefix}{num:08d}"
|
return f"_{prefix}{num:08d}"
|
||||||
|
|
||||||
|
# Event types to add
|
||||||
|
EVENT_TYPES = [
|
||||||
|
("Baptism", 0.7, 0, 2), # 70% chance, 0-2 years after birth
|
||||||
|
("Christening", 0.5, 0, 1), # 50% chance, 0-1 years after birth
|
||||||
|
("Education", 0.8, 5, 18), # 80% chance, 5-18 years after birth
|
||||||
|
("Graduation", 0.6, 18, 25), # 60% chance, 18-25 years after birth
|
||||||
|
("Occupation", 0.9, 18, 65), # 90% chance, 18-65 years after birth
|
||||||
|
("Military Service", 0.3, 18, 30), # 30% chance, 18-30 years after birth
|
||||||
|
("Residence", 0.7, 0, 80), # 70% chance, any time
|
||||||
|
("Emigration", 0.2, 20, 50), # 20% chance, 20-50 years after birth
|
||||||
|
("Immigration", 0.15, 20, 50), # 15% chance, 20-50 years after birth
|
||||||
|
("Retirement", 0.4, 60, 75), # 40% chance, 60-75 years after birth
|
||||||
|
("Burial", 0.6, None, None), # 60% chance if death exists, at death time
|
||||||
|
("Cremation", 0.2, None, None), # 20% chance if death exists, at death time
|
||||||
|
]
|
||||||
|
|
||||||
|
# Generate additional events for a person
|
||||||
|
def gen_additional_events(pid, first_name, surname, birth_year, death_year=None):
|
||||||
|
events = []
|
||||||
|
event_id_offset = pid * 10 + 2 # Start after birth and death events
|
||||||
|
|
||||||
|
for event_type, probability, min_years, max_years in EVENT_TYPES:
|
||||||
|
if random.random() > probability:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Special handling for death-related events
|
||||||
|
if event_type in ("Burial", "Cremation"):
|
||||||
|
if not death_year:
|
||||||
|
continue
|
||||||
|
event_year = death_year
|
||||||
|
event_month = random.randint(1, 12)
|
||||||
|
event_day = random.randint(1, 28)
|
||||||
|
else:
|
||||||
|
if max_years is None:
|
||||||
|
continue
|
||||||
|
event_year = birth_year + random.randint(min_years, max_years)
|
||||||
|
if death_year and event_year > death_year:
|
||||||
|
continue
|
||||||
|
event_month = random.randint(1, 12)
|
||||||
|
event_day = random.randint(1, 28)
|
||||||
|
|
||||||
|
event_handle = gen_handle("EVENT", event_id_offset)
|
||||||
|
event_id_offset += 1
|
||||||
|
|
||||||
|
# Generate description based on event type
|
||||||
|
if event_type == "Education":
|
||||||
|
description = f"Education - {first_name} {surname}"
|
||||||
|
elif event_type == "Graduation":
|
||||||
|
description = f"Graduation - {first_name} {surname}"
|
||||||
|
elif event_type == "Occupation":
|
||||||
|
occupations = ["Farmer", "Teacher", "Engineer", "Doctor", "Lawyer", "Merchant",
|
||||||
|
"Carpenter", "Blacksmith", "Sailor", "Soldier", "Clerk", "Nurse"]
|
||||||
|
occupation = random.choice(occupations)
|
||||||
|
description = f"{occupation} - {first_name} {surname}"
|
||||||
|
elif event_type == "Military Service":
|
||||||
|
description = f"Military Service - {first_name} {surname}"
|
||||||
|
elif event_type == "Residence":
|
||||||
|
places = ["New York", "London", "Paris", "Berlin", "Rome", "Madrid", "Amsterdam",
|
||||||
|
"Vienna", "Prague", "Warsaw", "Stockholm", "Copenhagen"]
|
||||||
|
place = random.choice(places)
|
||||||
|
description = f"Residence in {place} - {first_name} {surname}"
|
||||||
|
elif event_type == "Emigration":
|
||||||
|
description = f"Emigration - {first_name} {surname}"
|
||||||
|
elif event_type == "Immigration":
|
||||||
|
description = f"Immigration - {first_name} {surname}"
|
||||||
|
elif event_type == "Retirement":
|
||||||
|
description = f"Retirement - {first_name} {surname}"
|
||||||
|
else:
|
||||||
|
description = f"{event_type} of {surname}, {first_name}"
|
||||||
|
|
||||||
|
event_xml = f""" <event handle="{event_handle}" change="{int(datetime.now().timestamp())}" id="E{event_id_offset-1:04d}">
|
||||||
|
<type>{event_type}</type>
|
||||||
|
<dateval val="{event_year}-{event_month:02d}-{event_day:02d}"/>
|
||||||
|
<description>{description}</description>
|
||||||
|
</event>
|
||||||
|
"""
|
||||||
|
events.append((event_handle, event_xml))
|
||||||
|
|
||||||
|
return events
|
||||||
|
|
||||||
# Generate a person
|
# Generate a person
|
||||||
def gen_person(pid, first_name, surname, birth_year, death_year=None, gender="M",
|
def gen_person(pid, first_name, surname, birth_year, death_year=None, gender="M",
|
||||||
parentin_families=None, childof_families=None):
|
parentin_families=None, childof_families=None, reuse_additional_events=None):
|
||||||
handle = gen_handle("PERSON", pid)
|
handle = gen_handle("PERSON", pid)
|
||||||
birth_handle = gen_handle("EVENT", pid * 10)
|
birth_handle = gen_handle("EVENT", pid * 10)
|
||||||
death_handle = gen_handle("EVENT", pid * 10 + 1) if death_year else None
|
death_handle = gen_handle("EVENT", pid * 10 + 1) if death_year else None
|
||||||
@ -28,6 +111,18 @@ def gen_person(pid, first_name, surname, birth_year, death_year=None, gender="M"
|
|||||||
if death_handle:
|
if death_handle:
|
||||||
person_xml += f""" <eventref hlink="{death_handle}" role="Primary"/>
|
person_xml += f""" <eventref hlink="{death_handle}" role="Primary"/>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# Add additional events - reuse if provided, otherwise generate new
|
||||||
|
if reuse_additional_events is not None:
|
||||||
|
# reuse_additional_events is a list of (handle, xml) tuples
|
||||||
|
additional_events = reuse_additional_events
|
||||||
|
else:
|
||||||
|
additional_events = gen_additional_events(pid, first_name, surname, birth_year, death_year)
|
||||||
|
|
||||||
|
for event_handle, _ in additional_events:
|
||||||
|
person_xml += f""" <eventref hlink="{event_handle}" role="Primary"/>
|
||||||
|
"""
|
||||||
|
|
||||||
# Add parentin references (for fathers and mothers)
|
# Add parentin references (for fathers and mothers)
|
||||||
if parentin_families:
|
if parentin_families:
|
||||||
for family_handle in parentin_families:
|
for family_handle in parentin_families:
|
||||||
@ -63,7 +158,10 @@ def gen_person(pid, first_name, surname, birth_year, death_year=None, gender="M"
|
|||||||
</event>
|
</event>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return person_xml, birth_event, death_event
|
# Collect all additional events (return tuples for reuse, XML strings for output)
|
||||||
|
all_additional_events_xml = [event_xml for _, event_xml in additional_events]
|
||||||
|
|
||||||
|
return person_xml, birth_event, death_event, all_additional_events_xml, additional_events
|
||||||
|
|
||||||
# Generate a family
|
# Generate a family
|
||||||
def gen_family(fid, father_handle, mother_handle, marriage_year, children_handles):
|
def gen_family(fid, father_handle, mother_handle, marriage_year, children_handles):
|
||||||
@ -122,7 +220,7 @@ def main():
|
|||||||
father_id = 1
|
father_id = 1
|
||||||
father_handle = gen_handle("PERSON", father_id)
|
father_handle = gen_handle("PERSON", father_id)
|
||||||
main_family_handle = gen_handle("FAMILY", 1)
|
main_family_handle = gen_handle("FAMILY", 1)
|
||||||
father_person, father_birth, father_death = gen_person(
|
father_person, father_birth, father_death, father_additional_xml, _ = gen_person(
|
||||||
father_id, "John", "Smith", 1950, 2010, "M",
|
father_id, "John", "Smith", 1950, 2010, "M",
|
||||||
parentin_families=[main_family_handle]
|
parentin_families=[main_family_handle]
|
||||||
)
|
)
|
||||||
@ -130,15 +228,18 @@ def main():
|
|||||||
# Mother: Mary Smith, born 1952, died 2015
|
# Mother: Mary Smith, born 1952, died 2015
|
||||||
mother_id = 2
|
mother_id = 2
|
||||||
mother_handle = gen_handle("PERSON", mother_id)
|
mother_handle = gen_handle("PERSON", mother_id)
|
||||||
mother_person, mother_birth, mother_death = gen_person(
|
mother_person, mother_birth, mother_death, mother_additional_xml, _ = gen_person(
|
||||||
mother_id, "Mary", "Smith", 1952, 2015, "F",
|
mother_id, "Mary", "Smith", 1952, 2015, "F",
|
||||||
parentin_families=[main_family_handle]
|
parentin_families=[main_family_handle]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
all_additional_events = father_additional_xml + mother_additional_xml
|
||||||
|
|
||||||
# Generate 15 children
|
# Generate 15 children
|
||||||
children = []
|
children = []
|
||||||
child_handles = []
|
child_handles = []
|
||||||
child_events = []
|
child_events = []
|
||||||
|
child_additional_events_map = {} # Store additional events by child_id
|
||||||
child_id = 3
|
child_id = 3
|
||||||
|
|
||||||
for i in range(15):
|
for i in range(15):
|
||||||
@ -148,7 +249,7 @@ def main():
|
|||||||
death_year = birth_year + random.randint(60, 90) if random.random() < 0.3 else None # 30% chance of death
|
death_year = birth_year + random.randint(60, 90) if random.random() < 0.3 else None # 30% chance of death
|
||||||
|
|
||||||
child_handle = gen_handle("PERSON", child_id)
|
child_handle = gen_handle("PERSON", child_id)
|
||||||
child_person, child_birth, child_death = gen_person(
|
child_person, child_birth, child_death, child_additional_xml, child_additional_tuples = gen_person(
|
||||||
child_id, first_name, "Smith", birth_year, death_year, gender,
|
child_id, first_name, "Smith", birth_year, death_year, gender,
|
||||||
childof_families=[main_family_handle]
|
childof_families=[main_family_handle]
|
||||||
)
|
)
|
||||||
@ -158,6 +259,9 @@ def main():
|
|||||||
child_events.append(child_birth)
|
child_events.append(child_birth)
|
||||||
if child_death:
|
if child_death:
|
||||||
child_events.append(child_death)
|
child_events.append(child_death)
|
||||||
|
# Store tuples for reuse when regenerating
|
||||||
|
child_additional_events_map[child_id] = child_additional_tuples
|
||||||
|
all_additional_events.extend(child_additional_xml)
|
||||||
child_id += 1
|
child_id += 1
|
||||||
|
|
||||||
# Generate family
|
# Generate family
|
||||||
@ -214,7 +318,7 @@ def main():
|
|||||||
"birth": spouse_birth, "death": None, "gender": spouse_gender,
|
"birth": spouse_birth, "death": None, "gender": spouse_gender,
|
||||||
"parentin": [child_family_handle], "childof": []}
|
"parentin": [child_family_handle], "childof": []}
|
||||||
|
|
||||||
spouse_person, spouse_birth_event, spouse_death_event = gen_person(
|
spouse_person, spouse_birth_event, spouse_death_event, spouse_additional_xml, _ = gen_person(
|
||||||
grandchild_id, spouse_name, "Smith", spouse_birth, None, spouse_gender,
|
grandchild_id, spouse_name, "Smith", spouse_birth, None, spouse_gender,
|
||||||
parentin_families=[child_family_handle]
|
parentin_families=[child_family_handle]
|
||||||
)
|
)
|
||||||
@ -222,6 +326,7 @@ def main():
|
|||||||
grandchild_events.append(spouse_birth_event)
|
grandchild_events.append(spouse_birth_event)
|
||||||
if spouse_death_event:
|
if spouse_death_event:
|
||||||
grandchild_events.append(spouse_death_event)
|
grandchild_events.append(spouse_death_event)
|
||||||
|
all_additional_events.extend(spouse_additional_xml)
|
||||||
grandchild_id += 1
|
grandchild_id += 1
|
||||||
|
|
||||||
# Update parent to include parentin reference
|
# Update parent to include parentin reference
|
||||||
@ -240,7 +345,7 @@ def main():
|
|||||||
"birth": gchild_birth, "death": None, "gender": gchild_gender,
|
"birth": gchild_birth, "death": None, "gender": gchild_gender,
|
||||||
"parentin": [], "childof": [child_family_handle]}
|
"parentin": [], "childof": [child_family_handle]}
|
||||||
|
|
||||||
gchild_person, gchild_birth_event, gchild_death_event = gen_person(
|
gchild_person, gchild_birth_event, gchild_death_event, gchild_additional_xml, _ = gen_person(
|
||||||
grandchild_id, gchild_name, "Smith", gchild_birth, None, gchild_gender,
|
grandchild_id, gchild_name, "Smith", gchild_birth, None, gchild_gender,
|
||||||
childof_families=[child_family_handle]
|
childof_families=[child_family_handle]
|
||||||
)
|
)
|
||||||
@ -249,6 +354,7 @@ def main():
|
|||||||
grandchild_events.append(gchild_birth_event)
|
grandchild_events.append(gchild_birth_event)
|
||||||
if gchild_death_event:
|
if gchild_death_event:
|
||||||
grandchild_events.append(gchild_death_event)
|
grandchild_events.append(gchild_death_event)
|
||||||
|
all_additional_events.extend(gchild_additional_xml)
|
||||||
grandchild_id += 1
|
grandchild_id += 1
|
||||||
|
|
||||||
# Create family for this couple
|
# Create family for this couple
|
||||||
@ -258,13 +364,17 @@ def main():
|
|||||||
child_events.append(fam_marriage)
|
child_events.append(fam_marriage)
|
||||||
|
|
||||||
# Regenerate children XMLs with updated family references
|
# Regenerate children XMLs with updated family references
|
||||||
|
# We need to regenerate to update family references, but reuse the same events
|
||||||
children = []
|
children = []
|
||||||
for i, child_handle in enumerate(child_handles):
|
for i, child_handle in enumerate(child_handles):
|
||||||
child_pid = 3 + i
|
child_pid = 3 + i
|
||||||
data = person_data[child_pid]
|
data = person_data[child_pid]
|
||||||
child_person, _, _ = gen_person(
|
# Reuse the original additional events to ensure consistency
|
||||||
|
original_additional_events = child_additional_events_map.get(child_pid, [])
|
||||||
|
child_person, _, _, _, _ = gen_person(
|
||||||
child_pid, data["name"], data["surname"], data["birth"], data["death"], data["gender"],
|
child_pid, data["name"], data["surname"], data["birth"], data["death"], data["gender"],
|
||||||
parentin_families=data["parentin"], childof_families=data["childof"]
|
parentin_families=data["parentin"], childof_families=data["childof"],
|
||||||
|
reuse_additional_events=original_additional_events
|
||||||
)
|
)
|
||||||
children.append(child_person)
|
children.append(child_person)
|
||||||
|
|
||||||
@ -293,6 +403,8 @@ def main():
|
|||||||
xml_content += event
|
xml_content += event
|
||||||
for event in grandchild_events:
|
for event in grandchild_events:
|
||||||
xml_content += event
|
xml_content += event
|
||||||
|
for event in all_additional_events:
|
||||||
|
xml_content += event
|
||||||
|
|
||||||
xml_content += """ </events>
|
xml_content += """ </events>
|
||||||
<people>
|
<people>
|
||||||
@ -316,6 +428,7 @@ def main():
|
|||||||
with open("demo_family.gramps", "w", encoding="utf-8") as f:
|
with open("demo_family.gramps", "w", encoding="utf-8") as f:
|
||||||
f.write(xml_content)
|
f.write(xml_content)
|
||||||
|
|
||||||
|
total_events = len(child_events) + len(grandchild_events) + len(all_additional_events)
|
||||||
print(f"Generated demo_family.gramps with:")
|
print(f"Generated demo_family.gramps with:")
|
||||||
print(f" - 2 parents (John and Mary Smith)")
|
print(f" - 2 parents (John and Mary Smith)")
|
||||||
print(f" - 15 children")
|
print(f" - 15 children")
|
||||||
@ -323,6 +436,8 @@ def main():
|
|||||||
print(f" - ~20 grandchildren")
|
print(f" - ~20 grandchildren")
|
||||||
print(f" - Multiple families with marriage events")
|
print(f" - Multiple families with marriage events")
|
||||||
print(f" - Birth and death events for all")
|
print(f" - Birth and death events for all")
|
||||||
|
print(f" - {len(all_additional_events)} additional events (Baptism, Education, Occupation, etc.)")
|
||||||
|
print(f" - Total events: {total_events}")
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user