pysits 2.0.0.dev2__tar.gz → 2.0.0.dev4__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 (215) hide show
  1. pysits-2.0.0.dev4/.github/actions/setup-pysits/action.yml +43 -0
  2. pysits-2.0.0.dev4/.github/workflows/ruff.yaml +32 -0
  3. pysits-2.0.0.dev4/.github/workflows/tests.yaml +80 -0
  4. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/PKG-INFO +13 -3
  5. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pyproject.toml +13 -2
  6. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/__init__.py +4 -0
  7. pysits-2.0.0.dev4/pysits/backend/arrow.py +106 -0
  8. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/backend/functions.py +3 -0
  9. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/backend/pkgs.py +6 -0
  10. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/conversions/decorators.py +43 -0
  11. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/conversions/tibble.py +36 -0
  12. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/plot.md +35 -9
  13. pysits-2.0.0.dev4/pysits/models/visual.py +567 -0
  14. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/sits/colors.py +4 -2
  15. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/sits/visualization.py +43 -43
  16. pysits-2.0.0.dev4/pysits/templates/plot.html +24 -0
  17. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/visualization/__init__.py +10 -2
  18. pysits-2.0.0.dev4/pysits/visualization/base.py +189 -0
  19. pysits-2.0.0.dev4/pysits/visualization/device.py +86 -0
  20. pysits-2.0.0.dev4/pysits/visualization/host.py +64 -0
  21. pysits-2.0.0.dev4/pysits/visualization/options.py +292 -0
  22. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/tests/conftest.py +26 -15
  23. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/tests/test_classification.py +2 -2
  24. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/tests/test_embedding.py +3 -3
  25. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/tests/test_som.py +8 -9
  26. pysits-2.0.0.dev4/tests/test_visual_models.py +528 -0
  27. pysits-2.0.0.dev4/tests/test_visualization.py +426 -0
  28. pysits-2.0.0.dev4/uv.lock +3641 -0
  29. pysits-2.0.0.dev2/.claude/settings.local.json +0 -8
  30. pysits-2.0.0.dev2/.github/workflows/ruff.yaml +0 -42
  31. pysits-2.0.0.dev2/pysits/visualization/base.py +0 -177
  32. pysits-2.0.0.dev2/pysits/visualization/image.py +0 -48
  33. pysits-2.0.0.dev2/pysits/visualization/tmap.py +0 -85
  34. pysits-2.0.0.dev2/tests/test_visualization.py +0 -181
  35. pysits-2.0.0.dev2/uv.lock +0 -2527
  36. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/.gitattributes +0 -0
  37. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/.gitignore +0 -0
  38. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/.pre-commit-config.yaml +0 -0
  39. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/LICENSE +0 -0
  40. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/README.md +0 -0
  41. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/conda/meta.yaml +0 -0
  42. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/backend/__init__.py +0 -0
  43. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/backend/loaders.py +0 -0
  44. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/conversions/__init__.py +0 -0
  45. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/conversions/clojure.py +0 -0
  46. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/conversions/common.py +0 -0
  47. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/conversions/dsl/__init__.py +0 -0
  48. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/conversions/dsl/base.py +0 -0
  49. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/conversions/dsl/mask.py +0 -0
  50. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/conversions/dsl/tuning.py +0 -0
  51. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/conversions/stac.py +0 -0
  52. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/conversions/vector.py +0 -0
  53. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/conversions/xarray.py +0 -0
  54. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/__init__.py +0 -0
  55. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/impute_linear.md +0 -0
  56. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/impute_mean.md +0 -0
  57. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/impute_mean_window.md +0 -0
  58. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/impute_median.md +0 -0
  59. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_accuracy.md +0 -0
  60. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_accuracy_summary.md +0 -0
  61. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_add_base_cube.md +0 -0
  62. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_apply.md +0 -0
  63. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_as_geopandas.md +0 -0
  64. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_bands.md +0 -0
  65. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_barlow_twins.md +0 -0
  66. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_bbox.md +0 -0
  67. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_classify.md +0 -0
  68. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_clean.md +0 -0
  69. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_cluster_clean.md +0 -0
  70. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_cluster_dendro.md +0 -0
  71. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_cluster_frequency.md +0 -0
  72. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_colors.md +0 -0
  73. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_colors_qgis.md +0 -0
  74. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_colors_reset.md +0 -0
  75. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_colors_set.md +0 -0
  76. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_colors_show.md +0 -0
  77. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_combine_predictions.md +0 -0
  78. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_confidence_sampling.md +0 -0
  79. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_config.md +0 -0
  80. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_config_show.md +0 -0
  81. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_config_user_file.md +0 -0
  82. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_contrastive_learning.md +0 -0
  83. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_cube.md +0 -0
  84. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_cube_copy.md +0 -0
  85. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_encode.md +0 -0
  86. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_formula_linear.md +0 -0
  87. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_formula_logref.md +0 -0
  88. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_geo_dist.md +0 -0
  89. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_get_class.md +0 -0
  90. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_get_data.md +0 -0
  91. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_get_probs.md +0 -0
  92. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_kfold_validate.md +0 -0
  93. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_label_classification.md +0 -0
  94. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_labels.md +0 -0
  95. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_labels_summary.md +0 -0
  96. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_lightgbm.md +0 -0
  97. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_lighttae.md +0 -0
  98. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_list_collections.md +0 -0
  99. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_lstm_fcn.md +0 -0
  100. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_merge.md +0 -0
  101. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_mixture_model.md +0 -0
  102. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_mlp.md +0 -0
  103. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_model_export.md +0 -0
  104. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_mosaic.md +0 -0
  105. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_parallel.md +0 -0
  106. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_patterns.md +0 -0
  107. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_pre_train.md +0 -0
  108. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_pred_features.md +0 -0
  109. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_pred_normalize.md +0 -0
  110. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_pred_references.md +0 -0
  111. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_pred_sample.md +0 -0
  112. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_predictors.md +0 -0
  113. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_random_sampling.md +0 -0
  114. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_reclassify.md +0 -0
  115. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_reduce.md +0 -0
  116. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_reduce_imbalance.md +0 -0
  117. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_regularize.md +0 -0
  118. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_resnet.md +0 -0
  119. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_rfor.md +0 -0
  120. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_roi_to_tiles.md +0 -0
  121. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_sample.md +0 -0
  122. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_sampling_design.md +0 -0
  123. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_sankey.md +0 -0
  124. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_segment.md +0 -0
  125. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_select.md +0 -0
  126. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_show_prediction.md +0 -0
  127. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_slic.md +0 -0
  128. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_smooth.md +0 -0
  129. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_snic.md +0 -0
  130. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_som_clean_samples.md +0 -0
  131. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_som_evaluate_cluster.md +0 -0
  132. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_som_map.md +0 -0
  133. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_som_remove_samples.md +0 -0
  134. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_ssl_lejepa.md +0 -0
  135. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_ssl_mae.md +0 -0
  136. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_ssl_vicreg.md +0 -0
  137. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_stats.md +0 -0
  138. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_stratified_sampling.md +0 -0
  139. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_svm.md +0 -0
  140. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_tae.md +0 -0
  141. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_tempcnn.md +0 -0
  142. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_texture.md +0 -0
  143. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_tiles_to_roi.md +0 -0
  144. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_timeline.md +0 -0
  145. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_timeseries_to_csv.md +0 -0
  146. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_to_csv.md +0 -0
  147. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_to_xlsx.md +0 -0
  148. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_train.md +0 -0
  149. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_tuning.md +0 -0
  150. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_tuning_hparams.md +0 -0
  151. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_uncertainty.md +0 -0
  152. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_uncertainty_sampling.md +0 -0
  153. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_validate.md +0 -0
  154. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_variance.md +0 -0
  155. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_view.md +0 -0
  156. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/sits_xgboost.md +0 -0
  157. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/content/summary.md +0 -0
  158. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/docs/decorators.py +0 -0
  159. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/extras/__init__.py +0 -0
  160. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/extras/earthdatalogin.py +0 -0
  161. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/extras/torch.py +0 -0
  162. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/jinja.py +0 -0
  163. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/models/__init__.py +0 -0
  164. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/models/base.py +0 -0
  165. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/models/data/__init__.py +0 -0
  166. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/models/data/accuracy.py +0 -0
  167. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/models/data/base.py +0 -0
  168. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/models/data/cube.py +0 -0
  169. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/models/data/frame.py +0 -0
  170. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/models/data/frame_accessor.py +0 -0
  171. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/models/data/matrix.py +0 -0
  172. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/models/data/table.py +0 -0
  173. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/models/data/ts.py +0 -0
  174. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/models/data/tuning.py +0 -0
  175. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/models/data/vector.py +0 -0
  176. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/models/frame.py +0 -0
  177. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/models/ml.py +0 -0
  178. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/models/resolver.py +0 -0
  179. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/settings.py +0 -0
  180. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/sits/__init__.py +0 -0
  181. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/sits/config.py +0 -0
  182. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/sits/context.py +0 -0
  183. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/sits/cube.py +0 -0
  184. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/sits/data.py +0 -0
  185. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/sits/exporters/__init__.py +0 -0
  186. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/sits/exporters/files.py +0 -0
  187. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/sits/exporters/sf.py +0 -0
  188. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/sits/exporters/xarray.py +0 -0
  189. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/sits/impute.py +0 -0
  190. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/sits/ml.py +0 -0
  191. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/sits/segment.py +0 -0
  192. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/sits/tiles.py +0 -0
  193. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/sits/ts.py +0 -0
  194. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/sits/tuning.py +0 -0
  195. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/sits/utils.py +0 -0
  196. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/templates/cube.html +0 -0
  197. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/templates/tuning.html +0 -0
  198. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/pysits/visualization/leaflet.py +0 -0
  199. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/tests/test_config.py +0 -0
  200. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/tests/test_conversions.py +0 -0
  201. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/tests/test_cube.py +0 -0
  202. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/tests/test_data.py +0 -0
  203. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/tests/test_dsl.py +0 -0
  204. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/tests/test_exporters.py +0 -0
  205. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/tests/test_exporters_geopandas.py +0 -0
  206. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/tests/test_exporters_xarray.py +0 -0
  207. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/tests/test_extras.py +0 -0
  208. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/tests/test_indexing.py +0 -0
  209. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/tests/test_ml_models.py +0 -0
  210. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/tests/test_resolver.py +0 -0
  211. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/tests/test_rl_models.py +0 -0
  212. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/tests/test_tiles.py +0 -0
  213. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/tests/test_tuning.py +0 -0
  214. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/tests/test_utils.py +0 -0
  215. {pysits-2.0.0.dev2 → pysits-2.0.0.dev4}/tests/test_validation.py +0 -0
