diff --git a/.github/workflows/publish-docs.yml b/.github/workflows/publish-docs.yml index 1298df9..6650db2 100644 --- a/.github/workflows/publish-docs.yml +++ b/.github/workflows/publish-docs.yml @@ -4,6 +4,10 @@ on: branches: - master + pull_request: + branches: + - master + workflow_dispatch: # Manual trigger jobs: @@ -13,6 +17,11 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Install system dependencies (pandoc) + run: | + sudo apt-get update + sudo apt-get install -y pandoc + - uses: actions/setup-python@v5 with: python-version: '3.10' @@ -33,9 +42,25 @@ jobs: make clean make html - - name: Deploy docs + # Deploy stable docs (root of gh-pages) only from master pushes + - name: Deploy docs (stable) + if: github.event_name == 'push' && github.ref == 'refs/heads/master' uses: peaceiris/actions-gh-pages@v3 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: ./docs/_build/html + # Deploy PR preview docs to gh-pages under pr// + - name: Deploy docs (PR preview) + if: github.event_name == 'pull_request' + uses: peaceiris/actions-gh-pages@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./docs/_build/html + destination_dir: pr/${{ github.event.pull_request.number }} + keep_files: true + + - name: Print PR preview URL + if: github.event_name == 'pull_request' + run: | + echo "Deployed PR docs preview at: https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/pr/${{ github.event.pull_request.number }}/" diff --git a/README.md b/README.md index 84eb314..4b47e5a 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,5 @@ Python API for [Firefly](http://github.com/Caltech-IPAC/firefly), IPAC's Advance You can find the documentation at https://caltech-ipac.github.io/firefly_client. -NOTE: Many parts of this documentation are a work in progress because the firefly_client API and its use cases evolved since it was written. Please report any issues or suggestions on the [GitHub issues](https://github.com/Caltech-IPAC/firefly_client/issues). diff --git a/docs/_ext/script_pages.py b/docs/_ext/script_pages.py new file mode 100644 index 0000000..958ba7b --- /dev/null +++ b/docs/_ext/script_pages.py @@ -0,0 +1,223 @@ +"""Sphinx extension: generate per-script RST pages, copy .py into built _sources, and rewrite source links.""" +import os +import glob +import io +from sphinx.util import logging + +logger = logging.getLogger(__name__) + +MARKER_TEMPLATE = '.. AUTO-GENERATED from {}' + + +def _title_from_script(path): + """Extract a title from the first commented heading line; fallback to filename.""" + title = os.path.splitext(os.path.basename(path))[0] + try: + with io.open(path, 'r', encoding='utf-8') as fh: + first_line = fh.readline() + # Skip shebang (#!) if present + if first_line and first_line.lstrip().startswith('#!'): + first_line = fh.readline() + # Look for first comment line + title_comment = None + if first_line and first_line.lstrip().startswith('#'): + title_comment = first_line.strip().lstrip('#').strip() + if title_comment: + title = title_comment + except Exception: + pass + return title + + +def _generate_rst_for_scripts(app): + """Create a .rst next to each .py under docs/usage/examples/. + + - If `.rst` already exists and does NOT start with our auto-generated marker, + we leave it alone (so user-written RST isn't overwritten). + - Otherwise we create or overwrite the RST to include the script via literalinclude. + """ + logger = logging.getLogger(__name__) + srcdir = app.srcdir + + patterns = [ + os.path.join(srcdir, 'usage', 'examples', '*.py'), + ] + py_files = [] + for pat in patterns: + py_files.extend(glob.glob(pat)) + py_files = sorted(set(py_files)) + + generated = 0 + + for script_fpath in py_files: + script_basename = os.path.basename(script_fpath) + # Skip conf.py and other build files + if script_basename in ('conf.py',): + continue + + rst_path = os.path.splitext(script_fpath)[0] + '.rst' + marker = MARKER_TEMPLATE.format(script_basename) + + # If rst exists and not generated by us, skip it + if os.path.exists(rst_path): + try: + with io.open(rst_path, 'r', encoding='utf-8') as rh: + first = rh.readline().strip() + if first != marker: + logger.info(f'Skipping existing RST: {rst_path}') + continue + except Exception: + # If we can't read, skip to be safe + logger.warning(f'Could not read existing RST {rst_path}; skipping') + continue + + # Build content + title = _title_from_script(script_fpath) + underline = '=' * len(title) + # Make the literalinclude path relative to the generated RST location + rst_dir = os.path.dirname(rst_path) + rel = os.path.relpath(script_fpath, rst_dir) + lines = [ + marker, + '', + title, + underline, + '', + f'.. literalinclude:: {rel}', + ' :language: python', + ' :linenos:', + '', + ] + + try: + with io.open(rst_path, 'w', encoding='utf-8') as oh: + oh.write('\n'.join(lines)) + generated += 1 + logger.info(f'Generated {rst_path} from {script_basename}') + except Exception as e: + logger.warning(f'Failed to write {rst_path}: {e}') + + logger.info(f'Generated {generated} script RST files') + + +def _remove_generated_rst(app, exception): + """Remove RST files that were auto-generated for scripts and copy .py into built _sources. + + Safety rules: + - Only remove files whose first line starts with the auto-generated marker + ('.. AUTO-GENERATED from ...'). This avoids deleting user-authored RST. + - Only remove files after a successful build (exception is None). + """ + logger = logging.getLogger(__name__) + + # If build failed, do not remove files so devs can inspect outputs + if exception is not None: + logger.info('Build failed; leaving auto-generated RST files in place') + return + + srcdir = app.srcdir + patterns = [ + os.path.join(srcdir, 'usage', 'examples', '*.rst'), + ] + + rst_files = [] + for pat in patterns: + rst_files.extend(glob.glob(pat)) + + removed = 0 + for rst in sorted(set(rst_files)): + try: + with io.open(rst, 'r', encoding='utf-8') as fh: + first = fh.readline().strip() + if first.startswith(MARKER_TEMPLATE.format('')): + # If building HTML, copy the original .py into the built _sources + # directory so the "View source" link can serve the real Python file. + try: + py_full = os.path.splitext(rst)[0] + '.py' + if os.path.exists(py_full) and getattr(app, 'builder', None) is not None: + try: + builder_name = getattr(app.builder, 'name', None) + outdir = getattr(app.builder, 'outdir', None) + except Exception: + builder_name = None + outdir = None + + if builder_name == 'html' and outdir: + dest_dir = os.path.join(outdir, '_sources') + rel_py = os.path.relpath(py_full, app.srcdir) + dest_path = os.path.join(dest_dir, rel_py) + os.makedirs(os.path.dirname(dest_path), exist_ok=True) + # Copy file contents + try: + with io.open(py_full, 'r', encoding='utf-8') as rf, io.open(dest_path, 'w', encoding='utf-8') as wf: + wf.write(rf.read()) + logger.info(f'Copied Python source to built _sources: {dest_path}') + except Exception as e: + logger.warning(f'Failed to write built source {dest_path}: {e}') + + except Exception: + # non-fatal; continue to removal attempt + pass + + try: + os.remove(rst) + removed += 1 + logger.info(f'Removed generated RST: {rst}') + except Exception as e: + logger.warning(f'Failed to remove generated RST {rst}: {e}') + except Exception as e: + logger.warning(f'Could not read {rst}; skipping removal: {e}') + + logger.info(f'Removed {removed} auto-generated script RST files') + + +def _rewrite_sourcelink_to_py(app, pagename, templatename, context, doctree): + """If the current page was generated from a script RST, point "View source" to the .py. + + This mirrors nbsphinx behaviour for notebooks where the "Show source" link + points to the original notebook instead of the generated RST. + """ + try: + # doc2path with base=None returns a path relative to srcdir + rst_rel = app.env.doc2path(pagename, base=None) + except Exception: + return + + rst_full = os.path.join(app.srcdir, rst_rel) + if not os.path.exists(rst_full): + return + + try: + with io.open(rst_full, 'r', encoding='utf-8') as fh: + first = fh.readline().strip() + except Exception: + return + + # Only rewrite for our auto-generated script RST files + if not first.startswith(MARKER_TEMPLATE.format('')): + return + + py_full = os.path.splitext(rst_full)[0] + '.py' + if not os.path.exists(py_full): + return + + # Make the path relative to the source directory (what Sphinx expects) + rel_py = os.path.relpath(py_full, app.srcdir) + + # Replace the template context variable so the HTML theme will link to .py + context['sourcename'] = rel_py + + +def setup(app): + # Generate per-script RST files before reading sources + app.connect('builder-inited', _generate_rst_for_scripts) + # Remove the generated per-script RST files after a successful build + app.connect('build-finished', _remove_generated_rst) + # Make "View source" point to the original .py for auto-generated script pages + app.connect('html-page-context', _rewrite_sourcelink_to_py) + + return { + 'version': '1.0', + 'parallel_read_safe': True, + 'parallel_write_safe': True, + } diff --git a/docs/_static/firefly-in-python-flow.png b/docs/_static/firefly-in-python-flow.png new file mode 100644 index 0000000..2a41941 Binary files /dev/null and b/docs/_static/firefly-in-python-flow.png differ diff --git a/docs/conf.py b/docs/conf.py index b84657f..7ef53e2 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -6,8 +6,13 @@ # -- Project information ----------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information +# Make local extension modules under _ext/ importable +import os +import sys +sys.path.insert(0, os.path.abspath('_ext')) + project = 'firefly_client' -copyright = '2024, Caltech/IPAC Firefly Developers' +copyright = '2026, Caltech/IPAC Firefly Developers' author = 'Caltech/IPAC Firefly Developers' # -- General configuration --------------------------------------------------- @@ -15,11 +20,18 @@ extensions = [ 'sphinx_automodapi.automodapi', - 'myst_parser' + 'myst_parser', + 'nbsphinx', + 'script_pages', # custom extension for auto-generating RST files for examples/*.py scripts ] templates_path = ['_templates'] -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] +exclude_patterns = [ + '_build', 'Thumbs.db', '.DS_Store', + # exclude any docs in subdirectories under usage/examples/ since they are + # not included in any toctree and are for internal use only + 'usage/examples/*/**' +] # -- Options for HTML output ------------------------------------------------- @@ -52,3 +64,16 @@ # -- Options for extensions ------------------------------------------------- myst_heading_anchors = 3 + +# nbsphinx configuration: render notebooks and Python scripts +# Do not execute notebooks during docs build; use stored outputs if present. +nbsphinx_execute = 'never' + +# Allow build to continue even if some notebooks error (useful for demos). +nbsphinx_allow_errors = True + +# Ensure Pygments syntax highlighting for Jupyter code cells. +nbsphinx_codecell_lexer = 'ipython' + +# Remove the .txt suffix that gets added to source files +html_sourcelink_suffix = '' diff --git a/docs/development/guide.rst b/docs/development/guide.rst index 825dce7..adbca7c 100644 --- a/docs/development/guide.rst +++ b/docs/development/guide.rst @@ -4,18 +4,37 @@ Local development Get latest source from ``master`` branch at https://github.com/Caltech-IPAC/firefly_client. +.. code-block:: shell + + git clone https://github.com/Caltech-IPAC/firefly_client.git + cd firefly_client + Environment Setup ----------------- -TBD +Create a Python virtual environment and install required dependencies. +The folllowing commands demonstrate how to do this using ``conda`` (assuming you have `miniconda `_ installed on your system): + +.. code-block:: shell + + conda create -n ffpy -c conda-forge python jupyter astropy # jupyter and astropy are needed for running examples + conda activate ffpy + pip install -e ".[docs]" # editable installation with docs dependencies +Now you can run the examples notebooks/scripts in the ``examples/`` directory. +This can be done by starting a Jupyter Notebook or JupyterLab session from the terminal (``jupyter notebook`` or ``jupyter lab``), or by using an IDE that supports running Python notebooks or scripts (like VSCode, IntelliJ, etc.). + +.. note:: + The changes you make to the source code will be reflected when you run the examples since the package is installed in editable mode. + But make sure to restart the active Python kernel/session to pick up the changes. + Building documentation ---------------------- -Make sure you have the virtual/conda environment activated and documentation -dependencies installed in that environment. +Make sure you have the virtual environment activated and documentation +dependencies installed in that environment (``[docs]``). Then do: @@ -28,4 +47,13 @@ Open ``docs/_build/html/index.html`` in your browser to see the documentation website. Each time you make a change in documentation source, build it using -above command and reload the above file in browser. \ No newline at end of file +above command and reload the above html file in browser. + +.. note:: + The Sphinx docs include rendered Jupyter notebooks (via ``nbsphinx``), which can require **pandoc**. + If you see an error like ``PandocMissing``, install pandoc first (e.g., ``brew install pandoc`` on macOS). + +Development Tests/Examples +-------------------------- + +Refer to the `examples/development_tests directory `_ of firefly-client GitHub repository. diff --git a/docs/index.rst b/docs/index.rst index 8c85d0e..1bebdbc 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -6,7 +6,7 @@ firefly_client - Python API to Firefly visualization ##################################################### -`firefly_client` provides a Python API to the Firefly visualization framework. +``firefly_client`` provides a Python API to the Firefly visualization framework. You can find it on Github at https://github.com/Caltech-IPAC/firefly_client .. _firefly_client-intro: @@ -21,11 +21,45 @@ framework for the Portal Aspect of the LSST Science User Platform. Its client-server architecture is designed to enable a user to easily visualize images and catalog data from a remote site. -The `firefly_client` package provides a lightweight client class that includes -a Python interface to `Firefly's Javascript API `_. -This document contains examples of how to start a `FireflyClient` instance +The ``firefly_client`` package provides a lightweight client class that includes +a Python interface to Firefly's Javascript API. +This document contains examples of how to start a ``FireflyClient`` instance with details about the server location, and how to use the instance -to upload and display astronomical images, tables and catalogs. +to upload and display astronomical images, tables and charts. + + +What to expect +============== + +.. raw:: html + +
+ +.. image:: _static/firefly-in-python-flow.png + :alt: Firefly in Python Flow Diagram + :align: center + +.. raw:: html + +
+ +It's important to note that Firefly visualization in Python notebooks is +**NOT a per-cell chart or widget**, unlike common plotting libraries +such as Plotly or Bokeh. + +Under the hood, Firefly is a dedicated web application running at a specific +URL, rather than a plot produced as a notebook cell output. +Your notebook's Python session connects to a Firefly server, either a publicly +hosted instance (such as the `IRSA Viewer`_) or a local server running via Docker_. +Using a server enables advanced, compute-intensive interactivity that is +difficult to support directly within a notebook's UI. + +Multiple notebook cells can then send commands to the same Firefly instance, +which manages linked views of images, charts, and tables, similar to an +**interactive dashboard**. + +.. _IRSA Viewer: https://irsa.ipac.caltech.edu/irsaviewer/ +.. _Docker: https://hub.docker.com/r/ipac/firefly .. _firefly_client-using: diff --git a/docs/usage/callbacks-extensions.ipynb b/docs/usage/callbacks-extensions.ipynb new file mode 100644 index 0000000..2f4c444 --- /dev/null +++ b/docs/usage/callbacks-extensions.ipynb @@ -0,0 +1,174 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "a50e0ce4", + "metadata": {}, + "source": [ + "# Advanced: Callbacks and Extensions\n", + "So far we have been sending data to Firefly to visualize. This notebook shows how to add extensions to Firefly to bring back data into our Python session through callback functions. \n", + "\n", + ".. note::\n", + " Callbacks involve interactive UI actions (e.g., point selection), so running the code is only half the story—you must also trigger the UI interaction in the Firefly viewer." + ] + }, + { + "cell_type": "markdown", + "id": "dac26d1a", + "metadata": {}, + "source": [ + "## Setup\n", + "First, we create a `FireflyClient` instance and open a Firefly viewer. See [Initializing a FireflyClient instance](./initializing-vanilla.html) for more details. Then, we display a FITS image from a URL so that we have an image for triggering point-selection event. See [Displaying a FITS Image](./displaying-fits-image.html) for more details." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "6f079cb4", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from firefly_client import FireflyClient\n", + "\n", + "# Initialize a FireflyClient instance\n", + "fc = FireflyClient.make_client(url=\"https://irsa.ipac.caltech.edu/irsaviewer\")\n", + "\n", + "# Display a FITS image (from URL of WISE W2 cutout of M51 galaxy)\n", + "img_url = 'https://irsa.ipac.caltech.edu/ibe/data/wise/allsky/4band_p1bm_frm/9a/05379a/141/05379a141-w2-int-1b.fits?center=202.4841667,47.23055556&size=400pix'\n", + "plot_id = 'wise-cutout'\n", + "fc.show_fits_image(file_input=img_url, plot_id=plot_id, title='WISE Cutout')" + ] + }, + { + "cell_type": "markdown", + "id": "3551d0f9", + "metadata": {}, + "source": [ + "## Define and register a callback\n", + "A callback receives an event dictionary from Firefly. This example prints out world coordinates when a point-selection event occurs." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "80c57513", + "metadata": {}, + "outputs": [], + "source": [ + "def print_coords(event):\n", + " if 'data' in event and 'wpt' in event['data']:\n", + " wpt = event['data']['wpt'] # world point\n", + " wdata = wpt.split(';')\n", + " ra = float(wdata[0])\n", + " dec = float(wdata[1])\n", + " print(f'ra={ra:.6f}, dec={dec:.6f}')\n", + "\n", + "fc.add_listener(print_coords)" + ] + }, + { + "cell_type": "markdown", + "id": "0fb30b23", + "metadata": {}, + "source": [ + "## Add an extension to trigger the callback\n", + "To activate the callback in point-selection mode, add it as an extension with `ext_type='POINT'`. The title of the extension will appear as a clickable text-button when the Firefly viewer is in point-selection mode." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "21d7963b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ra=202.395939, dec=47.228118\n", + "ra=202.510304, dec=47.185369\n", + "ra=202.496007, dec=47.267874\n" + ] + } + ], + "source": [ + "fc.add_extension(ext_type='POINT', plot_id=None, title='Print coords', extension_id='pickit')" + ] + }, + { + "cell_type": "markdown", + "id": "eca88603", + "metadata": {}, + "source": [ + "## Trigger the callback (manual step)\n", + "In the Firefly browser tab:\n", + "1. Enable point-selection mode (enable 'Lock by click' switch in the bottom right of image display).\n", + "2. Click on the image to select a point.\n", + "3. Click the **Print coords** button to trigger the callback.\n", + "\n", + "You should see RA/Dec printed in your Python session output (which is the last code cell executed in the context of Python notebooks)." + ] + }, + { + "cell_type": "markdown", + "id": "65c42c6b", + "metadata": {}, + "source": [ + "## Remove the callback\n", + "When you’re done, remove the listener:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "ca66dbb9", + "metadata": {}, + "outputs": [], + "source": [ + "fc.remove_listener(print_coords)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "ffpy", + "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.12.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/usage/callbacks-extensions.rst b/docs/usage/callbacks-extensions.rst deleted file mode 100644 index 710383a..0000000 --- a/docs/usage/callbacks-extensions.rst +++ /dev/null @@ -1,40 +0,0 @@ -Advanced: Callbacks and Extensions ----------------------------------- - -Callback functions can be added to :class:`FireflyClient`. Here is a simple -example of defining and registering a callback that prints world coordinates -to the Python session: - -.. code-block:: py - - def print_coords(event): - if 'wpt' in event['data']: - wpt = event['data']['wpt'] - wdata = wpt.split(';') - ra = float(wdata[0]) - dec = float(wdata[1]) - print('ra={:.6f}, dec={:.6f}'.format(ra,dec)) - - fc.add_listener(print_coords) - -To activate the callback in point-selection mode, add it as an extension -with `ext_type='POINT'`. By default, the title of the extension will appear -as a clickable icon when the Firefly viewer is in point mode. A small image -can be passed in instead via the `img_src` parameter. - -.. code-block:: py - - fc.add_extension(ext_type='POINT', plot_id=None, title='Print coords', - extension_id='pickit') - -To activate point-selection mode, in the Firefly browser tab, select -the 'Lock by click' checkbox at the upper right. Then selecting any point -in an image will overlay a box at that point. Finally, click on the -'Print coords' icon in the image display window to cause the callback -to be triggered, and coordinates to be printed out. - -The callback can be deleted with `FireflyClient.remove_listener`: - -.. code-block:: py - - fc.remove_listener(print_coords) diff --git a/docs/usage/charting.ipynb b/docs/usage/charting.ipynb new file mode 100644 index 0000000..cdaecbb --- /dev/null +++ b/docs/usage/charting.ipynb @@ -0,0 +1,263 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "ff215e10", + "metadata": {}, + "source": [ + "# Visualizing tables as Charts\n", + "\n", + "This notebook shows you how to plot columns of a table quickly as scatter charts or histograms in Firefly. You will also learn how to customize the charts using Plotly-style configuration and display spectra from supported type of table." + ] + }, + { + "cell_type": "markdown", + "id": "5c82d0f9", + "metadata": {}, + "source": [ + "## Setup\n", + "First, we create a `FireflyClient` instance and open a Firefly viewer. See [Initializing a FireflyClient instance](./initializing-vanilla.html) for more details. Then, we display a catalog table from a URL so that we have table data to create charts. See [Displaying Tables and Catalogs](./viewing-tables.html) for more details." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "d26d722f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from firefly_client import FireflyClient\n", + "\n", + "# Initialize a FireflyClient instance\n", + "fc = FireflyClient.make_client(url=\"http://localhost:8080/firefly\")\n", + "\n", + "# Display a catalog table (from URL of 2MASS TAP query for M51)\n", + "table_url = \"http://irsa.ipac.caltech.edu/TAP/sync?FORMAT=IPAC_TABLE&QUERY=SELECT+*+FROM+fp_psc+WHERE+CONTAINS(POINT('J2000',ra,dec),CIRCLE('J2000',202.4841667,47.23055556,0.125))=1\"\n", + "table_id = '2mass-catalog'\n", + "fc.show_table(file_input=table_url, tbl_id=table_id, title='2MASS Catalog')" + ] + }, + { + "cell_type": "markdown", + "id": "1d035b65", + "metadata": {}, + "source": [ + ".. note::\n", + " Firefly automatically tries to plot the displayed table in the \"Active Chart\" tab (typically a ra-dec scatter plot for catalogs). But for full control over plotting, we need the following methods which will create new charts in the \"Pinned Charts\" tab. So make sure to switch to \"Pinned Charts\" tab to see the charts created in this notebook." + ] + }, + { + "cell_type": "markdown", + "id": "8ae74274", + "metadata": {}, + "source": [ + "## Quick scatter plot\n", + "Use `show_xyplot` method of FireflyClient object for a straightforward scatter plot from table columns. X and Y axis column parameters (`xCol` and `yCol`) can be an expression involving one or more table columns. See API docs for more parameters to customize the scatter plot." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "3209b784", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fc.show_xyplot(tbl_id=table_id, # specifies which table to plot from\n", + " xCol='j_m', yCol='h_m-k_m')" + ] + }, + { + "cell_type": "markdown", + "id": "43225da9", + "metadata": {}, + "source": [ + "## Quick histogram\n", + "Use `show_histogram` method of FireflyClient object for a straightforward histogram from a table column. See API docs for more parameters to customize the histogram." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "9642b55b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fc.show_histogram(tbl_id=table_id, col='j_m', numBins=30)" + ] + }, + { + "cell_type": "markdown", + "id": "43e3e798", + "metadata": {}, + "source": [ + "## Configurable plots\n", + "Alternatively, more generic method `show_chart` can be used to create similar plot but with a lot more configuration parameters as [Plotly data/layout structure](https://plotly.com/javascript/reference/index/). This gives more control over marker style, axes' titles, etc. \n", + "\n", + "The `trace` dictionary in `data` array should have:\n", + "1. a Firefly-specific key `tbl_id` to specify which table to plot from\n", + "2. the `x` and `y` keys assigned to the column names or expressions prefixed with `tables::`." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "0a990b0c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "trace0 = {\n", + " # Firefly-specific key and values\n", + " 'tbl_id': table_id, 'x': \"tables::j_m\", 'y': \"tables::h_m-k_m\",\n", + " # Plotly keys and values\n", + " 'type': 'scatter', 'mode': 'markers',\n", + " 'marker': dict(size=4, color='red', opacity=0.6)\n", + " }\n", + "layout = {'title': '2MASS color-mag',\n", + " 'xaxis': dict(title='J'), 'yaxis': dict(title='H - K')} \n", + "\n", + "fc.show_chart(data=[trace0], layout=layout)" + ] + }, + { + "cell_type": "markdown", + "id": "d59d2c75", + "metadata": {}, + "source": [ + "Similarly, histograms can also be created using `show_chart` method but it has more Firefly-specific keys as shown below:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "d0205c2f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "trace0 = dict(type='fireflyHistogram',\n", + " marker=dict(color='rgba(153, 51, 153, 0.8)'),\n", + " firefly=dict(\n", + " tbl_id=table_id,\n", + " options=dict(\n", + " algorithm='fixedsizeBins',\n", + " fixedBinSizeSelection='numBins',\n", + " numBins=30,\n", + " columnOrExpr='j_m'\n", + " )))\n", + "\n", + "layout_hist = dict(title='Photometry histogram',\n", + " xaxis=dict(title='J (mag)'),\n", + " yaxis=dict(title='Number'))\n", + "\n", + "fc.show_chart(layout=layout_hist, data=[trace0])" + ] + }, + { + "cell_type": "markdown", + "id": "a9517c84", + "metadata": {}, + "source": [ + "## Spectra\n", + "If a table follows [IVOA Spectrum Data Model](https://www.ivoa.net/documents/SpectrumDM/), simply displaying the table will automatically create a spectrum plot in the \"Active Chart\" tab (make sure to switch to this tab). You can fine tune it directly in Firefly UI using the chart options dialog in the toolbar." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "58730b96", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "euclid_spec_url = 'http://irsa.ipac.caltech.edu/api/spectrumdm/convert/euclid/q1/SIR/102159776/EUC_SIR_W-COMBSPEC_102159776_2024-11-05T16:21:17.235160Z.fits?dataset_id=euclid_combspec&hdu=217'\n", + "\n", + "fc.show_table(euclid_spec_url, title='Euclid Spectrum')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "ffpy", + "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.12.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/usage/charting.rst b/docs/usage/charting.rst deleted file mode 100644 index 3c6cdea..0000000 --- a/docs/usage/charting.rst +++ /dev/null @@ -1,39 +0,0 @@ -Making Plots and Histograms ---------------------------- - -Once a table has been uploaded to Firefly, :meth:`FireflyClient.show_chart` -will display a scatter plot. The `x` and `y` parameters can be set -to use names of columns in the table, or to arithmetic expressions that combine -table columns. - -.. code-block:: py - - trace1 = dict(tbl_id='2mass-tbl', x='tables::j_m', - y='tables::h_m-k_m', mode='markers', type='scatter', - marker=dict(size=4)) - - layout1 = dict(title='2MASS color-mag', - xaxis=dict(title='J'), yaxis=dict(title='H - K')) - - fc.show_chart(layout=layout1, data=[trace1]) - -A histogram can be displayed with :meth:`FireflyClient.show_chart`: - -.. code-block:: py - - trace2 = dict(type='fireflyHistogram', - name='j_m', - marker=dict(color='rgba(153, 51, 153, 0.8)'), - firefly=dict(tbl_id='2mass-tbl', - options=dict(algorithm='fixedsizeBins', - fixedBinSizeSelection='numBins', - numBins=30, - columnOrExpr='j_m'))) - - layout_hist = dict(title='Photometry histogram', - xaxis=dict(title='j_m (mag)'), - yaxis=dict(title='Number')) - - fc.show_chart(layout=layout_hist, data=[trace2]) - -Both plot types include options for log scaling as well as other settings. diff --git a/docs/usage/demo-notebooks.rst b/docs/usage/demo-notebooks.rst index 1e72ee7..1e94946 100644 --- a/docs/usage/demo-notebooks.rst +++ b/docs/usage/demo-notebooks.rst @@ -6,32 +6,40 @@ Demo Notebooks Reference Guide ----------------- -For a high-level overview of the Firefly Python client API and important methods, refer to this `reference guide notebook `_. +For a high-level overview of the Firefly Python client API and important methods, refer to this notebook: + +.. toctree:: + :maxdepth: 2 + + examples/reference-guide Science Use-cases ----------------- -IRSA Tutorials is collection of multiple notebooks that demonstrate the use of IRSA data services and tools for science use-cases. -The following tutorial notebooks demonstrates the use of Firefly Python client: +IRSA Notebook Tutorials is collection of notebooks that demonstrate the use of IRSA data services and tools for science use-cases. +The following notebook tutorials demonstrate the use of Firefly Python client: -- `Using Firefly visualization tools in Python to vet SEDs `_ -- `Using Firefly visualization tools to understand the light curves of Solar System objects `_ -- `Using Firefly to Explore OpenUniverse2024 Data Preview Simulated Roman and Rubin Images `_ -- `Euclid Q1: PHZ catalogs — Visualize with Firefly section `_ +- `Using Firefly visualization tools in Python to vet SEDs `_ +- `Using Firefly visualization tools to understand the light curves of Solar System objects `_ +- `Using Firefly to Explore OpenUniverse2024 Data Preview Simulated Roman and Rubin Images `_ +- `Euclid Q1: PHZ catalogs — Visualize with Firefly section `_ Other Examples --------------- For a full list of notebooks/scripts that demonstrate the use of -Firefly Python client, refer to |nbviewer_examples| (rendered in nbviewer). - -.. warning:: - Several of the notebooks in the examples directory use deprecated API (or discouraged API that is about to be deprecated) and will be updated soon. +Firefly Python client, refer to the following: +.. toctree:: + :maxdepth: 1 + :glob: -.. |nbviewer_examples| raw:: html + examples/demo-* + examples/plot-interface + examples/filetable + examples/multi-moc - this examples directory +.. note:: + All of these notebooks/scripts are also available in the `examples directory `_ of firefly-client GitHub repository. diff --git a/docs/usage/displaying-3color.ipynb b/docs/usage/displaying-3color.ipynb new file mode 100644 index 0000000..25fce01 --- /dev/null +++ b/docs/usage/displaying-3color.ipynb @@ -0,0 +1,246 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "cab445d6", + "metadata": {}, + "source": [ + "" + ] + }, + { + "cell_type": "markdown", + "id": "067800d8", + "metadata": {}, + "source": [ + "# Displaying 3-Color FITS Images\n", + "\n", + "This notebook shows how to create a 3-color composite image (RGB) in Firefly." + ] + }, + { + "cell_type": "markdown", + "id": "110faec8", + "metadata": {}, + "source": [ + "## Setup\n", + "First, we create a `FireflyClient` instance and open a Firefly viewer. See [Initializing a FireflyClient instance](./initializing-vanilla.html) for more details." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "4bd1902a", + "metadata": {}, + "outputs": [], + "source": [ + "from firefly_client import FireflyClient\n", + "\n", + "# Initialize a FireflyClient instance\n", + "fc = FireflyClient.make_client(url=\"https://irsa.ipac.caltech.edu/irsaviewer\")" + ] + }, + { + "cell_type": "markdown", + "id": "03bd3396", + "metadata": {}, + "source": [ + "## Show 3-color image\n", + "A 3-color composite is built by providing per-band inputs to the `show_fits_3color` method.\n", + "\n", + "This method accepts a `three_color_params` parameter, which takes a list of dictionaries (one per band) in the order **[R, G, B]**. The dictionary should have key names defined in [FITS Plotting Parameters](https://github.com/Caltech-IPAC/firefly/blob/dev/docs/fits-plotting-parameters.md) for the Firefly JavaScript. Key names can be *case-insensitive*.\n", + "\n", + ".. warning::\n", + " The 3-color image creation from FireflyClient uses low-level API at the moment. Hence, `show_fits_3color` is not symmetric to the API of `show_fits_image` method and may be unstable (in some cases).\n", + "\n", + "### From a URL\n", + "Provide `url` key in each band's dictionary:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "5707c31e", + "metadata": {}, + "outputs": [], + "source": [ + "# [W4, W3, W2] from WISE all-sky as [R, G, B]\n", + "rgb_urls = [f'https://irsa.ipac.caltech.edu/ibe/data/wise/allsky/4band_p1bm_frm/9a/05379a/141/05379a141-{band}-int-1b.fits'\n", + " for band in ['w4', 'w3', 'w2']]" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "a6e7b037", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "three_color_params = [\n", + " {\n", + " 'url': url,\n", + " 'title': '3 color image'\n", + " } for url in rgb_urls\n", + "]\n", + "\n", + "fc.show_fits_3color(three_color_params=three_color_params,\n", + " plot_id='3color-img')" + ] + }, + { + "cell_type": "markdown", + "id": "eb60d37e", + "metadata": {}, + "source": [ + "### From a local file\n", + "Provide `file` key in each band's dictionary. The `file` value is the location on Firefly server instead of location on your machine, so it must be the return value of `upload_file` method." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "55e25051", + "metadata": {}, + "outputs": [], + "source": [ + "from astropy.utils.data import download_file\n", + "rgb_local_paths = [download_file(url, cache=True, timeout=120) for url in rgb_urls]\n", + "\n", + "three_color_params = [\n", + " {\n", + " 'file': fc.upload_file(fpath),\n", + " 'title': '3 color image'\n", + " } for fpath in rgb_local_paths\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0440c11e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fc.show_fits_3color(three_color_params=three_color_params,\n", + " plot_id='3color-img' # same id to replace previous image plot\n", + " )" + ] + }, + { + "cell_type": "markdown", + "id": "28728b53", + "metadata": {}, + "source": [ + "### From IRSA-Specific Searches\n", + "\n", + "Since `show_fits_3color` uses low-level API, you can also retrieve images on-the-fly (instead of providing a url or local path) by utilizing Firefly's image search processors that powers the IRSA archives. See more details in [Retrieving Images Using IRSA-Specific Searches](#)." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "b53fb1c2", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rv = '92,-2,92,8,NaN,2,44,25,600,120'\n", + "ra = 202.4841667\n", + "dec = 47.23055556\n", + "target = f'{ra};{dec};EQ_J2000'\n", + "size_deg = 0.25\n", + "\n", + "threeC = [\n", + " {\n", + " 'Type': 'SERVICE',\n", + " 'Service': 'WISE',\n", + " 'Title': '3 color',\n", + " 'SurveyKey': '3a',\n", + " 'SurveyKeyBand': '4',\n", + " 'WorldPt': target,\n", + " 'RangeValues': rv,\n", + " 'SizeInDeg': size_deg\n", + " },\n", + " {\n", + " 'Type': 'SERVICE',\n", + " 'Service': 'WISE',\n", + " 'Title': '3 color',\n", + " 'SurveyKey': '3a',\n", + " 'SurveyKeyBand': '2',\n", + " 'WorldPt': target,\n", + " 'RangeValues': rv,\n", + " 'SizeInDeg': size_deg\n", + " },\n", + " {\n", + " 'Type': 'SERVICE',\n", + " 'Service': 'WISE',\n", + " 'Title': '3 color',\n", + " 'SurveyKey': '3a',\n", + " 'SurveyKeyBand': '1',\n", + " 'WorldPt': target,\n", + " 'RangeValues': rv,\n", + " 'SizeInDeg': size_deg\n", + " }\n", + "]\n", + "\n", + "fc.show_fits_3color(three_color_params=threeC,\n", + " plot_id='wise_m51')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "ffpy", + "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.12.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/usage/displaying-hips.ipynb b/docs/usage/displaying-hips.ipynb new file mode 100644 index 0000000..d05d3b2 --- /dev/null +++ b/docs/usage/displaying-hips.ipynb @@ -0,0 +1,196 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "6f3a8081", + "metadata": {}, + "source": [ + "" + ] + }, + { + "cell_type": "markdown", + "id": "f73449da", + "metadata": {}, + "source": [ + "# Displaying HiPS Images\n", + "\n", + "This notebook shows how to display HiPS (Hierarchical Progressive Survey) images in Firefly and how to add MOC layer to them." + ] + }, + { + "cell_type": "markdown", + "id": "396f5621", + "metadata": {}, + "source": [ + "## Setup\n", + "First, we create a `FireflyClient` instance and open a Firefly viewer. See [Initializing a FireflyClient instance](./initializing-vanilla.html) for more details." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "a3fc5ef0", + "metadata": {}, + "outputs": [], + "source": [ + "from firefly_client import FireflyClient\n", + "\n", + "# Initialize a FireflyClient instance\n", + "fc = FireflyClient.make_client(url=\"https://irsa.ipac.caltech.edu/irsaviewer\")" + ] + }, + { + "cell_type": "markdown", + "id": "579df16f", + "metadata": {}, + "source": [ + "## Show HiPS image\n", + "HiPS images are fetched and rendered progressively from a HiPS survey endpoint. To display a HiPS image, use `show_hips` method of the FireflyClient object and provide:\n", + "\n", + "- `hips_root_url`: the HiPS survey endpoint\n", + "- `WorldPt`: the target position as a serialized string: `';;EQ_J2000'`\n", + "- `SizeInDeg`: (optional) the field of view size in degrees" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "fa9883ee", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "hips_url = 'https://irsa.ipac.caltech.edu/data/hips/CDS/2MASS/Color/'\n", + "# hips_url = 'http://alasky.u-strasbg.fr/DSS/DSSColor'\n", + "\n", + "ra = 202.4841667\n", + "dec = 47.23055556\n", + "size_in_deg = 1.6\n", + "target = f'{ra};{dec};EQ_J2000'\n", + "\n", + "hips_plot_id = 'hips-img-id' # to identify this particular image display for later operations\n", + "\n", + "fc.show_hips(plot_id=hips_plot_id, \n", + " hips_root_url=hips_url,\n", + " Title='HiPS image', \n", + " WorldPt=target,\n", + " SizeInDeg=size_in_deg # can be omitted\n", + " )" + ] + }, + { + "cell_type": "markdown", + "id": "4f1bba1c", + "metadata": {}, + "source": [ + "## Modify displayed HiPS\n", + "You can modify this image display similar to how you would [modify a FITS image display](#)." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "fc110e4d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fc.set_pan(plot_id=hips_plot_id, # note we use the plot id we defined above\n", + " x=ra+0.25, y=dec-0.25, coord='j2000')" + ] + }, + { + "cell_type": "markdown", + "id": "72a9ca79", + "metadata": {}, + "source": [ + "It's often more convinient to modify image display through UI controls in the image toolbar instead." + ] + }, + { + "cell_type": "markdown", + "id": "b9d746d1", + "metadata": {}, + "source": [ + "## Overlay MOC (sky coverage map)\n", + "You can overlay a MOC (Multi-Order Coverage map) on the HiPS image to visually compare the sky coverage. A MOC is typically a single-column table in FITS format, so we can display it using the `show_table` method. It is recommended to set the `visible` parameter to `False` so as not to show a table display in Firefly after fetching the table data for the provided MOC file." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7539af31", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "moc_url = 'https://irsa.ipac.caltech.edu/data/MOC/spitzer_seip.moc.fits'\n", + "\n", + "fc.show_table(file_input=moc_url, visible=False)" + ] + }, + { + "cell_type": "markdown", + "id": "b3f8ebd1", + "metadata": {}, + "source": [ + ".. note::\n", + " It may take some time to load the MOC file, and since there's no feedback from the table display, look for the spinner on the top left of the HiPS image display." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "ffpy", + "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.12.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/usage/displaying-images.ipynb b/docs/usage/displaying-images.ipynb new file mode 100644 index 0000000..53e28b1 --- /dev/null +++ b/docs/usage/displaying-images.ipynb @@ -0,0 +1,619 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "e3b6f6e2", + "metadata": {}, + "source": [ + "" + ] + }, + { + "cell_type": "markdown", + "id": "5eb7e6e3", + "metadata": {}, + "source": [ + "# Displaying FITS Images\n", + "\n", + "This notebook shows how to display FITS images in Firefly and how to modify the image display (pan/zoom/stretch/align)." + ] + }, + { + "cell_type": "markdown", + "id": "3b560f3a", + "metadata": {}, + "source": [ + "## Setup\n", + "First, we create a `FireflyClient` instance and open a Firefly viewer. See [Initializing a FireflyClient instance](./initializing-vanilla.html) for more details." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "b4fb58c6", + "metadata": {}, + "outputs": [], + "source": [ + "from firefly_client import FireflyClient\n", + "\n", + "# Following imports are just for example data fetching and processing (not needed always)\n", + "from astropy.utils.data import download_file\n", + "from astropy.io import fits\n", + "from astropy.convolution import convolve, Gaussian2DKernel\n", + "import io\n", + "\n", + "# Initialize a FireflyClient instance\n", + "fc = FireflyClient.make_client(url=\"https://irsa.ipac.caltech.edu/irsaviewer\")" + ] + }, + { + "cell_type": "markdown", + "id": "aa994567", + "metadata": {}, + "source": [ + "## Show FITS Image in Firefly\n", + "\n", + "Use the `show_fits_image` method of the FireflyClient object to display a FITS image. It can take a local file path, URL, or a file-like object as input via the `file_input` parameter.\n", + "\n", + "It is recommended to explicitly specify the `plot_id` parameter for later use in modifying the image display." + ] + }, + { + "cell_type": "markdown", + "id": "ad969ddf", + "metadata": {}, + "source": [ + "### From a URL\n", + "You can specify url of any FITS image. Here we use cutout of a WISE all-sky image of M51 galaxy in W2 band:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "d34e928b", + "metadata": {}, + "outputs": [], + "source": [ + "cutout_image_url = 'https://irsa.ipac.caltech.edu/ibe/data/wise/allsky/4band_p1bm_frm/9a/05379a/141/05379a141-w2-int-1b.fits?center=202.4841667,47.23055556&size=400pix'" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "a1e5eb4d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cutout_image_plot_id = 'wise-cutout'\n", + "fc.show_fits_image(file_input=cutout_image_url,\n", + " plot_id=cutout_image_plot_id,\n", + " title='WISE Cutout')" + ] + }, + { + "cell_type": "markdown", + "id": "99723675", + "metadata": {}, + "source": [ + "### From a local file\n", + "You can specify path of any local FITS file. Here we download the full WISE all-sky image of M51 in W2 and use its file path:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "f242a994", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'/Users/jsinghal/.astropy/cache/download/url/ef686a664b2c17e3d8590b511be8a400/contents'" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "full_image_url = 'https://irsa.ipac.caltech.edu/ibe/data/wise/allsky/4band_p1bm_frm/9a/05379a/141/05379a141-w2-int-1b.fits'\n", + "full_image_fpath = download_file(full_image_url, cache=True, timeout=120)\n", + "full_image_fpath" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "d59743bc", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "full_image_plot_id = 'wise-fullimage'\n", + "fc.show_fits_image(file_input=full_image_fpath,\n", + " plot_id=full_image_plot_id, # using a different plot id to not overwrite previous plot\n", + " title='WISE Full Image')" + ] + }, + { + "cell_type": "markdown", + "id": "7b3ca9c2", + "metadata": {}, + "source": [ + "### From an in-memory file-like object\n", + "You can also use a file-like object (e.g. `BytesIO` stream) instead of a local file path or URL. This is useful when you are working with a FITS file in memory and don't want to write it to disk. " + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "a5e54b24", + "metadata": {}, + "outputs": [], + "source": [ + "processed_fits = io.BytesIO()\n", + "\n", + "with fits.open(cutout_image_url) as hdul:\n", + " # Do some processing on FITS image data (like simple Gaussian smoothing here)\n", + " img_data = hdul[0].data\n", + " gaussian_kernel = Gaussian2DKernel(x_stddev=2)\n", + " img_data = convolve(img_data, gaussian_kernel)\n", + "\n", + " new_hdu = fits.PrimaryHDU(data=img_data, header=hdul[0].header)\n", + " new_hdu.writeto(processed_fits, overwrite=True)\n", + " processed_fits.seek(0) # to bring reading pointer to the beginning of file" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "3c8b16be", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fc.show_fits_image(file_input=processed_fits,\n", + " plot_id='wise-processed',\n", + " title='Processed WISE Cutout')" + ] + }, + { + "cell_type": "markdown", + "id": "478b5067", + "metadata": {}, + "source": [ + "## Modify the displayed image(s)\n", + "Zooming, panning, and changing the stretch is accomplished by following methods, passing in the `plot_id` as the first argument.\n", + "\n", + "### Panning to a coordinate\n", + "To pan the full image to center on the M51 cutout's center:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "06df4d66", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fc.set_pan(plot_id=full_image_plot_id, # note we use the plot id we defined above\n", + " x=202.4841667, y=47.23055556, coord='j2000')" + ] + }, + { + "cell_type": "markdown", + "id": "d0838835", + "metadata": {}, + "source": [ + "### Zooming\n", + "To zoom into the full image by a factor of 2:" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "6ee07da8", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fc.set_zoom(plot_id=full_image_plot_id, factor=2)" + ] + }, + { + "cell_type": "markdown", + "id": "2c88e71b", + "metadata": {}, + "source": [ + "### Changing the color stretch\n", + "Set the stretch for the full image based on IRAF zscale interval with a linear algorithm:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "047d45e6", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True,\n", + " 'rv_string': '91,1.000000,91,1.000000,NaN,2.000000,44,25,600,120,0,NaN,1.000000'}" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fc.set_stretch(plot_id=full_image_plot_id, stype='zscale', algorithm='linear')\n", + "\n", + "# Or for a log stretch with sigma limits:\n", + "# fc.set_stretch(plot_id=full_image_plot_id, stype='sigma', algorithm='log', lower_value=-2, upper_value=30)" + ] + }, + { + "cell_type": "markdown", + "id": "af1be2fb", + "metadata": {}, + "source": [ + "### Aligning multiple images\n", + "You can align mutliple images covering the same sky location by target, WCS, pixels, etc. Optionally, you can also lock the alignment so that panning/zooming one image will pan/zoom the other images in sync.\n", + "\n", + "To align both full image and cutout image by WCS and to lock the WCS matching:" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "364d0b32", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fc.align_images(lock_match=True)" + ] + }, + { + "cell_type": "markdown", + "id": "ae7bf7dc", + "metadata": {}, + "source": [ + "## Advanced Usage (Low-level, Unstable API)\n", + "In most cases, you do not need the low-level API to create or modify image displays, since the higher-level methods shown above cover common workflows and you can always directly use the UI controls in Firefly. For completeness, the sections below document low-level operations that may be useful to advanced users. Note that the low-level API is unstable and may change, so examples here might not work in all cases." + ] + }, + { + "cell_type": "markdown", + "id": "be52e9e5", + "metadata": {}, + "source": [ + "### Changing the color map\n", + "FireflyClient doesn't provide a high-level method to change the color map but you can do so by\n", + "using the lower-level API: dispatch the relevant JavaScript action with the required parameters in the payload." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "ae0feb19", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fc.dispatch(action_type='ImagePlotCntlr.ColorChange',\n", + " payload={\n", + " 'plotId': full_image_plot_id,\n", + " 'cbarId': 24 # veridis color map\n", + " })" + ] + }, + { + "cell_type": "markdown", + "id": "13496ec5", + "metadata": {}, + "source": [ + "### Specifying Zoom and Stretch Values When First Displaying an Image\n", + "It can be advantageous to specify the zoom, stretch, and color table parameters in the same command that displays the image, to avoid problems with the later commands being ignored when the image display has not completed.\n", + "\n", + "\n", + "To specify the stretch as part of the image display, you can generate a range values string. This example is for an asinh stretch with a Q value of 6 and an upper level of 98 percent:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "de44bb1e", + "metadata": {}, + "outputs": [], + "source": [ + "from firefly_client import RangeValues\n", + "rvstring = RangeValues.create_rv_standard(algorithm='asinh',\n", + " asinh_q_value=6,\n", + " upper_value=98.0)" + ] + }, + { + "cell_type": "markdown", + "id": "40863744", + "metadata": {}, + "source": [ + "The zoom value can be specified in several different ways. When displaying images with different pixel scales, the best practice is to specify `ZoomType='ARCSEC_PER_SCREEN_PIX'` and then the numerical value, e.g. `ZoomArcsecPerScreenPix=0.3`.\n", + "\n", + "These parameters use the key names defined in [FITS Plotting Parameters](https://github.com/Caltech-IPAC/firefly/blob/dev/docs/fits-plotting-parameters.md) for the Firefly JavaScript. They can be passed to the `show_fits_image` method as additional keyword arguments:" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "58155b58", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fc.show_fits_image(file_input=cutout_image_url,\n", + " plot_id=cutout_image_plot_id, # same plot id to replace the previous image\n", + " title='WISE Cutout',\n", + " # additional keyword arguments\n", + " ColorTable=4,\n", + " ZoomType='ARCSEC_PER_SCREEN_PIX',\n", + " ZoomArcsecPerScreenPix=0.3,\n", + " RangeValues=rvstring\n", + " )" + ] + }, + { + "cell_type": "markdown", + "id": "a689462c", + "metadata": {}, + "source": [ + "### Retrieving Images Using IRSA-Specific Searches\n", + "Instead of providing FITS image file (as a local file path, URL, or file-like object), you can also retrieve images by utilizing Firefly's image search processors that powers the IRSA archives.\n", + "\n", + "A table of available projects for image searches is maintained in the Firefly code base. The\n", + "information can be retrieved into an Astropy table:" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "ef8b6b99", + "metadata": {}, + "outputs": [], + "source": [ + "from astropy.table import Table\n", + "surveys = Table.read('https://raw.githubusercontent.com/Caltech-IPAC/firefly/dev/src/firefly/java/edu/caltech/ipac/firefly/resources/irsa-image-master-table.csv',\n", + " format='csv')" + ] + }, + { + "cell_type": "markdown", + "id": "04d74c05", + "metadata": {}, + "source": [ + "To select images available for the WISE AllSky project:" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "f8a82d3e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
Table length=4\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
missionIdprojectsubProjectsurveyKeyacronymwavebandIdimageIdtitlewavelengthwavelengthDescwaveTypeprojectTypeKeyprojectTypeDescminRangeDegmaxRangeDeghelpUrltooltipapiTypefilterdataTypedefaultRgbColor
str8str115str8str33str25str11str2str42float64str15str7str13str13float64float64str74str46str7str80str5str5
WISEWISE AllSky Atlas--1bWISE AllSky W11--W1 (3.4 microns)3.43.4 micronsmid-IRall-skyall-sky0.010.2https://irsa.ipac.caltech.edu/docs/irsaviewer_datasets.html#WISEAll-SkyWISE AllSky SIngle Exposure W1 3.4 micronsWISE--image--
WISEWISE AllSky Atlas--1bWISE AllSky W22--W2 (4.6 microns)4.64.6 micronsmid-IRall-skyall-sky0.010.2https://irsa.ipac.caltech.edu/docs/irsaviewer_datasets.html#WISEAll-SkyWISE AllSky SIngle Exposure W2WISE--image--
WISEWISE AllSky Atlas--1bWISE AllSky W33--W3 (12 microns)12.012 micronsmid-IRall-skyall-sky0.010.2https://irsa.ipac.caltech.edu/docs/irsaviewer_datasets.html#WISEAll-SkyWISE AllSky SIngle Exposure W3WISE--image--
WISEWISE AllSky Atlas--1bWISE AllSky W44--W4 (22 microns)22.022 micronsmid-IRall-skyall-sky0.010.2https://irsa.ipac.caltech.edu/docs/irsaviewer_datasets.html#WISEAll-SkyWISE AllSky SIngle Exposure W4WISE--image--
" + ], + "text/plain": [ + "\n", + "missionId project subProject ... filter dataType defaultRgbColor\n", + " str8 str115 str8 ... str80 str5 str5 \n", + "--------- ------------------ ---------- ... ------ -------- ---------------\n", + " WISE WISE AllSky Atlas -- ... -- image --\n", + " WISE WISE AllSky Atlas -- ... -- image --\n", + " WISE WISE AllSky Atlas -- ... -- image --\n", + " WISE WISE AllSky Atlas -- ... -- image --" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wise_surveys = surveys[surveys['missionId'] == 'WISE']\n", + "wise_surveys[['AllSky' in project for project in wise_surveys['project']]]" + ] + }, + { + "cell_type": "markdown", + "id": "4024ab85", + "metadata": {}, + "source": [ + "To search the WISE AllSky survey in W1 band:" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "58c4e5f8", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "size_in_arcsec = 600\n", + "ra = 202.4841667\n", + "dec = 47.23055556\n", + "target = f'{ra};{dec};EQ_J2000'\n", + "fc.show_fits_image(plot_id='IRAC1',\n", + " Title='WISE AllSky W1 Search',\n", + " Type='SERVICE',\n", + " Service='WISE', # apiType\n", + " SurveyKey='1b', # surveyKey\n", + " SurveyKeyBand='1', # wavebandId\n", + " WorldPt=target,\n", + " SizeInDeg=size_in_arcsec/3600,\n", + " ColorTable=1,\n", + " ZoomType='ARCSEC_PER_SCREEN_PIX',\n", + " ZoomArcsecPerScreenPix=0.3,\n", + " RangeValues=rvstring)" + ] + }, + { + "cell_type": "markdown", + "id": "9134fee2", + "metadata": {}, + "source": [ + "Since we added additional images to the viewer, we re-align and lock them by WCS so panning/zooming stays in sync:" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "0a635fb7", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fc.align_images(lock_match=True)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "ffpy", + "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.12.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/usage/displaying-images.rst b/docs/usage/displaying-images.rst deleted file mode 100644 index 128033d..0000000 --- a/docs/usage/displaying-images.rst +++ /dev/null @@ -1,232 +0,0 @@ -################# -Displaying Images -################# - -Since Firefly was originally developed to visualize data products from -astronomical archives, displaying an image is a two-step process of -uploading a file and then showing it. The examples here use the data -products downloaded in :ref:`firefly_client-getting-started`. - -The :meth:`FireflyClient.upload_file` method uploads the file and -returns a location understood by the Firefly server. The location -string is passed to :meth:`FireflyClient.show_fits` to display -the image. In the display step, -it is recommended to explicitly specify the `plot_id` parameter -for later use in modifying the image display. - -.. code-block:: py - - fval = fc.upload_file('2mass-m31-green.fits') - fc.show_fits(fval, plot_id='m31-green', title='2MASS H, M31') - - -Modifying an Image Display --------------------------- - -Zooming, panning, and changing the stretch (mapping of pixels to display -values) is accomplished by corresponding methods, passing in the `plot_id` -as the first argument. - -.. code-block:: py - - fc.set_zoom('m31-green', 4) - fc.set_pan('m31-green', 200, 195) - fc.set_stretch('m31-green', 'sigma', 'log', lower_value=-2, upper_value=30) - -A "zscale" stretch may be commanded with alternate parameters: - -.. code-block:: py - - fc.set_stretch('m31-green', 'zscale', 'linear') - -At present the API does not include a function for changing the color map -for the image. The relevant Javascript action may be invoked using -:meth:`FireflyClient.dispatch`: - -.. code-block:: py - - fc.dispatch(action_type='ImagePlotCntlr.ColorChange', - payload={'plotId': 'm31-green', - 'cbarId': 16}) - -The colormap can be reverted to the original grayscale by using the -command above together with `'cbarId' : 0`. - - -Specifying Zoom and Stretch Values When First Displaying an Image ------------------------------------------------------------------ - -It is often advantageous to specify the zoom, stretch, and color table -parameters in the same command that displays the image, to avoid problems -with the later commands being ignored when the image display has not completed. - - -To specify the stretch as part of the image display, you can generate -a range values string. This example is for an asinh stretch with a Q -value of 6 and an upper level of 98 percent: - -.. code-block:: py - - rvstring = fc._create_rangevalues_standard(algorithm='asinh', - asinh_q_value=6, - upper_value=98.0) - -The zoom value can be -specified in several different ways. When displaying images with different -pixel scales, the best practice is to specify -`ZoomType='ARCSEC_PER_SCREEN_PIX'` and then the numerical value, -e.g. `ZoomArcsecPerScreenPix=0.3`. - -The color table is specified with an integer. The pan point can be -specified with parameter `WorldPt`. For example: - -.. code-block:: py - - size_in_arcsec = 400 - ra = 150.00983 - dec = 2.59783 - target = '{};{};EQ_J2000'.format(ra, dec) - fc.show_fits(plot_id='IRAC1', - Title='COSMOS 3.6um', - Type='SERVICE', - Service='ATLAS', - SurveyKey='cosmos.cosmos_irac', - SurveyKeyBand='IRAC1', - WorldPt=target, - SizeInDeg=size_in_arcsec/3600, - ColorTable=1, - ZoomType='ARCSEC_PER_SCREEN_PIX', - ZoomArcsecPerScreenPix=0.3, - RangeValues=rvstring) - -Turning On WCS Locking ----------------------- - -When multiple images covering the same sky location are displayed, you can -align and lock by sky coordinates. To lock and align by world coordinates: - -.. code-block:: py - - fc.align_images(lock_match=True) - -Retrieving Images Using IRSA-Specific Searches ----------------------------------------------- - -Firefly includes image search processors for Infrared Science Archive (IRSA) -image holdings. A table of available projects for image searches is -maintained in the Firefly code base. The information can be retrieved -into an Astropy table: - -.. code-block:: py - - from astropy.table import Table - surveys = Table.read('https://raw.githubusercontent.com/Caltech-IPAC/firefly/dev/src/firefly/' + - 'java/edu/caltech/ipac/firefly/resources/irsa-image-master-table.csv', - format='csv') - -To select images available for the COSMOS project: - -.. code-block:: py - - cosmos_surveys = surveys[surveys['missionId'] == 'COSMOS'] - -To search the survey: - -.. code-block:: py - - size_in_arcsec = 200 - ra = 150.00983 - dec = 2.59783 - target = '{};{};EQ_J2000'.format(ra, dec) - fc.show_fits(plot_id='IRAC1', - Title='COSMOS 3.6um', - Type='SERVICE', - Service='ATLAS', - SurveyKey='cosmos.cosmos_irac', - SurveyKeyBand='IRAC1', - WorldPt=target, - SizeInDeg=size_in_arcsec/3600, - ColorTable=1, - ZoomType='ARCSEC_PER_SCREEN_PIX', - ZoomArcsecPerScreenPix=0.3, - RangeValues=rvstring) - - -Displaying HiPS Images ----------------------- - -While the above examples involve displaying FITS images, it's also possible to view a HiPS image using a different method that involves specifying the base URL where the target search is performed. -To search the survey: - -.. code-block:: py - - hips_url = 'https://irsa.ipac.caltech.edu/data/hips/CDS/2MASS/Color/' - size_in_deg = 0.2 - ra = 274.700727 - dec = -13.807228 - target = '{};{};EQ_J2000'.format(ra, dec) - fc.show_hips(viewer_id='hipspc1', - plot_id='HipsID1-1', - hips_root_url = hips_url, - Title='HiPS-2m', - WorldPt=target, - SizeInDeg=size_in_deg) - - -Displaying 3-Color Images -------------------------- - -It is possible to create a 3-color composite image using a list of dictionaries containing included parameters on all given bands (or simply one dictionary for that band). For example: - -.. code-block:: py - - rv = '92,-2,92,8,NaN,2,44,25,600,120' - ra = 210.80227 - dec = 54.34895 - target = '{};{};EQ_J2000'.format(ra, dec) - threeC= [ - { - 'Type' : 'SERVICE', - 'Service' : 'WISE', - 'Title' : '3 color', - 'SurveyKey' : '3a', - 'SurveyKeyBand': '3', - 'WorldPt' : target, - 'RangeValues': rv, - 'SizeInDeg' : '.14' - }, - { - 'Type' : 'SERVICE', - 'Service' : 'WISE', - 'Title' : '3 color', - 'SurveyKey' : '3a', - 'SurveyKeyBand': '2', - 'WorldPt' : target, - 'RangeValues': rv, - 'SizeInDeg' : '.14' - }, - { - 'Type' : 'SERVICE', - 'Service' : 'WISE', - 'Title' : '3 color', - 'SurveyKey' : '3a', - 'SurveyKeyBand': '1', - 'WorldPt' : target, - 'RangeValues': rv, - 'SizeInDeg' : '.14' - }] - fc.show_fits_3color(threeC, - plot_id='wise_m101', - viewer_id='3C') - - -Displaying Image from a URL ---------------------------- - -If you have the URL of an image, you can pass it directly instead of -downloading it and then uploading it to firefly: - -.. code-block:: py - - image_url = 'http://irsa.ipac.caltech.edu/ibe/data/wise/allsky/4band_p1bm_frm/6a/02206a/149/02206a149-w1-int-1b.fits?center=70,20&size=200pix' - fc.show_fits(url=image_url, plot_id='wise-allsky', title='WISE all-sky') diff --git a/docs/usage/examples b/docs/usage/examples new file mode 120000 index 0000000..d15735c --- /dev/null +++ b/docs/usage/examples @@ -0,0 +1 @@ +../../examples \ No newline at end of file diff --git a/docs/usage/getting-started.ipynb b/docs/usage/getting-started.ipynb new file mode 100644 index 0000000..7e61108 --- /dev/null +++ b/docs/usage/getting-started.ipynb @@ -0,0 +1,157 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "9535bf07", + "metadata": {}, + "source": [ + "# Getting Started" + ] + }, + { + "cell_type": "markdown", + "id": "da017587", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "- Python 3\n", + "- `firefly_client` (installable with `pip install firefly_client`)\n", + "- URL for a Firefly server" + ] + }, + { + "cell_type": "markdown", + "id": "37ed2705", + "metadata": {}, + "source": [ + "## Connect to Firefly and open the viewer\n", + "Create a `FireflyClient` instance by providing the URL of the Firefly server you want to connect to. Here we use the public [IRSA Viewer](https://irsa.ipac.caltech.edu/irsaviewer):" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "836ce9e7", + "metadata": {}, + "outputs": [], + "source": [ + "from firefly_client import FireflyClient\n", + "fc = FireflyClient.make_client(url='https://irsa.ipac.caltech.edu/irsaviewer')" + ] + }, + { + "cell_type": "markdown", + "id": "04d46eda", + "metadata": {}, + "source": [ + "`make_client()` usually opens a browser tab with the Firefly viewer automatically. If it didn’t, run `launch_browser()` which returns a success flag and the viewer URL." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "19e45530", + "metadata": {}, + "outputs": [], + "source": [ + "# fc.launch_browser()" + ] + }, + { + "cell_type": "markdown", + "id": "819addb2", + "metadata": {}, + "source": [ + "## Display a FITS image\n", + "Now, use the Firefly client we created above (`fc`) to show your image in Firefly." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "885fd22b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Image file can be a local path, URL, or file-like object - replace with your file\n", + "image_fpath = (\n", + " 'https://irsa.ipac.caltech.edu/ibe/data/wise/allsky/4band_p1bm_frm/9a/05379a/141/'\n", + " '05379a141-w2-int-1b.fits?center=202.4841667,47.23055556&size=400pix'\n", + ")\n", + "fc.show_fits_image(image_fpath)" + ] + }, + { + "cell_type": "markdown", + "id": "fac78b11", + "metadata": {}, + "source": [ + "## Display a catalog table\n", + "Similarly, you can show your table in Firefly.\n", + "\n", + "The sources are also overlaid automatically on the image if the table is a catalog containing celestial coordinates, and a default chart is displayed." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0bf10066", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Table file can be a local path, URL, or file-like object - replace with your file\n", + "table_fpath = (\n", + " \"http://irsa.ipac.caltech.edu/TAP/sync?FORMAT=IPAC_TABLE&QUERY=\"\n", + " \"SELECT+*+FROM+fp_psc+\"\n", + " \"WHERE+CONTAINS(POINT('J2000',ra,dec),\"\n", + " \"CIRCLE('J2000',202.4841667,47.23055556,0.125))=1\"\n", + ")\n", + "fc.show_table(table_fpath)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "ffpy", + "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.12.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/usage/getting-started.rst b/docs/usage/getting-started.rst deleted file mode 100644 index 41ee913..0000000 --- a/docs/usage/getting-started.rst +++ /dev/null @@ -1,67 +0,0 @@ -############### -Getting Started -############### - -Prerequisites -============= - -* Python 3 - -* firefly_client (installable with `pip install firefly_client`) - -* URL for a Firefly server - -.. _firefly_client-getting-started: - -Getting Started -=============== - -First, download some data by using wget or curl: - -.. code-block:: shell - :name: gs-download - - wget http://web.ipac.caltech.edu/staff/roby/demo/2mass-m31-green.fits - wget http://web.ipac.caltech.edu/staff/roby/demo/m31-2mass-2412-row.tbl - - curl -o 2mass-m31-green.fits http://web.ipac.caltech.edu/staff/roby/demo/2mass-m31-green.fits - curl -o m31-2mass-2412-row.tbl http://web.ipac.caltech.edu/staff/roby/demo/m31-2mass-2412-row.tbl - -Second, start a Python session and connect an instance of :class:`firefly_client.FireflyClient` -to a Firefly server. In this example, we will use a public server. For ease of demonstration, -please start the Python session in the directory from which you downloaded the sample files. - -.. code-block:: py - :name: gs-start - - from firefly_client import FireflyClient - fc = FireflyClient.make_client('https://irsa.ipac.caltech.edu/irsaviewer') - -Third, open a new browser tab using the :meth:`FireflyClient.launch_browser` method. If -a browser cannot be opened, a URL will be displayed for your web browser. - -.. code-block:: py - :name: gs-launch - - fc.launch_browser() - -Fourth, display an image in a FITS file by uploading the -file to the server with :meth:`FireflyClient.upload_file` -and then showing the image. - -.. code-block:: py - :name: gs-image - - fval = fc.upload_file('2mass-m31-green.fits') - fc.show_fits(fval) - -Fifth, display a table by uploading a catalog table (here, in IPAC format) and -then showing the table. The sources are also overlaid automatically on the -image since the catalog contains celestial coordinates, and a default -chart is displayed. - -.. code-block:: py - :name: gs-table - - tval = fc.upload_file('m31-2mass-2412-row.tbl') - fc.show_table(tval) diff --git a/docs/usage/index.rst b/docs/usage/index.rst index 8bbe48b..06d27ac 100644 --- a/docs/usage/index.rst +++ b/docs/usage/index.rst @@ -8,6 +8,8 @@ Using firefly_client getting-started initializing-vanilla displaying-images + displaying-3color + displaying-hips overlaying-regions viewing-tables charting diff --git a/docs/usage/initializing-vanilla.ipynb b/docs/usage/initializing-vanilla.ipynb new file mode 100644 index 0000000..657702f --- /dev/null +++ b/docs/usage/initializing-vanilla.ipynb @@ -0,0 +1,255 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "90c41059", + "metadata": {}, + "source": [ + "# Initializing a FireflyClient instance\n", + "This notebook focuses only on the initialization of a `FireflyClient` object. Later notebooks will demonstrate how to use it for visualizing your data.\n", + "\n", + "## Pick a Firefly server URL\n", + "\n", + "[Firefly](https://github.com/Caltech-IPAC/firefly), the interactive data visualization tool, is a web application (with a URL) that can be controlled from Python with a `FireflyClient` object. When we create the `FireflyClient` instance, we need to provide the URL of the Firefly server we want to connect to.\n", + "\n", + "By default, the value of the environment variable `FIREFLY_URL` will be used as the Firefly server URL. It can be set to one of the following:\n", + "1. a local Firefly server which can be run via a [Firefly Docker image](https://hub.docker.com/r/ipac/firefly), typically at http://localhost:8080/firefly\n", + "2. a public Firefly server such as:\n", + " - IRSA Viewer at https://irsa.ipac.caltech.edu/irsaviewer\n", + " - Rubin Science Platform Portal at https://data.lsst.cloud/portal/app/ (requires authentication; the `ACCESS_TOKEN` environment variable must be set)\n", + "\n", + "If `FIREFLY_URL` is not defined, the default server URL is `http://localhost:8080/firefly`, which is often used for a Firefly server running locally.\n", + "\n", + ".. note::\n", + " The environment variable must be defined in the shell where Jupyter (or the Python session) was started. It may not work if defined in a notebook cell through `%env` or `os.environ`.\n" + ] + }, + { + "cell_type": "markdown", + "id": "0a7a82bb", + "metadata": {}, + "source": [ + "## Imports\n", + "The only required import here is `FireflyClient`." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "c676470f", + "metadata": {}, + "outputs": [], + "source": [ + "from firefly_client import FireflyClient" + ] + }, + { + "cell_type": "markdown", + "id": "f1da6b4e", + "metadata": {}, + "source": [ + "## Initialize FireflyClient\n", + "There are two ways to initialize `FireflyClient` from Python, depending on whether you're running the notebook in JupyterLab or not:" + ] + }, + { + "cell_type": "markdown", + "id": "c5726946", + "metadata": {}, + "source": [ + "### 1. From Jupyter Notebook (or a Python shell)\n", + "You can use `make_client()` in a Jupyter Notebook (or even a Python shell), which will open the Firefly viewer in a new web browser tab. `make_client()` also allows you to pass the URL directly (other than through environment variable) as the `url` parameter." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "f337056e", + "metadata": {}, + "outputs": [], + "source": [ + "# fc = FireflyClient.make_client() # URL is taken from FIREFLY_URL env variable\n", + "\n", + "# URL can be defined explicitly as a parameter\n", + "fc = FireflyClient.make_client(url=\"https://irsa.ipac.caltech.edu/irsaviewer\")" + ] + }, + { + "cell_type": "markdown", + "id": "9af544ca", + "metadata": {}, + "source": [ + ".. note::\n", + " When running locally, `make_client()` will usually try to open a browser tab automatically. If it can’t (for example, if you're running on a remote machine), it will print or display a URL that you can click to open." + ] + }, + { + "cell_type": "markdown", + "id": "7e62001a", + "metadata": {}, + "source": [ + ".. warning::\n", + " After initializing `fc`, make sure you’ve opened the Firefly viewer URL before running methods which update the UI." + ] + }, + { + "cell_type": "markdown", + "id": "7d171495", + "metadata": {}, + "source": [ + "### 2. From JupyterLab\n", + "You can use `make_lab_client()` in JupyterLab to open the Firefly viewer in a new tab within the Lab, which provides a more integrated UI experience. This requires you to have [jupyter_firefly_extensions](https://github.com/Caltech-IPAC/jupyter_firefly_extensions/blob/master/README.md) set up in your environment:\n", + "1. In your Python environment, run `pip install jupyter_firefly_extensions`.\n", + "2. Set `FIREFLY_URL` environment variable before running `jupyter lab`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "187e0078", + "metadata": {}, + "outputs": [], + "source": [ + "# fc = FireflyClient.make_lab_client()" + ] + }, + { + "cell_type": "markdown", + "id": "7ae06c1c", + "metadata": {}, + "source": [ + "## Other helpful methods\n", + "\n", + "### Reinitialize the viewer\n", + "To clean the state of the Firefly server (i.e., remove all displayed components and start fresh), you can reinitialize the viewer. This is specifically helpful if a Python connection with the server is already open and re-running `make_lab_client` (or `make_client`) leads to stale state." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "6eee34fa", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fc.reinit_viewer()" + ] + }, + { + "cell_type": "markdown", + "id": "b5a95d6c", + "metadata": {}, + "source": [ + "### Explicitly open a browser tab\n", + "By default, `make_client()` opens a browser tab for Firefly. You can also trigger that behavior explicitly for a `FireflyClient` object by using the `launch_browser` method. It will return two values: a boolean indicating whether the web browser open was successful, and the URL for your web browser." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "c4e3e890", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(True,\n", + " 'https://irsa.ipac.caltech.edu/irsaviewer/?__wsch=anNpbmdoYWwyMDI2LTAxLTA3')" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fc.launch_browser()" + ] + }, + { + "cell_type": "markdown", + "id": "a92a4290", + "metadata": {}, + "source": [ + "### Display Firefly URL\n", + "You can use `display_url()` to print the browser URL if running in a terminal, and to show a clickable link if running in a Jupyter notebook." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "b9fcbab6", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "Open your web browser to this link" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fc.display_url()" + ] + }, + { + "cell_type": "markdown", + "id": "118244d2", + "metadata": {}, + "source": [ + "### Set a custom channel\n", + "`FireflyClient` opens a connection to the Firefly server on a particular WebSocket channel. You can override it when using `make_client()` as shown below.\n", + "\n", + "In typical usage, it is unnecessary to set the channel when instantiating `FireflyClient`, as a unique string will be auto-generated. If you do wish to set the channel explicitly (e.g., for sharing your Firefly viewer/display with someone else), take care to make the channel unique." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "bc6dbbcf", + "metadata": {}, + "outputs": [], + "source": [ + "fc2 = FireflyClient.make_client(url=\"https://irsa.ipac.caltech.edu/irsaviewer\",\n", + " channel_override=\"my-custom-channel\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "ffpy", + "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.12.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/usage/initializing-vanilla.rst b/docs/usage/initializing-vanilla.rst deleted file mode 100644 index d93acf6..0000000 --- a/docs/usage/initializing-vanilla.rst +++ /dev/null @@ -1,79 +0,0 @@ -##################################### -Initializing a FireflyClient instance -##################################### - -Once a Firefly server has been identified, the connection parameters can be -used to initialize a :class:`FireflyClient` instance. By default, the value -of the environment variable `FIREFLY_URL` will be used as the server URL, if defined. If -`FIREFLY_URL` is not defined, the default server URL is `http://localhost:8080/firefly` -which is often used for a Firefly server running locally. - -Optional arguments for initializing a `FireflyClient` instance include `channel` -and `html_file`. - -For a default server running locally, use `localhost` or `127.0.0.1` together -with the port that the server is using, and append `/firefly`. The default port is 8080. - -.. code-block:: py - :name: using-localhost - - import firefly_client - fc = firefly_client.FireflyClient('http://127.0.0.1:8080/firefly') - -If the Python session is running on your own machine, you can use the -:meth:`FireflyClient.launch_browser` method to open up a browser tab. - -.. code-block:: py - :name: launch-browser - - fc.launch_browser() - -The :meth:`FireflyClient.launch_browser` method will return two values: a boolean -indicating whether the web browser open was successful, and the URL for your -web browser. - -.. warning:: - - On Mac OS X 10.12.5, an error message may be displayed with a URL and - a note that it doesn't understand the "open location message". If a - browser tab is not automatically opened, copy and paste the displayed - URL into the address bar of your browser. This issue has been fixed - in Mac OS X 10.12.6. - -If your Python session is not running on your local machine, the -:meth:`FireflyClient.launch_browser` -method will display the URL for your web browser. Alternatively, you can use -the :meth:`FireflyClient.display_url` method to print the browser URL if -running in a terminal, and to show a clickable link if running in a -Jupyter notebook. - -.. code-block:: py - - fc.display_url() - -In typical usage, it is unnecessary to set the `channel` parameter when -instantiating `FireflyClient`. A unique string will be auto-generated. -If you do wish to set the channel explicitly, e.g. for sharing your display -with someone else, take care to make the channel unique. - -.. warning:: - - After initializing :class:`FireflyClient`, make sure you have opened a web browser - to the appropriate URL, before proceeding to use the Python API described - in the following sections. - - -Initializing with the make_client Factory Function --------------------------------------------------- - -For an easier initialization, you can use the :meth:`FireflyClient.make_client` -factor function. This function will use the value of the FIREFLY_URL -environment variable for the Firefly server. Additionally, it will attempt -to start a Firefly browser tab or window if possible, and if not, it will -display a link for the Firefly display. - -.. code-block:: py - - fc = FireflyClient.make_client() - - diff --git a/docs/usage/overlaying-regions.ipynb b/docs/usage/overlaying-regions.ipynb new file mode 100644 index 0000000..bd7a3d3 --- /dev/null +++ b/docs/usage/overlaying-regions.ipynb @@ -0,0 +1,262 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "caa4d3cd", + "metadata": {}, + "source": [ + "# Visualizing Regions on Images\n", + "\n", + "Firefly supports [DS9-style region](https://ds9.si.edu/doc/ref/region.html) overlays. This notebook demonstrates how to create a region layer, add/remove region data, and delete a layer." + ] + }, + { + "cell_type": "markdown", + "id": "90681d7f", + "metadata": {}, + "source": [ + "## Setup\n", + "First, we create a `FireflyClient` instance and open a Firefly viewer. See [Initializing a FireflyClient instance](./initializing-vanilla.html) for more details. Then, we display a FITS image from a URL so that we have an image to overlay regions on. See [Displaying a FITS Image](./displaying-fits-image.html) for more details." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "14b195f0", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from firefly_client import FireflyClient\n", + "import tempfile\n", + "\n", + "# Initialize a FireflyClient instance\n", + "fc = FireflyClient.make_client(url=\"https://irsa.ipac.caltech.edu/irsaviewer\")\n", + "\n", + "# Display a FITS image (from URL of WISE W2 cutout of M51 galaxy)\n", + "img_url = 'https://irsa.ipac.caltech.edu/ibe/data/wise/allsky/4band_p1bm_frm/9a/05379a/141/05379a141-w2-int-1b.fits?center=202.4841667,47.23055556&size=400pix'\n", + "plot_id = 'wise-cutout'\n", + "fc.show_fits_image(file_input=img_url, plot_id=plot_id, title='WISE Cutout')" + ] + }, + { + "cell_type": "markdown", + "id": "46b50b8c", + "metadata": {}, + "source": [ + "## Create a region layer\n", + "\n", + "Regions are drawn as layers on top of images. Typically, you create a layer with `overlay_region_layer()`, then add more items with `add_region_data()`.\n", + "\n", + "### From region commands (string)\n", + "\n", + "A string or list of strings containing [region commands](https://ds9.si.edu/doc/ref/region.html) can be added as an overlay layer on an image." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "8ff1f3df", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "region_data = [\"icrs\",\n", + " \"circle 202.4841667d 47.23055556d 6' # color=red\",\n", + " \"text 202.5608556d 47.3021292d {M51} # color=red\",\n", + " ]\n", + "region_layer_id = 'wise-regions'\n", + "fc.overlay_region_layer(region_data=region_data,\n", + " title='WISE Annotations',\n", + " region_layer_id=region_layer_id,\n", + " plot_id=plot_id)" + ] + }, + { + "cell_type": "markdown", + "id": "e9c02ca6", + "metadata": {}, + "source": [ + "### From a region file\n", + "If you have a region file (.reg or .txt), you can directly upload that using `upload_file` method and overlay it by using `file_on_server` parameter of `overlay_region_layer` method." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "13f8a78f", + "metadata": {}, + "outputs": [], + "source": [ + "# Set it to region file you have locally\n", + "reg_fpath = None\n", + "\n", + "# Here we genrate a region file using region data defined above\n", + "with tempfile.NamedTemporaryFile(mode='w+t', delete=False, suffix=\".txt\") as reg_file:\n", + " reg_file.write(\"\\n\".join(region_data))\n", + " reg_fpath = reg_file.name" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "4d7fa9e6", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fc.overlay_region_layer(file_on_server=fc.upload_file(reg_fpath),\n", + " title='WISE Annotations',\n", + " region_layer_id=region_layer_id, # same ID to replace previous one\n", + " plot_id=plot_id)" + ] + }, + { + "cell_type": "markdown", + "id": "93cb573e", + "metadata": {}, + "source": [ + "## Add region data to an existing layer\n", + "\n", + "To add more regions to the same layer, use `add_region_data()`. Pass the ID of that layer as `region_layer_id` parameter." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "f6794996", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ra, dec = 202.49808, 47.26617\n", + "point_source = f'icrs;point {ra}d {dec}d # point=cross 25 text={{NGC 5195}} color=cyan'\n", + "fc.add_region_data(region_data=point_source,\n", + " region_layer_id=region_layer_id)" + ] + }, + { + "cell_type": "markdown", + "id": "fb678124", + "metadata": {}, + "source": [ + "## Remove a region command\n", + "\n", + "You can use `remove_region_data()` to remove an individual region command if you saved the exact string you added." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "b3b1cc99", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fc.remove_region_data(region_data=point_source, region_layer_id=region_layer_id)" + ] + }, + { + "cell_type": "markdown", + "id": "76646355", + "metadata": {}, + "source": [ + "## Delete an entire region layer\n", + "\n", + "To remove the entire region layer, use `delete_region_layer()`." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "0359b1c7", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fc.delete_region_layer(region_layer_id)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "ffpy", + "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.12.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/usage/overlaying-regions.rst b/docs/usage/overlaying-regions.rst deleted file mode 100644 index 9f39273..0000000 --- a/docs/usage/overlaying-regions.rst +++ /dev/null @@ -1,40 +0,0 @@ -Visualizing Regions -------------------- - -The API includes detailed support for ds9-style regions. A list of strings -containing region commands can be added to an overlay layer on an image. - -.. code-block:: py - - region_data = ['J2000', - 'text 10.6845417 41.2689167{M31 Nucleus} #color=red', - 'point 10.7035000 41.2535833 # point=circle 20', - 'image;line(249.5 164.1 283.8 206.6) # color=blue width=5'] - fc.add_region_data(region_data=region_data, region_layer_id='layer1', - title='my_marks', plot_id='m31-green') - -An individual region command can be removed using -:meth:`FireflyClient.remove_region_data`. To remove the blue line: - -.. code-block:: py - - fc.remove_region_data(region_data=region_data[-1], - region_layer_id='layer1') - -An entire region layer can be deleted with :meth:`FireflyClient.delete_region_layer`: - -.. code-block:: py - - fc.delete_region_layer(region_layer_id='layer1', plot_id='m31-green') - -A region layer can be uploaded from a file and overlaid on an image by -using :meth:`FireflyClient.upload_file` and :meth:`FireflyClient.overlay_region_layer`: - -.. code-block:: py - - with open('myreg.txt', 'w') as fh: - fh.write('\n'.join(region_data)) - rval = fc.upload_file('myreg.txt') - fc.overlay_region_layer(file_on_server=rval, - region_layer_id='layer2', - plot_id='m31-green') diff --git a/docs/usage/viewing-tables.ipynb b/docs/usage/viewing-tables.ipynb new file mode 100644 index 0000000..335c5d6 --- /dev/null +++ b/docs/usage/viewing-tables.ipynb @@ -0,0 +1,484 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "73088cb6", + "metadata": {}, + "source": [ + "# Displaying Tables and Catalogs\n", + "\n", + "This notebook shows how to display tables in Firefly and how to modify the table display (filtering/sorting). Catalog tables are overlaid on images by default if Firefly recognizes celestial coordinates in the table." + ] + }, + { + "cell_type": "markdown", + "id": "b53c9bca", + "metadata": {}, + "source": [ + "## Setup\n", + "First, we create a `FireflyClient` instance and open a Firefly viewer. See [Initializing a FireflyClient instance](./initializing-vanilla.html) for more details. Then, we display a FITS image from a URL so that we have an image for catalog overlays. See [Displaying a FITS Image](./displaying-fits-image.html) for more details." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "95cdcb78", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from firefly_client import FireflyClient\n", + "\n", + "# Following imports are just for example data fetching and processing (not needed always)\n", + "from astropy.utils.data import download_file\n", + "from astropy.table import Table\n", + "import io\n", + "\n", + "# Initialize a FireflyClient instance\n", + "fc = FireflyClient.make_client(url=\"https://irsa.ipac.caltech.edu/irsaviewer\")\n", + "\n", + "# Display a FITS image (from URL of WISE W2 cutout of M51 galaxy)\n", + "cutout_image_url = 'https://irsa.ipac.caltech.edu/ibe/data/wise/allsky/4band_p1bm_frm/9a/05379a/141/05379a141-w2-int-1b.fits?center=202.4841667,47.23055556&size=400pix'\n", + "plot_id = 'wise-cutout'\n", + "fc.show_fits_image(file_input=cutout_image_url, plot_id=plot_id, title='WISE Cutout')" + ] + }, + { + "cell_type": "markdown", + "id": "074f5bd7", + "metadata": {}, + "source": [ + "## Display a Table\n", + "\n", + "Use `show_table` method of the FireflyClient object to display a table. Similar to `show_fits_image`, it can take a URL, a local file path, or a file-like object as input via the `file_input` parameter." + ] + }, + { + "cell_type": "markdown", + "id": "5fa64b5a", + "metadata": {}, + "source": [ + "### From a local file\n", + "You can specify path of any local table file. Here we download the Gaia DR3 catalog for 300\" cone around M51 and use its file path:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "2555a125", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'/Users/jsinghal/.astropy/cache/download/url/55fa7a5603170b3f0b7f826748efe73a/contents'" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tbl_url_gaia = \"https://gea.esac.esa.int/tap-server/tap/sync?LANG=ADQL&QUERY=SELECT+*+FROM+gaiadr3.gaia_source+WHERE+CONTAINS(POINT('ICRS',ra,dec),CIRCLE('ICRS',202.4841667,47.23055556,0.083333))=1\"\n", + "tbl_fpath_gaia = download_file(tbl_url_gaia, cache=True, timeout=120)\n", + "tbl_fpath_gaia" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "ce7a9c19", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tbl_id_gaia = 'gaia-catalog'\n", + "fc.show_table(file_input=tbl_fpath_gaia,\n", + " tbl_id=tbl_id_gaia, \n", + " title='Gaia Catalog')" + ] + }, + { + "cell_type": "markdown", + "id": "98c42f09", + "metadata": {}, + "source": [ + "### From an in-memory file-like object\n", + "\n", + "You can also use a file-like object (e.g. `StringIO` or `BytesIO` stream) instead of a local file path or URL. This is useful when you are working with a Table file in memory (for e.g. as an Astropy Table) and don't want to write it to disk. " + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "51aa7844", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
Table length=5\n", + "
\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
solution_idDESIGNATIONSOURCE_IDrandom_indexref_epochrara_errordecdec_errorparallaxparallax_errorparallax_over_errorpmpmrapmra_errorpmdecpmdec_errorra_dec_corrra_parallax_corrra_pmra_corrra_pmdec_corrdec_parallax_corrdec_pmra_corrdec_pmdec_corrparallax_pmra_corrparallax_pmdec_corrpmra_pmdec_corrastrometric_n_obs_alastrometric_n_obs_acastrometric_n_good_obs_alastrometric_n_bad_obs_alastrometric_gof_alastrometric_chi2_alastrometric_excess_noiseastrometric_excess_noise_sigastrometric_params_solvedastrometric_primary_flagnu_eff_used_in_astrometrypseudocolourpseudocolour_errorra_pseudocolour_corrdec_pseudocolour_corrparallax_pseudocolour_corrpmra_pseudocolour_corrpmdec_pseudocolour_corrastrometric_matched_transitsvisibility_periods_usedastrometric_sigma5d_maxmatched_transitsnew_matched_transitsmatched_transits_removedipd_gof_harmonic_amplitudeipd_gof_harmonic_phaseipd_frac_multi_peakipd_frac_odd_winruwescan_direction_strength_k1scan_direction_strength_k2scan_direction_strength_k3scan_direction_strength_k4scan_direction_mean_k1scan_direction_mean_k2scan_direction_mean_k3scan_direction_mean_k4duplicated_sourcephot_g_n_obsphot_g_mean_fluxphot_g_mean_flux_errorphot_g_mean_flux_over_errorphot_g_mean_magphot_bp_n_obsphot_bp_mean_fluxphot_bp_mean_flux_errorphot_bp_mean_flux_over_errorphot_bp_mean_magphot_rp_n_obsphot_rp_mean_fluxphot_rp_mean_flux_errorphot_rp_mean_flux_over_errorphot_rp_mean_magphot_bp_rp_excess_factorphot_bp_n_contaminated_transitsphot_bp_n_blended_transitsphot_rp_n_contaminated_transitsphot_rp_n_blended_transitsphot_proc_modebp_rpbp_gg_rpradial_velocityradial_velocity_errorrv_method_usedrv_nb_transitsrv_nb_deblended_transitsrv_visibility_periods_usedrv_expected_sig_to_noiserv_renormalised_gofrv_chisq_pvaluerv_time_durationrv_amplitude_robustrv_template_teffrv_template_loggrv_template_fe_hrv_atm_param_originvbroadvbroad_errorvbroad_nb_transitsgrvs_maggrvs_mag_errorgrvs_mag_nb_transitsrvs_spec_sig_to_noisephot_variable_flaglbecl_lonecl_latin_qso_candidatesin_galaxy_candidatesnon_single_starhas_xp_continuoushas_xp_sampledhas_rvshas_epoch_photometryhas_epoch_rvhas_mcmc_gspphothas_mcmc_mscin_andromeda_surveyclassprob_dsc_combmod_quasarclassprob_dsc_combmod_galaxyclassprob_dsc_combmod_starteff_gspphotteff_gspphot_lowerteff_gspphot_upperlogg_gspphotlogg_gspphot_lowerlogg_gspphot_uppermh_gspphotmh_gspphot_lowermh_gspphot_upperdistance_gspphotdistance_gspphot_lowerdistance_gspphot_upperazero_gspphotazero_gspphot_lowerazero_gspphot_upperag_gspphotag_gspphot_lowerag_gspphot_upperebpminrp_gspphotebpminrp_gspphot_lowerebpminrp_gspphot_upperlibname_gspphot
yrdegmasdegmasmasmasmas / yrmas / yrmas / yrmas / yrmas / yrmas1 / um1 / um1 / ummasdegdegdegdegdegelectron / selectron / smagelectron / selectron / smagelectron / selectron / smagmagmagmagkm / skm / sdkm / sKlog(cm.s**-2)dexkm / skm / smagmagdegdegdegdegKKKlog(cm.s**-2)log(cm.s**-2)log(cm.s**-2)dexdexdexpcpcpcmagmagmagmagmagmagmagmagmag
int64objectint64int64float64float64float32float64float32float64float32float32float32float64float32float64float32float32float32float32float32float32float32float32float32float32float32int16int16int16int16float32float32float32float32int16boolfloat32float32float32float32float32float32float32float32int16int16float32int16int16int16float32float32int16int16float32float32float32float32float32float32float32float32float32boolint16float64float32float32float32int16float64float32float32float32int16float64float32float32float32float32int16int16int16int16int16float32float32float32float32float32int16int16int16int16float32float32float32float32float32float32float32float32int16float32float32int16float32float32int16float32objectfloat64float64float64float64boolboolint16boolboolboolboolboolboolboolboolfloat32float32float32float32float32float32float32float32float32float32float32float32float32float32float32float32float32float32float32float32float32float32float32float32object
1636148068921376768Gaia DR3 155198829213154956815519882921315495688900820522016.0202.47621835713810.748323247.151972776228120.90635014-1.55288169676193121.2272083-1.26537742.435153-2.4330676697812940.994036850.100757503706651461.26996960.37464455-0.189580160.1645490.16169423-0.267974230.140673730.170917-0.16200161-0.377165970.27786323258025622.6322927328.2862.32079221.056778695False--1.3422680.26838365-0.06818995-0.025997920.19759205-0.068285316-0.140469131241.8951416381700.04526214396.571175021.11861560.184248670.373258770.174519910.3911204-74.23466-63.91142337.65227521.430153True29395.722430396933180.9790209597.7736320.73483326181.2285475622398417.1616810.5600719.69297625139.12624891666614.4043859.65860419.3893723.346705702602500.30360413-1.04185681.3454609--------------------------------------------NOT_AVAILABLE104.7920549886698968.59840109705154175.1697559722966650.90282916020732FalseTrue0FalseFalseFalseFalseFalseFalseFalseFalse0.000613337850.998519960.0008667134------------------------------------------
1636148068921376768Gaia DR3 1551988463929387648155198846392938764816361497722016.0202.436023552909940.444228647.1665352226328240.597321-0.210152053103638050.7318001-0.287171424.13046170.88223862278057660.56147894.0351415228795810.75259410.27231008-0.15583270.0490657130.08984825-0.214837010.0243773630.3666216-0.06945767-0.373181760.20351215446043797.8904915884.07934.623820.21786395False--1.09234140.150204180.00750743360.107977310.036282983-0.048866370.03252402752271.1143742703980.09647766111.126526141.27961210.211497130.3069240.118643630.28504333-56.36863-64.5628545.92181816.223856False519200.253152925281461.3851699144.5693819.933418221406.211639888164254.93128225.59946817.468416231191.584613295731732.5869336.56633817.05758312.97256102202300.41083336-2.4650022.8758354--------------------------------------------NOT_AVAILABLE104.8767057535582168.59620898462525175.1210834453790450.898730580732106FalseTrue0FalseFalseFalseFalseFalseFalseFalseFalse5.039107e-110.99999633.7102905e-06------------------------------------------
1636148068921376768Gaia DR3 1551988773167190784155198877316719078410193545502016.0202.473203779877340.385525647.189644985715040.45663941.52114523855006480.61758242.46306471.2724876-0.463938104979195630.48734134-1.18489920389850760.5858320.21224469-0.112964990.0393107720.08014045-0.0568773750.050551110.26251525-0.10948872-0.33805060.2342358445943873.5123873574.45332.74379943.949466295False--1.77056810.12830798-0.046022233-0.03372772-0.0159144140.03260910.01230576252260.87323254651930.04841678680.55671301.1210413----------------False535196.272227645192661.3947663140.7205219.9552251945.707503741238839.50697323.93773717.89915501248.815933364719367.42367618.5219217.00664911.18101905105000.89250183-2.05606842.9485703--------------------------------------------NOT_AVAILABLE104.8391760547594668.56482582796096175.1322755827956750.93224110096643FalseTrue0FalseFalseFalseFalseFalseFalseFalseFalse1.2306821e-101.01.5448892e-08------------------------------------------
1636148068921376768Gaia DR3 1551988807529534208155198880752953420815801030352016.0202.476360314691650.2781962847.201814460503580.31006017-1.29368957897934740.41817343-3.09366774.04422661.66627712921698110.34709073.68500901716005740.401813060.14083208-0.17493783-0.00223527620.1443171-0.0854718460.1000377460.25123927-0.058198392-0.2681360.107605435494049048.797426856.99832.5235798.44341995False--1.76908730.08837092-0.009559230.0111100910.067102350.020670226-0.01831183458300.58091736747400.0751268442.541615611.29494320.144107610.181373430.083373840.31451-95.37658-61.8711242.6610814.672581False596297.468649268002651.9929224149.2625419.50376331988.544402607739143.888522.52399617.85105131891.162016105026944.44282520.05187617.3730036.31900702502500.47804832-1.65271192.1307602--------------------------------------------NOT_AVAILABLE104.8473541831317368.55283585204637175.1237760788416450.94337703119712FalseTrue0FalseFalseFalseFalseFalseFalseFalseFalse4.911622e-100.99905010.0009499131------------------------------------------
1636148068921376768Gaia DR3 155199042243653811215519904224365381122031187922016.0202.504637459728540.5857174447.229141001353160.7143791-1.27758908286871130.8813056-1.4496552.8226283-2.7475935445175160.7255988-0.64649817814629550.87648620.23443323-0.112172480.138224560.115287475-0.0347322080.0933008640.38000315-0.032184172-0.226375710.223657194640458638.1626972947.44687.54979447.09826395False--1.61621610.18061645-0.014007429-0.068259280.024061043-0.0184590560.0789985256291.3104724702100.19378218153.90639202.50748370.218877510.247038630.095638780.3500768-93.71961-64.6571447.03715.638713False554231.605305833965451.702601136.0302919.77549660669.712400811333319.92728833.60780318.2738260515.752988859784821.50603923.98177517.9667915.118472606006000.30702972-1.50167471.8087044--------------------------------------------NOT_AVAILABLE104.829794916154568.52005828530262175.123225696429950.97677659075816FalseTrue0FalseFalseFalseFalseFalseFalseFalseFalse1.2920486e-080.99892770.0010722713------------------------------------------
" + ], + "text/plain": [ + "\n", + " solution_id DESIGNATION ... libname_gspphot\n", + " ... \n", + " int64 object ... object \n", + "------------------- ---------------------------- ... ---------------\n", + "1636148068921376768 Gaia DR3 1551988292131549568 ... \n", + "1636148068921376768 Gaia DR3 1551988463929387648 ... \n", + "1636148068921376768 Gaia DR3 1551988773167190784 ... \n", + "1636148068921376768 Gaia DR3 1551988807529534208 ... \n", + "1636148068921376768 Gaia DR3 1551990422436538112 ... " + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "gaia_tbl = Table.read(tbl_fpath_gaia)\n", + "gaia_galaxy_tbl = gaia_tbl[gaia_tbl['classprob_dsc_combmod_galaxy'] >= 0.95]\n", + "gaia_galaxy_tbl[:5]" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "673d095b", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "WARNING: W50: ?:?:?: W50: Invalid unit string 'log(cm.s**-2)' [astropy.io.votable.tree]\n" + ] + } + ], + "source": [ + "tbl_stream = io.BytesIO()\n", + "gaia_galaxy_tbl.write(tbl_stream, format='votable')" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "a78ae323", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fc.show_table(file_input=tbl_stream,\n", + " tbl_id=tbl_id_gaia+'-galaxy',\n", + " title='Gaia Galaxy Catalog')" + ] + }, + { + "cell_type": "markdown", + "id": "e0dc369e", + "metadata": {}, + "source": [ + "### From a URL\n", + "\n", + "You can specify URL of any table. Here we use an IRSA TAP query to retrieve a 2MASS catalog for 0.125 degree cone at M51." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "ad28bca6", + "metadata": {}, + "outputs": [], + "source": [ + "tbl_url_2mass = \"http://irsa.ipac.caltech.edu/TAP/sync?FORMAT=IPAC_TABLE&QUERY=SELECT+*+FROM+fp_psc+WHERE+CONTAINS(POINT('J2000',ra,dec),CIRCLE('J2000',202.4841667,47.23055556,0.125))=1\"" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "d7fb13ba", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tbl_id_2mass = '2mass-catalog'\n", + "fc.show_table(file_input=tbl_url_2mass,\n", + " tbl_id=tbl_id_2mass,\n", + " title='2MASS Catalog')" + ] + }, + { + "cell_type": "markdown", + "id": "6886f4a1", + "metadata": {}, + "source": [ + ".. note::\n", + " Displaying a catalog table also caused Firefly to overlay the image with markers for each row of the table by default. Also we see the active chart and coverage tab as bonus! If we have more than one images displayed, the catalog overlay will appear to all images that cover the catalog area." + ] + }, + { + "cell_type": "markdown", + "id": "8ef1d9e4", + "metadata": {}, + "source": [ + "## Modify the displayed table\n", + "After displaying a table in Firefly, you can apply filters and sorting by `tbl_id`." + ] + }, + { + "cell_type": "markdown", + "id": "609acf80", + "metadata": {}, + "source": [ + "### Sorting by a column\n", + "You can sort the table by a column in ascending (`ASC`) or descending (`DESC`) order:" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "1b2cd933", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fc.sort_table_column(tbl_id=tbl_id_2mass, # note: we use the table id we defined above\n", + " column_name='j_m', sort_direction='ASC')" + ] + }, + { + "cell_type": "markdown", + "id": "8e0cebb3", + "metadata": {}, + "source": [ + "### Filtering the rows\n", + "Filters can be specified as an SQL WHERE clause-like string with column names quoted:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "2a4d4245", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fc.apply_table_filters(tbl_id=tbl_id_2mass,\n", + " filters='\"j_m\"<15 and \"j_cmsig\"<0.05')" + ] + }, + { + "cell_type": "markdown", + "id": "32a84282", + "metadata": {}, + "source": [ + ".. note::\n", + " You can see these filters in the table display. The catalog markers on the image also reduce in number as well as the active chart updates too.\n", + "\n", + "To remove the filters:" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "e57a13b5", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fc.apply_table_filters(tbl_id=tbl_id_2mass, filters='')" + ] + }, + { + "cell_type": "markdown", + "id": "de39fc06", + "metadata": {}, + "source": [ + "## Tweaking the table display parameters\n", + "`show_table` method offers several parameters other than the ones we used above, to control how to display the table." + ] + }, + { + "cell_type": "markdown", + "id": "2d78bc35", + "metadata": {}, + "source": [ + "### Load table without displaying it\n", + "By default, `show_table` loads the provided table and displays it in a table viewer. If it is desired to overlay the table on an image, or to make plots from it without showing the table in the viewer, you can set the `visible` parameter to False. \n", + "\n", + ".. tip::\n", + " This is especially useful for loading a MOC file (a single-column table) since you only want to overlay the MOC map on the HiPS image without displaying the table. See [Overlay MOC on HiPS](./displaying-hips.html)" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "85a78e22", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tbl_url_spitzer = \"https://irsa.ipac.caltech.edu/cgi-bin/Gator/nph-query?outfmt=1&catalog=slphotdr4&objstr=202.484167d+47.230556d+eq+j2000&spatial=Cone&radius=240\"\n", + "fc.show_table(file_input=tbl_url_spitzer,\n", + " title='Spitzer catalog',\n", + " visible=False)" + ] + }, + { + "cell_type": "markdown", + "id": "1626fa0c", + "metadata": {}, + "source": [ + ".. note::\n", + " It may take some time to load this catalog table, and since there's no feedback from the table display, look for the spinner on the top left of the image display." + ] + }, + { + "cell_type": "markdown", + "id": "f8e11a84", + "metadata": {}, + "source": [ + "### Display table without catalog overlay\n", + "\n", + "If the table contains celestial coordinates recognized by Firefly, the catalog overlay will appear by default on the displayed image. But if you specifically do not want the table overlaid on the image, you can set the `is_catalog` parameter to False" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fc.show_table(file_input=tbl_url_spitzer,\n", + " title='Spitzer: no overlay',\n", + " is_catalog=False\n", + " )" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "ffpy", + "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.12.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/usage/viewing-tables.rst b/docs/usage/viewing-tables.rst deleted file mode 100644 index 6d87145..0000000 --- a/docs/usage/viewing-tables.rst +++ /dev/null @@ -1,71 +0,0 @@ -############################### -Visualizing Tables and Catalogs -############################### - -Tables can be uploaded to the Firefly server with :meth:`FireflyClient.upload_file`, -and displayed in a table viewer component with :meth:`FireflyClient.show_table`. -The default is to overlay symbols for each row of the table (`is_catalog=True`) -if the table contains recognizable celestial coordinates. - -.. code-block:: py - - tval = fc.upload_file('m31-2mass-2412-row.tbl') - fc.show_table(file_on_server=tval, tbl_id='m31-table') - -Modifying Table Display Parameters ----------------------------------- - -If it is desired to overlay the table on an image, or to make plots from it, -without showing the table in the viewer, use :meth:`FireflyClient.fetch_table`: - -.. code-block:: py - - fc.fetch_table(file_on_server=tval, tbl_id='invisible-table') - -Alternatively, you can turn off the `visible` parameter in :meth:`FireflyClient.show_table`: - -.. code-block:: py - - fc.show_table(file_on_server=tval, tbl_id='invisible-table', visible=False) - -If the table does not contain celestial coordinates recognized by Firefly, -the image overlay will not appear. But if you specifically do not want -the table overlaid on the image, `is_catalog=False` can be specified (it is -`True` by default): - -.. code-block:: py - - fc.show_table(file_on_server=tval, tbl_id='2mass-tbl', is_catalog=False) - - -Displaying Table from a URL ---------------------------- - -If you have the URL of a table, you can pass it directly instead of -downloading it and then uploading it to firefly: - -.. code-block:: py - - table_url = "http://irsa.ipac.caltech.edu/TAP/sync?FORMAT=IPAC_TABLE&QUERY=SELECT+*+FROM+fp_psc+WHERE+CONTAINS(POINT('J2000',ra,dec),CIRCLE('J2000',70.0,20.0,0.1))=1" - tbl_id_2mass_psc = '2mass-point-source-catalog' - fc.show_table(url=table_url, tbl_id=tbl_id_2mass_psc) - -Filtering/Sorting a loaded Table --------------------------------- - -After displaying a table in firefly, you can also apply filters on it. -You will need to pass the `tbl_id` of that table and specify `filters` as an -SQL WHERE clause-like string with column names quoted: - -.. code-block:: py - - fc.apply_table_filters(tbl_id=tbl_id_2mass_psc, filters='"j_m">15 and "j_m"<16 and "j_cmsig"<0.06') - -You can sort the table by a column in ascending (`ASC`) or descending (`DESC`) -order: - -.. code-block:: py - - fc.sort_table_column(tbl_id=tbl_id_2mass_psc, column_name='j_m', sort_direction='ASC') - -If a column has sorting, it can be removed by specifying `sort_direction=''`. diff --git a/examples/demo-3color.ipynb b/examples/demo-3color.ipynb index 70067a1..3f29918 100644 --- a/examples/demo-3color.ipynb +++ b/examples/demo-3color.ipynb @@ -1,5 +1,12 @@ { "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Show a 3 color image" + ] + }, { "cell_type": "code", "execution_count": 1, diff --git a/examples/demo-HiPS.ipynb b/examples/demo-HiPS.ipynb index e478c27..0f95fec 100644 --- a/examples/demo-HiPS.ipynb +++ b/examples/demo-HiPS.ipynb @@ -1,5 +1,12 @@ { "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Show HiPS Image" + ] + }, { "cell_type": "markdown", "metadata": {}, diff --git a/examples/demo-advanced-steps.ipynb b/examples/demo-advanced-steps.ipynb deleted file mode 100644 index ac27066..0000000 --- a/examples/demo-advanced-steps.ipynb +++ /dev/null @@ -1,369 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This notebook demonstrates basic usage of the firefly_client API fto render tables, images and charts in a grid layout style.\n", - "\n", - "Note that it may be necessary to wait for some cells (like those displaying an image) to complete before executing later cells." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "## Setup" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from firefly_client import FireflyClient\n", - "import astropy.utils.data\n", - "using_lab = True\n", - "url = 'http://127.0.0.1:8080/firefly'\n", - "#FireflyClient._debug= True" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fc = FireflyClient.make_lab_client() if using_lab else FireflyClient.make_client(url)\n", - "fc.change_triview_layout( FireflyClient.BIVIEW_T_IChCov)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Display tables, images, XY charts, and Histograms in Window/Grid like layout\n", - "\n", - "Each rendered unit on Firefly Slate Viewer is called a'cell'. To render a cell and its content, the cell location (row, column, width, height), element type and cell ID are needed. (row, column) and (width, height) represent the position and size of the cell in terms of the grid blocks on Firefly Slate Viewer. Element types include types of 'tables', images', 'xyPlots', 'tableImageMeta' and 'coverageImage'. " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We use astropy here for convenience, but firefly_client itself does not depend on astropy." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "## Display tables and catalogs\n", - "\n", - "\n", - "Add some tables into cell 'main' (default cell id for tables)\n", - "\n", - "\n", - "- add first table in cell 'main':\n", - "- 'main' is the cell id currently supported by Firefly for element type 'tables'\n", - "- this cell is shown at row = 0, col = 0 with width = 4, height = 2" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "\n", - "tbl_name = astropy.utils.data.download_file(\"http://web.ipac.caltech.edu/staff/roby/demo/moving/MOST_results-sample.tbl\",\n", - " timeout=120, cache=True)\n", - "meta_info = {'datasetInfoConverterId': 'SimpleMoving','positionCoordColumns': 'ra_obj;dec_obj;EQ_J2000',\n", - " 'datasource': 'image_url'}\n", - "fc.show_table(fc.upload_file(tbl_name), tbl_id='movingtbl', title='A moving object table', page_size=15, meta=meta_info)\n", - " " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "- add 2nd table in cell 'main' for chart and histogram " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "tbl_name = astropy.utils.data.download_file('http://web.ipac.caltech.edu/staff/roby/demo/WiseDemoTable.tbl',\n", - " timeout=120, cache=True)\n", - "fc.show_table(fc.upload_file(tbl_name), tbl_id='tbl_chart', title='table for xyplot and histogram', page_size=15)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "- add 3rd table in cell 'main'" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "tbl_name = astropy.utils.data.download_file(\"http://web.ipac.caltech.edu.s3-us-west-2.amazonaws.com/staff/roby/data-products-test/dp-test.tbl\", \n", - " timeout=120, cache=True)\n", - "meta_info = {'datasource': 'DP'}\n", - "fc.show_table(fc.upload_file(tbl_name), title='A table of simple images', page_size=15, meta=meta_info)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "- add 4th table in cell 'main'" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "tbl_name = astropy.utils.data.download_file(\"http://web.ipac.caltech.edu/staff/roby/demo/test-table-m31.tbl\", \n", - " timeout=120, cache=True)\n", - "\n", - "meta_info = {'positionCoordColumns': 'ra_obj;dec_obj;EQ_J2000', 'datasource': 'FITS'}\n", - "fc.show_table(fc.upload_file(tbl_name), title='A table of m31 images', page_size=15, meta=meta_info)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Add different types of image displays\n", - "\n", - "- show cell with id 'image-meta' continaing image from the active table containing datasource column in cell 'main'\n", - "- the cell is shown at row = 2, col = 0 with width = 4, height = 2 " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "- show cell 'wise-content' containing fits at row = 0, col = 4 with width = 2, height = 2" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "\n", - "image_name = astropy.utils.data.download_file('http://irsa.ipac.caltech.edu/ibe/data/wise/allsky/4band_p1bm_frm/6a/02206a' +\n", - " '/149/02206a149-w1-int-1b.fits?center=70,20&size=200pix')\n", - "fc.show_fits(file_on_server=fc.upload_file(image_name), title='WISE Cutout')\n", - " " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "- show 4 fits of moving objects in cell 'movingStff' at row = 2, col = 4 with width = 2, height = 2" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "\n", - "fc.show_fits(plot_id='m49025b_143_2', OverlayPosition='330.347003;-2.774482;EQ_J2000',\n", - " ZoomType='TO_WIDTH_HEIGHT', Title='49025b143-w2', plotGroupId='movingGroup',\n", - " URL='http://web.ipac.caltech.edu/staff/roby/demo/moving/49025b143-w2-int-1b.fits')\n", - "fc.show_fits(plot_id='m49273b_134_2', OverlayPosition='333.539702;-0.779310;EQ_J2000',\n", - " ZoomType='TO_WIDTH_HEIGHT', Title='49273b134-w2', plotGroupId='movingGroup',\n", - " URL='http://web.ipac.caltech.edu/staff/roby/demo/moving/49273b134-w2-int-1b.fits')\n", - "fc.show_fits(plot_id='m49277b_135_1', OverlayPosition='333.589054;-0.747251;EQ_J2000',\n", - " ZoomType='TO_WIDTH_HEIGHT', Title='49277b135-w1', plotGroupId='movingGroup',\n", - " URL='http://web.ipac.caltech.edu/staff/roby/demo/moving/49277b135-w1-int-1b.fits')\n", - "fc.show_fits(plot_id='m49289b_134_2', OverlayPosition='333.736578;-0.651222;EQ_J2000',\n", - " ZoomType='TO_WIDTH_HEIGHT', Title='49289b134-w2', plotGroupId='movingGroup',\n", - " URL='http://web.ipac.caltech.edu/staff/roby/demo/moving/49289b134-w2-int-1b.fits')\n", - " " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Add charts (xy plot and histogram)\n", - "\n", - "- show the cell 'chart-cell-xy' with xy plot related to the table with id 'tbl_chart' in cell 'main'\n", - "- this cell is shown at row = 4, col = 0 with width = 2, height = 3" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "\n", - "trace1 = {\n", - " 'tbl_id': 'tbl_chart',\n", - " 'x': \"tables::ra1\",\n", - " 'y': \"tables::dec1\",\n", - " 'mode': 'markers',\n", - " 'type': 'scatter', \n", - " 'marker': {'size': 4}}\n", - "trace_data=[trace1]\n", - " \n", - "layout_s = {'title': 'Coordinates', \n", - " 'xaxis': {'title': 'ra1 (deg)'}, 'yaxis': {'title': 'dec1 (deg)'}} \n", - "fc.show_chart( layout=layout_s, data=trace_data ) " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "- show the cell with histogram related to the table with id 'tbl_chart' in cell 'main', \n", - "- this cell is shown at row = 4, col = 2, with width = 2, height = 3 \n", - "- the cell id is automatically created by FireflyClient in case it is not specified externally. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "\n", - "histData = [\n", - " {\n", - " 'type': 'fireflyHistogram',\n", - " 'name': 'magzp', \n", - " 'marker': {'color': 'rgba(153, 51, 153, 0.8)'},\n", - " 'firefly': {\n", - " 'tbl_id': 'tbl_chart',\n", - " 'options': {\n", - " 'algorithm': 'fixedSizeBins',\n", - " 'fixedBinSizeSelection': 'numBins',\n", - " 'numBins': 30,\n", - " 'columnOrExpr': 'magzp'\n", - " }\n", - " },\n", - " }\n", - " ]\n", - "\n", - "layout_hist = {'title': 'Magnitude Zeropoints',\n", - " 'xaxis': {'title': 'magzp'}, 'yaxis': {'title': ''}} \n", - "result = fc.show_chart(layout=layout_hist, data=histData ) " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Add more images\n", - "\n", - "- show coverage image associated with the active table in cell 'main'\n", - "- ths cell is shown at row = 4, col = 4 with width = 2, height = 3" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "- show image in random location without passing cell location and cell id (i.e. without calling add_cell)\n", - "- the image is shown in the cell with id 'DEFAULT_FITS_VIEWER_ID' in default, \n", - "- and the cell is automatically located by Firefly" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "img_name = astropy.utils.data.download_file('http://web.ipac.caltech.edu/staff/roby/demo/wise-m51-band2.fits', \n", - " timeout=120, cache=True)\n", - "fc.show_fits(file_on_server=fc.upload_file(img_name))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fc.show_fits(plot_id='zzz', file_on_server=fc.upload_file(img_name))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "- show second image in random. it is shown in the same cell as the previous one " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fc.show_fits(plot_id='xxq', Service='TWOMASS', Title='2mass from service', ZoomType='LEVEL',\n", - " initZoomLevel=2, SurveyKey='asky', SurveyKeyBand='k',\n", - " WorldPt='10.68479;41.26906;EQ_J2000', SizeInDeg='.12')" - ] - } - ], - "metadata": { - "anaconda-cloud": {}, - "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.12" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/examples/demo-advanced-tables-images-upload.ipynb b/examples/demo-advanced-tables-images-upload.ipynb deleted file mode 100644 index 1825c59..0000000 --- a/examples/demo-advanced-tables-images-upload.ipynb +++ /dev/null @@ -1,294 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This notebook demonstrates basic usage of the firefly_client API for Firefly to render tables, images and charts in a grid layout style. \n", - "\n", - "Note that it may be necessary to wait for some cells (like those displaying an image) to complete before executing later cells." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "## Setup" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Imports for firefly_client" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from firefly_client import FireflyClient\n", - "import astropy.utils.data\n", - "using_lab = False\n", - "url = 'http://127.0.0.1:8080/firefly'\n", - "#FireflyClient._debug= True" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This example tentatively uses 127.0.0.1:8080 as the server " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fc = FireflyClient.make_lab_client() if using_lab else FireflyClient.make_client(url)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Dispaly tables, images, XY charts, and Histograms in Window/Grid like layout\n", - "\n", - "Each rendered unit on Firefly." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Please refer to firefly_slate_demo.py which contains functions to render cells with element tables, images, xy charts or histograms onto Firefly Slate Viewer by using firefly_client API. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import firefly_slate_demo as fs" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Display tables and catalogs" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Open a browser to the firefly server in a new tab. Only works when running the notebook locally." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Add some tables into cell 'main' (default grid viewer id for tables)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# first table in cell 'main' \n", - "fs.load_moving_table(0,0,4,2, fc)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# add table in cell 'main' for chart and histogram \n", - "fs.add_table_for_chart(fc)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# add table in cell 'main'\n", - "fs.add_simple_image_table(fc)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# add table in cell 'main'\n", - "fs.add_simple_m31_image_table(fc)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "f= '/Users/roby/fits/2mass-m31-2412rows.tbl'\n", - "file= fc.upload_file(f);" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fc.show_table(file)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fc.show_table('${cache-dir}/upload_2482826742890803252.fits')\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Add different types of image displays" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# show cell containing the image from the active table with datasource column in cell 'main'\n", - "fs.load_image_metadata(2, 0, 4, 2, fc, 'image-meta')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# show cell containing FITS in cell 'wise-cutout'\n", - "fs.load_image(0, 4, 2, 2, fc, 'wise-cutout') # load an image" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# show cell with 4 FITS of moving objects in cell 'movingStff'\n", - "fs.load_moving(2, 4, 2, 2, fc, 'movingStuff')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Add charts (xy plot and histogram)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# show xy plot in cell 'chart-cell-xy' associated with the table for chart in cell 'main'\n", - "fs.load_xy(4, 0, 2, 3, fc, 'chart-cell-xy')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# show histogram associated with the table for chart in cell 'main', the cell id is generated by firefly_client\n", - "fs.load_histogram(4, 2, 2, 3, fc)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Add more images" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# show cell containing coverage image associated with the active table in cell 'main'\n", - "fs.load_coverage_image(4, 4, 3, 3, fc, 'image-coverage')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# show cell containing image in ranmon location without passing the location and cell id\n", - "fs.load_first_image_in_random(fc)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# show second image in random location. This image is located in the same cell as the previous one \n", - "fs.load_second_image_in_random(fc)" - ] - } - ], - "metadata": { - "anaconda-cloud": {}, - "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.12" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/examples/demo-basic.ipynb b/examples/demo-basic.ipynb index 343fe79..0b27035 100644 --- a/examples/demo-basic.ipynb +++ b/examples/demo-basic.ipynb @@ -4,7 +4,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Intro" + "# Basic API Usage" ] }, { diff --git a/examples/basic-demo-tableload.ipynb b/examples/demo-multiple-table.ipynb similarity index 99% rename from examples/basic-demo-tableload.ipynb rename to examples/demo-multiple-table.ipynb index 0cb692c..0d4b9ff 100644 --- a/examples/basic-demo-tableload.ipynb +++ b/examples/demo-multiple-table.ipynb @@ -4,7 +4,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Intro" + "# Show a file containing multiple tables" ] }, { diff --git a/examples/demo-lsst-footprint.ipynb b/examples/demo-overlay-footprint.ipynb similarity index 99% rename from examples/demo-lsst-footprint.ipynb rename to examples/demo-overlay-footprint.ipynb index 2b63fab..afbf40d 100644 --- a/examples/demo-lsst-footprint.ipynb +++ b/examples/demo-overlay-footprint.ipynb @@ -4,7 +4,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Intro" + "# Overlay a footprint on image" ] }, { diff --git a/examples/demo-region.ipynb b/examples/demo-region.ipynb index 25d3679..25a4119 100644 --- a/examples/demo-region.ipynb +++ b/examples/demo-region.ipynb @@ -4,7 +4,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Intro" + "# Add region data to image" ] }, { diff --git a/examples/demo-show-image.ipynb b/examples/demo-show-image.ipynb deleted file mode 100644 index 9c42e65..0000000 --- a/examples/demo-show-image.ipynb +++ /dev/null @@ -1,56 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from firefly_client import FireflyClient\n", - "using_lab = False\n", - "url = 'http://127.0.0.1:8080/firefly'\n", - "#FireflyClient._debug= True" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fc = FireflyClient.make_lab_client() if using_lab else FireflyClient.make_client(url)\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fc.show_fits(URL='http://web.ipac.caltech.edu/staff/roby/demo/wise-m51-band2.fits')\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.10.12" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/examples/demo-simple-callback-in-jupyter.ipynb b/examples/demo-simple-callback-in-jupyter.ipynb new file mode 100644 index 0000000..1ae377c --- /dev/null +++ b/examples/demo-simple-callback-in-jupyter.ipynb @@ -0,0 +1,212 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Extensions and Callback" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'3.4.0'" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from firefly_client import __version__ as v\n", + "v" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "from firefly_client import FireflyClient\n", + "# FireflyClient._debug = True # enable for debug logging" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'http://127.0.0.1:8080/firefly/?__wsch=anNpbmdoYWwyMDI1LTEyLTIy'" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# pick some host\n", + "local_host = 'http://127.0.0.1:8080/firefly'\n", + "irsa = 'https://irsa.ipac.caltech.edu/irsaviewer'\n", + "fd = 'https://fireflydev.ipac.caltech.edu/firefly'\n", + "data_lsst_host = 'https://data.lsst.cloud/portal/app/'\n", + "host = local_host\n", + "\n", + "using_lab = False\n", + "fc = FireflyClient.make_lab_client() if using_lab else FireflyClient.make_client(host)\n", + "fc.get_firefly_url()" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fc.show_fits_image(file_input=\"http://web.ipac.caltech.edu.s3-us-west-2.amazonaws.com/staff/roby/demo/wise-00.fits\", plot_id='x2')" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True,\n", + " 'rv_string': '91,1.000000,91,1.000000,NaN,2.000000,44,25,600,120,0,NaN,1.000000'}" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fc.set_stretch('x1', stype='zscale')" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Extensions can be made but there is no web socket connections until a listener is added\n", + "\n", + "fc.add_extension(ext_type='POINT', title='Output Selected Point', shortcut_key='ctrl-p')\n", + "fc.add_extension(ext_type='LINE_SELECT', title='Output Selected line', shortcut_key='meta-b')\n", + "fc.add_extension(ext_type='AREA_SELECT', title='Output Selected Area', shortcut_key='a')" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'anNpbmdoYWwyMDI1LTEyLTIy': ['1ad', '1af', '1b0']}\n", + "app_data.wsConnUpdated\n", + "POINT\n", + " image point: 188.09900990093206;112.15841584156112\n", + " world point: 202.50072514443582;47.26622697944404;EQ_J2000\n", + "AREA_SELECT\n", + " image points: 173.7454031117884;130.18387553038747 to 210.1301272982422;95.1343705799178\n", + " world points: 202.50875172959275;47.27314011276992;EQ_J2000 to 202.4883768975841;47.25968005990187;EQ_J2000\n", + "LINE_SELECT\n", + " image points: 67.5954738330976;70.0990099009901 to 144.70438472418672;97.47100424328147\n", + " world points: 202.56865416307835;47.25038336191467;EQ_J2000 to 202.52519055730875;47.260701294534044;EQ_J2000\n" + ] + } + ], + "source": [ + "# A Web socket should not be made until this cell is executed\n", + "\n", + "def example_listener(ev):\n", + " if False: # set to True to see all events\n", + " print(ev)\n", + " if 'data' not in ev:\n", + " print('no data found in ev')\n", + " return\n", + " data = ev['data']\n", + " if 'payload' in data:\n", + " print(data['payload'])\n", + " if 'type' in data:\n", + " print(data['type'])\n", + " if data['type'] == 'POINT':\n", + " print(' image point: %s' % data['ipt'])\n", + " print(' world point: %s' % data['wpt'])\n", + " if data['type'] == 'LINE_SELECT' or data['type'] == 'AREA_SELECT':\n", + " print(' image points: %s to %s' % (data['ipt0'], data['ipt1']))\n", + " print(' world points: %s to %s' % (data['wpt0'], data['wpt1']))\n", + "\n", + "\n", + "fc.add_listener(example_listener)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "ffpy", + "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.12.5" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/test/test-simple-callback-response.py b/examples/demo-simple-callback-in-terminal.py similarity index 84% rename from test/test-simple-callback-response.py rename to examples/demo-simple-callback-in-terminal.py index 7ba67ab..ce6a9ac 100644 --- a/test/test-simple-callback-response.py +++ b/examples/demo-simple-callback-in-terminal.py @@ -1,21 +1,17 @@ +# Extensions and Callback via Terminal from firefly_client import FireflyClient import firefly_client -import time -lsst_demo_host = 'https://lsst-demo.ncsa.illinois.edu/firefly' local_host = 'http://127.0.0.1:8080/firefly' fd = 'https://fireflydev.ipac.caltech.edu/firefly' irsa_host = 'https://irsa.ipac.caltech.edu/irsaviewer' data_lsst_host = 'https://data.lsst.cloud/portal/app/' -# host = 'https://fireflydev.ipac.caltech.edu/firefly-multi-ticket/firefly/' host = local_host -channel1 = 'channel-test-1' v_str = firefly_client.__dict__['__version__'] if '__version__' in firefly_client.__dict__ else 'development' print('Version: %s' % v_str) -FireflyClient._debug = False +# FireflyClient._debug = True # enable for debug logging token = None -# fc = FireflyClient.make_client(host, channel_override=channel1, launch_browser=True, token=token) fc = FireflyClient.make_client(host, launch_browser=True, token=token) print(fc.get_firefly_url()) fc.show_fits(url="http://web.ipac.caltech.edu.s3-us-west-2.amazonaws.com/staff/roby/demo/wise-00.fits") @@ -52,4 +48,4 @@ def example_listener(ev): # fc.remove_listener(example_listener) # time.sleep(2) # fc.add_listener(example_listener) -fc.wait_for_events() \ No newline at end of file +fc.wait_for_events() # needed to keep the process alive to show callback output in terminal \ No newline at end of file diff --git a/examples/demo-advanced-table-images.ipynb b/examples/deprecated_grid_layout/demo-firefly-slate-module.ipynb similarity index 97% rename from examples/demo-advanced-table-images.ipynb rename to examples/deprecated_grid_layout/demo-firefly-slate-module.ipynb index dbcb27f..bc83d26 100644 --- a/examples/demo-advanced-table-images.ipynb +++ b/examples/deprecated_grid_layout/demo-firefly-slate-module.ipynb @@ -1,5 +1,12 @@ { "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Do grid layout rendering using firefly_slate_demo" + ] + }, { "cell_type": "markdown", "metadata": {}, diff --git a/examples/demo-advanced-all.ipynb b/examples/deprecated_grid_layout/demo-grid-basic.ipynb similarity index 99% rename from examples/demo-advanced-all.ipynb rename to examples/deprecated_grid_layout/demo-grid-basic.ipynb index 95991a2..6b5af15 100644 --- a/examples/demo-advanced-all.ipynb +++ b/examples/deprecated_grid_layout/demo-grid-basic.ipynb @@ -1,5 +1,12 @@ { "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Do grid layout rendering: basic" + ] + }, { "cell_type": "markdown", "metadata": {}, diff --git a/examples/firefly_slate_demo.py b/examples/deprecated_grid_layout/firefly_slate_demo.py similarity index 100% rename from examples/firefly_slate_demo.py rename to examples/deprecated_grid_layout/firefly_slate_demo.py diff --git a/test/test-5-instances-3-channels.py b/examples/development_tests/test-5-instances-3-channels.py similarity index 97% rename from test/test-5-instances-3-channels.py rename to examples/development_tests/test-5-instances-3-channels.py index 407d973..993cedd 100644 --- a/test/test-5-instances-3-channels.py +++ b/examples/development_tests/test-5-instances-3-channels.py @@ -21,7 +21,7 @@ def listener4(ev): print(ev) -lsst_demo_host = 'https://lsst-demo.ncsa.illinois.edu/firefly' +lsst_host = 'https://data.lsst.cloud/portal/app' local_host = 'http://127.0.0.1:8080/firefly' host = local_host channel1 = 'channel-test-1' diff --git a/examples/test-access.ipynb b/examples/development_tests/test-access.ipynb similarity index 100% rename from examples/test-access.ipynb rename to examples/development_tests/test-access.ipynb diff --git a/examples/development_tests/test-show_data.ipynb b/examples/development_tests/test-show_data.ipynb new file mode 100644 index 0000000..e07e16b --- /dev/null +++ b/examples/development_tests/test-show_data.ipynb @@ -0,0 +1,564 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "ed946441", + "metadata": {}, + "source": [ + "# Show Any Data File" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "7cce6ff0", + "metadata": {}, + "outputs": [], + "source": [ + "from firefly_client import FireflyClient\n", + "import os" + ] + }, + { + "cell_type": "markdown", + "id": "192cb924", + "metadata": {}, + "source": [ + "## Create a FireflyClient instance" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "55ec43a3", + "metadata": {}, + "outputs": [], + "source": [ + "using_lab = True\n", + "# url = 'https://irsadev.ipac.caltech.edu/irsaviewer'\n", + "# url = 'http://localhost:8080/firefly'" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "ede61748", + "metadata": {}, + "outputs": [], + "source": [ + "fc = FireflyClient.make_lab_client() if using_lab else FireflyClient.make_client(url)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "2d64edfa", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fc.reinit_viewer()" + ] + }, + { + "cell_type": "markdown", + "id": "f93c68b5", + "metadata": {}, + "source": [ + "## File inputs " + ] + }, + { + "cell_type": "markdown", + "id": "a63b7082", + "metadata": {}, + "source": [ + "### Local file" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "d5e77f7c", + "metadata": {}, + "outputs": [], + "source": [ + "# local_fpath = '/Users/jsinghal/dev/cm/__test_data/MF.20210502.18830.fits' # MEF\n", + "local_fpath = '/Users/jsinghal/dev/cm/__test_data/test_image.fits' # single ext FITS\n", + "# local_fpath = '/Users/jsinghal/dev/cm/__test_data/m31-2mass-2412-row.tbl' # table\n", + "# local_fpath = '/Users/jsinghal/Downloads/spherex_obscore.moc.fits' # MOC" + ] + }, + { + "cell_type": "markdown", + "id": "266c1776", + "metadata": {}, + "source": [ + "#### Default naming" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "0e3beac7", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fc.show_data(local_fpath) # image ✕, table ✓ " + ] + }, + { + "cell_type": "markdown", + "id": "647c4dcf", + "metadata": {}, + "source": [ + "#### Default naming with metadata preview" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "edf7ff0b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fc.show_data(local_fpath, preview_metadata=True) # image ✓, table ✓ " + ] + }, + { + "cell_type": "markdown", + "id": "612dbcb4", + "metadata": {}, + "source": [ + "#### Custom naming" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "9226455f", + "metadata": {}, + "outputs": [ + { + "ename": "TypeError", + "evalue": "FireflyClient.show_data() got an unexpected keyword argument 'displayName'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[8], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mfc\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mshow_data\u001b[49m\u001b[43m(\u001b[49m\u001b[43mlocal_fpath\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdisplayName\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43msome data\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m \u001b[38;5;66;03m# image ✕, table ✓ \u001b[39;00m\n", + "\u001b[0;31mTypeError\u001b[0m: FireflyClient.show_data() got an unexpected keyword argument 'displayName'" + ] + } + ], + "source": [ + "fc.show_data(local_fpath, displayName='some data') # image ✕, table ✓ " + ] + }, + { + "cell_type": "markdown", + "id": "86fd67fd", + "metadata": {}, + "source": [ + "#### Custom naming with metadata preview" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "7653dd95", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fc.show_data(local_fpath, displayName='some data', preview_metadata=True) # image ✓, table ✓ " + ] + }, + { + "cell_type": "markdown", + "id": "ea629b9a", + "metadata": {}, + "source": [ + "### URL" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "1d4540cd", + "metadata": {}, + "outputs": [], + "source": [ + "# FITS image (Single ext)\n", + "# remote_path = 'http://irsa.ipac.caltech.edu/ibe/data/wise/allsky/4band_p1bm_frm/6a/02206a/149/02206a149-w1-int-1b.fits'\n", + "\n", + "# Table query\n", + "remote_path = \"http://irsa.ipac.caltech.edu/TAP/sync?FORMAT=IPAC_TABLE&QUERY=SELECT+*+FROM+fp_psc+WHERE+CONTAINS(POINT('J2000',ra,dec),CIRCLE('J2000',70.0,20.0,0.1))=1\"\n", + "\n", + "# Table file\n", + "# remote_path = \"https://irsa.ipac.caltech.edu/ibe/data/wise/allsky/4band_p1bm_frm/6a/00766a/006/00766a006-fflag-1b.tbl\"" + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "id": "4c714ff0", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 55, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# file_payload = {'fileOnServer': 'dsfsf'}\n", + "# file_payload = {'url': 'asasds'}\n", + "file_payload = {}\n", + "\n", + "source = file_payload.get('fileOnServer') or file_payload.get('url')\n", + "source is None" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dc496c04", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dea58a4c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(True, '02206a149-w1-int-1b.some.fits')" + ] + }, + "execution_count": 45, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "url_points_to_file('http://irsa.ipac.caltech.edu/ibe/data/wise/allsky/4band_p1bm_frm/6a/02206a/149/02206a149-w1-int-1b.some.fits')" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "id": "564952df", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "os.path.isfile(remote_path.split('?', 1)[0])" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "id": "fb2781bd", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "\"sync?FORMAT=IPAC_TABLE&QUERY=SELECT+*+FROM+fp_psc+WHERE+CONTAINS(POINT('J2000',ra,dec),CIRCLE('J2000',70.0,20.0,0.1))=1\"" + ] + }, + "execution_count": 36, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "os.path.basename(remote_path)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "38d0beb7", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fc.show_data(remote_path) # image ✕, table file ✓, table query ✕" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ce99fa2d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fc.show_data(remote_path, preview_metadata=True) # image ✓, table file ✓, table query ✕" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "35eb6eb7", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fc.show_data(remote_path, displayName='remote data') # image ✕, table file ✓, table query ✕" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "5f1c2fbc", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fc.show_data(remote_path, displayName='remote data', preview_metadata=True) # image ✕, table file ✕, table query ✕" + ] + }, + { + "cell_type": "markdown", + "id": "12933161", + "metadata": {}, + "source": [ + "### File already on server\n", + "\n", + "Is already covered by local file" + ] + }, + { + "cell_type": "markdown", + "id": "c9749e31", + "metadata": {}, + "source": [ + "### File stream\n", + "\n", + "Is similar to file upload, so covered by local file?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "739d2ff8", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "WARNING: show_fits() is deprecated. Use show_fits_image() instead.\n" + ] + }, + { + "data": { + "text/plain": [ + "{'success': True}" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "size_in_arcsec = 30\n", + "ra = 150.00983\n", + "dec = 2.59783\n", + "target = '{};{};EQ_J2000'.format(ra, dec)\n", + "\n", + "service_params = dict(Title='COSMOS 3.6um',\n", + " Type='SERVICE',\n", + " Service='ATLAS',\n", + " SurveyKey='cosmos.cosmos_irac',\n", + " SurveyKeyBand='IRAC1',\n", + " WorldPt=target,\n", + " SizeInDeg=30/3600,\n", + " ColorTable=1,\n", + " ZoomType='ARCSEC_PER_SCREEN_PIX',\n", + " ZoomArcsecPerScreenPix=0.3,)\n", + "\n", + "fc.show_fits(plot_id='plot-id',\n", + " url='http://irsa.ipac.caltech.edu/ibe/data/wise/allsky/4band_p1bm_frm/6a/02206a/149/02206a149-w1-int-1b.fits',\n", + " file_on_server=fc.upload_file('/Users/jsinghal/dev/cm/__test_data/test_image.fits'),\n", + " # title='test image',\n", + " # **service_params,\n", + " )" + ] + }, + { + "cell_type": "markdown", + "id": "3b18d864", + "metadata": {}, + "source": [ + "### Issues identified\n", + "- displayName does not work for any URL input (it seems to work for default naming because that's what it assigns too)\n", + " - yet to debug, probably is getting ignored since no special handling like file_on_server case\n", + "- displayName does not work for immediate FITS image file on server but only when stopped at metadata preview step\n", + " - debugger tells me that the server sets the display name correctly in the response (that's why it shows up in metadata preview) so probably a client issue?" + ] + }, + { + "cell_type": "markdown", + "id": "8b7fc624", + "metadata": {}, + "source": [ + "## Test setting ID that can be controlled later" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "02bb34ef", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'success': True,\n", + " 'rv_string': '91,1.000000,91,1.000000,NaN,2.000000,44,25,600,120,0,NaN,1.000000'}" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fc.set_stretch('img1', 'zscale', 'linear')" + ] + }, + { + "cell_type": "markdown", + "id": "759471f7", + "metadata": {}, + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "ffpy", + "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.12.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/test/test-socket-not-added-until-listener.ipynb b/examples/development_tests/test-socket-not-added-until-listener.ipynb similarity index 93% rename from test/test-socket-not-added-until-listener.ipynb rename to examples/development_tests/test-socket-not-added-until-listener.ipynb index 3a18baf..3fff1ad 100644 --- a/test/test-socket-not-added-until-listener.ipynb +++ b/examples/development_tests/test-socket-not-added-until-listener.ipynb @@ -1,5 +1,12 @@ { "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test socket not added until listener is added" + ] + }, { "cell_type": "code", "execution_count": 1, @@ -12,12 +19,12 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# This test can be modified to make multiple firefly_clients to prove there is only 1 per channel\n", - "lsst_demo_host = 'https://lsst-demo.ncsa.illinois.edu/firefly'\n", + "lsst_host = 'https://data.lsst.cloud/portal/app'\n", "local_host = 'http://127.0.0.1:8080/firefly'\n", "host = local_host\n", "channel1 = 'channel-test-1'\n", @@ -29,7 +36,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -44,7 +51,6 @@ } ], "source": [ - "\n", "fc1_c1.show_fits(url=\"http://web.ipac.caltech.edu.s3-us-west-2.amazonaws.com/staff/roby/demo/wise-00.fits\")" ] }, diff --git a/examples/filetable.py b/examples/filetable.py index 32b031e..9ce2065 100755 --- a/examples/filetable.py +++ b/examples/filetable.py @@ -1,4 +1,5 @@ #!/usr/bin/env python +# Load files as a table of data products from argparse import ArgumentParser, HelpFormatter import csv @@ -57,7 +58,11 @@ def filetable_to_firefly( Dictionary of metadata items """ - filelist = glob(topdir + "/**/" + pattern, recursive=recursive) + if recursive: + file_lookup_path = os.path.join(topdir, "**", pattern) + else: + file_lookup_path = os.path.join(topdir, pattern) + filelist = glob(file_lookup_path, recursive=recursive) if sort: filelist = sorted(filelist) metadict = {"datasource": "path"} @@ -154,6 +159,10 @@ def main(): if printurl: input("Press Enter after you have opened the Firefly URL printed above...") + # TODO: figure out how to activate data products (meta) tab in Bi-View + # if "slate" not in html_file: + # fc.change_triview_layout(firefly_client.FireflyClient.BIVIEW_T_IChCov) + # fc.dispatch('layout.updateLayout', {'images':{'selectedTab':'meta'}}) r = fc.add_cell(0, 0, 1, 2, "tables", "main") fc.show_table(tbl_val, meta=metainfo) r = fc.add_cell(0, 1, 1, 2, "tableImageMeta", "image-meta") diff --git a/examples/multi-moc.py b/examples/multi-moc.py index b046570..9930957 100644 --- a/examples/multi-moc.py +++ b/examples/multi-moc.py @@ -1,3 +1,4 @@ +# Load multiple MOCs import astropy.utils.data from firefly_client import FireflyClient fc = FireflyClient.make_client('http://127.0.0.1:8080/firefly', channel_override='moc-channel') diff --git a/examples/plot-interface.ipynb b/examples/plot-interface.ipynb index 881a65b..1c91045 100644 --- a/examples/plot-interface.ipynb +++ b/examples/plot-interface.ipynb @@ -1,5 +1,12 @@ { "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Plot interface: `firefly_client.plot` module" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -153,7 +160,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Upload a table directly from disk." + "## Upload a table directly from disk." ] }, { @@ -235,7 +242,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Viewing a Python image object" + "## Viewing a Python image object" ] }, { @@ -301,7 +308,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Viewing a Numpy array" + "## Viewing a Numpy array" ] }, { @@ -363,7 +370,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Uploading a Python table object" + "## Uploading a Python table object" ] }, { diff --git a/examples/reference-guide.ipynb b/examples/reference-guide.ipynb index cb20160..c112c09 100644 --- a/examples/reference-guide.ipynb +++ b/examples/reference-guide.ipynb @@ -652,7 +652,7 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": null, "metadata": {}, "outputs": [ { diff --git a/firefly_client/firefly_client.py b/firefly_client/firefly_client.py index cfc3fcc..f8478ab 100644 --- a/firefly_client/firefly_client.py +++ b/firefly_client/firefly_client.py @@ -1006,7 +1006,8 @@ def show_table(self, file_input=None, file_on_server=None, url=None, is_catalog : `bool`, optional If the table file is a catalog (the default is *True*) or not. meta : `dict` - META_INFO for the table search request. + META_INFO for the table search request. The meta data allowed in + this dict are defined in https://github.com/Caltech-IPAC/firefly/blob/master/src/firefly/js/data/MetaConst.js target_search_info : `dict`, optional The information for target search, it may contain the following fields: @@ -1078,12 +1079,12 @@ def show_table(self, file_input=None, file_on_server=None, url=None, title = target_search_info.get('catalog', tbl_id) meta_info = {'title': title, 'tbl_id': tbl_id} + if not is_catalog: + meta_info.update({'CatalogOverlayType': False}) meta and meta_info.update(meta) tbl_req = {'startIdx': 0, 'pageSize': page_size, 'tbl_id': tbl_id} if has_file_input: - tbl_type = 'table' if not is_catalog else 'catalog' - # Handle different params of file input source = None if file_input: @@ -1096,7 +1097,7 @@ def show_table(self, file_input=None, file_on_server=None, url=None, warn('url is deprecated, use file_input parameter instead') source = url - tbl_req.update({'source': source, 'tblType': tbl_type, + tbl_req.update({'source': source, 'id': 'IpacTableFromSource'}) table_index and tbl_req.update({'tbl_index': table_index}) elif target_search_info: @@ -1235,7 +1236,7 @@ def show_xyplot(self, tbl_id, standalone=False, group_id=None, **chart_params): warning and r.update({'warning': warning}) return r - def show_histogram(self, tbl_id, group_id=PINNED_CHART_VIEWER_ID, **histogram_params): + def show_histogram(self, tbl_id, group_id=None, **histogram_params): """ Show a histogram @@ -1286,7 +1287,7 @@ def show_histogram(self, tbl_id, group_id=PINNED_CHART_VIEWER_ID, **histogram_pa warning and r.update({'warning': warning}) return r - def show_chart(self, group_id=PINNED_CHART_VIEWER_ID, **chart_params): + def show_chart(self, group_id=None, **chart_params): """ Show a plot.ly chart diff --git a/pyproject.toml b/pyproject.toml index a187fc3..57ddb0b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -45,8 +45,10 @@ Repository = "http://github.com/Caltech-IPAC/firefly_client.git" [project.optional-dependencies] docs = [ - "Sphinx~=7.1.0", + "Sphinx>=7.3,<8.0", "sphinx-automodapi", "pydata-sphinx-theme", - "myst-parser" + "myst-parser", + "nbsphinx", + "ipython" # for syntax highlighting in notebooks html output ] diff --git a/test/cb.ipynb b/test/cb.ipynb deleted file mode 100644 index 624af28..0000000 --- a/test/cb.ipynb +++ /dev/null @@ -1,107 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import firefly_client\n", - "from firefly_client import FireflyClient\n", - "firefly_client.__dict__['__version__'] " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "FireflyClient._debug = False\n", - "fc = FireflyClient.make_lab_client()\n", - "fc.get_firefly_url()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fc.show_fits(url=\"http://web.ipac.caltech.edu.s3-us-west-2.amazonaws.com/staff/roby/demo/wise-00.fits\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Extensions can be made but there is not web socket connections until a listener is added\n", - "\n", - "fc.add_extension(ext_type='LINE_SELECT', title='a line')\n", - "fc.add_extension(ext_type='AREA_SELECT', title='a area')\n", - "fc.add_extension(ext_type='POINT', title='a point')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# A Web socket should not be made until this cell is added\n", - "\n", - "def listener1(ev):\n", - " if False:\n", - " print(ev)\n", - " if 'data' not in ev:\n", - " print('no data found in ev')\n", - " return\n", - " data = ev['data']\n", - " if 'payload' in data:\n", - " print(data['payload'])\n", - " if 'type' in data:\n", - " print(data['type'])\n", - " if data['type'] == 'POINT':\n", - " print(' image point: %s' % data['ipt'])\n", - " print(' world point: %s' % data['wpt'])\n", - " if data['type'] == 'LINE_SELECT' or data['type'] == 'AREA_SELECT':\n", - " print(' image points: %s to %s' % (data['ipt0'], data['ipt1']))\n", - " print(' world points: %s to %s' % (data['wpt0'], data['wpt1']))\n", - "\n", - "\n", - " \n", - "fc.add_listener(listener1)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "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.6.9" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/test/fc-version.py b/test/fc-version.py deleted file mode 100644 index 1ca4971..0000000 --- a/test/fc-version.py +++ /dev/null @@ -1,4 +0,0 @@ -from firefly_client import FireflyClient -import firefly_client -v_str = firefly_client.__dict__['__version__'] if '__version__' in firefly_client.__dict__ else 'development' -print('Version: %s' % v_str) diff --git a/test/test-simple-callback-in-lab.ipynb b/test/test-simple-callback-in-lab.ipynb deleted file mode 100644 index fc87614..0000000 --- a/test/test-simple-callback-in-lab.ipynb +++ /dev/null @@ -1,146 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from firefly_client import FireflyClient" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# This test can be modified to make multiple firefly_clients to prove there is only 1 per channel\n", - "\n", - "# some host\n", - "lsst_demo_host = 'https://lsst-demo.ncsa.illinois.edu/firefly'\n", - "local_host = 'http://127.0.0.1:8080/firefly'\n", - "irsa = 'https://irsa.ipac.caltech.edu/irsaviewer'\n", - "fd = 'https://fireflydev.ipac.caltech.edu/firefly'\n", - "\n", - "#host = 'http://127.0.0.1:8080/suit'\n", - "host = local_host\n", - "channel1 = 'channel-test-1'\n", - "FireflyClient._debug = False\n", - "#fc = FireflyClient.make_client(host, channel_override=channel1, launch_browser=True)\n", - "fc = FireflyClient.make_lab_client(start_browser_tab=False, start_tab=True, verbose=True )\n", - "#fc = FireflyClient.make_lab_client(start_tab=False)\n", - "fc.get_firefly_url()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fc.get_firefly_url()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fc.show_fits(url=\"http://web.ipac.caltech.edu.s3-us-west-2.amazonaws.com/staff/roby/demo/wise-00.fits\", plot_id='x2')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fc.set_stretch('x1', stype='zscale')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Extensions can be made but there is not web socket connections until a listener is added\n", - "\n", - "fc.add_extension(ext_type='LINE_SELECT', title='a line', shortcut_key='meta-e')\n", - "fc.add_extension(ext_type='AREA_SELECT', title='a area')\n", - "fc.add_extension(ext_type='POINT', title='a point')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# A Web socket should not be made until this cell is added\n", - "\n", - "def listener1(ev):\n", - " if False:\n", - " print(ev)\n", - " if 'data' not in ev:\n", - " print('no data found in ev')\n", - " return\n", - " data = ev['data']\n", - " if 'payload' in data:\n", - " print(data['payload'])\n", - " if 'type' in data:\n", - " print(data['type'])\n", - " if data['type'] == 'POINT':\n", - " print(' image point: %s' % data['ipt'])\n", - " print(' world point: %s' % data['wpt'])\n", - " if data['type'] == 'LINE_SELECT' or data['type'] == 'AREA_SELECT':\n", - " print(' image points: %s to %s' % (data['ipt0'], data['ipt1']))\n", - " print(' world points: %s to %s' % (data['wpt0'], data['wpt1']))\n", - "\n", - "\n", - " \n", - "fc.add_listener(listener1)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from firefly_client import __version__ as v\n", - "v" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "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.6.9" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -}