rubin-sim 2.6.1.dev2__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.
- batch/compile_prenight_metadata_cache.sh +34 -0
- batch/run_auxtel_prenight_sims.sh +163 -0
- batch/run_prenight_sims.sh +239 -0
- docs/.gitignore +3 -0
- docs/Makefile +32 -0
- docs/api.rst +25 -0
- docs/conf.py +8 -0
- docs/data-api.rst +12 -0
- docs/data-download.rst +70 -0
- docs/developer.rst +14 -0
- docs/documenteer.toml +11 -0
- docs/index.rst +22 -0
- docs/installation.rst +76 -0
- docs/introduction.rst +37 -0
- docs/maf-api-batches.rst +12 -0
- docs/maf-api-db.rst +12 -0
- docs/maf-api-maf-contrib.rst +12 -0
- docs/maf-api-maps.rst +12 -0
- docs/maf-api-metricbundles.rst +12 -0
- docs/maf-api-metrics.rst +12 -0
- docs/maf-api-plots.rst +12 -0
- docs/maf-api-run-comparison.rst +12 -0
- docs/maf-api-slicers.rst +12 -0
- docs/maf-api-stackers.rst +12 -0
- docs/maf-api-utils.rst +12 -0
- docs/maf-api.rst +22 -0
- docs/maf.rst +60 -0
- docs/metric_list.py +49 -0
- docs/moving-objects-api.rst +12 -0
- docs/moving-objects.rst +22 -0
- docs/phot-utils-api.rst +12 -0
- docs/phot-utils.rst +11 -0
- docs/prenight.rst +117 -0
- docs/protoarchive.rst +276 -0
- docs/satellite-constellations-api.rst +12 -0
- docs/satellite-constellations.rst +13 -0
- docs/selfcal-api.rst +12 -0
- docs/selfcal.rst +15 -0
- docs/sim-archive-api.rst +12 -0
- docs/skybrightness-api.rst +12 -0
- docs/skybrightness.rst +23 -0
- docs/user-guide.rst +28 -0
- docs/vseqarchive-architecture.rst +438 -0
- docs/vseqarchive-setup.rst +238 -0
- docs/vseqarchive.rst +225 -0
- rubin_sim/__init__.py +7 -0
- rubin_sim/data/__init__.py +1 -0
- rubin_sim/data/rs_download_data.py +155 -0
- rubin_sim/maf/__init__.py +34 -0
- rubin_sim/maf/batches/__init__.py +18 -0
- rubin_sim/maf/batches/altaz_batch.py +161 -0
- rubin_sim/maf/batches/col_map_dict.py +274 -0
- rubin_sim/maf/batches/common.py +388 -0
- rubin_sim/maf/batches/ddf_batch.py +728 -0
- rubin_sim/maf/batches/filterchange_batch.py +182 -0
- rubin_sim/maf/batches/glance_batch.py +591 -0
- rubin_sim/maf/batches/hourglass_batch.py +79 -0
- rubin_sim/maf/batches/info_batch.py +114 -0
- rubin_sim/maf/batches/metadata_batch.py +558 -0
- rubin_sim/maf/batches/moving_objects_batch.py +1587 -0
- rubin_sim/maf/batches/openshutter_batch.py +100 -0
- rubin_sim/maf/batches/radar_limited.py +1100 -0
- rubin_sim/maf/batches/science_radar_batch.py +1910 -0
- rubin_sim/maf/batches/skycoverage.py +155 -0
- rubin_sim/maf/batches/slew_batch.py +146 -0
- rubin_sim/maf/batches/srd_batch.py +637 -0
- rubin_sim/maf/batches/time_batch.py +757 -0
- rubin_sim/maf/batches/time_sci_batch.py +105 -0
- rubin_sim/maf/batches/visitdepth_batch.py +485 -0
- rubin_sim/maf/db/__init__.py +2 -0
- rubin_sim/maf/db/add_run.py +34 -0
- rubin_sim/maf/db/results_db.py +1074 -0
- rubin_sim/maf/db/tracking_db.py +332 -0
- rubin_sim/maf/ddf_dir.py +53 -0
- rubin_sim/maf/generate_ss.py +218 -0
- rubin_sim/maf/glance_dir.py +58 -0
- rubin_sim/maf/maf_contrib/__init__.py +25 -0
- rubin_sim/maf/maf_contrib/calculate_lsst_field_visibility_astropy.py +170 -0
- rubin_sim/maf/maf_contrib/depth_limited_num_gal_metric.py +109 -0
- rubin_sim/maf/maf_contrib/example_new_metrics.py +40 -0
- rubin_sim/maf/maf_contrib/filter_pair_t_gaps_metric.py +208 -0
- rubin_sim/maf/maf_contrib/grb_transient_metric.py +249 -0
- rubin_sim/maf/maf_contrib/gw170817_det_metric.py +72 -0
- rubin_sim/maf/maf_contrib/intervals_between_obs_metric.py +68 -0
- rubin_sim/maf/maf_contrib/kne_metrics.py +473 -0
- rubin_sim/maf/maf_contrib/lss_metrics.py +45 -0
- rubin_sim/maf/maf_contrib/lss_obs_strategy/__init__.py +3 -0
- rubin_sim/maf/maf_contrib/lss_obs_strategy/constants_for_pipeline.py +73 -0
- rubin_sim/maf/maf_contrib/lss_obs_strategy/galaxy_counts_metric_extended.py +205 -0
- rubin_sim/maf/maf_contrib/lss_obs_strategy/galaxy_counts_with_pixel_calibration.py +171 -0
- rubin_sim/maf/maf_contrib/lv_dwarfs/__init__.py +1 -0
- rubin_sim/maf/maf_contrib/lv_dwarfs/lv_dwarfs_metrics.py +388 -0
- rubin_sim/maf/maf_contrib/microlensing_metric.py +593 -0
- rubin_sim/maf/maf_contrib/num_obs_in_survey_time_overlap_metric.py +43 -0
- rubin_sim/maf/maf_contrib/periodic_metric.py +51 -0
- rubin_sim/maf/maf_contrib/periodic_star_metric.py +186 -0
- rubin_sim/maf/maf_contrib/periodic_star_modulation_metric.py +236 -0
- rubin_sim/maf/maf_contrib/presto_color_kne_pop_metric.py +441 -0
- rubin_sim/maf/maf_contrib/selfcal_uniformity_metric.py +171 -0
- rubin_sim/maf/maf_contrib/star_count_mass_metric.py +64 -0
- rubin_sim/maf/maf_contrib/star_count_metric.py +56 -0
- rubin_sim/maf/maf_contrib/star_counts/__init__.py +8 -0
- rubin_sim/maf/maf_contrib/star_counts/abs_mag.py +324 -0
- rubin_sim/maf/maf_contrib/star_counts/coords.py +99 -0
- rubin_sim/maf/maf_contrib/star_counts/readme.txt +1 -0
- rubin_sim/maf/maf_contrib/star_counts/spec_type.py +91 -0
- rubin_sim/maf/maf_contrib/star_counts/starcount.py +30 -0
- rubin_sim/maf/maf_contrib/star_counts/starcount_bymass.py +93 -0
- rubin_sim/maf/maf_contrib/star_counts/stellardensity.py +59 -0
- rubin_sim/maf/maf_contrib/static_probes_fom_summary_metric.py +386 -0
- rubin_sim/maf/maf_contrib/tdes_pop_metric.py +362 -0
- rubin_sim/maf/maf_contrib/transient_ascii_sed_metric.py +652 -0
- rubin_sim/maf/maf_contrib/triplet_metric.py +156 -0
- rubin_sim/maf/maf_contrib/var_depth_metric.py +157 -0
- rubin_sim/maf/maf_contrib/xrb_metrics.py +523 -0
- rubin_sim/maf/maf_contrib/young_stellar_objects_metric.py +200 -0
- rubin_sim/maf/maf_night_report.py +200 -0
- rubin_sim/maf/make_fbs_tracking_db.py +90 -0
- rubin_sim/maf/maps/__init__.py +8 -0
- rubin_sim/maf/maps/base_map.py +72 -0
- rubin_sim/maf/maps/create_gaia_density_map.py +158 -0
- rubin_sim/maf/maps/dust_map.py +66 -0
- rubin_sim/maf/maps/dust_map_3d.py +190 -0
- rubin_sim/maf/maps/ebv_3d_hp.py +170 -0
- rubin_sim/maf/maps/ebv_hp.py +64 -0
- rubin_sim/maf/maps/gal_coords_map.py +22 -0
- rubin_sim/maf/maps/galactic_plane_priority_maps.py +210 -0
- rubin_sim/maf/maps/stellar_density_map.py +73 -0
- rubin_sim/maf/maps/trilegal_map.py +82 -0
- rubin_sim/maf/metadata_dir.py +90 -0
- rubin_sim/maf/metric_bundles/__init__.py +3 -0
- rubin_sim/maf/metric_bundles/metric_bundle.py +816 -0
- rubin_sim/maf/metric_bundles/metric_bundle_group.py +834 -0
- rubin_sim/maf/metric_bundles/mo_metric_bundle.py +646 -0
- rubin_sim/maf/metrics/__init__.py +52 -0
- rubin_sim/maf/metrics/agn_time_lag_metric.py +118 -0
- rubin_sim/maf/metrics/agnstructure.py +141 -0
- rubin_sim/maf/metrics/area_summary_metrics.py +120 -0
- rubin_sim/maf/metrics/base_metric.py +215 -0
- rubin_sim/maf/metrics/brown_dwarf_metric.py +162 -0
- rubin_sim/maf/metrics/cadence_metrics.py +400 -0
- rubin_sim/maf/metrics/calibration_metrics.py +618 -0
- rubin_sim/maf/metrics/chip_vendor_metric.py +43 -0
- rubin_sim/maf/metrics/color_slope_metrics.py +189 -0
- rubin_sim/maf/metrics/cosmology_summary_metrics.py +1212 -0
- rubin_sim/maf/metrics/coverage_metric.py +48 -0
- rubin_sim/maf/metrics/crowding_metric.py +255 -0
- rubin_sim/maf/metrics/cumulative_metric.py +46 -0
- rubin_sim/maf/metrics/dcr_metric.py +93 -0
- rubin_sim/maf/metrics/exgal_m5.py +57 -0
- rubin_sim/maf/metrics/fft_metric.py +27 -0
- rubin_sim/maf/metrics/galactic_plane_metrics.py +375 -0
- rubin_sim/maf/metrics/galplane_time_sampling_metrics.py +236 -0
- rubin_sim/maf/metrics/hourglass_metric.py +130 -0
- rubin_sim/maf/metrics/incremental_template_metric.py +255 -0
- rubin_sim/maf/metrics/kuiper_metrics.py +26 -0
- rubin_sim/maf/metrics/mo_metrics.py +1496 -0
- rubin_sim/maf/metrics/mo_summary_metrics.py +464 -0
- rubin_sim/maf/metrics/night_pointing_metric.py +70 -0
- rubin_sim/maf/metrics/optimal_m5_metric.py +94 -0
- rubin_sim/maf/metrics/pair_metric.py +69 -0
- rubin_sim/maf/metrics/periodic_detect_metric.py +133 -0
- rubin_sim/maf/metrics/phase_gap_metric.py +172 -0
- rubin_sim/maf/metrics/qso_number_counts_metric.py +138 -0
- rubin_sim/maf/metrics/scaling_metrics.py +148 -0
- rubin_sim/maf/metrics/schedview_metrics.py +39 -0
- rubin_sim/maf/metrics/season_metrics.py +344 -0
- rubin_sim/maf/metrics/simple_metrics.py +546 -0
- rubin_sim/maf/metrics/sky_sat_metric.py +18 -0
- rubin_sim/maf/metrics/sn_cadence_metric.py +104 -0
- rubin_sim/maf/metrics/sn_n_sn_metric.py +1364 -0
- rubin_sim/maf/metrics/sn_sl_metric.py +216 -0
- rubin_sim/maf/metrics/sn_snr_metric.py +715 -0
- rubin_sim/maf/metrics/snr_weight.py +24 -0
- rubin_sim/maf/metrics/star_density.py +77 -0
- rubin_sim/maf/metrics/string_count_metric.py +95 -0
- rubin_sim/maf/metrics/summary_metrics.py +201 -0
- rubin_sim/maf/metrics/surfb_metric.py +175 -0
- rubin_sim/maf/metrics/technical_metrics.py +271 -0
- rubin_sim/maf/metrics/tgaps.py +412 -0
- rubin_sim/maf/metrics/tomography_models.py +2034 -0
- rubin_sim/maf/metrics/transient_metrics.py +268 -0
- rubin_sim/maf/metrics/uniformity_metrics.py +418 -0
- rubin_sim/maf/metrics/use_metrics.py +55 -0
- rubin_sim/maf/metrics/vector_metrics.py +190 -0
- rubin_sim/maf/metrics/visit_groups_metric.py +341 -0
- rubin_sim/maf/metrics/weak_lensing_systematics_metric.py +210 -0
- rubin_sim/maf/plots/__init__.py +14 -0
- rubin_sim/maf/plots/hg_plotters.py +1117 -0
- rubin_sim/maf/plots/hourglass_plotters.py +120 -0
- rubin_sim/maf/plots/mo_plotters.py +358 -0
- rubin_sim/maf/plots/nd_plotters.py +220 -0
- rubin_sim/maf/plots/neo_distance_plotter.py +140 -0
- rubin_sim/maf/plots/night_pointing_plotter.py +96 -0
- rubin_sim/maf/plots/oned_plotters.py +114 -0
- rubin_sim/maf/plots/perceptual_rainbow.py +30 -0
- rubin_sim/maf/plots/plot_handler.py +766 -0
- rubin_sim/maf/plots/skyproj_plotters.py +540 -0
- rubin_sim/maf/plots/spatial_plotters.py +1029 -0
- rubin_sim/maf/plots/special_plotters.py +256 -0
- rubin_sim/maf/plots/two_d_plotters.py +177 -0
- rubin_sim/maf/plots/xyplotter.py +37 -0
- rubin_sim/maf/run_comparison/__init__.py +5 -0
- rubin_sim/maf/run_comparison/archive.py +584 -0
- rubin_sim/maf/run_comparison/gather_summaries.py +125 -0
- rubin_sim/maf/run_comparison/microlensing_compare.py +514 -0
- rubin_sim/maf/run_comparison/radar_plot.py +202 -0
- rubin_sim/maf/run_comparison/summary_plots.py +710 -0
- rubin_sim/maf/run_moving_calc.py +239 -0
- rubin_sim/maf/run_moving_fractions.py +128 -0
- rubin_sim/maf/run_moving_join.py +103 -0
- rubin_sim/maf/run_selfcal_metric.py +92 -0
- rubin_sim/maf/scimaf_dir.py +87 -0
- rubin_sim/maf/show_maf.py +227 -0
- rubin_sim/maf/slicers/__init__.py +13 -0
- rubin_sim/maf/slicers/base_slicer.py +513 -0
- rubin_sim/maf/slicers/base_spatial_slicer.py +202 -0
- rubin_sim/maf/slicers/healpix_sdss_slicer.py +118 -0
- rubin_sim/maf/slicers/healpix_slicer.py +189 -0
- rubin_sim/maf/slicers/healpix_subset_slicer.py +293 -0
- rubin_sim/maf/slicers/hourglass_slicer.py +37 -0
- rubin_sim/maf/slicers/mo_slicer.py +171 -0
- rubin_sim/maf/slicers/movie_slicer.py +288 -0
- rubin_sim/maf/slicers/nd_slicer.py +147 -0
- rubin_sim/maf/slicers/one_d_slicer.py +210 -0
- rubin_sim/maf/slicers/time_interval_slicers.py +283 -0
- rubin_sim/maf/slicers/uni_slicer.py +57 -0
- rubin_sim/maf/slicers/user_points_slicer.py +141 -0
- rubin_sim/maf/stackers/__init__.py +13 -0
- rubin_sim/maf/stackers/base_stacker.py +221 -0
- rubin_sim/maf/stackers/coord_stackers.py +224 -0
- rubin_sim/maf/stackers/date_stackers.py +192 -0
- rubin_sim/maf/stackers/general_stackers.py +683 -0
- rubin_sim/maf/stackers/get_col_info.py +104 -0
- rubin_sim/maf/stackers/label_stackers.py +114 -0
- rubin_sim/maf/stackers/m5_optimal_stacker.py +126 -0
- rubin_sim/maf/stackers/mo_phase.py +265 -0
- rubin_sim/maf/stackers/mo_stackers.py +486 -0
- rubin_sim/maf/stackers/n_follow_stacker.py +187 -0
- rubin_sim/maf/stackers/neo_dist_stacker.py +126 -0
- rubin_sim/maf/stackers/sdss_stackers.py +30 -0
- rubin_sim/maf/stackers/sn_stacker.py +152 -0
- rubin_sim/maf/stackers/teff_stacker.py +154 -0
- rubin_sim/maf/utils/__init__.py +6 -0
- rubin_sim/maf/utils/astrometry_utils.py +93 -0
- rubin_sim/maf/utils/generate_fov_map.py +58 -0
- rubin_sim/maf/utils/get_date_version.py +28 -0
- rubin_sim/maf/utils/maf_utils.py +212 -0
- rubin_sim/maf/utils/opsim_utils.py +259 -0
- rubin_sim/maf/utils/output_utils.py +34 -0
- rubin_sim/maf/utils/sn_n_sn_utils.py +894 -0
- rubin_sim/maf/utils/sn_utils.py +369 -0
- rubin_sim/maf/utils/stellar_mags.py +197 -0
- rubin_sim/maf/web/__init__.py +2 -0
- rubin_sim/maf/web/favicon.ico +0 -0
- rubin_sim/maf/web/maf_run_results.py +645 -0
- rubin_sim/maf/web/maf_tracking.py +139 -0
- rubin_sim/maf/web/sorttable.js +496 -0
- rubin_sim/maf/web/templates/allmetricresults.html +72 -0
- rubin_sim/maf/web/templates/configs.html +28 -0
- rubin_sim/maf/web/templates/macros.html +243 -0
- rubin_sim/maf/web/templates/master.html +294 -0
- rubin_sim/maf/web/templates/metricselect.html +91 -0
- rubin_sim/maf/web/templates/multicolor.html +147 -0
- rubin_sim/maf/web/templates/results.html +82 -0
- rubin_sim/maf/web/templates/runselect.html +58 -0
- rubin_sim/maf/web/templates/stats.html +50 -0
- rubin_sim/moving_objects/__init__.py +8 -0
- rubin_sim/moving_objects/base_obs.py +468 -0
- rubin_sim/moving_objects/cheby_fits.py +689 -0
- rubin_sim/moving_objects/cheby_values.py +231 -0
- rubin_sim/moving_objects/chebyshev_utils.py +365 -0
- rubin_sim/moving_objects/direct_obs.py +376 -0
- rubin_sim/moving_objects/make_lsst_obs.py +282 -0
- rubin_sim/moving_objects/ooephemerides.py +643 -0
- rubin_sim/moving_objects/orbits.py +507 -0
- rubin_sim/moving_objects/pre_generate.py +37 -0
- rubin_sim/moving_objects/utils.py +61 -0
- rubin_sim/phot_utils/__init__.py +7 -0
- rubin_sim/phot_utils/bandpass.py +425 -0
- rubin_sim/phot_utils/photometric_parameters.py +449 -0
- rubin_sim/phot_utils/physical_parameters.py +50 -0
- rubin_sim/phot_utils/predicted_zeropoints.py +245 -0
- rubin_sim/phot_utils/sed.py +1773 -0
- rubin_sim/phot_utils/sed_utils.py +52 -0
- rubin_sim/phot_utils/signaltonoise.py +695 -0
- rubin_sim/phot_utils/spectral_resampling.py +161 -0
- rubin_sim/satellite_constellations/__init__.py +3 -0
- rubin_sim/satellite_constellations/basis_function.py +40 -0
- rubin_sim/satellite_constellations/model_observatory.py +157 -0
- rubin_sim/satellite_constellations/sat_utils.py +488 -0
- rubin_sim/selfcal/__init__.py +4 -0
- rubin_sim/selfcal/generate_catalog.py +188 -0
- rubin_sim/selfcal/offsets.py +119 -0
- rubin_sim/selfcal/solver.py +143 -0
- rubin_sim/selfcal/star_tools.py +42 -0
- rubin_sim/sim_archive/__init__.py +14 -0
- rubin_sim/sim_archive/conda_packages.py +65 -0
- rubin_sim/sim_archive/future_vsarch.py +480 -0
- rubin_sim/sim_archive/make_snapshot.py +255 -0
- rubin_sim/sim_archive/prenight.py +216 -0
- rubin_sim/sim_archive/prenightindex.py +229 -0
- rubin_sim/sim_archive/prototype.py +1029 -0
- rubin_sim/sim_archive/sim_archive.py +680 -0
- rubin_sim/sim_archive/tempdb.py +56 -0
- rubin_sim/sim_archive/util.py +146 -0
- rubin_sim/sim_archive/vseqarchive.py +965 -0
- rubin_sim/sim_archive/vseqmetadata.py +1721 -0
- rubin_sim/skybrightness/__init__.py +5 -0
- rubin_sim/skybrightness/allsky_db.py +93 -0
- rubin_sim/skybrightness/data/ESO_Spectra/eso_tools.py +505 -0
- rubin_sim/skybrightness/data/solarSpec/package.py +22 -0
- rubin_sim/skybrightness/generate_hdf5.py +243 -0
- rubin_sim/skybrightness/interp_components.py +798 -0
- rubin_sim/skybrightness/sky_model.py +771 -0
- rubin_sim/skybrightness/twilight_func.py +83 -0
- rubin_sim/skybrightness/utils.py +91 -0
- rubin_sim-2.6.1.dev2.dist-info/METADATA +95 -0
- rubin_sim-2.6.1.dev2.dist-info/RECORD +387 -0
- rubin_sim-2.6.1.dev2.dist-info/WHEEL +5 -0
- rubin_sim-2.6.1.dev2.dist-info/entry_points.txt +24 -0
- rubin_sim-2.6.1.dev2.dist-info/licenses/LICENSE +674 -0
- rubin_sim-2.6.1.dev2.dist-info/top_level.txt +5 -0
- sql/make_vseqmeta.sql +251 -0
- tests/data/test_data.py +26 -0
- tests/data/test_ddf_grid.py +17 -0
- tests/maf/test_3x2fom.py +68 -0
- tests/maf/test_archive.py +162 -0
- tests/maf/test_basemetrics.py +99 -0
- tests/maf/test_batchcommon.py +36 -0
- tests/maf/test_batches.py +159 -0
- tests/maf/test_cadencemetrics.py +388 -0
- tests/maf/test_calibrationmetrics.py +242 -0
- tests/maf/test_color_slopes.py +71 -0
- tests/maf/test_cosmology_summaries.py +20 -0
- tests/maf/test_gathersummaries.py +48 -0
- tests/maf/test_healpixslicer.py +439 -0
- tests/maf/test_healpixsubsetslicer.py +273 -0
- tests/maf/test_hgplotters.py +145 -0
- tests/maf/test_hourglassmetric.py +33 -0
- tests/maf/test_io.py +187 -0
- tests/maf/test_json.py +169 -0
- tests/maf/test_maps.py +199 -0
- tests/maf/test_metricbundle.py +69 -0
- tests/maf/test_mometrics.py +422 -0
- tests/maf/test_movieslicer.py +216 -0
- tests/maf/test_ndslicer.py +240 -0
- tests/maf/test_neodistanceplotter.py +41 -0
- tests/maf/test_onedslicer.py +245 -0
- tests/maf/test_opsimutils.py +80 -0
- tests/maf/test_plotters.py +134 -0
- tests/maf/test_resultsdb.py +145 -0
- tests/maf/test_schedviewmetrics.py +14 -0
- tests/maf/test_simplemetrics.py +200 -0
- tests/maf/test_snmetrics.py +335 -0
- tests/maf/test_snmetrics_nsn.py +123 -0
- tests/maf/test_stackers.py +423 -0
- tests/maf/test_stellarmags.py +50 -0
- tests/maf/test_stringcount.py +26 -0
- tests/maf/test_summary_plots.py +197 -0
- tests/maf/test_summarymetrics.py +82 -0
- tests/maf/test_technicalmetrics.py +267 -0
- tests/maf/test_templatemetrics.py +86 -0
- tests/maf/test_timeintervalslicers.py +97 -0
- tests/maf/test_trackingdb.py +88 -0
- tests/maf/test_unislicer.py +116 -0
- tests/maf/test_vectormetrics.py +225 -0
- tests/maf/test_visitgroupsmetric.py +181 -0
- tests/moving_objects/test_camera.py +39 -0
- tests/moving_objects/test_chebyfits.py +188 -0
- tests/moving_objects/test_chebyshevutils.py +76 -0
- tests/moving_objects/test_chebyvalues.py +245 -0
- tests/moving_objects/test_ephemerides.py +219 -0
- tests/moving_objects/test_orbits.py +170 -0
- tests/moving_objects/test_sed_data.py +61 -0
- tests/phot_utils/test_approximatebandpasses.py +91 -0
- tests/phot_utils/test_photometricparameters.py +268 -0
- tests/phot_utils/test_photometry.py +61 -0
- tests/phot_utils/test_predicted_zeropoints.py +53 -0
- tests/phot_utils/test_read_bandpasses.py +29 -0
- tests/phot_utils/test_sed.py +368 -0
- tests/phot_utils/test_snr.py +370 -0
- tests/satellite_constellations/test_satellites.py +36 -0
- tests/sim_archive/test_make_snapshot.py +24 -0
- tests/sim_archive/test_prototype_sim_archive.py +204 -0
- tests/sim_archive/test_vseqarchive.py +947 -0
- tests/skybrightness/test_skymodel.py +359 -0
|
@@ -0,0 +1,766 @@
|
|
|
1
|
+
__all__ = ("apply_zp_norm", "PlotHandler", "BasePlotter")
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import warnings
|
|
5
|
+
|
|
6
|
+
import matplotlib.pyplot as plt
|
|
7
|
+
import numpy as np
|
|
8
|
+
|
|
9
|
+
import rubin_sim.maf.utils as utils
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def apply_zp_norm(metric_value, plot_dict):
|
|
13
|
+
if "zp" in plot_dict:
|
|
14
|
+
if plot_dict["zp"] is not None:
|
|
15
|
+
metric_value = metric_value - plot_dict["zp"]
|
|
16
|
+
if "norm_val" in plot_dict:
|
|
17
|
+
if plot_dict["norm_val"] is not None:
|
|
18
|
+
metric_value = metric_value / plot_dict["norm_val"]
|
|
19
|
+
return metric_value
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class BasePlotter:
|
|
23
|
+
"""
|
|
24
|
+
Serve as the base type for MAF plotters and example of API.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def __init__(self):
|
|
28
|
+
self.plot_type = None
|
|
29
|
+
# This should be included in every subsequent default_plot_dict
|
|
30
|
+
# (assumed to be present).
|
|
31
|
+
self.default_plot_dict = {
|
|
32
|
+
"title": None,
|
|
33
|
+
"xlabel": None,
|
|
34
|
+
"label": None,
|
|
35
|
+
"labelsize": None,
|
|
36
|
+
"fontsize": None,
|
|
37
|
+
"figsize": None,
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
def __call__(self, metric_value, slicer, user_plot_dict, fig=None):
|
|
41
|
+
"""
|
|
42
|
+
Parameters
|
|
43
|
+
----------
|
|
44
|
+
metric_value : `numpy.ma.MaskedArray`
|
|
45
|
+
The metric values from the bundle.
|
|
46
|
+
slicer : `rubin_sim.maf.slicers.TwoDSlicer`
|
|
47
|
+
The slicer.
|
|
48
|
+
user_plot_dict: `dict`
|
|
49
|
+
Dictionary of plot parameters set by user
|
|
50
|
+
(overrides default values).
|
|
51
|
+
fig : `matplotlib.figure.Figure`
|
|
52
|
+
Matplotlib figure number to use. Default = None, starts new figure.
|
|
53
|
+
|
|
54
|
+
Returns
|
|
55
|
+
-------
|
|
56
|
+
fig : `matplotlib.figure.Figure`
|
|
57
|
+
Figure with the plot.
|
|
58
|
+
"""
|
|
59
|
+
pass
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class PlotHandler:
|
|
63
|
+
"""Create plots from a single or series of metric bundles.
|
|
64
|
+
|
|
65
|
+
Parameters
|
|
66
|
+
----------
|
|
67
|
+
out_dir : `str`, optional
|
|
68
|
+
Directory to save output plots.
|
|
69
|
+
results_db : `rubin_sim.maf.ResultsDb`, optional
|
|
70
|
+
ResultsDb into which to record plot location and information.
|
|
71
|
+
savefig : `bool`, optional
|
|
72
|
+
Flag for saving images to disk (versus create and return
|
|
73
|
+
to caller).
|
|
74
|
+
fig_format : `str`, optional
|
|
75
|
+
Figure format to use to save full-size output. Default PDF.
|
|
76
|
+
dpi : `int`, optional
|
|
77
|
+
DPI to save output figures to disk at. (for matplotlib figures).
|
|
78
|
+
thumbnail : `bool`, optional
|
|
79
|
+
Flag for saving thumbnails (reduced size pngs) to disk.
|
|
80
|
+
trim_whitespace : `bool`, optional
|
|
81
|
+
Flag for trimming whitespace option to matplotlib output figures.
|
|
82
|
+
Default True, usually doesn't need to be changed.
|
|
83
|
+
"""
|
|
84
|
+
|
|
85
|
+
def __init__(
|
|
86
|
+
self,
|
|
87
|
+
out_dir=".",
|
|
88
|
+
results_db=None,
|
|
89
|
+
savefig=True,
|
|
90
|
+
fig_format="pdf",
|
|
91
|
+
dpi=600,
|
|
92
|
+
thumbnail=True,
|
|
93
|
+
trim_whitespace=True,
|
|
94
|
+
):
|
|
95
|
+
self.out_dir = out_dir
|
|
96
|
+
self.results_db = results_db
|
|
97
|
+
self.savefig = savefig
|
|
98
|
+
self.fig_format = fig_format
|
|
99
|
+
self.dpi = dpi
|
|
100
|
+
self.trim_whitespace = trim_whitespace
|
|
101
|
+
self.thumbnail = thumbnail
|
|
102
|
+
self.filtercolors = {
|
|
103
|
+
"u": "cyan",
|
|
104
|
+
"g": "g",
|
|
105
|
+
"r": "y",
|
|
106
|
+
"i": "r",
|
|
107
|
+
"z": "m",
|
|
108
|
+
"y": "k",
|
|
109
|
+
" ": None,
|
|
110
|
+
}
|
|
111
|
+
self.filterorder = {" ": -1, "u": 0, "g": 1, "r": 2, "i": 3, "z": 4, "y": 5}
|
|
112
|
+
|
|
113
|
+
def set_metric_bundles(self, m_bundles):
|
|
114
|
+
"""
|
|
115
|
+
Set the metric bundle or bundles (list or dictionary).
|
|
116
|
+
Reuse the PlotHandler by resetting this reference.
|
|
117
|
+
The metric bundles have to have the same slicer.
|
|
118
|
+
"""
|
|
119
|
+
self.m_bundles = []
|
|
120
|
+
# Try to add the metricBundles in filter order.
|
|
121
|
+
if isinstance(m_bundles, dict):
|
|
122
|
+
for m_b in m_bundles.values():
|
|
123
|
+
vals = m_b.file_root.split("_")
|
|
124
|
+
forder = [self.filterorder.get(f, None) for f in vals if len(f) == 1]
|
|
125
|
+
forder = [o for o in forder if o is not None]
|
|
126
|
+
if len(forder) == 0:
|
|
127
|
+
forder = len(self.m_bundles)
|
|
128
|
+
else:
|
|
129
|
+
forder = forder[-1]
|
|
130
|
+
self.m_bundles.insert(forder, m_b)
|
|
131
|
+
self.slicer = self.m_bundles[0].slicer
|
|
132
|
+
else:
|
|
133
|
+
for m_b in m_bundles:
|
|
134
|
+
vals = m_b.file_root.split("_")
|
|
135
|
+
forder = [self.filterorder.get(f, None) for f in vals if len(f) == 1]
|
|
136
|
+
forder = [o for o in forder if o is not None]
|
|
137
|
+
if len(forder) == 0:
|
|
138
|
+
forder = len(self.m_bundles)
|
|
139
|
+
else:
|
|
140
|
+
forder = forder[-1]
|
|
141
|
+
self.m_bundles.insert(forder, m_b)
|
|
142
|
+
self.slicer = self.m_bundles[0].slicer
|
|
143
|
+
for m_b in self.m_bundles:
|
|
144
|
+
if m_b.slicer.slicer_name != self.slicer.slicer_name:
|
|
145
|
+
raise ValueError("MetricBundle items must have the same type of slicer")
|
|
146
|
+
self._combine_metric_names()
|
|
147
|
+
self._combine_run_names()
|
|
148
|
+
self._combine_metadata()
|
|
149
|
+
self._combine_constraints()
|
|
150
|
+
self.set_plot_dicts(reset=True)
|
|
151
|
+
|
|
152
|
+
def set_plot_dicts(self, plot_dicts=None, plot_func=None, reset=False):
|
|
153
|
+
"""
|
|
154
|
+
Set or update the plot_dict for the (possibly joint) plots.
|
|
155
|
+
|
|
156
|
+
Resolution is: (from lowest to higher)
|
|
157
|
+
auto-generated items (colors/labels/titles)
|
|
158
|
+
< anything previously set in the plot_handler
|
|
159
|
+
< defaults set by the plotter
|
|
160
|
+
< explicitly set items in the metricBundle plot_dict
|
|
161
|
+
< explicitly set items in the plot_dicts list passed to this method.
|
|
162
|
+
"""
|
|
163
|
+
if reset:
|
|
164
|
+
# Have to explicitly set each dictionary to a (separate)
|
|
165
|
+
# blank dictionary.
|
|
166
|
+
self.plot_dicts = [{} for b in self.m_bundles]
|
|
167
|
+
|
|
168
|
+
if isinstance(plot_dicts, dict):
|
|
169
|
+
# We were passed a single dictionary, not a list.
|
|
170
|
+
plot_dicts = [plot_dicts] * len(self.m_bundles)
|
|
171
|
+
|
|
172
|
+
auto_label_list = self._build_legend_labels()
|
|
173
|
+
auto_color_list = self._build_colors()
|
|
174
|
+
auto_cbar = self._build_cbar_format()
|
|
175
|
+
auto_title = self._build_title()
|
|
176
|
+
if plot_func is not None:
|
|
177
|
+
auto_xlabel, auto_ylabel = self._build_x_ylabels(plot_func)
|
|
178
|
+
|
|
179
|
+
# Loop through each bundle and generate a plot_dict for it.
|
|
180
|
+
for i, bundle in enumerate(self.m_bundles):
|
|
181
|
+
# First use the auto-generated values.
|
|
182
|
+
tmp_plot_dict = {}
|
|
183
|
+
tmp_plot_dict["title"] = auto_title
|
|
184
|
+
tmp_plot_dict["label"] = auto_label_list[i]
|
|
185
|
+
tmp_plot_dict["color"] = auto_color_list[i]
|
|
186
|
+
tmp_plot_dict["cbar_format"] = auto_cbar
|
|
187
|
+
# Update that with anything previously set in the plot_handler.
|
|
188
|
+
tmp_plot_dict.update(self.plot_dicts[i])
|
|
189
|
+
# Then override with plot_dict items set explicitly
|
|
190
|
+
# based on the plot type.
|
|
191
|
+
if plot_func is not None:
|
|
192
|
+
tmp_plot_dict["xlabel"] = auto_xlabel
|
|
193
|
+
tmp_plot_dict["ylabel"] = auto_ylabel
|
|
194
|
+
# Replace auto-generated plot dict items with things
|
|
195
|
+
# set by the plotter_defaults, if they are not None.
|
|
196
|
+
plotter_defaults = plot_func.default_plot_dict
|
|
197
|
+
for k, v in plotter_defaults.items():
|
|
198
|
+
if v is not None:
|
|
199
|
+
tmp_plot_dict[k] = v
|
|
200
|
+
# Then add/override based on the bundle plot_dict parameters
|
|
201
|
+
# if they are set.
|
|
202
|
+
tmp_plot_dict.update(bundle.plot_dict)
|
|
203
|
+
# Finally, override with anything set explicitly by the user.
|
|
204
|
+
if plot_dicts is not None:
|
|
205
|
+
tmp_plot_dict.update(plot_dicts[i])
|
|
206
|
+
# And save this new dictionary back in the class.
|
|
207
|
+
self.plot_dicts[i] = tmp_plot_dict
|
|
208
|
+
|
|
209
|
+
# Check that the plot_dicts do not conflict.
|
|
210
|
+
self._check_plot_dicts()
|
|
211
|
+
|
|
212
|
+
def _combine_metric_names(self):
|
|
213
|
+
"""
|
|
214
|
+
Combine metric names.
|
|
215
|
+
"""
|
|
216
|
+
# Find the unique metric names.
|
|
217
|
+
self.metric_names = set()
|
|
218
|
+
for m_b in self.m_bundles:
|
|
219
|
+
self.metric_names.add(m_b.metric.name)
|
|
220
|
+
# Find a pleasing combination of the metric names.
|
|
221
|
+
order = ["u", "g", "r", "i", "z", "y"]
|
|
222
|
+
if len(self.metric_names) == 1:
|
|
223
|
+
joint_name = " ".join(self.metric_names)
|
|
224
|
+
else:
|
|
225
|
+
# Split each unique name into a list to see
|
|
226
|
+
# if we can merge the names.
|
|
227
|
+
name_lengths = [len(x.split()) for x in self.metric_names]
|
|
228
|
+
name_lists = [x.split() for x in self.metric_names]
|
|
229
|
+
# If the metric names are all the same length, see
|
|
230
|
+
# if we can combine any parts.
|
|
231
|
+
if len(set(name_lengths)) == 1:
|
|
232
|
+
joint_name = []
|
|
233
|
+
for i in range(name_lengths[0]):
|
|
234
|
+
tmp = set([x[i] for x in name_lists])
|
|
235
|
+
# Try to catch special case of filters and
|
|
236
|
+
# put them in order.
|
|
237
|
+
if tmp.intersection(order) == tmp:
|
|
238
|
+
filterlist = ""
|
|
239
|
+
for f in order:
|
|
240
|
+
if f in tmp:
|
|
241
|
+
filterlist += f
|
|
242
|
+
joint_name.append(filterlist)
|
|
243
|
+
else:
|
|
244
|
+
# Otherwise, just join and put into joint_name.
|
|
245
|
+
joint_name.append("".join(tmp))
|
|
246
|
+
joint_name = " ".join(joint_name)
|
|
247
|
+
# If the metric names are not the same length,
|
|
248
|
+
# just join everything.
|
|
249
|
+
else:
|
|
250
|
+
joint_name = " ".join(self.metric_names)
|
|
251
|
+
self.joint_metric_names = joint_name
|
|
252
|
+
|
|
253
|
+
def _combine_run_names(self):
|
|
254
|
+
"""
|
|
255
|
+
Combine runNames.
|
|
256
|
+
"""
|
|
257
|
+
self.run_names = set()
|
|
258
|
+
for m_b in self.m_bundles:
|
|
259
|
+
self.run_names.add(m_b.run_name)
|
|
260
|
+
self.joint_run_names = " ".join(self.run_names)
|
|
261
|
+
|
|
262
|
+
def _combine_metadata(self):
|
|
263
|
+
"""
|
|
264
|
+
Combine info_label.
|
|
265
|
+
"""
|
|
266
|
+
info_label = set()
|
|
267
|
+
for m_b in self.m_bundles:
|
|
268
|
+
info_label.add(m_b.info_label)
|
|
269
|
+
self.info_label = info_label
|
|
270
|
+
# Find a pleasing combination of the info_label.
|
|
271
|
+
if len(info_label) == 1:
|
|
272
|
+
self.joint_metadata = " ".join(info_label)
|
|
273
|
+
else:
|
|
274
|
+
order = ["u", "g", "r", "i", "z", "y"]
|
|
275
|
+
# See if there are any subcomponents we can combine,
|
|
276
|
+
# splitting on some values we expect to separate
|
|
277
|
+
# info_label clauses.
|
|
278
|
+
splitmetas = []
|
|
279
|
+
for m in self.info_label:
|
|
280
|
+
# Try to split info_label into separate phrases
|
|
281
|
+
# (filter / proposal / constraint..).
|
|
282
|
+
if " and " in m:
|
|
283
|
+
m = m.split(" and ")
|
|
284
|
+
elif ", " in m:
|
|
285
|
+
m = m.split(", ")
|
|
286
|
+
else:
|
|
287
|
+
m = [
|
|
288
|
+
m,
|
|
289
|
+
]
|
|
290
|
+
# Strip white spaces from individual elements.
|
|
291
|
+
m = set([im.strip() for im in m])
|
|
292
|
+
splitmetas.append(m)
|
|
293
|
+
# Look for common elements and
|
|
294
|
+
# separate from the general info_label.
|
|
295
|
+
common = set.intersection(*splitmetas)
|
|
296
|
+
diff = [x.difference(common) for x in splitmetas]
|
|
297
|
+
# Now look within the 'diff' elements and
|
|
298
|
+
# see if there are any common words to split off.
|
|
299
|
+
diffsplit = []
|
|
300
|
+
for d in diff:
|
|
301
|
+
if len(d) > 0:
|
|
302
|
+
m = set([x.split() for x in d][0])
|
|
303
|
+
else:
|
|
304
|
+
m = set()
|
|
305
|
+
diffsplit.append(m)
|
|
306
|
+
diffcommon = set.intersection(*diffsplit)
|
|
307
|
+
diffdiff = [x.difference(diffcommon) for x in diffsplit]
|
|
308
|
+
# If the length of any of the 'differences' is 0,
|
|
309
|
+
# then we should stop and not try to subdivide.
|
|
310
|
+
lengths = [len(x) for x in diffdiff]
|
|
311
|
+
if min(lengths) == 0:
|
|
312
|
+
# Sort them in order of length
|
|
313
|
+
# (so it goes 'g', 'g dithered', etc.)
|
|
314
|
+
tmp = []
|
|
315
|
+
for d in diff:
|
|
316
|
+
tmp.append(list(d)[0])
|
|
317
|
+
diff = tmp
|
|
318
|
+
xlengths = [len(x) for x in diff]
|
|
319
|
+
idx = np.argsort(xlengths)
|
|
320
|
+
diffdiff = [diff[i] for i in idx]
|
|
321
|
+
diffcommon = []
|
|
322
|
+
else:
|
|
323
|
+
# diffdiff is the part where we might expect
|
|
324
|
+
# our filter values to appear;
|
|
325
|
+
# try to put this in order.
|
|
326
|
+
diffdiff_ordered = []
|
|
327
|
+
diffdiff_end = []
|
|
328
|
+
for f in order:
|
|
329
|
+
for d in diffdiff:
|
|
330
|
+
if len(d) == 1:
|
|
331
|
+
if list(d)[0] == f:
|
|
332
|
+
diffdiff_ordered.append(d)
|
|
333
|
+
for d in diffdiff:
|
|
334
|
+
if d not in diffdiff_ordered:
|
|
335
|
+
diffdiff_end.append(d)
|
|
336
|
+
diffdiff = diffdiff_ordered + diffdiff_end
|
|
337
|
+
diffdiff = [" ".join(c) for c in diffdiff]
|
|
338
|
+
# And put it all back together.
|
|
339
|
+
combo = (
|
|
340
|
+
", ".join(["".join(c) for c in diffdiff])
|
|
341
|
+
+ " "
|
|
342
|
+
+ " ".join(["".join(d) for d in diffcommon])
|
|
343
|
+
+ " "
|
|
344
|
+
+ " ".join(["".join(e) for e in common])
|
|
345
|
+
)
|
|
346
|
+
self.joint_metadata = combo
|
|
347
|
+
|
|
348
|
+
def _combine_constraints(self):
|
|
349
|
+
"""
|
|
350
|
+
Combine the constraints.
|
|
351
|
+
"""
|
|
352
|
+
constraints = set()
|
|
353
|
+
for m_b in self.m_bundles:
|
|
354
|
+
if m_b.constraint is not None:
|
|
355
|
+
constraints.add(m_b.constraint)
|
|
356
|
+
self.constraints = "; ".join(constraints)
|
|
357
|
+
|
|
358
|
+
def _build_title(self):
|
|
359
|
+
"""
|
|
360
|
+
Build a plot title from the metric names, runNames and info_label.
|
|
361
|
+
"""
|
|
362
|
+
# Create a plot title from the unique parts of
|
|
363
|
+
# the metric/run_name/info_label.
|
|
364
|
+
plot_title = ""
|
|
365
|
+
if len(self.run_names) == 1:
|
|
366
|
+
plot_title += list(self.run_names)[0]
|
|
367
|
+
if len(self.info_label) == 1:
|
|
368
|
+
plot_title += " " + list(self.info_label)[0]
|
|
369
|
+
if len(self.metric_names) == 1:
|
|
370
|
+
plot_title += ": " + list(self.metric_names)[0]
|
|
371
|
+
if plot_title == "":
|
|
372
|
+
# If there were more than one of everything above,
|
|
373
|
+
# use joint info_label and metricNames.
|
|
374
|
+
plot_title = self.joint_metadata + " " + self.joint_metric_names
|
|
375
|
+
return plot_title
|
|
376
|
+
|
|
377
|
+
def _build_x_ylabels(self, plot_func, len_max=25):
|
|
378
|
+
"""
|
|
379
|
+
Build a plot x and y label.
|
|
380
|
+
|
|
381
|
+
Parameters
|
|
382
|
+
----------
|
|
383
|
+
len_max : `int`, optional
|
|
384
|
+
If the xlabel starts longer than this, add the units as a newline.
|
|
385
|
+
"""
|
|
386
|
+
if plot_func.plot_type == "BinnedData":
|
|
387
|
+
if len(self.m_bundles) == 1:
|
|
388
|
+
m_b = self.m_bundles[0]
|
|
389
|
+
if len(m_b.slicer.slice_col_name) < len_max:
|
|
390
|
+
xlabel = m_b.slicer.slice_col_name + " (" + m_b.slicer.slice_col_units + ")"
|
|
391
|
+
else:
|
|
392
|
+
xlabel = m_b.slicer.slice_col_name + " \n(" + m_b.slicer.slice_col_units + ")"
|
|
393
|
+
ylabel = m_b.metric.name + " (" + m_b.metric.units + ")"
|
|
394
|
+
else:
|
|
395
|
+
xlabel = set()
|
|
396
|
+
for m_b in self.m_bundles:
|
|
397
|
+
xlabel.add(m_b.slicer.slice_col_name)
|
|
398
|
+
xlabel = ", ".join(xlabel)
|
|
399
|
+
ylabel = self.joint_metric_names
|
|
400
|
+
elif plot_func.plot_type == "MetricVsH":
|
|
401
|
+
if len(self.m_bundles) == 1:
|
|
402
|
+
m_b = self.m_bundles[0]
|
|
403
|
+
ylabel = m_b.metric.name + " (" + m_b.metric.units + ")"
|
|
404
|
+
else:
|
|
405
|
+
ylabel = self.joint_metric_names
|
|
406
|
+
xlabel = "H (mag)"
|
|
407
|
+
else:
|
|
408
|
+
if len(self.m_bundles) == 1:
|
|
409
|
+
m_b = self.m_bundles[0]
|
|
410
|
+
xlabel = m_b.metric.name
|
|
411
|
+
if m_b.metric.units is not None:
|
|
412
|
+
if len(m_b.metric.units) > 0:
|
|
413
|
+
if len(xlabel) < len_max:
|
|
414
|
+
xlabel += " (" + m_b.metric.units + ")"
|
|
415
|
+
else:
|
|
416
|
+
xlabel += "\n(" + m_b.metric.units + ")"
|
|
417
|
+
ylabel = None
|
|
418
|
+
else:
|
|
419
|
+
xlabel = self.joint_metric_names
|
|
420
|
+
ylabel = set()
|
|
421
|
+
for m_b in self.m_bundles:
|
|
422
|
+
if "ylabel" in m_b.plot_dict:
|
|
423
|
+
ylabel.add(m_b.plot_dict["ylabel"])
|
|
424
|
+
if len(ylabel) == 1:
|
|
425
|
+
ylabel = list(ylabel)[0]
|
|
426
|
+
else:
|
|
427
|
+
ylabel = None
|
|
428
|
+
return xlabel, ylabel
|
|
429
|
+
|
|
430
|
+
def _build_legend_labels(self):
|
|
431
|
+
"""
|
|
432
|
+
Build a set of legend labels,
|
|
433
|
+
using the parts of the run_name/info_label/metricNames that change.
|
|
434
|
+
"""
|
|
435
|
+
if len(self.m_bundles) == 1:
|
|
436
|
+
return [None]
|
|
437
|
+
labels = []
|
|
438
|
+
for m_b in self.m_bundles:
|
|
439
|
+
if "label" in m_b.plot_dict:
|
|
440
|
+
label = m_b.plot_dict["label"]
|
|
441
|
+
else:
|
|
442
|
+
label = ""
|
|
443
|
+
if len(self.run_names) > 1:
|
|
444
|
+
label += m_b.run_name
|
|
445
|
+
if len(self.info_label) > 1:
|
|
446
|
+
label += " " + m_b.info_label
|
|
447
|
+
if len(self.metric_names) > 1:
|
|
448
|
+
label += " " + m_b.metric.name
|
|
449
|
+
labels.append(label)
|
|
450
|
+
return labels
|
|
451
|
+
|
|
452
|
+
def _build_colors(self):
|
|
453
|
+
"""
|
|
454
|
+
Try to set an appropriate range of colors for the metric Bundles.
|
|
455
|
+
"""
|
|
456
|
+
if len(self.m_bundles) == 1:
|
|
457
|
+
if "color" in self.m_bundles[0].plot_dict:
|
|
458
|
+
return [self.m_bundles[0].plot_dict["color"]]
|
|
459
|
+
else:
|
|
460
|
+
return ["b"]
|
|
461
|
+
colors = []
|
|
462
|
+
for m_b in self.m_bundles:
|
|
463
|
+
color = "b"
|
|
464
|
+
if "color" in m_b.plot_dict:
|
|
465
|
+
color = m_b.plot_dict["color"]
|
|
466
|
+
else:
|
|
467
|
+
if m_b.constraint is not None:
|
|
468
|
+
# If the filter is part of the sql constraint, we'll
|
|
469
|
+
# try to use that first.
|
|
470
|
+
if "filter" in m_b.constraint:
|
|
471
|
+
vals = m_b.constraint.split('"')
|
|
472
|
+
for v in vals:
|
|
473
|
+
if len(v) == 1:
|
|
474
|
+
# Guess that this is the filter value
|
|
475
|
+
if v in self.filtercolors:
|
|
476
|
+
color = self.filtercolors[v]
|
|
477
|
+
colors.append(color)
|
|
478
|
+
# If we happened to end up with the same color throughout
|
|
479
|
+
# (say, the metrics were all in the same filter)
|
|
480
|
+
# then go ahead and generate random colors.
|
|
481
|
+
if (len(self.m_bundles) > 1) and (len(np.unique(colors)) == 1):
|
|
482
|
+
colors = [
|
|
483
|
+
np.random.rand(
|
|
484
|
+
3,
|
|
485
|
+
)
|
|
486
|
+
for m_b in self.m_bundles
|
|
487
|
+
]
|
|
488
|
+
return colors
|
|
489
|
+
|
|
490
|
+
def _build_cbar_format(self):
|
|
491
|
+
"""
|
|
492
|
+
Set the color bar format.
|
|
493
|
+
"""
|
|
494
|
+
cbar_format = None
|
|
495
|
+
if len(self.m_bundles) == 1:
|
|
496
|
+
if self.m_bundles[0].metric.metric_dtype == "int":
|
|
497
|
+
cbar_format = "%d"
|
|
498
|
+
else:
|
|
499
|
+
metric_dtypes = set()
|
|
500
|
+
for m_b in self.m_bundles:
|
|
501
|
+
metric_dtypes.add(m_b.metric.metric_dtype)
|
|
502
|
+
if len(metric_dtypes) == 1:
|
|
503
|
+
if list(metric_dtypes)[0] == "int":
|
|
504
|
+
cbar_format = "%d"
|
|
505
|
+
return cbar_format
|
|
506
|
+
|
|
507
|
+
def _build_file_root(self, outfile_suffix=None):
|
|
508
|
+
"""
|
|
509
|
+
Build a root filename for plot outputs.
|
|
510
|
+
If there is only one metricBundle,
|
|
511
|
+
this is equal to the metricBundle fileRoot + outfile_suffix.
|
|
512
|
+
For multiple metricBundles,
|
|
513
|
+
this is created from the runNames, info_label and metric names.
|
|
514
|
+
|
|
515
|
+
If you do not wish to use the automatic filenames,
|
|
516
|
+
then you could set 'savefig' to False and
|
|
517
|
+
save the file manually to disk,
|
|
518
|
+
using the plot figure numbers returned by 'plot'.
|
|
519
|
+
"""
|
|
520
|
+
if len(self.m_bundles) == 1:
|
|
521
|
+
outfile = self.m_bundles[0].file_root
|
|
522
|
+
else:
|
|
523
|
+
outfile = "_".join([self.joint_run_names, self.joint_metric_names, self.joint_metadata])
|
|
524
|
+
outfile += "_" + self.m_bundles[0].slicer.slicer_name[:4].upper()
|
|
525
|
+
if outfile_suffix is not None:
|
|
526
|
+
outfile += "_" + outfile_suffix
|
|
527
|
+
outfile = utils.name_sanitize(outfile)
|
|
528
|
+
return outfile
|
|
529
|
+
|
|
530
|
+
def _build_display_dict(self):
|
|
531
|
+
"""
|
|
532
|
+
Generate a display dictionary.
|
|
533
|
+
This is most useful for when there are many metricBundles
|
|
534
|
+
being combined into a single plot.
|
|
535
|
+
"""
|
|
536
|
+
if len(self.m_bundles) == 1:
|
|
537
|
+
return self.m_bundles[0].display_dict
|
|
538
|
+
else:
|
|
539
|
+
display_dict = {}
|
|
540
|
+
group = set()
|
|
541
|
+
subgroup = set()
|
|
542
|
+
order = 0
|
|
543
|
+
for m_b in self.m_bundles:
|
|
544
|
+
group.add(m_b.display_dict["group"])
|
|
545
|
+
subgroup.add(m_b.display_dict["subgroup"])
|
|
546
|
+
if order < m_b.display_dict["order"]:
|
|
547
|
+
order = m_b.display_dict["order"] + 1
|
|
548
|
+
display_dict["order"] = order
|
|
549
|
+
if len(group) > 1:
|
|
550
|
+
display_dict["group"] = "Comparisons"
|
|
551
|
+
else:
|
|
552
|
+
display_dict["group"] = list(group)[0]
|
|
553
|
+
if len(subgroup) > 1:
|
|
554
|
+
display_dict["subgroup"] = "Comparisons"
|
|
555
|
+
else:
|
|
556
|
+
display_dict["subgroup"] = list(subgroup)[0]
|
|
557
|
+
|
|
558
|
+
display_dict["caption"] = (
|
|
559
|
+
"%s metric(s) calculated on a %s grid, for opsim runs %s, for info_label values of %s."
|
|
560
|
+
% (
|
|
561
|
+
self.joint_metric_names,
|
|
562
|
+
self.m_bundles[0].slicer.slicer_name,
|
|
563
|
+
self.joint_run_names,
|
|
564
|
+
self.joint_metadata,
|
|
565
|
+
)
|
|
566
|
+
)
|
|
567
|
+
|
|
568
|
+
return display_dict
|
|
569
|
+
|
|
570
|
+
def _check_plot_dicts(self):
|
|
571
|
+
"""
|
|
572
|
+
Check to make sure there are no conflicts in the plot_dicts
|
|
573
|
+
that are being used in the same subplot.
|
|
574
|
+
"""
|
|
575
|
+
# Check that the length is OK
|
|
576
|
+
if len(self.plot_dicts) != len(self.m_bundles):
|
|
577
|
+
raise ValueError(
|
|
578
|
+
"plot_dicts (%i) must be same length as mBundles (%i)"
|
|
579
|
+
% (len(self.plot_dicts), len(self.m_bundles))
|
|
580
|
+
)
|
|
581
|
+
|
|
582
|
+
# These are the keys that need to match (or be None)
|
|
583
|
+
keys2_check = ["xlim", "ylim", "color_min", "color_max", "title"]
|
|
584
|
+
|
|
585
|
+
# Identify how many subplots there are.
|
|
586
|
+
# If there are more than one, just don't change anything.
|
|
587
|
+
# This assumes that if there are more than one,
|
|
588
|
+
# the plot_dicts are actually all compatible.
|
|
589
|
+
subplots = set()
|
|
590
|
+
for pd in self.plot_dicts:
|
|
591
|
+
if "subplot" in pd:
|
|
592
|
+
subplots.add(pd["subplot"])
|
|
593
|
+
|
|
594
|
+
# Now check subplots are consistent.
|
|
595
|
+
if len(subplots) <= 1:
|
|
596
|
+
reset_keys = []
|
|
597
|
+
for key in keys2_check:
|
|
598
|
+
values = [pd[key] for pd in self.plot_dicts if key in pd]
|
|
599
|
+
if len(np.unique(values)) > 1:
|
|
600
|
+
# We will reset some of the keys to the default,
|
|
601
|
+
# but for some we should do better.
|
|
602
|
+
if key.endswith("Max"):
|
|
603
|
+
for pd in self.plot_dicts:
|
|
604
|
+
pd[key] = np.max(values)
|
|
605
|
+
elif key.endswith("Min"):
|
|
606
|
+
for pd in self.plot_dicts:
|
|
607
|
+
pd[key] = np.min(values)
|
|
608
|
+
elif key == "title":
|
|
609
|
+
title = self._build_title()
|
|
610
|
+
for pd in self.plot_dicts:
|
|
611
|
+
pd["title"] = title
|
|
612
|
+
else:
|
|
613
|
+
warnings.warn(
|
|
614
|
+
'Found more than one value to be set for "%s" in the plot_dicts.' % (key)
|
|
615
|
+
+ " Will reset to default value. (found values %s)" % values
|
|
616
|
+
)
|
|
617
|
+
reset_keys.append(key)
|
|
618
|
+
# Reset the most of the keys to defaults;
|
|
619
|
+
# this can generally be done safely.
|
|
620
|
+
for key in reset_keys:
|
|
621
|
+
for pd in self.plot_dicts:
|
|
622
|
+
pd[key] = None
|
|
623
|
+
|
|
624
|
+
def plot(
|
|
625
|
+
self,
|
|
626
|
+
plot_func,
|
|
627
|
+
plot_dicts=None,
|
|
628
|
+
display_dict=None,
|
|
629
|
+
outfile_root=None,
|
|
630
|
+
outfile_suffix=None,
|
|
631
|
+
):
|
|
632
|
+
"""
|
|
633
|
+
Create a plot for the active metric bundles (self.set_metric_bundles).
|
|
634
|
+
|
|
635
|
+
Parameters
|
|
636
|
+
----------
|
|
637
|
+
plot_func : `rubin_sim.plots.BasePlotter`
|
|
638
|
+
The plotter to use to make the figure.
|
|
639
|
+
plot_dicts : `list` of [`dict`], optional
|
|
640
|
+
List of plot_dicts for each metric bundle.
|
|
641
|
+
Can use these to override individual metric bundle colors, etc.
|
|
642
|
+
display_dict : `dict`, optional
|
|
643
|
+
Information to save to resultsDb to accompany the figure on the
|
|
644
|
+
show_maf pages. Generally set automatically. Includes a caption.
|
|
645
|
+
outfile_root : `str`, optional
|
|
646
|
+
Output filename. Generally set automatically, but can be
|
|
647
|
+
overriden (such as when output filenames get too long).
|
|
648
|
+
outfile_suffix : `str`, optional
|
|
649
|
+
A suffix to add to the end of the default output filename.
|
|
650
|
+
Useful when creating a series of plots, such as for a movie.
|
|
651
|
+
|
|
652
|
+
Returns
|
|
653
|
+
-------
|
|
654
|
+
fig : `matplotlib.figure.Figure`
|
|
655
|
+
The plot.
|
|
656
|
+
"""
|
|
657
|
+
if not plot_func.object_plotter:
|
|
658
|
+
# Check that metric_values type and plotter are compatible
|
|
659
|
+
# (most are float/float, but some plotters expect object data ..
|
|
660
|
+
# and some only do sometimes).
|
|
661
|
+
for m_b in self.m_bundles:
|
|
662
|
+
if m_b.metric.metric_dtype == "object":
|
|
663
|
+
metric_is_color = m_b.plot_dict.get("metric_is_color", False)
|
|
664
|
+
if not metric_is_color:
|
|
665
|
+
warnings.warn("Cannot plot object metric values with this plotter.")
|
|
666
|
+
return
|
|
667
|
+
|
|
668
|
+
# Update x/y labels using plot_type.
|
|
669
|
+
self.set_plot_dicts(plot_dicts=plot_dicts, plot_func=plot_func, reset=False)
|
|
670
|
+
# Set outfile name.
|
|
671
|
+
if outfile_root is None:
|
|
672
|
+
outfile = self._build_file_root(outfile_suffix)
|
|
673
|
+
else:
|
|
674
|
+
outfile = outfile_root
|
|
675
|
+
plot_type = plot_func.plot_type
|
|
676
|
+
if len(self.m_bundles) > 1:
|
|
677
|
+
plot_type = "Combo" + plot_type
|
|
678
|
+
# Make plot.
|
|
679
|
+
fig = None
|
|
680
|
+
for m_b, plot_dict in zip(self.m_bundles, self.plot_dicts):
|
|
681
|
+
if m_b.metric_values is None:
|
|
682
|
+
# Skip this metricBundle.
|
|
683
|
+
msg = 'MetricBundle (%s) has no "metric_values".' % (m_b.file_root)
|
|
684
|
+
msg += " Either the values have not been calculated or they have been deleted."
|
|
685
|
+
warnings.warn(msg)
|
|
686
|
+
elif np.size(np.where(~m_b.metric_values.mask)) == 0:
|
|
687
|
+
msg = "MetricBundle (%s) has no unmasked metric_values, skipping plots." % (m_b.file_root)
|
|
688
|
+
warnings.warn(msg)
|
|
689
|
+
else:
|
|
690
|
+
fig = plot_func(m_b.metric_values, m_b.slicer, plot_dict, fig=fig)
|
|
691
|
+
# Add a legend if more than one metricValue is being plotted
|
|
692
|
+
# or if legendloc is specified.
|
|
693
|
+
legend_loc = None
|
|
694
|
+
if "legend_loc" in self.plot_dicts[0]:
|
|
695
|
+
legend_loc = self.plot_dicts[0]["legend_loc"]
|
|
696
|
+
if len(self.m_bundles) > 1:
|
|
697
|
+
try:
|
|
698
|
+
legend_loc = self.plot_dicts[0]["legend_loc"]
|
|
699
|
+
except KeyError:
|
|
700
|
+
legend_loc = "upper right"
|
|
701
|
+
if legend_loc is not None:
|
|
702
|
+
# Activate expected figure and write legend.
|
|
703
|
+
plt.figure(fig)
|
|
704
|
+
plt.legend(loc=legend_loc, fancybox=True, fontsize="smaller")
|
|
705
|
+
# Add the super title if provided.
|
|
706
|
+
if "suptitle" in self.plot_dicts[0]:
|
|
707
|
+
plt.suptitle(self.plot_dicts[0]["suptitle"])
|
|
708
|
+
# Save to disk and file info to results_db if desired.
|
|
709
|
+
if self.savefig:
|
|
710
|
+
if display_dict is None:
|
|
711
|
+
display_dict = self._build_display_dict()
|
|
712
|
+
self.save_fig(
|
|
713
|
+
fig,
|
|
714
|
+
outfile,
|
|
715
|
+
plot_type,
|
|
716
|
+
self.joint_metric_names,
|
|
717
|
+
self.slicer.slicer_name,
|
|
718
|
+
self.joint_run_names,
|
|
719
|
+
self.constraints,
|
|
720
|
+
self.joint_metadata,
|
|
721
|
+
display_dict,
|
|
722
|
+
)
|
|
723
|
+
return fig
|
|
724
|
+
|
|
725
|
+
def save_fig(
|
|
726
|
+
self,
|
|
727
|
+
fig,
|
|
728
|
+
outfile_root,
|
|
729
|
+
plot_type,
|
|
730
|
+
metric_name,
|
|
731
|
+
slicer_name,
|
|
732
|
+
run_name,
|
|
733
|
+
constraint,
|
|
734
|
+
info_label,
|
|
735
|
+
display_dict=None,
|
|
736
|
+
):
|
|
737
|
+
plot_file = outfile_root + "_" + plot_type + "." + self.fig_format
|
|
738
|
+
if fig is None:
|
|
739
|
+
warnings.warn(f"Trying to save figure to {plot_file} but" "figure is None. Skipping.")
|
|
740
|
+
return
|
|
741
|
+
if self.trim_whitespace:
|
|
742
|
+
fig.savefig(
|
|
743
|
+
os.path.join(self.out_dir, plot_file),
|
|
744
|
+
dpi=self.dpi,
|
|
745
|
+
bbox_inches="tight",
|
|
746
|
+
format=self.fig_format,
|
|
747
|
+
)
|
|
748
|
+
else:
|
|
749
|
+
fig.savefig(
|
|
750
|
+
os.path.join(self.out_dir, plot_file),
|
|
751
|
+
dpi=self.dpi,
|
|
752
|
+
format=self.fig_format,
|
|
753
|
+
)
|
|
754
|
+
# Generate a png thumbnail.
|
|
755
|
+
if self.thumbnail:
|
|
756
|
+
thumb_file = "thumb." + outfile_root + "_" + plot_type + ".png"
|
|
757
|
+
fig.savefig(os.path.join(self.out_dir, thumb_file), dpi=72, bbox_inches="tight")
|
|
758
|
+
# Save information about the file to results_db.
|
|
759
|
+
if self.results_db:
|
|
760
|
+
if display_dict is None:
|
|
761
|
+
display_dict = {}
|
|
762
|
+
metric_id = self.results_db.update_metric(
|
|
763
|
+
metric_name, slicer_name, run_name, constraint, info_label, None
|
|
764
|
+
)
|
|
765
|
+
self.results_db.update_display(metric_id=metric_id, display_dict=display_dict, overwrite=False)
|
|
766
|
+
self.results_db.update_plot(metric_id=metric_id, plot_type=plot_type, plot_file=plot_file)
|