# In the ipython shell do:
# %load_ext ipython_IDV
# or
# %reload_ext ipython_IDV
#
# This needs to have IDV_HOME pointing to the IDV install directory
# This will execute IDV_HOME/runIdv
#
import platform
import os
import os.path
import re
import subprocess
import json
import time
from shutil import copyfile
from base64 import b64encode
from IPython.display import HTML
from IPython.display import Image
from IPython.display import IFrame
from IPython.display import display
from IPython.display import Javascript
from IPython.display import DisplayObject
from IPython.display import TextDisplayObject
from IPython.display import clear_output
import tempfile
from tempfile import NamedTemporaryFile
from tempfile import gettempdir
from IPython.display import FileLink
import time
from IPython import get_ipython
from ipywidgets import *
import ipywidgets as widgets
from zipfile import *
import requests
import xml.etree.ElementTree as ET
from xml.etree.ElementTree import ParseError
from glob import glob
from os import listdir
from os.path import isfile, join
import IPython
from IPython.lib import kernel
import shlex
from io import BytesIO
from zipfile import ZipFile
try:
from urllib.request import urlopen
from urllib.parse import urlparse, urlencode, urljoin
except ImportError:
from urlparse import urljoin
from urlparse import urlparse
from urllib import urlopen, urlencode
import requests
try:
import xarray
def to_IDV(data, filename = None):
"""Load a xarray variable or dataset to load into IDV"""
if filename:
data.to_netcdf(filename)
load_data(filename)
else:
with NamedTemporaryFile(suffix='.nc') as f:
data.to_netcdf(f.name)
load_data(f.name)
xarray.DataArray.to_IDV=to_IDV
xarray.Dataset.to_IDV=to_IDV
def from_zidv(fileorurl=None,outdir=None):
"""Loading data from IDV zip file '.zidv' as xarray Dataset
fileorurl can be a local .zidv file or a remote url.
Optionally, outdir can be specified where the file is unzipped"""
if fileorurl.startswith('http'):
zfile = urlopen(fileorurl)
zfile = BytesIO(zfile.read())
elif isfile(fileorurl):
zfile=fileorurl
else:
return 'Unknown File or Url'
das=dict()
with ZipFile(zfile) as zip_file:
for contained_file in zip_file.namelist():
if str(contained_file).startswith('data'):
try:
das.update({contained_file:xarray.open_dataset(zip_file.extract(contained_file,outdir))})
except Exception as err:
print('Skipping file '+str(contained_file)+' because of error '+err)
return das
xarray.from_zidv=from_zidv
xarray.open_zidv=from_zidv
except ImportError:
print('xarray package is missing, functionality related to loading data'
'from xarray into IDV will not be available')
##Try importing netcdf. Some users won't have this installed
try:
from netCDF4 import Dataset
except ImportError:
print('netCDF4 is not installed');
def read_url(url):
"""Utility to read a URL. Returns the text of the result"""
##First try this with verify=True (the default)
##If it fails then try it with verify=False
##We do this so we don't get a warning with https urls that have normal signed certificates but
##we can still handle https from servers with self signed certs
try:
return requests.get(url).text
except:
try:
return requests.get(url, verify=False).text
except Exception as some_exception:
print("Error reading url:" + url)
print("Exception:" + repr(some_exception));
def test_it(line, cell=None):
print(os.listdir("."))
#
# Here are the magic commands
#
def idv_help(line, cell=None):
DrilsdownUI.status("")
html = "
idv_help Show this help message
" \
+ "run_idv
" \
+ "make_ui
" \
+ "load_bundle
" \
+ " If no bundle given and if set_ramadda has been called the bundle will be fetched from RAMADDA
" \
+ "load_bundle_make_image
" \
+ "load_catalog Load the case study catalog into the IDV
" \
+ "make_image <-publish> <-caption ImageName> <-capture (legend|window)> Capture an IDV image and optionally publish it to RAMADDA
" \
+ "make_movie <-publish> <-caption MovieName> <-capture (legend|window)> <-quality 0.1-1.0 set the resolution of the images. 1.0= full resolution> Capture an IDV movie and optionally publish it to RAMADDA
" \
+ "save_bundle <-publish> <-embed> - write out the bundle and optionally publish to RAMADDA. If embed then embed the bundle xml into the notebook as a link
" \
+ "publish_bundle - write out the bundle and publish it to RAMADDA
" \
+ "publish_notebook - publish the current notebook to RAMADDA via the IDV
" \
+ "set_ramadda
" \
+ "create_case_study
" \
+ "set_bbox <north west south east> No arguments to clear the bbox
"
DrilsdownUI.do_display(HTML(html))
def run_idv(line=None, cell=None):
"""Magic hook to start the IDV"""
Idv.run_idv(from_user=True)
def load_catalog(line, cell=None):
Idv.load_catalog(line)
def load_bundle_make_image(line, cell=None):
load_bundle(line, cell)
return make_image(line, cell)
def create_case_study(line, cell=None):
url = Repository.theRepository.make_url("/entry/form?parentof="
+ Repository.theRepository.entryId
+ "&type=type_drilsdown_casestudy&name=" + line)
url = url.replace(" ", "%20")
print("Go to this link to create the Case Study:")
print(url)
print("Then call %set_ramadda with the new Case Study URL")
def load_data(line, cell=None, name=None):
Idv.load_data(line, name)
def load_bundle(line, cell=None):
if line is None or line == "":
if Repository.theRepository is not None:
line = Repository.theRepository.make_url("/drilsdown/getbundle?entryid=" + Repository.theRepository.entryId)
if line is None or line == "":
print("No bundle argument provided")
return
Idv.load_bundle(line)
def make_image(line, cell=None):
# toks = line.split(" ")
toks = shlex.split(line);
skip = 0
publish = False
caption = None
display_id = None
cptr = None;
for i in range(len(toks)):
if skip > 0:
skip = skip-1
continue
tok = toks[i].strip()
if tok == "":
continue
if tok == "-publish":
publish = True
elif tok == "-caption":
skip = 1
caption = toks[i+1]
elif tok == "-capture":
skip = 1
cptr = toks[i+1]
elif tok == "-display":
skip = 1
display_id = toks[i+1]
elif tok == "-help":
print("%make_image <-display displayid> <-caption caption> <-publish>")
return
else:
print("Unknown argument:" + tok)
print("%make_image <-display displayid> <-caption caption> <-publish>")
return
DrilsdownUI.do_display(Idv.make_image(publish, caption, display_id=display_id, display=False, capture=cptr))
def publish_notebook(line, cell=None):
Idv.publish_notebook()
def make_movie(line, cell=None):
toks = shlex.split(line)
skip = 0
publish = False
display_id = None
caption = None
cptr = None;
quality = None;
for i in range(len(toks)):
if skip > 0:
skip = skip-1
continue
tok = toks[i]
if tok == "-publish":
publish = True
elif tok == "-caption":
skip = 1
caption = toks[i+1]
elif tok == "-quality":
skip = 1
quality = toks[i+1]
elif tok == "-capture":
skip = 1
cptr = toks[i+1]
elif tok == "-display":
skip = 1
display_id = toks[i+1]
return Idv.make_movie(publish, caption, display_id=display_id, capture=cptr, quality=quality)
def set_ramadda(line, cell=None):
"""Set the ramadda to be used. The arg should be the normal /entry/view URL for a RAMADDA entry"""
line_toks = line.split(" ")
should_list = len(line_toks) == 1
line = line_toks[0]
Repository.set_repository(Ramadda(line), should_list)
def list_repository(entry_id=None, repository=None):
"""List the entries held by the entry id"""
if repository is None:
repository = Repository.theRepository
repository.list_entry(entry_id)
def save_bundle(line, cell=None):
extra = ""
filename = "idv.xidv"
publish = False
embed = False;
toks = shlex.split(line)
for i in range(len(toks)):
tok = toks[i]
if tok != "":
if tok == "-publish":
publish = True
elif tok == "-embed":
embed = True
else:
filename = tok
Idv.save_bundle(filename, publish, embed=embed)
def publish_bundle(line, cell=None):
extra = " publish=\"true\" "
filename = "idv.xidv"
if line != "" and line is not None:
filename = line
Idv.publish_bundle(filename)
def set_bbox(line, cell=None):
Idv.setBBOX(line)
def make_ui(line):
DrilsdownUI.make_ui()
def load_ipython_extension(shell):
"""Define the magics"""
magic_type = "line"
shell.register_magic_function(test_it, magic_type)
shell.register_magic_function(idv_help, magic_type)
shell.register_magic_function(run_idv, magic_type)
shell.register_magic_function(make_ui, magic_type)
shell.register_magic_function(load_bundle, magic_type)
shell.register_magic_function(load_bundle_make_image, magic_type)
shell.register_magic_function(load_catalog, magic_type)
shell.register_magic_function(make_image, magic_type)
shell.register_magic_function(make_movie, magic_type)
shell.register_magic_function(set_ramadda, magic_type)
shell.register_magic_function(create_case_study, magic_type)
shell.register_magic_function(set_bbox, magic_type)
shell.register_magic_function(save_bundle, magic_type)
shell.register_magic_function(publish_bundle, magic_type)
shell.register_magic_function(publish_notebook, magic_type)
class DrilsdownUI:
"""Handles all of the UI callbacks """
idToRepository = {}
@staticmethod
def make_ui():
global repositories
name_map = {}
names = []
first = None
for i in range(len(repositories)):
repository = repositories[i]
if i == 0:
first = repository.get_id()
DrilsdownUI.idToRepository[repository.get_id()] = repository
name_map[repository.get_name()] = repository.get_id()
names.append(repository.get_name())
text_layout = Layout(width='150px')
repository_selector = widgets.Dropdown(
options=name_map,
value=first,
)
search = widgets.Text(
layout=text_layout,
value='',
placeholder='IDV bundle',
description='',
disabled=False)
search.on_submit(DrilsdownUI.handle_search)
search.type = "type_idv_bundle"
cssearch = widgets.Text(
value='',
layout=text_layout,
placeholder='Case Study or folder',
description='',
disabled=False)
cssearch.on_submit(DrilsdownUI.handle_search)
cssearch.type = "type_drilsdown_casestudy"
gridsearch = widgets.Text(
value='',
layout=text_layout,
placeholder='Gridded data files',
description='',
disabled=False)
gridsearch.on_submit(DrilsdownUI.handle_search)
gridsearch.type = "cdm_grid"
allsearch = widgets.Text(
value='',
layout=text_layout,
placeholder='All',
description='',
disabled=False)
allsearch.on_submit(DrilsdownUI.handle_search)
allsearch.type = ""
list_btn = DrilsdownUI.make_button("List", DrilsdownUI.list_repository_clicked)
list_btn.entry = None
cbx = widgets.Checkbox(
value=False,
description='Publish',
disabled=False)
repository_selector.observe(DrilsdownUI.repository_selector_changed, names='value')
DrilsdownUI.statusLabel = Label("")
display(VBox(
[HTML("ipython_IDV Control Panel
"),
HBox([HTML("Resources:"),
repository_selector,
list_btn]),
HBox([HTML("Search for:"), search,
cssearch, gridsearch, allsearch]),
HBox([DrilsdownUI.make_button("Run IDV", DrilsdownUI.run_idv_clicked),
DrilsdownUI.make_button("Make Image", DrilsdownUI.make_image_clicked, cbx),
DrilsdownUI.make_button("Make Movie", DrilsdownUI.make_movie_clicked, cbx),
DrilsdownUI.make_button("Save Bundle", DrilsdownUI.save_bundle_clicked, cbx),
# DrilsdownUI.make_button("Publish Notebook", Idv.publish_notebook),
cbx]),
HBox([
# Label("Outputs append below until Cleared:"),
DrilsdownUI.make_button("Clear Outputs", DrilsdownUI.clear_clicked),
DrilsdownUI.make_button("Commands Help", idv_help),
DrilsdownUI.statusLabel
]),
]))
displayedItems = []
@staticmethod
def do_display(comp):
"""Call this to display a component that can later be cleared with the Clear button"""
display(comp)
DrilsdownUI.displayedItems.append(comp)
@staticmethod
def status(text):
##If we haven't made a UI we don't have a statusLabel
try:
DrilsdownUI.statusLabel.value = text
except:
print(text);
@staticmethod
def make_button(label, callback, extra=None):
"""Utility to make a button widget"""
b = widgets.Button(
description=label,
disabled=False,
button_style='', # 'success', 'info', 'warning', 'danger' or ''
tooltip=label,
)
b.extra = extra
b.on_click(callback)
return b
@staticmethod
def handle_search(widget):
type = widget.type
value = widget.value.replace(" ", "%20")
if hasattr(Repository.theRepository, "do_search"):
DrilsdownUI.status("Searching...")
entries = Repository.theRepository.do_search(value, type)
Repository.theRepository.display_entries("Search Results: " + widget.value + "
", entries)
DrilsdownUI.status("")
else:
DrilsdownUI.status("Search not available")
@staticmethod
def run_idv_clicked(b):
Idv.run_idv(from_user=True)
@staticmethod
def save_bundle_clicked(b):
extra = ""
if b.extra.value:
extra = "-publish"
save_bundle(extra)
@staticmethod
def make_image_clicked(b):
DrilsdownUI.status("")
extra = ""
if b.extra.value:
extra = "-publish"
print("%make_image " + extra);
image = make_image(extra)
if image is not None:
DrilsdownUI.do_display(image)
@staticmethod
def make_movie_clicked(b):
DrilsdownUI.status("")
print("%make_movie");
if b.extra.value:
movie = Idv.make_movie(True)
else:
movie = Idv.make_movie(False)
if movie is not None:
DrilsdownUI.do_display(movie)
@staticmethod
def load_bundle_clicked(b):
url = b.entry.get_file_path();
print("%load_bundle " + url);
load_bundle(url)
@staticmethod
def view_url_clicked(b):
DrilsdownUI.do_display(HTML("" + b.name + ""))
display(IFrame(src=b.url, width=800, height=400))
@staticmethod
def load_data_clicked(b):
load_data(b.entry.get_data_path(), None, b.name)
@staticmethod
def set_data_clicked(b):
url = b.entry.get_data_path()
Idv.data_url = url
print('To access the data use the variable: Idv.data_url or:\n' + url)
@staticmethod
def set_url_clicked(b):
url = b.entry.make_get_file_url()
Idv.file_url = url
print('To access the URL use the variable: Idv.file_url or:\n' + url)
@staticmethod
def list_repository_clicked(b):
if b.entry is None:
list_repository(None)
else:
list_repository(b.entry.get_id(), b.entry.get_repository())
@staticmethod
def load_catalog_clicked(b):
load_catalog(b.url)
@staticmethod
def repository_selector_changed(s):
repository = DrilsdownUI.idToRepository[s['new']]
Repository.set_repository(repository)
@staticmethod
def clear_clicked(b):
DrilsdownUI.status("")
clear_output()
for i in range(len(DrilsdownUI.displayedItems)):
item = DrilsdownUI.displayedItems[i]
if hasattr(item, "close"):
item.close()
DrilsdownUI.displayedItems = []
clear_output()
class IdvResults:
results = "";
call_ok = False;
def __init__(self, ok = False, results=""):
self.call_ok = ok;
self.results = results;
def __repr__(self):
return self.results;
def set_ok(self, ok):
self.call_ok = ok;
def ok(self):
return self.call_ok;
def set_results(self,results):
self.results = results;
def get_results(self):
return self.results;
class Idv:
debug = False
debugBaseUrl = True;
bbox = None
data_url = None
file_url = None
path = None
# These correspond to the commands in ucar.unidata.idv.IdvMonitor
cmd_ping = "/ping"
cmd_loadisl = "/loadisl"
base_url = None
# The port is defined by the idv.monitorport = 8765 in the .unidata/idv/DefaultIdv/idv.properties
base_urls = ["http://127.0.0.1:8788", "http://127.0.0.1:8765"]
@staticmethod
def setDebug(debug):
Idv.debug = debug
@staticmethod
def get_base_url():
if Idv.base_url is not None:
return Idv.base_url
# Try the different ports
for url in Idv.base_urls:
try:
if Idv.debug and Idv.debugBaseUrl:
print("Trying:" + url + Idv.cmd_ping);
urlopen(url + Idv.cmd_ping).read()
if Idv.debug:
print("IDV base url:" + url)
Idv.base_url = url
Idv.debugBaseUrl = False;
return Idv.base_url
except:
dummy = None
if Idv.debug:
print("Failed to connect to the IDV")
Idv.debugBaseUrl = False;
return None
@staticmethod
def idv_ping():
"""This function checks if the IDV is running"""
# NOTE: Don't call idv_call here because idv_call calls run_idv which calls ping
try:
base_url=Idv.get_base_url();
if base_url is not None:
return urlopen(base_url + Idv.cmd_ping).read()
return None;
except Exception as some_exception:
## print("err:" + repr(some_exception));
return None
@staticmethod
def set_path(path):
"""This function directly sets the path to the IDV executable"""
Idv.path = path
@staticmethod
def set_port(port):
"""This function sets the port the IDV listens on"""
Idv.base_url = "http://127.0.0.1:" + port
@staticmethod
def sniff_out_path():
roots = ["/Applications", "C:\\Program Files"]
majors = ["IDV_6", "IDV_5"]
dots = ["9", "8", "7", "6", "5", "4", "3", "2", "1"]
minors = ["u10", "u9", "u8", "u7", "u6", "u5", "u4", "u3", "u2", "u1", ""]
for root in roots:
for major in majors:
for dot in dots:
for minor in minors:
dir = os.path.join(root, major + "." + dot + minor)
# print(dir)
if os.path.isdir(dir):
return dir
return None
@staticmethod
def run_idv(from_user=False):
"""Check if the IDV is running"""
idv_running = Idv.idv_ping()
if idv_running:
if from_user:
DrilsdownUI.status("IDV is running")
return
# path might have been set directly by set_path
path = Idv.path
# Check if the env is defined
if path is None:
idvDir = None
if "IDV_HOME" in os.environ:
idvDir = os.environ['IDV_HOME']
else:
idvDir = Idv.sniff_out_path()
if idvDir is None:
print("No IDV_HOME environment variable set")
Idv.print_set_path()
return
path = os.path.join(idvDir, "runIDV")
# check for windows
# if not os.path.isfile(path): # old way
if 'indow' in platform.system():
path = os.path.join(idvDir,"runIDV.bat")
if not os.path.isfile(path):
print("Could not find an executable IDV script in:")
print(idvDir)
Idv.print_set_path()
return
else:
if not os.path.isfile(path):
print("IDV exectuable does not exist:")
print(path)
return
print("Starting IDV: " + path)
cwd = os.path.dirname(path)
subprocess.Popen([path], cwd=cwd)
# Give the IDV a chance to get going
suffix = ""
for x in range(0, 60):
if Idv.idv_ping() is not None:
DrilsdownUI.status("IDV started")
return
if x % 2 == 0:
DrilsdownUI.status("Waiting on the IDV " + suffix)
suffix = suffix+"."
time.sleep(1)
DrilsdownUI.status("IDV failed to start (or is slow in starting)")
@staticmethod
def print_set_path():
print("You can set the path to runIDV with:")
print("from ipython_IDV import Idv")
print('Idv.set_path("/path to idv executable")')
print('#e.g.:')
print('Idv.set_path("/Applications/IDV_5.6/runIDV")')
print('If that fails, try:')
print('import os')
print("os.environ['IDV_HOME']='/home/gary/IDV_5.5/'")
print("Of course, replace /home/gary with your actual IDV install location")
@staticmethod
def run_isl(isl):
return Idv.idv_call(Idv.cmd_loadisl, {"isl": isl});
@staticmethod
def idv_call(command, args=None):
"""
Will start up the IDV if needed then call the command
If args is non-null then this is a map of the url arguments to pass to the IDV
"""
Idv.run_idv(from_user=False)
result = IdvResults(False,"");
try:
url = Idv.get_base_url() +command
if args:
url += "?" + urlencode(args)
if Idv.debug:
print("Calling " + url)
xml = urlopen(url).read().decode("utf-8")
root = ET.fromstring(xml)
result.set_ok(root.attrib['ok'] == 'true')
if root.text is not None:
result.set_results(root.text)
else:
result.set_results("")
#Handle older versions of the IDV
except ParseError as pe:
result.set_ok(True);
result.set_results(xml)
except Exception as some_exception:
result.set_results( "Error occurred:" + repr(some_exception))
if not result.ok():
print("An error has occurred:" + result.get_results());
return result;
@staticmethod
def load_data(url, name=None):
extra1 = ""
extra2 = ""
if name is not None:
extra1 += ' name="' + name + '" '
isl = '\n' + extra2 + '\n'
result = Idv.run_isl(isl);
if not result.ok():
print("load_data failed")
return
print("data loaded")
theNotebook = "xx"
def test():
Idv.theNotebook = "yy"
def setname(name):
Idv.theNotebook = name
print("NAME = " + name)
@staticmethod
def getname():
# A hack from
# https://stackoverflow.com/questions/12544056/how-do-i-get-the-current-ipython-notebook-name
# to get the name of the notebook file
connection_file_path = kernel.get_connection_file()
connection_file = os.path.basename(connection_file_path)
kernel_id = connection_file.split('-', 1)[1].split('.')[0]
print("connection file:" + connection_file_path)
response = requests.get('http://127.0.0.1:{port}/api/sessions'.format(port=8888))
print(response.text)
matching = [s for s in json.loads(response.text) if s['kernel']['id'] == kernel_id]
if matching:
return os.getcwd() + "/" + matching[0]['notebook']['path']
else:
print("Could not find notebook filename")
None
@staticmethod
def publish_notebook(extra=None):
# If we do this then the Javascript object shows up in the notebook
# js = Javascript('IPython.notebook.save_checkpoint();')
# display(js)
file = Idv.getname()
if file is None:
return
isl = ''
DrilsdownUI.status("Make sure you do 'File->Save and Checkpoint'. Check your IDV to publish the file")
result = Idv.run_isl(isl);
if not result.ok():
print("Publication failed")
return
if result.get_results().strip()!="":
print("Publication successful")
print("URL: " + result.get_results())
return
print("Publication failed")
@staticmethod
def setBBOX(line):
toks = line.split()
if len(toks) == 0:
Idv.bbox = None
print("BBOX is cleared")
return
Idv.bbox = []
for i in range(len(toks)):
Idv.bbox.append(float(toks[i]))
print("BBOX is set")
@staticmethod
def load_catalog(url=None):
if url is None or url == "":
url = Repository.theRepository.make_url("/entry/show?parentof="
+ Repository.theRepository.entryId
+ "&output=thredds.catalog")
else:
url = url.replace("&", "&")
isl = '\n'
result = Idv.run_isl(isl);
if not result.ok():
print("load_catalog failed")
return
print("Catalog loaded")
@staticmethod
def save_bundle(filename, publish=False, embed = False):
extra = ""
if filename is None:
filename = "idv.xidv"
if publish:
extra += ' publish="true" '
if not os.path.isabs(filename):
filename = os.path.join(os.getcwd() ,filename);
isl = ''
result = Idv.run_isl(isl);
if not result.ok():
print("save failed")
return
if os.path.isfile(filename):
DrilsdownUI.status("Bundle saved:" + filename)
if embed:
bundle = open(filename, "rb").read()
bundle = b64encode(bundle).decode('ascii')
name = os.path.basename(filename);
html = '' + name +'';
DrilsdownUI.do_display(HTML(html))
else:
DrilsdownUI.do_display(FileLink(filename))
return;
DrilsdownUI.status("Bundle not saved")
@staticmethod
def load_bundle(bundle_url, bbox=None):
extra1 = ""
extra2 = ""
if bbox is None:
bbox = Idv.bbox
if bbox is not None:
extra1 += 'bbox="' + repr(bbox[0]) + "," + repr(bbox[1]) + "," + repr(bbox[2]) + "," + repr(bbox[3]) + '"'
# The padding is to reset the viewpoint to a bit larger area than the bbox
padding = (float(bbox[0]) - float(bbox[2]))*0.1
north = float(bbox[0])+padding
west = float(bbox[1])-padding
# For some reason we need to pad south a bit more
south = float(bbox[2])-1.5*padding
east = float(bbox[3])+padding
extra2 += ''
isl = '\n' + extra2 + '\n'
result = Idv.run_isl(isl);
if not result.ok():
DrilsdownUI.status("Bundle load failed")
return
DrilsdownUI.status("Bundle loaded")
@staticmethod
def publish_bundle(filename):
extra = " publish=\"true\" "
isl = ''
result = Idv.run_isl(isl);
if not result.ok():
print("save failed")
return
if result.get_results().strip() != "":
print("Publication successful")
print("URL: " + result.get_results())
if os.path.isfile(filename):
print("bundle saved:" + filename)
return FileLink(filename)
print("Publication failed")
@staticmethod
def make_movie(publish=False, caption=None, display=True, display_id=None, capture=None, quality=None):
return Idv.make_imageOrMovie(False, publish, caption, display, display_id, capture, quality)
@staticmethod
def make_image(publish=False, caption=None, display=True, display_id=None, capture=None):
return Idv.make_imageOrMovie(True, publish, caption, display, display_id, capture)
@staticmethod
def make_imageOrMovie(image, publish=False, caption=None, display=True, display_id=None, capture=None, quality=None):
what = "movie"
if image:
what = "image"
DrilsdownUI.status("Making " + what + "...")
self_publish = False
idv_publish = False
parent = None
isl = ''
extra = ""
extra2 = ""
name = None
ramadda = Repository.theRepository
if capture is not None:
extra += " capture=\"" + capture +"\" "
if type(publish) is bool:
if publish:
idv_publish = True
extra = " publish=\"true\" "
elif publish is not None:
self_publish = True
if 'ramadda' in publish:
ramadda = Ramadda(publish['ramadda'])
if 'parent' in publish:
parent = publish['parent']
else:
parent = ramadda.get_id()
if 'name' in publish:
name = publish['name']
if caption is not None:
extra2 += ''
label = caption
label = label.replace("-", " ")
extra2 += ''
extra2 += ''
if name is None:
name = caption
if display_id is not None:
extra += ' display="' + display_id + '" '
if quality is not None:
extra += ' quality="' + quality +'" '
with NamedTemporaryFile(suffix='.gif', delete=False) as f:
isl += '<' + what + ' file="' + f.name + '"' \
+ extra + '>' + extra2 + '' + what + '>'
result = Idv.run_isl(isl)
f.seek(0)
if idv_publish:
if not result.ok():
DrilsdownUI.status("make " + what + " failed")
return
if result.get_results().strip() != "":
print("Publication successful " + "URL: " + result.get_results())
else:
print("Publication failed");
if self_publish:
ramadda.publish(name, file=f.name, parent=parent)
data = open(f.name, "rb").read()
f.close()
# data = b64encode(data).decode('ascii')
# img = ''
if display:
DrilsdownUI.status("")
DrilsdownUI.do_display(IPython.core.display.Image(data))
else:
return IPython.core.display.Image(data)
DrilsdownUI.status("")
@staticmethod
def export_data(filename=None, display_id=None, load_data = True, suffix='nc'):
DrilsdownUI.status("Exporting data ...")
extra = ""
if display_id is not None:
extra += ' display="' + display_id + '" '
if filename is None:
f = NamedTemporaryFile(suffix='.' + suffix, delete=False)
filename = f.name;
isl = ''
result = Idv.run_isl(isl)
if not result.ok():
return;
# print("Data exported to: " + filename);
if load_data:
placeholder = False;
# filename= '/Users/jeffmc/test.nc';
# filename= '/Users/jeffmc/test.netcdf';
dataset= Dataset(filename, "r");
return dataset;
# return load_data(filename);
# img = ''
DrilsdownUI.status("data exported to: " + filename)
class Repository:
theRepository = None
def __init__(self, id):
self.id = id
def set_repository(repository, should_list=False):
"""Set the repository to be used. The arg should be the normal /entry/view URL for a REPOSITORY entry"""
Repository.theRepository = repository
if should_list:
list_repository(Repository.theRepository.entry_id, repository)
return Repository.theRepository
def get_id(self):
return self.entry_id
def display_entries(self, label="Entries", entries=[]):
cnt = 0
indent = HTML(" ")
rows = [HTML(label)]
for i in range(len(entries)):
if cnt > 100:
break
cnt = cnt+1
entry = entries[i]
name = entry.get_name()
id = entry.get_id()
icon = entry.get_icon()
full_name = name
max_length = 25
if len(name) > max_length:
name = name[:max_length-len(name)]
name = name.ljust(max_length, " ")
name = name.replace(" ", " ")
row = []
if entry.get_url() is not None:
href = self.make_entry_href(id, name, icon, full_name)
href = "" + href + ""
href = HTML(href)
row = [indent, href]
else:
label = "" + name + ""
row = [indent, HTML(label)]
if entry.is_bundle():
b = DrilsdownUI.make_button("Load bundle", DrilsdownUI.load_bundle_clicked)
b.entry = entry
row.append(b)
entry.add_display_widget(row)
elif entry.is_grid():
b = DrilsdownUI.make_button("Load data", DrilsdownUI.load_data_clicked)
b.name = full_name
b.entry = entry
row.append(b)
b = DrilsdownUI.make_button("Set data", DrilsdownUI.set_data_clicked)
b.entry = entry
row.append(b)
elif entry.is_group():
b = DrilsdownUI.make_button("List", DrilsdownUI.list_repository_clicked)
b.entry = entry
row.append(b)
catalog_url = entry.get_catalog_url()
if catalog_url is not None:
load_catalog = DrilsdownUI.make_button("Load Catalog", DrilsdownUI.load_catalog_clicked)
load_catalog.url = catalog_url
row.append(load_catalog)
else:
if entry.get_url() is not None:
b = DrilsdownUI.make_button("View", DrilsdownUI.view_url_clicked)
b.url = self.make_url("/entry/show?entryid=" + id)
b.name = name
row.append(b)
file_size = entry.get_file_size()
if file_size > 0:
link = self.make_url("/entry/get?entryid=" + id)
row.append(HTML(' Download ('
+ repr(file_size) + ' bytes) '))
else:
row.append(HTML('' + entry.path + '>'))
rows.append(HBox(row))
DrilsdownUI.do_display(VBox(rows))
if cnt == 0:
DrilsdownUI.do_display(HTML("No entries found"))
class LocalFiles(Repository):
def __init__(self, dir):
if dir is None:
self.dir = "."
else:
self.dir = dir
self.cwd = self.dir
self.name = "Local Files"
self.searchCnt = 0
def list_entry(self, entry_id):
"""List the entries held by the entry id"""
entries = self.do_list(entry_id)
self.display_entries("
", entries)
def get_id(self):
return self.dir
def get_name(self):
return self.name
def get_base(self):
return self.dir
def do_list(self, dir=None, display=False, label="Entries"):
"""make a list of RamaddaEntry objects that are children of the given entryId"""
if dir is None:
dir = self.dir
files = os.listdir(dir)
entries = []
prefix = dir+"/"
if prefix == "./":
prefix = ""
for i in range(len(files)):
if files[i].startswith(".") is not True:
entries.append(FileEntry(self, prefix + files[i]))
if display:
self.display_entries(label, entries)
else:
return entries
def do_search(self, value, type=None):
"""Do a search for the text value and (optionally) the entry type. Return a list of RamaddaEntry objects"""
self.searchCnt = 0
# print("Search not supported for local files")
files = []
self.do_search_inner(value, self.dir, files, type)
return files
def do_search_inner(self, value, dir, list, type):
# Only check so many files - should make this breadth firs
if self.searchCnt > 5000:
return
files = os.listdir(dir)
for i in range(len(files)):
file_mixed_case = files[i]
file = file_mixed_case.lower()
if file.startswith("."):
continue
if re.match(value, file_mixed_case) or value in file_mixed_case or re.match(value, file) or value in file:
ok = True
if type is not None:
if type == "type_idv_bundle":
if not file_mixed_case.endswith(".xidv") and not file_mixed_case.endswith(".zidv"):
ok = False
if type == "type_drilsdown_casestudy":
if not os.path.isdir(dir + "/" + file):
ok = False
if type == "cdm_grid":
if not file_mixed_case.endswith(".nc"):
ok = False
if ok:
list.append(FileEntry(self, dir+"/" + file))
if os.path.isdir(dir + "/" + file):
self.do_search_inner(value, dir + "/" + file, list, type)
class TDS(Repository):
def __init__(self, url, name=None):
self.url = url
if name is not None:
self.name = name
else:
catalog = read_url(url)
root = ET.fromstring(catalog)
self.name = root.attrib['name']
def list_entry(self, entry_id):
"""List the entries held by the entry id"""
entries = self.do_list(entry_id)
self.display_entries("
", entries)
def get_id(self):
return self.url
def get_name(self):
return self.name
def get_base(self):
return self.url
def do_list(self, url=None, display=False, label="Entries"):
"""make a list of RamaddaEntry objects that are children of the given entryId"""
if url is None:
url = self.url
catalog = read_url(url)
root = ET.fromstring(catalog)
entries = []
for child in root:
# print("child:" + child.tag)
self.get_entries(root, url, child, entries)
if display:
self.display_entries(label, entries)
else:
return entries
def clean_tag(self, tag):
tag = re.sub("{.*}", "", tag)
return tag
def get_entries(self, root, url, element, entries):
tag = self.clean_tag(element.tag)
if tag == "dataset":
for child in element:
self.get_entries(root, url, child, entries)
service_name = self.find_service_name(root)
if service_name is not None:
print("dataset:" + element.attrib["name"])
return
return
if tag == "catalogRef":
href = element.attrib["{http://www.w3.org/1999/xlink}href"]
title = element.attrib["{http://www.w3.org/1999/xlink}title"]
url = urljoin(url, href)
entries.append(TDSCatalogEntry(self, url, title))
return
return
def find_opendap_services(self, parentService, element, map):
# serviceType="OPENDAP"
return
def find_service_name(self, element):
if element.tag == "serviceName":
return element.text
for child in element:
name = self.find_service_name(child)
if name is not None:
return name
return None
class Ramadda(Repository):
theRamadda = None
def __init__(self, url, name=None):
self.url = url
toks = urlparse(url)
self.host = toks.scheme + "://" + toks.netloc
self.base = toks.scheme + "://" + toks.netloc
path = re.sub("/entry.*", "", toks.path)
self.base += path
self.entryId = re.search("entryid=([^&]+)", toks.query).group(1)
if name is not None:
self.name = name
else:
toks = read_url(self.make_url("/entry/show?output=entry.csv&escapecommas=true&fields=name,icon&entryid="
+ self.entryId)).split("\n")[1].split(",")
self.name = toks[0].replace("_comma_", ",")
def get_id(self):
return self.entryId
def get_name(self):
return self.name
def get_base(self):
return self.base
def list_entry(self, entry_id):
if entry_id is None:
entry_id = self.entryId
"""List the entries held by the entry id"""
# print(self.make_url("/entry/show?output=entry.csv&escapecommas=true&fields=name,icon&entryid=" + entry_id))
toks = read_url(self.make_url("/entry/show?output=entry.csv&escapecommas=true&fields=name,icon&entryid="
+ entry_id)).split("\n")[1].split(",")
base_name = toks[0]
base_name = base_name.replace("_comma_", ",")
icon = toks[1]
entries = self.do_list(entry_id)
self.display_entries("" + " "
+ "" + base_name + "
", entries)
def do_list(self, entry_id=None, display=False, label="Entries"):
"""make a list of RamaddaEntry objects that are children of the given entry_id"""
if entry_id is None:
entry_id = self.entryId
csv = read_url(self.make_url("/entry/show?entryid=" + entry_id
+ "&output=default.csv&escapecommas=true&fields="
"name,id,type,icon,url,size&orderby=name"))
entries = self.make_entries(csv)
if display:
self.display_entries(label, entries)
else:
return entries
def do_search(self, value, type=None):
"""Do a search for the text value and (optionally) the entry type. Return a list of RamaddaEntry objects"""
entries = []
if type is None or type == "":
url = self.make_url(
"/search/do?output=default.csv&escapecommas=true&fields=name,id,type,icon,url,size&orderby=name&text="
+ value)
else:
url = self.make_url(
"/search/type/" + type
+ "?output=default.csv&escapecommas=true&orderby=name&fields=name,id,type,icon,url,size&text="
+ value)
csv = read_url(url)
return self.make_entries(csv)
def make_entries(self, csv):
"""Convert the RAMADDA csv into a list of RamaddaEntry objects """
entries = []
lines = csv.split("\n")
cnt = 0
for i in range(len(lines)):
if i == 0:
continue
line2 = lines[i]
line2 = line2.split(",")
if len(line2) >= 5:
cnt = cnt+1
name = line2[0]
name = name.replace("_comma_", ",")
id = line2[1]
type = line2[2]
icon = line2[3]
url = line2[4]
file_size = 0
try:
file_size = float(line2[5])
except:
print("bad line:" + line2[5])
entry = RamaddaEntry(self, name, id, type, icon, url, file_size)
entries.append(entry)
return entries
def make_url(self, path):
"""Add the ramadda base path to the given url path"""
return self.base + path
def make_entry_url(self, entryId):
"""make a href for the given entry"""
return self.base + '/entry/show?entryid=' + entryId
def make_entry_href(self, entryId, name, icon=None, alt=""):
"""make a href for the given entry"""
html = '' + name + ''
if icon is not None:
html = " " + html
return html
def publish(self, name, file=None, parent=None):
if "RAMADDA_USER" not in os.environ:
print("No RAMADDA_USER environment variable set")
return
if "RAMADDA_PASSWORD" not in os.environ:
print("No RAMADDA_PASSWORD environment variable set")
return
user = os.environ['RAMADDA_USER']
password = os.environ['RAMADDA_PASSWORD']
if parent is None:
parent = self.entryId
extra = ""
if file is not None:
extra += ' file="' + os.path.basename(file) + '" '
entry_xml = ''
with NamedTemporaryFile(suffix='.zip') as tmpZip:
with ZipFile(tmpZip.name, 'w') as myzip:
with NamedTemporaryFile(suffix='.xml') as tmpFile:
entries_file = open(tmpFile.name, 'w')
entries_file.write(entry_xml)
entries_file.close()
myzip.write(tmpFile.name, arcname='entries.xml')
if file is not None:
myzip.write(file)
files = {'file': open(tmpZip.name, 'rb')}
# TODO: change http to https
url = self.make_url("/entry/xmlcreate")
r = requests.post(url, files=files,
data={'group': parent, 'auth.user': user, 'auth.password': password, 'response': 'xml'})
root = ET.fromstring(r.text)
if root.attrib['code'] == 'ok':
for child in root:
display(HTML("Published file: " + self.make_entry_href(child.attrib['id'], name)))
else:
print('Error publishing file')
print(r.text)
class RepositoryEntry:
def __init__(self, repository, name, id, type, icon, file_size):
self.repository = repository
self.name = name.replace("_comma_", ",")
self.id = id
self.type = type
self.icon = icon
self.file_size = file_size
def get_file_path(self):
return None
def get_data_path(self):
return self.get_file_path()
def get_catalog_url(self):
return None
def get_repository(self):
return self.repository
def get_name(self):
return self.name
def get_id(self):
return self.id
def get_type(self):
return self.type
def get_icon(self):
return self.icon
def get_url(self):
return None
def get_file_size(self):
return self.file_size
def is_bundle(self):
return False
def is_grid(self):
return self.get_type() == "cdm_grid" or self.get_name().endswith(".nc")
def is_group(self):
return False
def add_display_widget(self, row):
return
class TDSCatalogEntry(RepositoryEntry):
def __init__(self, repository, url, name):
RepositoryEntry.__init__(self, repository, name, url, "", None, 0)
self.url = url
def get_file_path(self):
return self.url
def is_group(self):
return True
def get_catalog_url(self):
return self.url
class FileEntry(RepositoryEntry):
def __init__(self, repository, path):
# print(path)
RepositoryEntry.__init__(self, repository, path, path, "", None, os.path.getsize(path))
self.path = path
def get_file_path(self):
return os.getcwd() + "/" + self.path
def get_data_path(self):
return self.get_file_path()
def is_bundle(self):
return self.path.find("xidv") >= 0 or self.path.find("zidv") >= 0
def is_group(self):
return os.path.isdir(self.path)
class RamaddaEntry(RepositoryEntry):
def __init__(self, ramadda, name, id, type, icon, url, fileSize):
RepositoryEntry.__init__(self,ramadda, name, id, type, icon, fileSize)
self.url = url
def get_file_path(self):
return self.url
# return self.get_repository().make_url("/entry/get?entryid=" + self.get_id())
def get_data_path(self):
return self.make_opendap_url()
def get_catalog_url(self):
return self.repository.make_url("/entry/show?output=thredds.catalog&entryid=" + self.id)
def get_icon(self):
return self.icon
def get_url(self):
return self.url
def is_bundle(self):
return self.get_type() == "type_idv_bundle" or self.get_url().find("xidv") >= 0 \
or self.get_url().find("zidv") >= 0
def is_grid(self):
return self.get_type() == "cdm_grid" or self.get_name().endswith(".nc")
def is_group(self):
return self.get_type() == "type_drilsdown_casestudy" or self.get_type() == "group" \
or self.get_type() == "localfiles"
def make_opendap_url(self):
return self.get_repository().base + "/opendap/" + self.id + "/entry.das"
def make_get_file_url(self):
return self.url
# return self.get_repository().base + "/entry/get?entryid=" + self.id
def add_display_widget(self, row):
b = DrilsdownUI.make_button("Set URL", DrilsdownUI.set_url_clicked)
b.entry = self
row.append(b)
link = self.get_repository().make_url("/entry/show/?output=idv.islform&entryid=" + self.get_id())
row.append(HTML('Subset Bundle'))
# Make the REPOSITORIES
repositories = [Ramadda("http://weather.rsmas.miami.edu/repository/entry/show?entryid=45e3b50b-dbe2-408b-a6c2-2c009749cd53",
"The Mapes IDV Collection"),
Ramadda("http://geodesystems.com/repository/entry/show?entryid=12704a38-9a06-4989-aac4-dafbbe13a675",
"Geode Systems Drilsdown Collection"),
Ramadda("https://www.esrl.noaa.gov/psd/repository/entry/show?entryid=f8d470f4-a072-4c1e-809e-d6116a393818",
"NOAA-ESRL-PSD Climate Data Repository"),
# Ramadda("http://ramadda.atmos.albany.edu:8080/repository?entryid=643aa629-c53d-48cb-8454-572fad73cb0f",
# "University of Albany RAMADDA"),
TDS("http://thredds.ucar.edu/thredds/catalog.xml",
"Unidata THREDDS Data Server"),
Ramadda("https://motherlode.ucar.edu/repository/entry/show?entryid=0",
"Unidata RAMADDA Server"),
TDS("http://weather.rsmas.miami.edu/thredds/catalog.xml",
"University of Miami THREDDS Data Server"),
LocalFiles(".")
]
Repository.theRepository = repositories[0]
show_ui = True;
if 'drilsdown.showui' in os.environ:
show_ui = os.environ['drilsdown.showui'] == "True"
if show_ui:
make_ui("")