geocif 0.4.332__tar.gz → 0.4.334__tar.gz

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.
Files changed (88) hide show
  1. {geocif-0.4.332/geocif.egg-info → geocif-0.4.334}/PKG-INFO +1 -1
  2. {geocif-0.4.332 → geocif-0.4.334}/geocif/__init__.py +1 -1
  3. {geocif-0.4.332 → geocif-0.4.334}/geocif/analysis.py +89 -0
  4. {geocif-0.4.332 → geocif-0.4.334/geocif.egg-info}/PKG-INFO +1 -1
  5. {geocif-0.4.332 → geocif-0.4.334}/pyproject.toml +1 -1
  6. {geocif-0.4.332 → geocif-0.4.334}/LICENSE +0 -0
  7. {geocif-0.4.332 → geocif-0.4.334}/MANIFEST.in +0 -0
  8. {geocif-0.4.332 → geocif-0.4.334}/README.md +0 -0
  9. {geocif-0.4.332 → geocif-0.4.334}/geocif/agmet/__init__.py +0 -0
  10. {geocif-0.4.332 → geocif-0.4.334}/geocif/agmet/geoagmet.py +0 -0
  11. {geocif-0.4.332 → geocif-0.4.334}/geocif/agmet/plot.py +0 -0
  12. {geocif-0.4.332 → geocif-0.4.334}/geocif/agmet/utils.py +0 -0
  13. {geocif-0.4.332 → geocif-0.4.334}/geocif/backup/__init__.py +0 -0
  14. {geocif-0.4.332 → geocif-0.4.334}/geocif/backup/constants.py +0 -0
  15. {geocif-0.4.332 → geocif-0.4.334}/geocif/backup/features.py +0 -0
  16. {geocif-0.4.332 → geocif-0.4.334}/geocif/backup/geo.py +0 -0
  17. {geocif-0.4.332 → geocif-0.4.334}/geocif/backup/geocif.py +0 -0
  18. {geocif-0.4.332 → geocif-0.4.334}/geocif/backup/metadata.py +0 -0
  19. {geocif-0.4.332 → geocif-0.4.334}/geocif/backup/models.py +0 -0
  20. {geocif-0.4.332 → geocif-0.4.334}/geocif/cid/__init__.py +0 -0
  21. {geocif-0.4.332 → geocif-0.4.334}/geocif/cid/definitions.py +0 -0
  22. {geocif-0.4.332 → geocif-0.4.334}/geocif/cid/indices.py +0 -0
  23. {geocif-0.4.332 → geocif-0.4.334}/geocif/dashboard/__init__.py +0 -0
  24. {geocif-0.4.332 → geocif-0.4.334}/geocif/dashboard/__main__.py +0 -0
  25. {geocif-0.4.332 → geocif-0.4.334}/geocif/dashboard/app.py +0 -0
  26. {geocif-0.4.332 → geocif-0.4.334}/geocif/dashboard/auth.py +0 -0
  27. {geocif-0.4.332 → geocif-0.4.334}/geocif/dashboard/data.py +0 -0
  28. {geocif-0.4.332 → geocif-0.4.334}/geocif/dashboard/tabs/__init__.py +0 -0
  29. {geocif-0.4.332 → geocif-0.4.334}/geocif/dashboard/tabs/agmet_graphics.py +0 -0
  30. {geocif-0.4.332 → geocif-0.4.334}/geocif/dashboard/tabs/historical_accuracy.py +0 -0
  31. {geocif-0.4.332 → geocif-0.4.334}/geocif/dashboard/tabs/shap_explanation.py +0 -0
  32. {geocif-0.4.332 → geocif-0.4.334}/geocif/dashboard/tabs/yield_predictions.py +0 -0
  33. {geocif-0.4.332 → geocif-0.4.334}/geocif/data.py +0 -0
  34. {geocif-0.4.332 → geocif-0.4.334}/geocif/experiments.py +0 -0
  35. {geocif-0.4.332 → geocif-0.4.334}/geocif/fdw_export.py +0 -0
  36. {geocif-0.4.332 → geocif-0.4.334}/geocif/geocif.py +0 -0
  37. {geocif-0.4.332 → geocif-0.4.334}/geocif/geocif_runner.py +0 -0
  38. {geocif-0.4.332 → geocif-0.4.334}/geocif/hf_sync.py +0 -0
  39. {geocif-0.4.332 → geocif-0.4.334}/geocif/indices_runner.py +0 -0
  40. {geocif-0.4.332 → geocif-0.4.334}/geocif/logger.py +0 -0
  41. {geocif-0.4.332 → geocif-0.4.334}/geocif/ml/__init__.py +0 -0
  42. {geocif-0.4.332 → geocif-0.4.334}/geocif/ml/correlations.py +0 -0
  43. {geocif-0.4.332 → geocif-0.4.334}/geocif/ml/embedding.py +0 -0
  44. {geocif-0.4.332 → geocif-0.4.334}/geocif/ml/feature_engineering.py +0 -0
  45. {geocif-0.4.332 → geocif-0.4.334}/geocif/ml/feature_selection.py +0 -0
  46. {geocif-0.4.332 → geocif-0.4.334}/geocif/ml/gomp.py +0 -0
  47. {geocif-0.4.332 → geocif-0.4.334}/geocif/ml/outliers.py +0 -0
  48. {geocif-0.4.332 → geocif-0.4.334}/geocif/ml/outlook.py +0 -0
  49. {geocif-0.4.332 → geocif-0.4.334}/geocif/ml/output.py +0 -0
  50. {geocif-0.4.332 → geocif-0.4.334}/geocif/ml/spatial_autocorrelation.py +0 -0
  51. {geocif-0.4.332 → geocif-0.4.334}/geocif/ml/spatial_neighbors.py +0 -0
  52. {geocif-0.4.332 → geocif-0.4.334}/geocif/ml/stages.py +0 -0
  53. {geocif-0.4.332 → geocif-0.4.334}/geocif/ml/stats.py +0 -0
  54. {geocif-0.4.332 → geocif-0.4.334}/geocif/ml/trainers.py +0 -0
  55. {geocif-0.4.332 → geocif-0.4.334}/geocif/ml/trend.py +0 -0
  56. {geocif-0.4.332 → geocif-0.4.334}/geocif/ml/xai.py +0 -0
  57. {geocif-0.4.332 → geocif-0.4.334}/geocif/playground/__init__.py +0 -0
  58. {geocif-0.4.332 → geocif-0.4.334}/geocif/playground/aa.py +0 -0
  59. {geocif-0.4.332 → geocif-0.4.334}/geocif/playground/area.py +0 -0
  60. {geocif-0.4.332 → geocif-0.4.334}/geocif/playground/automl.py +0 -0
  61. {geocif-0.4.332 → geocif-0.4.334}/geocif/playground/download_esi.py +0 -0
  62. {geocif-0.4.332 → geocif-0.4.334}/geocif/playground/eval.py +0 -0
  63. {geocif-0.4.332 → geocif-0.4.334}/geocif/playground/gee_access.py +0 -0
  64. {geocif-0.4.332 → geocif-0.4.334}/geocif/playground/misc.py +0 -0
  65. {geocif-0.4.332 → geocif-0.4.334}/geocif/playground/reg.py +0 -0
  66. {geocif-0.4.332 → geocif-0.4.334}/geocif/playground/sustain.py +0 -0
  67. {geocif-0.4.332 → geocif-0.4.334}/geocif/playground/test_catboost.py +0 -0
  68. {geocif-0.4.332 → geocif-0.4.334}/geocif/playground/tmp.py +0 -0
  69. {geocif-0.4.332 → geocif-0.4.334}/geocif/playground/wolayita.py +0 -0
  70. {geocif-0.4.332 → geocif-0.4.334}/geocif/playground/wolayita_maize_mask.py +0 -0
  71. {geocif-0.4.332 → geocif-0.4.334}/geocif/playground/wolayita_v2.py +0 -0
  72. {geocif-0.4.332 → geocif-0.4.334}/geocif/playground/wolayita_v3.py +0 -0
  73. {geocif-0.4.332 → geocif-0.4.334}/geocif/risk/__init__.py +0 -0
  74. {geocif-0.4.332 → geocif-0.4.334}/geocif/risk/impact_assessment.py +0 -0
  75. {geocif-0.4.332 → geocif-0.4.334}/geocif/utils.py +0 -0
  76. {geocif-0.4.332 → geocif-0.4.334}/geocif/viz/__init__.py +0 -0
  77. {geocif-0.4.332 → geocif-0.4.334}/geocif/viz/plot.py +0 -0
  78. {geocif-0.4.332 → geocif-0.4.334}/geocif/yield_outlook.py +0 -0
  79. {geocif-0.4.332 → geocif-0.4.334}/geocif.egg-info/SOURCES.txt +0 -0
  80. {geocif-0.4.332 → geocif-0.4.334}/geocif.egg-info/dependency_links.txt +0 -0
  81. {geocif-0.4.332 → geocif-0.4.334}/geocif.egg-info/requires.txt +0 -0
  82. {geocif-0.4.332 → geocif-0.4.334}/geocif.egg-info/top_level.txt +0 -0
  83. {geocif-0.4.332 → geocif-0.4.334}/requirements.txt +0 -0
  84. {geocif-0.4.332 → geocif-0.4.334}/setup.cfg +0 -0
  85. {geocif-0.4.332 → geocif-0.4.334}/setup.py +0 -0
  86. {geocif-0.4.332 → geocif-0.4.334}/tests/test_agmet.py +0 -0
  87. {geocif-0.4.332 → geocif-0.4.334}/tests/test_geocif.py +0 -0
  88. {geocif-0.4.332 → geocif-0.4.334}/tests/test_spatial_neighbors.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: geocif
