ecoscape-utilities 0.0.36__py3-none-any.whl → 0.0.38__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of ecoscape-utilities might be problematic. Click here for more details.

@@ -11,6 +11,34 @@ from pyproj.crs import CRS
11
11
 
12
12
  from scgt import GeoTiff
13
13
 
14
+ def expand_sqlite_query(query, params):
15
+ """
16
+ Expands an SQLite query string with named parameters from a dictionary.
17
+
18
+ Args:
19
+ query (str): The SQL query string with :variable placeholders.
20
+ params (dict): A dictionary mapping variable names to their values.
21
+
22
+ Returns:
23
+ str: The expanded SQL query string.
24
+ """
25
+ expanded_query = query
26
+ for key, value in params.items():
27
+ placeholder = f":{key}"
28
+ if isinstance(value, str):
29
+ # Escape any single quotes within the string
30
+ formatted_value = f"'{value.replace("'", "''")}'"
31
+ elif value is None:
32
+ formatted_value = 'NULL'
33
+ else:
34
+ # For integers, floats, and other types
35
+ formatted_value = str(value)
36
+
37
+ expanded_query = expanded_query.replace(placeholder, formatted_value)
38
+
39
+ return expanded_query
40
+
41
+
14
42
  """
15
43
  A module for interaction with a sqlite database. Contains functions for query execution,
16
44
  and some common functionality we need to run on the DB
@@ -72,14 +100,14 @@ class EbirdObservations(Connection):
72
100
  super().__init__(db_file)
73
101
 
74
102
  def get_all_squares(self, state=None,
75
- breeding=True, date_range=None,
103
+ breeding=None, date_range=None,
76
104
  lat_range=None, lng_range=None, max_dist=2, min_time=None,
77
105
  verbose=False):
78
106
  """
79
107
  Gets all squares with bird (any bird) observations, for a certain state,
80
108
  and withing certain lat, lng, and date ranges.
81
109
  :param state (str): state code
82
- :param breeding (boolean): whether to filter observations by breeding months (getting only apr-june)
110
+ :param breeding: None, or pair of months delimiting the breeding season, e.g. ("04", "06").
83
111
  :param date_range: tuple of 2 date-strings in format "YYYY-MM-DD" to get only observations in this date range
84
112
  :param lat_range: tuple of 2 floats for the lower and upper bounds for latitude
85
113
  :param lng_range: tuple of 2 floats for the lower and upper bounds for longitude
@@ -99,12 +127,12 @@ class EbirdObservations(Connection):
99
127
  query_string.append('and "STATE CODE" = :state')
100
128
  d['state'] = state
101
129
  # Adds breeding portion
102
- if breeding:
130
+ if breeding is not None:
103
131
  query_string.extend([
104
- 'and (substr("OBSERVATION DATE", 6, 2) = "04"',
105
- 'OR substr("OBSERVATION DATE", 6, 2) = "05"',
106
- 'OR substr("OBSERVATION DATE", 6, 2) = "06")'
132
+ 'and substr("OBSERVATION DATE", 6, 2) >= ":br1"',
133
+ 'and substr("OBSERVATION DATE", 6, 2) <= ":br2"',
107
134
  ])
135
+ d['br1'], d['br2'] = breeding
108
136
  if date_range is not None:
109
137
  query_string.append('and "OBSERVATION DATE" >= :min_date')
110
138
  query_string.append('and "OBSERVATION DATE" <= :max_date')
@@ -120,11 +148,12 @@ class EbirdObservations(Connection):
120
148
  query_string = " ".join(query_string)
121
149
  if verbose:
122
150
  print("Query:", query_string)
151
+ print("Expanded query:", expand_sqlite_query(query_string, d))
123
152
  squares_list = self.execute_query((query_string, d))
124
153
  return [sq[0] for sq in squares_list]
125
154
 
126
155
  def get_square_observations(self, square, bird,
127
- breeding=True, date_range=None,
156
+ breeding=None, date_range=None,
128
157
  lat_range=None, lng_range=None, max_dist=2, min_time=None,
129
158
  verbose=False):