@@ -0,0 +1,43 @@
1
+ name: Set up pysits
2
+ description: R with the sits stack, and uv-managed Python
3
+
4
+ inputs:
5
+ python-version:
6
+ description: Python version to run pysits on
7
+ required: true
8
+
9
+ runs:
10
+ using: composite
11
+
12
+ steps:
13
+ - uses: r-lib/actions/setup-r@v2
14
+ with:
15
+ Ncpus: '4'
16
+
17
+ # R is installed under `/opt/R`, which the dynamic loader does not search.
18
+ # `rpy2` links against `libR.so` at import, so without this it falls back
19
+ # to ABI mode and then fails to load R's own base packages
20
+ - name: Put libR on the loader path
21
+ shell: bash
22
+ run: |
23
+ echo "LD_LIBRARY_PATH=$(R RHOME)/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" >> "$GITHUB_ENV"
24
+
25
+ - uses: r-lib/actions/setup-r-dependencies@v2
26
+ with:
27
+ packages: |
28
+ github::e-sensing/sits@dev
29
+ any::arrow
30
+ any::earthdatalogin
31
+
32
+ # The `torch` R package ships without libtorch, and pysits disables the
33
+ # implicit download (`TORCH_INSTALL=0`), so without this operation
34
+ # the deep learning models would fail only once a test train one
35
+ - name: Install libtorch
36
+ shell: bash
37
+ run: Rscript -e 'torch::install_torch()'
38
+
39
+ # After R: `rpy2` has no Linux wheel and is compiled against it
40
+ - uses: astral-sh/setup-uv@v9.0.0
41
+ with:
42
+ python-version: ${{ inputs.python-version }}
43
+ enable-cache: true
@@ -0,0 +1,32 @@
1
+ name: Code check
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ workflow_dispatch:
10
+ inputs:
11
+ reason:
12
+ required: false
13
+ description: 'Reason'
14
+ default: 'Manual trigger'
15
+
16
+ concurrency:
17
+ group: ${{ github.workflow }}-${{ github.ref }}
18
+ cancel-in-progress: ${{ github.event_name == 'pull_request' }}
19
+
20
+ permissions:
21
+ contents: read
22
+
23
+ jobs:
24
+ lint:
25
+ name: Run ruff
26
+ runs-on: ubuntu-latest
27
+
28
+ steps:
29
+ - uses: actions/checkout@v7
30
+ - uses: astral-sh/ruff-action@v4.1.0
31
+ with:
32
+ version-file: uv.lock
@@ -0,0 +1,80 @@
1
+ name: Tests
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ # Run every Saturday at 3:00 AM
10
+ schedule:
11
+ # * is a special character in YAML so you have to quote this string
12
+ - cron: '0 3 * * 6'
13
+
14
+ workflow_dispatch:
15
+ inputs:
16
+ reason:
17
+ required: false
18
+ description: 'Reason'
19
+ default: 'Manual trigger'
20
+
21
+ concurrency:
22
+ group: ${{ github.workflow }}-${{ github.ref }}
23
+ cancel-in-progress: ${{ github.event_name == 'pull_request' }}
24
+
25
+ permissions:
26
+ contents: read
27
+
28
+ env:
29
+ # pak resolves `sits` from GitHub; without a token it shares the anonymous
30
+ # rate limit with every other runner
31
+ GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
32
+
33
+ jobs:
34
+ test:
35
+ name: Python ${{ matrix.python-version }}
36
+ runs-on: ubuntu-latest
37
+ timeout-minutes: 120
38
+
39
+ strategy:
40
+ # Report every version, so a single break does not hide the others
41
+ fail-fast: false
42
+ matrix:
43
+ # The suite trains various models on CPU. To reduce execution time,
44
+ # a change is only checked against floor and ceiling versions.
45
+ # The weekly test covers all other versions
46
+ python-version: ${{ fromJSON((github.event_name == 'push' || github.event_name == 'pull_request') && '["3.10", "3.14"]' || '["3.10", "3.11", "3.12", "3.13", "3.14"]') }}
47
+
48
+ steps:
49
+ - uses: actions/checkout@v7
50
+
51
+ - uses: ./.github/actions/setup-pysits
52
+ with:
53
+ python-version: ${{ matrix.python-version }}
54
+
55
+ - name: Install pysits
56
+ run: uv sync --locked --extra dev
57
+
58
+ - name: Run tests
59
+ run: uv run pytest
60
+
61
+ latest-dependencies:
62
+ name: Latest dependencies
63
+ # `uv.lock` pins what `test` runs against, so a release that breaks pysits
64
+ # stays invisible there until someone relocks. This resolves from scratch.
65
+ if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
66
+ runs-on: ubuntu-latest
67
+ timeout-minutes: 120
68
+
69
+ steps:
70
+ - uses: actions/checkout@v7
71
+
72
+ - uses: ./.github/actions/setup-pysits
73
+ with:
74
+ python-version: '3.14'
75
+
76
+ - name: Install pysits, ignoring the lockfile
77
+ run: uv sync --upgrade --extra dev
78
+
79
+ - name: Run tests
80
+ run: uv run pytest
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: pysits
3
- Version: 2.0.0.dev2
3
+ Version: 2.0.0.dev4
4
4
  Summary: Python wrapper for the sits R package
5
5
  Project-URL: Homepage, https://github.com/e-sensing/pysits
6
6
  Project-URL: Issue Tracker, https://github.com/e-sensing/pysits/issues
@@ -20,17 +20,27 @@ Requires-Dist: geopandas>=1.1.0
20
20
  Requires-Dist: jinja2>=3.1.6
21
21
  Requires-Dist: matplotlib>=3.10.1
22
22
  Requires-Dist: pandas>=2.2.3
23
+ Requires-Dist: pandas>=2.3.3; python_version >= '3.14'
23
24
  Requires-Dist: pillow>=11.1.0
24
25
  Requires-Dist: pyarrow>=20.0.0
25
- Requires-Dist: rpy2<4.0.0,>=3.5.17
26
+ Requires-Dist: rpy2<4.0.0,>=3.6.0
26
27
  Requires-Dist: shapely>=2.1.1
27
28
  Provides-Extra: dev
29
+ Requires-Dist: affine>=2.4.0; extra == 'dev'
28
30
  Requires-Dist: cloudpickle>=3.1.1; extra == 'dev'
31
+ Requires-Dist: dask>=2025.3.0; extra == 'dev'
32
+ Requires-Dist: ipykernel>=6.29.0; extra == 'dev'
33
+ Requires-Dist: odc-stac>=0.5.3; extra == 'dev'
34
+ Requires-Dist: planetary-computer>=1.0.0; extra == 'dev'
29
35
  Requires-Dist: pre-commit>=3.6.0; extra == 'dev'
