population-trend 2.0.2__py3-none-any.whl → 3.1.0__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.
@@ -1,6 +1,8 @@
1
1
  """A template Python module"""
2
2
 
3
- __version__ = "2.0.2"
3
+ __version__ = "3.1.0"
4
4
  from .cli import * # noqa
5
5
  from .filter_data import * # noqa
6
6
  from .population_growth_model import * # noqa
7
+ from .calculate_growth_rates import * # noqa
8
+ from bootstrapping_tools import * # noqa
@@ -0,0 +1,206 @@
1
+ from bootstrapping_tools import (
2
+ lambda_calculator,
3
+ power_law,
4
+ bootstrap_from_time_series,
5
+ get_bootstrap_deltas,
6
+ generate_latex_interval_string,
7
+ calculate_p_values,
8
+ )
9
+ from matplotlib.ticker import MaxNLocator
10
+
11
+ import json
12
+ import matplotlib.pyplot as plt
13
+ import numpy as np
14
+
15
+
16
+ def do_nothing():
17
+ pass
18
+
19
+
20
+ def fit_population_model(seasons_series, data_series):
21
+ parameters = lambda_calculator(seasons_series, data_series)
22
+ model = power_law(
23
+ seasons_series - seasons_series.iloc[0],
24
+ parameters[0],
25
+ parameters[1],
26
+ )
27
+ return model
28
+
29
+
30
+ def calculate_porcentual_diff(x, y):
31
+ return 100 * (x - y) / y
32
+
33
+
34
+ def generate_number_and_season_string(number, season):
35
+ return "{} ({})".format(
36
+ number,
37
+ season,
38
+ )
39
+
40
+
41
+ def calculate_seasons_intervals(seasons):
42
+ years = []
43
+ first_index = 0
44
+ for index in np.where(np.diff(seasons) != 1)[0]:
45
+ if seasons[first_index] == seasons[index]:
46
+ years.append(f"{seasons[index]}")
47
+ else:
48
+ years.append(f"{seasons[first_index]}-{seasons[index]}")
49
+ first_index = index + 1
50
+ years.append(f"{seasons[first_index]}-{seasons[-1]}")
51
+ return years
52
+
53
+
54
+ def calculate_interest_numbers(cantidad_nidos, model):
55
+ first_number = generate_number_and_season_string(
56
+ cantidad_nidos["Maxima_cantidad_nidos"].iloc[0],
57
+ cantidad_nidos["Temporada"].iloc[0],
58
+ )
59
+ first_number_calculated = generate_number_and_season_string(
60
+ model.iloc[0], cantidad_nidos["Temporada"].iloc[0]
61
+ )
62
+ last_number = "{{{:,.0f}}} ({})".format(
63
+ cantidad_nidos["Maxima_cantidad_nidos"].iloc[-1],
64
+ int(cantidad_nidos["Temporada"].iloc[-1]),
65
+ )
66
+ last_number_calculated = generate_number_and_season_string(
67
+ model.iloc[-1],
68
+ cantidad_nidos["Temporada"].iloc[-1],
69
+ )
70
+ return first_number, first_number_calculated, last_number, last_number_calculated
71
+
72
+
73
+ def calculate_percent_diff_in_seasons(cantidad_nidos, model):
74
+ if cantidad_nidos["Maxima_cantidad_nidos"].iloc[0] == 0:
75
+ porcentaje_cambio = calculate_porcentual_diff(model.iloc[-1], model.iloc[0])
76
+ else:
77
+ porcentaje_cambio = calculate_porcentual_diff(
78
+ model.iloc[-1], cantidad_nidos["Maxima_cantidad_nidos"].iloc[0]
79
+ )
80
+ return porcentaje_cambio
81
+
82
+
83
+ class Bootstrap_from_time_series_parameterizer:
84
+ def __init__(self, blocks_length=3, N=2000):
85
+ self.parameters = dict(
86
+ dataframe=None,
87
+ column_name="Maxima_cantidad_nidos",
88
+ N=N,
89
+ return_distribution=True,
90
+ blocks_length=blocks_length,
91
+ )
92
+
93
+ def set_data(self, data):
94
+ self.parameters["dataframe"] = data
95
+
96
+
97
+ Bootstrap = dict(
98
+ default=Bootstrap_from_time_series_parameterizer(),
99
+ testing=Bootstrap_from_time_series_parameterizer(blocks_length=2, N=100),
100
+ )
101
+
102
+
103
+ class Bootstrap_from_time_series:
104
+ def __init__(self, bootstrap_parametrizer):
105
+ self.parameters = bootstrap_parametrizer.parameters
106
+ self.lambdas_distribution, self.intervals = self._calculate_distribution_and_interval()
107
+ self.season_series = self.parameters["dataframe"]["Temporada"]
108
+ self.data_series = self.parameters["dataframe"][self.parameters["column_name"]]
109
+ self.lambdas = [interval[0] for interval in self.intervals]
110
+
111
+ def get_distribution(self):
112
+ return self.lambdas_distribution
113
+
114
+ def _calculate_distribution_and_interval(self):
115
+ lambdas_distribution, intervals = bootstrap_from_time_series(**self.parameters)
116
+ return lambdas_distribution, intervals
117
+
118
+ def get_inferior_central_and_superior_limit(self):
119
+ inferior_limit, central, superior_limit = get_bootstrap_deltas(
120
+ self.lambdas, **{"decimals": 2}
121
+ )
122
+ return inferior_limit, central, superior_limit
123
+
124
+ def get_lambda_interval_latex_string(self):
125
+ lambda_latex_string = generate_latex_interval_string(self.lambdas, **{"decimals": 2})
126
+ return lambda_latex_string
127
+
128
+ def generate_season_interval(self):
129
+ return "({}-{})".format(
130
+ self.season_series.min(axis=0),
131
+ self.season_series.max(axis=0),
132
+ )
133
+
134
+ def get_monitored_seasons(self):
135
+ monitored_seasons = np.sort(self.season_series.astype(int).unique())
136
+ if len(monitored_seasons) == 1:
137
+ return f"{monitored_seasons[0]}"
138
+ else:
139
+ seasons_intervals = calculate_seasons_intervals(monitored_seasons)
140
+ return ",".join(seasons_intervals)
141
+
142
+ def xxfit_population_model(self):
143
+ parameters = lambda_calculator(self.season_series, self.data_series)
144
+ model = power_law(
145
+ self.season_series - self.season_series.iloc[0],
146
+ parameters[0],
147
+ parameters[1],
148
+ )
149
+ return model
150
+
151
+ def save_intervals(self, output_path):
152
+ json_dict = {
153
+ "intervals": list(self.intervals),
154
+ "lambda_latex_interval": self.get_lambda_interval_latex_string(),
155
+ }
156
+ with open(output_path, "w") as file:
157
+ json.dump(json_dict, file)
158
+
159
+
160
+ def calculate_growth_rates_table(bootstrap: Bootstrap_from_time_series_parameterizer):
161
+ bootstraper = Bootstrap_from_time_series(bootstrap)
162
+ df = bootstrap.parameters["dataframe"]
163
+ model = bootstraper.xxfit_population_model()
164
+ inferior_limit, central, superior_limit = bootstraper.get_inferior_central_and_superior_limit()
165
+ lambda_latex_string = bootstraper.get_lambda_interval_latex_string()
166
+ bootstrap_distribution = bootstraper.get_distribution()
167
+ lambdas_distribution = [interval[0] for interval in bootstrap_distribution]
168
+ p_value_mayor, p_value_menor = calculate_p_values(lambdas_distribution)
169
+ intervalo = bootstraper.generate_season_interval()
170
+ monitored_seasons = bootstraper.get_monitored_seasons()
171
+ porcentaje_cambio = calculate_percent_diff_in_seasons(df, model)
172
+ (
173
+ first_number,
174
+ _,
175
+ last_number,
176
+ last_number_calculated,
177
+ ) = calculate_interest_numbers(df, model)
178
+ return [
179
+ intervalo,
180
+ first_number,
181
+ last_number,
182
+ last_number_calculated,
183
+ lambda_latex_string,
184
+ df["Latitud"].iloc[0],
185
+ central,
186
+ f"-{inferior_limit}",
187
+ f"+{superior_limit}",
188
+ f"{{{int(porcentaje_cambio):,}}}",
189
+ p_value_mayor,
190
+ p_value_menor,
191
+ monitored_seasons,
192
+ ]
193
+
194
+
195
+ def set_axis_plot_config(ax):
196
+ ax.xaxis.set_major_locator(MaxNLocator(integer=True))
197
+ ax.spines["right"].set_visible(False)
198
+ ax.spines["top"].set_visible(False)
199
+ plt.yticks(rotation=90, size=20)
200
+ locs_x, labels_x = plt.xticks()
201
+ locs_y, labels_y = plt.yticks()
202
+ plt.xticks(locs_x[1:], size=20)
203
+ plt.xlim(locs_x[0], locs_x[-1])
204
+ plt.ylim(0, locs_y[-1])
205
+ plt.xlabel("Año", size=20, labelpad=10)
206
+ plt.ylabel("Cantidad de parejas reproductoras", size=20)
population_trend/cli.py CHANGED
@@ -37,15 +37,15 @@ def plot_population_trend(
37
37
  lambda_latex = intervals_json["lambda_latex_interval"]
38
38
 
39
39
  Modelo_Tendencia_Poblacional = Population_Trend_Model(fit_data, intervals, variable_of_interest)
40
- Graficador = Plotter_Population_Trend_Model()
40
+ Graficador = Plotter_Population_Trend_Model(fit_data)
41
41
  Graficador.plot_smooth(Modelo_Tendencia_Poblacional)
42
42
  Graficador.plot_model(Modelo_Tendencia_Poblacional)
43
- Graficador.plot_data(Modelo_Tendencia_Poblacional, fit_data[variable_of_interest])
43
+ Graficador.plot_data(variable_of_interest)
44
44
  legend_mpl_object = Graficador.set_legend_location(island)
45
- Graficador.set_x_lim(Modelo_Tendencia_Poblacional)
45
+ Graficador.set_x_lim()
46
46
  Graficador.set_y_lim(fit_data[variable_of_interest])
47
47
  Graficador.set_labels()
48
- Graficador.set_ticks(Modelo_Tendencia_Poblacional)
48
+ Graficador.set_ticks()
49
49
  Graficador.draw()
50
50
  Graficador.plot_growth_rate_interval(legend_mpl_object, lambda_latex)
51
51
  Graficador.savefig(island, output_path)
@@ -4,12 +4,17 @@ from bootstrapping_tools import power_law, lambda_calculator
4
4
  import matplotlib.pyplot as plt
5
5
 
6
6
 
7
- def resample_seasons(df):
7
+ def normalize_seasons(df):
8
8
  first_season = int(df.Temporada.min())
9
9
  last_season = int(df.Temporada.max())
10
10
  return np.linspace(first_season, last_season, last_season - first_season + 1).astype(int)
11
11
 
12
12
 
13
+ def calculate_model_domain(data):
14
+ last_value = data.Temporada.max() - data.Temporada.min()
15
+ return np.linspace(0, last_value, 100)
16
+
17
+
13
18
  def calculate_upper_limit(data_interest_variable):
14
19
  upper_limit = roundup(
15
20
  data_interest_variable.max() * 1.2,
@@ -21,36 +26,36 @@ def calculate_upper_limit(data_interest_variable):
21
26
  class Population_Trend_Model:
22
27
  def __init__(self, fit_data, intervals, interest_variable):
23
28
  self.intervals = intervals
24
- self.plot_seasons = fit_data["Temporada"][:] - fit_data["Temporada"].iloc[0] + 1
25
- self.ticks_text = resample_seasons(fit_data)
26
- self.ticks_positions = ticks_positions_array(self.ticks_text)
27
- self.time_to_model = np.linspace(
28
- self.ticks_positions.min(), self.ticks_positions.max(), 100
29
- )
29
+ self.model_domain = calculate_model_domain(fit_data)
30
30
  self.initial_population = lambda_calculator(
31
31
  fit_data["Temporada"], fit_data[interest_variable]
32
32
  )[1]
33
33
 
34
34
  @property
35
35
  def model_min(self):
36
- return power_law(self.time_to_model, self.intervals[0], self.initial_population)
36
+ return power_law(self.model_domain, self.intervals[0], self.initial_population)
37
37
 
38
38
  @property
39
39
  def model_med(self):
40
- return power_law(self.time_to_model, self.intervals[1], self.initial_population)
40
+ return power_law(self.model_domain, self.intervals[1], self.initial_population)
41
41
 
42
42
  @property
43
43
  def model_max(self):
44
- return power_law(self.time_to_model, self.intervals[2], self.initial_population)
44
+ return power_law(self.model_domain, self.intervals[2], self.initial_population)
45
45
 
46
46
 
47
47
  class Plotter_Population_Trend_Model:
48
- def __init__(self):
48
+ def __init__(self, data):
49
49
  self.fig, self.ax = geci_plot()
50
+ self.data = data
51
+ self.plot_seasons = self.data["Temporada"][:] - self.data["Temporada"].iloc[0] + 1
52
+ self.ticks_text = normalize_seasons(self.data)
53
+ self.ticks_positions = ticks_positions_array(self.ticks_text)
54
+ self.plot_domain = np.linspace(self.ticks_positions.min(), self.ticks_positions.max(), 100)
50
55
 
51
56
  def plot_smooth(self, Population_Trend_Model):
52
57
  self.ax.fill_between(
53
- Population_Trend_Model.time_to_model,
58
+ self.plot_domain,
54
59
  Population_Trend_Model.model_min,
55
60
  Population_Trend_Model.model_max,
56
61
  alpha=0.2,
@@ -60,17 +65,17 @@ class Plotter_Population_Trend_Model:
60
65
 
61
66
  def plot_model(self, Population_Trend_Model):
62
67
  plt.plot(
63
- Population_Trend_Model.time_to_model,
68
+ self.plot_domain,
64
69
  Population_Trend_Model.model_med,
65
70
  label="Population growth model",
66
71
  color="b",
67
72
  )
68
73
  return self.fig
69
74
 
70
- def plot_data(self, Population_Trend_Model, fit_data):
75
+ def plot_data(self, variable_to_bootstrap):
71
76
  plt.plot(
72
- Population_Trend_Model.plot_seasons,
73
- fit_data,
77
+ self.plot_seasons,
78
+ self.data[variable_to_bootstrap],
74
79
  "-Dk",
75
80
  label="Active Nests",
76
81
  )
@@ -92,20 +97,20 @@ class Plotter_Population_Trend_Model:
92
97
  calculate_upper_limit(fit_data),
93
98
  )
94
99
 
95
- def set_x_lim(self, Population_Trend_Model):
100
+ def set_x_lim(self):
96
101
  plt.xlim(
97
- Population_Trend_Model.ticks_positions.min() - 0.2,
98
- Population_Trend_Model.ticks_positions.max(),
102
+ self.ticks_positions.min() - 0.2,
103
+ self.ticks_positions.max(),
99
104
  )
100
105
 
101
106
  def set_labels(self):
102
107
  plt.ylabel("Number of breeding pairs", size=20)
103
108
  plt.xlabel("Seasons", size=20)
104
109
 
105
- def set_ticks(self, Population_Trend_Model):
110
+ def set_ticks(self):
106
111
  plt.xticks(
107
- Population_Trend_Model.ticks_positions,
108
- Population_Trend_Model.ticks_text,
112
+ self.ticks_positions,
113
+ self.ticks_text,
109
114
  rotation=90,
110
115
  size=20,
111
116
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: population_trend
3
- Version: 2.0.2
3
+ Version: 3.1.0
4
4
  Summary: A template Python module
5
5
  Home-page: https://github.com/IslasGECI/population_trend
6
6
  Author: Ciencia de Datos • GECI
@@ -8,7 +8,7 @@ Author-email: ciencia.datos@islas.org.mx
8
8
  Requires-Python: >=3.9
9
9
  Description-Content-Type: text/markdown
10
10
  Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
11
- Requires-Dist: bootstrapping-tools==1.1.1
11
+ Requires-Dist: bootstrapping-tools==2.0.0
12
12
  Requires-Dist: geci-plots
13
13
  Requires-Dist: typer
14
14
 
@@ -0,0 +1,9 @@
1
+ population_trend/__init__.py,sha256=mr5F6CLyrEM5ITNVsP0YgFZff-b2E7GRbunCPuELGiA,251
2
+ population_trend/calculate_growth_rates.py,sha256=SQobh1f2xKFKu7MO7To7avxU2Cym1ebu2tKfpbLTpbo,6901
3
+ population_trend/cli.py,sha256=CkzXmfjekIV4RplUyJo1Af-GI22zovB4u5alt8BNYIo,1894
4
+ population_trend/filter_data.py,sha256=D0Y1vztcbbo98af9q7wRhlHfH__bNFI8tnVOdJY6hu0,403
5
+ population_trend/population_growth_model.py,sha256=fSUKg8UH-pdN1tNYskGcMmmiqqAy9Ciz0E4X-IeP9WM,4361
6
+ population_trend-3.1.0.dist-info/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
7
+ population_trend-3.1.0.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
8
+ population_trend-3.1.0.dist-info/METADATA,sha256=e5YM8iZ6yCz3b9uRIrFOa2AeXa6uIPQ4bW77D0NAPno,1504
9
+ population_trend-3.1.0.dist-info/RECORD,,
@@ -1,8 +0,0 @@
1
- population_trend/__init__.py,sha256=FmowP9ov97-TOtFOosVO-nkT9euMfvVycHT-cQglXAk,163
2
- population_trend/cli.py,sha256=8QdnQqvozFZDXHumyaib1KC0GhAzO1n71Zwl70v9MFw,1982
3
- population_trend/filter_data.py,sha256=D0Y1vztcbbo98af9q7wRhlHfH__bNFI8tnVOdJY6hu0,403
4
- population_trend/population_growth_model.py,sha256=fnCnEKiZu4umt8eB4wSr0LVdqHN6hpmQrvF8vTBKtEE,4316
5
- population_trend-2.0.2.dist-info/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
6
- population_trend-2.0.2.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
7
- population_trend-2.0.2.dist-info/METADATA,sha256=SwfTDlPuyGmVHx5Ehjt-fZUtlpHC16BHymhVYsll9oY,1504
8
- population_trend-2.0.2.dist-info/RECORD,,