Add 5 new statistics to StatisticsChart.py plugin

svn: r3988
This commit is contained in:
Eero Tamminen 2005-01-29 17:11:02 +00:00
parent 3b7b70d606
commit 5bcbb04bb8
2 changed files with 150 additions and 42 deletions

View File

@ -1,3 +1,19 @@
2005-01-29 Eero Tamminen <eerot@sf>
* src/plugins/StatisticsChart.py:
- Add first versions of following statistics:
- Child counts
- Marriage places
- Marriage ages
- Ages when first child was born
- Ages when last child was born
- Added a note that children can be either biological or adopted
(this relation can be gotten easily/fast only when going from child
to parents, not when going from parent to children like I need to)
- Take advantage of Don's age calculations function
-> Remove "Estimate" from the age descriptions
- Convert ages to correctly sortable strings
- Add a few TODO notes
2005-01-28 Alex Roitman <shura@alex.neuro.umn.edu> 2005-01-28 Alex Roitman <shura@alex.neuro.umn.edu>
* src/PedView.py: Fix remnants of gnome.canvas syntax. * src/PedView.py: Fix remnants of gnome.canvas syntax.
* src/ReadGrdb.py: Add to CVS: native database importer. * src/ReadGrdb.py: Add to CVS: native database importer.

View File

