3
# Copyright 2011 S. Brewster Malevich <malevich@email.arizona.edu>
5
# PyDendro is free software: you can redistribute it and/or modify
6
# it under the terms of the GNU General Public License as published by
7
# the Free Software Foundation, either version 3 of the License, or
8
# (at your option) any later version.
10
# This program is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
# GNU General Public License for more details.
15
# You should have received a copy of the GNU General Public License
16
# along with this program. If not, see <http://www.gnu.org/licenses/>
19
Classes to read dendrochronological files from the ITRDB.
24
from scipy.stats.stats import pearsonr
28
"""Parent class to be inherited specific dendro files formats.
31
path -- Path to the target .crn file.
34
def __init__(self, path):
35
"""Opens file 'path' and checks that it exists.
37
if not os.path.isfile(path):
41
class RawMeas(DendroFile):
42
"""Class to handle *.rwl files from the ITRDB.
44
-This class is in progress.-
47
path -- Path to the target .crn file.
50
def __init__(self, path):
51
"""Parses the RWL file, defining instance attributes.
53
DendroFile.__init__(self,path)
54
# TODO: Test if file has header... (do they all?)
55
# TODO: Parse header file.
58
class Chronology(DendroFile):
59
"""Class to handle *.crn files from the ITRDB.
62
path -- Path to the target .crn file.
65
An object of class Chronology.
68
Note that the optional ITRDB "Chronology Statistics" will not be
69
preserved. This object is based on format definitions of the ITRDB (see
70
http://www.ncdc.noaa.gov/paleo/treeinfo.html).
76
A string indicating the tree-ring chronology file type (e.g. "ARSTND",
80
A list of integers corresponding to each year with a chronology index
84
A list of float for chronology tree-ring index values for each
85
of the chronology's years.
88
An integer list of the measurement sample site for each year of the
92
A string name of sampled species for the chronology site.
95
A string code for the sampled species of the chronology site.
98
A string site ID for the chronology.
101
Name of the chronology's sample site. A string.
104
String giving the state and country of the chronology's sample site.
107
An integer of the chronology sample site's latitude and longitude
108
(ddmm or dddmm). I've found a variety of formats for this so, beware.
111
Integer of the chronology site's elevation.
114
The first year of the chronology. An integer.
117
The last year of the chronology. An integer.
120
A string giving the chonology's final collection date.
123
A string of lead investigator(s).
126
def __init__(self, path):
127
"""Parses the Chronology file defining instance attributes.
129
DendroFile.__init__(self,path)
133
self.sampledepth = []
134
self.speciesname = None
135
self.speciescode = None
140
self.elevation = None
141
self.firstyear = None
143
self.collectiondate = None
144
self.investigator = None
146
types = {'a.crn':'ARSTND',
147
'p.crn':'Low Pass Filter',
150
'w.crn':'Re-Whitened Residual',
151
'n.crn':'Measurements Only'}
152
if self._path[-5:] in types:
153
self.type = types[self._path[-5:]]
155
self.type = 'Unknown'
156
headermark = [' 1 ', ' 2 ', ' 3 '] # To identify the header.
157
header1 = linecache.getline(path, 1)
158
header2 = linecache.getline(path, 2)
159
header3 = linecache.getline(path, 3)
160
if header1[6:9] == headermark[0]:
161
self.siteid = str(header1[0:6]).strip()
162
self.sitename = str(header1[9:61]).strip()
163
self.speciescode = str(header1[61:65]).strip()
165
raise NameError('File ' + self._path
166
+ ' appears to have no header.')
167
if header2[6:9] == headermark[1]:
168
self.location = str(header2[9:22]).strip()
169
self.speciesname = str(header2[22:30]).strip()
170
# Slice elevation to ':44' to cut out the "M".
171
self.elevation = int(header2[40:44])
172
self.latlon = str(header2[47:57]).strip()
173
self.firstyear = int(header2[67:71])
174
self.lastyear = int(header2[72:76])
175
self.years = range(self.firstyear, self.lastyear + 1)
177
raise NameError('File ' + self._path
178
+ ' appears to have no header.')
179
if header3[6:9] == headermark[2]:
180
self.investigator = str(header3[9:72]).strip()
181
self.collectiondate = str(header3[72:80]).strip()
183
raise NameError('File ' + self._path
184
+ ' appears to have no header.')
185
lastdecade = self.lastyear - (self.lastyear % 10) # To ID last line.
186
for line in open(path):
187
if line[6:9] in headermark:
189
a = 10 # Tree-ring index index.
191
c = 14 # Ring count index.
193
for i in range(0, 10):
201
victim = victim.strip()
202
victim = victim.zfill(4)
203
self.values.append(float(victim[:1] + '.' + victim[1:]))
204
self.sampledepth.append(int(line[c:d]))
209
if int(line[6:10]) == lastdecade: # Stop after last line.
211
if len(self.values) != len(self.sampledepth) != len(self.years):
212
raise NameError('Unequal values, samples sizes'
213
+ 'and years from chronology file.')
215
def crop_corr(self, x, x_years):
216
"""Crop and correlate a chrnology with a given variable.
219
x -- An array/list(?) of your variable of interest.
220
x_years -- Array/list of years corresponding to the x observations.
223
A tuple giving 1) Pearson's correlation coefficient, 2) 2-tailed
224
p-value, 3) length of the common period between crn and x.
227
crn_values = np.array(self.values)
228
crn_years = np.array(self.years)
229
if len(crn_values) != len(crn_years):
230
raise ValueError('unequal values and years')
231
# Might want to check if x and x_years are not array...?
232
# Type checks are python taboo but I'm not sure how numpy will handle
234
year_min = np.maximum(np.min(crn_years), np.min(x_years))
235
year_max = np.minimum(np.max(crn_years), np.max(x_years))
236
crn_crop = crn_values[(crn_years >= year_min)
237
& (crn_years <= year_max)]
238
x_crop = x[(x_years >= year_min) & (x_years <= year_max)]
239
results = pearsonr(crn_crop, x_crop)
240
results += (len(crn_crop),)