36
+ Requires-Dist: pystac>=1.15.0; extra == 'dev'
30
37
  Requires-Dist: pytest-cov>=6.1.1; extra == 'dev'
31
38
  Requires-Dist: pytest-randomly>=3.16.0; extra == 'dev'
32
39
  Requires-Dist: pytest>=7.4.4; extra == 'dev'
40
+ Requires-Dist: rasterio>=1.3.0; extra == 'dev'
41
+ Requires-Dist: rioxarray>=0.18.2; extra == 'dev'
33
42
  Requires-Dist: ruff>=0.11.12; extra == 'dev'
43
+ Requires-Dist: xarray>=2025.3.0; extra == 'dev'
34
44
  Provides-Extra: xarray
35
45
  Requires-Dist: affine>=2.4.0; extra == 'xarray'
36
46
  Requires-Dist: dask>=2025.3.0; extra == 'xarray'
@@ -17,7 +17,7 @@
17
17
 
18
18
  [project]
19
19
  name = "pysits"
20
- version = "2.0.0.dev2"
20
+ version = "2.0.0.dev4"
21
21
  description = "Python wrapper for the sits R package"
22
22
  readme = "README.md"
23
23
  requires-python = ">=3.10,<4"
@@ -58,8 +58,13 @@ classifiers = [
58
58
  ]
