From 3bc5b6b2b76a183ee689125967998e5021c49252 Mon Sep 17 00:00:00 2001 From: Nabil Freij Date: Wed, 11 Sep 2024 14:41:28 -0700 Subject: [PATCH 1/4] Reworked the entire docs --- .github/workflows/testing.yml | 10 +- .gitignore | 4 +- docs/CODE_OF_CONDUCT.rst | 50 - docs/Makefile | 9 + .../_static/css/admonition_color_contrast.css | 144 -- docs/_static/css/plasmapy.css | 186 --- ...mposite_image_full_disk_14February2015.png | Bin .../XRT_filter_wheels_Sun_View_Diagram.png | Bin docs/{ => _static}/images/XRTpy_logo.png | Bin .../hinode_satellite.png | Bin .../notebook_images/astropy_logo_notext.png | Bin 12730 -> 0 bytes docs/_substitutions.rst | 2 +- docs/about_xrt.rst | 68 +- .../acknowledging_xrtpy.rst | 29 +- .../xrtpy.image_correction.deconvolve.rst | 8 - docs/api_static/xrtpy.image_correction.rst | 8 - docs/api_static/xrtpy.response.channel.rst | 8 - docs/api_static/xrtpy.response.rst | 8 - ...response.temperature_from_filter_ratio.rst | 8 - .../xrtpy.response.temperature_response.rst | 8 - docs/api_static/xrtpy.rst | 8 - .../xrtpy.util.make_exposure_map.rst | 8 - docs/api_static/xrtpy.util.rst | 8 - docs/api_static/xrtpy.util.time.rst | 8 - docs/bibliography.rst | 6 +- docs/changelog/0.2.0.rst | 9 +- docs/changelog/0.3.0.rst | 8 +- docs/changelog/0.4.0.rst | 11 +- docs/changelog/dev.rst | 8 - docs/changelog/index.rst | 7 +- docs/code_of_conduct.rst | 51 + docs/conf.py | 381 +++--- docs/contributing.rst | 33 + docs/contributing/contributing.rst | 25 - docs/contributing/index.rst | 13 - .../installation_for_development.rst | 39 - docs/contributing/release_guide.rst | 7 - docs/examples.rst | 34 - docs/feedback_communication.rst | 31 +- docs/getting_started.rst | 99 +- docs/glossary.rst | 6 +- docs/images/XRTpy_logo copy.png | Bin 130131 -> 0 bytes docs/images/hinode_satellite.png | Bin 108399 -> 0 bytes docs/index.rst | 39 +- docs/install.rst | 240 ++-- docs/make.bat | 6 +- docs/nitpick-exceptions | 8 + .../computing_functions/effective_area.ipynb | 325 ----- .../temperature_response.ipynb | 384 ------ .../Deconvolving_XRT_images.ipynb | 120 -- .../data_analysis/Remove_lightleak.ipynb | 149 --- .../Temperature_using_composites.ipynb | 156 --- .../Using_temperature_from_filter_ratio.ipynb | 257 ---- ...to_Data_Extraction_and_Visualization.ipynb | 1176 ----------------- docs/notebooks/getting_started/channel.ipynb | 361 ----- docs/notebooks/getting_started/units.ipynb | 724 ---------- docs/reference/image_correction.rst | 6 + docs/reference/index.rst | 10 + docs/reference/response.rst | 6 + docs/reference/util.rst | 6 + docs/reference/xrtpy.rst | 5 + docs/response/index.html | 30 - examples/README.txt | 5 + examples/channels.py | 103 ++ examples/deconvolving.py | 45 + examples/effective_area.py | 75 ++ examples/remove_lightleak.py | 48 + examples/sorting_data.py | 85 ++ examples/temperature_from_filter_ratios.py | 70 + examples/temperature_response.py | 88 ++ pyproject.toml | 23 +- xrtpy/image_correction/__init__.py | 8 +- xrtpy/image_correction/deconvolve.py | 4 +- xrtpy/image_correction/remove_lightleak.py | 4 +- xrtpy/response/__init__.py | 6 +- xrtpy/response/channel.py | 22 +- xrtpy/response/effective_area.py | 41 +- .../response/temperature_from_filter_ratio.py | 4 +- xrtpy/util/__init__.py | 4 +- xrtpy/util/time.py | 6 +- 80 files changed, 1165 insertions(+), 4834 deletions(-) delete mode 100644 docs/CODE_OF_CONDUCT.rst delete mode 100644 docs/_static/css/admonition_color_contrast.css delete mode 100644 docs/_static/css/plasmapy.css rename docs/{ => _static}/images/XRT_composite_image_full_disk_14February2015.png (100%) rename docs/{ => _static}/images/XRT_filter_wheels_Sun_View_Diagram.png (100%) rename docs/{ => _static}/images/XRTpy_logo.png (100%) rename docs/_static/{notebook_images => images}/hinode_satellite.png (100%) delete mode 100644 docs/_static/notebook_images/astropy_logo_notext.png rename docs/{contributing => }/acknowledging_xrtpy.rst (64%) delete mode 100644 docs/api_static/xrtpy.image_correction.deconvolve.rst delete mode 100644 docs/api_static/xrtpy.image_correction.rst delete mode 100644 docs/api_static/xrtpy.response.channel.rst delete mode 100644 docs/api_static/xrtpy.response.rst delete mode 100644 docs/api_static/xrtpy.response.temperature_from_filter_ratio.rst delete mode 100644 docs/api_static/xrtpy.response.temperature_response.rst delete mode 100644 docs/api_static/xrtpy.rst delete mode 100644 docs/api_static/xrtpy.util.make_exposure_map.rst delete mode 100644 docs/api_static/xrtpy.util.rst delete mode 100644 docs/api_static/xrtpy.util.time.rst delete mode 100644 docs/changelog/dev.rst create mode 100644 docs/code_of_conduct.rst create mode 100644 docs/contributing.rst delete mode 100644 docs/contributing/contributing.rst delete mode 100644 docs/contributing/index.rst delete mode 100644 docs/contributing/installation_for_development.rst delete mode 100644 docs/contributing/release_guide.rst delete mode 100644 docs/examples.rst delete mode 100644 docs/images/XRTpy_logo copy.png delete mode 100644 docs/images/hinode_satellite.png create mode 100644 docs/nitpick-exceptions delete mode 100644 docs/notebooks/computing_functions/effective_area.ipynb delete mode 100644 docs/notebooks/computing_functions/temperature_response.ipynb delete mode 100644 docs/notebooks/data_analysis/Deconvolving_XRT_images.ipynb delete mode 100644 docs/notebooks/data_analysis/Remove_lightleak.ipynb delete mode 100644 docs/notebooks/data_analysis/Temperature_using_composites.ipynb delete mode 100644 docs/notebooks/data_analysis/Using_temperature_from_filter_ratio.ipynb delete mode 100644 docs/notebooks/getting_started/A_Practical_Guide_to_Data_Extraction_and_Visualization.ipynb delete mode 100644 docs/notebooks/getting_started/channel.ipynb delete mode 100644 docs/notebooks/getting_started/units.ipynb create mode 100644 docs/reference/image_correction.rst create mode 100644 docs/reference/index.rst create mode 100644 docs/reference/response.rst create mode 100644 docs/reference/util.rst create mode 100644 docs/reference/xrtpy.rst delete mode 100644 docs/response/index.html create mode 100644 examples/README.txt create mode 100644 examples/channels.py create mode 100644 examples/deconvolving.py create mode 100644 examples/effective_area.py create mode 100644 examples/remove_lightleak.py create mode 100644 examples/sorting_data.py create mode 100644 examples/temperature_from_filter_ratios.py create mode 100644 examples/temperature_response.py diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index cad2db30c..b69812608 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -92,7 +92,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v4 with: - python-version: '3.10' + python-version: '3.12' - name: Install nox run: python -m pip install --progress-bar off --upgrade nox @@ -100,13 +100,5 @@ jobs: - name: Install graphviz run: sudo apt install graphviz - - name: Install pandoc - run: | - PANDOC_VERSION="3.1.11.1" - wget -q https://github.com/jgm/pandoc/releases/download/${PANDOC_VERSION}/pandoc-${PANDOC_VERSION}-1-amd64.deb - sudo dpkg -i pandoc-${PANDOC_VERSION}-1-amd64.deb - rm pandoc-${PANDOC_VERSION}-1-amd64.deb - pandoc --version - - name: Build documentation run: nox -s build_docs_nitpicky -- -q diff --git a/.gitignore b/.gitignore index 649a8126c..ff1d418d0 100644 --- a/.gitignore +++ b/.gitignore @@ -69,7 +69,9 @@ instance/ .scrapy # Sphinx documentation -docs/_build/ +docs/generated +docs/sg_execution_times.rst +docs/_build docs/api # PyBuilder diff --git a/docs/CODE_OF_CONDUCT.rst b/docs/CODE_OF_CONDUCT.rst deleted file mode 100644 index 49621ee5c..000000000 --- a/docs/CODE_OF_CONDUCT.rst +++ /dev/null @@ -1,50 +0,0 @@ -.. currentmodule:: xrtpy - -.. _CODE_OF_CONDUCT: - -******************* -Code of Conduct -******************* - -XRTpy follows the Contributor Covenant Code of Conduct, which is a widely adopted standard for fostering an inclusive -and respectful community. Below are the key principles and standards that all contributors and community members are -expected to adhere to. - -Our Pledge -========== -We, as contributors and maintainers of XRTpy, pledge to make participation in our project and community a harassment-free -experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of -experience, education, socioeconomic status, nationality, personal appearance, race, religion, or sexual identity and -orientation. - -Respectful Communication -========================= -We expect all participants to communicate respectfully and constructively. This includes being polite, considerate, and welcoming, -while avoiding any form of harassment, discrimination, or offensive behavior. - -Diversity and Inclusion -========================= -XRTpy values diversity and is dedicated to creating an inclusive environment. We welcome contributions from people of all backgrounds, -regardless of gender, disability, ethnicity, religion, nationality, sexual orientation, or any other characteristic. - -Constructive Criticism -========================= -Feedback is essential for the growth and improvement of XRTpy. We encourage everyone to provide and receive feedback in a constructive manner. -Criticism should focus on improving the project and fostering learning, with an emphasis on what is best for the overall community. - -Conflict Resolution and Enforcement -===================================== -Conflicts may arise in any collaborative environment. Participants should engage respectfully and with an open mind. -If unresolved, project maintainers will mediate to ensure a fair resolution. Violations of this Code of Conduct will result -in appropriate consequences, including warnings, temporary bans, or permanent removal. Community leaders are responsible for -enforcing these rules and taking corrective action as needed. - -**Enforcement and Reporting** - -- Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at xrtpy@cfa.harvard.edu. All complaints will be reviewed and investigated promptly and fairly. -- Community leaders are obligated to respect the privacy and security of the reporter of any incident. - - -This Code of Conduct is adapted from the `Contributor Covenant`_, version 2.1. - -.. _Contributor Covenant : https://www.contributor-covenant.org/version/2/1/code_of_conduct.html diff --git a/docs/Makefile b/docs/Makefile index d4bb2cbb9..7fdc90e89 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -14,6 +14,15 @@ help: .PHONY: help Makefile +html-noplot: + @$(SPHINXBUILD) -D plot_gallery=0 -b html $(ALLSPHINXOPTS) $(SOURCEDIR) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +clean: + rm -rf $(BUILDDIR) + rm -rf ./generated + # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile diff --git a/docs/_static/css/admonition_color_contrast.css b/docs/_static/css/admonition_color_contrast.css deleted file mode 100644 index f91be52be..000000000 --- a/docs/_static/css/admonition_color_contrast.css +++ /dev/null @@ -1,144 +0,0 @@ -/* - The following sections were adapted from the file - sphinx_rtd_theme_ext_color_contrast/_static/sphinx_rtd_theme_ext_color_contrast.css - in the following repository: - https://github.com/AaltoSciComp/sphinx_rtd_theme_ext_color_contrast - The license is in our licenses directory. - - These customizations will be able to be removed if sphinx_rtd_theme - defaults end up getting changed to meet accessibility guidelines. -*/ - - -/* warning */ -.wy-alert.wy-alert-warning .wy-alert-title, -.rst-content .wy-alert-warning.note .wy-alert-title, -.rst-content .attention .wy-alert-title, -.rst-content .caution .wy-alert-title, -.rst-content .wy-alert-warning.danger .wy-alert-title, -.rst-content .wy-alert-warning.error .wy-alert-title, -.rst-content .wy-alert-warning.hint .wy-alert-title, -.rst-content .wy-alert-warning.important .wy-alert-title, -.rst-content .wy-alert-warning.tip .wy-alert-title, -.rst-content .warning .wy-alert-title, -.rst-content .wy-alert-warning.seealso .wy-alert-title, -.rst-content .admonition-todo .wy-alert-title, -.rst-content .wy-alert-warning.admonition .wy-alert-title, -.wy-alert.wy-alert-warning .rst-content .admonition-title, -.rst-content .wy-alert.wy-alert-warning .admonition-title, -.rst-content .wy-alert-warning.note .admonition-title, -.rst-content .attention .admonition-title, -.rst-content .caution .admonition-title, -.rst-content .wy-alert-warning.danger .admonition-title, -.rst-content .wy-alert-warning.error .admonition-title, -.rst-content .wy-alert-warning.hint .admonition-title, -.rst-content .wy-alert-warning.important .admonition-title, -.rst-content .wy-alert-warning.tip .admonition-title, -.rst-content .warning .admonition-title, .rst-content -.wy-alert-warning.seealso .admonition-title, -.rst-content .admonition-todo .admonition-title, -.rst-content .wy-alert-warning.admonition .admonition-title { - background: #B15E16; -} - -/* important */ - -.wy-alert.wy-alert-success .wy-alert-title, -.rst-content .wy-alert-success.note .wy-alert-title, -.rst-content .wy-alert-success.attention .wy-alert-title, -.rst-content .wy-alert-success.caution .wy-alert-title, -.rst-content .wy-alert-success.danger .wy-alert-title, -.rst-content .wy-alert-success.error .wy-alert-title, -.rst-content .hint .wy-alert-title, -.rst-content .important .wy-alert-title, -.rst-content .tip .wy-alert-title, -.rst-content .wy-alert-success.warning .wy-alert-title, -.rst-content .wy-alert-success.seealso .wy-alert-title, -.rst-content .wy-alert-success.admonition-todo .wy-alert-title, -.rst-content .wy-alert-success.admonition .wy-alert-title, -.wy-alert.wy-alert-success .rst-content .admonition-title, -.rst-content .wy-alert.wy-alert-success .admonition-title, -.rst-content .wy-alert-success.note .admonition-title, -.rst-content .wy-alert-success.attention .admonition-title, -.rst-content .wy-alert-success.caution .admonition-title, -.rst-content .wy-alert-success.danger .admonition-title, -.rst-content .wy-alert-success.error .admonition-title, -.rst-content .hint .admonition-title, -.rst-content .important .admonition-title, -.rst-content .tip .admonition-title, -.rst-content .wy-alert-success.warning .admonition-title, -.rst-content .wy-alert-success.seealso .admonition-title, -.rst-content .wy-alert-success.admonition-todo .admonition-title, -.rst-content .wy-alert-success.admonition .admonition-title { - background: #12826C; -} - -/* seealso, note, etc */ - -.wy-alert.wy-alert-info .wy-alert-title, -.rst-content .note .wy-alert-title, -.rst-content .wy-alert-info.attention .wy-alert-title, -.rst-content .wy-alert-info.caution .wy-alert-title, -.rst-content .wy-alert-info.danger .wy-alert-title, -.rst-content .wy-alert-info.error .wy-alert-title, -.rst-content .wy-alert-info.hint .wy-alert-title, -.rst-content .wy-alert-info.important .wy-alert-title, -.rst-content .wy-alert-info.tip .wy-alert-title, -.rst-content .wy-alert-info.warning .wy-alert-title, -.rst-content .seealso .wy-alert-title, -.rst-content .wy-alert-info.admonition-todo .wy-alert-title, -.rst-content .wy-alert-info.admonition .wy-alert-title, -.wy-alert.wy-alert-info .rst-content .admonition-title, -.rst-content .wy-alert.wy-alert-info .admonition-title, -.rst-content .note .admonition-title, -.rst-content .wy-alert-info.attention .admonition-title, -.rst-content .wy-alert-info.caution .admonition-title, -.rst-content .wy-alert-info.danger .admonition-title, -.rst-content .wy-alert-info.error .admonition-title, -.rst-content .wy-alert-info.hint .admonition-title, -.rst-content .wy-alert-info.important .admonition-title, -.rst-content .wy-alert-info.tip .admonition-title, -.rst-content .wy-alert-info.warning .admonition-title, -.rst-content .seealso .admonition-title, -.rst-content .wy-alert-info.admonition-todo .admonition-title, -.rst-content .wy-alert-info.admonition .admonition-title { - background: #277CB4; -} - -/* error, danger */ - -.rst-content .danger .admonition-title, -.rst-content .danger .wy-alert-title, -.rst-content .error .admonition-title, -.rst-content .error .wy-alert-title, -.rst-content .wy-alert-danger.admonition-todo .admonition-title, -.rst-content .wy-alert-danger.admonition-todo .wy-alert-title, -.rst-content .wy-alert-danger.admonition .admonition-title, -.rst-content .wy-alert-danger.admonition .wy-alert-title, -.rst-content .wy-alert-danger.attention .admonition-title, -.rst-content .wy-alert-danger.attention .wy-alert-title, -.rst-content .wy-alert-danger.caution .admonition-title, -.rst-content .wy-alert-danger.caution .wy-alert-title, -.rst-content .wy-alert-danger.hint .admonition-title, -.rst-content .wy-alert-danger.hint .wy-alert-title, -.rst-content .wy-alert-danger.important .admonition-title, -.rst-content .wy-alert-danger.important .wy-alert-title, -.rst-content .wy-alert-danger.note .admonition-title, -.rst-content .wy-alert-danger.note .wy-alert-title, -.rst-content .wy-alert-danger.seealso .admonition-title, -.rst-content .wy-alert-danger.seealso .wy-alert-title, -.rst-content .wy-alert-danger.tip .admonition-title, -.rst-content .wy-alert-danger.tip .wy-alert-title, -.rst-content .wy-alert-danger.warning .admonition-title, -.rst-content .wy-alert-danger.warning .wy-alert-title, -.rst-content .wy-alert.wy-alert-danger .admonition-title, -.wy-alert.wy-alert-danger .rst-content .admonition-title, -.wy-alert.wy-alert-danger .wy-alert-title { - background: #e31704; -} - -/* Generic admonition titles */ - -.wy-alert-title, .rst-content .admonition-title { - background: #277CB4; -} diff --git a/docs/_static/css/plasmapy.css b/docs/_static/css/plasmapy.css deleted file mode 100644 index b59e85f70..000000000 --- a/docs/_static/css/plasmapy.css +++ /dev/null @@ -1,186 +0,0 @@ -/* - This file contains styles rules for PlasmaPy's documentation, which - includes new rules as well as rules that override styles from the - Sphinx Read the Docs theme (sphinx_rtd_theme). - - The CSS style rule syntax is: - - selectors-list { - properties-list - } - - The code in selectors-list selects the patterns for the elements to be - styled. The code in properties-list sets the style of these elements. - The CSS rule to be applied is generally the one that has the most - specific selectors. - - For more information on CSS, go to: https://www.w3schools.com/css - - Most web browsers have inspection tools that help with adding new CSS - rules. Right-click or ctrl-click on an element of a website, and - choose "inspect" to see the HTML code along with CSS selectors and - properties. - - When creating a new rule, use increased specificity instead of - !important when possible. Using !important can make debugging more - difficult. Use relative units like rem (root font size) to help with - accessibility and scaling. Please add descriptive comments for new - rules that are understandable to someone who is unfamiliar with CSS. - - CSS files can be validated at: https://jigsaw.w3.org/css-validator -*/ - -/* ----------------------------------------------------------------------------- - * RTD Overrides - */ - -/* Style for toctree in a table */ -td .toctree-wrapper ul { - font-size: 16px; - line-height: 18px !important; - list-style: none !important; - margin-bottom: 0 !important; -} - -td .toctree-wrapper ul li { - list-style: none !important; - margin-left: 0 !important; -} - -/* Unordered list nested in ordered list */ -.section li ul { - margin-bottom: 12px !important; -} - -/* Add margin-bottom to inheritance diagrams */ -div.graphviz { - margin-bottom: 24px !important; -} - -/* - * Remove bottom margin for the autosummary table in a directive:option:: - * section - */ -.rst-content dl.rst table p, -.rst-content dl.std table p, -.rst-content dl.py table p { - margin-bottom: 0 !important; -} - -/* Remove excess bottom margin for table headings */ -.rst-content table.docutils thead p { - margin-bottom: 0; -} - -/* Remove excess bottom margin for for multiline table entries when using line-block */ -.rst-content table.docutils div.line-block { - margin-bottom: 0; -} - -/* Allow text wrapping for last column of a table. */ -.rst-content table.docutils td:last-child p { - white-space: normal; - line-height: 140%; -} - -/* Reduce top/bottom margin for equations in tables */ -table div.MathJax_Display { - margin: 0.5em 0; -} - -/* - * Adjustments to the Glossary styling - */ -dl.glossary dd ul { - margin-bottom: 12px !important; -} -dl.glossary dd { - margin-top: 4px; - margin-bottom: 18px; -} -dl.glossary dt { - margin-bottom: 2px; -} - -/* Styles for text in the footer chosen to improve contrast. */ - -footer p { - color: #141414; -} - -/* - Styles for hyperlinks. The colors must meet the WCAG AA standard - for contrast. Link colors can be tested for accessibility at: - https://webaim.org/resources/linkcontrastchecker -*/ - -div.wy-nav-content a:link { - color: #0069d6; -} -div.wy-nav-content a:visited { - color: #9151b6; -} -div.wy-nav-content a:hover { - text-decoration:underline; -} - -/* - The style for generic code literals, in particular text that is - enclosed in double back ticks in reST (e.g., ``make -j 32``). -*/ - -div.wy-nav-content .rst-content code.literal { - background-color: #f6f6f6; - color: #db2424; -} - -/* - The style for links to Python objects, in particular text enclosed in - single back ticks in reST (e.g., `~plasmapy.particles`). -*/ - -div.wy-nav-content .rst-content code.literal.xref { - color: #0069d6; - font-weight: bold; -} - -/* - The style for literal text that shows the location of a file, in - particular when used by the reST role :file: (e.g., - :file:`docs/_static/css/plasmapy.css`). -*/ -div.wy-nav-content .rst-content code.literal.file { - color: #b84d00; - background-color: #F9F1F0; -} - -/* ----------------------------------------------------------------------------- - * RTD layout styling additions - */ - -/* Style for module/index links in sidebar below the search field. */ -div.pkgnav { - color: white; - font-size: 1em; - margin-top: 12px; - text-align: center; -} - -div.pkgnav ul { - list-style: none; -} - -div.pkgnav ul li { - display: inline; -} - -div.pkgnav ul li a { - color: #f9f9f0; - margin: 0; - text-shadow: 0 0 1px rgba(0, 0, 0, 0.5); -} - -div.pkgnav ul li a:hover { - color: #f50404; - text-shadow: 0 0 1px rgba(255, 255, 255, 0.5); -} diff --git a/docs/images/XRT_composite_image_full_disk_14February2015.png b/docs/_static/images/XRT_composite_image_full_disk_14February2015.png similarity index 100% rename from docs/images/XRT_composite_image_full_disk_14February2015.png rename to docs/_static/images/XRT_composite_image_full_disk_14February2015.png diff --git a/docs/images/XRT_filter_wheels_Sun_View_Diagram.png b/docs/_static/images/XRT_filter_wheels_Sun_View_Diagram.png similarity index 100% rename from docs/images/XRT_filter_wheels_Sun_View_Diagram.png rename to docs/_static/images/XRT_filter_wheels_Sun_View_Diagram.png diff --git a/docs/images/XRTpy_logo.png b/docs/_static/images/XRTpy_logo.png similarity index 100% rename from docs/images/XRTpy_logo.png rename to docs/_static/images/XRTpy_logo.png diff --git a/docs/_static/notebook_images/hinode_satellite.png b/docs/_static/images/hinode_satellite.png similarity index 100% rename from docs/_static/notebook_images/hinode_satellite.png rename to docs/_static/images/hinode_satellite.png diff --git a/docs/_static/notebook_images/astropy_logo_notext.png b/docs/_static/notebook_images/astropy_logo_notext.png deleted file mode 100644 index bcff0ed69dfd4de115cf4ba8e2c17c4dfb03bb7f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12730 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 diff --git a/docs/_substitutions.rst b/docs/_substitutions.rst index bd3f806bd..c866378c7 100644 --- a/docs/_substitutions.rst +++ b/docs/_substitutions.rst @@ -1,4 +1,4 @@ -.. |bibliography| replace:: :ref:`bibliography`\ +.. |bibliography| replace:: :ref:`xrtpy-bibliography`\ .. |Channel| replace:: :class:`~xrtpy.response.channel.Channel` .. |EffectiveAreaFundamental| replace:: :class:`~xrtpy.response.effective_area.EffectiveAreaFundamental` .. |glossary| replace:: :ref:`glossary`\ diff --git a/docs/about_xrt.rst b/docs/about_xrt.rst index d6cbee4c4..5ac7716ee 100644 --- a/docs/about_xrt.rst +++ b/docs/about_xrt.rst @@ -1,57 +1,55 @@ -.. _about-xrt: +.. _xrtpy-about-xrt: -.. image:: images/hinode_satellite.png - :alt: Hinode Satellite - :align: right - :scale: 64% - - -******************************* -About the X-Ray Telescope (XRT) -******************************* - -.. contents:: Contents - :local: +********* +About XRT +********* Hinode ====== -Hinode is a joint mission involving the space agencies of Japan, the United States, Europe, and the United Kingdom. It is depicted in the *illustration shown above*. + +.. image:: _static/images/hinode_satellite.png + :alt: Hinode Satellite + :align: center + +Hinode is a joint mission involving the space agencies of Japan, the United States, Europe, and the United Kingdom. +It is depicted in the *illustration shown above*. The spacecraft is equipped with three instruments: the Solar Optical Telescope (SOT), the Extreme Ultraviolet Imaging Spectrometer (EIS), and the X-Ray Telescope (XRT). -These instruments are designed to provide multi-wavelength data from the photosphere to the upper corona. The solar spacecraft spacecraft was launched at 6:36 a.m on -September 23, 2006 (Japan Standard Time) and placed into a polar, sun-synchronous orbit, enabling continuous observations of the Sun. For further information, visit `NASA's Hinode space mission to the Sun`_. +These instruments are designed to provide multi-wavelength data from the photosphere to the upper corona. +The solar spacecraft spacecraft was launched at 6:36 a.m on September 23, 2006 (Japan Standard Time) and placed into a polar, sun-synchronous orbit, enabling continuous observations of the Sun. +For further information, visit `NASA's Hinode space mission to the Sun`_. The X-Ray Telescope -==================== -The X-Ray Telescope (XRT), depicted as a long linear black tube on the Hinode spacecraft (illustration at the top of the page), is a crucial instrument for observing the solar corona's most intense regions, with temperatures ranging from 1,000,000 to 10,000,000 Kelvin. -The image below is a synoptic composite from February 14, 2015, created using the Al-Mesh/Be-Thin/Al-Med filters. -This method combines images taken with different filters, each set to a distinct color in the RGB color model to highlight various thermal conditions within the corona. -For a comprehensive overview of XRT's mission and capabilities, please visit the official xrt-cfa-harvard_ website. +=================== -.. image:: images/XRT_composite_image_full_disk_14February2015.png +.. image:: _static/images/XRT_composite_image_full_disk_14February2015.png :alt: XRT Composite Image :align: center - :scale: 40% + :scale: 50% + +The X-Ray Telescope (XRT), depicted as a long linear black tube on the Hinode spacecraft is a crucial instrument for observing the solar corona's most intense regions, with temperatures ranging from 1,000,000 to 10,000,000 Kelvin. +The image below is a synoptic composite from February 14, 2015, created using the Al-Mesh/Be-Thin/Al-Med filters. +This method combines images taken with different filters, each set to a distinct color in the RGB color model to highlight various thermal conditions within the corona. +For a comprehensive overview of XRT's mission and capabilities, please visit the official xrt-cfa-harvard_ website. + +.. tip:: + + Visit the `XRT Picture of the Week`_ and the `Hinode-XRT YouTube`_ page for captivating visual content showcasing the XRT's solar observations. SolarSoft XRT Analysis Guide ============================ + The `SolarSoft XRT Analysis Guide`_ is a comprehensive resource for analysis of XRT data. -It includes both an Instrument Guide and an overview of the X-Ray telescope's hardware components. -The XRT software was originally created in Interactive Data Language (IDL). -IDL is a software programming language used to analyze and create meaningful information from numerical data. +It includes both an instrument guide and an overview of the x-ray telescope's hardware components. +The XRT software was originally created in the Interactive Data Language (IDL). .. note:: + Please note that the `SolarSoft XRT Analysis Guide`_ does not serve as a guide for using XRTpy. It focuses solely on the analysis of XRT data using the IDL software. -.. tip:: - Visit the `XRT Picture of the Week`_ and the `Hinode-XRT YouTube`_ page for captivating visual content showcasing the XRT's solar observations. - -.. _NASA's Hinode space mission to the Sun: https://www.nasa.gov/mission_pages/hinode/mission.html +.. _Hinode-XRT YouTube: https://www.youtube.com/user/xrtpow .. _Interactive Data Language: https://www.l3harrisgeospatial.com/Software-Technology/IDL - +.. _NASA's Hinode space mission to the Sun: https://www.nasa.gov/mission_pages/hinode/mission.html .. _SolarSoft XRT Analysis Guide: https://xrt.cfa.harvard.edu/resources/documents/XAG/XAG.pdf -.. _xrt-cfa-harvard: https://xrt.cfa.harvard.edu/index.php -.. _Artist's concept of the Hinode: https://www.nasa.gov/mission_pages/sunearth/missions/mission-hinode.html - -.. _Hinode-XRT YouTube: https://www.youtube.com/user/xrtpow .. _XRT Picture of the Week: https://xrt.cfa.harvard.edu/xpow +.. _xrt-cfa-harvard: https://xrt.cfa.harvard.edu/index.php diff --git a/docs/contributing/acknowledging_xrtpy.rst b/docs/acknowledging_xrtpy.rst similarity index 64% rename from docs/contributing/acknowledging_xrtpy.rst rename to docs/acknowledging_xrtpy.rst index 3b371b075..1cda32683 100644 --- a/docs/contributing/acknowledging_xrtpy.rst +++ b/docs/acknowledging_xrtpy.rst @@ -1,30 +1,33 @@ -.. _citation_guide: +.. _xrtpy-citation: -=============================================== -Citing XRTpy in Publications and Presentations -=============================================== +************ +Citing XRTpy +************ - -If XRTpy has been useful in your research, we encourage you to consider including a citation or acknowledgment in your work. Below are suggested formats to credit XRTpy in your scientific papers, posters, or presentations. While this is not required, it is greatly appreciated. - -Suggested Citations -=================== +If XRTpy has been useful in your research, we encourage you to consider including a citation or acknowledgment in your work. +Below are suggested formats to credit XRTpy in your scientific papers, posters, or presentations. +While this is not required, it is greatly appreciated. For a scientific paper ----------------------- +====================== + You may use the following format to cite XRTpy in your publications: +.. code-block:: text + "We acknowledge the use of XRTpy (v0.4.1) for Hinode X-Ray Telescope data analysis, available at https://xrtpy.readthedocs.io/ (Velasquez et al. 2024, JOSS, DOI: 10.21105/joss.06396)." For a poster or presentation ----------------------------- +============================ + If you are presenting work that involves XRTpy in a poster or presentation, you may use the following acknowledgment: +.. code-block:: text + "This work made use of XRTpy (v0.4.1), a Python package for solar Hinode X-Ray Telescope data analysis, available at https://xrtpy.readthedocs.io/ (Velasquez et al. 2024, JOSS, DOI: 10.21105/joss.06396)." References ========== -Velasquez, J., Murphy, N., Reeves, K. K., Slavin, J., Weber, M., & Barnes, W. (2024). XRTpy: A Hinode-X-Ray Telescope Python Package. The Journal of Open Source Software, 9(100), 6396. https://doi.org/10.21105/joss.06396 -.. _joss_citation: https://doi.org/10.21105/joss.06396 +Velasquez, J., Murphy, N., Reeves, K. K., Slavin, J., Weber, M., & Barnes, W. (2024). XRTpy: A Hinode-X-Ray Telescope Python Package. The Journal of Open Source Software, 9(100), 6396. https://doi.org/10.21105/joss.06396 diff --git a/docs/api_static/xrtpy.image_correction.deconvolve.rst b/docs/api_static/xrtpy.image_correction.deconvolve.rst deleted file mode 100644 index 5f874e05b..000000000 --- a/docs/api_static/xrtpy.image_correction.deconvolve.rst +++ /dev/null @@ -1,8 +0,0 @@ -:orphan: - -`xrtpy.image_correction.deconvolve` -=================================== - -.. currentmodule:: xrtpy.image_correction.deconvolve - -.. automodapi:: xrtpy.image_correction.deconvolve diff --git a/docs/api_static/xrtpy.image_correction.rst b/docs/api_static/xrtpy.image_correction.rst deleted file mode 100644 index 3b136affa..000000000 --- a/docs/api_static/xrtpy.image_correction.rst +++ /dev/null @@ -1,8 +0,0 @@ -:orphan: - -`xrtpy.image_correction` -======================== - -.. currentmodule:: xrtpy.image_correction - -.. automodapi:: xrtpy.image_correction diff --git a/docs/api_static/xrtpy.response.channel.rst b/docs/api_static/xrtpy.response.channel.rst deleted file mode 100644 index be53692bd..000000000 --- a/docs/api_static/xrtpy.response.channel.rst +++ /dev/null @@ -1,8 +0,0 @@ -:orphan: - -`xrtpy.response.channel` -======================== - -.. currentmodule:: xrtpy.response.channel - -.. automodapi:: xrtpy.response.channel diff --git a/docs/api_static/xrtpy.response.rst b/docs/api_static/xrtpy.response.rst deleted file mode 100644 index 80adc6faa..000000000 --- a/docs/api_static/xrtpy.response.rst +++ /dev/null @@ -1,8 +0,0 @@ -:orphan: - -`xrtpy.response` -================ - -.. currentmodule:: xrtpy.response - -.. automodapi:: xrtpy.response diff --git a/docs/api_static/xrtpy.response.temperature_from_filter_ratio.rst b/docs/api_static/xrtpy.response.temperature_from_filter_ratio.rst deleted file mode 100644 index a4bf0d0b6..000000000 --- a/docs/api_static/xrtpy.response.temperature_from_filter_ratio.rst +++ /dev/null @@ -1,8 +0,0 @@ -:orphan: - -`xrtpy.response.temperature_from_filter_ratio` -============================================== - -.. currentmodule:: xrtpy.response.temperature_from_filter_ratio - -.. automodapi:: xrtpy.response.temperature_from_filter_ratio diff --git a/docs/api_static/xrtpy.response.temperature_response.rst b/docs/api_static/xrtpy.response.temperature_response.rst deleted file mode 100644 index 4da3ad44c..000000000 --- a/docs/api_static/xrtpy.response.temperature_response.rst +++ /dev/null @@ -1,8 +0,0 @@ -:orphan: - -`xrtpy.response.temperature_response` -===================================== - -.. currentmodule:: xrtpy.response.temperature_response - -.. automodapi:: xrtpy.response.temperature_response diff --git a/docs/api_static/xrtpy.rst b/docs/api_static/xrtpy.rst deleted file mode 100644 index 91fb98a50..000000000 --- a/docs/api_static/xrtpy.rst +++ /dev/null @@ -1,8 +0,0 @@ -:orphan: - -`xrtpy` -======= - -.. currentmodule:: xrtpy - -.. automodapi:: xrtpy diff --git a/docs/api_static/xrtpy.util.make_exposure_map.rst b/docs/api_static/xrtpy.util.make_exposure_map.rst deleted file mode 100644 index 804ac0d2e..000000000 --- a/docs/api_static/xrtpy.util.make_exposure_map.rst +++ /dev/null @@ -1,8 +0,0 @@ -:orphan: - -`xrtpy.util.make_exposure_map` -============================== - -.. currentmodule:: xrtpy.util.make_exposure_map - -.. automodapi:: xrtpy.util.make_exposure_map diff --git a/docs/api_static/xrtpy.util.rst b/docs/api_static/xrtpy.util.rst deleted file mode 100644 index 9ad5963ee..000000000 --- a/docs/api_static/xrtpy.util.rst +++ /dev/null @@ -1,8 +0,0 @@ -:orphan: - -`xrtpy.util` -============ - -.. currentmodule:: xrtpy.util - -.. automodapi:: xrtpy.util diff --git a/docs/api_static/xrtpy.util.time.rst b/docs/api_static/xrtpy.util.time.rst deleted file mode 100644 index 31fa124b0..000000000 --- a/docs/api_static/xrtpy.util.time.rst +++ /dev/null @@ -1,8 +0,0 @@ -:orphan: - -`xrtpy.util.time` -================= - -.. currentmodule:: xrtpy.util.time - -.. automodapi:: xrtpy.util.time diff --git a/docs/bibliography.rst b/docs/bibliography.rst index 54b204ac0..f42008333 100644 --- a/docs/bibliography.rst +++ b/docs/bibliography.rst @@ -1,10 +1,10 @@ -.. _bibliography: +.. _xrtpy-bibliography: ############ Bibliography ############ -.. The bibliography is built from references contained within - bibliography.bib. Add new references to bibliography.bib. +.. The bibliography is built from references contained within bibliography.bib. + Add new references to bibliography.bib. .. bibliography:: diff --git a/docs/changelog/0.2.0.rst b/docs/changelog/0.2.0.rst index ea15cb3ca..93f888f2f 100644 --- a/docs/changelog/0.2.0.rst +++ b/docs/changelog/0.2.0.rst @@ -4,20 +4,17 @@ XRTpy v0.2.0 (2023-03-16) Deprecations and Removals ------------------------- -- Fixed time handling in contamination calculations using ``astropy.time``. - (:pr:`104`) +- Fixed time handling in contamination calculations using ``astropy.time``. (:pr:`104`) Features -------- -- Added routine ``xrt_teem`` to derive temperatures and emission - measures from pairs of images using the filter ratio method. (:pr:`89`) +- Added routine ``xrt_teem`` to derive temperatures and emission measures from pairs of images using the filter ratio method. (:pr:`89`) Bug Fixes --------- -- Addressed and fixed the temperature response ``nan`` calculations output. - (:pr:`111`) +- Addressed and fixed the temperature response ``nan`` calculations output. (:pr:`111`) Improved Documentation ---------------------- diff --git a/docs/changelog/0.3.0.rst b/docs/changelog/0.3.0.rst index e8f12e61c..efce6835d 100644 --- a/docs/changelog/0.3.0.rst +++ b/docs/changelog/0.3.0.rst @@ -4,18 +4,18 @@ XRTpy v0.3.0 (2023-03-31) Deprecations and Removals ------------------------- -- Modified `~xrtpy.response.xrt_teem.xrt_teem` to return a `~collections.namedtuple` of SunPy maps. (:pr:`148`) +- Modified ``xrtpy.response.xrt_teem.xrt_teem`` to return a `~collections.namedtuple` of SunPy maps. (:pr:`148`) Features -------- -- New routine `~xrtpy.util.xrt_deconvolve.xrt_deconvolve`, uses the Hinode XRT point spread function and the Richardson-Lucy algorithm to deconvolve (sharpen) an XRT image. (:pr:`145`) -- New functionality, `~xrtpy.util.xrt_remove_lightleak.xrt_remove_lightleak` for subtracting light leak (visible stray light) image from XRT synoptic composite images. (:pr:`151`) +- New routine ``xrtpy.util.xrt_deconvolve.xrt_deconvolve``, uses the Hinode XRT point spread function and the Richardson-Lucy algorithm to deconvolve (sharpen) an XRT image. (:pr:`145`) +- New functionality, ``xrtpy.util.xrt_remove_lightleak.xrt_remove_lightleak`` for subtracting light leak (visible stray light) image from XRT synoptic composite images. (:pr:`151`) Improved Documentation ---------------------- - Updated Python requirements for packages used in XRTpy. (:pr:`139,137`) - Redeveloped the XRTpy GitHub issue templates. (:pr:`154`) -- Updated the bibliography and `~xrtpy.response.xrt_teem.xrt_teem` example notebook. (:pr:`158`) +- Updated the bibliography and ``xrtpy.response.xrt_teem.xrt_teem`` example notebook. (:pr:`158`) - Updated the XRT contamination data file, which is now up-to-date through 2023-05-20. (:pr:`160`) diff --git a/docs/changelog/0.4.0.rst b/docs/changelog/0.4.0.rst index e148a409a..28c5c5bd5 100644 --- a/docs/changelog/0.4.0.rst +++ b/docs/changelog/0.4.0.rst @@ -3,17 +3,22 @@ XRTpy v0.4.0 (2023-10-10) Deprecations and Removals ------------------------- + - Remove the light-leak files from the repository in favor of pulling them from one of two possible SolarSoft mirrors with the goal of reducing the total repository size. (:pr:`178,180`) Documentation ------------- + - Updated Python example notebooks to ensure a user-friendly and accessible experience. (:pr:`164`) - Revised and improved all text/documentation sections of XRTpy to ensure accuracy, clarity, and completeness. (:pr:`165`) Internal modifications and improvements --------------------------------------- -- Modified `~xrtpy.response.xrt_deconvolve` to use the Sunpy data manager to download the data files. (:pr:`172`) + +- Modified ``xrtpy.response.xrt_deconvolve`` to use the Sunpy data manager to download the data files. (:pr:`172`) - Updated the Read the Docs configuration file. (:pr:`173`) - Removed psf files after a new improvement in downloading them as part of the XRTpy package. (:pr:`177`) -- Updated the `xrt_contam_on_ccd.geny` file with new CCD contamination values. (:pr:`191`) -- Moved `xrt_deconvolve` and `xrt_remove_lightleak` from the `util` directory to a new directory named `image_correction`, and removed the `xrt_` prefix from their names. Renamed `xrt_teem` to `temperature_from_filter_ratio`. Updated all tests and notebooks to reflect the name and directory changes. (:pr:`196`) +- Updated the ``xrt_contam_on_ccd.geny`` file with new CCD contamination values. (:pr:`191`) +- Moved ``xrt_deconvolve`` and ``xrt_remove_lightleak`` from the ``util`` directory to a new directory named ``image_correction``, and removed the ``xrt_`` prefix from their names. + Renamed ``xrt_teem`` to ``temperature_from_filter_ratio``. + Updated all tests and notebooks to reflect the name and directory changes. (:pr:`196`) diff --git a/docs/changelog/dev.rst b/docs/changelog/dev.rst deleted file mode 100644 index a7648c71f..000000000 --- a/docs/changelog/dev.rst +++ /dev/null @@ -1,8 +0,0 @@ -:orphan: - -================== -Unreleased changes -================== - -.. changelog:: - :towncrier: ../../ diff --git a/docs/changelog/index.rst b/docs/changelog/index.rst index 2b1bf0e2d..e9889186a 100644 --- a/docs/changelog/index.rst +++ b/docs/changelog/index.rst @@ -1,17 +1,14 @@ -.. _changelog: +.. _xrtpy-changelog: ######### Changelog ######### -This document lists the changes made during each release of XRTpy, -including bug fixes and changes to the application programming interface -(API). +This document lists the changes made during each release of XRTpy, including bug fixes and changes to the application programming interface (API). .. toctree:: :maxdepth: 1 - dev 0.4.0 0.3.0 0.2.0 diff --git a/docs/code_of_conduct.rst b/docs/code_of_conduct.rst new file mode 100644 index 000000000..81e1fde1a --- /dev/null +++ b/docs/code_of_conduct.rst @@ -0,0 +1,51 @@ +.. _xrtpy-coc: + +*************** +Code of Conduct +*************** + +XRTpy follows the Contributor Covenant Code of Conduct, which is a widely adopted standard for fostering an inclusive and respectful community. +Below are the key principles and standards that all contributors and community members are expected to adhere to. + +Our Pledge +========== + +We, as contributors and maintainers of XRTpy, pledge to make participation in our project and community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, education, socioeconomic status, nationality, personal appearance, race, religion, or sexual identity and orientation. + +Respectful Communication +======================== + +We expect all participants to communicate respectfully and constructively. +This includes being polite, considerate, and welcoming, while avoiding any form of harassment, discrimination, or offensive behavior. + +Diversity and Inclusion +======================= + +XRTpy values diversity and is dedicated to creating an inclusive environment. +We welcome contributions from people of all backgrounds, regardless of gender, disability, ethnicity, religion, nationality, sexual orientation, or any other characteristic. + +Constructive Criticism +====================== + +Feedback is essential for the growth and improvement of XRTpy. +We encourage everyone to provide and receive feedback in a constructive manner. +Criticism should focus on improving the project and fostering learning, with an emphasis on what is best for the overall community. + +Conflict Resolution and Enforcement +=================================== + +Conflicts may arise in any collaborative environment. +Participants should engage respectfully and with an open mind. +If unresolved, project maintainers will mediate to ensure a fair resolution. +Violations of this Code of Conduct will result in appropriate consequences, including warnings, temporary bans, or permanent removal. +Community leaders are responsible for enforcing these rules and taking corrective action as needed. + +**Enforcement and Reporting** + +- Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at ``xrtpy@cfa.harvard.edu``. + All complaints will be reviewed and investigated promptly and fairly. +- Community leaders are obligated to respect the privacy and security of the reporter of any incident. + +This Code of Conduct is adapted from the `Contributor Covenant`_, version 2.1. + +.. _Contributor Covenant : https://www.contributor-covenant.org/version/2/1/code_of_conduct.html diff --git a/docs/conf.py b/docs/conf.py index a436e6593..6bdd721d5 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,175 +1,220 @@ -# Configuration file for the Sphinx documentation builder. -# -# This file does only contain a selection of the most common options. For a -# full list see the documentation: -# http://www.sphinx-doc.org/en/master/config +""" +Configuration file for the Sphinx documentation builder. +""" +# -- stdlib imports ------------------------------------------------------------ import os -from datetime import datetime - -from sphinx.application import Sphinx - -# -- Project information ----------------------------------------------------- - +import warnings +from datetime import UTC, datetime +from pathlib import Path + +from packaging.version import Version + +# -- Read the Docs Specific Configuration -------------------------------------- +# This needs to be done before xrtpy is imported +on_rtd = os.environ.get("READTHEDOCS", None) == "True" +if on_rtd: + os.environ["SUNPY_CONFIGDIR"] = "/home/docs/" + os.environ["HOME"] = "/home/docs/" + os.environ["LANG"] = "C" + os.environ["LC_ALL"] = "C" + os.environ["PARFIVE_HIDE_PROGRESS"] = "True" + +# -- Imports ------------------------------------------------------------------- +from astropy.utils.exceptions import AstropyDeprecationWarning # NOQA: E402 +from matplotlib import MatplotlibDeprecationWarning # NOQA: E402 +from sunpy.util.exceptions import ( # NOQA: E402 + SunpyDeprecationWarning, + SunpyPendingDeprecationWarning, +) + +# -- Project information ------------------------------------------------------- project = "xrtpy" author = "Joy Velasquez, Nick Murphy, and Jonathan Slavin" -copyright = f"2021–{datetime.utcnow().year}, {author}" +copyright = f"2021-{datetime.now(tz=UTC).year}, {author}" # The full version, including alpha/beta/rc tags -# from xrtpy import __version__ -# release = __version__ +from xrtpy import __version__ # NOQA: E402 + +_version_ = Version(__version__) +# NOTE: Avoid "post" appearing in version string in rendered docs +if _version_.is_postrelease: + version = release = f"{_version_.major}.{_version_.minor}.{_version_.micro}" +else: + version = release = str(_version_) +is_development = _version_.is_devrelease +# -- General configuration --------------------------------------------------- -release = "0.4.0" +# We want to make sure all the following warnings fail the build +warnings.filterwarnings("error", category=SunpyDeprecationWarning) +warnings.filterwarnings("error", category=SunpyPendingDeprecationWarning) +warnings.filterwarnings("error", category=MatplotlibDeprecationWarning) +warnings.filterwarnings("error", category=AstropyDeprecationWarning) -# -- General configuration --------------------------------------------------- +# For the linkcheck +linkcheck_allowed_redirects = { + r"https://doi\.org/.+": r"https://.+", # DOI links are more persistent + r"https://docs.+\.org": r"https://docs.+\.org/en/.+", + r"https://docs.+\.io": r"https://docs.+\.io/en/.+", + r"https://docs.+\.com": r"https://docs.+\.com/en/.+", + r"https://docs.+\.dev": r"https://docs.+\.dev/en/.+", + r"https://.+\.readthedocs\.io": r"https://.+\.readthedocs\.io/en/.+", + r"https://.+/github\.io": r"https://.+/github\.io/en/.+", + r"https://pip\.pypa\.io": r"https://pip\.pypa\.io/en/.+", + r"https://www.python.org/dev/peps/pep.+": "https://peps.python.org/pep.+", +} +linkcheck_anchors = True +linkcheck_anchors_ignore = [] + +# sphinxext-opengraph +ogp_image = "https://raw.githubusercontent.com/HinodeXRT/xrtpy/main/docs/_static/images/XRTpy_logo.png" +ogp_use_first_image = True +ogp_description_length = 160 +ogp_custom_meta_tags = [ + '', +] + +# Suppress warnings about overriding directives as we overload some of the +# doctest extensions. +suppress_warnings = [ + "app.add_directive", +] # Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# extensions coming with Sphinx (named "sphinx.ext.*") or your custom # ones. extensions = [ + "hoverxref.extension", + "matplotlib.sphinxext.plot_directive", "sphinx_automodapi.automodapi", + "sphinx_automodapi.smart_resolver", + "sphinx_copybutton", + "sphinx_design", + "sphinx_gallery.gen_gallery", + "sphinx_issues", "sphinx.ext.autodoc", + "sphinx.ext.coverage", + "sphinx.ext.doctest", + "sphinx.ext.inheritance_diagram", "sphinx.ext.intersphinx", - "sphinx.ext.graphviz", "sphinx.ext.mathjax", "sphinx.ext.napoleon", "sphinx.ext.todo", - "nbsphinx", - "sphinx_changelog", - "sphinx_copybutton", - "sphinx_gallery.load_style", - "IPython.sphinxext.ipython_console_highlighting", - "sphinx_changelog", - "sphinx_issues", - "sphinxcontrib.bibtex", - "hoverxref.extension", - "sphinx_copybutton", - "sphinx_codeautolink", "sphinx.ext.viewcode", + "sphinxcontrib.bibtex", + "sphinxext.opengraph", ] -bibtex_bibfiles = ["bibliography.bib"] -bibtex_default_style = "plain" -bibtex_reference_style = "author_year" -bibtex_cite_id = "{key}" +# Set automodapi to generate files inside the generated directory +automodapi_toctreedirnm = "generated/api" # Add any paths that contain templates here, relative to this directory. -# templates_path = ['_templates'] +# templates_path = ["_templates"] # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +# html_extra_path = ['robots.txt'] + exclude_patterns = [ - ".DS_Store", "_build", + "Thumbs.db", + ".DS_Store", "_links.rst", "_substitutions.rst", - "Thumbs.db", ] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: source_suffix = ".rst" -# The root toctree document. -root_doc = "index" - -# -- nbsphinx configuration -------------------------------------------------- +# The master toctree document. +master_doc = "index" -nbsphinx_allow_errors = True # Allow errors in Jupyter notebooks +# The reST default role (used for this markup: `text`) to use for all +# documents. Set to the "smart" one. +default_role = "obj" -# -- Options for intersphinx extension --------------------------------------- +# Disable having a separate return type row +napoleon_use_rtype = False -intersphinx_mapping = { - "astropy": ("https://docs.astropy.org/en/stable/", None), - "ndcube": ("https://docs.sunpy.org/projects/ndcube/en/stable/", None), - "numpy": ("https://numpy.org/doc/stable/", None), - "python": ("https://docs.python.org/3", None), - "scipy": ("https://docs.scipy.org/doc/scipy/reference/", None), - "sunpy": ("https://docs.sunpy.org/en/stable/", None), -} +# Disable google style docstrings +napoleon_google_docstring = False -hoverxref_intersphinx = [ - "astropy", - "ndcube", - "numpy", - "python", - "scipy", - "sunpy", -] +# Disable the use of param, which prevents a distinct "Other Parameters" section +napoleon_use_param = False -autoclass_content = "both" -autodoc_typehints_format = "short" +# Enable nitpicky mode, which forces links to be non-broken +nitpicky = True +# This is not used. See docs/nitpick-exceptions file for the actual listing. +nitpick_ignore = [] +with Path("nitpick-exceptions").open() as f: + for line in f: + if line.strip() == "" or line.startswith("#"): + continue + dtype, target = line.split(None, 1) + target = target.strip() + nitpick_ignore.append((dtype, target)) -# -- Options for HTML output ------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -html_theme = "sphinx_rtd_theme" - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ["_static"] +bibtex_bibfiles = ["bibliography.bib"] +bibtex_default_style = "plain" +bibtex_reference_style = "author_year" +bibtex_cite_id = "{key}" -linkcheck_allowed_redirects = { - r"https://doi\.org/.+": r"https://.+", # DOI links are more persistent - r"https://docs.+\.org": r"https://docs.+\.org/en/.+", - r"https://docs.+\.io": r"https://docs.+\.io/en/.+", - r"https://docs.+\.com": r"https://docs.+\.com/en/.+", - r"https://docs.+\.dev": r"https://docs.+\.dev/en/.+", - r"https://.+\.readthedocs\.io": r"https://.+\.readthedocs\.io/en/.+", - r"https://.+/github\.io": r"https://.+/github\.io/en/.+", - r"https://pip\.pypa\.io": r"https://pip\.pypa\.io/en/.+", - r"https://www.python.org/dev/peps/pep.+": "https://peps.python.org/pep.+", -} +# This is added to the end of RST files — a good place to put substitutions to be used globally. +rst_epilog = "" +for epilog_file in ["_links.rst", "_substitutions.rst"]: + with Path(epilog_file).open() as file: + rst_epilog += file.read() -linkcheck_anchors = True -linkcheck_anchors_ignore = [ - "/room", - r".+openastronomy.+", - "L[0-9].+", - "!forum/plasmapy", -] +# Configure sphinx-issues +issues_github_path = "HinodeXRT/xrtpy" -# Use a code highlighting style that meets the WCAG AA contrast standard -pygments_style = "default" +# -- Options for intersphinx extension --------------------------------------- -nbsphinx_thumbnails = { - "notebooks/getting_started/units": ( - "_static/notebook_images/astropy_logo_notext.png" - ), # CC BY-SA - "notebooks/getting_started/A_Practical_Guide_to_Data_Extraction_and_Visualization": ( - "_static/notebook_images/hinode_satellite.png" +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = { + "python": ( + "https://docs.python.org/3/", + (None, "http://www.astropy.org/astropy-data/intersphinx/python3.inv"), + ), + "numpy": ( + "https://numpy.org/doc/stable/", + (None, "http://www.astropy.org/astropy-data/intersphinx/numpy.inv"), ), + "scipy": ( + "https://docs.scipy.org/doc/scipy/reference/", + (None, "http://www.astropy.org/astropy-data/intersphinx/scipy.inv"), + ), + "astropy": ("https://docs.astropy.org/en/stable/", None), + "matplotlib": ("https://matplotlib.org/stable", None), + "ndcube": ("https://docs.sunpy.org/projects/ndcube/en/stable/", None), + "sunpy": ("https://docs.sunpy.org/en/stable/", None), } -# adapted from sphinx-hoverxref conf.py +# -- Options for hoverxref ----------------------------------------------------- + if os.environ.get("READTHEDOCS"): - # Building on Read the Docs hoverxref_api_host = "https://readthedocs.org" if os.environ.get("PROXIED_API_ENDPOINT"): # Use the proxied API endpoint - # - A RTD thing to avoid a CSRF block when docs are using a - # custom domain + # A RTD thing to avoid a CSRF block when docs are using a custom domain hoverxref_api_host = "/_" -hoverxref_tooltip_maxwidth = 600 # RTD main window is 696px hoverxref_auto_ref = True -hoverxref_mathjax = True -hoverxref_sphinxtabs = True - -# hoverxref has to be applied to these hoverxref_domains = ["py", "cite"] hoverxref_roles = ["confval", "term"] - +hoverxref_mathjax = True +hoverxref_modal_hover_delay = 500 +hoverxref_tooltip_maxwidth = 600 # RTD main window is 696px +hoverxref_intersphinx = list(intersphinx_mapping.keys()) hoverxref_role_types = { - # roles with cite domain - "p": "tooltip", - "t": "tooltip", - # - # roles with py domain + # Roles within the py domain "attr": "tooltip", "class": "tooltip", "const": "tooltip", @@ -179,50 +224,90 @@ "meth": "tooltip", "mod": "tooltip", "obj": "tooltip", - # - # roles with std domain + # Roles within the std domain "confval": "tooltip", "hoverxref": "tooltip", - "ref": "tooltip", + "ref": "tooltip", # Would be used by hoverxref_auto_ref if we set it to True "term": "tooltip", } -# Configure sphinx-issues -issues_github_path = "HinodeXRT/xrtpy" +# -- Options for HTML output --------------------------------------------------- -# Specify patterns to ignore when doing a nitpicky documentation build. - -python_role = "py:.*" - -nitpick_ignore_regex = [ - (python_role, "and"), - (python_role, "array .*"), - (python_role, "array_like"), - (python_role, "callable"), - (python_role, "function"), - (python_role, ".*integer.*"), - (python_role, "iterable"), - (python_role, "key"), - (python_role, "keyword-only"), - (python_role, ".* object"), - (python_role, "optional"), - (python_role, "or"), - (python_role, ".*real number.*"), - (python_role, ".*Unit.*"), +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = "pydata_sphinx_theme" +html_theme_options = { + "logo": { + "text": "XrtPy", + }, + "use_edit_page_button": True, + "icon_links": [ + { + "name": "GitHub", + "url": "https://github.com/HinodeXRT/xrtpy/", + "icon": "fa-brands fa-github", + }, + { + "name": "PyPI", + "url": "https://pypi.org/project/xrtpy/", + "icon": "fa-brands fa-python", + }, + ], +} +html_context = { + "github_user": "HinodeXRT", + "github_repo": "xrtpy", + "github_version": "main", + "doc_path": "docs", +} +html_logo = "_static/images/XRTpy_logo.png" +html_sidebars = { + # Sidebar removal + "about_xrt*": [], + "install*": [], + "getting_started*": [], + "bibliography*": [], + "glossary*": [], + "feedback_communication*": [], + "contributing*": [], + "code_of_conduct*": [], +} +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +# html_static_path = ["_static"] + +# Render inheritance diagrams in SVG +graphviz_output_format = "svg" + +graphviz_dot_args = [ + "-Nfontsize=10", + "-Nfontname=Helvetica Neue, Helvetica, Arial, sans-serif", + "-Efontsize=10", + "-Efontname=Helvetica Neue, Helvetica, Arial, sans-serif", + "-Gfontsize=10", + "-Gfontname=Helvetica Neue, Helvetica, Arial, sans-serif", ] -# This is added to the end of RST files — a good place to put substitutions to -# be used globally. -rst_epilog = "" -for epilog_file in ["_links.rst", "_substitutions.rst"]: - with open(epilog_file) as file: # noqa: PTH123 - rst_epilog += file.read() - -# Add the nbsphinx_allow_errors option -nbsphinx_allow_errors = True +# -- Sphinx Gallery ------------------------------------------------------------ + +sphinx_gallery_conf = { + "backreferences_dir": Path("generated") / "modules", + "filename_pattern": "^((?!skip_).)*$", + "examples_dirs": Path("..") / "examples", + "within_subsection_order": "ExampleTitleSortKey", + "gallery_dirs": Path("generated") / "gallery", + "matplotlib_animations": True, + "default_thumb_file": "https://raw.githubusercontent.com/HinodeXRT/xrtpy/main/docs/_static/images/XRTpy_logo.png", + "abort_on_example_error": False, + "plot_gallery": "True", + "remove_config_comments": True, + "doc_module": ("xrtpy"), + "only_warn_on_example_error": True, +} +# -- Options for sphinx-copybutton --------------------------------------------- -def setup(app: Sphinx) -> None: - app.add_config_value("revision", "", True) # noqa: FBT003 - app.add_css_file("css/admonition_color_contrast.css") - app.add_css_file("css/plasmapy.css", priority=600) +# Python Repl + continuation, Bash, ipython and qtconsole + continuation, jupyter-console + continuation +copybutton_prompt_text = r">>> |\.\.\. |\$ |In \[\d*\]: | {2,5}\.\.\.: | {5,8}: " +copybutton_prompt_is_regexp = True diff --git a/docs/contributing.rst b/docs/contributing.rst new file mode 100644 index 000000000..d75aa3041 --- /dev/null +++ b/docs/contributing.rst @@ -0,0 +1,33 @@ +.. _xrtpy-contributing: + +********************* +Contributing to XRTpy +********************* + +Thank you for your interest in contributing to XRTpy! +We welcome contributions from the community to improve and expand the functionality of this package. + +There are several ways you can contribute to XRTpy: + +1. **Reporting Issues**: + If you encounter any bugs or have suggestions for improvements, please report them using the `GitHub-issue`_ page. + Provide as much detail as possible, including steps to reproduce the issue and any relevant screenshots or code snippets. + +2. **Submitting Pull Requests**: + If you want to contribute code, follow these steps: + + - Read the `sunpy Newcomers Guide `__. + - Fork the repository on GitHub. + - Create a new branch from the "main" branch for your changes. + - Make your changes, ensuring that you follow the coding standards and include tests for any new functionality. + - Commit your changes with clear and descriptive commit messages. + - Push your branch to your forked repository. + - Create a pull request (PR) from your branch to the "main" branch of the original repository. + +3. **Improving Documentation**: + Good documentation is crucial for the usability of the package. + You can help by improving existing documentation, or writing new tutorials. + +Thank you for contributing to XRTpy! + +.. _GitHub-issue: https://github.com/HinodeXRT/xrtpy/issues diff --git a/docs/contributing/contributing.rst b/docs/contributing/contributing.rst deleted file mode 100644 index 0cbe97ad9..000000000 --- a/docs/contributing/contributing.rst +++ /dev/null @@ -1,25 +0,0 @@ -.. _contributing: - -********************* -Contributing to XRTpy -********************* - -Thank you for your interest in contributing to XRTpy! We welcome contributions from the community to improve and expand the functionality of this package. - -There are several ways you can contribute to XRTpy: - -1. **Reporting Issues**: If you encounter any bugs or have suggestions for improvements, please report them using the `GitHub-issue`_ page. Provide as much detail as possible, including steps to reproduce the issue and any relevant screenshots or code snippets. - -2. **Submitting Pull Requests**: If you want to contribute code, follow these steps: - - Fork the repository on GitHub. - - Create a new branch from the `main` branch for your changes. - - Make your changes, ensuring that you follow the coding standards and include tests for any new functionality. - - Commit your changes with clear and descriptive commit messages. - - Push your branch to your forked repository. - - Create a pull request (PR) from your branch to the `main` branch of the original repository. - -3. **Improving Documentation**: Good documentation is crucial for the usability of the package. You can help by improving existing documentation, or writing new tutorials. - -Visit the `Development Environment` section to set up your development environment. Thank you for contributing to XRTpy! - -.. _GitHub-issue: https://github.com/HinodeXRT/xrtpy/issues diff --git a/docs/contributing/index.rst b/docs/contributing/index.rst deleted file mode 100644 index f7530cd26..000000000 --- a/docs/contributing/index.rst +++ /dev/null @@ -1,13 +0,0 @@ -.. _contributor guide: - -***************** -Contributor Guide -***************** - -.. toctree:: - :maxdepth: 3 - - contributing - installation_for_development - release_guide - acknowledging_xrtpy diff --git a/docs/contributing/installation_for_development.rst b/docs/contributing/installation_for_development.rst deleted file mode 100644 index 869a31998..000000000 --- a/docs/contributing/installation_for_development.rst +++ /dev/null @@ -1,39 +0,0 @@ -.. _installation for development: - -**************************** -Installation for Development -**************************** - -Development Environment -======================== -To set up your development environment: - -1. Clone the repository:: - - git clone https://github.com/HinodeXRT/xrtpy.git` - cd xrtpy - -2. Install the package in editable mode:: - - pip install -e . - -Coding Standards -================ -- Follow the `PEP-8`_ coding style. -- Write clear and concise commit messages. -- Include docstrings for all functions and classes. -- Ensure that your code is covered by tests and that all tests pass before submitting a PR. - -Testing -======= -We use `pytest` for testing. To run the tests, use the following command:: - - pytest - -Ensure that all tests pass before submitting your PR. - -Communication -============= -For any questions or discussions, you can email us at `xrtpy@cfa.harvard.edu`. - -.. _PEP-8: https://peps.python.org/pep-0008/ diff --git a/docs/contributing/release_guide.rst b/docs/contributing/release_guide.rst deleted file mode 100644 index 2f51004ae..000000000 --- a/docs/contributing/release_guide.rst +++ /dev/null @@ -1,7 +0,0 @@ -.. _release guide: - -************* -Release Guide -************* - -This page has not yet been written. diff --git a/docs/examples.rst b/docs/examples.rst deleted file mode 100644 index 64499aa5e..000000000 --- a/docs/examples.rst +++ /dev/null @@ -1,34 +0,0 @@ -Examples -======== -In this section, we provide a catalog of example Jupyter notebooks that -demonstrate the various functionalities offered by `XRTpy`. These notebooks -serve as practical guides for utilizing the features and capabilities of XRTpy -in different scenarios. By exploring these examples, users can gain a better -understanding of how to effectively use XRTpy for their analysis tasks. - -.. contents:: - :local: - -Getting started ---------------- - -.. nbgallery:: - :glob: - - notebooks/getting_started/* - -Computing response functions ----------------------------- - -.. nbgallery:: - :glob: - - notebooks/computing_functions/* - -Data analysis -------------- - -.. nbgallery:: - :glob: - - notebooks/data_analysis/* diff --git a/docs/feedback_communication.rst b/docs/feedback_communication.rst index 514be42c9..7a7377646 100644 --- a/docs/feedback_communication.rst +++ b/docs/feedback_communication.rst @@ -1,28 +1,29 @@ -.. currentmodule:: xrtpy +.. _xrytpy-feedback-communication: -.. _feedback_communication: +****************** +Providing Feedback +****************** -******************** -Communication Routes -******************** - -XRTpy has several methods of contact to get direct intel of XRTpy's current -works, reporting bugs, giving feedback, and asking questions. Please direct any comments, questions, or suggestions to `xrtpy@cfa.harvard.edu`_. +XRTpy has several methods that one can use to get contact with XRTpy developers, giving feedback or giving feedback. Feedback ======== -We appreciate any feedback describing your experience using XRTpy. We welcome other methods and ideas towards the development of XRTpy. You may contact us via `email`_ or through `GitHub Hinode XRT`_. -Bug Encounters -============== -In the event that you come across a direct XRTpy error, flaw, or unexpected operation, please report it to us directly via `email`_ or by creating a `GitHub-issue`_. +We appreciate any feedback describing your experience using XRTpy. +We welcome other methods and ideas towards the development of XRTpy. +You may contact us via `GitHub Hinode XRT`_ or `email`_. + +Bugs +==== + +If you encounter a XRTpy error, flaw, or unexpected operation, please report it to us by creating a `GitHub-issue`_ or by sending an `email`_. Contributing ============ -We welcome contributions from the community! For detailed guidelines on how to contribute, please see our `Contributing Guide` page section `Contributing to XRTpy` . +We welcome contributions from the community! +For detailed guidelines on how to contribute, please see :ref:`xrtpy-contributing`. -.. _xrtpy@cfa.harvard.edu: xrtpy@cfa.harvard.edu .. _email: xrtpy@cfa.harvard.edu -.. _GitHub-issue: https://github.com/HinodeXRT/xrtpy/issues .. _GitHub Hinode XRT : https://github.com/HinodeXRT/xrtpy +.. _GitHub-issue: https://github.com/HinodeXRT/xrtpy/issues diff --git a/docs/getting_started.rst b/docs/getting_started.rst index 999d6ed5f..f1fc16c24 100644 --- a/docs/getting_started.rst +++ b/docs/getting_started.rst @@ -1,86 +1,93 @@ +.. _xrtpy-getting-started: + =============== Getting Started =============== -XRTpy is a Python package being developed for the analysis of observations made by the X-Ray Telescope (XRT) -on the board Hinode spacecraft. This page is intended for new users of `xrtpy`. For more background information about XRT please refer to the `SolarSoft XRT Analysis Guide`_. +XRTpy is a Python package being developed for the analysis of observations made by the X-Ray Telescope (XRT) on the board Hinode spacecraft. +This page is intended for new users of `xrtpy`. For more background information about XRT please refer to the `SolarSoft XRT Analysis Guide`_. +XRTpy Objects +************* -XRTpy Objects: -************** -XRTpy currently offers *Channel*, *Effective Area*, and *Temperature Response* classes. We have also introduced new functionality, including -the ablility to derive temperatures and emission measures for a pair of images, sharpen images using the point spread function, and -a function to correct synoptic images for the light leak (visible stray light) that XRT has developed. +XRTpy currently offers *Channel*, *Effective Area*, and *Temperature Response* classes. +There is the ability to to derive temperatures and emission measures for a pair of images, sharpen images using a Point Spread Function (PSF) deconvolution, and to correct synoptic images for the light leak (visible stray light) that XRT has developed. Visit our Example page for detail notebook example guides on how to use the XRTpy classes and functions. - Channel ------- -|Channel| is an instrument configuration class that contains the properties of particular XRT filters. It provides a detailed information on the filter channel, including the Charge-Coupled Device (CCD), Entrance Filter, Focus-Filter(s), Geometry, and Mirror(s). +|Channel| is an instrument configuration class that contains the properties of particular XRT filters. +It provides a detailed information on the filter channel, including the Charge-Coupled Device (CCD), Entrance Filter, Focus-Filter(s), Geometry, and Mirror(s). Effective Area -------------- + XRTpy calculates the effective areas for a set of XRT filter channels paired with thicknesses of the CCD contamination layer. For more information about the instrumental spectral responses, refer to the `SolarSoft XRT Analysis Guide`_. - Temperature Response -------------------- -XRTpy calculates the temperature response for each XRT filter channel, assuming a spectral emission model, refer to :cite:t:`narukage:2011` and :cite:t:`narukage:2014`. -The XRT default emission model is `CHIANTI`_ atomic database version 10.0 with coronal abundances :cite:t:`feldman:1992`. This structure contains data and information about a plasma emission model, as a function of wavelength and temperature. +XRTpy calculates the temperature response for each XRT filter channel, assuming a spectral emission model, refer to :cite:t:`narukage:2011` and :cite:t:`narukage:2014`. +The XRT default emission model is `CHIANTI`_ atomic database version 10.0 with coronal abundances :cite:t:`feldman:1992`. +This structure contains data and information about a plasma emission model, as a function of wavelength and temperature. Deriving Temperature and Emission Measure for a Pair of Images -------------------------------------------------------------- -XRTpy provides a routine, *temperature_from_filter_ratio*, that employs the objects listed above to derive the temperature and emission -measure in for a given pair of images using the filter ratio method. This uses the same methods as in the SolarSoft IDL -routine of the same name. Familiarize yourself with the utilization of this function through the notebook example provided on our Example page. +XRTpy provides a routine, *temperature_from_filter_ratio*, that employs the objects listed above to derive the temperature and emission measure in for a given pair of images using the filter ratio method. +This uses the same methods as in the SolarSoft IDL routine of the same name. +Familiarize yourself with the utilization of this function through the notebook example provided on our Example page. Enhancing Images Sharpness with Point Spread Function - Deconvolution --------------------------------------------------------------------- + Deconvolution is a powerful technique used to enhance image sharpness by mitigating the blurring effect -caused by the telescope's point spread function (PSF). It is particularly useful for removing the blurring -around sharp objects or features in the XRT image. To learn how to use *deconvolve*, refer to the notebook examples provided on our Example page. +caused by the telescope's point spread function (PSF). +It is particularly useful for removing the blurring around sharp objects or features in the XRT image. +To learn how to use *deconvolve*, refer to the notebook examples provided on our Example page. Subtracting Light Leak from XRT Synoptic Composite Images --------------------------------------------------------- -We have developed a specialized function designed to subtract light leak, *remove_lightleak*, which refers to visible stray -light, from XRT synoptic composite images. By applying this function, you can effectively remove the -unwanted artifacts caused by light leak, resulting in cleaner and more accurate images for further analysis and interpretation. + +We have developed a specialized function designed to subtract light leak, *remove_lightleak*, which refers to visible stray light, from XRT synoptic composite images. +By applying this function, you can effectively remove the unwanted artifacts caused by light leak, resulting in cleaner and more accurate images for further analysis and interpretation. Explore our Example page for a notebook example that demonstrate the usage of this function. Abundance Model --------------- + The standard XRT temperature response routines are calculated assuming `CHIANTI`_ coronal abundances, :cite:t:`feldman:1992`. -Additionally, XRTpy offers the ability to choose two other sets of `CHIANTI`_ abundances i.e. Hybrid and Photospheric. -The Hybrid abundances are base on :cite:t:`Fludra:1999` and Photospheric abundances are base on :cite:t:`Grevesse:2007`. +Additionally, XRTpy offers the ability to choose two other sets of `CHIANTI`_ abundances i.e., Hybrid and Photospheric. +The Hybrid abundances are based on :cite:t:`Fludra:1999` and Photospheric abundances are base on :cite:t:`Grevesse:2007`. The `CHIANTI`_ files contain data and information about a plasma emission model, as a function of wavelength and temperature. Visit `XRT temperature response with other choice of abundances`_ for future detailed information. .. note:: + XRTpy has future plans to accept other plasma emission spectra models. -XRTpy defaults to using CHIANTI `"coronal"` abundance. You can specify the other abundances by defining the abundance type name, -such as `"hybrid"` or `"photospheric"` in the `abundance_model` parameter. For example: +XRTpy defaults to using CHIANTI's "coronal" abundance. +You can specify the other abundances by defining the abundance type name, such as "hybrid" or "photospheric" in the ``abundance_model`` parameter. -.. code-block:: bash +For example: - xrtpy.response.TemperatureResponseFundamental( - 'Al-poly', - '2022/07/04T23:43:12', - abundance_model = 'Hybrid' - ) +.. code-block:: python -The `abundance_model` parameter is used in the same format in `temperature_from_filter_ratio`. + xrtpy.response.TemperatureResponseFundamental( + "Al-poly", "2022/07/04T23:43:12", abundance_model="Hybrid" + ) +The ``abundance_model`` parameter is used in the same format in `xrtpy.response.temperature_from_filter_ratio`. Data Products ************* + The XRT website provides readily available `XRT data products`_, including both Level 1 and Level 2 data. -The `Level 1 Data`_ section contains an extensive archive of all Level 1 XRT data that has been calibrated using the `xrt_prep`_ routine, with units expressed in instrumental Data Numbers. -Additionally, for users interested in synoptic images, `Level 2 Synoptics`_ data is available, which consists of composite images from the twice-daily synoptic program. These images have been processed and are available in the archive. +The `Level 1 Data`_ section contains an extensive archive of all Level 1 XRT data that has been calibrated using the `xrt_prep`_ routine, with units expressed in Data Numbers. +Additionally, for users interested in synoptic images, `Level 2 Synoptics`_ data is available, which consists of composite images from the twice-daily synoptic program. +These images have been processed and are available in the archive. For more detailed information about our XRT data products, please visit the `XRT data products`_ site, where you can find comprehensive data resources and references. .. _Level 1 Data: https://xrt.cfa.harvard.edu/level1/ @@ -88,11 +95,14 @@ For more detailed information about our XRT data products, please visit the `XRT .. _XRT data products: https://xrt.cfa.harvard.edu/data_products/index.php .. _xrt_prep: https://xrt.cfa.harvard.edu/resources/documents/XAG/XAG.pdf +.. _xrtpy-getting-started-filters: + X-Ray Filter Channel -********************* +******************** -The XRT controls filter imaging using two sequentially positioned filter wheels, as shown in the diagram below. Each wheel houses a variety of filters. By rotating these wheels, scientists can select different filters to study the sun in multiple wavelengths, thereby enhancing the resolution and quality of solar images. -Refer to Section 3 in the `X-Ray Telescope Instrument Guide` in the `SolarSoft XRT Analysis Guide`_ for more information about the XRT filters. +XRT uses two sequentially positioned filter wheels, as shown in the diagram below, where each wheel houses a variety of filters. +By rotating these wheels, scientists can select different filters to study the Sun in different wavelengths, thereby enhancing the resolution and quality of solar images. +Refer to Section 3 in the "X-Ray Telescope Instrument Guide" in the `SolarSoft XRT Analysis Guide`_ for more information abo[ut the XRT filters. The existing filters are structured as follows: #. Filter Configuration @@ -112,20 +122,21 @@ The existing filters are structured as follows: - Aluminum Thick (*Al-thick*) - Beryllium Thick (*Be-thick*) #. *Open* - Each filter wheel has an empty position, named 'Open'. The open position is in place when a filter on the other filter wheel is being used. + Each filter wheel has an empty position, named 'Open'. + The open position is in place when a filter on the other filter wheel is being used. #. *G-band* - The G-Band filter allows visible light into the telescope and onto the CCD. XRTpy does not - calculate the effective area or the temperature response for the G-Band filter. + The G-Band filter allows visible light into the telescope and onto the CCD. + XRTpy does not calculate the effective area or the temperature response for the G-Band filter. .. note:: - Filters are expressed by their abbreviation when used in XRTpy. For example, if we want to explore the filter channel - that selects the titanium-on-polyimide filter, then the string would be ``'Ti-poly'``. The process is the same for all XRT - filter channels. -.. image:: images/XRT_filter_wheels_Sun_View_Diagram.png + Filters are expressed by their abbreviation when used in XRTpy. + For example, if we want to explore the filter channel that selects the Titanium Polyimide filter, then the string would be ``'Ti-poly'``. + The process is the same for all XRT filter channels. + +.. image:: _static/images/XRT_filter_wheels_Sun_View_Diagram.png :alt: Diagram of the XRT Filter Wheels :align: center - :scale: 25% .. _CHIANTI: https://www.chiantidatabase.org/chianti_database_history.html .. _SolarSoft XRT Analysis Guide: https://xrt.cfa.harvard.edu/resources/documents/XAG/XAG.pdf diff --git a/docs/glossary.rst b/docs/glossary.rst index 715638b44..d2013fb51 100644 --- a/docs/glossary.rst +++ b/docs/glossary.rst @@ -1,6 +1,4 @@ -.. currentmodule:: xrtpy - -.. _glossary: +.. _xrtpy-glossary: ******** Glossary @@ -21,7 +19,7 @@ Glossary Contamination (related to the XRT) Contamination refers to the accumulation of contaminating material on the XRT CCD and focal plane filters (FPFs), which results in a decrease in sensitivity. - Refer to Section 2.5.3 `Contamination` in the `SolarSoft XRT Analysis Guide`_ for more information about the XRT contamination. + Refer to Section 2.5.3 "Contamination" in the `SolarSoft XRT Analysis Guide`_ for more information about the XRT contamination. Temperature response Temperature response refers to the instrument's temperature response function for a specific filter channel. Units measured in diff --git a/docs/images/XRTpy_logo copy.png b/docs/images/XRTpy_logo copy.png deleted file mode 100644 index 44be6548f4070754a30ad9e4e4edc088b1c8785d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 130131 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