3
- Version: 0.4.332
3
+ Version: 0.4.334
4
4
  Summary: Models to visualize and forecast crop conditions and yields
5
5
  Author-email: Ritvik Sahajpal <ritvik@umd.edu>
6
6
  License: MIT
@@ -2,6 +2,6 @@
2
2
 
3
3
  __author__ = """Ritvik Sahajpal"""
4
4
  __email__ = "ritvik@umd.edu"
5
- __version__ = "0.4.332"
5
+ __version__ = "0.4.333"
6
6
 
7
7
  __all__ = ["ml", "cid", "viz", "agmet", "fdw_export", "dashboard"]
@@ -189,6 +189,7 @@ class Geoanalysis:
189
189
  self.logger.info(f"Analyze {self.country} {self.crop}")
190
190
 
191
191
  self._plot_yield_with_ci(self.df_analysis)
192
+ self._plot_yield_with_ci_historical(self.df_analysis)
192
193
 
193
194
  df = self._clean_data()
194
195
  if df.empty:
@@ -700,6 +701,8 @@ class Geoanalysis:
700
701
  )
701
702
 
702
703
  median_col = "Median Yield (tn per ha) (2018-2022)"
704
+ if f"{median_col}_y" in df_ci.columns:
705
+ median_col = f"{median_col}_y"
703
706
  has_median = median_col in df_ci.columns and df_ci[median_col].notna().any()
704
707
 
705
708
  fig, ax = plt.subplots(figsize=(8, max(4, len(df_ci) * 0.4)))
@@ -736,6 +739,92 @@ class Geoanalysis:
736
739
  fig.savefig(self.dir_country_plots / fname, dpi=250)
737
740
  plt.close(fig)
738
741
 
742
+ def _plot_yield_with_ci_historical(self, df):
743
+ """Forest plot of predicted yield with CI and individual historical year yields."""
744
+ if "lower CI" not in df.columns or "upper CI" not in df.columns:
745
+ return
746
+ df_ci = df.dropna(subset=["lower CI", "upper CI"])
747
+ if df_ci.empty:
748
+ return
749
+
750
+ # Use latest stage per region
751
+ df_ci = (
752
+ df_ci.sort_values("Stage Name")
753
+ .groupby("Region")
754
+ .last()
755
+ .reset_index()
756
+ .sort_values(self.predicted)
757
+ )
758
+
759
+ # Load historical yields from statistics CSV
760
+ try:
761
+ if self.country == "pooled":
762
+ frames = []
763
+ for c in self.countries:
764
+ f = utils.statistics_file_path(self.dir_out, self.method, c, self.crop)
765
+ if f.exists():
766
+ frames.append(pd.read_csv(f))
767
+ df_hist = pd.concat(frames, ignore_index=True)
768
+ else:
769
+ f = utils.statistics_file_path(self.dir_out, self.method, self.country, self.crop)
770
+ df_hist = pd.read_csv(f)
771
+ df_hist = df_hist[["Region", "Harvest Year", "Yield (tn per ha)"]].dropna()
772
+ except Exception:
773
+ return
774
+
775
+ # Last 5 years of available data
776
+ years = sorted(df_hist["Harvest Year"].unique())[-5:]
777
+ df_hist = df_hist[df_hist["Harvest Year"].isin(years)]
778
+
779
+ # Pivot: one column per year
780
+ df_pivot = df_hist.pivot_table(
781
+ index="Region", columns="Harvest Year", values="Yield (tn per ha)"
782
+ )
783
+
784
+ # Only keep regions that are in df_ci
785
+ regions = df_ci["Region"].values
786
+ df_pivot = df_pivot.reindex(regions)
787
+
788
+ fig, ax = plt.subplots(figsize=(8, max(4, len(df_ci) * 0.4)))
789
+ y_pos = np.arange(len(df_ci))
790
+
791
+ # CI error bars
792
+ xerr_low = df_ci[self.predicted].values - df_ci["lower CI"].values
793
+ xerr_high = df_ci["upper CI"].values - df_ci[self.predicted].values
794
+ ax.errorbar(
795
+ df_ci[self.predicted].values, y_pos,
796
+ xerr=[xerr_low, xerr_high],
797
+ fmt="o", color="steelblue", capsize=3, zorder=10,
798
+ label="Predicted \u00b1 CI",
799
+ )
800
+
801
+ # Historical year diamonds — each year gets a distinct color
802
+ cmap = plt.cm.RdYlGn
803
+ colors = [cmap(i / max(len(years) - 1, 1)) for i in range(len(years))]
804
+ for idx, yr in enumerate(years):
805
+ if yr in df_pivot.columns:
806
+ vals = df_pivot[yr].values
807
+ ax.scatter(
808
+ vals, y_pos,
809
+ marker="D", color=colors[idx], edgecolors="k",
810
+ linewidths=0.3, s=25, zorder=5,
811
+ label=str(int(yr)),
812
+ )
813
+
814
+ ax.set_yticks(y_pos)
815
+ ax.set_yticklabels(regions, fontsize=8)
816
+ ax.set_xlabel("Yield (tn per ha)")
817
+ ax.set_title(
818
+ f"Predicted Yield with CI & Historical Yields \u2014 {self.country} {self.crop}",
819
+ fontsize=10, fontweight="bold",
820
+ )
821
+ ax.legend(fontsize=7, loc="lower right")
822
+ plt.tight_layout()
823
+
824
+ fname = f"yield_ci_historical_{self.country}_{self.crop}.png"
825
+ fig.savefig(self.dir_country_plots / fname, dpi=250)
826
+ plt.close(fig)
827
+
739
828
  def _plot_national_yield(self, df_national_yield):
740
829
  from sklearn.metrics import (
741
830
  mean_squared_error,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: geocif
3
- Version: 0.4.332
3
+ Version: 0.4.334
4
4
  Summary: Models to visualize and forecast crop conditions and yields
5
5
  Author-email: Ritvik Sahajpal <ritvik@umd.edu>
6
6
  License: MIT
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "geocif"
3
- version = "0.4.332"
3
+ version = "0.4.334"
4
4
 
5
5
  description = "Models to visualize and forecast crop conditions and yields"
6
6
  readme = "README.md"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes