Skip to content

Commit

Permalink
Merge pull request #39 from eteq/interactive
Browse files Browse the repository at this point in the history
Interactive Notebook stuff
  • Loading branch information
eteq committed Nov 12, 2015
2 parents b660b36 + ae1a3c4 commit bcd1b0b
Show file tree
Hide file tree
Showing 2 changed files with 307 additions and 0 deletions.
195 changes: 195 additions & 0 deletions stginga/examples/ginga_nbinteract.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"from __future__ import print_function\n",
"\n",
"import logging\n",
"import webbrowser\n",
"from cStringIO import StringIO\n",
"\n",
"import numpy as np\n",
"\n",
"from astropy.io import fits\n",
"from stginga import nbinteract\n",
"\n",
"from IPython.html.widgets import interact\n",
"from IPython import display"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"server = nbinteract.GingaServer()\n",
"server.start()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"server.get_viewer_urls()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"display.IFrame(server.get_viewer_urls()['Main Viewer'], 625, 625)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The next cell will open a new window with the same view as above"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"webbrowser.open(server.get_viewer_urls()['Main Viewer'])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Note that this next cell may take some time to download the first time"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"f = fits.open('https://archive.stsci.edu/pub/hlsp/angst/acs/hlsp_angst_hst_acs-wfc_10210-ugc8760_f814w_v1_ref.fits')\n",
"server.load_fits(f)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"You'll need to download have some acs image for this dataset to run the next cell. A convenient one (to match the above) might be: https://archive.stsci.edu/cgi-bin/mastpreview?mission=hst&dataid=J8YY05021"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"fi = fits.open('j8yy05kbq_drc.fits')\n",
"\n",
"@interact(hdunum=(1,3))\n",
"def switch_hdu(hdunum=1):\n",
" server.load_fits(fi[hdunum])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"v = server.viewers['Main Viewer']\n",
"aim = v.fitsimage.get_image()\n",
"\n",
"for r in v.canvas.get_objects()[1:]:\n",
" corners = np.array(r.get_points())\n",
" xmin, xmax = np.min(corners[:, 0]), np.max(corners[:, 0])\n",
" ymin, ymax = np.min(corners[:, 1]), np.max(corners[:, 1])\n",
" data_square = aim.get_data()[ymin:ymax, xmin:xmax]\n",
" flux = np.sum(data_square)\n",
" print('Rectangle centered on', r.get_center_pt(), 'has flux', flux)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"# clear all rectangles\n",
"v = server.viewers['Main Viewer']\n",
"v.canvas.deleteObjects(v.canvas.get_objects()[1:])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Debug code "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"log = logging.Logger('nbinteract sio logger')\n",
"logsio = StringIO()\n",
"#log.addHandler(logging.StreamHandler(stream=logsio))\n",
"log.addHandler(logging.NullHandler())"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 2",
"language": "python",
"name": "python2"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.10"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
112 changes: 112 additions & 0 deletions stginga/nbinteract.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
"""Wrapper script to run Ginga optimized for STScI data."""
from __future__ import (absolute_import, division, print_function,
unicode_literals)

import os

from astropy.io import fits
from astropy.utils import isiterable

import tornado.httpserver
import tornado.web
import tornado.ioloop

from ginga.misc import log, Task
from ginga.AstroImage import AstroImage
from ginga.web.pgw import Widgets, js, PgHelp, ipg

__all__ = ['start_server', 'GingaServer', '']


class GingaServer(object):
def __init__(self, host='localhost', port=9909, logger=None, numthreads=5):
self.tornado_app = None
self.viewers = {}
self.host = host
self.port = port

if logger is None:
logger = log.get_logger("nbinteract_server", null=True)
self.logger = logger

self.thread_pool = Task.ThreadPool(numthreads, logger)
self.app = Widgets.Application(logger=self.logger, base_url=self.base_url)

@property
def base_url(self):
return "http://{0}:{1}/app".format(self.host, self.port)

def __repr__(self):
repr_str = object.__repr__(self)
if self.url:
urlstr = 'not started'
else:
urlstr = 'URL={0}'.format(self.url)
return repr_str.replace('object at', urlstr + ' at')


def start(self, create_main_window=True):
self.thread_pool.startall()

#TODO: DONT DO THIS. Use package data instead
js_path = os.path.dirname(js.__file__)

self.tornado_app = tornado.web.Application([
(r"/js/(.*\.js)", tornado.web.StaticFileHandler,
{"path": js_path}),
(r"/app", PgHelp.WindowHandler,
dict(name='Application', url='/app', app=self.app)),
(r"/app/socket", PgHelp.ApplicationHandler,
dict(name='Ginga', app=self.app)),
], logger=self.logger)


self.tornado_server = tornado.httpserver.HTTPServer(self.tornado_app)
self.tornado_server.listen(self.port, self.host)

if create_main_window:
self.new_viewer('Main Viewer')

def stop(self):
raise NotImplementedError

def new_viewer(self, viewer_name,):
"""
Create a new viewer with the given name
"""
if viewer_name in self.viewers:
raise ValueError('Viewer {} already exists'.format(viewer_name))

# our own viewer object, customized with methods (see above)
self.viewers[viewer_name] = ipg.ImageViewer(self.logger, self.app.make_window(viewer_name))
return self.viewers[viewer_name]

def get_viewer_urls(self):
return {name: viewer.top.url for name, viewer in self.viewers.items()}


def load_fits(self, fileorhdu, viewer_name='Main Viewer'):
if isinstance(fileorhdu, file):
fileorhdu = fits.HDUList.fromfile(fileorhdu)

if isiterable(fileorhdu):
for hdui in fileorhdu:
if hasattr(hdui, 'is_image') and hdui.is_image:
hdu = hdui
break
else:
raise ValueError('fileorhdu was iterable but did not contain any image HDUs')
elif hasattr(fileorhdu, 'data') and hasattr(fileorhdu,'header'):
#quacks like an HDU - give it a shot
hdu = fileorhdu
else:
raise ValueError('fileorhdu was not a fits file or HDU-ish thing')


viewer = self.viewers[viewer_name]
if viewer.fitsimage.get_image() is None:
aim = AstroImage(logger=self.logger)
aim.load_hdu(hdu)
viewer.fitsimage.set_image(aim)
else:
viewer.fitsimage.get_image().load_hdu(hdu)

0 comments on commit bcd1b0b

Please sign in to comment.