@ -17,8 +17,10 @@
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
# #
# Statistics plugin (w) 2004-2005 by Eero Tamminen. # Statistics plugin (w) 2004-2005 by Eero Tamminen with lots of help
# Partially based on code from the Timeline graph plugin. # from Alex Roitman.
#
# To see things still missing, search for "TODO"...
# #
# $Id$ # $Id$
@ -46,8 +48,11 @@ import gtk
# GRAMPS modules # GRAMPS modules
# #
#------------------------------------------------------------------------ #------------------------------------------------------------------------
import const # gender and report type names
from RelLib import Person # need Person internals for getting gender / gender name # Person and relation types
from RelLib import Person, Family
# gender and report type names
import const
import BaseDoc import BaseDoc
import Report import Report
import ReportUtils import ReportUtils
@ -108,15 +113,20 @@ class Extract:
self.get_birth, self.get_place), self.get_birth, self.get_place),
'data_dplace': ("Death places", _("Death places"), 'data_dplace': ("Death places", _("Death places"),
self.get_death, self.get_place), self.get_death, self.get_place),
#'data_mplace': (self.marriage_place, "Marriage place", _("Marriage place")), 'data_mplace': ("Marriage places", _("Marriage places"),
#'data_fchild': (self.first_child_age, "Estimated ages for bearing the first child", _("Estimated ages for bearing the first child")), self.get_marriage_handles, self.get_places),
#'data_lchild': (self.last_child_age, "Estimated Ages for bearing the last child", _("Estimated Ages for bearing the last child")), 'data_fchild': ("Ages when first child born", _("Ages when first child born"),
#'data_ccount': (self.child_count, "Number of children", _("Number of children")), self.get_child_handles, self.get_first_child_age),
#'data_mage': (self.marriage_age, "Estimated (first) marriage ages", _("Estimated (first) marriage ages")), 'data_lchild': ("Ages when last child born", _("Ages when last child born"),
'data_dage': ("Estimated ages at death", _("Estimated ages at death"), self.get_child_handles, self.get_last_child_age),
self.get_person, self.get_death_age), 'data_ccount': ("Number of children", _("Number of children"),
'data_age': ("Estimated ages", _("Estimated ages"), self.get_child_handles, self.get_child_count),
self.get_person, self.get_person_age) 'data_mage': ("Marriage ages", _("Marriage ages"),
self.get_marriage_handles, self.get_event_ages),
'data_dage': ("Ages at death", _("Ages at death"),
self.get_person, self.get_death_age),
'data_age': ("Ages", _("Ages"),
self.get_person, self.get_person_age)
} }
# ----------------- data extraction methods -------------------- # ----------------- data extraction methods --------------------
@ -124,6 +134,7 @@ class Extract:
def get_title(self, person): def get_title(self, person):
"return title for given person" "return title for given person"
# TODO: return all titles, not just primary ones...
title = person.get_primary_name().get_title() title = person.get_primary_name().get_title()
if title: if title:
return [title] return [title]
@ -132,7 +143,7 @@ class Extract:
def get_forename(self, person): def get_forename(self, person):
"return forenames for given person" "return forenames for given person"
# because this returns list, other methods return list too # TODO: return all forenames, not just primary ones...
firstnames = person.get_primary_name().get_first_name().strip() firstnames = person.get_primary_name().get_first_name().strip()
if firstnames: if firstnames:
return [name.capitalize() for name in firstnames.split()] return [name.capitalize() for name in firstnames.split()]
@ -182,50 +193,97 @@ class Extract:
if place: if place:
return [place] return [place]
return [_("Place missing")] return [_("Place missing")]
def get_places(self, data):
"return places for given (person,event_handles)"
places = []
person, event_handles = data
for event_handle in event_handles:
event = self.db.get_event_from_handle(event_handle)
place_handle = event.get_place_handle()
if place_handle:
place = self.db.get_place_from_handle(place_handle).get_title()
if place:
places.append(place)
else:
places.append(_("Place missing"))
return places
def get_person_age(self, person): def get_person_age(self, person):
"return age for given person, if alive" "return age for given person, if alive"
death = self.get_death(person) death = person.get_death_handle()
if not death: if not death:
return self.estimate_age(person) return [self.estimate_age(person)]
return [_("Already dead")] return [_("Already dead")]
def get_death_age(self, person): def get_death_age(self, person):
"return age at death for given person, if dead" "return age at death for given person, if dead"
death = self.get_death(person) death_handle = person.get_death_handle()
if death: if death_handle:
return self.estimate_age(person) return [self.estimate_age(person, death_handle)]
return [_("Still alive")] return [_("Still alive")]
def marriage_age(self, person): def get_event_ages(self, data):
return "TODO: Marriage age stat unimplemented" "return ages at given (person,event_handles)"
ages = []
person, event_handles = data
for event_handle in event_handles:
ages.append(self.estimate_age(person, event_handle))
if ages:
return ages
return [_("Events missing")]
def marriage_place(self, person): def get_first_child_age(self, data):
return "TODO: Marriage place stat unimplemented" "return age when first child in given (person,child_handles) was born"
ages, errors = self.get_sorted_child_ages(data)
if ages:
errors.append(ages[0])
return errors
return [_("Children missing")]
def first_child_age(self, person): def get_last_child_age(self, data):
return "TODO: First child bearing age stat unimplemented" "return age when last child in given (person,child_handles) was born"
ages, errors = self.get_sorted_child_ages(data)
if ages:
errors.append(ages[-1])
return errors
return [_("Children missing")]
def last_child_age(self, person): def get_child_count(self, data):
return "TODO: Last child bearing age stat unimplemented" "return number of children in given (person,child_handles)"
return [str(len(data[1]))]
def child_count(self, person):
return "TODO: Child count stat unimplemented"
# ------------------- utility methods ------------------------- # ------------------- utility methods -------------------------
def get_sorted_child_ages(self, data):
"return (sorted_ages,errors) for given (person,child_handles)"
ages = []
errors = []
person, child_handles = data
for child_handle in child_handles:
child = self.db.get_person_from_handle(child_handle)
birth_handle = child.get_birth_handle()
if birth_handle:
ages.append(self.estimate_age(person, birth_handle))
else:
errors.append(_("Birth missing"))
continue
ages.sort()
return (ages, errors)
def estimate_age(self, person): def estimate_age(self, person, end=None, begin=None):
"return estimated age (range) for given person or error message" """return estimated age (range) for given person or error message.
age = ReportUtils.estimate_age(self.db, person) age string is padded with spaces so that it can be sorted"""
age = ReportUtils.estimate_age(self.db, person, end, begin)
if age[0] < 0 or age[1] < 0: if age[0] < 0 or age[1] < 0:
# inadequate information # inadequate information
return [_("Date(s) missing")] return _("Date(s) missing")
if age[0] == age[1]: if age[0] == age[1]:
# exact year # exact year
return [str(age[0])] return "%3d" % age[0]
else: else:
# minimum and maximum # minimum and maximum
return [str(age[0]) + "-" + str(age[1])] return "%3d-%d" % (age[0], age[1])
# ------------------- type methods ------------------------- # ------------------- type methods -------------------------
# take db and person and return suitable gramps object(s) # take db and person and return suitable gramps object(s)
@ -235,18 +293,48 @@ class Extract:
return person return person
def get_birth(self, person): def get_birth(self, person):
"return birth event for given person or None" "return birth event for given person or None"
birth_handle = person.get_birth_handle() birth_handle = person.get_birth_handle()
if birth_handle: if birth_handle:
return self.db.get_event_from_handle(birth_handle) return self.db.get_event_from_handle(birth_handle)
return None return None
def get_death(self, person): def get_death(self, person):
"return death event for given person or None" "return death event for given person or None"
death_handle = person.get_death_handle() death_handle = person.get_death_handle()
if death_handle: if death_handle:
return self.db.get_event_from_handle(death_handle) return self.db.get_event_from_handle(death_handle)
return None return None
def get_child_handles(self, person):
"return list of child handles for given person or None"
children = []
for fam_handle in person.get_family_handle_list():
fam = self.db.get_family_from_handle(fam_handle)
for child_handle in fam.get_child_handle_list():
children.append(child_handle)
# TODO: it would be good to return only biological children,
# but GRAMPS doesn't offer any efficient way to check that
# (I don't want to check each children's parent family mother
# and father relations as that would make this *much* slower)
if children:
return (person, children)
return None
def get_marriage_handles(self, person):
"return list of marriage event handles for given person or None"
marriages = []
for family_handle in person.get_family_handle_list():
family = self.db.get_family_from_handle(family_handle)
if family.get_relationship() == Family.MARRIED:
for event_handle in family.get_event_list():
if event_handle:
event = self.db.get_event_from_handle(event_handle)
if event.get_name() == "Marriage":
marriages.append(event_handle)
if marriages:
return (person, marriages)
return None
# ----------------- data collection methods -------------------- # ----------------- data collection methods --------------------
@ -296,7 +384,7 @@ class Extract:
# which methods to use # which methods to use
for key in options: for key in options:
if options[key] and key in self.extractors: if options[key] and key in self.extractors:
# localized data title, value dict and method # localized data title, value dict, type and data method
data.append((ext[key][1], {}, ext[key][2], ext[key][3])) data.append((ext[key][1], {}, ext[key][2], ext[key][3]))
# go through the people and collect data # go through the people and collect data
@ -697,6 +785,10 @@ class StatisticsChartOptions(ReportOptions.ReportOptions):
dialog.add_frame_option("Chart Selection", "", hbox, tip) dialog.add_frame_option("Chart Selection", "", hbox, tip)
hbox.show_all() hbox.show_all()
# Note about children
label = gtk.Label(_("Note that children can be both biological or adopted."))
dialog.add_frame_option("Chart Selection", "", label)
def parse_user_options(self, dialog): def parse_user_options(self, dialog):
""" """