3030 BACK_ALT = ''
3131
3232# Format to use for the grid style when displaying tables with the tableformatter module
33- grid_style = tf .AlternatingRowGrid (BACK_PRI , BACK_ALT ) # Use rows of alternating color to assist as a visual guide
33+ grid_style = tf .AlternatingRowGrid (BACK_PRI , BACK_ALT ) # Use rows of alternating color to assist as a visual guide
3434
3535# Create a function to format a fixed-width table for pretty-printing using the desired table format
3636table = functools .partial (tf .generate_table , grid_style = grid_style )
3737
3838
39- # Population data from Wikipedia: https://en.wikipedia.org/wiki/List_of_cities_proper_by_population
40- EXAMPLE_DATA = [['Shanghai' , 'Shanghai' , 'China' , 'Asia' , 24183300 , 6340.5 ],
41- ['Beijing' , 'Hebei' , 'China' , 'Asia' , 20794000 , 1749.57 ],
42- ['Karachi' , 'Sindh' , 'Pakistan' , 'Asia' , 14910352 , 615.58 ],
43- ['Shenzen' , 'Guangdong' , 'China' , 'Asia' , 13723000 , 1493.32 ],
44- ['Guangzho' , 'Guangdong' , 'China' , 'Asia' , 13081000 , 1347.81 ],
45- ['Mumbai' , 'Maharashtra' , 'India' , 'Asia' , 12442373 , 465.78 ],
46- ['Istanbul' , 'Istanbul' , 'Turkey' , 'Eurasia' , 12661000 , 620.29 ],
47- ]
48-
49- # Calculate population density
50- for row in EXAMPLE_DATA :
51- row .append (row [- 2 ]/ row [- 1 ])
52-
53-
54- # TODO: Color row text foreground based on population density
55-
39+ # Formatter functions
5640
5741def no_dec (num : float ) -> str :
5842 """Format a floating point number with no decimal places."""
@@ -64,17 +48,94 @@ def two_dec(num: float) -> str:
6448 return "{0:.2f}" .format (num )
6549
6650
51+ # Population data from Wikipedia: https://en.wikipedia.org/wiki/List_of_cities_proper_by_population
52+
53+
54+ # ############ Table data formatted as an iterable of iterable fields ############
55+
56+ EXAMPLE_ITERABLE_DATA = [['Shanghai' , 'Shanghai' , 'China' , 'Asia' , 24183300 , 6340.5 ],
57+ ['Beijing' , 'Hebei' , 'China' , 'Asia' , 20794000 , 1749.57 ],
58+ ['Karachi' , 'Sindh' , 'Pakistan' , 'Asia' , 14910352 , 615.58 ],
59+ ['Shenzen' , 'Guangdong' , 'China' , 'Asia' , 13723000 , 1493.32 ],
60+ ['Guangzho' , 'Guangdong' , 'China' , 'Asia' , 13081000 , 1347.81 ],
61+ ['Mumbai' , 'Maharashtra' , 'India' , 'Asia' , 12442373 , 465.78 ],
62+ ['Istanbul' , 'Istanbul' , 'Turkey' , 'Eurasia' , 12661000 , 620.29 ],
63+ ]
64+
65+ # Calculate population density
66+ for row in EXAMPLE_ITERABLE_DATA :
67+ row .append (row [- 2 ]/ row [- 1 ])
68+
69+
6770# # Column headers plus optional formatting info for each column
6871columns = [tf .Column ('City' , header_halign = tf .ColumnAlignment .AlignCenter ),
6972 tf .Column ('Province' , header_halign = tf .ColumnAlignment .AlignCenter ),
7073 'Country' , # NOTE: If you don't need any special effects, you can just pass a string
7174 tf .Column ('Continent' , cell_halign = tf .ColumnAlignment .AlignCenter ),
7275 tf .Column ('Population' , cell_halign = tf .ColumnAlignment .AlignRight , formatter = tf .FormatCommas ()),
73- tf .Column ('Area (km^2)' , cell_halign = tf .ColumnAlignment .AlignRight , formatter = two_dec ),
74- tf .Column ('Pop. Density (/km^2)' , width = 12 , cell_halign = tf .ColumnAlignment .AlignRight , formatter = no_dec ),
76+ tf .Column ('Area (km²)' , width = 7 , header_halign = tf .ColumnAlignment .AlignCenter ,
77+ cell_halign = tf .ColumnAlignment .AlignRight , formatter = two_dec ),
78+ tf .Column ('Pop. Density (/km²)' , width = 12 , header_halign = tf .ColumnAlignment .AlignCenter ,
79+ cell_halign = tf .ColumnAlignment .AlignRight , formatter = no_dec ),
7580 ]
7681
7782
83+ # ######## Table data formatted as an iterable of python objects #########
84+
85+ class CityInfo (object ):
86+ """City information container"""
87+ def __init__ (self , city : str , province : str , country : str , continent : str , population : int , area : float ):
88+ self .city = city
89+ self .province = province
90+ self .country = country
91+ self .continent = continent
92+ self ._population = population
93+ self ._area = area
94+
95+ def get_population (self ):
96+ """Population of the city"""
97+ return self ._population
98+
99+ def get_area (self ):
100+ """Area of city in km²"""
101+ return self ._area
102+
103+
104+ def pop_density (data : CityInfo ):
105+ """Calculate the population density from the data entry"""
106+ if isinstance (data , CityInfo ):
107+ return no_dec (data .get_population () / data .get_area ())
108+
109+ return ''
110+
111+
112+ EXAMPLE_OBJECT_DATA = [CityInfo ('Shanghai' , 'Shanghai' , 'China' , 'Asia' , 24183300 , 6340.5 ),
113+ CityInfo ('Beijing' , 'Hebei' , 'China' , 'Asia' , 20794000 , 1749.57 ),
114+ CityInfo ('Karachi' , 'Sindh' , 'Pakistan' , 'Asia' , 14910352 , 615.58 ),
115+ CityInfo ('Shenzen' , 'Guangdong' , 'China' , 'Asia' , 13723000 , 1493.32 ),
116+ CityInfo ('Guangzho' , 'Guangdong' , 'China' , 'Asia' , 13081000 , 1347.81 ),
117+ CityInfo ('Mumbai' , 'Maharashtra' , 'India' , 'Asia' , 12442373 , 465.78 ),
118+ CityInfo ('Istanbul' , 'Istanbul' , 'Turkey' , 'Eurasia' , 12661000 , 620.29 ),
119+ ]
120+
121+ # If table entries are python objects, all columns must be defined with the object attribute to query for each field
122+ # - attributes can be fields or functions. If a function is provided, the formatter will automatically call
123+ # the function to retrieve the value
124+ obj_cols = [tf .Column ('City' , attrib = 'city' , header_halign = tf .ColumnAlignment .AlignCenter ),
125+ tf .Column ('Province' , attrib = 'province' , header_halign = tf .ColumnAlignment .AlignCenter ),
126+ tf .Column ('Country' , attrib = 'country' ),
127+ tf .Column ('Continent' , attrib = 'continent' , cell_halign = tf .ColumnAlignment .AlignCenter ),
128+ tf .Column ('Population' , attrib = 'get_population' , cell_halign = tf .ColumnAlignment .AlignRight ,
129+ formatter = tf .FormatCommas ()),
130+ tf .Column ('Area (km²)' , attrib = 'get_area' , width = 7 , header_halign = tf .ColumnAlignment .AlignCenter ,
131+ cell_halign = tf .ColumnAlignment .AlignRight , formatter = two_dec ),
132+ tf .Column ('Pop. Density (/km²)' , width = 12 , header_halign = tf .ColumnAlignment .AlignCenter ,
133+ cell_halign = tf .ColumnAlignment .AlignRight , obj_formatter = pop_density ),
134+ ]
135+
136+ # TODO: Color row text foreground based on population density
137+
138+
78139class TableDisplay (cmd2 .Cmd ):
79140 """Example cmd2 application showing how you can display tabular data."""
80141
@@ -98,7 +159,11 @@ def ptable(self, tabular_data, headers=()):
98159
99160 def do_table (self , _ ):
100161 """Display data on the Earth's most populated cities in a table."""
101- self .ptable (EXAMPLE_DATA , columns )
162+ self .ptable (EXAMPLE_ITERABLE_DATA , columns )
163+
164+ def do_object_table (self , _ ):
165+ """Display data on the Earth's most populated cities in a table."""
166+ self .ptable (EXAMPLE_OBJECT_DATA , obj_cols )
102167
103168
104169if __name__ == '__main__' :
0 commit comments