diff --git a/examples/slate-demo-explicit.ipynb b/examples/slate-demo-explicit.ipynb index 8ce4d4e..4f2cf13 100644 --- a/examples/slate-demo-explicit.ipynb +++ b/examples/slate-demo-explicit.ipynb @@ -66,7 +66,7 @@ "cell_type": "code", "execution_count": null, "metadata": { - "collapsed": true + "collapsed": false }, "outputs": [], "source": [ @@ -81,7 +81,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Dispaly tables, images, XY charts, and Histograms in Window/Grid like layout\n", + "## 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'. " ] @@ -126,15 +126,34 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "\n", - "## Display tables and catalogs\n" + "re-init Firefly completely and clean the viewer. You may restart the viewer instead of launching a new browser to repeat rendering cells. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fc.reinit_viewer()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Add some tables into cell 'main' (default cell id for tables)" + "\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" ] }, { @@ -145,10 +164,6 @@ }, "outputs": [], "source": [ - "# 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\n", - "\n", "r = fc.add_cell(0, 0, 4, 2, 'tables', 'main')\n", "\n", "if r['success']:\n", @@ -160,6 +175,13 @@ " " ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- add 2nd table in cell 'main' for chart and histogram " + ] + }, { "cell_type": "code", "execution_count": null, @@ -168,11 +190,16 @@ }, "outputs": [], "source": [ - "# add 2nd table in cell 'main' for chart and histogram \n", - "\n", "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)\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'" ] }, { @@ -183,12 +210,17 @@ }, "outputs": [], "source": [ - "# add 3rd table in cell 'main'\n", - "\n", "tbl_name = astropy.utils.data.download_file(\"http://web.ipac.caltech.edu/staff/roby/demo/test-table4.tbl\", \n", " timeout=120, cache=True)\n", "meta_info = {'datasource': 'FITS'}\n", - "fc.show_table(fc.upload_file(tbl_name), title='A table of simple images', page_size=15, meta=meta_info)\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'" ] }, { @@ -199,20 +231,21 @@ }, "outputs": [], "source": [ - "# add 4th table in cell 'main'\n", - "\n", "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)\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" + "## 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 " ] }, { @@ -223,15 +256,19 @@ }, "outputs": [], "source": [ - "# 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 \n", - "\n", "r = fc.add_cell(2, 0, 4, 2, 'tableImageMeta', 'image-meta')\n", "if r['success']:\n", " fc.show_image_metadata(viewer_id=r['cell_id'])\n", " " ] }, + { + "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, @@ -240,8 +277,6 @@ }, "outputs": [], "source": [ - "# show cell 'wise-content' containing fits at row = 0, col = 4 with width = 2, height = 2\n", - "\n", "r = fc.add_cell(0, 4, 2, 2, 'images', 'wise-cutout')\n", "if r['success']:\n", " image_name = astropy.utils.data.download_file('http://irsa.ipac.caltech.edu/ibe/data/wise/allsky/4band_p1bm_frm/6a/02206a' +\n", @@ -250,6 +285,13 @@ " " ] }, + { + "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, @@ -258,8 +300,6 @@ }, "outputs": [], "source": [ - "# show 4 fits of moving objects in cell 'movingStff' at row = 2, col = 4 with width = 2, height = 2\n", - "\n", "r = fc.add_cell(2, 4, 2, 2, 'images', 'movingStuff')\n", "if r['success']:\n", " v_id = r['cell_id']\n", @@ -282,7 +322,10 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Add charts (xy plot and histogram)" + "## 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" ] }, { @@ -293,15 +336,21 @@ }, "outputs": [], "source": [ - "# 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\n", - "\n", "r = fc.add_cell(4, 0, 2, 3, 'xyPlots', 'chart-cell-xy')\n", "if r['success']:\n", " fc.show_xyplot('tbl_chart', group_id=r['cell_id'], xCol='ra1', yCol='dec1')\n", " " ] }, + { + "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, @@ -310,21 +359,19 @@ }, "outputs": [], "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. \n", - "\n", "r = fc.add_cell(4, 2, 2, 3, 'xyPlots')\n", "if r['success']:\n", - " fc.show_histogram('tbl_chart', group_id=r['cell_id'], col='modeint', xOptions='log')\n", - "\n" + " fc.show_histogram('tbl_chart', group_id=r['cell_id'], col='modeint', xOptions='log')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Add more images" + "## 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" ] }, { @@ -335,12 +382,18 @@ }, "outputs": [], "source": [ - "# show coverage image associated with the active table in cell 'main'\n", - "# ths cell is shown at row = 4, col = 4 with width = 3, height = 3\n", - "\n", - "r = fc.add_cell(4, 4, 3, 3, 'coverageImage', 'image-coverage')\n", + "r = fc.add_cell(4, 4, 2, 3, 'coverageImage', 'image-coverage')\n", "if r['success']:\n", - " fc.show_coverage(viewer_id=r['cell_id'])\n" + " fc.show_coverage(viewer_id=r['cell_id'])" + ] + }, + { + "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" ] }, { @@ -351,13 +404,16 @@ }, "outputs": [], "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\n", - "\n", "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))\n" + "fc.show_fits(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 " ] }, { @@ -368,11 +424,9 @@ }, "outputs": [], "source": [ - "# show second image in random. it is shown in the same cell as the previous one \n", - "\n", "fc.show_fits(plot_id='xxq', Service='TWOMASS', Title='2mass from service', ZoomType='LEVEL',\n", " initZoomLevel=2, SurveyKey='k', WorldPt='10.68479;41.26906;EQ_J2000',\n", - " RangeValues='92,-1,92,2,1,0,1,2,44,120', SizeInDeg='.12')\n" + " RangeValues='92,-1,92,2,1,0,1,2,44,120', SizeInDeg='.12')" ] }, { diff --git a/examples/slate-demo-explicit2.ipynb b/examples/slate-demo-explicit2.ipynb new file mode 100644 index 0000000..d84bbc8 --- /dev/null +++ b/examples/slate-demo-explicit2.ipynb @@ -0,0 +1,339 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This notebook demonstrates basic usage of the firefly_client API for Firefly Slate Viewer to render tables, images and charts in a grid layout style. This notebook shows the same layout content as what ffapi-api-slate2.html renders in Firefly. \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 Python 2/3 compatibility\n", + "Imports for firefly_client\n", + "\n", + "This example tentatively uses 127.0.0.1:8080 as the server\n", + "'slate.html' is a template made for grid view \n", + "\n", + "Open a browser to the firefly server in a new tab. Only works when running the notebook locally." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "from __future__ import print_function, division, absolute_import\n", + "from firefly_client import FireflyClient\n", + "import astropy.utils.data\n", + "\n", + "host='127.0.0.1:8080'\n", + "channel = 'myChannel8'\n", + "html = 'slate.html'\n", + "\n", + "fc = FireflyClient(host, channel=channel, html_file=html)\n", + "fc.launch_browser()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display tables, images, and charts 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' or 'coverageImage'. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Entering a target to search the catalog and image. The coordinates are in decimal hours and decimal degrees for EQ_J2000. The Galactic coordinates are in degrees" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "target = '10.68479;41.26906;EQ_J2000' #Galaxy M31\n", + "# other notable targets to try\n", + "#target = '148.88822;69.06529;EQ_J2000' #Galaxy M81\n", + "#target = '202.48417;47.23056;EQ_J2000' #Galaxy M51\n", + "#target = '136.9316774;+1.1195886;galactic' # W5 star-forming region" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "## Display tables, images and charts by using plotly\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- All plots are added in one notebook cell to better simulate an application\n", + "- Before re-executing this cell (perhaps with a different target selected), reload the Firefly browser window to clear out the existing plots." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fc.reinit_viewer()\n", + "\n", + "# Add 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 = 4 with width = 2, height = 2\n", + "\n", + "r = fc.add_cell(0, 4, 2, 2, 'tables', 'main')\n", + "\n", + "if r['success']:\n", + " \n", + " fc.show_table(tbl_id='wiseCatTbl', title='WISE catalog', \n", + " target_search_info={'catalogProject': 'WISE', 'catalog': 'allwise_p3as_psd',\n", + " 'position': target, 'SearchMethod': 'Cone', 'radius': 1200},\n", + " options={'removable': True, 'showUnits': False, 'showFilters': True})\n", + " \n", + " \n", + "# Add first chart - scatter (plot.ly direct plot)\n", + "# in cell 0, 0, 2, 2, \n", + "viewer_id = 'newChartContainer'\n", + "r = fc.add_cell(0, 0, 2, 2,'xyPlots', viewer_id)\n", + "\n", + "if r['success']:\n", + " trace1 = {\n", + " 'x': \"tables::wiseCatTbl,w1mpro-w2mpro\",\n", + " 'y': \"tables::wiseCatTbl,w2mpro-w3mpro\",\n", + " 'mode': 'markers',\n", + " 'type': 'scatter', \n", + " 'marker': {'size': 4}}\n", + " trace_data=[trace1]\n", + " ffData=[{'dataType': 'fireflyScatter'}]\n", + " layout_s = {'title': 'Color-Color', \n", + " 'xaxis': {'title': 'w1mpro-w2mpro (mag)'}, 'yaxis': {'title': 'w2mpro-w3mpro (mag)'}} \n", + " fc.show_plot(group_id=viewer_id, layout=layout_s, data=trace_data, fireflyData=ffData )\n", + " \n", + "# Add second chart - heatmap (plot.ly direct plot) \n", + "# in cell 2, 0, 2, 3\n", + "viewer_id = 'heatMapContainer'\n", + "r = fc.add_cell(2, 0, 2, 3,'xyPlots', viewer_id)\n", + "\n", + "if r['success']:\n", + " dataHM = [\n", + " {\n", + " 'type': 'heatmap',\n", + " 'name': 'w1 vs. w2',\n", + " 'x': \"tables::wiseCatTbl,w1mpro\",\n", + " 'y': \"tables::wiseCatTbl,w2mpro\",\n", + " 'colorscale': 'Blues'\n", + " },\n", + " {\n", + " 'type': 'heatmap',\n", + " 'name': 'w1 vs. w3',\n", + " 'x': \"tables::wiseCatTbl,w1mpro\",\n", + " 'y': \"tables::wiseCatTbl,w3mpro\",\n", + " 'colorscale': 'Reds',\n", + " 'reversescale': True\n", + " },\n", + " {\n", + " 'type': 'heatmap',\n", + " 'name': 'w1 vs. w4',\n", + " 'x': \"tables::wiseCatTbl,w1mpro\",\n", + " 'y': \"tables::wiseCatTbl,w4mpro\",\n", + " 'colorscale': 'Greens'\n", + " }]\n", + " \n", + " fireflyDataHM = [\n", + " {'dataType': 'fireflyHeatmap'},\n", + " {'dataType': 'fireflyHeatmap'},\n", + " {'dataType': 'fireflyHeatmap'}]\n", + " layout_hm = {'title': 'Magnitude-magnitude densities', \n", + " 'xaxis': {'title': 'w1 photometry (mag)'}, 'yaxis': {'title': ''}} \n", + " fireflyLayoutHM = {\n", + " 'xaxis': {'min': 5, 'max': 20},\n", + " 'yaxis': {'min': 4, 'max': 18}\n", + " };\n", + "\n", + " fc.show_plot(group_id=viewer_id, layout=layout_hm, data=dataHM, fireflyData=fireflyDataHM, \n", + " fireflyLayout=fireflyLayoutHM ) \n", + " \n", + "# Add third chart - histogram (plot.ly direct plot) \n", + "# in cell 2, 2, 2, 3\n", + "viewer_id = 'histContainer'\n", + "r = fc.add_cell(2, 2, 2, 3, 'xyPlots', viewer_id)\n", + "\n", + "if r['success']:\n", + " dataH = [\n", + " {'name': 'w1mpro', 'marker': {'color': 'rgba(153, 51, 153, 0.8)'}},\n", + " {'name': 'w2mpro', 'marker': {'color': 'rgba(102,153,0, 0.7)'}}\n", + " ]\n", + " \n", + " fireflyDataH = [\n", + " {\n", + " 'dataType': 'fireflyHistogram',\n", + " 'tbl_id': 'wiseCatTbl',\n", + " 'options': {\n", + " 'algorithm': 'fixedSizeBins',\n", + " 'fixedBinSizeSelection': 'numBins',\n", + " 'numBins': 30,\n", + " 'columnOrExpr': 'w1mpro'}\n", + " },\n", + " {\n", + " 'dataType': 'fireflyHistogram',\n", + " 'tbl_id': 'wiseCatTbl',\n", + " 'options': {\n", + " 'algorithm': 'fixedSizeBins',\n", + " 'fixedBinSizeSelection': 'numBins',\n", + " 'numBins': 40,\n", + " 'columnOrExpr': 'w2mpro' \n", + " }\n", + " }\n", + " ]\n", + " layout_hist = {'title': 'Photometry histogram',\n", + " 'xaxis': {'title': 'photometry (mag)'}, 'yaxis': {'title': ''}} \n", + " result = fc.show_plot(group_id=viewer_id, layout=layout_hist, data=dataH, fireflyData=fireflyDataH ) \n", + " \n", + "# Add fourth chart - 3D plot (plot.ly direct plot)\n", + "# in cell 2, 4, 2, 3, \n", + "viewer_id = '3dChartContainer'\n", + "r = fc.add_cell(2, 4, 2, 3, 'xyPlots', viewer_id)\n", + "\n", + "if r['success']:\n", + " data3d = [\n", + " {\n", + " 'type': 'scatter3d',\n", + " 'name': 'w1-w2-w3',\n", + " 'x': \"tables::wiseCatTbl,w1mpro\",\n", + " 'y': \"tables::wiseCatTbl,w2mpro\",\n", + " 'z': \"tables::wiseCatTbl,w3mpro\",\n", + " 'mode' : 'markers',\n", + " 'marker' : {\n", + " 'size': 3,\n", + " 'line': {\n", + " 'color': 'rgb(127, 127, 127, 0.14)',\n", + " 'width': 1}\n", + " },\n", + " 'hoverinfo': 'x+y+z'\n", + " }]\n", + "\n", + " fsize = {'size': 11}\n", + " layout3d = {\n", + " 'title': 'Photometry in band 1, 2, 3',\n", + " 'scene':{\n", + " 'xaxis': {\n", + " 'title': 'w1 (mag)',\n", + " 'titlefont': fsize\n", + " },\n", + " 'yaxis': {\n", + " 'title': 'w2 (mag)',\n", + " 'titlefont': fsize\n", + " },\n", + " 'zaxis': {\n", + " 'title': 'w3 (mag)',\n", + " 'titlefont': fsize\n", + " }\n", + " }\n", + " }\n", + " \n", + " fc.show_plot(group_id=viewer_id, is_3d=True, layout=layout3d, data=data3d ) \n", + " \n", + "# Add a three color fits\n", + "# in cell 0, 2, 2, 2\n", + "viewer_id = '3C'\n", + "r = fc.add_cell(0, 2, 2, 2, 'images', viewer_id)\n", + "rv = '92,-2,92,8,NaN,2,44,25,600,120'\n", + "if r['success']:\n", + " threeC= [\n", + " {\n", + " 'Type' : 'SERVICE',\n", + " 'Service' : 'WISE',\n", + " 'Title' : '3 color',\n", + " 'SurveyKey' : 'Atlas',\n", + " 'SurveyKeyBand': '1',\n", + " 'WorldPt' : target,\n", + " 'RangeValues': rv,\n", + " 'SizeInDeg' : '1'\n", + " },\n", + " {\n", + " 'Type' : 'SERVICE',\n", + " 'Service' : 'WISE',\n", + " 'Title' : '3 color',\n", + " 'SurveyKey' : 'Atlas',\n", + " 'SurveyKeyBand': '2',\n", + " 'WorldPt' : target,\n", + " 'RangeValues': rv,\n", + " 'SizeInDeg' : '1'\n", + " },\n", + " {\n", + " 'Type' : 'SERVICE',\n", + " 'Service' : 'WISE',\n", + " 'Title' : '3 color',\n", + " 'SurveyKey' : 'Atlas',\n", + " 'SurveyKeyBand': '3',\n", + " 'WorldPt' : target,\n", + " 'RangeValues': rv,\n", + " 'SizeInDeg' : '1'\n", + " }]\n", + " \n", + " fc.show_fits_3color(threeC, viewer_id=viewer_id)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "anaconda-cloud": {}, + "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.1" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/firefly_client/firefly_client.py b/firefly_client/firefly_client.py index 2e13219..05d2683 100644 --- a/firefly_client/firefly_client.py +++ b/firefly_client/firefly_client.py @@ -67,6 +67,7 @@ class FireflyClient(WebSocketClient): 'FetchTblData': 'table.fetch', 'ShowTable': 'table.search', 'ShowXYPlot': 'charts.data/chartAdd', + 'ShowPlot': 'charts.data/chartAdd', 'ZoomImage': 'ImagePlotCntlr.ZoomImage', 'PanImage': 'ImagePlotCntlr.recenter', 'StretchImage': 'ImagePlotCntlr.StretchChange', @@ -78,12 +79,13 @@ class FireflyClient(WebSocketClient): 'DeleteOverlayMask': 'ImagePlotCntlr.deleteOverlayPlot', 'AddCell': 'layout.addCell', 'ShowCoverage': 'layout.enableSpecialViewer', - 'ShowImageMetaData': 'layout.enableSpecialViewer'} + 'ShowImageMetaData': 'layout.enableSpecialViewer', + 'ReinitViewer': 'app_data.reinitApp'} """Definition of Firefly action (`dict`).""" # id for table, region layer, extension _item_id = {'Table': 0, 'RegionLayer': 0, 'Extension': 0, 'MaskLayer': 0, 'XYPlot': 0, - 'Cell': 0, 'Histogram': 0} + 'Cell': 0, 'Histogram': 0, 'Plotly': 0} # urls: # launch browser: http:////;wsch= or (mode == 'full') @@ -113,7 +115,6 @@ def __init__(self, host=_my_localhost, channel=None, basedir='firefly', html_fil self.channel = channel self.session = requests.Session() self.headers = {'FF_FF-channel': self.channel} - # print 'websocket url:%s' % url self.connect() def _handle_event(self, ev): @@ -261,7 +262,7 @@ def get_firefly_url(self, mode='minimal', channel=None): if not channel: channel = self.channel - url = 'http://%s/%s%s?id=Loader&channelID='%(self.this_host, self._basedir, self.html_file) + url = 'http://%s/%s%s?id=Loader&channelID=' % (self.this_host, self._basedir, self.html_file) if mode.lower() == "full": url = self.url_bw @@ -394,7 +395,7 @@ def upload_data(self, stream, data_type): url = 'http://%s/%s/sticky/CmdSrv?cmd=upload&preload=' % (self.this_host, self._basedir) url += 'true&type=FITS' if data_type.upper() == 'FITS' else 'false&type=UNKNOWN' - stream.seek(0,0) + stream.seek(0, 0) data_pack = {'data': stream} result = self.session.post(url, files=data_pack, headers=self.headers) if result.status_code == 200: @@ -452,6 +453,7 @@ def dispatch_remote_action(self, channel, action_type, payload): action = {'type': action_type, 'payload': payload} url = self.url_root + '?channelID=' + channel + '&cmd=pushAction&action=' url += json.dumps(action) + return self._send_url_as_get(url) def dispatch_remote_action_by_post(self, channel, action_type, payload): @@ -527,10 +529,25 @@ def add_cell(self, row, col, width, height, element_type, cell_id=None): 'type': element_type, 'cellId': cell_id} - r = self.dispatch_remote_action(self.channel, FireflyClient.ACTION_DICT['AddCell'], payload) + r = self.dispatch_remote_action_by_post(self.channel, FireflyClient.ACTION_DICT['AddCell'], payload) r.update({'cell_id': cell_id}) return r + def reinit_viewer(self): + """ + re-initialize the viewer + + Returns + ------- + out : `dict` + Status of the request, like {'success': True}. + """ + + payload = {} + + r = self.dispatch_remote_action_by_post(self.channel, FireflyClient.ACTION_DICT['ReinitViewer'], payload) + return r + def show_fits(self, file_on_server=None, plot_id=None, viewer_id=None, **additional_params): """ Show a FITS image. @@ -541,14 +558,14 @@ def show_fits(self, file_on_server=None, plot_id=None, viewer_id=None, **additio The is the name of the file on the server. If you use `upload_file()`, then it is the return value of the method. Otherwise it is a file that Firefly has direct access to. - plot_id : `str` or `list` of `str`, optional + plot_id : `str`, optional The ID you assign to the image plot. This is necessary to further control the plot. viewer_id : `str`, optional The ID you assign to the viewer (or cell) used to contain the image plot. If grid view is used for display, the viewer id is the cell id of the cell which contains the image plot. \*\*additional_params : optional keyword arguments - Any valid fits viewer plotting parameters, please see the details in `fits plotting parameters`_. + Any valid fits viewer plotting parameter, please see the details in `fits plotting parameters`_. .. _fits plotting parameters: https://github.com/Caltech-IPAC/firefly/blob/dev/docs/fits-plotting-parameters.md @@ -563,6 +580,9 @@ def show_fits(self, file_on_server=None, plot_id=None, viewer_id=None, **additio ------- out : `dict` Status of the request, like {'success': True}. + + .. note:: Either `file_on_server` or the target information set by `addition_parameters` + is used for fits search. """ wp_request = {'plotGroupId': 'groupFromPython', @@ -581,10 +601,46 @@ def show_fits(self, file_on_server=None, plot_id=None, viewer_id=None, **additio if additional_params: payload['wpRequest'].update(additional_params) - return self.dispatch_remote_action(self.channel, FireflyClient.ACTION_DICT['ShowFits'], payload) + return self.dispatch_remote_action_by_post(self.channel, FireflyClient.ACTION_DICT['ShowFits'], payload) - def show_table(self, file_on_server, tbl_id=None, title=None, page_size=100, is_catalog=True, - meta=None): + def show_fits_3color(self, three_color_params, plot_id=None, viewer_id=None): + """ + Show a FITS image by giving the three color requirement + + Parameters + ---------- + three_color_params : `list` of `dict` or `dict` + A list or objects contains fits viewer plotting parameters for either all bands or one single band. + For valid fits viewer plotting parameter, please see the details in `fits plotting parameters`_ or + the description of ****additional_params** in function `show_fits`. + + plot_id : `str`, optional + The ID you assign to the image plot. This is necessary to further control the plot. + viewer_id : `str`, optional + The ID you assign to the viewer (or cell) used to contain the image plot. If grid view is used for + display, the viewer id is the cell id of the cell which contains the image plot. + + Returns + ------- + out : `dict` + Status of the request, like {'success': True}. + """ + + three_color = three_color_params if type(three_color_params).__name__ == 'list' else [three_color_params] + for item in three_color: + item.update({'GroupLocked': item.get('GroupLocked') if 'GroupLocked' in item else False}) + item.update({'plotGroupId': item.get('plotGroupId') if 'plotGroupId' in item else 'groupFromPython'}) + item.update({'Title': item.get('Title') if 'Title' in item else '3 Color'}) + if 'plotId' not in item and plot_id: + item.update({'plotId': plot_id}) + + payload = {'wpRequest': three_color, 'threeColor': True, 'useContextModifications': True} + payload.update({'viewerId': viewer_id if viewer_id else 'DEFAULT_FITS_VIEWER_ID'}) + + return self.dispatch_remote_action_by_post(self.channel, FireflyClient.ACTION_DICT['ShowFits'], payload) + + def show_table(self, file_on_server=None, tbl_id=None, title=None, page_size=100, is_catalog=True, + meta=None, target_search_info=None, options=None): """ Show a table. @@ -604,29 +660,77 @@ def show_table(self, file_on_server, tbl_id=None, title=None, page_size=100, is_ If the table file is a catalog (the default is *True*) or not. meta : `dict` META_INFO for the table search request. + target_search_info : `dict`, optional + The information for target search, it may contain the following fields: + + **catalogProject** : `str` + Catalog project, such as *'WISE'*. + **catalog** : `str` + Table to be searched, such as *'allwise_p3as_psd'*. + **use** : `str` + Usage of the table search, such as *'catalog_overlay'*. + **position** : `str` + Target position, such as *'10.68479;41.26906;EQ_J2000'*. + **SearchMethod** : {'Cone', 'Eliptical', 'Box', 'Polygon', 'Table', 'AllSky'} + Target search method. + **radius** : `float` + The radius for *'Cone'* or the semi-major axis for *'Eliptical'* search in terms of unit *arcsec*. + **posang** : `float` + Position angle for *'Elipitical'* search in terms of unit *arcsec*. + **ratio** : `float` + Axial ratio for *'Elipital'* search. + **size** : `float` + Side size for *'Box'* search in terms of unit *arcsec*. + **polygon** : `str` + ra/dec of polygon corners, such as *'ra1, dec1, ra2, dec2,... raN, decN'*. + **filename** : `str` + The name of file on server on multi-objects for *'Table'* search. + + options : `dict`, optional + Containing parameters for table display, such as, + + **removable** : `bool` + if table is removable. + **showUnits** : `bool` + if table shows units for the columns. + **showFilters** : `bool` + if table shows filter button Returns ------- out : `dict` Status of the request, like {'success': True}. + + .. note:: `file_on_server` and `target_search_info` are exclusively required. """ if not tbl_id: tbl_id = FireflyClient._gen_item_id('Table') if not title: - title = tbl_id + title = tbl_id if file_on_server else target_search_info.get('catalog', tbl_id) meta_info = {'title': title, 'tbl_id': tbl_id} if meta: meta_info.update(meta) - tbl_type = 'table' if not is_catalog else 'catalog' - tbl_req = {'startIdx': 0, 'pageSize': page_size, 'source': file_on_server, 'tblType': tbl_type, - 'id': 'IpacTableFromSource', 'tbl_id': tbl_id} + tbl_req = {'startIdx': 0, 'pageSize': page_size, 'tbl_id': tbl_id} + if file_on_server: + tbl_type = 'table' if not is_catalog else 'catalog' + tbl_req.update({'source': file_on_server, 'tblType': tbl_type, + 'id': 'IpacTableFromSource'}) + elif target_search_info: + target_search_info.update( + {'use': target_search_info.get('use') if 'use' in target_search_info else 'catalog_overlay'}) + tbl_req.update({'id': 'GatorQuery', 'UserTargetWorldPt': target_search_info.get('position')}) + target_search_info.pop('position', None) + tbl_req.update(target_search_info) + tbl_req.update({'META_INFO': meta_info}) + if options: + tbl_req.update({'options': options}) payload = {'request': tbl_req} - return self.dispatch_remote_action(self.channel, FireflyClient.ACTION_DICT['ShowTable'], payload) + return self.dispatch_remote_action_by_post(self.channel, FireflyClient.ACTION_DICT['ShowTable'], payload) def fetch_table(self, file_on_server, tbl_id=None, page_size=1): """ @@ -656,7 +760,7 @@ def fetch_table(self, file_on_server, tbl_id=None, page_size=1): meta_info = {'title': tbl_id, 'tbl_id': tbl_id} tbl_req.update({'META_INFO': meta_info}) payload = {'request': tbl_req, 'hlRowIdx': 0} - return self.dispatch_remote_action(self.channel, FireflyClient.ACTION_DICT['FetchTblData'], payload) + return self.dispatch_remote_action_by_post(self.channel, FireflyClient.ACTION_DICT['FetchTblData'], payload) def show_xyplot(self, tbl_id, standalone=False, group_id=None, **chart_params): """ @@ -736,10 +840,11 @@ def show_xyplot(self, tbl_id, standalone=False, group_id=None, **chart_params): else: group_id = tbl_id - payload = {'chartId': cid, 'chartType': 'scatter', 'groupId': group_id, + payload = {'chartId': cid, 'chartType': 'scatter', + 'groupId': group_id, 'viewerId': group_id, 'chartDataElements': chart_data_elements} - return self.dispatch_remote_action(self.channel, FireflyClient.ACTION_DICT['ShowXYPlot'], payload) + return self.dispatch_remote_action_by_post(self.channel, FireflyClient.ACTION_DICT['ShowXYPlot'], payload) def show_histogram(self, tbl_id, group_id=None, **histogram_params): """ @@ -805,9 +910,55 @@ def show_histogram(self, tbl_id, group_id=None, **histogram_params): cid = FireflyClient._gen_item_id('Histogram') payload = {'chartId': cid, 'chartType': 'histogram', 'groupId': group_id, + 'viewerId': group_id, 'chartDataElements': [chart_data_elements]} - return self.dispatch_remote_action(self.channel, FireflyClient.ACTION_DICT['ShowXYPlot'], payload) + return self.dispatch_remote_action_by_post(self.channel, FireflyClient.ACTION_DICT['ShowXYPlot'], payload) + + def show_plot(self, group_id=None, **chart_params): + """ + Show a plot by using plot.ly charts + + Parameters + ---------- + group_id : `str`, optional + Group ID of the chart group where the chart belongs to. If grid view is used, group id is + the cell id of the cell which contains the chart. + \*\*chart_params : optional keyword arguments + Parameters for the chart. The options are shown as below: + + **chartId**: `str`, optional + The chart ID. + **data**: `list` of `dict`, optional + An array of data for all traces of the plot.ly chart. + **fireflyData**: `list` of `dict`, optional + This array contains the information for creating a table and the table has data for chart rendering. + **layout**: 'dict', optional + The layout for plot.ly layout. + **fireflyLayout** : `dict`, optional + The layout contains information to be processed by Firefly. + + Returns + ------- + out : `dict` + Status of the request, like {'success': True}. + + """ + + if not group_id: + group_id = 'default' + chart_id = chart_params.get('chartId') if 'chartId' in chart_params else FireflyClient._gen_item_id('Plotly') + payload = {'chartId': chart_id, + 'groupId': group_id, + 'viewerId': group_id, + 'chartType': 'plot.ly', + 'closable': True} + + for item in ['data', 'fireflyData', 'layout', 'fireflyLayout']: + if item in chart_params: + payload.update({item: chart_params.get(item)}) + + return self.dispatch_remote_action_by_post(self.channel, FireflyClient.ACTION_DICT['ShowPlot'], payload) def show_coverage(self, viewer_id=None, table_group='main'): """ @@ -831,7 +982,7 @@ def show_coverage(self, viewer_id=None, table_group='main'): payload = {'viewerType': FireflyClient.LO_VIEW_DICT[view_type], 'cellId': cid} - return self.dispatch_remote_action(self.channel, FireflyClient.ACTION_DICT['ShowCoverage'], payload) + return self.dispatch_remote_action_by_post(self.channel, FireflyClient.ACTION_DICT['ShowCoverage'], payload) def show_image_metadata(self, viewer_id=None, table_group='main'): """ @@ -855,7 +1006,8 @@ def show_image_metadata(self, viewer_id=None, table_group='main'): payload = {'viewerType': FireflyClient.LO_VIEW_DICT[view_type], 'cellId': cid} - return self.dispatch_remote_action(self.channel, FireflyClient.ACTION_DICT['ShowImageMetaData'], payload) + return self.dispatch_remote_action_by_post(self.channel, FireflyClient.ACTION_DICT['ShowImageMetaData'], + payload) def add_extension(self, ext_type, plot_id=None, title='', tool_tip='', extension_id=None, image_src=None): @@ -888,8 +1040,6 @@ def add_extension(self, ext_type, plot_id=None, title='', tool_tip='', .. note:: If `image_src` is not specified, then no extension is added. """ - #if ext_type not in FireflyClient.EXTENSION_TYPE: - # ext_type = 'NONE' if not extension_id: extension_id = FireflyClient._gen_item_id('Extension') @@ -926,7 +1076,7 @@ def set_zoom(self, plot_id, factor=1.0): def zoom_oneplot(one_plot_id, f): payload = {'plotId': one_plot_id, 'userZoomType': 'LEVEL', 'level': f, 'actionScope': 'SINGLE'} - return self.dispatch_remote_action(self.channel, FireflyClient.ACTION_DICT['ZoomImage'], payload) + return self.dispatch_remote_action_by_post(self.channel, FireflyClient.ACTION_DICT['ZoomImage'], payload) if isinstance(plot_id, tuple) or isinstance(plot_id, list): return [zoom_oneplot(x, factor) for x in plot_id] @@ -961,7 +1111,7 @@ def set_pan(self, plot_id, x=None, y=None, coord='image'): else: payload.update({'centerPt': {'x': x, 'y': y, 'type': 'J2000'}}) - return self.dispatch_remote_action(self.channel, FireflyClient.ACTION_DICT['PanImage'], payload) + return self.dispatch_remote_action_by_post(self.channel, FireflyClient.ACTION_DICT['PanImage'], payload) def set_stretch(self, plot_id, stype=None, algorithm=None, **additional_params): """ @@ -1012,7 +1162,7 @@ def set_stretch(self, plot_id, stype=None, algorithm=None, **additional_params): st_data = [{'band': 'NO_BAND', 'rv': serialized_rv, 'bandVisible': True}] payload = {'stretchData': st_data, 'plotId': plot_id} - return self.dispatch_remote_action(self.channel, FireflyClient.ACTION_DICT['StretchImage'], payload) + return self.dispatch_remote_action_by_post(self.channel, FireflyClient.ACTION_DICT['StretchImage'], payload) # ----------------------------------------------------------------- # Region Stuff @@ -1089,8 +1239,8 @@ def delete_region_layer(self, region_layer_id, plot_id=None): if plot_id: payload.update({'plotId': plot_id}) - return self.dispatch_remote_action(self.channel, - FireflyClient.ACTION_DICT['DeleteRegionLayer'], payload) + return self.dispatch_remote_action_by_post(self.channel, + FireflyClient.ACTION_DICT['DeleteRegionLayer'], payload) def add_region_data(self, region_data, region_layer_id, title=None, plot_id=None): """ @@ -1190,8 +1340,8 @@ def add_mask(self, bit_number, image_number, plot_id, mask_id=None, color=None, if file_on_server: payload.update({'fileKey': file_on_server}) - return self.dispatch_remote_action(self.channel, - FireflyClient.ACTION_DICT['PlotMask'], payload) + return self.dispatch_remote_action_by_post(self.channel, + FireflyClient.ACTION_DICT['PlotMask'], payload) def remove_mask(self, plot_id, mask_id): """ @@ -1211,8 +1361,8 @@ def remove_mask(self, plot_id, mask_id): """ payload = {'plotId': plot_id, 'imageOverlayId': mask_id} - return self.dispatch_remote_action(self.channel, - FireflyClient.ACTION_DICT['DeleteOverlayMask'], payload) + return self.dispatch_remote_action_by_post(self.channel, + FireflyClient.ACTION_DICT['DeleteOverlayMask'], payload) # ----------------------------------------------------------------- # Range Values