IaVb-6XZub=AHJD)=%MM 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

gTDH*9E(BU;Sbe8X|M`3F+PN;!hB3TN@|U( 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. +Instead, we recommend that you use miniforge which is a minimal installer that setups conda with the conda-forge channel, which is free to use for everyone. +If you are using miniforge, you can skip the next section -To install the most recent release of `xrtpy` on PyPI_ with pip_ into -an existing Python_ |minpython|\ + environment on macOS or Linux, open a -terminal and run: +Installing miniforge +-------------------- -.. code-block:: bash +If you don't already have a Python installation then we recommend installing Python with `miniforge `__. +This will install ``conda`` and automatically configure the default channel (a channel is a remote software repository) to be ``conda-forge``, which is where ``sunpy`` is available. - python -m pip install xrtpy +First, download the installer for your system and architecture from the links below: -On some systems, it might be necessary to specify the Python_ version -number by using ``python3``, ``python3.9``, ``python3.10``, or -``python3.11`` instead of ``python``. +.. grid:: 3 -To install XRTpy on Windows, run: + .. grid-item-card:: Linux -.. code-block:: bash + `x86-64 `__ - py -3.10 -m pip install xrtpy + `aarch64 `__ -The version of Python_ may be changed from ``3.10`` to another supported -Python |minpython|\ + release that has been installed on your computer. + `ppc64le `__ -For more detailed information, please refer to this tutorial on -`installing packages`_. + .. grid-item-card:: Windows + :link: https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-Windows-x86_64.exe -.. _install-conda: + `x86-64 `__ -Installing XRTpy with Conda -============================== + .. grid-item-card:: Mac -Conda_ is a package management system and environment manager that is -commonly used in the scientific Python_ ecosystem. Conda_ lets us create -and switch between Python_ environments that are isolated from each -other and the system installation. Conda_ can also be used for packages -written in languages other than Python_. + `x86-64 `__ -After `installing Conda`_ or miniconda_, `xrtpy` can be installed -into an activated Conda_ environment by opening a terminal and running: + `arm64 (Apple + Silicon) `__ -.. code-block:: bash +Then select your platform to install miniforge: - conda install -c conda-forge xrtpy +.. tab-set:: -Here ``-c conda-forge`` indicates that `xrtpy` should be installed -from the conda-forge_ channel. + .. tab-item:: Linux & Mac + :sync: platform -To install `xrtpy` into another existing Conda_ environment, append -:samp:`-n {env_name}` to the previous command, where :samp:`{env_name}` -is replaced with the name of the environment. + Linux & Mac Run the script downloaded above, with + ``bash ``. The following should work: -To create a new environment with `xrtpy` installed in it, run: + .. code-block:: console -.. code-block:: bash + bash Miniforge3-$(uname)-$(uname -m).sh - conda create -n env_name -c conda-forge xrtpy + Once the installer has completed, close and reopen your terminal. -where :samp:`{env_name}` is replaced by the name of the environment. To -activate this environment, run: + .. tab-item:: Windows + :sync: platform -.. code-block:: bash + Double click the executable file downloaded from + the links above. - conda activate env_name + Once the installer has completed you should have a new "miniforge + Prompt" entry in your start menu. -To update `xrtpy` to the most recent version within a currently -activated Conda_ environment, run: +In a new terminal (miniforge Prompt on Windows) run ``conda list`` to test that the install has worked. -.. code-block:: bash - - conda update xrtpy - -.. tip:: - - Creating a Conda_ environment can sometimes take a few minutes. If it - takes longer than that, try updating to the newest version of Conda_ - with ``conda update conda`` or checking out these tips for - `improving Conda performance`_. - -Installing XRTpy with Anaconda Navigator -=========================================== - -.. note:: +Installing xrtpy +---------------- - This section contains instructions on how to install XRTpy with - `Anaconda Navigator`_ at the time of writing. For the most up-to-date - information, please go to the official documentation on `installing - Anaconda Navigator`_ and `managing packages`_. +To install ``xrtpy``, start by launching a terminal (under a UNIX-like system) or the miniforge Prompt (under Windows). +Now we will create and activate a new virtual environment to install ``xrtpy`` into: -`Anaconda Navigator`_ is a graphical user interface (GUI) for Conda_ -that can be used to install Python packages. It is installed -automatically with newer versions of Conda_. If you are using Miniconda_ -or a different Conda_ environment, you can install it with -``conda install anaconda-navigator``. After that it can be opened by -entering ``anaconda-navigator`` in the terminal. - -First, go to the :guilabel:`Environments` tab and select -:guilabel:`Channels`. If ``conda-forge`` is not listed, then go to -:guilabel:`Add`, enter ``https://conda.anaconda.org/conda-forge``, and -click on :guilabel:`Update channels` and then :guilabel:`Update index`. - -Next, while on the :guilabel:`Environments` tab, select the environment -that you would like to install `xrtpy` in. The default is generally -``base (root)``. Optionally, you may select :guilabel:`Create` to start -a new environment. In the search bar, enter ``xrtpy``. Click on the -checkbox next to ``xrtpy``, and select :guilabel:`Apply` to begin the -installation process. - -To test the installation, click on the :guilabel:`▶` icon that should be -present next to the activated environment, and select -:guilabel:`Open terminal`. Enter ``python`` in the terminal, and then -``import xrtpy`` to make sure it works. - -Installing XRTpy from source code -==================================== - -Obtaining official releases ---------------------------- - -A ZIP_ file containing the source code for official releases of -`xrtpy` can be obtained `from PyPI`_ or `from Zenodo`_. - -Alternatively, official releases can be downloaded from the -releases_ page on `XRTpy's GitHub repository`_. - -Obtaining source code from GitHub ---------------------------------- +.. code-block:: bash -If you have git_ installed on your computer, you may clone `XRTpy's -GitHub repository`_ and access the source code from the most recent -development version by running: + $ conda create --name xrtpy + # Only run the following two lines + # if you have NOT installed miniforge or added conda-forge to your channels + # Do not run these lines if you are using Anaconda + $ conda config --add channels conda-forge + $ conda config --set channel_priority strict + $ conda activate xrtpy -.. code:: bash +In this case the environment is named 'xrtpy'. +Feel free to change this to a different environment name. - git clone https://github.com/xrtpy/xrtpy.git +The benefit of using a virtual environment is that it allows you to install packages without affecting any other Python installation on your system. +This also means you can work on multiple projects (research or coding) with different package requirements without them interfering with each other. -The repository will be cloned inside a new subdirectory called -:file:`xrtpy`. +Now we have a fresh environment we can install ``xrtpy``: -If you do not have git_ installed on your computer, then you may download -the most recent source code from `XRTpy's GitHub repository`_ by -going to :guilabel:`Code` and selecting :guilabel:`Download ZIP`. -`Unzipping `__ the file will -create a subdirectory called :file:`XRTpy` that contains the source -code. +.. code-block:: bash -Building and installing ------------------------ + $ conda install xrtpy -To install the downloaded version of `xrtpy`, enter the :file:`xrtpy` -directory and run: +This will install ``xrtpy`` and all of its dependencies. +If you want to install another package later, you can run ``conda install ``. -.. code-block:: bash +pip +~~~ - pip install . +This is for installing ``xrtpy`` within a Python environment, where ``pip`` has been used to install all previous packages. +You will want to make sure you are using a `Python virtual environment `__. -If you expect to occasionally edit the source code, instead run: +Once the environment active, to acquire a full ``xrtpy`` installation: .. code-block:: bash - # For Bash - pip install -e .[developer] + $ pip install xrtpy - # For Zsh - pip install -e ".[developer]" - -The ``-e`` flag makes the installation editable and ``[developer]`` -indicates that all of the dependencies needed for developing XRTpy -will be installed. - -.. note:: - If you noticed any places where the installation instructions could - be improved or have become out of date, please create an issue on - `XRTpy's GitHub repository`_. It would really help! +.. warning:: + If you get a ``PermissionError`` this means that you do not have the required administrative access to install new packages to your Python installation. + Do **not** install any Python packages using ``sudo``. + This error implies you have an incorrectly configured virtual environment or it is not activated. .. note:: - If you noticed any places where the installation instructions could - be improved or have become out of date, please create an issue on - `XRTpy's GitHub repository`_. It would really help! - -.. _Anaconda Navigator: https://www.anaconda.com/products/individual -.. _clone a repository using SSH: https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-ssh-urls -.. _conda-forge: https://conda-forge.org -.. _download Python: https://www.python.org/downloads/ -.. _from PyPI: https://pypi.org/project/xrtpy -.. _from Zenodo: https://doi.org/10.5281/zenodo.1436011 -.. _improving Conda performance: https://docs.conda.io/projects/conda/en/latest/user-guide/concepts/conda-performance.html#improving-conda-performance -.. _installing Anaconda Navigator: https://docs.anaconda.com/anaconda/navigator/install/ -.. _installing Conda: https://docs.conda.io/projects/conda/en/latest/user-guide/install/index.html -.. _installing packages: https://packaging.python.org/en/latest/tutorials/installing-packages/#installing-from-vcs -.. _managing packages: https://docs.anaconda.com/anaconda/navigator/tutorials/manage-packages/#installing-a-package -.. _miniconda: https://docs.conda.io/en/latest/miniconda.html -.. _releases: https://github.com/xrtpy/xrtpy/releases -.. _ZIP: https://en.wikipedia.org/wiki/ZIP_(file_format) + If you noticed any places where the installation instructions could be improved or have become out of date, please create an issue on `XRTpy's GitHub repository`_. + It would really help! diff --git a/docs/make.bat b/docs/make.bat index 922152e96..d85ed391a 100644 --- a/docs/make.bat +++ b/docs/make.bat @@ -21,15 +21,15 @@ if errorlevel 9009 ( echo.may add the Sphinx directory to PATH. echo. echo.If you don't have Sphinx installed, grab it from - echo.http://sphinx-doc.org/ + echo.https://sphinx-doc.org/ exit /b 1 ) -%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% goto end :help -%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% :end popd diff --git a/docs/nitpick-exceptions b/docs/nitpick-exceptions new file mode 100644 index 000000000..ba01bcab5 --- /dev/null +++ b/docs/nitpick-exceptions @@ -0,0 +1,8 @@ +# Prevents sphinx nitpicky mode picking up on optional +# (see https://github.com/sphinx-doc/sphinx/issues/6861) +# Even if it was "fixed", still broken +py:class optional +# See https://github.com/numpy/numpy/issues/10039 +py:obj numpy.datetime64 +# Epoch issue +py:obj Time diff --git a/docs/notebooks/computing_functions/effective_area.ipynb b/docs/notebooks/computing_functions/effective_area.ipynb deleted file mode 100644 index d37ca8eea..000000000 --- a/docs/notebooks/computing_functions/effective_area.ipynb +++ /dev/null @@ -1,325 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Effective Area Analysis for X-Ray Telescope (XRT)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "In this example, we will explore the effective areas for different XRT filter channels, considering their respective thicknesses of the CCD contamination layer at a specific date and time. Understanding the effective areas is essential for accurately interpreting and quantifying X-ray signals. Let's dive into the details and calculations below." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Import the xrtpy module for X-ray Telescope (XRT) calculations\n", - "import xrtpy" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Contents\n", - "\n", - "1. [Define Filter](#Define-a-Filter-Channel)\n", - "2. [Define Date & Time](#Define-a-date-and-time) \n", - "3. [Effective-Area-Fundamental](#EffectiveAreaFundamental)\n", - "4. [Effective Area Function](#Effective-Area-function)\n", - "5. [Plotting the Effective Area versus Wavelength](#Plotting-the-Effective-Area-versus-Wavelength)\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Define a Filter Channel" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "[xrtpy- X-Ray Filter Channel]: https://xrtpy.readthedocs.io/en/latest/getting_started.html\n", - "In XRT analysis, the filter channels play a crucial role in determining the effective areas. A filter channel refers to a specific configuration of filter materials. By defining the filter channel appropriately, we can accurately calculate the effective area for a given XRT configuration.\n", - "\n", - "Let's begin by defining a filter channel using its abbreviation. For example, if we want to explore the effective area for an aluminum-on-polyimide filter channel, we need to specify the relevant abbreviation. This step ensures that we consider the correct filter configuration in our calculations. Refer to the [xrtpy- X-Ray Filter Channel] section for more information. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Define the filter channel abbreviation\n", - "Filter = \"Al-poly\"" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Define a date and time" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "[sunpy-time]: https://docs.sunpy.org/en/stable/guide/time.html\n", - "\n", - "Let's consider exploring the data captured approximately a year after the launch date. We need to define a specific date and time. We will use the format \"YYYY-MM-DD HH:MM:SS\" to represent the desired date and time. The date and time can be specified using various formats depending on your preference and data availability. Please refer to the [sunpy-time] documentation for detailed examples and further information on different date and time string formats. \n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Define the date and time for analysis\n", - "date_time = \"2007-09-22T22:59:59\"" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## EffectiveAreaFundamental" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The `EffectiveAreaFundamental` object plays a central role in calculating the effective area. It provides a range of functions and properties that are essential for this computation. By utilizing the `EffectiveAreaFundamental` object, we can accurately determine the effective area based on the specified filter channel, date, and time.\n", - "\n", - "To access the functionality of the EffectiveAreaFundamental object, we need to reference it by inserting the defined `Filter` and `date_time`. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Create an instance of the EffectiveAreaFundamental object\n", - "Effective_Area_Fundamental = xrtpy.response.EffectiveAreaFundamental(Filter, date_time)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Effective Area function" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To actually calculate the effective area function we call the `effective_area()` method of the `Effective_Area_Fundamental` object. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Calculate the effective area\n", - "effective_area = Effective_Area_Fundamental.effective_area()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "[astropy-quantity]: https://docs.astropy.org/en/stable/api/astropy.units.quantity.Quantity.html\n", - "\n", - "[astropy.units]: https://docs.astropy.org/en/stable/units/index.html\n", - "\n", - "\n", - "The `effective_area` function returns the effective area for a selected filter, date, and time as an [astropy-quantity] with [astropy.units]. \n", - " " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print(\"Effective Area:\\n\", effective_area)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Plotting the Effective Area versus Wavelength" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To gain insights into the X-ray Telescope (XRT) observations, we will plot the effective area against the corresponding wavelengths. This visualization allows us to understand how the effective area varies across different wavelengths and provides valuable information for interpreting XRT data." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We will utilize the `channel_wavelength` property within the Effective_Area_Fundamental object to get the wavelengths. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Wavelength unit in Angstroms A˚\n", - "wavelength = Effective_Area_Fundamental.channel_wavelength" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "To further analyze the effective area data, we will focus on the observations relative to the spacecraft launch date. This will allow us to identify any differences or trends in the effective area during the early stages of the mission. We will define the effective area data for the launch date in the same manner as previously shown." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Create an instance of the EffectiveAreaFundamental object for the launch date and time of the same filter channel\n", - "relative_launch_date_time = \"2006-09-22T22:59:59\"\n", - "\n", - "EAF_launch_date_time = xrtpy.response.EffectiveAreaFundamental(\n", - " Filter, relative_launch_date_time\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# launch date effective area\n", - "launch_date_effective_area = EAF_launch_date_time.effective_area()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Create a plotting function that plots the effective area versus wavelegth." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def plot_effective_area():\n", - " import matplotlib.pyplot as plt\n", - "\n", - " plt.figure(figsize=(30, 13))\n", - "\n", - " plt.plot(\n", - " wavelength,\n", - " effective_area,\n", - " linewidth=8,\n", - " label=f\"{Filter} {date_time}\",\n", - " )\n", - "\n", - " plt.plot(\n", - " wavelength,\n", - " launch_date_effective_area,\n", - " linewidth=8,\n", - " label=f\"{Filter} {relative_launch_date_time}\",\n", - " )\n", - "\n", - " plt.title(\"XRT Effective Area\\nAl-Poly\", fontsize=30)\n", - " plt.xlabel(\"Wavelength (Å)\", fontsize=30)\n", - " plt.ylabel(\"Effective Area ($cm^{2}$)\", fontsize=30)\n", - " plt.legend(fontsize=30)\n", - "\n", - " plt.xticks(fontsize=27)\n", - " plt.yticks(fontsize=27)\n", - " plt.xlim(0, 60)\n", - "\n", - " plt.grid(color=\"lightgrey\")\n", - " plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Run `plot_effective_area` function to create the plot." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "plot_effective_area()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "[Montana State University Solar Physics site]: http://solar.physics.montana.edu/HINODE/XRT/xrt_contam_db.html \n", - "[Narukage et. al. (2011)]: https://doi.org/10.1007/s11207-010-9685-2 \n", - "\n", - "\n", - "By plotting the effective area at the spacecraft launch date and comparing it to the effective area a year after, we can observe and analyze any differences. These differences arise from variations in the contamination layer thickness on the CCD which blocks some of the X-rays thus reducing the effective area. For detailed information about the calculation of the XRT CCD contaminant layer thickness, you can refer to the [Montana State University Solar Physics site].\n", - "\n", - "To further understand the factors contributing to the observed differences, additional information can be found in the research paper by [Narukage et. al. (2011)]. This paper provides valuable insights into the characteristics and behavior of the XRT instrument, which can aid in interpreting the effective area data." - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.0" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/docs/notebooks/computing_functions/temperature_response.ipynb b/docs/notebooks/computing_functions/temperature_response.ipynb deleted file mode 100644 index 33fa67055..000000000 --- a/docs/notebooks/computing_functions/temperature_response.ipynb +++ /dev/null @@ -1,384 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "651705ab", - "metadata": {}, - "source": [ - "# Temperature Response Analysis for X-Ray Telescope (XRT)" - ] - }, - { - "cell_type": "markdown", - "id": "fa939b73", - "metadata": {}, - "source": [ - "This notebook explores the temperature response of X-ray channels in the X-Ray Telescope (XRT). The temperature response provides valuable insights into how the XRT instrument detects and responds to different temperatures of X-ray emissions. By assuming a specific spectral emission model at a given date, we can investigate the behavior of the XRT channels." - ] - }, - { - "cell_type": "markdown", - "id": "cf0b72e9", - "metadata": {}, - "source": [ - "To begin the analysis, we will import the necessary packages that enable us to perform the temperature response calculations and generate visualizations." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3adc142e", - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "\n", - "import xrtpy" - ] - }, - { - "cell_type": "markdown", - "id": "aeaf3280", - "metadata": {}, - "source": [ - "Let's dive in and explore the fascinating temperature response characteristics of the XRT!" - ] - }, - { - "cell_type": "markdown", - "id": "c15461c5", - "metadata": {}, - "source": [ - "## Contents\n", - "\n", - "1. [Define a Filter Channel](#Define-a-Filter-Channel)\n", - "2. [Define Date & Time](#Define-a-date-and-time) \n", - "3. [Temperature-Response-Fundamental](#TemperatureResponseFundamental)\n", - "4. [Temperature Response Function](#Temperature-Response-function)\n", - "5. [Plot Temperature Response](#Plotting-the-Temperature-Response)" - ] - }, - { - "cell_type": "markdown", - "id": "14415906", - "metadata": {}, - "source": [ - "## Define a Filter Channel" - ] - }, - { - "cell_type": "markdown", - "id": "14a820fe", - "metadata": {}, - "source": [ - "[xrtpy- X-Ray Filter Channel]: https://xrtpy.readthedocs.io/en/latest/getting_started.html\n", - "\n", - "A filter channel is defined by its common abbreviation, which represents a specific type of filter used to modify the X-ray radiation passing through. In this example, we will explore the carbon-on-polyimide filter (abbreviated as \"C-poly\").\n", - "\n", - "For detailed information about various filter channels and their characteristics, you can refer to the [xrtpy- X-Ray Filter Channel] section.\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "745b98ae", - "metadata": {}, - "outputs": [], - "source": [ - "filter_ = \"C-poly\"" - ] - }, - { - "cell_type": "markdown", - "id": "f1dba447", - "metadata": {}, - "source": [ - "## Define a date and time" - ] - }, - { - "cell_type": "markdown", - "id": "9434fb73", - "metadata": {}, - "source": [ - "[sunpy-time]: https://docs.sunpy.org/en/stable/guide/time.html\n", - "\n", - "In order to analyze the temperature response, it is necessary to specify a date and time for the analysis. The date and time can be defined together using specific string formats. To explore the data captured a year after the launch date, we will define the date and time accordingly.\n", - "\n", - "For detailed examples and further information about date and time string formats, you can refer to the [sunpy-time] documentation." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3268b4b9", - "metadata": {}, - "outputs": [], - "source": [ - "date_time = \"2007-09-22T21:59:59\"" - ] - }, - { - "cell_type": "markdown", - "id": "8a98f3d5", - "metadata": {}, - "source": [ - "## TemperatureResponseFundamental" - ] - }, - { - "cell_type": "markdown", - "id": "b113a3ef", - "metadata": {}, - "source": [ - "The `TemperatureResponseFundamental` object is a crucial component that provides all the necessary functions and properties for calculating the temperature response in our analysis. By referencing this object, we can access the required methods and attributes for further calculations.\n", - "\n", - "To create a `TemperatureResponseFundamental` object, you need to provide the defined filter channel (`Filter`) and the desired date and time (`date_time`). Additionally, you can specify the abundance model of interest, such as `Photospheric`, which influences the temperature response calculations.\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d8a24315", - "metadata": {}, - "outputs": [], - "source": [ - "Temperature_Response_Fundamental = xrtpy.response.TemperatureResponseFundamental(\n", - " filter_, date_time, abundance_model=\"Photospheric\"\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "453dbe8c", - "metadata": {}, - "source": [ - "## Temperature Response function" - ] - }, - { - "cell_type": "markdown", - "id": "f56c4b89", - "metadata": {}, - "source": [ - "\n", - "To calculate the temperature response, simply call the `temperature_response()` function on the `Temperature_Response_Fundamental` object. This function utilizes the specified filter, date, and abundance model to generate the temperature response as a result.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5dc098fd", - "metadata": {}, - "outputs": [], - "source": [ - "temperature_response = Temperature_Response_Fundamental.temperature_response()" - ] - }, - { - "cell_type": "markdown", - "id": "07a2b8ed", - "metadata": {}, - "source": [ - "[astropy-quantity]: https://docs.astropy.org/en/stable/api/astropy.units.quantity.Quantity.html\n", - "\n", - "[astropy.units]: https://docs.astropy.org/en/stable/units/index.html\n", - "\n", - "The `temperature_response()` function returns the temperature response for the selected filter, date, and time. The returned value is an [astropy-quantity] object with associated [astropy.units]." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0961f9e5", - "metadata": {}, - "outputs": [], - "source": [ - "print(\"Temperature Response:\\n\", temperature_response)" - ] - }, - { - "cell_type": "markdown", - "id": "b94ac326", - "metadata": {}, - "source": [ - "## Plotting the Temperature-Response" - ] - }, - { - "cell_type": "markdown", - "id": "b23d6157", - "metadata": {}, - "source": [ - "[chiantidatrbase.org]: https://www.chiantidatabase.org/\n", - "\n", - "In this section, we will visualize the temperature response by plotting the `temperature_response` function against the corresponding temperatures. It's important to note that the CHIANTI temperatures used in this plot are the temperatures of the solar plasma and are independent of the channel filter.\n", - "\n", - "The CHIANTI temperatures are stored in the `Temperature_Response_Fundamental` object and are provided in units of Kelvin (K). These temperatures serve as the independent variable for plotting the temperature response.\n", - "\n", - "By visualizing the temperature response, we can gain insights into how it varies with respect to temperature, providing a deeper understanding of the XRT channelcharacteristics.\n", - "\n", - "Additionally, if you wish to explore more details about the CHIANTI database, you can find further information at [chiantidatrbase.org].\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "bc2b0b98", - "metadata": {}, - "outputs": [], - "source": [ - "CHIANTI_temperature = Temperature_Response_Fundamental.CHIANTI_temperature" - ] - }, - { - "cell_type": "markdown", - "id": "1e5be3e3", - "metadata": {}, - "source": [ - "[numpy.log10]: https://numpy.org/doc/stable/reference/generated/numpy.log10.html\n", - "We take the log of the `CHIANTI_temperature` for plotting, which compresses the scale and enhances the visibility of the variations for lower temperatures.\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0a247d01", - "metadata": {}, - "outputs": [], - "source": [ - "log_CHIANTI_temperature = np.log10(CHIANTI_temperature.value)" - ] - }, - { - "cell_type": "markdown", - "id": "e0d954e8", - "metadata": {}, - "source": [ - "In addition, we will compare the data shortly after the spacecraft launch date with the current data. This allows us to identify any differences or variations in the temperature response over time.\n", - "\n", - "We define a new temperature response data for the launch date. The process for obtaining this data is the same as previously shown, where we specify the filter, launch date, and abundance model.\n", - "\n", - "By comparing the temperature response at the launch date with the current temperature response, we can gain insights into any changes that may have occurred over time. This comparison helps us understand the stability and evolution of the XRT." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "01876a0b", - "metadata": {}, - "outputs": [], - "source": [ - "launch_date_time = \"2006-09-22T23:59:59\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0a31f268", - "metadata": {}, - "outputs": [], - "source": [ - "launch_date_temperature_response = xrtpy.response.TemperatureResponseFundamental(\n", - " filter_, launch_date_time, abundance_model=\"Photospheric\"\n", - ").temperature_response()" - ] - }, - { - "cell_type": "markdown", - "id": "eeb2df4c", - "metadata": {}, - "source": [ - "Create a plotting function that plots the `temperature_response` versus `log_CHIANTI_temperature` for the chosen filter, date, and time. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6868a101", - "metadata": {}, - "outputs": [], - "source": [ - "def plotting_temperature_response():\n", - " plt.figure(figsize=(30, 12))\n", - "\n", - " plt.plot(\n", - " log_CHIANTI_temperature,\n", - " np.log10(temperature_response.value),\n", - " linewidth=4,\n", - " label=f\"{filter_} {date_time}\",\n", - " )\n", - " plt.plot(\n", - " log_CHIANTI_temperature,\n", - " np.log10(launch_date_temperature_response.value),\n", - " linewidth=3,\n", - " label=f\"{filter_} {launch_date_time}\",\n", - " color=\"red\",\n", - " )\n", - "\n", - " plt.title(\"XRT Temperature Response\", fontsize=30)\n", - " plt.xlabel(\"Log(T) ($K$)\", fontsize=27)\n", - " plt.ylabel(\"$DN$ $cm^5$ $ s^-1$ $pix^-1$\", fontsize=27)\n", - " plt.legend(fontsize=30)\n", - "\n", - " plt.xticks(fontsize=25)\n", - " plt.yticks(fontsize=25)\n", - "\n", - " plt.grid()\n", - " plt.show()" - ] - }, - { - "cell_type": "markdown", - "id": "967f1713", - "metadata": {}, - "source": [ - "Run `plotting_temperature_response` function to create the plot." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "9f36b383", - "metadata": {}, - "outputs": [], - "source": [ - "plotting_temperature_response()" - ] - }, - { - "cell_type": "markdown", - "id": "a116ead0", - "metadata": {}, - "source": [ - "[Montana State University Solar Physics site]: http://solar.physics.montana.edu/HINODE/XRT/xrt_contam_db.html\n", - "[Narukage et. al. (2011)]: https://doi.org/10.1007/s11207-010-9685-2 \n", - "\n", - "Plotting the temperature response at launch date and a year after highlights the differences. This is due to the contamination layer thickness on the CCD. Information about the XRT CCD contaminant layer thickness calculation can be found at [Montana State University Solar Physics site]. In addition, more information can be found referencing [Narukage et. al. (2011)]." - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.0" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/docs/notebooks/data_analysis/Deconvolving_XRT_images.ipynb b/docs/notebooks/data_analysis/Deconvolving_XRT_images.ipynb deleted file mode 100644 index 900faee7c..000000000 --- a/docs/notebooks/data_analysis/Deconvolving_XRT_images.ipynb +++ /dev/null @@ -1,120 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "1aa7ee5e", - "metadata": {}, - "source": [ - "# Using deconvolve to deconvolve images" - ] - }, - { - "cell_type": "markdown", - "id": "e3ee1e4a", - "metadata": {}, - "source": [ - "deconvolve can sharpen images using the point spread function derived for Hinode XRT " - ] - }, - { - "cell_type": "markdown", - "id": "6d3ff603", - "metadata": {}, - "source": [ - "Deconvolution is ordinarily used when wanting to remove the blurring around sharp objects or features caused by the telescope's point spread function. Here we show an example of its use for an XRT image taken during the transit of Venus in 2012. We download this data from the VSO using methods in SunPy." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4442702b", - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib.pyplot as plt\n", - "import sunpy.map\n", - "from sunpy.net import Fido\n", - "from sunpy.net import attrs as a\n", - "\n", - "from xrtpy.image_correction.deconvolve import deconvolve\n", - "\n", - "# Search for the data with a define time range and instrument\n", - "result = Fido.search(\n", - " a.Time(\"2012-06-05 21:58:39\", \"2012-06-05 21:59:00\"), a.Instrument(\"xrt\")\n", - ")\n", - "\n", - "data_file = Fido.fetch(result[0], progress=False)" - ] - }, - { - "cell_type": "markdown", - "id": "9414720e", - "metadata": {}, - "source": [ - "deconvolve takes a SunPy map as input and returns the deconvolved image and metadata as a SunPy map." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ebd15dbb", - "metadata": {}, - "outputs": [], - "source": [ - "# Create sunpy map from the fetched data\n", - "in_map = sunpy.map.Map(data_file)\n", - "\n", - "# Apply xrtpy deconvolution\n", - "out_map = deconvolve(in_map)" - ] - }, - { - "cell_type": "markdown", - "id": "3c34a2a1", - "metadata": {}, - "source": [ - "deconvolve uses the Richardson-Lucy deconvolution algorithm and takes a few optional input parameters including niter (no. of iterations to perform, 5 by default), pdf1keV (to use the point spread function defined at 1.0 keV rather than the default one defined at 560 eV) and verbose (False by default). Above we just used the default settings.\n", - "\n", - "To see the effects of the deconvolution we plot both the input and output images:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "94a60a68", - "metadata": {}, - "outputs": [], - "source": [ - "# Plotting the original and deconvolved images\n", - "fig = plt.figure(figsize=(10, 5))\n", - "ax1 = fig.add_subplot(1, 2, 1, projection=in_map)\n", - "in_map.plot(axes=ax1, title=\"Original Image\")\n", - "ax2 = fig.add_subplot(1, 2, 2, projection=out_map)\n", - "out_map.plot(axes=ax2, title=\"Deconvolved Image\")\n", - "fig.subplots_adjust(wspace=0.5)\n", - "plt.show()" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.5" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/docs/notebooks/data_analysis/Remove_lightleak.ipynb b/docs/notebooks/data_analysis/Remove_lightleak.ipynb deleted file mode 100644 index b300a1e9e..000000000 --- a/docs/notebooks/data_analysis/Remove_lightleak.ipynb +++ /dev/null @@ -1,149 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "a74f630b", - "metadata": {}, - "source": [ - "# Using the `remove_lightleak` function to analyze XRT composite images" - ] - }, - { - "cell_type": "markdown", - "id": "1ad4f399", - "metadata": {}, - "source": [ - "The `remove_lightleak` function is built to subtract light leak (visible stray light) image from XRT synoptic composite images. Level two synoptic composite image data is available at [xrt.cfa.harvard.edu](https://xrt.cfa.harvard.edu/data_products/index.php). This template will guide you through the method of using `remove_lightleak`." - ] - }, - { - "cell_type": "markdown", - "id": "5dfaf58c", - "metadata": {}, - "source": [ - "Begin by importing `remove_lightleak` function from XRTpy." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "bc3b75d9", - "metadata": {}, - "outputs": [], - "source": [ - "from pathlib import Path\n", - "\n", - "import sunpy.map" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "57a48df5", - "metadata": {}, - "outputs": [], - "source": [ - "from astropy.utils.data import get_pkg_data_path\n", - "\n", - "from xrtpy.image_correction.remove_lightleak import remove_lightleak" - ] - }, - { - "cell_type": "markdown", - "id": "afe208c1", - "metadata": {}, - "source": [ - "This example will be using XRT synoptic data from the first day of summer of 2015." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d9e2a205", - "metadata": {}, - "outputs": [], - "source": [ - "directory = get_pkg_data_path(\"example_data\", package=\"xrtpy.image_correction.data\")\n", - "data_file = Path(directory) / \"comp_XRT20150621_055911.7.fits\"\n", - "\n", - "print(\"File used:\\n\", data_file.name)" - ] - }, - { - "cell_type": "markdown", - "id": "1d1c92c7", - "metadata": {}, - "source": [ - "Take on [`sunpy.map.Map`](https://docs.sunpy.org/en/stable/code_ref/map.html) to run the composite data file." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e2a1f65c", - "metadata": {}, - "outputs": [], - "source": [ - "in_map = sunpy.map.Map(data_file)" - ] - }, - { - "cell_type": "markdown", - "id": "e1b239db", - "metadata": {}, - "source": [ - "The `remove_lightleak` function takes a [`sunpy.map.Map`](https://docs.sunpy.org/en/stable/code_ref/map.html) as input and returns the composite image and metadata as a `Map`." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6144be5e", - "metadata": {}, - "outputs": [], - "source": [ - "out_map = remove_lightleak(in_map)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "bc66b8e2", - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib.pyplot as plt\n", - "from matplotlib.colors import LogNorm\n", - "\n", - "fig = plt.figure()\n", - "ax1 = fig.add_subplot(1, 2, 1, projection=in_map)\n", - "in_map.plot(axes=ax1, title=\"Original Image\", norm=LogNorm(1.0, None))\n", - "ax2 = fig.add_subplot(1, 2, 2, projection=out_map)\n", - "out_map.plot(axes=ax2, title=\"Light Leak Subtracted Image\", norm=LogNorm(1.0, None))\n", - "fig.subplots_adjust(wspace=0.5)\n", - "plt.show()" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.5" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/docs/notebooks/data_analysis/Temperature_using_composites.ipynb b/docs/notebooks/data_analysis/Temperature_using_composites.ipynb deleted file mode 100644 index 98e9f7cdf..000000000 --- a/docs/notebooks/data_analysis/Temperature_using_composites.ipynb +++ /dev/null @@ -1,156 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "84f543ec", - "metadata": {}, - "source": [ - "# Deriving temperatures using composite images and the filter ratio method" - ] - }, - { - "cell_type": "markdown", - "id": "210dadd6", - "metadata": {}, - "source": [ - "The `temperature_from_filter_ratio` routine in XTRpy derives the temperature and emission measure in XRT images by using two images taken at nearly the same time but using different filters. When doing this you can use standard XRT Level 1 data files or you can use \"composite\" images. Composite images are created from two or three images taken sequentially with the same pointing and filter but with different exposure times. Generally one wants to use either a long and short pair of exposures or a long-medium-short triple of exposures. Such composite images are made routinely for the synoptic archive of Hinode. The idea behind composite images is that pixels in the image that are saturated in the long exposure are replaced by pixels from the short (or medium) exposure that are not saturated and thus create an image with a greater dynamic range than you would get with a single image." - ] - }, - { - "cell_type": "markdown", - "id": "a2a60e43", - "metadata": {}, - "source": [ - "We start by importing `temperature_from_filter_ratio`." - ] - }, - { - "cell_type": "markdown", - "id": "03904c0f", - "metadata": {}, - "source": [ - "To use composite images, we need to generate their exposure maps, which are images where each pixel value is the exposure time of the image from which the pixel came. Most of the pixels will generally be from the long exposure image, but for the brightest part of the image, the pixels will come from the medium or short exposure image that was used to generate the composite image. The composite images that we'll use can be downloaded from the XRT archive." - ] - }, - { - "cell_type": "markdown", - "id": "93c47f6b", - "metadata": {}, - "source": [ - "For this example, we will use the `download_file` utility from `astropy` to download the composite files. We also use the routine `filename2repo_path` from `XRTpy` to find the correct URL for each file to be downloaded." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ef4d8a39", - "metadata": {}, - "outputs": [], - "source": [ - "from astropy.utils.data import download_file\n", - "\n", - "from xrtpy.response.temperature_from_filter_ratio import temperature_from_filter_ratio\n", - "from xrtpy.util.filename2repo_path import filename2repo_path\n", - "\n", - "filename1 = \"comp_XRT20210730_175810.1.fits\"\n", - "filename2 = \"comp_XRT20210730_175831.6.fits\"\n", - "url1 = filename2repo_path(filename1, join=True)\n", - "url2 = filename2repo_path(filename2, join=True)\n", - "# These files will go under your astropy cache directory, typically ~/.astropy/cache/download/url/\n", - "file1 = download_file(url1, allow_insecure=True)\n", - "file2 = download_file(url2, allow_insecure=True)" - ] - }, - { - "cell_type": "markdown", - "id": "51b1846e", - "metadata": {}, - "source": [ - "Then we need to calculate the exposure maps, which will be used with `temperature_from_filter_ratio`." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "74e3e2d1", - "metadata": {}, - "outputs": [], - "source": [ - "from xrtpy.util.make_exposure_map import make_exposure_map\n", - "\n", - "expmap1 = make_exposure_map(file1)\n", - "expmap2 = make_exposure_map(file2)" - ] - }, - { - "cell_type": "markdown", - "id": "a6374f89", - "metadata": {}, - "source": [ - "Note that each call to this routine will result in more files being downloaded. Now we are ready to call `temperature_from_filter_ratio`. This routine takes Sunpy maps as input (not related to exposure maps)." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "78cc7ab9", - "metadata": {}, - "outputs": [], - "source": [ - "from sunpy.map import Map\n", - "\n", - "map1 = Map(file1)\n", - "map2 = Map(file2)\n", - "T_EM = temperature_from_filter_ratio(map1, map2, expmap1=expmap1, expmap2=expmap2)" - ] - }, - { - "cell_type": "markdown", - "id": "49ec6f18", - "metadata": {}, - "source": [ - "`temperature_from_filter_ratio` returns a named tuple of maps: Tmap, EMmap, Terrmap, EMerrmap. To make a nice looking plot, we use `matplotlib`." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4d3fd2bd", - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib.pyplot as plt\n", - "\n", - "fig = plt.figure()\n", - "T_e = T_EM.Tmap\n", - "m = Map(10.0**T_e.data, T_e.meta)\n", - "m.plot(vmin=8.0e5, vmax=3.0e6, cmap=\"turbo\")\n", - "m.draw_limb()\n", - "m.draw_grid()\n", - "cb = plt.colorbar()\n", - "plt.show()" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.5" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/docs/notebooks/data_analysis/Using_temperature_from_filter_ratio.ipynb b/docs/notebooks/data_analysis/Using_temperature_from_filter_ratio.ipynb deleted file mode 100644 index fa5501a59..000000000 --- a/docs/notebooks/data_analysis/Using_temperature_from_filter_ratio.ipynb +++ /dev/null @@ -1,257 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "642ac1b3", - "metadata": {}, - "source": [ - "# Using temperature_from_filter_ratio to analyze XRT data" - ] - }, - { - "cell_type": "markdown", - "id": "22b53fce", - "metadata": {}, - "source": [ - "This example demonstrates how to use the `temperature_from_filter_ratio` function from `xrtpy` to calculate the XRT temperature and emission measure in an image using the filter ratio method.\n", - "\n", - "**Note**: To run this example, you need additional dependencies. If you installed `xrtpy` from pip, you might need to install `sunpy[net]` separately. You can do this by running:\n", - "\n", - "```pip install sunpy[net]```" - ] - }, - { - "cell_type": "markdown", - "id": "f5f04496", - "metadata": {}, - "source": [ - "First we need to import `temperature_from_filter_ratio`." - ] - }, - { - "cell_type": "markdown", - "id": "8aee2bae", - "metadata": {}, - "source": [ - "As an example we will use the test data included in XRTpy, though data with the right characteristics in the XRT archive could also be used. It's necessary to use two images that are the same size and different filters. To get good results the images should have been taken close in time as well, ideally adjacent in time. Note that not all filter ratios produce good results. \n", - "\n", - "This data was generated using the IDL routine xrt_prep.pro from SolarSoft and is unnormalized. Data in the Level 1 archive are normalized, which is also okay to use, though the IDL routine `xrt_teem.pro` did not allow that. For normalized data the image data is multiplied by the exposure time before analysis. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b0dbae75", - "metadata": {}, - "outputs": [], - "source": [ - "import sunpy.map\n", - "from sunpy.net import Fido\n", - "from sunpy.net import attrs as a\n", - "\n", - "from xrtpy.response.temperature_from_filter_ratio import temperature_from_filter_ratio" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "da83268f", - "metadata": {}, - "outputs": [], - "source": [ - "result = Fido.search(\n", - " a.Time(\"2011-01-28 01:31:55\", \"2011-01-28 01:32:05\"), a.Instrument(\"xrt\")\n", - ")\n", - "\n", - "data_files = Fido.fetch(result, progress=False)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "681f4be1", - "metadata": {}, - "outputs": [], - "source": [ - "file1 = data_files[1]\n", - "file2 = data_files[0]\n", - "print(\"Files used:\\n\", file1, \"\\n\", file2)" - ] - }, - { - "cell_type": "markdown", - "id": "35dd0c83", - "metadata": {}, - "source": [ - "[Sunpy maps]:https://docs.sunpy.org/en/stable/code_ref/map.html\n", - "\n", - "`temperature_from_filter_ratio` uses [Sunpy maps] as input. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "48ac4220", - "metadata": {}, - "outputs": [], - "source": [ - "map1 = sunpy.map.Map(file1)\n", - "map2 = sunpy.map.Map(file2)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "20f21153", - "metadata": {}, - "outputs": [], - "source": [ - "print(\n", - " map1.fits_header[\"TELESCOP\"],\n", - " map1.fits_header[\"INSTRUME\"],\n", - ")\n", - "print(\n", - " \"\\n File 1 used:\\n\",\n", - " file1,\n", - " \"\\n Observation date:\",\n", - " map1.fits_header[\"DATE_OBS\"],\n", - " map1.fits_header[\"TIMESYS\"],\n", - " \"\\n Filter Wheel 1:\",\n", - " map1.fits_header[\"EC_FW1_\"],\n", - " map1.fits_header[\"EC_FW1\"],\n", - " \"\\n Filter Wheel 2:\",\n", - " map1.fits_header[\"EC_FW2_\"],\n", - " map1.fits_header[\"EC_FW2\"],\n", - " \"\\n Dimension:\",\n", - " map1.fits_header[\"NAXIS1\"],\n", - " map1.fits_header[\"NAXIS1\"],\n", - ")\n", - "\n", - "print(\n", - " \"\\nFile 2 used:\\n\",\n", - " file2,\n", - " \"\\n Observation date:\",\n", - " map2.fits_header[\"DATE_OBS\"],\n", - " map2.fits_header[\"TIMESYS\"],\n", - " \"\\n Filter Wheel 1:\",\n", - " map2.fits_header[\"EC_FW1_\"],\n", - " map2.fits_header[\"EC_FW1\"],\n", - " \"\\n Filter Wheel 2:\",\n", - " map2.fits_header[\"EC_FW2_\"],\n", - " map2.fits_header[\"EC_FW2\"],\n", - " \"\\n Dimension:\",\n", - " map2.fits_header[\"NAXIS1\"],\n", - " map2.fits_header[\"NAXIS1\"],\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "905f4e11", - "metadata": {}, - "source": [ - "The `temperature_from_filter_ratio` function has several options, mirroring the IDL routine xrt_teem.pro in SolarSoft in most respects. A simple call with no extra parameters calculates the temperature and (volume) emission measure for the two images without any binning or masking of the data." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ddc9862b", - "metadata": {}, - "outputs": [], - "source": [ - "T_EM = temperature_from_filter_ratio(map1, map2)\n", - "T_e = T_EM.Tmap" - ] - }, - { - "cell_type": "markdown", - "id": "d0ef85f3", - "metadata": {}, - "source": [ - "The output of `temperature_from_filter_ratio` is a namedtuple of SunPy maps with attributes `Tmap`, `EMmap`, `Terrmap`, and `EMerrmap`. As with the SolarSoft IDL routine xrt_teem.pro, the output images are logs of the quantities. `Tmap.data` is the electron temperature, `EMmap.data` is the volume emission measure, `Terrmap.data` is a measure of the uncertainties in the temperature determined for each pixel and `EMerrmap.data` is the same for the emission measure. Each map has data and associated metadata. To examine the results one can use `matplotlib` and `sunpy`:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3ae1f53b", - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "from sunpy.coordinates.sun import B0, angular_radius\n", - "from sunpy.map import Map\n", - "\n", - "# To avoid error messages from sunpy we add metadata to the header:\n", - "rsun_ref = 6.95700e08\n", - "hdr1 = map1.meta\n", - "rsun_obs = angular_radius(hdr1[\"DATE_OBS\"]).value\n", - "dsun = rsun_ref / np.sin(rsun_obs * np.pi / 6.48e5)\n", - "solarb0 = B0(hdr1[\"DATE_OBS\"]).value\n", - "hdr1[\"DSUN_OBS\"] = dsun\n", - "hdr1[\"RSUN_REF\"] = rsun_ref\n", - "hdr1[\"RSUN_OBS\"] = rsun_obs\n", - "hdr1[\"SOLAR_B0\"] = solarb0\n", - "\n", - "fig = plt.figure()\n", - "# We could create a plot simply by doing T_e.plot(), but here we choose to make a linear plot of T_e\n", - "m = Map((10.0**T_e.data, T_e.meta))\n", - "m.plot(title=\"Derived Temperature\", vmin=2.0e6, vmax=1.2e7, cmap=\"turbo\")\n", - "m.draw_limb()\n", - "m.draw_grid(linewidth=2)\n", - "cb = plt.colorbar(label=\"T (K)\")" - ] - }, - { - "cell_type": "markdown", - "id": "4e069966", - "metadata": {}, - "source": [ - "See the temperature_from_filter_ratio.py script for more information. Among the options are verbose output, binning the data by an integer factor (to increase the signal to noise), specifying a temperature range to examine, providing a mask for excluding regions of the images from the analysis, and setting error thresholds on the temperature and photon noise that differ from the default values." - ] - }, - { - "cell_type": "markdown", - "id": "94df8fee", - "metadata": {}, - "source": [ - "[Narukage et al. (2014, Solar Phys. 289, 1029)]:https://xrtpy.readthedocs.io/en/stable/bibliography.html\n", - "[Guidoni et al. (2015, ApJ 800, 54)]:https://xrtpy.readthedocs.io/en/stable/bibliography.html\n", - "\n", - "\n", - "These data were analyzed by [Guidoni et al. (2015, ApJ 800, 54)]. See also [Narukage et al. (2014, Solar Phys. 289, 1029)]. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "9fb5dcfa-f5c8-4a80-bf8e-442afe4916b6", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.5" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/docs/notebooks/getting_started/A_Practical_Guide_to_Data_Extraction_and_Visualization.ipynb b/docs/notebooks/getting_started/A_Practical_Guide_to_Data_Extraction_and_Visualization.ipynb deleted file mode 100644 index 1d41d727d..000000000 --- a/docs/notebooks/getting_started/A_Practical_Guide_to_Data_Extraction_and_Visualization.ipynb +++ /dev/null @@ -1,1176 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "5889d1e9", - "metadata": {}, - "source": [ - "[Hinode X-Ray Telescope]:https://xrt.cfa.harvard.edu/\n", - "\n", - "# Hinode-XRT: A Practical Guide to Data Extraction and Visualization\n", - "\n", - "This notebook provides a step-by-step guide on how to download, process, and visualize solar observation data from the [Hinode X-Ray Telescope], making it accessible for research and analysis.\n", - "\n", - "*Created by Joy Velasquez. Version 1 - February 29, 2024*" - ] - }, - { - "cell_type": "markdown", - "id": "2c79b374", - "metadata": {}, - "source": [ - "## Introduction\n", - "\n", - "This notebook is designed as a preliminary guide to handle solar observation data specifically from the Hinode X-Ray Telescope (XRT). While this example does not directly utilize `xrtpy` functionalities, it lays the groundwork for handling and understanding XRT data, which can be further processed and analyzed using `xrtpy`.\n", - "\n", - "Here's what we'll cover:\n", - "- **Downloading XRT Data**: Step-by-step instructions to download XRT data for a specified period of interest.\n", - "- **Data Filtering**: Use custom functions for filtering and refining the downloaded data.\n", - "- **Visualization and Movie Creation**: Explore methods to visualize the data and compile it into movie format, providing a dynamic view of solar observations.\n", - "\n", - "Whether for research analysis or as a stepping stone to using `xrtpy` for more advanced applications, this guide aims to equip you with the fundamental skills necessary for effective data manipulation and visualization in solar physics. \n" - ] - }, - { - "cell_type": "markdown", - "id": "99e5293f", - "metadata": {}, - "source": [ - "## Table of Contents\n", - "1. [Importing Necessary Packages](#importing-necessary-packages)\n", - "2. [Using Fido to Search and Download XRT Data](#using-fido-to-search-and-download-xrt-data)\n", - "3. [Inspecting the Downloaded Data](#inspecting-the-downloaded-data)\n", - "4. [Exploring Functions to Enhance Data Quality](#exploring-functions-to-enhance-data-quality)\n", - " - 4.1 [Filtering FITS Files Through Selected Filter](#filtering-fits-files-through-selected-filter)\n", - " - 4.2 [Filtering FITS Files Through Pixel Size](#filtering-fits-files-through-pixel-size)\n", - " - 4.3 [Filtering FITS Files by Exposure Time](#filtering-fits-files-by-exposure-time)\n", - "5. [Navigating FITS Images](#navigating-fits-images)\n", - "6. [Removing Unwanted FITS Files](#removing-unwanted-fits-files)\n", - "7. [Visualizing Solar Dynamics by Creating a Movie from XRT FITS Data](#visualizing-solar-dynamics-by-creating-a-movie-from-xrt-fits-data)\n" - ] - }, - { - "cell_type": "markdown", - "id": "b8c49bf6", - "metadata": {}, - "source": [ - "### Importing Necessary Packages" - ] - }, - { - "cell_type": "markdown", - "id": "76671fc6", - "metadata": {}, - "source": [ - "Before we begin, let's import all the necessary Python packages and modules required for this notebook. Key packages include:\n", - "\n", - "- `sunpy`: An open-source Python library for Solar Physics data analysis.\n", - "- `matplotlib`: A library for creating static, animated, and interactive visualizations in Python.\n", - "- `astropy`: Used for astronomy and astrophysics data processing.\n", - "\n", - "These packages, among others, will enable us to download, inspect, filter, and visualize the XRT data effectively.\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "cbbd8a2d", - "metadata": {}, - "outputs": [], - "source": [ - "# Standard library imports for file and temporary directory management\n", - "import os\n", - "import tempfile\n", - "\n", - "# Counting occurrences of unique elements\n", - "# creating and managing images and videos\n", - "import imageio\n", - "import ipywidgets as widgets\n", - "import matplotlib.pyplot as plt\n", - "\n", - "# SunPy library for solar physics data analysis\n", - "import sunpy.map\n", - "\n", - "# Astropy units module for handling physical quantities\n", - "from astropy import units as u\n", - "\n", - "# IPython and ipywidgets for interactive widgets in the notebook\n", - "from IPython.display import (\n", - " Video, # For embedding videos in the notebook\n", - " clear_output,\n", - " display,\n", - ")\n", - "\n", - "# SunPy modules for querying and downloading solar data\n", - "from sunpy.net import Fido\n", - "from sunpy.net import attrs as a\n", - "\n", - "# #******************************************\n", - "# #Command to ensure necessary libraries are installed (uncomment and run if needed)\n", - "# !pip install sunpy matplotlib imageio ipywidgets\n", - "# #******************************************" - ] - }, - { - "cell_type": "markdown", - "id": "b5ef5aa9", - "metadata": {}, - "source": [ - "\n", - "## Using Fido to Search and Download XRT Data" - ] - }, - { - "cell_type": "markdown", - "id": "2420734d", - "metadata": {}, - "source": [ - "[SunPy]:https://sunpy.org/\n", - "[Fido]:https://docs.sunpy.org/en/stable/generated/api/sunpy.net.Fido.html#sunpy.net.Fido\n", - "\n", - "### Searching for Hinode XRT Data\n", - "\n", - "[Fido] is a unified interface provided by [SunPy] for querying and downloading data across various solar physics data sources and missions. In this section, we'll focus on using Fido to find and retrieve data from the Hinode X-Ray Telescope (XRT).\n", - "\n", - "We'll walk through the process of defining a search query, which includes specifying a time range and selecting the instrument, to fetch targeted datasets effectively. " - ] - }, - { - "cell_type": "markdown", - "id": "107d208b", - "metadata": {}, - "source": [ - "In this section, we'll focus on the observation of [Active Region (AR) 13234](https://www.solarmonitor.org/region_pop.php?date=20230223&type=hxrt_flter®ion=13234) by Hinode-XRT. Recorded on May 21, 2023, around 18:51 UT, this region, located near the solar limb, showcased active flaring activities, presenting an intriguing case for study.\n", - "\n", - "For those interested in further exploring flare activities observed by the Hinode mission, the [XRT Flare Catalog](https://xrt.cfa.harvard.edu/flare_catalog/) offers a comprehensive database.\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e05834db", - "metadata": {}, - "outputs": [], - "source": [ - "# Define the time range of interest for solar observations\n", - "time_range = a.Time(\"2021-05-21 18:51:00\", \"2021-05-22 01:59:54\")\n", - "\n", - "# Specify the instrument as 'xrt' to search for Hinode X-Ray Telescope data\n", - "instrument = a.Instrument(\"xrt\")\n", - "\n", - "\n", - "# This will return a catalog of available XRT data during the specified period\n", - "xrt_downloaded_files = Fido.search(time_range, instrument)\n", - "\n", - "# Display the search results\n", - "print(xrt_downloaded_files)" - ] - }, - { - "cell_type": "markdown", - "id": "af5e9f4d", - "metadata": {}, - "source": [ - "#### Downloading Hinode XRT Data Using `Fido.fetch`\n", - "\n", - "Having identified the desired Hinode XRT data with `Fido.search`, we proceed to download the datasets using the `Fido.fetch` function. This function accepts the search results as its input and facilitates the data download to a designated directory on your local system.\n", - "\n", - "In the next code cell, we illustrate the utilization of `Fido.fetch` to procure our previously identified data. This demonstration includes specifying a target directory for the downloads. Additionally, we'll introduce handling techniques for managing the download outputs.\n", - "\n", - "**Note**: If no directory is specified, `Fido.fetch` defaults to downloading files to a SunPy-managed directory. You can customize the download location by providing a path to the `path` parameter of `Fido.fetch`.\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6c241846", - "metadata": { - "scrolled": false - }, - "outputs": [], - "source": [ - "# Note: Depending on the amount of data and network speed, this process can take some time.\n", - "# The `progress` parameter in `Fido.fetch` controls the display of the download progress bar.\n", - "# Setting `progress=False` disables the progress bar, which can be useful for cleaner output,\n", - "# especially when running this in a script or automated pipeline. By default, we keep it True\n", - "# for this interactive session to monitor the download progress.\n", - "\n", - "# This will download the files to the default SunPy data directory or a specified path.\n", - "# Replace `xrt_downloaded_files` with your search results variable if different.\n", - "xrt_files_results = Fido.fetch(xrt_downloaded_files, progress=True)\n", - "\n", - "# If you wish to specify a different download directory, you can do so by adding the `path` parameter:\n", - "# xrt_files_results = Fido.fetch(xrt_downloaded_files, path='/desired/download/directory/', progress=True)" - ] - }, - { - "cell_type": "markdown", - "id": "4dc907b5", - "metadata": {}, - "source": [ - "XRT follows standard Flexible Image Transport System ([FITS](https://fits.gsfc.nasa.gov/)) file naming conventions.\n" - ] - }, - { - "cell_type": "markdown", - "id": "22f2b99e", - "metadata": {}, - "source": [ - "\n", - "## Inspecting the Downloaded Data" - ] - }, - { - "cell_type": "markdown", - "id": "33d78610", - "metadata": {}, - "source": [ - "Once the download is complete, it's important to inspect the data to ensure that what we have collected is suitable for our analysis. This step involves checking the basic information about the downloaded files, such as their names, file sizes, and data types. This information can help us verify that the download was successful and that we have the correct data for our project.\n", - "\n", - "We will demonstrate practical methods to retrieve and display these details using Python's standard utilities along with SunPy-specific functions." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "66441923", - "metadata": {}, - "outputs": [], - "source": [ - "# total number of files downloaded using Fido\n", - "num_files = len(xrt_files_results)\n", - "print(f\"Number of files downloaded: {num_files}\")\n", - "\n", - "# few examples of file names to understand the naming convention\n", - "print(\"\\nSample file names:\")\n", - "for file in xrt_files_results[:5]:\n", - " print(file)\n", - "\n", - "# Example of inspecting a single file from the downloaded dataset\n", - "# Here, we choose a file arbitrarily (the 85th file) for inspection\n", - "sample_file_index = 84 # Adjust the index as desired\n", - "sample_data = sunpy.map.Map(xrt_files_results[sample_file_index])\n", - "\n", - "# Print information about the sample file\n", - "# This includes metadata like observation time, instrument, and data dimensions\n", - "print(f\"\\nSample data info for file number {sample_file_index + 1}:\")\n", - "print(sample_data)\n", - "\n", - "# Visualize the data from the sample file\n", - "# This step is crucial for a quick quality check and to familiarize with the data\n", - "plt.figure(figsize=(10, 8))\n", - "sample_data.peek() # 'peek' method generates a quick-look plot of the data\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "id": "bd7f1676", - "metadata": {}, - "source": [ - "Having successfully collected the Hinode-XRT data, we now have several exciting options at our disposal. We can analyze the FITS files to understand the solar phenomena, visualize the observations in image form, or even create a dynamic movie showcasing a solar event. However, we can take further step towards cleaning up some of the data we have downloaded following the *Exploring Functions to Enhance Data Quality* sections below, which is **optional**. " - ] - }, - { - "cell_type": "markdown", - "id": "f926c721", - "metadata": {}, - "source": [ - "\n", - "## Exploring Functions to Enhance Data Quality" - ] - }, - { - "cell_type": "markdown", - "id": "73757bf1", - "metadata": {}, - "source": [ - "In the following sections, I introduce a series of custom functions aimed at filtering and refining the downloaded Hinode-XRT data. These functions are designed to be user-friendly and accessible, serving as a practical toolset for both novice and experienced users. \n", - "\n", - "\n", - "\n", - "### Why Enhance Data Quality?\n", - "\n", - "The Sun, as observed by Hinode-XRT, presents dynamic and complex phenomena. Filtering the data helps isolate specific events or features, ensuring that subsequent analyses or visualizations focus on the most relevant and high-quality data. These enhancements are **optional** but highly recommended to achieve a clearer, more meaningful understanding of the solar data collected.\n" - ] - }, - { - "cell_type": "markdown", - "id": "833a6cc1", - "metadata": {}, - "source": [ - "\n", - "### Filtering FITS Files Through Selected Filter" - ] - }, - { - "cell_type": "markdown", - "id": "62e7c934", - "metadata": {}, - "source": [ - "Identifying the type of data contained within Hinode XRT FITS files can be challenging, as the file titles do not provide sufficient information. To address this, I have developed a function that leverages `sunpy.map` to read the header information of each FITS file. This process allows us to identify and count the unique filters present within the dataset. \n", - "\n", - "To utilize this function, simply run the provided code in the next cell. When prompted, enter your desired filter criteria. This intuitive approach enables you to effectively narrow down your dataset to include only the most relevant observations for your analysis." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "20262c07", - "metadata": {}, - "outputs": [], - "source": [ - "def normalize_string(s):\n", - " \"\"\"\n", - " Normalize a string for comparison by converting to lowercase, replacing hyphens and underscores with spaces, and removing 'open'.\n", - "\n", - " Parameters:\n", - " - s (str): The string to normalize.\n", - "\n", - " Returns:\n", - " - str: The normalized string.\n", - " \"\"\"\n", - " return (\n", - " s.lower()\n", - " .replace(\"open\", \"\")\n", - " .strip(\"- \")\n", - " .replace(\"_\", \" \")\n", - " .replace(\"-\", \" \")\n", - " .strip()\n", - " )\n", - "\n", - "\n", - "## I have plans to update this function at a later time to allow users to collect FITS for more than one filter.\n", - "\n", - "\n", - "def filter_fits_files_by_XRT_filter(fits_files):\n", - " \"\"\"\n", - " Filters FITS files by XRT filter criteria, accommodating flexible user input formats. It enhances readability and ensures valid input by normalizing filter names.\n", - "\n", - " Parameters:\n", - " - fits_files (list): List of FITS file paths.\n", - "\n", - " Returns:\n", - " - filtered_files (list): List of file paths that match the user-selected XRT channel filter.\n", - "\n", - " Raises:\n", - " - ValueError: If the user input does not match any available filter.\n", - " \"\"\"\n", - " measurement_info = {}\n", - "\n", - " for file_path in fits_files:\n", - " from sunpy.map import Map\n", - "\n", - " sunpy_map = Map(file_path)\n", - " measurement = sunpy_map.measurement\n", - " # Normalize measurement for consistent comparison\n", - " normalized_measurement = normalize_string(measurement)\n", - " if normalized_measurement in measurement_info:\n", - " measurement_info[normalized_measurement] += 1\n", - " else:\n", - " measurement_info[normalized_measurement] = 1\n", - "\n", - " # Display available filters and their counts\n", - " filters_output = \"\\n\".join(\n", - " [f\"{key.title()}: {value} files\" for key, value in measurement_info.items()]\n", - " )\n", - " print(f\"The files have the following filters and counts:\\n{filters_output}\")\n", - " filter_choice = input(\"Please select an XRT channel filter of interest: \")\n", - " normalized_filter_choice = normalize_string(filter_choice)\n", - "\n", - " # Validate user input\n", - " if normalized_filter_choice not in measurement_info:\n", - " raise ValueError(\n", - " \"Invalid filter choice. Please enter a valid XRT channel filter from the list provided.\"\n", - " )\n", - "\n", - " filtered_files = []\n", - " for file_path in fits_files:\n", - " sunpy_map = Map(file_path)\n", - " normalized_measurement = normalize_string(sunpy_map.measurement)\n", - " if normalized_filter_choice in normalized_measurement:\n", - " filtered_files.append(file_path)\n", - "\n", - " name_of_filter = filter_choice.title()\n", - " print(f\"\\nFilter choice: {name_of_filter}\")\n", - " print(\n", - " f\"You have {len(filtered_files)} FITS files that match the '{name_of_filter}' filter.\"\n", - " )\n", - " print(\"Be sure to store this data as a new variable.\")\n", - "\n", - " return filtered_files" - ] - }, - { - "cell_type": "markdown", - "id": "1539a632", - "metadata": {}, - "source": [ - "In this example, we'll be investigating the `Al-Poly` filter on the XRT. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "122165bc", - "metadata": {}, - "outputs": [], - "source": [ - "# Assuming xrt_files_results is a list of FITS file paths\n", - "# My new variable name is reflected base on the filter of interest\n", - "xrt_Al_poly_Obs_FITs = filter_fits_files_by_XRT_filter(xrt_files_results)" - ] - }, - { - "cell_type": "markdown", - "id": "942fec9e", - "metadata": {}, - "source": [ - "\n", - "### Filtering FITS Files Through Pixel Size" - ] - }, - { - "cell_type": "markdown", - "id": "f9a8251f", - "metadata": {}, - "source": [ - "Filtering Hinode XRT FITS files by pixel dimensions, measured in units of pixels (`pix`), is a practical approach to ensure data uniformity. We refer to these **dimensions** within the context of `sunpy.map.Map`.\n", - "\n", - "XRT images typically have dimensions of `[384x384, 512x512, or 1024x1024]`, although any specific area of the CCD can be read out. For comprehensive details, please refer to the [SolarSoft XRT Analysis Guide](https://xrt.cfa.harvard.edu/resources/documents/XAG/XAG.pdf).\n" - ] - }, - { - "cell_type": "markdown", - "id": "d233ee89", - "metadata": {}, - "source": [ - "The function `filter_fits_files_by_XRT_dimensions` simplifies the process of selecting FITS files based on pixel dimensions. Upon running this function, you'll encounter a prompt displaying the available dimensions within your dataset. After selecting a preferred option, the function will generate a new list of FITS files filtered according to the specified dimensions. To utilize this functionality, execute the function in the cell below and follow the instructions in the subsequent steps." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "fca60980", - "metadata": {}, - "outputs": [], - "source": [ - "def filter_fits_files_by_XRT_dimensions(fits_files):\n", - " \"\"\"\n", - " Filters FITS files by their dimensions, allowing for flexible input formatting.\n", - " Provides up to three attempts for input, with error handling for invalid formats.\n", - "\n", - " Parameters:\n", - " - fits_files (list): List of paths to the FITS files.\n", - "\n", - " Returns:\n", - " - A list of file paths that match the user-selected dimensions.\n", - " \"\"\"\n", - " dimension_counts = {}\n", - "\n", - " # Determine the unique dimensions of all FITS files and count them\n", - " for file_path in fits_files:\n", - " xrt_map = sunpy.map.Map(file_path)\n", - " # Construct a tuple for dimensions to facilitate comparison\n", - " dimensions_tuple = (xrt_map.dimensions.x.value, xrt_map.dimensions.y.value)\n", - " dimensions_str = f\"{dimensions_tuple[0]:.0f}, {dimensions_tuple[1]:.0f}\"\n", - " dimension_counts[dimensions_str] = dimension_counts.get(dimensions_str, 0) + 1\n", - "\n", - " print(\n", - " \"Unique dimensions (in pixels) found in the dataset and their counts:\\n x:pix , y:pix\"\n", - " )\n", - " for dimensions, count in sorted(dimension_counts.items()):\n", - " print(f\"{dimensions}: {count} files\")\n", - "\n", - " attempts = 0\n", - " while attempts < 3:\n", - " chosen_dimensions_str = input(\n", - " \"\\nPlease enter the dimensions of interest (e.g., '384, 384'): \"\n", - " )\n", - " try:\n", - " x_dim, y_dim = (\n", - " int(dim.strip()) for dim in chosen_dimensions_str.split(\",\")\n", - " )\n", - " chosen_dimensions_tuple = (x_dim, y_dim)\n", - " chosen_dimensions_str = (\n", - " f\"{x_dim}, {y_dim}\" # Reformatted string for comparison\n", - " )\n", - " except ValueError:\n", - " print(\"Invalid format. Please enter dimensions in the format 'X, Y'.\")\n", - " attempts += 1\n", - " continue\n", - "\n", - " # Check if the processed input matches any known dimensions\n", - " if chosen_dimensions_str in dimension_counts:\n", - " break # Valid dimension found; proceed with filtering\n", - "\n", - " print(f\"Error: '{chosen_dimensions_str}' is not a recognized dimension.\")\n", - " attempts += 1\n", - "\n", - " if attempts == 3:\n", - " print(\"\\nMaximum attempts reached. Please rerun and try again.\\n\")\n", - " return []\n", - "\n", - " filtered_files = []\n", - " for file_path in fits_files:\n", - " xrt_map = sunpy.map.Map(file_path)\n", - " if (\n", - " xrt_map.dimensions.x.value,\n", - " xrt_map.dimensions.y.value,\n", - " ) == chosen_dimensions_tuple:\n", - " filtered_files.append(file_path)\n", - "\n", - " print(\n", - " f\"\\nFound {len(filtered_files)} files matching the dimensions {chosen_dimensions_str}.\"\n", - " )\n", - " return filtered_files" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d97daba4", - "metadata": {}, - "outputs": [], - "source": [ - "# For this example, I will continue to use xrt_Al_poly_Obs_FITs. The function will prompt you to select from\n", - "# available dimensions and return a new list containing only the files that match the selected dimensions.\n", - "\n", - "\n", - "# Now, call the function with your list of FITS file paths:\n", - "xrt_Al_poly_384_Obs_FITs = filter_fits_files_by_XRT_dimensions(xrt_Al_poly_Obs_FITs)" - ] - }, - { - "cell_type": "markdown", - "id": "3d418012", - "metadata": {}, - "source": [ - "### Filtering FITS Files by Exposure Time\n", - "\n", - "Different exposure times can significantly affect the quality and the type of data captured in each image. This section introduces a method to filter your dataset based on specific exposure time criteria, allowing for a more refined and targeted analysis.\n", - "\n", - "#### Why Filter by Exposure Time?\n", - "\n", - "Filtering by exposure time can help isolate images that are best suited for your research goals. For instance, shorter exposure times might be preferred for studying rapid solar events, while longer exposures could provide deeper insights into fainter solar features. This flexibility ensures that you can tailor your dataset to include only the most relevant images.\n", - "\n", - "#### How It Works\n", - "\n", - "The `filter_fits_by_exposure_time` function enables you to specify criteria for selecting images based on their exposure times. You can choose to include images with an exact exposure time, those with exposure times within a specified range, or images with exposure times above or below a certain threshold. This functionality is designed to give you maximum control over the composition of your dataset.\n", - "\n", - "#### Key Features:\n", - "- **Exact Match**: Retrieve images with a specific exposure time by entering the exact value in seconds.\n", - "- **Range Selection**: Specify a range of exposure times to include images that fall within this interval.\n", - "- **Above or Below a Threshold**: Filter images based on whether their exposure times are above or below a specified value.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b2136b56", - "metadata": {}, - "outputs": [], - "source": [ - "def get_exposure_time_counts(fits_files):\n", - " \"\"\"\n", - " Generates a dictionary of exposure times and their counts from FITS files.\n", - "\n", - " Parameters:\n", - " - fits_files (list): List of FITS file paths.\n", - "\n", - " Returns:\n", - " - Dictionary with exposure times as keys and counts and file paths as values.\n", - " \"\"\"\n", - " exposure_time_counts = {}\n", - " for file_path in fits_files:\n", - " map_ = sunpy.map.Map(file_path)\n", - " exposure_time = round(map_.exposure_time.to(u.s).value, 2)\n", - " if exposure_time not in exposure_time_counts:\n", - " exposure_time_counts[exposure_time] = {\"count\": 1, \"files\": [file_path]}\n", - " else:\n", - " exposure_time_counts[exposure_time][\"count\"] += 1\n", - " exposure_time_counts[exposure_time][\"files\"].append(file_path)\n", - " return exposure_time_counts\n", - "\n", - "\n", - "def display_exposure_time_counts(exposure_time_counts):\n", - " \"\"\"\n", - " Displays the exposure times and their counts.\n", - "\n", - " Parameters:\n", - " - exposure_time_counts (dict): Dictionary of exposure times and their counts.\n", - " \"\"\"\n", - " print(\"Exposure times in the dataset (in seconds) and their counts:\")\n", - " for time, info in exposure_time_counts.items():\n", - " print(f\"{time}s: {info['count']} file(s)\")\n", - "\n", - "\n", - "def filter_files_by_criteria(exposure_time_counts, criteria):\n", - " \"\"\"\n", - " Filters FITS files based on user-specified exposure time criteria.\n", - "\n", - " Parameters:\n", - " - exposure_time_counts (dict): Dictionary of exposure times and their counts.\n", - " - criteria (str): User-specified exposure time criteria.\n", - "\n", - " Returns:\n", - " - List of FITS file paths that match the exposure time criteria.\n", - " \"\"\"\n", - " filtered_files = []\n", - " if \"-\" in criteria:\n", - " lower, upper = map(float, criteria.split(\"-\"))\n", - " for time, info in exposure_time_counts.items():\n", - " if lower <= time <= upper:\n", - " filtered_files.extend(info[\"files\"])\n", - " elif criteria.startswith(\"<\"):\n", - " max_time = float(criteria[1:])\n", - " for time, info in exposure_time_counts.items():\n", - " if time < max_time:\n", - " filtered_files.extend(info[\"files\"])\n", - " elif criteria.startswith(\">\"):\n", - " min_time = float(criteria[1:])\n", - " for time, info in exposure_time_counts.items():\n", - " if time > min_time:\n", - " filtered_files.extend(info[\"files\"])\n", - " else:\n", - " exact_time = float(criteria)\n", - " for time, info in exposure_time_counts.items():\n", - " if time == exact_time:\n", - " filtered_files.extend(info[\"files\"])\n", - " return filtered_files\n", - "\n", - "\n", - "def filter_fits_by_exposure_time(fits_files):\n", - " \"\"\"\n", - " Filters FITS files based on exposure time criteria specified by the user.\n", - "\n", - " Parameters:\n", - " - fits_files (list): List of FITS file paths.\n", - "\n", - " Returns:\n", - " - List of FITS file paths that match the exposure time criteria.\n", - " \"\"\"\n", - " exposure_time_counts = get_exposure_time_counts(fits_files)\n", - " display_exposure_time_counts(exposure_time_counts)\n", - " criteria = input(\n", - " \"\\nEnter the exposure time criteria (e.g., '0.36' for exactly 0.36s, '<1.5' for less than 1.5s, '>1.5' for more than 1.5s, '2-120' for between 2s and 120s): \"\n", - " )\n", - " print(\"\\nSelected exposure time(s):\", criteria)\n", - " filtered_files = filter_files_by_criteria(exposure_time_counts, criteria)\n", - " print(f\"\\nFound {len(filtered_files)} files matching the criteria.\")\n", - " return filtered_files" - ] - }, - { - "cell_type": "markdown", - "id": "e6364f7e", - "metadata": {}, - "source": [ - "To use the `filter_fits_by_exposure_time` function, simply run the provided code with your list of FITS files. You will then be prompted to enter your exposure time criteria. The function will process your request and return a filtered list of FITS files that match your specified criteria, making it easier to proceed with a more focused analysis." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "bee020c3", - "metadata": {}, - "outputs": [], - "source": [ - "# In this example we're using the filtered Al-Poly Filter & 384 by 384 pixels FITS\n", - "xrt_Al_poly_384_Obs_FITs_fixed_exposure_time = filter_fits_by_exposure_time(\n", - " xrt_Al_poly_384_Obs_FITs\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "45351527", - "metadata": {}, - "source": [ - "## Navigating FITS Images " - ] - }, - { - "cell_type": "markdown", - "id": "486afe2b", - "metadata": {}, - "source": [ - "Now, we have the capability to review images within our curated list of filtered FITS files. This enhanced navigation functionality not only facilitates sequential browsing but also introduces the ability to directly access a specific image within the dataset. Such a feature is invaluable for evaluating your dataset in detail, allowing you to identify and exclude FITS files that may not be relevant to your analysis or contain poor-quality images captured by the XRT." - ] - }, - { - "cell_type": "markdown", - "id": "cfde7c27", - "metadata": {}, - "source": [ - "Using the `view_fits_images` function, you can move forward or backward through the image dataset or jump to an image directly navigate to a specific image by entering its number in the dataset. This feature is particularly useful when dealing with large datasets, as it enables quick access to images of interest without the need to sequentially skim through potentially hundreds of files. Whether you're looking for a particular phase of a solar event or need to examine the quality of specific images, this tool enhances your workflow by making data access more efficient and user-friendly." - ] - }, - { - "cell_type": "markdown", - "id": "a8e58fd2", - "metadata": {}, - "source": [ - "You may find the need to remove certain images or FITS data that are not relevant or of poor quality for your analysis. To facilitate this, maintain a list with either the index numbers or the titles of the FITS files. This metadata is readily available each time you view an image in the dataset. In a later section titled **Removing-unwanted-FITS-Files**, we will introduce functions designed specifically for cleaning your dataset, leveraging the list you've compiled during the review process." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5304a6e7", - "metadata": {}, - "outputs": [], - "source": [ - "def view_fits_images(fits_files):\n", - " \"\"\"\n", - " Displays FITS images one at a time with navigation buttons and an option to jump to a specific image.\n", - "\n", - " Parameters:\n", - " - fits_files (list): List of paths to the FITS files.\n", - " \"\"\"\n", - "\n", - " current_index = [0] # Use a list to allow modifications from inner functions\n", - "\n", - " def show_image(index=None):\n", - " \"\"\"Displays the image at the current index and clears the previous output.\"\"\"\n", - " if index is not None:\n", - " # Safely update the current index based on user input\n", - " current_index[0] = max(0, min(index, len(fits_files) - 1))\n", - "\n", - " clear_output(wait=True) # Clear the previous image and controls\n", - " display(\n", - " widgets.HBox([prev_button, next_button, jump_input, jump_button])\n", - " ) # Redisplay the controls\n", - "\n", - " fits_path = fits_files[current_index[0]]\n", - " sunpy_map = sunpy.map.Map(fits_path)\n", - "\n", - " # Display FITS file name and image counter\n", - " print(\n", - " f\"File: {fits_path.split('/')[-1]} (Image {current_index[0] + 1} of {len(fits_files)})\"\n", - " )\n", - "\n", - " plt.figure(figsize=(6, 6))\n", - " sunpy_map.plot()\n", - " plt.show()\n", - "\n", - " update_buttons_status()\n", - "\n", - " def go_next():\n", - " \"\"\"Go to the next image.\"\"\"\n", - " if current_index[0] < len(fits_files) - 1:\n", - " current_index[0] += 1\n", - " show_image()\n", - "\n", - " def go_prev():\n", - " \"\"\"Go to the previous image.\"\"\"\n", - " if current_index[0] > 0:\n", - " current_index[0] -= 1\n", - " show_image()\n", - "\n", - " def jump_to_image():\n", - " \"\"\"Jump to the image number entered by the user.\"\"\"\n", - " try:\n", - " index = int(jump_input.value) - 1 # Convert to 0-based index\n", - " show_image(index)\n", - " except ValueError:\n", - " print(\"Please enter a valid image number.\")\n", - "\n", - " def update_buttons_status():\n", - " \"\"\"Updates the status of next/prev buttons based on the current index.\"\"\"\n", - " next_button.disabled = current_index[0] >= len(fits_files) - 1\n", - " prev_button.disabled = current_index[0] <= 0\n", - "\n", - " # Create navigation buttons\n", - " next_button = widgets.Button(description=\"Next\")\n", - " prev_button = widgets.Button(description=\"Previous\")\n", - " next_button.on_click(go_next)\n", - " prev_button.on_click(go_prev)\n", - "\n", - " # Create jump to image widgets\n", - " jump_input = widgets.Text(\n", - " description=\"Jump to Image:\", placeholder=\"Enter image number\"\n", - " )\n", - " jump_button = widgets.Button(description=\"Go\")\n", - " jump_button.on_click(jump_to_image)\n", - "\n", - " # Initially display buttons and the first image\n", - " display(widgets.HBox([prev_button, next_button, jump_input, jump_button]))\n", - " show_image()" - ] - }, - { - "cell_type": "markdown", - "id": "92a92fbc", - "metadata": {}, - "source": [ - "### Simple and Intuitive Use\n", - "\n", - "To navigate through your FITS images dataset:\n", - "\n", - "1. **Navigation**: Use the \"Next\" or \"Previous\" buttons to move sequentially through your dataset, one image at a time.\n", - "2. **Direct Jump**: If you want to view a specific image, enter its number in the \"Jump to Image\" field and click \"Go\". The image number should correspond to its sequential position in your list of FITS files, allowing direct and straightforward access to any image in your dataset.\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "9a83991e", - "metadata": {}, - "outputs": [], - "source": [ - "# We're going to use our filtered FITS data set: xrt_Al_poly_384_Obs_FITs\n", - "view_fits_images(xrt_Al_poly_384_Obs_FITs_fixed_exposure_time)" - ] - }, - { - "cell_type": "markdown", - "id": "93a04e6b", - "metadata": {}, - "source": [ - "### Removing Unwanted FITS Files \n", - "\n", - "#### Strategy for Removal: \n", - "The removal process involves three main steps:\n", - "\n", - "#### Identification: \n", - "While reviewing images, note the index numbers or title filename of those you wish to exclude. Keeping track of these details as you go can streamline the removal process.\n", - "\n", - "#### Compilation: \n", - "Organize the identified indices or filenames into a Python list. This step formalizes your removal list, making the next step straightforward.\n", - "\n", - "#### Execution: \n", - "With the list prepared, you'll use a specific function to remove the unwanted files from your dataset. This function will be based on whether you're working with indices or filenames.\n", - "\n", - "#### Implementation Details\n", - "This section will introduce two functions tailored to your method of identification — one for index numbers and another for filenames. You can choose the one that best fits your workflow.\n" - ] - }, - { - "cell_type": "markdown", - "id": "74951466", - "metadata": {}, - "source": [ - "After reviewing the FITS images using the `view_fits_images` function, you may identify some images that you wish to remove from your dataset. This could be due to poor quality, irrelevance to your study, or any other reason. Below we provide a straightforward method to facilitate this, allowing you to easily remove these unwanted files from your dataset.\n", - "\n", - "##### Strategy for Removal\n", - "\n", - "1. **Identification**: While reviewing images, note the index number(s) or FITS filename(s) of those you wish to exclude. \n", - "\n", - "\n", - "2. **Compilation**: Create a Python [list](https://docs.python.org/3/tutorial/datastructures.html) with these indices as integers or FITS filename as a string.\n", - "\n", - "3. **Execution**: With the list prepared, you'll use a specific function to remove the unwanted files from your dataset. This function will be based on whether you're working with indices or filenames.\n", - "\n", - "##### Implementation\n", - "\n", - "Depending on your preference for using image numbers or filenames for identification, you can use one of the two provided functions.\n", - "\n", - "##### Using Index Numbers to Remove Files\n", - "\n", - "For cases where you've identified unwanted images by their index position number in the dataset, the `remove_fits_by_index` function will do the removal." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "685e2307", - "metadata": {}, - "outputs": [], - "source": [ - "def remove_fits_by_index(original_list, indices_to_remove):\n", - " \"\"\"\n", - " Removes FITS files from the dataset based on their index numbers.\n", - "\n", - " Parameters:\n", - " - original_list (list): The original list of FITS file paths.\n", - " - indices_to_remove (list): A list of index numbers representing the FITS files to remove.\n", - "\n", - " Returns:\n", - " - A new list with the specified FITS files removed.\n", - " \"\"\"\n", - " return [\n", - " item for idx, item in enumerate(original_list) if idx not in indices_to_remove\n", - " ]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c2f2ab42", - "metadata": {}, - "outputs": [], - "source": [ - "# Example usage of the remove_fits_by_index function\n", - "indices_to_remove = [\n", - " 2,\n", - " 5,\n", - " 7,\n", - "] # Assuming these are the indices of images to remove, based on their order in the dataset\n", - "\n", - "# Generate the updated list excluding specified FITS files\n", - "updated_index_xrt_Al_poly_384_Obs = remove_fits_by_index(\n", - " xrt_Al_poly_384_Obs_FITs_fixed_exposure_time, indices_to_remove\n", - ")\n", - "\n", - "# Print the new length of the file list\n", - "print(\"New length of file list:\", len(updated_index_xrt_Al_poly_384_Obs))\n", - "\n", - "# Optionally, print the first and last filenames in the updated list to show the range of the dataset\n", - "if updated_index_xrt_Al_poly_384_Obs:\n", - " print(\n", - " \"First file in the list:\", updated_index_xrt_Al_poly_384_Obs[0].split(\"/\")[-1]\n", - " )\n", - " print(\n", - " \"Last file in the list:\", updated_index_xrt_Al_poly_384_Obs[-1].split(\"/\")[-1]\n", - " )\n", - "else:\n", - " print(\"The list is now empty.\")" - ] - }, - { - "cell_type": "markdown", - "id": "11561344", - "metadata": {}, - "source": [ - "##### Using FITS filename to remove file\n", - "If you prefer noting down filenames:\n", - "\n", - "##### Using FITS Filenames to Remove Files\n", - "\n", - "If you find it more intuitive to work with filenames rather than index numbers, the following method allows you to remove unwanted images by their filenames. This can be particularly useful when the filenames contain descriptive information about the data, making them easier to identify without viewing each image sequentially.\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2480daea", - "metadata": {}, - "outputs": [], - "source": [ - "def remove_fits_by_filename(original_list, filenames_to_remove):\n", - " \"\"\"\n", - " Removes FITS files from the dataset based on their filenames.\n", - "\n", - " Parameters:\n", - " - original_list (list): The original list of FITS file paths.\n", - " - filenames_to_remove (list): A list of filenames representing the FITS files to remove.\n", - "\n", - " Returns:\n", - " - A new list with the specified FITS files removed.\n", - " \"\"\"\n", - " return [\n", - " item for item in original_list if item.split(\"/\")[-1] not in filenames_to_remove\n", - " ]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "9385f185", - "metadata": {}, - "outputs": [], - "source": [ - "# Example usage of the remove_fits_by_filename function\n", - "filenames_to_remove = [\n", - " \"l1_xrt20210521_185300_6.fits\",\n", - " \"l1_xrt20210521_185720_2.fits\",\n", - " \"l1_xrt20210521_190120_3.fits\",\n", - "] # Example filenames of images to remove\n", - "\n", - "# Generate the updated list excluding the specified FITS files\n", - "updated_FITS_xrt_Al_poly_384_Obs = remove_fits_by_filename(\n", - " xrt_Al_poly_384_Obs_FITs_fixed_exposure_time, filenames_to_remove\n", - ")\n", - "\n", - "# Print the new length of the file list\n", - "print(\"New length of file list:\", len(updated_FITS_xrt_Al_poly_384_Obs))\n", - "\n", - "# Optionally, print the first and last filenames in the updated list to show the range of the dataset\n", - "if updated_FITS_xrt_Al_poly_384_Obs:\n", - " print(\"First file in the list:\", updated_FITS_xrt_Al_poly_384_Obs[0].split(\"/\")[-1])\n", - " print(\"Last file in the list:\", updated_FITS_xrt_Al_poly_384_Obs[-1].split(\"/\")[-1])\n", - "else:\n", - " print(\"The list is now empty.\")" - ] - }, - { - "cell_type": "markdown", - "id": "fdf3db70", - "metadata": {}, - "source": [ - "\n", - "## Visualizing Solar Dynamics by Creating a Movie from XRT FITS Data" - ] - }, - { - "cell_type": "markdown", - "id": "bc025ab8", - "metadata": {}, - "source": [ - "Creating a movie from FITS files is an excellent way to visualize data, particularly for dynamic solar phenomena observed by the Hinode XRT. We can accomplish this using SunPy to handle FITS files and matplotlib, along with imageio, to create the animation." - ] - }, - { - "cell_type": "markdown", - "id": "87c9e991", - "metadata": {}, - "source": [ - "The `create_solar_movie_from_FITS` function generates a movie (MP4 format) from the FITS files you provide. If you're interested in customizing this process, you can review and modify the function as needed. To proceed with creating a movie using the default settings, run the cell containing the function below. Then, move to the following cell for instructions on how to use this function in your workflow." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4ee1372d", - "metadata": {}, - "outputs": [], - "source": [ - "def create_solar_movie_from_FITS(\n", - " fits_files, output_file=\"solar_movie.mp4\", fps=5, processing=True\n", - "):\n", - " \"\"\"\n", - " Creates a movie from a sequence of FITS files.\n", - "\n", - " Parameters:\n", - " - fits_files (list): List of paths to the FITS files.\n", - " - output_file (str): Path where the output movie will be saved.\n", - " - fps (int): Frames per second for the output movie.\n", - " - processing (bool): If True, prints processing messages. Default is True.\n", - " \"\"\"\n", - " # Create a temporary directory to store the frames\n", - " frames_dir = tempfile.mkdtemp()\n", - " frames = []\n", - "\n", - " if processing:\n", - " print(f\"Starting to process {len(fits_files)} FITS files.\\n\")\n", - "\n", - " for i, file_path in enumerate(fits_files):\n", - " if processing:\n", - " print(f\"Processing file {i+1}/{len(fits_files)}: {file_path}\")\n", - " # Load the FITS file as a SunPy Map\n", - " xrt_map = sunpy.map.Map(file_path)\n", - "\n", - " # Plotting the SunPy Map\n", - " fig = plt.figure(figsize=(8, 8))\n", - " ax = plt.subplot(projection=xrt_map)\n", - " xrt_map.plot(axes=ax)\n", - "\n", - " # Adding title and labels\n", - " plt.title(\n", - " f'XRT {xrt_map.measurement} {xrt_map.date.strftime(\"%Y-%m-%d %H:%M:%S\")}'\n", - " )\n", - " ax.set_xlabel(\"Helioprojective Longitude (Solar-X)\")\n", - " ax.set_ylabel(\"Helioprojective Latitude (Solar-Y)\")\n", - " plt.tight_layout()\n", - "\n", - " # Saving the frame\n", - " frame_path = os.path.join(frames_dir, f\"frame_{i:04d}.png\")\n", - " plt.savefig(frame_path)\n", - " plt.close(fig)\n", - " frames.append(frame_path)\n", - " if processing:\n", - " print(f\"Saved frame {i+1}/{len(fits_files)}\")\n", - "\n", - " if processing:\n", - " print(\"\\nStarting to compile the movie.\\n\")\n", - "\n", - " # Compile the movie from saved frames\n", - " with imageio.get_writer(output_file, fps=fps) as writer:\n", - " for frame_path in frames:\n", - " image = imageio.imread(frame_path)\n", - " writer.append_data(image)\n", - "\n", - " # Cleanup: Remove temporary frames and directory\n", - " for frame_path in frames:\n", - " os.remove(frame_path)\n", - " os.rmdir(frames_dir)\n", - "\n", - " if processing:\n", - " print(\n", - " f\"\\nMovie created: {output_file}\\nAll done!\\nMake sure to download the movie to your local machine to see it.\"\n", - " )" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0dbd03c2", - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "# Specify the output file name for the movie\n", - "solar_movie_example = \"solar_movie_example.mp4\"\n", - "\n", - "# Create the movie from the list of FITS files\n", - "# Using our Al-Poly by 384X384 filtered FITs files\n", - "create_solar_movie_from_FITS(\n", - " xrt_Al_poly_384_Obs_FITs_fixed_exposure_time,\n", - " output_file=solar_movie_example,\n", - " fps=15,\n", - " processing=True,\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1444b45f", - "metadata": {}, - "outputs": [], - "source": [ - "# from IPython.display import Video\n", - "\n", - "# Display the created movie within the notebook. Might to add \"embed=True\" to enable videos directly into a Jupyter Notebook\n", - "Video(solar_movie_example)" - ] - }, - { - "cell_type": "markdown", - "id": "272a9ca0", - "metadata": {}, - "source": [ - "### **A Note from Joy, an xrtpy dev**\n", - "\n", - "As an enthusiast of the Hinode X-Ray Telescope (XRT) and a developer for XRTpy, I created this guide to simplify the process of accessing and analyzing Hinode-XRT data using Python. The functions and methods presented in this guide are designed to serve as a starting point, and they are not currently part of the official `xrtpy` library. I encourage you to adapt and modify these functions to fit your specific research needs and preferences.\n", - "\n", - "#### Contributing to XRTpy\n", - "\n", - "If you're interested in contributing to the guide or the XRTpy project itself, we warmly welcome your input and collaboration. You can engage with us through [XRTpy's GitHub repository](https://github.com/HinodeXRT/xrtpy/pulls). Whether it's by suggesting features, improving documentation, or adding new functionalities, your contributions can significantly impact the scientific community's ability to study the Sun.\n", - "\n", - "#### Contact and Sharing\n", - "\n", - "Should you have any questions, or if you wish to share how you've utilized this guide in your work, please don't hesitate to reach out via email at [xrtpy@cfa.harvard.edu](mailto:xrtpy@cfa.harvard.edu). If you share or present your work based on this guide, please ensure to reference it appropriately.\n", - "\n", - "Thank you for exploring the Hinode-XRT data through this guide and XRTpy. Your feedback and contributions are what make our community thrive.\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.5" - }, - "nbsphinx": { - "execute": "never" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/docs/notebooks/getting_started/channel.ipynb b/docs/notebooks/getting_started/channel.ipynb deleted file mode 100644 index 7ba03ffa3..000000000 --- a/docs/notebooks/getting_started/channel.ipynb +++ /dev/null @@ -1,361 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Channel Properties - Exploring XRT Instrument Configuration" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We will explore the X-Ray Telescope (XRT) instrument properties using XRTpy's `Channel` object. The Channel object provides convenient methods and attributes to access and analyze various aspects of the XRT instrument configuration.\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Import the xrtpy package\n", - "import xrtpy" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "[xrtpy- X-Ray Filter Channel]: https://xrtpy.readthedocs.io/en/latest/getting_started.html\n", - "\n", - "Begin by defining a filter channel by its common abbreviation. In this example we will be exploring the titanium-on-polyimide filter. For detailed information about various filter channels and their characteristics, you can refer to the [xrtpy- X-Ray Filter Channel] section." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Define the filter channel abbreviation\n", - "Filter = \"Ti-poly\"" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To further explore the properties and characteristics of the defined filter channel, we will create a Channel object using `xrtpy.response.Channel`. By inserting the `Filter` variable as an input to the `xrtpy.response.Channel` object, we can conveniently work with the properties associated with the titanium-on-polyimide filter." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "channel = xrtpy.response.Channel(Filter)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now that we have created our `channel` object, we can delve into the X-Ray Telescope (XRT) instrument and its properties. We will start by examining basic information about the XRT instrument." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Display relevant information about the selected filter, observatory, and instrument\n", - "print(\"Selected filter:\", channel.name)\n", - "print(\"\\nObservatory:\", channel.observatory)\n", - "print(\"Instrument:\", channel.instrument)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### **Note: Instrument Properties**\n", - "###### It is important to note that most instrument properties of the X-Ray Telescope (XRT) remain the same regardless of the specific filter being used. This means that many characteristics and specifications of the XRT instrument, such as its dimensions, field of view, and detector properties, are independent of the selected filter." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Contents\n", - "\n", - "1. [Charge-Coupled Device](#Charge-Coupled-Device-(CCD))\n", - "2. [Entrance Filter](#Entrance-Filter) \n", - "3. [Focus-Filter](#Focus-Filter)\n", - "4. [Geometry](#Geometry)\n", - "5. [Mirror 1 and 2](#Mirror)\n", - "6. [Instrument Plotting](#Instrument-Plotting)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Charge-Coupled-Device (CCD)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The `channel.ccd` object reviews properties associated with the Charge-Coupled-Device (CCD) camera of the X-Ray Telescope (XRT) instrument.\n", - "\n", - "We can explore various characteristics of the CCD camera, such as its quantum_efficiency and pixel size to list a few." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print(channel.ccd.ccd_name)\n", - "\n", - "print(\"\\nPixel size: \", channel.ccd.ccd_pixel_size)\n", - "\n", - "print(\"Full well: \", channel.ccd.ccd_full_well)\n", - "print(\"Gain left: \", channel.ccd.ccd_gain_left)\n", - "print(\"Gain right: \", channel.ccd.ccd_gain_right)\n", - "print(\"eV pre electron: \", channel.ccd.ccd_energy_per_electron)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Entrance Filter" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can explore the XRT entrance filter properties utilizing `channel.entrancefilter` object. \n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print(channel.entrancefilter.entrancefilter_name)\n", - "print(\"Material: \", channel.entrancefilter.entrancefilter_material)\n", - "print(\"Thickness: \", channel.entrancefilter.entrancefilter_thickness)\n", - "print(\"Density: \", channel.entrancefilter.entrancefilter_density)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Focus-Filter" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "[X-Ray Filter Channel]: https://xrtpy.readthedocs.io/en/latest\n", - "\n", - "The XRT data is recorded through nine X-ray filters, which are implemented using two filter wheels. By utilizing the `channel.filter_#` notation, where `#` represents filter wheel 1 or 2, we can explore detailed information about the selected XRT channel filter.\n", - "\n", - "We are exploring the titanium-on-polyimide filter located in filter wheel 2, we will be utilizing the `channel.filter_2` object. This enables us to gather specific information about the properties and characteristics of this particular filter.\n", - "\n", - "It's worth noting that exploring the other filter will yield the result \"Open,\" as it's not use. For more comprehensive information about the XRT filters, you can refer to the [X-Ray Filter Channel] documentation." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print(\"Filter Wheel:\", channel.filter_2.filter_name)\n", - "print(\"\\nFilter material:\", channel.filter_2.filter_material)\n", - "print(\"Thickness: \", channel.filter_2.filter_thickness)\n", - "print(\"Density: \", channel.filter_2.filter_density)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Geometry" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can explore geometry factors in the XRT using `channel.geometry`." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print(channel.geometry.geometry_name)\n", - "print(\"\\nFocal length:\", channel.geometry.geometry_focal_len)\n", - "print(\"Aperture Area:\", channel.geometry.geometry_aperture_area)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Mirror" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The XRT is equipped with two mirrors, each having a unique configuration. We can access the properties of these mirrors using the `channel_mirror_#` notation, where `#` represents the first or second mirror surface. In this example, we will explore several XRT properties related to mirror 1 using the `channel_mirror_1` object. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print(channel.mirror_1.mirror_name)\n", - "print(\"Material: \", channel.mirror_1.mirror_material)\n", - "print(\"Density: \", channel.mirror_1.mirror_density)\n", - "print(\"Graze_angle: \", channel.mirror_1.mirror_graze_angle)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Instrument Plotting" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Plotting XRT properties - Transmittance" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Define the XRT transmission in `channel` by referencing transmission." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "transmission = channel.transmission" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Define the XRT wavelength in `channel` by referencing wavelength." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "wavelength = channel.wavelength" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Create a plotting function that plots the `transmission` versus `wavelength`. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def plot_transmission():\n", - " import matplotlib.pyplot as plt\n", - "\n", - " plt.figure(figsize=(10, 6))\n", - "\n", - " plt.plot(wavelength, transmission, label=f\"{channel.name}\")\n", - "\n", - " plt.title(\"X-Ray Telescope\", fontsize=15)\n", - " plt.xlabel(r\"$\\lambda$ [Å]\", fontsize=15)\n", - " plt.ylabel(r\"Transmittance\", fontsize=15)\n", - " plt.legend(fontsize=20)\n", - " plt.xlim(-5, 80)\n", - " plt.xticks(fontsize=15)\n", - " plt.yticks(fontsize=15)\n", - "\n", - " plt.grid(color=\"lightgrey\")\n", - " plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Run `plot_transmission` function to create the plot." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "plot_transmission()" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.5" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/docs/notebooks/getting_started/units.ipynb b/docs/notebooks/getting_started/units.ipynb deleted file mode 100644 index 754c7fa84..000000000 --- a/docs/notebooks/getting_started/units.ipynb +++ /dev/null @@ -1,724 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "6e8f0d92", - "metadata": {}, - "source": [ - "# Using Astropy Units" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e2751e56", - "metadata": { - "nbsphinx": "hidden" - }, - "outputs": [], - "source": [ - "%xmode minimal" - ] - }, - { - "cell_type": "markdown", - "id": "c566fe1c", - "metadata": {}, - "source": [ - "In scientific computing, we often represent physical quantities as numbers." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ee456b33", - "metadata": {}, - "outputs": [], - "source": [ - "distance_in_miles = 50\n", - "time_in_hours = 2\n", - "velocity_in_mph = distance_in_miles / time_in_hours\n", - "print(velocity_in_mph)" - ] - }, - { - "cell_type": "markdown", - "id": "93658d4f", - "metadata": {}, - "source": [ - "[astropy.units]: https://docs.astropy.org/en/stable/units/index.html\n", - "[xrtpy]: https://xrtpy.readthedocs.io/en/latest\n", - "\n", - "Representing a physical quantity as a number has risks. We might unknowingly perform operations with different units, like `time_in_seconds + time_in_hours`. We might even accidentally perform operations with physically incompatible units, like `length + time`, without catching our mistake. We can avoid these problems by using a units package.\n", - "\n", - "This notebook introduces [astropy.units] with an emphasis on the functionality needed to work with [xrtpy]. We typically import this subpackage as `u`." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8c20320a", - "metadata": {}, - "outputs": [], - "source": [ - "import astropy.units as u" - ] - }, - { - "cell_type": "markdown", - "id": "ad28288e", - "metadata": {}, - "source": [ - "## Contents\n", - "\n", - "1. [Unit basics](#Unit-basics)\n", - "2. [Unit operations](#Unit-operations) \n", - "3. [Unit conversations](#Unit-conversions)\n", - "4. [Detaching units and values](#Detaching-units-and-values)\n", - "5. [Equivalencies](#Equivalencies)\n", - "6. [Physical constants](#Physical-constants)\n", - "7. [Optimizing unit operations](#Optimizing-unit-operations)\n", - "8. [Physical Types](#Physical-types)" - ] - }, - { - "cell_type": "markdown", - "id": "a9fad673", - "metadata": {}, - "source": [ - "## Unit basics\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "id": "e9ccbb06", - "metadata": {}, - "source": [ - "We can create a physical quantity by multiplying or dividing a number or array with a unit." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8437650a", - "metadata": {}, - "outputs": [], - "source": [ - "distance = 60 * u.km\n", - "print(distance)" - ] - }, - { - "cell_type": "markdown", - "id": "ccc6659f", - "metadata": {}, - "source": [ - "[Quantity]: https://docs.astropy.org/en/stable/api/astropy.units.Quantity.html#astropy.units.Quantity\n", - "\n", - "This operation creates a [Quantity]: a number, sequence, or array that has been assigned a physical unit." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a6354b93", - "metadata": {}, - "outputs": [], - "source": [ - "type(distance)" - ] - }, - { - "cell_type": "markdown", - "id": "744a9b01", - "metadata": {}, - "source": [ - "[Quantity]: https://docs.astropy.org/en/stable/api/astropy.units.Quantity.html#astropy.units.Quantity\n", - "\n", - "We can also create an object by using the [Quantity] class itself." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8d2bb681", - "metadata": {}, - "outputs": [], - "source": [ - "time = u.Quantity(120, u.min)" - ] - }, - { - "cell_type": "markdown", - "id": "1bb28951", - "metadata": {}, - "source": [ - "[Quantity]: https://docs.astropy.org/en/stable/api/astropy.units.Quantity.html#astropy.units.Quantity\n", - "\n", - "We can create [Quantity] objects with compound units." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4932159b", - "metadata": {}, - "outputs": [], - "source": [ - "88 * u.imperial.mile / u.hour" - ] - }, - { - "cell_type": "markdown", - "id": "9cc9adba", - "metadata": {}, - "source": [ - "[Quantity]: https://docs.astropy.org/en/stable/api/astropy.units.Quantity.html#astropy.units.Quantity\n", - "\n", - "We can even create [Quantity] objects that are explicitly dimensionless." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "09e9752c", - "metadata": {}, - "outputs": [], - "source": [ - "3 * u.dimensionless_unscaled" - ] - }, - { - "cell_type": "markdown", - "id": "4cffc8a0", - "metadata": {}, - "source": [ - "[Quantity]: https://docs.astropy.org/en/stable/api/astropy.units.Quantity.html#astropy.units.Quantity\n", - "\n", - "We can also create a [Quantity] based off of a NumPy array or a list." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e3235d80", - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "\n", - "np.array([2.5, 3.2, 1.1]) * u.kg" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a686fd93", - "metadata": {}, - "outputs": [], - "source": [ - "[2, 3, 4] * u.m / u.s" - ] - }, - { - "cell_type": "markdown", - "id": "a60e9ea9", - "metadata": {}, - "source": [ - "## Unit operations\n", - "\n", - "[Quantity]: https://docs.astropy.org/en/stable/api/astropy.units.Quantity.html#astropy.units.Quantity\n", - "\n", - "Operations between [Quantity] objects handle unit conversions automatically. We can add [Quantity] objects together as long as their units have the same physical type." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "65e08284", - "metadata": {}, - "outputs": [], - "source": [ - "1 * u.m + 25 * u.cm" - ] - }, - { - "cell_type": "markdown", - "id": "edb43067", - "metadata": {}, - "source": [ - "Units get handled automatically during operations like multiplication, division, and exponentiation." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c36788db", - "metadata": {}, - "outputs": [], - "source": [ - "velocity = distance / time\n", - "print(velocity)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "04b48a57", - "metadata": {}, - "outputs": [], - "source": [ - "area = distance**2\n", - "print(area)" - ] - }, - { - "cell_type": "markdown", - "id": "98331629", - "metadata": {}, - "source": [ - "Attempting an operation between physically incompatible units gives us an error, which we can use to find bugs in our code." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0877feb6", - "metadata": { - "tags": [ - "raises-exception" - ] - }, - "outputs": [], - "source": [ - "3 * u.m + 3 * u.s" - ] - }, - { - "cell_type": "markdown", - "id": "4f0c461e", - "metadata": {}, - "source": [ - "[Quantity]: https://docs.astropy.org/en/stable/api/astropy.units.Quantity.html#astropy.units.Quantity\n", - "[numpy.ndarray]: https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html\n", - "\n", - "[Quantity] objects behave very similarly to NumPy arrays because [Quantity] is a subclass of [numpy.ndarray]." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "59389429", - "metadata": {}, - "outputs": [], - "source": [ - "balmer_series = [656.279, 486.135, 434.0472, 410.1734] * u.nm\n", - "Hα = balmer_series[0]\n", - "print(Hα)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a6545132", - "metadata": {}, - "outputs": [], - "source": [ - "np.max(balmer_series)" - ] - }, - { - "cell_type": "markdown", - "id": "e1bb9434", - "metadata": {}, - "source": [ - "[NumPy]: https://numpy.org/\n", - "[SciPy]: https://scipy.org/\n", - "\n", - "[Quantity]: https://docs.astropy.org/en/stable/api/astropy.units.Quantity.html#astropy.units.Quantity\n", - "[Quantity objects lose their units with some operations]: https://docs.astropy.org/en/stable/known_issues.html#quantities-lose-their-units-with-some-operations\n", - "\n", - "Most frequently encountered [NumPy] and [SciPy] functions can be used with [Quantity] objects. However, [Quantity objects lose their units with some operations]. " - ] - }, - { - "cell_type": "markdown", - "id": "b910a84b", - "metadata": {}, - "source": [ - "## Unit conversions\n", - "\n", - "[Quantity]: https://docs.astropy.org/en/stable/api/astropy.units.Quantity.html#astropy.units.Quantity\n", - "[to]: https://docs.astropy.org/en/stable/api/astropy.units.Quantity.html#astropy.units.Quantity.to\n", - "\n", - "The [to] method allows us to convert a [Quantity] to different units of the same physical type. This method accepts strings that represent a unit (including compound units) or a unit object." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "80f4f133", - "metadata": {}, - "outputs": [], - "source": [ - "velocity.to(\"m/s\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "21c46ef1", - "metadata": {}, - "outputs": [], - "source": [ - "velocity.to(u.m / u.s)" - ] - }, - { - "cell_type": "markdown", - "id": "c1e742ca", - "metadata": {}, - "source": [ - "[Quantity]: https://docs.astropy.org/en/stable/api/astropy.units.Quantity.html#astropy.units.Quantity\n", - "[si]: https://docs.astropy.org/en/stable/api/astropy.units.Quantity.html#astropy.units.Quantity.si\n", - "[cgs]: https://docs.astropy.org/en/stable/api/astropy.units.Quantity.html#astropy.units.Quantity.cgs\n", - "\n", - "The [si] and [cgs] attributes convert the [Quantity] to SI or CGS units, respectively. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "02bda4d2", - "metadata": {}, - "outputs": [], - "source": [ - "velocity.si" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "560a0cfe", - "metadata": {}, - "outputs": [], - "source": [ - "velocity.cgs" - ] - }, - { - "cell_type": "markdown", - "id": "1429d5a2", - "metadata": {}, - "source": [ - "## Detaching units and values\n", - "\n", - "[value]: https://docs.astropy.org/en/stable/api/astropy.units.Quantity.html#astropy.units.Quantity.value \n", - "[Quantity]: https://docs.astropy.org/en/stable/api/astropy.units.Quantity.html#astropy.units.Quantity\n", - "\n", - "The [value] attribute of a [Quantity] provides the number (as a NumPy scalar) or NumPy array without the unit." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "24e8403c", - "metadata": {}, - "outputs": [], - "source": [ - "time.value" - ] - }, - { - "cell_type": "markdown", - "id": "4c6c027b", - "metadata": {}, - "source": [ - "[unit]: https://docs.astropy.org/en/stable/api/astropy.units.Quantity.html#astropy.units.Quantity.unit\n", - "[Quantity]: https://docs.astropy.org/en/stable/api/astropy.units.Quantity.html#astropy.units.Quantity\n", - "\n", - "The [unit] attribute of a [Quantity] provides the unit without the value." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2c41a2fa", - "metadata": {}, - "outputs": [], - "source": [ - "time.unit" - ] - }, - { - "cell_type": "markdown", - "id": "be0c5349", - "metadata": {}, - "source": [ - "## Equivalencies" - ] - }, - { - "cell_type": "markdown", - "id": "07c3b9c1", - "metadata": {}, - "source": [ - "[electron-volt]: https://en.wikipedia.org/wiki/Electronvolt\n", - "[Boltzmann constant]: https://en.wikipedia.org/wiki/Boltzmann_constant\n", - "\n", - "Occasionally the [electron-volt] (eV) as a unit of temperature. This is a shortcut for describing the thermal energy per particle, or more accurately the temperature multiplied by the [Boltzmann constant], $k_B$. Because an electron-volt is a unit of energy rather than temperature, we cannot directly convert electron-volts to kelvin." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6b6fafd6", - "metadata": { - "tags": [ - "raises-exception" - ] - }, - "outputs": [], - "source": [ - "u.eV.to(\"K\")" - ] - }, - { - "cell_type": "markdown", - "id": "9299c8a1", - "metadata": {}, - "source": [ - "[astropy.units]: https://docs.astropy.org/en/stable/units/index.html\n", - "[equivalencies]: https://docs.astropy.org/en/stable/units/equivalencies.html\n", - "[temperature_energy()]: https://docs.astropy.org/en/stable/units/equivalencies.html#temperature-energy-equivalency\n", - "\n", - "To handle non-standard unit conversions, [astropy.units] allows the use of [equivalencies]. The conversion from eV to K can be done by using the [temperature_energy()] equivalency." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "afac5b4a", - "metadata": {}, - "outputs": [], - "source": [ - "(1 * u.eV).to(\"K\", equivalencies=u.temperature_energy())" - ] - }, - { - "cell_type": "markdown", - "id": "b4c492cc", - "metadata": {}, - "source": [ - "[dimensionless_angles()]: https://docs.astropy.org/en/stable/api/astropy.units.equivalencies.dimensionless_angles.html#dimensionless-angles\n", - "\n", - "[frequency]: https://en.wikipedia.org/wiki/Frequency\n", - "[angular frequency]: https://en.wikipedia.org/wiki/Angular_frequency\n", - "\n", - "Radians are treated dimensionlessly when the [dimensionless_angles()] equivalency is in effect. Note that this equivalency does not account for the multiplicative factor of $2π$ that is used when converting between [frequency] and [angular frequency]." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "9735710b", - "metadata": {}, - "outputs": [], - "source": [ - "(3.2 * u.rad / u.s).to(\"1 / s\", equivalencies=u.dimensionless_angles())" - ] - }, - { - "cell_type": "markdown", - "id": "7ec6d857", - "metadata": {}, - "source": [ - "## Physical constants" - ] - }, - { - "cell_type": "markdown", - "id": "b714de6a", - "metadata": {}, - "source": [ - "[astropy.constants]: https://docs.astropy.org/en/stable/constants/index.html\n", - "\n", - "We can use [astropy.constants] to access the most commonly needed physical constants." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "746a79a7", - "metadata": {}, - "outputs": [], - "source": [ - "from astropy.constants import c, e, k_B\n", - "\n", - "print(c)" - ] - }, - { - "cell_type": "markdown", - "id": "c3ee9feb", - "metadata": {}, - "source": [ - "[Constant]: https://docs.astropy.org/en/stable/api/astropy.constants.Constant.html#astropy.constants.Constant\n", - "[Quantity]: https://docs.astropy.org/en/stable/api/astropy.units.Quantity.html#astropy.units.Quantity\n", - "[u.temperature_energy()]: https://docs.astropy.org/en/stable/units/equivalencies.html#temperature-energy-equivalency\n", - "\n", - "A [Constant] behaves very similarly to a [Quantity]. For example, we can use the Boltzmann constant to mimic the behavior of [u.temperature_energy()]." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d2d59d08", - "metadata": {}, - "outputs": [], - "source": [ - "thermal_energy_per_particle = 0.6 * u.keV\n", - "temperature = thermal_energy_per_particle / k_B\n", - "print(temperature.to(\"MK\"))" - ] - }, - { - "cell_type": "markdown", - "id": "7c145497", - "metadata": {}, - "source": [ - "Electromagnetic constants often need the unit system to be specified. Code within PlasmaPy uses SI units." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "015de7fc", - "metadata": { - "tags": [ - "raises-exception" - ] - }, - "outputs": [], - "source": [ - "2 * e" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1a90c979", - "metadata": {}, - "outputs": [], - "source": [ - "2 * e.si" - ] - }, - { - "cell_type": "markdown", - "id": "f4da2ab0", - "metadata": {}, - "source": [ - "## Optimizing unit operations\n", - "\n", - "[performance tips]: https://docs.astropy.org/en/stable/units/index.html#performance-tips\n", - "[astropy.units]: https://docs.astropy.org/en/stable/units/index.html\n", - "\n", - "Astropy's documentation includes [performance tips] for using [astropy.units] in computationally intensive situations. For example, putting compound units in parentheses reduces the need to make multiple copies of the data." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e3bc2348", - "metadata": {}, - "outputs": [], - "source": [ - "volume = 0.62 * (u.barn * u.Mpc)" - ] - }, - { - "cell_type": "markdown", - "id": "55b8dcd1", - "metadata": {}, - "source": [ - "## Physical types" - ] - }, - { - "cell_type": "markdown", - "id": "0421ee56", - "metadata": {}, - "source": [ - "[physical type]: https://docs.astropy.org/en/stable/units/physical_types.html\n", - "[physical_type]: https://docs.astropy.org/en/stable/api/astropy.units.UnitBase.html#astropy.units.UnitBase.physical_type\n", - "[get_physical_type()]: https://docs.astropy.org/en/stable/api/astropy.units.get_physical_type.html#astropy.units.get_physical_type\n", - "\n", - "A [physical type] corresponds to physical quantities with dimensionally compatible units. Astropy has functionality that represents different physical types. These physical type objects can be accessed using either the [physical_type] attribute of a unit or [get_physical_type()]." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "da6c9c7d", - "metadata": {}, - "outputs": [], - "source": [ - "(u.m**2 / u.s).physical_type" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f0d49b03", - "metadata": {}, - "outputs": [], - "source": [ - "u.get_physical_type(\"number density\")" - ] - }, - { - "cell_type": "markdown", - "id": "8cd7e09a", - "metadata": {}, - "source": [ - "These physical type objects can be used for dimensional analysis." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d03b8eb0", - "metadata": {}, - "outputs": [], - "source": [ - "energy_density = (u.J * u.m**-3).physical_type\n", - "velocity = u.get_physical_type(\"velocity\")\n", - "print(energy_density * velocity)" - ] - } - ], - "metadata": { - "celltoolbar": "Tags", - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.4" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/docs/reference/image_correction.rst b/docs/reference/image_correction.rst new file mode 100644 index 000000000..9ee8be814 --- /dev/null +++ b/docs/reference/image_correction.rst @@ -0,0 +1,6 @@ +************************ +`xrtpy.image_correction` +************************ + +.. automodapi:: xrtpy.image_correction + :include-all-objects: diff --git a/docs/reference/index.rst b/docs/reference/index.rst new file mode 100644 index 000000000..fd6b8fe12 --- /dev/null +++ b/docs/reference/index.rst @@ -0,0 +1,10 @@ +******************* +xrtpy API Reference +******************* + +.. toctree:: + :maxdepth: 1 + :caption: Contents: + :glob: + + * diff --git a/docs/reference/response.rst b/docs/reference/response.rst new file mode 100644 index 000000000..b171b1c13 --- /dev/null +++ b/docs/reference/response.rst @@ -0,0 +1,6 @@ +**************** +`xrtpy.response` +**************** + +.. automodapi:: xrtpy.response + :include-all-objects: diff --git a/docs/reference/util.rst b/docs/reference/util.rst new file mode 100644 index 000000000..da3d31daf --- /dev/null +++ b/docs/reference/util.rst @@ -0,0 +1,6 @@ +************ +`xrtpy.util` +************ + +.. automodapi:: xrtpy.util + :include-all-objects: diff --git a/docs/reference/xrtpy.rst b/docs/reference/xrtpy.rst new file mode 100644 index 000000000..c1bbe85cf --- /dev/null +++ b/docs/reference/xrtpy.rst @@ -0,0 +1,5 @@ +******* +`xrtpy` +******* + +.. automodapi:: xrtpy diff --git a/docs/response/index.html b/docs/response/index.html deleted file mode 100644 index 3cbb92aa0..000000000 --- a/docs/response/index.html +++ /dev/null @@ -1,30 +0,0 @@ -.. _xrtpy-response: - -*************************** -Response (`xrtpy.response`) -*************************** - -.. py:module:: xrtpy.response -.. currentmodule:: xrtpy.response - -Introduction -============ - -The `xrtpy.response` subpackage includes functionality for describing -XRT_ channels & filters, finding the effective area, and calculating the -temperature response function. - -Submodules -========== - -.. toctree:: - :maxdepth: 2 - - channel - -API -=== - -.. automodapi:: xrtpy.response - :noindex: - :no-main-docstring: diff --git a/examples/README.txt b/examples/README.txt new file mode 100644 index 000000000..264c1806b --- /dev/null +++ b/examples/README.txt @@ -0,0 +1,5 @@ +*************** +Example Gallery +*************** + +The gallery contains examples of how to use ``xrtpy``. diff --git a/examples/channels.py b/examples/channels.py new file mode 100644 index 000000000..f155c2a02 --- /dev/null +++ b/examples/channels.py @@ -0,0 +1,103 @@ +""" +============================= +Exploring XRT's Configuration +============================= + +This example explores the X-Ray Telescope (XRT) instrument properties +using XRTpy's `xrtpy.response.Channel`. It provides convenient methods and attributes +to access and analyze various aspects of the XRT instrument configuration. +""" + +import matplotlib.pyplot as plt + +import xrtpy + +############################################################################## +# We begin by defining a filter channel by its common abbreviation. +# In this example we will be exploring the titanium-on-polyimide filter. +# For detailed information about various filter channels and their characteristics, you can refer to :ref:`xrtpy-getting-started-filters`. +# +# To explore the properties and characteristics of a defined filter channel, we will create a +# `xrtpy.response.Channel`. By passing in the filter name as an input, we can work +# with the properties associated with the titanium-on-polyimide filter. + +channel = xrtpy.response.Channel("Ti-poly") + +############################################################################## +# Now that we have created our channel, we can delve into the XRT instrument and its properties. +# We will start by examining basic information about the XRT instrument. + +print("Selected filter:", channel.name) +print("\nObservatory:", channel.observatory) +print("Instrument:", channel.instrument) + +############################################################################## +# It is important to note that most instrument properties of XRT remain the same +# regardless of the specific filter being used. This means that many characteristics +# and specifications of the XRT instrument, such as its dimensions, +# field of view, and detector properties, are independent of the selected filter. +# +# We can explore various characteristics of the the Charge-Coupled-Device (CCD) +# camera camera, such as its quantum efficiency and pixel size to list a few. + +print(channel.ccd.ccd_name) +print("\nPixel size: ", channel.ccd.ccd_pixel_size) +print("Full well: ", channel.ccd.ccd_full_well) +print("Gain left: ", channel.ccd.ccd_gain_left) +print("Gain right: ", channel.ccd.ccd_gain_right) +print("eV pre electron: ", channel.ccd.ccd_energy_per_electron) + +############################################################################## +# We can explore the XRT entrance filter properties utilizing ``entrancefilter``. + +print(channel.entrancefilter.entrancefilter_name) +print("Material: ", channel.entrancefilter.entrancefilter_material) +print("Thickness: ", channel.entrancefilter.entrancefilter_thickness) +print("Density: ", channel.entrancefilter.entrancefilter_density) + +############################################################################## +# XRT data is recorded through nine X-ray filters, which are implemented using two filter wheels. +# +# By utilizing the ``channel.filter_#`` notation, where ``#`` represents filter wheel 1 or 2, +# we can explore detailed information about the selected XRT channel filter. +# +# It's worth noting that sometimes the other filter will yield the result "Open," as it's not use. +# For more comprehensive information about the XRT filters, you can refer to :ref:`xrtpy-getting-started-filters`. + +print("Filter Wheel:", channel.filter_2.filter_name) +print("\nFilter material:", channel.filter_2.filter_material) +print("Thickness: ", channel.filter_2.filter_thickness) +print("Density: ", channel.filter_2.filter_density) + +############################################################################## +# We can explore geometry factors in the XRT using ``geometry``. + +print(channel.geometry.geometry_name) +print("\nFocal length:", channel.geometry.geometry_focal_len) +print("Aperture Area:", channel.geometry.geometry_aperture_area) + +############################################################################## +# The XRT is equipped with two mirrors and We can access the properties of these +# mirrors using the ``channel_mirror_#`` notation, where ``#`` represents the +# first or second mirror surface. + +print(channel.mirror_1.mirror_name) +print("Material: ", channel.mirror_1.mirror_material) +print("Density: ", channel.mirror_1.mirror_density) +print("Graze_angle: ", channel.mirror_1.mirror_graze_angle) + +############################################################################## +# Finally we can explore the XRT transmission properties + +plt.figure() + +plt.plot(channel.wavelength, channel.transmission, label=f"{channel.name}") +plt.title(f"{channel.name} filter") +plt.xlabel(r"$\lambda$ [Å]") +plt.ylabel(r"Transmittance") +# The full range goes up to 400 Å, but we will limit it to 80 Å for better visualization +plt.xlim(0, 80) +plt.grid(color="lightgrey") +plt.tight_layout() + +plt.show() diff --git a/examples/deconvolving.py b/examples/deconvolving.py new file mode 100644 index 000000000..503a36e03 --- /dev/null +++ b/examples/deconvolving.py @@ -0,0 +1,45 @@ +""" +======================= +Deconvolving XRT Images +======================= + +This example demonstrates deconvolvoing X-Ray Telescope (XRT) images using the +`xrtpy.image_correction.deconvolve` function in XRTpy. +""" + +import matplotlib.pyplot as plt +import sunpy.map +from sunpy.net import Fido +from sunpy.net import attrs as a + +from xrtpy.image_correction import deconvolve + +############################################################################## +# We will search for XRT data from the Virtual Solar Observatory (VSO) and fetch the first result. + +result = Fido.search( + a.Time("2012-06-05 21:58:39", "2012-06-05 21:59:00"), a.Instrument("xrt") +) +data_file = Fido.fetch(result[0]) + +############################################################################## +# Typically most deconvolve routines use the Richardson-Lucy deconvolution algorithm. + +xrt_map = sunpy.map.Map(data_file) +deconv_map = deconvolve(xrt_map) + +############################################################################## +# To see the effects of the deconvolution we plot both the before and after images. + +fig = plt.figure(figsize=(15, 10)) + +ax = fig.add_subplot(121, projection=xrt_map) +xrt_map.plot(axes=ax, title="Original") +ax1 = fig.add_subplot(122, projection=deconv_map) +deconv_map.plot(axes=ax1, title="Deconvolved") + +ax1.coords[1].set_ticks_visible(False) +ax1.coords[1].set_ticklabel_visible(False) +fig.tight_layout() + +plt.show() diff --git a/examples/effective_area.py b/examples/effective_area.py new file mode 100644 index 000000000..467f7c940 --- /dev/null +++ b/examples/effective_area.py @@ -0,0 +1,75 @@ +""" +======================= +Effective Area Analysis +======================= + +In this example, we will explore the effective areas for different XRT filter channels. +Understanding the effective areas is important for accurately interpreting and quantifying the data. +""" + +import matplotlib.pyplot as plt + +import xrtpy + +############################################################################## +# Let us begin by defining a filter channel using its abbreviation. +# For example, if we want to explore the effective area for an aluminum-on-polyimide filter +# channel, we need to specify the relevant abbreviation. + +xrt_filter = "Al-poly" + +############################################################################## +# `~.EffectiveAreaFundamental` allows us to accurately determine the effective area +# based on the specified filter channel, date, and time. + +date_time = "2023-09-22T22:59:59" +eaf = xrtpy.response.EffectiveAreaFundamental(xrt_filter, date_time) + +############################################################################## +# To actually calculate the effective area function we can call :meth:`~xrtpy.response.EffectiveAreaFundamental.effective_area`. + +effective_area = eaf.effective_area() +print("Effective Area:\n", effective_area) + +############################################################################## +# Differences overtime arise from an increase of the contamination layer on the +# CCD which blocks some of the X-rays thus reducing the effective area. +# For detailed information about the calculation of the XRT CCD contaminant layer thickness, +# you can refer to +# `Montana State University `__. +# +# Additional information is provided by +# `Narukage et. al. (2011) `__. + +relative_launch_date_time = "2006-09-22T22:59:59" +eaf_launch = xrtpy.response.EffectiveAreaFundamental( + xrt_filter, relative_launch_date_time +) +launch_effective_area = eaf_launch.effective_area() + +############################################################################## +# Finally, we can plot how the effective area has changed over time. + +plt.figure() + +plt.plot( + eaf.channel_wavelength, + effective_area, + label=f"{date_time}", +) +plt.plot( + eaf.channel_wavelength, + launch_effective_area, + label=f"{relative_launch_date_time}", +) + +plt.title("XRT Effective Area - Al-Poly") +plt.xlabel("Wavelength (Å)") +plt.ylabel("Effective Area ($cm^{2}$)") +plt.legend() +plt.xlim(0, 60) + +plt.grid(color="lightgrey") +plt.tight_layout() + +plt.show() diff --git a/examples/remove_lightleak.py b/examples/remove_lightleak.py new file mode 100644 index 000000000..ea6b1e36c --- /dev/null +++ b/examples/remove_lightleak.py @@ -0,0 +1,48 @@ +""" +=================== +Removing Light Leak +=================== + +In this example, we show how to remove the light leak (visible stray light) +from XRT synoptic composite images. +""" + +from pathlib import Path + +import astropy.units as u +import matplotlib.pyplot as plt +import sunpy.map +from astropy.utils.data import get_pkg_data_path + +from xrtpy.image_correction import remove_lightleak + +############################################################################## +# This example will be using XRT synoptic data from the first day of summer of 2015. +# This is stored in the ``example_data`` directory of the `xrtpy` package. + +directory = get_pkg_data_path("data/example_data", package="xrtpy.image_correction") +data_file = Path(directory) / "comp_XRT20150621_055911.7.fits" +xrt_map = sunpy.map.Map(data_file) + +############################################################################## +# Removing the light leak from the composite image is done using the `xrtpy.image_correction.remove_lightleak` function. + +lightleak_map = remove_lightleak(xrt_map) + +############################################################################## +# Finally, we plot the original and light leak subtracted images side by side. + +fig = plt.figure(figsize=(12, 6)) + +ax = fig.add_subplot(121, projection=xrt_map) +xrt_map.plot(axes=ax, title="Original", clip_interval=(1, 99.9) * u.percent) +ax1 = fig.add_subplot(122, projection=lightleak_map) +lightleak_map.plot( + axes=ax1, title="Light Leak Subtracted", clip_interval=(1, 99.9) * u.percent +) + +ax1.coords[1].set_ticks_visible(False) +ax1.coords[1].set_ticklabel_visible(False) +fig.tight_layout() + +plt.show() diff --git a/examples/sorting_data.py b/examples/sorting_data.py new file mode 100644 index 000000000..60e5ecc49 --- /dev/null +++ b/examples/sorting_data.py @@ -0,0 +1,85 @@ +""" +========================= +Filtering and Visualizing +========================= + +This example provides a simple overview of filtering and visualizing XRT data. +""" + +import astropy.units as u +import matplotlib.pyplot as plt +import sunpy.map +from sunpy.net import Fido +from sunpy.net import attrs as a + +############################################################################## +# To start we will download a range of XRT data from the Virtual Solar Observatory (VSO). +# The goal is to acquire a large set of files we can sort through and visualize. + +query = Fido.search( + a.Time("2021-05-21 18:51:00", "2021-05-22 00:00:00"), a.Instrument("xrt") +) +print(query) + +############################################################################## +# This query will return a large number of files, this is due to the fact we do not +# specify any additional filters. We can filter the data by specifying additional +# attributes in the query. +# +# For wavelength, we use a range that focuses the data to return only Al-Poly filter images. +# This will cut the results down in half. + +query = Fido.search( + a.Time("2021-05-21 20:51:00", "2021-05-22 00:00:00"), + a.Instrument("xrt"), + a.Wavelength(4 * u.nm, 5 * u.nm), +) +print(query) + +############################################################################## +# Now we will download the data. +# As this is still over 60 files, this process can take some time. + +xrt_files = Fido.fetch(query) + +############################################################################## +# We can now load the data into a `~sunpy.map.MapSequence` and create a animation. + +xrt_seq = sunpy.map.Map(xrt_files, sequence=True) + +fig = plt.figure() +ax = fig.add_subplot(projection=xrt_seq.maps[0]) +ani = xrt_seq.plot(axes=ax) + +############################################################################## +# You might notice that there is a jump in the sequence. +# The size of the data and the pointing changes. +# We can exclude these images by filtering the data further. + +xrt_seq_filtered_shape = sunpy.map.Map( + [m for m in xrt_seq if m.data.shape == (384, 384)], sequence=True +) + +fig = plt.figure() +ax = fig.add_subplot(projection=xrt_seq.maps[0]) +ani = xrt_seq_filtered_shape.plot(axes=ax) + +############################################################################## +# In fact, `sunpy.map.Map` provides many attributes that can be used to filter the data. +# This provides a lot of flexibility in how you can filter the data for your science objective. +# +# For example, we can filter the data by the exposure time or the detector. + +xrt_seq_filtered_exp_time = sunpy.map.Map( + [m for m in xrt_seq_filtered_shape if m.exposure_time < 0.1 * u.s], sequence=True +) + +fig = plt.figure() +ax = fig.add_subplot(projection=xrt_seq.maps[0]) +ani = xrt_seq_filtered_exp_time.plot(axes=ax) + +############################################################################## +# If you want to save this animation to a file, you can use the ``save`` method. +# For more information on how to use this method, `see the matplotlib documentation `__. + +plt.show() diff --git a/examples/temperature_from_filter_ratios.py b/examples/temperature_from_filter_ratios.py new file mode 100644 index 000000000..04d1aa9f0 --- /dev/null +++ b/examples/temperature_from_filter_ratios.py @@ -0,0 +1,70 @@ +""" +================================================ +Calculating the temperature and emission measure +================================================ + +In this example, we will showcase how to use the filter method to calculate +the temperature and emission measure of the X-ray Telescope (XRT) on Hinode. +""" + +import matplotlib.pyplot as plt +import sunpy.map +from astropy.visualization import ImageNormalize, LogStretch +from sunpy.net import Fido +from sunpy.net import attrs as a + +from xrtpy.response import temperature_from_filter_ratio + +############################################################################## +# To start, we will get XRT data via ``sunpy``. +# +# It is important to use images that same size and with the smallest time separation. +# Note that not all filter ratios produce good results. + +query = Fido.search( + a.Time("2011-01-28 01:31:55", "2011-01-28 01:32:05"), a.Instrument("xrt") +) +data_files = Fido.fetch(query) +xrt_map_1 = sunpy.map.Map(data_files[0]) +xrt_map_2 = sunpy.map.Map(data_files[1]) + +############################################################################## +# The `xrtpy.response.temperature_from_filter_ratio` function has several options, mirroring +# the IDL routine xrt_teem.pro in SolarSoft in most respects.A simple call with +# no extra parameters calculates the temperature and (volume) emission measure +# for the two images without any binning or masking of the data. + +T_EM = temperature_from_filter_ratio(xrt_map_1, xrt_map_2) + +############################################################################## +# The output is a namedtuple with attributes ``Tmap``, ``EMmap``, ``Terrmap``, and ``EMerrmap``. +# As with the SolarSoft IDL routine xrt_teem.pro, the output images are logs of the quantities. +# +# ``Tmap`` is the electron temperature, ``EMmap`` is the volume emission measure, ``Terrmap`` +# is a measure of the uncertainties in the temperature determined for each pixel and ``EMerrmap`` +# is the same for the emission measure. + +T_e = T_EM.Tmap + +fig = plt.figure() + +ax = plt.subplot(projection=T_e) +T_e.plot( + title="Derived Temperature", + cmap="inferno", + norm=ImageNormalize(vmin=6, vmax=7, stretch=LogStretch(10)), +) +T_e.draw_limb() +T_e.draw_grid() +plt.colorbar(label="T (K)") +plt.tight_layout() + +plt.show() + +############################################################################## +# If you want to do the same for Level 2 synoptic composite images, you have to use +# `~.make_exposure_map` to generate the exposure maps for the composite images. +# This is then passed to `xrtpy.response.temperature_from_filter_ratio` as the +# ``expmap1`` and ``expmap2`` arguments. +# Otherwise without accounting for the different exposure time per pixel, +# the temperature and emission measure will be incorrect. diff --git a/examples/temperature_response.py b/examples/temperature_response.py new file mode 100644 index 000000000..031d5153c --- /dev/null +++ b/examples/temperature_response.py @@ -0,0 +1,88 @@ +""" +==================== +Temperature Response +==================== + +In this example, we will explore the temperature response of the filters on XRT. +The temperature response provides important information on how XRT responds to +the different temperatures of X-ray emissions. +""" + +import matplotlib.pyplot as plt +import numpy as np + +import xrtpy + +############################################################################## +# A filter channel is defined by its common abbreviation, which represents +# a specific type of filter used to modify the X-ray radiation observed. +# In this example, we will explore the carbon-on-polyimide filter (abbreviated as "C-poly"). + +xrt_filter = "C-poly" + +############################################################################## +# `~.TemperatureResponseFundamental` provides the functions and properties for +# calculating the temperature response. + +date_time = "2023-09-22T21:59:59" +tpf = xrtpy.response.TemperatureResponseFundamental( + xrt_filter, date_time, abundance_model="Photospheric" +) + +############################################################################## +# To calculate the temperature response,we can do the following: + +temperature_response = tpf.temperature_response() +print("Temperature Response:\n", temperature_response) + +############################################################################## +# We will now visualize the temperature response function using CHIANTI. +# These temperatures are of the plasma and are independent of the channel filter. +# +# We use the log of the these temperatures, to enhance the visibility of the +# variations at lower temperatures. + +chianti_temperature = np.log10(tpf.CHIANTI_temperature.to_value()) + +############################################################################## +# Differences overtime arise from an increase of the contamination layer on the +# CCD which blocks some of the X-rays thus reducing the effective area. +# For detailed information about the calculation of the XRT CCD contaminant layer thickness, +# you can refer to +# `Montana State University `__. +# +# Additional information is provided by +# `Narukage et. al. (2011) `__. + + +launch_datetime = "2006-09-22T23:59:59" + +launch_temperature_response = xrtpy.response.TemperatureResponseFundamental( + xrt_filter, launch_datetime, abundance_model="Photospheric" +).temperature_response() + +############################################################################## +# Now we can plot the temperature response versus the log of the CHIANTI temperature +# and compare the results for the launch date and the chosen date. + +plt.figure() + +plt.plot( + chianti_temperature, + np.log10(temperature_response.value), + label=f"{date_time}", +) +plt.plot( + chianti_temperature, + np.log10(launch_temperature_response.value), + label=f"{launch_datetime}", + color="red", +) + +plt.title("XRT Temperature Response") +plt.xlabel("Log(T) ($K$)") +plt.ylabel("$DN$ $cm^5$ $ s^-1$ $pix^-1$") +plt.legend() +plt.grid() + +plt.show() diff --git a/pyproject.toml b/pyproject.toml index f2c2631b9..3dc13ea55 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -61,29 +61,17 @@ tests = [ "pytest-xdist >= 3.6.1", ] docs = [ - "docutils >= 0.19", - "imageio >= 2.20.0", - "ipykernel >= 6.20.0", - "ipython >= 8.4.0", - "ipywidgets >= 8.1.0", - "jinja2 != 3.1, >= 3.0.0", - "nbconvert >= 7.7.0, < 7.14", - "nbsphinx >= 0.9", - "numpydoc >= 1.5.0", - "pillow >= 9.1.0", - "pygments >= 2.12.0", + "pydata_sphinx_theme >= 0.15.0", "sphinx >= 7.3.0", - "sphinx-changelog >= 1.5.0", - "sphinx-codeautolink >= 0.15.2", + "sphinx_automodapi >= 0.17.0", "sphinx-copybutton >= 0.5.2", + "sphinx-design>=0.2.0", "sphinx-gallery >= 0.16.0", "sphinx-hoverxref >= 1.4.0", "sphinx-issues >= 4.1.0", - "sphinx_automodapi >= 0.17.0", - "sphinx_rtd_theme >= 2.0.0", "sphinxcontrib-bibtex >= 2.6.2", + "sphinxext-opengraph>=0.6.0", "sunpy[net] >= 4.0.0", - "towncrier >= 23.11.0", ] [project.urls] @@ -166,8 +154,7 @@ ignore = [ [tool.ruff.lint.per-file-ignores] "__init__.py" = ["E402", "F401", "F402", "F403"] # ignore import errors -"docs/notebooks/computing_functions/temperature_response.ipynb" = ["A001"] # filter variable shadows Python builtin -"docs/notebooks/getting_started/A_Practical_Guide_to_Data_Extraction_and_Visualization.ipynb" = ["PTH106", "PTH107", "PTH118"] # should switch to using pathlib here later +"examples/*" = ["INP001"] # is part of an implicit namespace package. [tool.ruff.lint.flake8-import-conventions.aliases] "astropy.units" = "u" diff --git a/xrtpy/image_correction/__init__.py b/xrtpy/image_correction/__init__.py index 8aeb436b7..61cd0ba9e 100644 --- a/xrtpy/image_correction/__init__.py +++ b/xrtpy/image_correction/__init__.py @@ -1,8 +1,6 @@ """Subpackage for image correction""" -__all__ = [ - "deconvolve", - "remove_lightleak", -] +from xrtpy.image_correction.deconvolve import deconvolve +from xrtpy.image_correction.remove_lightleak import remove_lightleak -from xrtpy.image_correction import deconvolve, remove_lightleak +__all__ = ["deconvolve", "remove_lightleak"] diff --git a/xrtpy/image_correction/deconvolve.py b/xrtpy/image_correction/deconvolve.py index 312c5cc72..f40930c84 100644 --- a/xrtpy/image_correction/deconvolve.py +++ b/xrtpy/image_correction/deconvolve.py @@ -2,8 +2,6 @@ Functionality for deconvolving XRT image data with the point spread function. """ -__all__ = ["deconvolve"] - from datetime import datetime from urllib.parse import urljoin @@ -16,6 +14,8 @@ from xrtpy.util import SSW_MIRRORS +__all__ = ["deconvolve"] + @manager.require( "PSF560.fits", diff --git a/xrtpy/image_correction/remove_lightleak.py b/xrtpy/image_correction/remove_lightleak.py index eeb13a5fc..40473a414 100644 --- a/xrtpy/image_correction/remove_lightleak.py +++ b/xrtpy/image_correction/remove_lightleak.py @@ -2,8 +2,6 @@ Functionality for removing the visible light leak from XRT composite image data. """ -__all__ = ["remove_lightleak"] - import warnings from urllib.parse import urljoin @@ -15,6 +13,8 @@ from xrtpy.util import SSW_MIRRORS +__all__ = ["remove_lightleak"] + LL_FILE_HASHES = { "term_p1cp_20140527_204601.fits": "bdb924a6ae62292980b266cec0fb96c3626d921efe8148a13b26f964513ea533", "term_p1tp_20140515_182503.fits": "0f5211633069cfb6a2d9d95f42d42bf52c4e16e1c47b89d32c567b430cd794b0", diff --git a/xrtpy/response/__init__.py b/xrtpy/response/__init__.py index 4c45a7aed..1e863714d 100644 --- a/xrtpy/response/__init__.py +++ b/xrtpy/response/__init__.py @@ -1,6 +1,5 @@ """Response analysis for Hinode/XRT""" -from xrtpy.response import channel, effective_area, temperature_response from xrtpy.response.channel import ( CCD, Channel, @@ -11,10 +10,10 @@ resolve_filter_name, ) from xrtpy.response.effective_area import EffectiveAreaFundamental +from xrtpy.response.temperature_from_filter_ratio import temperature_from_filter_ratio from xrtpy.response.temperature_response import TemperatureResponseFundamental __all__ = [ - "channel", "Geometry", "EntranceFilter", "Mirror", @@ -23,7 +22,6 @@ "Channel", "resolve_filter_name", "EffectiveAreaFundamental", - "effective_area", - "temperature_response", "TemperatureResponseFundamental", + "temperature_from_filter_ratio", ] diff --git a/xrtpy/response/channel.py b/xrtpy/response/channel.py index fffef20a3..6a11cb984 100644 --- a/xrtpy/response/channel.py +++ b/xrtpy/response/channel.py @@ -1,5 +1,12 @@ """Classes for describing channels on Hinode/XRT.""" +from pathlib import Path + +import numpy as np +import sunpy.io.special +import sunpy.time +from astropy import units as u + __all__ = [ "Geometry", "EntranceFilter", @@ -10,15 +17,6 @@ "resolve_filter_name", ] -from pathlib import Path - -import numpy as np -import sunpy.io.special -import sunpy.time -from astropy import units as u - -filename = Path(__file__).parent.absolute() / "data" / "xrt_channels_v0016.genx" - _channel_name_to_index_mapping = { "Al-mesh": 0, "Al-poly": 1, @@ -35,9 +33,9 @@ "Al-poly/Be-thick": 12, "C-poly/Ti-poly": 13, } - - -_genx_file = sunpy.io.special.genx.read_genx(filename)["SAVEGEN0"] +_genx_file = sunpy.io.special.genx.read_genx( + Path(__file__).parent.absolute() / "data" / "xrt_channels_v0016.genx" +)["SAVEGEN0"] def resolve_filter_name(name): diff --git a/xrtpy/response/effective_area.py b/xrtpy/response/effective_area.py index 4796fa8a7..468bafd98 100644 --- a/xrtpy/response/effective_area.py +++ b/xrtpy/response/effective_area.py @@ -1,6 +1,5 @@ __all__ = [ "EffectiveAreaFundamental", - "effective_area", ] import datetime @@ -250,9 +249,9 @@ def contamination_on_filter1_combo(self) -> u.angstrom: Notes ----- The interpolation is performed using a linear interpolation method over the - available contamination data points. The `filter_data_dates_to_seconds` and - `_combo_filter1_data` attributes are used to provide the data for interpolation, - and `filter_observation_date_to_seconds` provides the point at which to + available contamination data points. The ``filter_data_dates_to_seconds`` and + ``_combo_filter1_data`` attributes are used to provide the data for interpolation, + and ``filter_observation_date_to_seconds`` provides the point at which to evaluate the interpolation. Raises @@ -283,9 +282,9 @@ def contamination_on_filter2_combo(self) -> u.angstrom: Notes ----- The interpolation is performed using a linear interpolation method over the - available contamination data points. The `filter_data_dates_to_seconds` and - `_combo_filter2_data` attributes are used to provide the data for interpolation, - and `filter_observation_date_to_seconds` provides the point at which to + available contamination data points. The ``filter_data_dates_to_seconds`` and + ``_combo_filter2_data`` attributes are used to provide the data for interpolation, + and ``filter_observation_date_to_seconds`` provides the point at which to evaluate the interpolation. Raises @@ -325,7 +324,7 @@ def contamination_on_filter(self) -> u.angstrom: The interpolation is performed using a linear interpolation method over the available contamination data points. The `observation_date` attribute is used to provide the point at which to evaluate the interpolation. The data used for interpolation is specific to - the filter defined by the `filter_name` attribute. + the filter defined by the ``filter_name`` attribute. Raises ------ @@ -619,29 +618,3 @@ def effective_area(self) -> u.cm**2: * self._interpolated_CCD_contamination_transmission * self._interpolated_filter_contamination_transmission ) - - -def effective_area(filter_name, observation_date): - r""" - Calculate the effective area for a given XRT filter at a specific observation date. - - Parameters - ---------- - filter_name : str - The name of the filter for which the effective area is to be calculated. - observation_date : str or datetime.datetime - The date of the observation. Acceptable formats include any string or datetime object - that can be parsed by `sunpy.time.parse_time`. - - Returns - ------- - astropy.units.Quantity - Effective area in cm\ :math:`^2`. - - Notes - ----- - The effective area calculation takes into account the geometry of the XRT flight model, - the channel transmission, and the contamination layers on both the CCD and the filter. - """ - EAP = EffectiveAreaFundamental(filter_name, observation_date) - return EAP.effective_area() diff --git a/xrtpy/response/temperature_from_filter_ratio.py b/xrtpy/response/temperature_from_filter_ratio.py index a9664966a..8ec7f45f6 100644 --- a/xrtpy/response/temperature_from_filter_ratio.py +++ b/xrtpy/response/temperature_from_filter_ratio.py @@ -3,8 +3,6 @@ ratio technique. """ -__all__ = ["temperature_from_filter_ratio"] - import logging from collections import namedtuple from datetime import datetime @@ -18,6 +16,8 @@ from xrtpy.response.temperature_response import TemperatureResponseFundamental +__all__ = ["temperature_from_filter_ratio"] + TempEMdata = namedtuple("TempEMdata", "Tmap, EMmap, Terrmap, EMerrmap") # noqa: PYI024 diff --git a/xrtpy/util/__init__.py b/xrtpy/util/__init__.py index 926ff1142..0fbc5045e 100644 --- a/xrtpy/util/__init__.py +++ b/xrtpy/util/__init__.py @@ -1,9 +1,9 @@ -from xrtpy.util import filename2repo_path, make_exposure_map, time +from xrtpy.util.filename2repo_path import filename2repo_path +from xrtpy.util.make_exposure_map import make_exposure_map from xrtpy.util.time import epoch __all__ = [ "epoch", - "time", "filename2repo_path", "make_exposure_map", "SSW_MIRRORS", diff --git a/xrtpy/util/time.py b/xrtpy/util/time.py index e11771ed6..1b9c561fd 100644 --- a/xrtpy/util/time.py +++ b/xrtpy/util/time.py @@ -1,8 +1,6 @@ -__all__ = [ - "epoch", -] - import astropy.time +__all__ = ["epoch"] + # Hinode-XRT mission elapsed time "Epoch" is Sept 22, 2006 21:36:00. epoch = astropy.time.Time("2006-09-22 21:36:00") From f7cb6fab76e8394133dcf1480397c057db0dd3b4 Mon Sep 17 00:00:00 2001 From: Nabil Freij Date: Sat, 14 Sep 2024 22:19:00 -0700 Subject: [PATCH 2/4] First round of CRs --- LICENSE | 2 +- README.md | 6 +- changelog/139.removal.rst | 1 - changelog/187.doc.rst | 3 - changelog/README.md | 0 docs/about_xrt.rst | 55 ++++++++++++ docs/code_of_conduct.rst | 4 +- docs/conf.py | 6 +- docs/feedback_communication.rst | 2 +- docs/getting_started.rst | 144 -------------------------------- docs/index.rst | 7 +- docs/install.rst | 79 ++---------------- docs/reference/index.rst | 8 +- examples/README.txt | 2 +- examples/channels.py | 4 +- pyproject.toml | 4 +- 16 files changed, 81 insertions(+), 246 deletions(-) delete mode 100644 changelog/139.removal.rst delete mode 100644 changelog/187.doc.rst delete mode 100644 changelog/README.md delete mode 100644 docs/getting_started.rst diff --git a/LICENSE b/LICENSE index 7dd4d0b9c..44c7e7d1f 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ BSD 2-Clause License -Copyright (c) 2021–2023, XRTpy contributors +Copyright (c) 2021-2024, XRTpy contributors All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/README.md b/README.md index 21d098753..ad41ed28d 100644 --- a/README.md +++ b/README.md @@ -5,10 +5,8 @@ [![Read the Docs Status](https://readthedocs.org/projects/xrtpy/badge/?version=latest&logo=twitter)](http://xrtpy.readthedocs.io/en/latest/?badge=latest) [![astropy](http://img.shields.io/badge/powered%20by-AstroPy-orange.svg?style=flat&logo=astropy)](http://www.astropy.org/) -XRTpy is a Python package being developed for the analysis of observations -made by the X-Ray Telescope (XRT) on the *Hinode* spacecraft. +XRTpy is a Python package being developed for the analysis of observations made by the X-Ray Telescope (XRT) on the *Hinode* spacecraft. ## Acknowledgements -The development of XRTpy is supported by NASA contract NNM07AB07C to the -Smithsonian Astrophysical Observatory. +The development of XRTpy is supported by NASA contract NNM07AB07C to the Smithsonian Astrophysical Observatory. diff --git a/changelog/139.removal.rst b/changelog/139.removal.rst deleted file mode 100644 index 7f0939c7a..000000000 --- a/changelog/139.removal.rst +++ /dev/null @@ -1 +0,0 @@ -Removed support for Python 3.8. XRTpy now requires Python 3.9 or newer. diff --git a/changelog/187.doc.rst b/changelog/187.doc.rst deleted file mode 100644 index 040b53c83..000000000 --- a/changelog/187.doc.rst +++ /dev/null @@ -1,3 +0,0 @@ -Added Sphinx extensions to allow code blocks in the documentation to -be copied and to create links to pages that show source code of -different objects. diff --git a/changelog/README.md b/changelog/README.md deleted file mode 100644 index e69de29bb..000000000 diff --git a/docs/about_xrt.rst b/docs/about_xrt.rst index 5ac7716ee..aadc69a19 100644 --- a/docs/about_xrt.rst +++ b/docs/about_xrt.rst @@ -18,6 +18,9 @@ These instruments are designed to provide multi-wavelength data from the photosp The solar spacecraft spacecraft was launched at 6:36 a.m on September 23, 2006 (Japan Standard Time) and placed into a polar, sun-synchronous orbit, enabling continuous observations of the Sun. For further information, visit `NASA's Hinode space mission to the Sun`_. + +.. _xrtpy-about-xrt-filters: + The X-Ray Telescope =================== @@ -35,6 +38,58 @@ For a comprehensive overview of XRT's mission and capabilities, please visit the Visit the `XRT Picture of the Week`_ and the `Hinode-XRT YouTube`_ page for captivating visual content showcasing the XRT's solar observations. +XRT uses two sequentially positioned filter wheels, as shown in the diagram below, where each wheel houses a variety of filters. +By rotating these wheels, scientists can select different filters to study the Sun in different wavelengths, thereby enhancing the resolution and quality of solar images. +Refer to Section 3 in the "X-Ray Telescope Instrument Guide" in the `SolarSoft XRT Analysis Guide`_ for more information abo[ut the XRT filters. +The existing filters are structured as follows: + +#. Filter Configuration + #. Filter position + #. Filter Wheel 1: + - *Open* + - Aluminum Polyimide (*Al-poly*) + - Carbon Polyimide (*C-poly*) + - Beryllium Thin (*Be-thin*) + - Beryllium Medium (*Be-med*) + - Aluminum Medium (*Al-med*) + #. Filter Wheel 2: + - *Open* + - Aluminum Mesh (*Al-mesh*) + - Titanium Polyimide (*Ti-poly*) + - *G-band* + - Aluminum Thick (*Al-thick*) + - Beryllium Thick (*Be-thick*) + #. *Open* + Each filter wheel has an empty position, named 'Open'. + The open position is in place when a filter on the other filter wheel is being used. + #. *G-band* + The G-Band filter allows visible light into the telescope and onto the CCD. + XRTpy does not calculate the effective area or the temperature response for the G-Band filter. + +.. note:: + + Filters are expressed by their abbreviation when used in XRTpy. + For example, if we want to explore the filter channel that selects the Titanium Polyimide filter, then the string would be ``'Ti-poly'``. + The process is the same for all XRT filter channels. + +.. image:: _static/images/XRT_filter_wheels_Sun_View_Diagram.png + :alt: Diagram of the XRT Filter Wheels + :align: center + +Data Products +************* + +The XRT website provides readily available `XRT data products`_, including both Level 1 and Level 2 data. +The `Level 1 Data`_ section contains an extensive archive of all Level 1 XRT data that has been calibrated using the `xrt_prep`_ routine, with units expressed in Data Numbers. +Additionally, for users interested in synoptic images, `Level 2 Synoptics`_ data is available, which consists of composite images from the twice-daily synoptic program. +These images have been processed and are available in the archive. +For more detailed information about our XRT data products, please visit the `XRT data products`_ site, where you can find comprehensive data resources and references. + +.. _Level 1 Data: https://xrt.cfa.harvard.edu/level1/ +.. _Level 2 Synoptics: https://xrt.cfa.harvard.edu/data_products/Level2_Synoptics/ +.. _XRT data products: https://xrt.cfa.harvard.edu/data_products/index.php +.. _xrt_prep: https://xrt.cfa.harvard.edu/resources/documents/XAG/XAG.pdf + SolarSoft XRT Analysis Guide ============================ diff --git a/docs/code_of_conduct.rst b/docs/code_of_conduct.rst index 81e1fde1a..8970e0515 100644 --- a/docs/code_of_conduct.rst +++ b/docs/code_of_conduct.rst @@ -1,4 +1,4 @@ -.. _xrtpy-coc: +.. _XRTpy-coc: *************** Code of Conduct @@ -42,7 +42,7 @@ Community leaders are responsible for enforcing these rules and taking correctiv **Enforcement and Reporting** -- Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at ``xrtpy@cfa.harvard.edu``. +- Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at ``XRTpy@cfa.harvard.edu``. All complaints will be reviewed and investigated promptly and fairly. - Community leaders are obligated to respect the privacy and security of the reporter of any incident. diff --git a/docs/conf.py b/docs/conf.py index 6bdd721d5..786e15e3e 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -29,7 +29,7 @@ ) # -- Project information ------------------------------------------------------- -project = "xrtpy" +project = "XRTpy" author = "Joy Velasquez, Nick Murphy, and Jonathan Slavin" copyright = f"2021-{datetime.now(tz=UTC).year}, {author}" @@ -67,7 +67,7 @@ linkcheck_anchors_ignore = [] # sphinxext-opengraph -ogp_image = "https://raw.githubusercontent.com/HinodeXRT/xrtpy/main/docs/_static/images/XRTpy_logo.png" +ogp_image = "https://raw.githubusercontent.com/HinodeXRT/xrtpy/main/docs/_static/images/xrtpy_logo.png" ogp_use_first_image = True ogp_description_length = 160 ogp_custom_meta_tags = [ @@ -238,7 +238,7 @@ html_theme = "pydata_sphinx_theme" html_theme_options = { "logo": { - "text": "XrtPy", + "text": "XRTpy", }, "use_edit_page_button": True, "icon_links": [ diff --git a/docs/feedback_communication.rst b/docs/feedback_communication.rst index 7a7377646..266c08d67 100644 --- a/docs/feedback_communication.rst +++ b/docs/feedback_communication.rst @@ -4,7 +4,7 @@ Providing Feedback ****************** -XRTpy has several methods that one can use to get contact with XRTpy developers, giving feedback or giving feedback. +XRTpy has several methods that one can use to get contact with the XRTpy developers. Feedback ======== diff --git a/docs/getting_started.rst b/docs/getting_started.rst deleted file mode 100644 index f1fc16c24..000000000 --- a/docs/getting_started.rst +++ /dev/null @@ -1,144 +0,0 @@ -.. _xrtpy-getting-started: - -=============== -Getting Started -=============== - -XRTpy is a Python package being developed for the analysis of observations made by the X-Ray Telescope (XRT) on the board Hinode spacecraft. -This page is intended for new users of `xrtpy`. For more background information about XRT please refer to the `SolarSoft XRT Analysis Guide`_. - -XRTpy Objects -************* - -XRTpy currently offers *Channel*, *Effective Area*, and *Temperature Response* classes. -There is the ability to to derive temperatures and emission measures for a pair of images, sharpen images using a Point Spread Function (PSF) deconvolution, and to correct synoptic images for the light leak (visible stray light) that XRT has developed. -Visit our Example page for detail notebook example guides on how to use the XRTpy classes and functions. - -Channel -------- - -|Channel| is an instrument configuration class that contains the properties of particular XRT filters. -It provides a detailed information on the filter channel, including the Charge-Coupled Device (CCD), Entrance Filter, Focus-Filter(s), Geometry, and Mirror(s). - -Effective Area --------------- - -XRTpy calculates the effective areas for a set of XRT filter channels paired with thicknesses of the CCD contamination layer. -For more information about the instrumental spectral responses, refer to the `SolarSoft XRT Analysis Guide`_. - -Temperature Response --------------------- - -XRTpy calculates the temperature response for each XRT filter channel, assuming a spectral emission model, refer to :cite:t:`narukage:2011` and :cite:t:`narukage:2014`. -The XRT default emission model is `CHIANTI`_ atomic database version 10.0 with coronal abundances :cite:t:`feldman:1992`. -This structure contains data and information about a plasma emission model, as a function of wavelength and temperature. - -Deriving Temperature and Emission Measure for a Pair of Images --------------------------------------------------------------- - -XRTpy provides a routine, *temperature_from_filter_ratio*, that employs the objects listed above to derive the temperature and emission measure in for a given pair of images using the filter ratio method. -This uses the same methods as in the SolarSoft IDL routine of the same name. -Familiarize yourself with the utilization of this function through the notebook example provided on our Example page. - -Enhancing Images Sharpness with Point Spread Function - Deconvolution ---------------------------------------------------------------------- - -Deconvolution is a powerful technique used to enhance image sharpness by mitigating the blurring effect -caused by the telescope's point spread function (PSF). -It is particularly useful for removing the blurring around sharp objects or features in the XRT image. -To learn how to use *deconvolve*, refer to the notebook examples provided on our Example page. - -Subtracting Light Leak from XRT Synoptic Composite Images ---------------------------------------------------------- - -We have developed a specialized function designed to subtract light leak, *remove_lightleak*, which refers to visible stray light, from XRT synoptic composite images. -By applying this function, you can effectively remove the unwanted artifacts caused by light leak, resulting in cleaner and more accurate images for further analysis and interpretation. -Explore our Example page for a notebook example that demonstrate the usage of this function. - -Abundance Model ---------------- - -The standard XRT temperature response routines are calculated assuming `CHIANTI`_ coronal abundances, :cite:t:`feldman:1992`. -Additionally, XRTpy offers the ability to choose two other sets of `CHIANTI`_ abundances i.e., Hybrid and Photospheric. -The Hybrid abundances are based on :cite:t:`Fludra:1999` and Photospheric abundances are base on :cite:t:`Grevesse:2007`. -The `CHIANTI`_ files contain data and information about a plasma emission model, as a function of wavelength and temperature. -Visit `XRT temperature response with other choice of abundances`_ for future detailed information. - -.. note:: - - XRTpy has future plans to accept other plasma emission spectra models. - -XRTpy defaults to using CHIANTI's "coronal" abundance. -You can specify the other abundances by defining the abundance type name, such as "hybrid" or "photospheric" in the ``abundance_model`` parameter. - -For example: - -.. code-block:: python - - xrtpy.response.TemperatureResponseFundamental( - "Al-poly", "2022/07/04T23:43:12", abundance_model="Hybrid" - ) - -The ``abundance_model`` parameter is used in the same format in `xrtpy.response.temperature_from_filter_ratio`. - -Data Products -************* - -The XRT website provides readily available `XRT data products`_, including both Level 1 and Level 2 data. -The `Level 1 Data`_ section contains an extensive archive of all Level 1 XRT data that has been calibrated using the `xrt_prep`_ routine, with units expressed in Data Numbers. -Additionally, for users interested in synoptic images, `Level 2 Synoptics`_ data is available, which consists of composite images from the twice-daily synoptic program. -These images have been processed and are available in the archive. -For more detailed information about our XRT data products, please visit the `XRT data products`_ site, where you can find comprehensive data resources and references. - -.. _Level 1 Data: https://xrt.cfa.harvard.edu/level1/ -.. _Level 2 Synoptics: https://xrt.cfa.harvard.edu/data_products/Level2_Synoptics/ -.. _XRT data products: https://xrt.cfa.harvard.edu/data_products/index.php -.. _xrt_prep: https://xrt.cfa.harvard.edu/resources/documents/XAG/XAG.pdf - -.. _xrtpy-getting-started-filters: - -X-Ray Filter Channel -******************** - -XRT uses two sequentially positioned filter wheels, as shown in the diagram below, where each wheel houses a variety of filters. -By rotating these wheels, scientists can select different filters to study the Sun in different wavelengths, thereby enhancing the resolution and quality of solar images. -Refer to Section 3 in the "X-Ray Telescope Instrument Guide" in the `SolarSoft XRT Analysis Guide`_ for more information abo[ut the XRT filters. -The existing filters are structured as follows: - -#. Filter Configuration - #. Filter position - #. Filter Wheel 1: - - *Open* - - Aluminum Polyimide (*Al-poly*) - - Carbon Polyimide (*C-poly*) - - Beryllium Thin (*Be-thin*) - - Beryllium Medium (*Be-med*) - - Aluminum Medium (*Al-med*) - #. Filter Wheel 2: - - *Open* - - Aluminum Mesh (*Al-mesh*) - - Titanium Polyimide (*Ti-poly*) - - *G-band* - - Aluminum Thick (*Al-thick*) - - Beryllium Thick (*Be-thick*) - #. *Open* - Each filter wheel has an empty position, named 'Open'. - The open position is in place when a filter on the other filter wheel is being used. - #. *G-band* - The G-Band filter allows visible light into the telescope and onto the CCD. - XRTpy does not calculate the effective area or the temperature response for the G-Band filter. - -.. note:: - - Filters are expressed by their abbreviation when used in XRTpy. - For example, if we want to explore the filter channel that selects the Titanium Polyimide filter, then the string would be ``'Ti-poly'``. - The process is the same for all XRT filter channels. - -.. image:: _static/images/XRT_filter_wheels_Sun_View_Diagram.png - :alt: Diagram of the XRT Filter Wheels - :align: center - -.. _CHIANTI: https://www.chiantidatabase.org/chianti_database_history.html -.. _SolarSoft XRT Analysis Guide: https://xrt.cfa.harvard.edu/resources/documents/XAG/XAG.pdf -.. _xrt-cfa-harvard: https://xrt.cfa.harvard.edu/index.php -.. _XRT temperature response with other choice of abundances: http://solar.physics.montana.edu/takeda/xrt_response/xrt_resp.html diff --git a/docs/index.rst b/docs/index.rst index 9103704e1..a7004bb07 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -9,17 +9,14 @@ XRTpy Documentation :align: center :scale: 50% -This is the documentation for XRTpy, a Python_ package being developed for the analysis of observations made by the `X-Ray Telescope`_ (XRT) :cite:p:`golub:2007` on the Hinode_ spacecraft :cite:p:`kosugi:2007`. - -This is for version |version| of XRTpy. +This is the documentation for XRTpy (version |version|), a Python_ package being developed for the analysis of observations made by the `X-Ray Telescope`_ (XRT) :cite:p:`golub:2007` on the Hinode_ spacecraft :cite:p:`kosugi:2007`. .. toctree:: - :maxdepth: 2 + :maxdepth: 1 :caption: Contents: about_xrt install - getting_started generated/gallery/index reference/index acknowledging_xrtpy diff --git a/docs/install.rst b/docs/install.rst index a9aacafcf..8c586e714 100644 --- a/docs/install.rst +++ b/docs/install.rst @@ -1,4 +1,4 @@ -.. _xrtpy-install: +.. _XRTpy-install: **************** Installing XRTpy @@ -7,79 +7,10 @@ Installing XRTpy Installing Python ================= -There are many ways to install Python, but even if you have Python installed somewhere on your computer we recommend following these instructions anyway. -That's because we will create a new Python environment. -As well as containing a Python installation, this environment provides an isolated place to install Python packages (like ``xrtpy``) without affecting any other current Python installation. -If you already have Python and ``conda`` working you can skip the next section. -Please note that XRTpy requires Python_ |minpython| or newer. +To use ``xrtpy``, you will need to have Python installed on your system. +We recommend following :ref:`sunpy-tutorial-installing` which walks you through installing Python. -.. tip:: - - New versions of Python_ are released annually in October, and it can take a few months for the scientific Python ecosystem to catch up. - If you have trouble installing `xrtpy` on the most recent Python_ version between October and ∼March, then try installing it on the second most recent version. - -`If you are using Anaconda, we recommend that you uninstall it as the default package channel(s) have a restrictive license which means you might not be able to use it for free `__. -Instead, we recommend that you use miniforge which is a minimal installer that setups conda with the conda-forge channel, which is free to use for everyone. -If you are using miniforge, you can skip the next section - -Installing miniforge --------------------- - -If you don't already have a Python installation then we recommend installing Python with `miniforge `__. -This will install ``conda`` and automatically configure the default channel (a channel is a remote software repository) to be ``conda-forge``, which is where ``sunpy`` is available. - -First, download the installer for your system and architecture from the links below: - -.. grid:: 3 - - .. grid-item-card:: Linux - - `x86-64 `__ - - `aarch64 `__ - - `ppc64le `__ - - .. grid-item-card:: Windows - :link: https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-Windows-x86_64.exe - - `x86-64 `__ - - .. grid-item-card:: Mac - - `x86-64 `__ - - `arm64 (Apple - Silicon) `__ - -Then select your platform to install miniforge: - -.. tab-set:: - - .. tab-item:: Linux & Mac - :sync: platform - - Linux & Mac Run the script downloaded above, with - ``bash ``. The following should work: - - .. code-block:: console - - bash Miniforge3-$(uname)-$(uname -m).sh - - Once the installer has completed, close and reopen your terminal. - - .. tab-item:: Windows - :sync: platform - - Double click the executable file downloaded from - the links above. - - Once the installer has completed you should have a new "miniforge - Prompt" entry in your start menu. - -In a new terminal (miniforge Prompt on Windows) run ``conda list`` to test that the install has worked. - -Installing xrtpy +Installing XRTpy ---------------- To install ``xrtpy``, start by launching a terminal (under a UNIX-like system) or the miniforge Prompt (under Windows). @@ -116,7 +47,7 @@ pip This is for installing ``xrtpy`` within a Python environment, where ``pip`` has been used to install all previous packages. You will want to make sure you are using a `Python virtual environment `__. -Once the environment active, to acquire a full ``xrtpy`` installation: +Once the environment active, to acquire a ``xrtpy`` installation: .. code-block:: bash diff --git a/docs/reference/index.rst b/docs/reference/index.rst index fd6b8fe12..8882898b3 100644 --- a/docs/reference/index.rst +++ b/docs/reference/index.rst @@ -1,6 +1,8 @@ -******************* -xrtpy API Reference -******************* +.. _xrtpy-api-index: + +************* +API Reference +************* .. toctree:: :maxdepth: 1 diff --git a/examples/README.txt b/examples/README.txt index 264c1806b..d3289aaeb 100644 --- a/examples/README.txt +++ b/examples/README.txt @@ -2,4 +2,4 @@ Example Gallery *************** -The gallery contains examples of how to use ``xrtpy``. +The gallery contains examples of how to use XRTpy. diff --git a/examples/channels.py b/examples/channels.py index f155c2a02..485fbfaba 100644 --- a/examples/channels.py +++ b/examples/channels.py @@ -15,7 +15,7 @@ ############################################################################## # We begin by defining a filter channel by its common abbreviation. # In this example we will be exploring the titanium-on-polyimide filter. -# For detailed information about various filter channels and their characteristics, you can refer to :ref:`xrtpy-getting-started-filters`. +# For detailed information about various filter channels and their characteristics, you can refer to :ref:`xrtpy-about-xrt-filters`. # # To explore the properties and characteristics of a defined filter channel, we will create a # `xrtpy.response.Channel`. By passing in the filter name as an input, we can work @@ -62,7 +62,7 @@ # we can explore detailed information about the selected XRT channel filter. # # It's worth noting that sometimes the other filter will yield the result "Open," as it's not use. -# For more comprehensive information about the XRT filters, you can refer to :ref:`xrtpy-getting-started-filters`. +# For more comprehensive information about the XRT filters, you can refer to :ref:`xrtpy-about-xrt-filters`. print("Filter Wheel:", channel.filter_2.filter_name) print("\nFilter material:", channel.filter_2.filter_material) diff --git a/pyproject.toml b/pyproject.toml index 3dc13ea55..711546d00 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,7 @@ requires = [ ] [project] -name = "xrtpy" +name = "XRTpy" readme = "README.md" keywords = ["solar physics"] description = "For analyzing data from the X-Ray Telescope (XRT) on the Hinode spacecraft." @@ -215,7 +215,7 @@ write_to = "xrtpy/version.py" [tool.towncrier] package = "xrtpy" -name = "XRTpy" +name = "xrtpy" filename = "CHANGELOG.rst" directory = "changelog/" title_format = "{name} v{version} ({project_date})" From 8d14b47903d10cef37da401881ad7c6fd74030dc Mon Sep 17 00:00:00 2001 From: Nabil Freij Date: Tue, 24 Sep 2024 09:54:09 -0700 Subject: [PATCH 3/4] Fixed norm of images --- examples/remove_lightleak.py | 26 +++++++++++++++++++++++--- examples/sorting_data.py | 13 ++++++++++--- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/examples/remove_lightleak.py b/examples/remove_lightleak.py index ea6b1e36c..51e5c6f4f 100644 --- a/examples/remove_lightleak.py +++ b/examples/remove_lightleak.py @@ -9,10 +9,10 @@ from pathlib import Path -import astropy.units as u import matplotlib.pyplot as plt import sunpy.map from astropy.utils.data import get_pkg_data_path +from astropy.visualization import ImageNormalize, SqrtStretch from xrtpy.image_correction import remove_lightleak @@ -35,14 +35,34 @@ fig = plt.figure(figsize=(12, 6)) ax = fig.add_subplot(121, projection=xrt_map) -xrt_map.plot(axes=ax, title="Original", clip_interval=(1, 99.9) * u.percent) +xrt_map.plot( + axes=ax, + title="Original", + norm=ImageNormalize(vmin=0, vmax=7e3, stretch=SqrtStretch()), +) ax1 = fig.add_subplot(122, projection=lightleak_map) lightleak_map.plot( - axes=ax1, title="Light Leak Subtracted", clip_interval=(1, 99.9) * u.percent + axes=ax1, + title="Light Leak Subtracted", + norm=ImageNormalize(vmin=0, vmax=7e3, stretch=SqrtStretch()), ) ax1.coords[1].set_ticks_visible(False) ax1.coords[1].set_ticklabel_visible(False) fig.tight_layout() +############################################################################## +# They look almost identical, but the light leak has been removed from the second image. +# To confirm this we can plot the difference between the two images. + +diff_data = xrt_map.data - lightleak_map.data +# For this image, the difference is very small. +print(diff_data.min(), diff_data.max()) + +fig = plt.figure() +ax = fig.add_subplot(111) +ax.set_title("Lightleak Difference") +im = ax.imshow(diff_data, origin="lower") +fig.colorbar(im) + plt.show() diff --git a/examples/sorting_data.py b/examples/sorting_data.py index 60e5ecc49..ed4fe0b98 100644 --- a/examples/sorting_data.py +++ b/examples/sorting_data.py @@ -9,6 +9,7 @@ import astropy.units as u import matplotlib.pyplot as plt import sunpy.map +from astropy.visualization import ImageNormalize, SqrtStretch from sunpy.net import Fido from sunpy.net import attrs as a @@ -49,7 +50,9 @@ fig = plt.figure() ax = fig.add_subplot(projection=xrt_seq.maps[0]) -ani = xrt_seq.plot(axes=ax) +ani = xrt_seq.plot( + axes=ax, norm=ImageNormalize(vmin=0, vmax=5e3, stretch=SqrtStretch()) +) ############################################################################## # You might notice that there is a jump in the sequence. @@ -62,7 +65,9 @@ fig = plt.figure() ax = fig.add_subplot(projection=xrt_seq.maps[0]) -ani = xrt_seq_filtered_shape.plot(axes=ax) +ani = xrt_seq_filtered_shape.plot( + axes=ax, norm=ImageNormalize(vmin=0, vmax=5e3, stretch=SqrtStretch()) +) ############################################################################## # In fact, `sunpy.map.Map` provides many attributes that can be used to filter the data. @@ -76,7 +81,9 @@ fig = plt.figure() ax = fig.add_subplot(projection=xrt_seq.maps[0]) -ani = xrt_seq_filtered_exp_time.plot(axes=ax) +ani = xrt_seq_filtered_exp_time.plot( + axes=ax, norm=ImageNormalize(vmin=0, vmax=5e3, stretch=SqrtStretch()) +) ############################################################################## # If you want to save this animation to a file, you can use the ``save`` method. From 03261dbfa550cd43f98bad49ac994dc06df83270 Mon Sep 17 00:00:00 2001 From: Nabil Freij Date: Thu, 12 Dec 2024 14:44:44 -0800 Subject: [PATCH 4/4] precommit --- .pre-commit-config.yaml | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c41cd9921..b97f26f8a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -23,12 +23,12 @@ repos: - id: check-yaml - repo: https://github.com/python-jsonschema/check-jsonschema - rev: 0.29.4 + rev: 0.30.0 hooks: - id: check-github-workflows - repo: https://github.com/sirosen/texthooks - rev: 0.6.7 + rev: 0.6.8 hooks: - id: fix-smartquotes - id: fix-spaces @@ -40,6 +40,7 @@ repos: hooks: - id: remove-crlf name: remove CRLF line endings + - repo: https://github.com/macisamuele/language-formatters-pre-commit-hooks rev: v2.14.0 hooks: @@ -48,12 +49,6 @@ repos: - id: pretty-format-yaml args: [--autofix] -- repo: https://github.com/MarcoGorelli/absolufy-imports - rev: v0.3.1 - hooks: - - id: absolufy-imports - name: Use absolute rather than relative imports - - repo: https://github.com/pre-commit/pygrep-hooks rev: v1.10.0 hooks: @@ -72,7 +67,7 @@ repos: exclude: .*\.fits - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.7.2 + rev: v0.8.3 hooks: - id: ruff name: ruff @@ -86,4 +81,4 @@ repos: - id: blacken-docs name: autoformat code blocks in docs additional_dependencies: - - black \ No newline at end of file + - black