1 | import csv |
---|
2 | |
---|
3 | from anuga.anuga_exceptions import TitleValueError, \ |
---|
4 | DataMissingValuesError |
---|
5 | |
---|
6 | from anuga.file.csv_file import load_csv_as_dict |
---|
7 | |
---|
8 | from anuga.geospatial_data.geospatial_data import Geospatial_data,\ |
---|
9 | ensure_absolute |
---|
10 | |
---|
11 | LAT_TITLE = 'LATITUDE' |
---|
12 | LONG_TITLE = 'LONGITUDE' |
---|
13 | X_TITLE = 'x' |
---|
14 | Y_TITLE = 'y' |
---|
15 | |
---|
16 | |
---|
17 | |
---|
18 | class Exposure: |
---|
19 | ''' |
---|
20 | Class for National Exposure Database storage (NEXIS). |
---|
21 | Returns a csv file handle |
---|
22 | ''' |
---|
23 | def __init__(self,file_name, latitude_title=LAT_TITLE, |
---|
24 | longitude_title=LONG_TITLE, is_x_y_locations=None, |
---|
25 | x_title=X_TITLE, y_title=Y_TITLE, |
---|
26 | refine_polygon=None, title_check_list=None): |
---|
27 | """ |
---|
28 | This class is for handling the exposure csv file. |
---|
29 | It reads the file in and converts the lats and longs to a geospatial |
---|
30 | data object. |
---|
31 | Use the methods to read and write columns. |
---|
32 | |
---|
33 | The format of the csv files it reads is; |
---|
34 | The first row is a title row. |
---|
35 | comma's are the delimiters |
---|
36 | each column is a 'set' of data |
---|
37 | |
---|
38 | Feel free to use/expand it to read other csv files. |
---|
39 | |
---|
40 | It is not for adding and deleting rows |
---|
41 | |
---|
42 | Can geospatial handle string attributes? It's not made for them. |
---|
43 | Currently it can't load and save string att's. |
---|
44 | |
---|
45 | So just use geospatial to hold the x, y and georef? Bad, since |
---|
46 | different att's are in diferent structures. Not so bad, the info |
---|
47 | to write if the .csv file is saved is in attribute_dic |
---|
48 | |
---|
49 | The location info is in the geospatial attribute. |
---|
50 | """ |
---|
51 | |
---|
52 | self._file_name = file_name |
---|
53 | self._geospatial = None # |
---|
54 | |
---|
55 | # self._attribute_dic is a dictionary. |
---|
56 | #The keys are the column titles. |
---|
57 | #The values are lists of column data |
---|
58 | |
---|
59 | # self._title_index_dic is a dictionary. |
---|
60 | #The keys are the column titles. |
---|
61 | #The values are the index positions of file columns. |
---|
62 | self._attribute_dic, self._title_index_dic = \ |
---|
63 | load_csv_as_dict(self._file_name, \ |
---|
64 | title_check_list=title_check_list) |
---|
65 | try: |
---|
66 | #Have code here that handles caps or lower |
---|
67 | lats = self._attribute_dic[latitude_title] |
---|
68 | longs = self._attribute_dic[longitude_title] |
---|
69 | except KeyError: |
---|
70 | # maybe a warning.. |
---|
71 | #Let's see if this works.. |
---|
72 | if False != is_x_y_locations: |
---|
73 | is_x_y_locations = True |
---|
74 | pass |
---|
75 | else: |
---|
76 | self._geospatial = Geospatial_data(latitudes=lats, |
---|
77 | longitudes=longs) |
---|
78 | |
---|
79 | if is_x_y_locations is True: |
---|
80 | if self._geospatial is not None: |
---|
81 | pass #fixme throw an error |
---|
82 | try: |
---|
83 | xs = self._attribute_dic[x_title] |
---|
84 | ys = self._attribute_dic[y_title] |
---|
85 | points = [[float(i),float(j)] for i,j in map(None,xs,ys)] |
---|
86 | except KeyError: |
---|
87 | # maybe a warning.. |
---|
88 | msg = "Could not find location information." |
---|
89 | raise TitleValueError, msg |
---|
90 | else: |
---|
91 | self._geospatial = Geospatial_data(data_points=points) |
---|
92 | |
---|
93 | # create a list of points that are in the refining_polygon |
---|
94 | # described by a list of indexes representing the points |
---|
95 | |
---|
96 | ## |
---|
97 | # @brief Create a comparison method. |
---|
98 | # @param self This object. |
---|
99 | # @param other The other object. |
---|
100 | # @return True if objects are 'same'. |
---|
101 | def __cmp__(self, other): |
---|
102 | #check that 'other' is an instance of this class |
---|
103 | if isinstance(self, type(other)): |
---|
104 | result = cmp(self._attribute_dic, other._attribute_dic) |
---|
105 | if result <> 0: |
---|
106 | return result |
---|
107 | |
---|
108 | # The order of the columns is important. Therefore.. |
---|
109 | result = cmp(self._title_index_dic, other._title_index_dic) |
---|
110 | if result <> 0: |
---|
111 | return result |
---|
112 | for self_ls, other_ls in map(None, self._attribute_dic, |
---|
113 | other._attribute_dic): |
---|
114 | result = cmp(self._attribute_dic[self_ls], |
---|
115 | other._attribute_dic[other_ls]) |
---|
116 | if result <> 0: |
---|
117 | return result |
---|
118 | return 0 |
---|
119 | else: |
---|
120 | return 1 |
---|
121 | |
---|
122 | ## |
---|
123 | # @brief Get a list of column values given a column name. |
---|
124 | # @param column_name The name of the column to get values from. |
---|
125 | # @param use_refind_polygon Unused?? |
---|
126 | def get_column(self, column_name, use_refind_polygon=False): |
---|
127 | """ |
---|
128 | Given a column name return a list of the column values |
---|
129 | |
---|
130 | Note, the type of the values will be String! |
---|
131 | do this to change a list of strings to a list of floats |
---|
132 | time = [float(x) for x in time] |
---|
133 | |
---|
134 | Not implemented: |
---|
135 | if use_refind_polygon is True, only return values in the |
---|
136 | refined polygon |
---|
137 | """ |
---|
138 | |
---|
139 | if not self._attribute_dic.has_key(column_name): |
---|
140 | msg = 'There is no column called %s!' % column_name |
---|
141 | raise TitleValueError, msg |
---|
142 | |
---|
143 | return self._attribute_dic[column_name] |
---|
144 | |
---|
145 | ## |
---|
146 | # @brief ?? |
---|
147 | # @param value_column_name ?? |
---|
148 | # @param known_column_name ?? |
---|
149 | # @param known_values ?? |
---|
150 | # @param use_refind_polygon ?? |
---|
151 | def get_value(self, value_column_name, known_column_name, |
---|
152 | known_values, use_refind_polygon=False): |
---|
153 | """ |
---|
154 | Do linear interpolation on the known_colum, using the known_value, |
---|
155 | to return a value of the column_value_name. |
---|
156 | """ |
---|
157 | |
---|
158 | pass |
---|
159 | |
---|
160 | ## |
---|
161 | # @brief Get a geospatial object that describes the locations. |
---|
162 | # @param use_refind_polygon Unused?? |
---|
163 | def get_location(self, use_refind_polygon=False): |
---|
164 | """ |
---|
165 | Return a geospatial object which describes the |
---|
166 | locations of the location file. |
---|
167 | |
---|
168 | Note, if there is not location info, this returns None. |
---|
169 | |
---|
170 | Not implemented: |
---|
171 | if use_refind_polygon is True, only return values in the |
---|
172 | refined polygon |
---|
173 | """ |
---|
174 | |
---|
175 | return self._geospatial |
---|
176 | |
---|
177 | ## |
---|
178 | # @brief Add column to 'end' of CSV data. |
---|
179 | # @param column_name The new column name. |
---|
180 | # @param column_values The new column values. |
---|
181 | # @param overwrite If True, overwrites last column, doesn't add at end. |
---|
182 | def set_column(self, column_name, column_values, overwrite=False): |
---|
183 | """ |
---|
184 | Add a column to the 'end' (with the right most column being the end) |
---|
185 | of the csv file. |
---|
186 | |
---|
187 | Set overwrite to True if you want to overwrite a column. |
---|
188 | |
---|
189 | Note, in column_name white space is removed and case is not checked. |
---|
190 | Precondition |
---|
191 | The column_name and column_values cannot have comma's in it. |
---|
192 | """ |
---|
193 | |
---|
194 | # sanity checks |
---|
195 | value_row_count = \ |
---|
196 | len(self._attribute_dic[self._title_index_dic.keys()[0]]) |
---|
197 | if len(column_values) <> value_row_count: |
---|
198 | msg = 'The number of column values must equal the number of rows.' |
---|
199 | raise DataMissingValuesError, msg |
---|
200 | |
---|
201 | # check new column name isn't already used, and we aren't overwriting |
---|
202 | if self._attribute_dic.has_key(column_name): |
---|
203 | if not overwrite: |
---|
204 | msg = 'Column name %s already in use!' % column_name |
---|
205 | raise TitleValueError, msg |
---|
206 | else: |
---|
207 | # New title. Add it to the title index. |
---|
208 | self._title_index_dic[column_name] = len(self._title_index_dic) |
---|
209 | |
---|
210 | self._attribute_dic[column_name] = column_values |
---|
211 | |
---|
212 | ## |
---|
213 | # @brief Save the exposure CSV file. |
---|
214 | # @param file_name If supplied, use this filename, not original. |
---|
215 | def save(self, file_name=None): |
---|
216 | """ |
---|
217 | Save the exposure csv file |
---|
218 | """ |
---|
219 | |
---|
220 | if file_name is None: |
---|
221 | file_name = self._file_name |
---|
222 | |
---|
223 | fd = open(file_name, 'wb') |
---|
224 | writer = csv.writer(fd) |
---|
225 | |
---|
226 | #Write the title to a cvs file |
---|
227 | line = [None] * len(self._title_index_dic) |
---|
228 | for title in self._title_index_dic.iterkeys(): |
---|
229 | line[self._title_index_dic[title]] = title |
---|
230 | writer.writerow(line) |
---|
231 | |
---|
232 | # Write the values to a cvs file |
---|
233 | value_row_count = \ |
---|
234 | len(self._attribute_dic[self._title_index_dic.keys()[0]]) |
---|
235 | for row_i in range(value_row_count): |
---|
236 | line = [None] * len(self._title_index_dic) |
---|
237 | for title in self._title_index_dic.iterkeys(): |
---|
238 | line[self._title_index_dic[title]] = \ |
---|
239 | self._attribute_dic[title][row_i] |
---|
240 | writer.writerow(line) |
---|
241 | |
---|