130
159
  """
@@ -132,7 +161,7 @@ class EbirdObservations(Connection):
132
161
  total time, total distance, and total bird sightings, for a square.
133
162
  :param square: tuple of 2 floats, representing (lat, lng) of the square
134
163
  :param bird: bird
135
- :param breeding (boolean): whether to filter observations by breeding months (getting only apr-june)
164
+ :param breeding: pair of months delimiting breeding season, or None (e.g., ("04", "06")).
136
165
  :param date_range: tuple of 2 date-strings in format "YYYY-MM-DD" to get only observations in this date range
137
166
  :param lat_range: tuple of 2 floats for the lower and upper bounds for latitude
138
167
  :param lng_range: tuple of 2 floats for the lower and upper bounds for longitude
@@ -153,12 +182,12 @@ class EbirdObservations(Connection):
153
182
  query_string.append('and "DURATION MINUTES" >= :min_time')
154
183
  d["min_time"] = min_time
155
184
  # Adds breeding portion
156
- if breeding:
185
+ if breeding is not None:
157
186
  query_string.extend([
158
- 'and (substr("OBSERVATION DATE", 6, 2) = "04"',
159
- 'OR substr("OBSERVATION DATE", 6, 2) = "05"',
160
- 'OR substr("OBSERVATION DATE", 6, 2) = "06")'
187
+ 'and substr("OBSERVATION DATE", 6, 2) >= ":br1"',
188
+ 'and substr("OBSERVATION DATE", 6, 2) <= ":br2"',
161
189
  ])
190
+ d['br1'], d['br2'] = breeding
162
191
  if date_range is not None:
163
192
  query_string.append('and "OBSERVATION DATE" >= :min_date')
164
193
  query_string.append('and "OBSERVATION DATE" <= :max_date')
@@ -195,12 +224,12 @@ class EbirdObservations(Connection):
195
224
  query_string.append('and checklist."EFFORT DISTANCE KM" <= :dist')
196
225
  d["dist"] = max_dist
197
226
  # Adds breeding portion
198
- if breeding:
227
+ if breeding is not None:
199
228
  query_string.extend([
200
- 'and (substr(checklist."OBSERVATION DATE", 6, 2) = "04"',
201
- 'OR substr(checklist."OBSERVATION DATE", 6, 2) = "05"',
202
- 'OR substr(checklist."OBSERVATION DATE", 6, 2) = "06")'
229
+ 'and substr("OBSERVATION DATE", 6, 2) >= ":br1"',
230
+ 'and substr("OBSERVATION DATE", 6, 2) <= ":br2"',
203
231
  ])
232
+ d['br1'], d['br2'] = breeding
204
233
  if date_range is not None:
205
234
  query_string.append('and checklist."OBSERVATION DATE" >= :min_date')
206
235
  query_string.append('and checklist."OBSERVATION DATE" <= :max_date')
@@ -220,6 +249,7 @@ class EbirdObservations(Connection):
220
249
  query_string = " ".join(query_string)
221
250
  if verbose:
222
251
  print("Query:", query_string)
252
+ print("Expanded query:", expand_sqlite_query(query_string, d))
223
253
  r = self.execute_query((query_string, d))
224
254
  if r is None:
225
255
  num_birds = 0
@@ -237,7 +267,7 @@ class EbirdObservations(Connection):
237
267
  )
238
268
 
239
269
  def get_square_individual_checklists(self, square, bird,
240
- breeding=True, date_range=None,
270
+ breeding=None, date_range=None,
241
271
  lat_range=None, lng_range=None, max_dist=2,
242
272
  verbose=False):
243
273
  """
@@ -247,7 +277,7 @@ class EbirdObservations(Connection):
247
277
  and total bird sightings, for a square.
248
278
  :param square: tuple of 2 floats, representing (lat, lng) of the square
249
279
  :param bird (str): name of bird
250
- :param breeding (boolean): whether to filter observations by breeding months (getting only apr-june)
280
+ :param breeding: None, or pair of months delimiting breeding season ("04", "06").
251
281
  :param date_range: tuple of 2 date-strings in format "YYYY-MM-DD" to get only observations in this date range
252
282
  :param lat_range: tuple of 2 floats for the lower and upper bounds for latitude