59
59
 
60
60
  dependencies = [
61
- "rpy2>=3.5.17,<4.0.0",
61
+ # 3.6.0 is the first release distributing wheels. Earlier ones are
62
+ # source-only, so pip would compile rpy2 against the local R installation
63
+ "rpy2>=3.6.0,<4.0.0",
62
64
  "pandas>=2.2.3",
65
+ # pandas ships no wheels for Python 3.14 before 2.3.3. Without this floor
66
+ # pip builds pandas from source there, and the result segfaults.
67
+ "pandas>=2.3.3; python_version>='3.14'",
63
68
  "pillow>=11.1.0",
64
69
  "matplotlib>=3.10.1",
65
70
  "geopandas>=1.1.0",
@@ -90,6 +95,12 @@ dev = [
90
95
  "pytest-cov>=6.1.1",
91
96
  "pytest-randomly>=3.16.0",
92
97
  "cloudpickle>=3.1.1",
98
+ # The test suite covers the xarray exporters and reads rasters directly
99
+ "pysits[xarray]",
100
+ "rasterio>=1.3.0",
101
+ # Used to render Quarto documents to check that figures reach a
102
+ # document with the geometry the document asked for
103
+ "ipykernel>=6.29.0",
93
104
  ]
94
105
 
95
106
  [tool.ruff]
@@ -17,6 +17,10 @@
17
17
 
18
18
  """pysits module."""
19
19
 
20
+ # Importing `backend.arrow` first selects the libarrow allocator, which must
21
+ # happen before anything imports `pyarrow` or loads the R `arrow` package.
22
+ # Keep this import above the others. See `pysits.backend.arrow`.
23
+ from .backend import arrow as _arrow # noqa: F401
20
24
  from .conversions.dsl.mask import MaskValue
21
25
  from .conversions.dsl.tuning import hparam
22
26
  from .settings import __version__
@@ -0,0 +1,106 @@
1
+ #
2
+ # Copyright (C) 2025 sits developers.
3
+ #
4
+ # This program is free software; you can redistribute it and/or modify it
5
+ # under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation; either version 2 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program; if not, see <https://www.gnu.org/licenses/>.
16
+ #
17
+
18
+ """Arrow interoperability between R and Python.
19
+
20
+ ``pysits`` moves data between R and Python as Arrow IPC streams. That puts two
21
+ independent builds of the libarrow C++ library in a single process: the one
22
+ bundled in the R ``arrow`` package and the one bundled in ``pyarrow``. Their
23
+ symbols collapse into a single namespace, so a call made through ``pyarrow``
24
+ can be served by R's libarrow.
25
+
26
+ Each build keeps a private ``mimalloc`` heap. When the two are mixed, a buffer
27
+ allocated by one library is read back as zeroed memory by the other, and every
28
+ transfer is silently corrupted instead of failing. Both builds also support the
29
+ system allocator, which is shared, so selecting it keeps them interoperable.
30
+
31
+ The allocator is chosen by libarrow the first time it initializes, so importing
32
+ this module sets ``ARROW_DEFAULT_MEMORY_POOL``. It is imported before anything
33
+ that pulls in ``pyarrow`` or the R ``arrow`` package.
34
+ """
35
+
36
+ import os
37
+
38
+ #
39
+ # Allocator selected to keep R libarrow and pyarrow interoperable
40
+ #
41
+ ARROW_MEMORY_POOL_ENVVAR = "ARROW_DEFAULT_MEMORY_POOL"
42
+ ARROW_MEMORY_POOL = "system"
43
+
44
+ # Set on import: libarrow reads this once, when it initializes. A value already
45
+ # present in the environment is left alone so users can override it.
46
+ os.environ.setdefault(ARROW_MEMORY_POOL_ENVVAR, ARROW_MEMORY_POOL)
47
+
48
+ #
49
+ # Values transferred to R and back to verify the round-trip is lossless. A
50
+ # mismatched pair of libarrow builds reads them back as zeros.
51
+ #
52
+ PROBE_COLUMN = "pysits_arrow_probe"
53
+ PROBE_VALUES = [0.5, 1.5, 2.5]
54
+
55
+
56
+ def check_arrow_memory_pool() -> None:
57
+ """Refuse to load R ``arrow`` package under an unshared allocator.
58
+
59
+ Called before the R ``arrow`` package is loaded. Corruption appears only
60
+ once both libarrow builds are in use, and is silent when it does, so the
61
+ configuration is rejected up front rather than probed for afterwards.
62
+
63
+ Raises:
64
+ RuntimeError: If the selected allocator is not the shared one.
65
+ """
66
+ selected = os.environ.get(ARROW_MEMORY_POOL_ENVVAR)
67
+
68
+ if selected == ARROW_MEMORY_POOL:
69
+ return
70
+
71
+ raise RuntimeError(
72
+ f"{ARROW_MEMORY_POOL_ENVVAR} is set to '{selected}', but pysits "
73
+ f"requires '{ARROW_MEMORY_POOL}'.\n\n"
74
+ "The R `arrow` package and `pyarrow` each bundle their own build of "
75
+ "the libarrow C++ library. Loaded together, they must use the system "
76
+ "allocator to share buffers. With any other allocator, data sent "
77
+ "between R and Python is silently replaced by zeros.\n\n"
78
+ f"Unset {ARROW_MEMORY_POOL_ENVVAR}, or set it before starting Python:\n\n"
79
+ f" export {ARROW_MEMORY_POOL_ENVVAR}={ARROW_MEMORY_POOL}"
80
+ )
81
+
82
+
83
+ def arrow_interop_error(observed: list) -> RuntimeError:
84
+ """Build the error raised when an Arrow round-trip loses data.
85
+
86
+ Args:
87
+ observed (list): Values read back from R for `PROBE_VALUES`.
88
+
89
+ Returns:
90
+ RuntimeError: Error describing the cause and how to resolve it.
91
+ """
92
+ import pyarrow as pa
93
+
94
+ pool = pa.default_memory_pool().backend_name
95
+
96
+ return RuntimeError(
97
+ "Data sent to R is coming back corrupted, so pysits cannot run.\n\n"
98
+ f"Sent {PROBE_VALUES}, received {observed}.\n\n"
99
+ "The R `arrow` package and `pyarrow` each bundle their own build of "
100
+ "the libarrow C++ library. Loaded together, they must use the system "
101
+ f"allocator to share buffers, but pyarrow is using '{pool}'.\n\n"
102
+ "This happens when pyarrow is initialized before pysits with a "
103
+ "different allocator. Either import pysits before pyarrow, or set the "
104
+ "environment variable before starting Python:\n\n"
105
+ f" export {ARROW_MEMORY_POOL_ENVVAR}={ARROW_MEMORY_POOL}"
106
+ )
@@ -25,6 +25,9 @@ from pysits.backend.loaders import (
25
25
  # Base - plot
26
26
  r_fnc_plot = load_function_from_package("base::plot")
27
27
 
28
+ # Base - print
29
+ r_fnc_print = load_function_from_package("base::print")
30
+
28
31
  # Base - set column
29
32
  r_fnc_set_column = load_function_from_package("base::$<-")
30
33
 
@@ -17,6 +17,7 @@
17
17
 
18
18
  """backend packages."""
19
19
 
20
+ from pysits.backend.arrow import check_arrow_memory_pool
20
21
  from pysits.backend.loaders import load_package
21
22
  from pysits.settings import __sitsver__
22
23
 
@@ -33,4 +34,9 @@ r_pkg_leaflet = load_package("leaflet")
33
34
  r_pkg_kohonen = load_package("kohonen")
34
35
  r_pkg_sf = load_package("sf")
35
36
  r_pkg_htmlwidgets = load_package("htmlwidgets")
37
+
38
+ # `arrow` brings a second libarrow build into the process, so the allocator has
39
+ # to be compatible before it is loaded. See `pysits.backend.arrow`.
40
+ check_arrow_memory_pool()
41
+
36
42
  r_pkg_arrow = load_package("arrow")
@@ -94,6 +94,7 @@ def rpy2_fix_type_custom(
94
94
  for i, arg in enumerate(args):
95
95
  if i < len(param_names) and param_names[i] in converters:
96
96
  converted_args.append(converters[param_names[i]](arg))
97
+
97
98
  else:
98
99
  converted_args.append(arg)
99
100
 
@@ -102,6 +103,7 @@ def rpy2_fix_type_custom(
102
103
  for k, v in kwargs.items():
103
104
  if k in converters:
104
105
  converted_kwargs[k] = converters[k](v)
106
+
105
107
  else:
106
108
  converted_kwargs[k] = v
107
109
 
@@ -112,6 +114,47 @@ def rpy2_fix_type_custom(
112
114
  return decorator
113
115
 
114
116
 
117
+ def rpy2_fix_type_except(
118
+ *names: str,
119
+ ) -> Callable[[Callable[P, R]], Callable[P, R]]:
120
+ """Convert arguments to R-compatible objects, keeping some untouched.
121
+
122
+ Behaves like `rpy2_fix_type`, except for the named keyword arguments,
123
+ which reach the wrapped function exactly as they were given. This is
124
+ for arguments that configure pysits itself instead of the R call.
125
+ Converting those to R objects would strip them of the Python interface
126
+ the wrapped function needs.
127
+
128
+ Args:
129
+ *names (str): Names of the keyword arguments to leave untouched.
130
+
131
+ Returns:
132
+ Callable: A decorator that wraps a function to convert its
133
+ arguments, minus the named ones.
134
+
135
+ Example:
136
+ >>> @rpy2_fix_type_except("image_args")
137
+ ... def my_function(data, image_args=None, **kwargs):
138
+ ... # `data` and `kwargs` are R objects, `image_args` is a dict
139
+ ... pass
140
+ """
141
+
142
+ def decorator(func: Callable[P, R]) -> Callable[P, R]:
143
+ @functools.wraps(func)
144
+ def wrapper(*args: Any, **kwargs: Any) -> Any:
145
+ kept = {name: kwargs.pop(name) for name in names if name in kwargs}
146
+
147
+ kwargs = fix_reserved_words_parameters(**kwargs)
148
+ converted_args = [convert_to_r(arg) for arg in args]
149
+ converted_kwargs = {k: convert_to_r(v) for k, v in kwargs.items()}
150
+
151
+ return func(*converted_args, **converted_kwargs, **kept)
152
+
153
+ return wrapper
154
+
155
+ return decorator
156
+
157
+
115
158
  def function_call(r_function: Callable[P, R], output_wrapper: Callable[[R], T]):
116
159
  """Decorator function to call an R function and post-process the result.
117
160
 
@@ -36,6 +36,7 @@ from rpy2.robjects.conversion import localconverter
36
36
  from rpy2.robjects.vectors import DataFrame as RDataFrame
37
37
  from shapely import wkt
38
38
 
39
+ from pysits.backend.arrow import PROBE_COLUMN, PROBE_VALUES, arrow_interop_error
39
40
  from pysits.backend.functions import r_fnc_class, r_fnc_set_column
40
41
  from pysits.backend.pkgs import r_pkg_base, r_pkg_sf, r_pkg_sits
41
42
  from pysits.models.frame import NestedFrame
@@ -90,6 +91,39 @@ def _sf_to_shapely(sf_object: RDataFrame) -> list:
90
91
  #
91
92
  # Arrow IPC helpers
92
93
  #
94
+ def _check_arrow_interop() -> None:
95
+ """Verify that Arrow data is not corrupted once R's libarrow is loaded.
96
+
97
+ R libarrow only initializes on first use, so a probe is sent through R to
98
+ force it, and ``pyarrow`` is then re-tested. A mismatched pair of libarrow
99
+ builds corrupts the conversion of Python objects to Arrow arrays, returning
100
+ zeros instead of raising, which would silently damage every nested column.
101
+
102
+ Raises:
103
+ RuntimeError: If either transfer loses data.
104
+ """
105
+ probe = PandasDataFrame({PROBE_COLUMN: PROBE_VALUES})
106
+
107
+ # Forces R libarrow to initialize, and checks the Python -> R direction
108
+ r_probe = rpy2_globalenv["pysits_read_ipc_raw"](
109
+ robjects.vectors.ByteVector(_dataframe_to_ipc_bytes(probe))
110
+ )
111
+
112
+ # Load content from R
113
+ observed = list(r_probe.rx2(PROBE_COLUMN))
114
+
115
+ # If it is different, then given an error
116
+ if observed != PROBE_VALUES:
117
+ raise arrow_interop_error(observed)
118
+
119
+ # Both libarrow builds are live now: check the conversion of Python objects
120
+ # to Arrow arrays, which is the path nested columns depend on.
121
+ observed = pa.array(PROBE_VALUES).to_pylist()
122
+
123
+ if observed != PROBE_VALUES:
124
+ raise arrow_interop_error(observed)
125
+
126
+
93
127
  def _ensure_r_ipc_functions():
94
128
  """Define R-side IPC reader/writer/unnester functions once."""
95
129
  if "pysits_write_ipc_raw" in rpy2_globalenv:
@@ -162,6 +196,8 @@ def _ensure_r_ipc_functions():
162
196
  }
163
197
  """)
164
198
 
199
+ _check_arrow_interop()
200
+
165
201
 
166
202
  def _dataframe_to_ipc_bytes(df: PandasDataFrame) -> bytes:
167
203
  """Serialize a pandas DataFrame to Arrow IPC bytes.
@@ -85,19 +85,34 @@ Args:
85
85
  area_spar (float): For embedding predictions, the smoothing parameter
86
86
  passed to the spline fit (default `0.6`); higher values produce
87
87
  smoother profiles.
88
+ image_args (dict): Geometry to render the figure with, with any of the
89
+ keys `width` and `height` (in inches), and `res` (in dots per
90
+ inch). See the notes on figure size below.
88
91
  **kwargs (dict): Further specifications for the plot. The keywords
89
92
  understood depend on the type of `x` (see below).
90
93
 
91
94
  Returns:
92
- None: A plot appropriate to the type of `x` is drawn. Maps of cubes
93
- yield color or B/W raster images (optionally overlaid with segment
94
- boundaries for vector cubes); probability, uncertainty, and
95
- variance cubes yield per-class or per-pixel maps; classified cubes
96
- yield color maps where each pixel is colored by its label.
97
- Chart-based plots (patterns, predictions, embeddings, clusters,
98
- t-SNE, model diagnostics) render the corresponding plot. Some
99
- methods (accuracy tables, SOM diagnostics, model summaries) are
100
- called only for their side effect of drawing the plot.
95
+ SITSPlot | SITSPlotList: The rendered figure. Objects that produce
96
+ several figures, samples with more than one band or label, for
97
+ example, return a `SITSPlotList`, which behaves as a sequence of
98
+ `SITSPlot`.
99
+
100
+ Maps of cubes yield color or B/W raster images (optionally
101
+ overlaid with segment boundaries for vector cubes). Probability,
102
+ uncertainty, and variance cubes yield per-class or per-pixel maps.
103
+ Classified cubes yield color maps where each pixel is colored by
104
+ its label. Chart-based plots (patterns, predictions, embeddings,
105
+ clusters, t-SNE, model diagnostics) render the corresponding plot.
106
+
107
+ How the figure reaches the page depends on where the code runs.
108
+ In a notebook, or a Quarto document using the `jupyter` engine,
109
+ the returned figure is rendered as the result of the cell. In
110
+ RStudio, or a Quarto document using the `knitr` engine, the
111
+ figures are handed to `knitr` as it renders the chunk, so each
112
+ one becomes a document figure of its own, with its own caption,
113
+ cross-reference, and layout. Everywhere else plotting displays
114
+ nothing by itself: use `save` to write the figure to a file, or
115
+ `show` to open it in an image viewer.
101
116
 
102
117
  Notes:
103
118
  The set of valid keyword arguments depends on the type of `x`;
@@ -115,3 +130,14 @@ Examples:
115
130
  # Train a random forest model and plot its important variables
116
131
  rf_model = sits_train(samples_modis_ndvi, ml_method=sits_rfor())
117
132
  plot(rf_model)
133
+
134
+ # Render a larger figure, and write it to a file
135
+ figure = plot(rf_model, image_args={"width": 12, "height": 8})
136
+ figure.save("model.png")
137
+
138
+ # Set the size of every figure that follows
139
+ set_plot_options(width=8, height=5, dpi=150)
140
+
141
+ # Objects with several bands or labels produce one figure each
142
+ figures = plot(samples_l8_rondonia_2bands)
143
+ figures[0].save("first.png")