253
283
  :param lng_range: tuple of 2 floats for the lower and upper bounds for longitude
@@ -264,12 +294,12 @@ class EbirdObservations(Connection):
264
294
  query_string.append('and "EFFORT DISTANCE KM" <= :dist')
265
295
  d["dist"] = max_dist
266
296
  # Adds breeding portion
267
- if breeding:
297
+ if breeding is not None:
268
298
  query_string.extend([
269
- 'and (substr("OBSERVATION DATE", 6, 2) = "04"',
270
- 'OR substr("OBSERVATION DATE", 6, 2) = "05"',
271
- 'OR substr("OBSERVATION DATE", 6, 2) = "06")'
299
+ 'and substr("OBSERVATION DATE", 6, 2) >= ":br1"',
300
+ 'and substr("OBSERVATION DATE", 6, 2) <= ":br2"',
272
301
  ])
302
+ d['br1'], d['br2'] = breeding
273
303
  if date_range is not None:
274
304
  query_string.append('and "OBSERVATION DATE" >= :min_date')
275
305
  query_string.append('and "OBSERVATION DATE" <= :max_date')
@@ -299,12 +329,12 @@ class EbirdObservations(Connection):
299
329
  query_string.append('and checklist."EFFORT DISTANCE KM" <= :dist')
300
330
  d["dist"] = max_dist
301
331
  # Adds breeding portion
302
- if breeding:
332
+ if breeding is not None:
303
333
  query_string.extend([
304
- 'and (substr(checklist."OBSERVATION DATE", 6, 2) = "04"',
305
- 'OR substr(checklist."OBSERVATION DATE", 6, 2) = "05"',
306
- 'OR substr(checklist."OBSERVATION DATE", 6, 2) = "06")'
334
+ 'and substr("OBSERVATION DATE", 6, 2) >= ":br1"',
335
+ 'and substr("OBSERVATION DATE", 6, 2) <= ":br2"',
307
336
  ])
337
+ d['br1'], d['br2'] = breeding
308
338
  if date_range is not None:
309
339
  query_string.append('and checklist."OBSERVATION DATE" >= :min_date')
310
340
  query_string.append('and checklist."OBSERVATION DATE" <= :max_date')
@@ -324,6 +354,7 @@ class EbirdObservations(Connection):
324
354
  query_string = " ".join(query_string)
325
355
  if verbose:
326
356
  print("Query:", query_string)
357
+ print("Expanded query:", expand_sqlite_query(query_string, d))
327
358
  rows = self.execute_query((query_string, d))
328
359
  counts = defaultdict(int)
329
360
  for r in rows:
@@ -331,14 +362,14 @@ class EbirdObservations(Connection):
331
362
  checklists_df["Count"] = checklists_df.apply(lambda row : counts[row["SAMPLING EVENT IDENTIFIER"]], axis=1)
332
363
  return checklists_df
333
364
 
334
- def get_squares_with_bird(self, bird, max_dist=1, breeding=False,
365
+ def get_squares_with_bird(self, bird, max_dist=1, breeding=None,
335
366
  date_range=None, lat_range=None, lng_range=None,
336
367
  state=None, verbose=False):
337
368
  """Gets all the squares where a bird has been sighted. This is used
338
369
  primarily to refine the terrain resistance.
339
370
  :param bird: Common name of the bird
340
371
  :param max_dist: max length of the checklist in Km
341
- :param breeding: whether to consider only the breeding period or not
372
+ :param breeding: pair of months delimiting breeding season, or None.
342
373
  :param date_range: date range in years, as a string tuple of yyyy-mm-dd dates
343
374
  :param lat_range: range of latitudes to consider, as number tuple, optional.
344
375
  :param lng_range: range of longitudes to consider, as number tuple, optional.
@@ -358,12 +389,12 @@ class EbirdObservations(Connection):
358
389
  query_string.append('and checklist."PROTOCOL TYPE" != "Incidental"')
359
390
  query_string.append('and checklist."EFFORT DISTANCE KM" <= :dist')
360
391
  # Adds breeding portion
361
- if breeding:
392
+ if breeding is not None:
362
393
  query_string.extend([
363
- 'and (substr(checklist."OBSERVATION DATE", 6, 2) = "04"',
364
- 'OR substr(checklist."OBSERVATION DATE", 6, 2) = "05"',
365
- 'OR substr(checklist."OBSERVATION DATE", 6, 2) = "06")'
394
+ 'and substr("OBSERVATION DATE", 6, 2) >= ":br1"',
395
+ 'and substr("OBSERVATION DATE", 6, 2) <= ":br2"',
366
396
  ])
397
+ d['br1'], d['br2'] = breeding
367
398
  if date_range is not None:
368
399
  query_string.append('and checklist."OBSERVATION DATE" >= :min_date')
369
400
  query_string.append('and checklist."OBSERVATION DATE" <= :max_date')
@@ -380,82 +411,11 @@ class EbirdObservations(Connection):
380
411
  query_string = " ".join(query_string)
381
412
  if verbose:
382
413
  print("Query:", query_string)
414
+ print("Expanded query:", expand_sqlite_query(query_string, d))
383
415
  r = self.execute_query((query_string, d))
384
416
  return [row[0] for row in r]
385
417
 
386
418
 
387
- def get_observation_ratios(self, bird, min_checklists, bigsquare=False,
388
- max_dist=1, verbose=False,
389
- state=None, breeding=True):
390
- """This function is not used now. It was the old, deprecated way of
391
- doing validation, and we are keeping the code for reference only."""
392
- # First, I create a dictionary of squares to checklist counts.
393
- query_string = [
394
- 'select "SAMPLING EVENT IDENTIFIER",',
395
- 'BIGSQUARE' if bigsquare else 'SQUARE',
396
- 'from checklist where',
397
- '"ALL SPECIES REPORTED" = 1',
398
- ]
399
- d = {'dist': max_dist}
400
- query_string.append('and "PROTOCOL TYPE" != "Incidental"')
401
- query_string.append('and "EFFORT DISTANCE KM" <= :dist')
402
- if state is not None:
403
- query_string.append('and "STATE CODE" = :state')
404
- d['state'] = state
405
- # Adds breeding portion
406
- if breeding:
407
- query_string.extend([
408
- 'and (substr("OBSERVATION DATE", 6, 2) = "04"',
409
- 'OR substr("OBSERVATION DATE", 6, 2) = "05"',
410
- 'OR substr("OBSERVATION DATE", 6, 2) = "06")'
411
- ])
412
- query_string = " ".join(query_string)
413
- if verbose:
414
- print("Query:", query_string)
415
- observations = self.execute_query((query_string, d))
416
- checklists_per_square = defaultdict(int)
417
- for _, sq in observations:
418
- checklists_per_square[sq] += 1
419
- # Now I keep only the squares with a minimum of checklists.
420
- checklists_per_square = {sq: c for sq, c in checklists_per_square.items() if c >= min_checklists}
421
- # Ok, I care only about these squares.
422
- # Now I want to know, for each of these squares, how many checklists there are that
423
- # contain the bird.
424
- query_string = [
425
- 'select DISTINCT checklist."SAMPLING EVENT IDENTIFIER",',
426
- 'checklist.BIGSQUARE' if bigsquare else 'checklist.SQUARE',
427
- 'from checklist join observation on',
428
- 'checklist."SAMPLING EVENT IDENTIFIER" = observation."SAMPLING EVENT IDENTIFIER"',
429
- 'where observation."COMMON NAME" = :bird',
430
- 'and checklist."ALL SPECIES REPORTED" = 1',
431
- ]
432
- d = {'dist': max_dist ,'bird': bird}
433
- query_string.append('and checklist."PROTOCOL TYPE" != "Incidental"')
434
- query_string.append('and checklist."EFFORT DISTANCE KM" <= :dist')
435
- if state is not None:
436
- query_string.append('and checklist."STATE CODE" = :state')
437
- d['state'] = state
438
- if breeding:
439
- query_string.extend([
440
- 'and (substr(checklist."OBSERVATION DATE", 6, 2) = "04"',
441
- 'OR substr(checklist."OBSERVATION DATE", 6, 2) = "05"',
442
- 'OR substr(checklist."OBSERVATION DATE", 6, 2) = "06")',
443
- ])
444
- query_string = " ".join(query_string)
445
- if verbose:
446
- print("Query:", query_string)
447
- observations = self.execute_query((query_string, d))
448
- good_checklists_per_square = defaultdict(int)
449
- for _, sq in observations:
450
- if sq in checklists_per_square: # Otherwise, too few observations.
451
- good_checklists_per_square[sq] += 1
452
- for sq in checklists_per_square:
453
- if good_checklists_per_square[sq] > checklists_per_square[sq]:
454
- print("Too many checklists at", sq, good_checklists_per_square[sq], checklists_per_square[sq])
455
- return {sq: (good_checklists_per_square[sq] / checklists_per_square[sq])
456
- for sq in checklists_per_square}
457
-
458
-
459
419
  def format_coords(coords, bigsquare=False):
460
420
  """
461
421
  formats coords from the eBird database format '4406;-12131' to
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ecoscape-utilities
3
- Version: 0.0.36
3
+ Version: 0.0.38
4
4
  Summary: A collection of EcoScape utilities.
5
5
  Author-email: Luca de Alfaro <luca@ucsc.edu>, Coen Adler <ctadler@ucsc.edu>, Artie Nazarov <anazarov@ucsc.edu>, Natalia Ocampo-Peñuela <nocampop@ucsc.edu>, Jasmine Tai <cjtai@ucsc.edu>, Natalie Valett <nvalett@ucsc.edu>
6
6
  Project-URL: Homepage, https://github.com/ecoscape-earth/ecoscape-utilities
@@ -0,0 +1,8 @@
1
+ ecoscape_utilities/__init__.py,sha256=LXt1rL9JVsjnCmsNZwZ2aoElphIK-koaEDdW6ffZsMQ,50
2
+ ecoscape_utilities/bird_runs.py,sha256=v43PfH_4ojpkTE-EFOJxr0oOW3M9suNm_1zMjZ9P-eI,5409
3
+ ecoscape_utilities/ebird_db.py,sha256=vMezw5AFIrd4RVITWbLpsZlDGBxig5CoVQMzT7XDeNk,28067
4
+ ecoscape_utilities-0.0.38.dist-info/licenses/LICENSE.md,sha256=3vh2mpA_XIR3FJot6a5F9DqktAoq45sEGIRkYjvAEeU,1304
5
+ ecoscape_utilities-0.0.38.dist-info/METADATA,sha256=E9tCnd-2Ipwy9tzDGz30uICoVmJ2mzuxrGUcuuZFGSs,1382
6
+ ecoscape_utilities-0.0.38.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
7
+ ecoscape_utilities-0.0.38.dist-info/top_level.txt,sha256=jLf7iMlySaJg0Vh8z4lbAaqOc5W5ruMgKFvp797CryQ,19
8
+ ecoscape_utilities-0.0.38.dist-info/RECORD,,
@@ -1,8 +0,0 @@
1
- ecoscape_utilities/__init__.py,sha256=LXt1rL9JVsjnCmsNZwZ2aoElphIK-koaEDdW6ffZsMQ,50
2
- ecoscape_utilities/bird_runs.py,sha256=v43PfH_4ojpkTE-EFOJxr0oOW3M9suNm_1zMjZ9P-eI,5409
3
- ecoscape_utilities/ebird_db.py,sha256=LLd6noS4LJQLOtQEquVuRo1rRKm0XrM4ygba-xV7O88,30656
4
- ecoscape_utilities-0.0.36.dist-info/licenses/LICENSE.md,sha256=3vh2mpA_XIR3FJot6a5F9DqktAoq45sEGIRkYjvAEeU,1304
5
- ecoscape_utilities-0.0.36.dist-info/METADATA,sha256=8Jom07zUfpyrfIG4P_h3MnN-IrTp0-4d4bdJnQmQR1E,1382
6
- ecoscape_utilities-0.0.36.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
7
- ecoscape_utilities-0.0.36.dist-info/top_level.txt,sha256=jLf7iMlySaJg0Vh8z4lbAaqOc5W5ruMgKFvp797CryQ,19
8
- ecoscape_utilities-0.0.36.dist-info/RECORD,,