def test_embed_data_two_widgets(self): feature_track = pileup.Track( viz="features", label="myFeatures", source=pileup.sources.GA4GHFeatureJson('{}')) variant_track = pileup.Track( viz="variants", label="myVariants", source=pileup.sources.GA4GHVariantJson('{}')) w1 = pileup.PileupViewer(chrom="chr17", start=1, stop=250, reference="hg19", tracks=[feature_track]) w2 = pileup.PileupViewer(chrom="chr17", start=1, stop=250, reference="hg19", tracks=[variant_track]) jslink((w1, 'reference'), (w2, 'reference')) state = dependency_state([w1, w2], drop_defaults=True) data = embed_data(views=[w1, w2], drop_defaults=True, state=state) state = data['manager_state']['state'] views = data['view_specs'] assert len(views) == 2 model_names = [s['model_name'] for s in state.values()] widget_names = list( filter(lambda x: x == 'PileupViewerModel', model_names)) assert len(widget_names) == 2
def __init__(self, widget, **kwargs): from ipywidgets import embed, Widget super().__init__(**kwargs) spec = widget.get_view_spec() state = Widget.get_manager_state(widgets=[]) state["state"] = embed.dependency_state([widget], drop_defaults=True) self.bundle = dict(spec=spec, state=state)
def to_html(self, path): """ This function embed the chart widget into an HTML file dumped at the inputted path location. To see more details about embeding an ipywidget see: https://ipywidgets.readthedocs.io/en/latest/embedding.html """ embed_minimal_html(path, views=[self], state=dependency_state([self]))
def dict_from_widget(self): """generate a JSON-ready dict from a widget""" d = {} w = self.tracked_widget if w is not None: s = E.dependency_state(w)[w.comm.comm_id]["state"] for k in self.tracked_traits or list(s): d[k] = s.get(k, None) return d
def test_minimal_features_html(self): w = pileup.Features(json="{}", build='hg19', contig='chr1', start=1, stop=20) output = StringIO() state = dependency_state(w, drop_defaults=True) embed_minimal_html(output, views=w, drop_defaults=True, state=state) content = output.getvalue() assert content.splitlines()[0] == '<!DOCTYPE html>'
def to_html(self, imports=True, html_frame=True): # Bake positions (fixes centering bug in offline rendering) if len(self.__objects) == 0: return ma = np.zeros((len(self.__objects), 3)) mi = np.zeros((len(self.__objects), 3)) for r, obj in enumerate(self.__objects): ma[r] = self.__objects[obj]["max"] mi[r] = self.__objects[obj]["min"] ma = np.max(ma, axis=0) mi = np.min(mi, axis=0) diag = np.linalg.norm(ma-mi) mean = (ma - mi) / 2 + mi for r, obj in enumerate(self.__objects): v = self.__objects[obj]["geometry"].attributes["position"].array v -= mean scale = self.__s["scale"] * (diag) self._orbit.target = [0.0, 0.0, 0.0] self._cam.lookAt([0.0, 0.0, 0.0]) self._cam.position = [0.0, 0.0, scale] self._light.position = [0.0, 0.0, scale] state = embed.dependency_state(self._renderer) # Somehow these entries are missing when the state is exported in python. # Exporting from the GUI works, so we are inserting the missing entries. for k in state: if state[k]["model_name"] == "OrbitControlsModel": state[k]["state"]["maxAzimuthAngle"] = "inf" state[k]["state"]["maxDistance"]= "inf" state[k]["state"]["maxZoom"]= "inf" state[k]["state"]["minAzimuthAngle"] = "-inf" tpl = embed.load_requirejs_template if not imports: embed.load_requirejs_template = "" s = embed.embed_snippet(self._renderer, state=state) #s = embed.embed_snippet(self.__w, state=state) embed.load_requirejs_template = tpl if html_frame: s = "<html>\n<body>\n" + s + "\n</body>\n</html>" # Revert changes for r, obj in enumerate(self.__objects): v = self.__objects[obj]["geometry"].attributes["position"].array v += mean self.__update_view() return s
def ipywidget_state(widgets): from jinja2 import Markup from ipywidgets import embed as wembed drop_defaults = True state = wembed.dependency_state(widgets, drop_defaults=drop_defaults) from ipywidgets import Widget json_data = Widget.get_manager_state(widgets=[]) json_data['state'] = state json_data_str = json.dumps(json_data, indent=' ') snippet = wembed.snippet_template.format(load='', widget_views='', json_data=json_data_str) return Markup(snippet)
def test_minimal_pileup_html(self): track = pileup.Track(viz="pileup", label="myReads", source=pileup.sources.GA4GHAlignmentJson('{}')) w = pileup.PileupViewer(locus="chr17:1-250", reference="hg19", tracks=[track]) output = StringIO() state = dependency_state(w, drop_defaults=True) embed_minimal_html(output, views=w, drop_defaults=True, state=state) content = output.getvalue() assert content.splitlines()[0] == '<!DOCTYPE html>'
def test_snippet(self): class Parser(HTMLParser): state = 'initial' states = [] def handle_starttag(self, tag, attrs): attrs = dict(attrs) if tag == 'script' and attrs.get( 'type', '') == "application/vnd.jupyter.widget-state+json": self.state = 'widget-state' self.states.append(self.state) elif tag == 'script' and attrs.get( 'type', '') == "application/vnd.jupyter.widget-view+json": self.state = 'widget-view' self.states.append(self.state) def handle_endtag(self, tag): self.state = 'initial' def handle_data(self, data): if self.state == 'widget-state': manager_state = json.loads(data)['state'] assert len(manager_state) == 2 self.states.append('check-widget-state') elif self.state == 'widget-view': view = json.loads(data) assert isinstance(view, dict) self.states.append('check-widget-view') track = pileup.Track(viz="variants", label="myVariants", source=pileup.sources.GA4GHVariantJson('{}')) w = pileup.PileupViewer(chrom="chr17", start=1, stop=250, reference="hg19", tracks=[track]) state = dependency_state(w, drop_defaults=True) snippet = embed_snippet(views=w, drop_defaults=True, state=state) parser = Parser() parser.feed(snippet) assert parser.states == [ 'widget-state', 'check-widget-state', 'widget-view', 'check-widget-view' ]
def test_embed_variants(self): w = pileup.Variants(json="{}", build='hg19', contig='chr1', start=1, stop=20) state = dependency_state(w, drop_defaults=True) data = embed_data(views=w, drop_defaults=True, state=state) state = data['manager_state']['state'] views = data['view_specs'] assert len(views) == 1 model_names = [s['model_name'] for s in state.values()] assert 'VariantModel' in model_names
def test_snippet(self): class Parser(HTMLParser): state = 'initial' states = [] def handle_starttag(self, tag, attrs): attrs = dict(attrs) if tag == 'script' and attrs.get( 'type', '') == "application/vnd.jupyter.widget-state+json": self.state = 'widget-state' self.states.append(self.state) elif tag == 'script' and attrs.get( 'type', '') == "application/vnd.jupyter.widget-view+json": self.state = 'widget-view' self.states.append(self.state) def handle_endtag(self, tag): self.state = 'initial' def handle_data(self, data): if self.state == 'widget-state': manager_state = json.loads(data)['state'] assert len(manager_state) == 2 self.states.append('check-widget-state') elif self.state == 'widget-view': view = json.loads(data) assert isinstance(view, dict) self.states.append('check-widget-view') w = pileup.Reads(json="{}", build='hg19', contig='chr1', start=1, stop=20) state = dependency_state(w, drop_defaults=True) snippet = embed_snippet(views=w, drop_defaults=True, state=state) parser = Parser() parser.feed(snippet) assert parser.states == [ 'widget-state', 'check-widget-state', 'widget-view', 'check-widget-view' ]
def test_embed_pileup(self): track = pileup.Track(viz="features", label="myFeatures", source=pileup.sources.GA4GHFeatureJson('{}')) w = pileup.PileupViewer(locus="chr17:1-250", reference="hg19", tracks=[track]) state = dependency_state(w, drop_defaults=True) data = embed_data(views=w, drop_defaults=True, state=state) state = data['manager_state']['state'] views = data['view_specs'] assert len(views) == 1 model_names = [s['model_name'] for s in state.values()] assert 'PileupViewerModel' in model_names
def test_embed_data_two_widgets(self): w1 = pileup.Variants(json="{}", build='hg19', contig='chr1', start=1, stop=20) w2 = pileup.Features(json="{}", build='hg19', contig='chr1', start=1, stop=20) jslink((w1, 'start'), (w2, 'start')) state = dependency_state([w1, w2], drop_defaults=True) data = embed_data(views=[w1, w2], drop_defaults=True, state=state) state = data['manager_state']['state'] views = data['view_specs'] assert len(views) == 2 model_names = [s['model_name'] for s in state.values()] assert 'VariantModel' in model_names assert 'FeatureModel' in model_names
def generate_html(widgets, title, path, makedirs=True, all_states=False, offline=False, drop_defaults=False, template_options=(("extra_script_head", ""), ("body_pre", ""), ("body_post", "")), devmode=False, offline_cors=False, only_body=False, as_dict=False,): """ Write a minimal HTML file with widget views embedded. :type filepath: str :param filepath: The file to write the HTML output to. :type widgets: widget or collection of widgets or None :param widgets:The widgets to include views for. If None, all DOMWidgets are included (not just the displayed ones). :param makedirs: whether to make directories in the filename path, if they do not already exist :param title: title for the html page :param all_states: if True, the state of all widgets know to the widget manager is included, else only those in widgets :param offline: if True, use local urls for required js/css packages and download all js/css required packages (if not already available), such that the html can be viewed with no internet connection :param scripts_path: the directory to save required js/css packages to (relative to the filepath) :type drop_defaults: bool :param drop_defaults: Whether to drop default values from the widget states :param template: template string for the html, must contain at least {title} and {snippet} place holders :param template_options: list or dict of additional template options :param devmode: if True, attempt to get index.js from local js/dist directory :param devmode: if True, attempt to get index.js from local js/dist folder :param offline_cors: if True, sets crossorigin attribute to anonymous, this allows for the return of error data from js scripts but can block local loading of the scripts in some browsers """ #dir_name_dst = os.path.dirname(os.path.abspath(filepath)) #if not os.path.exists(dir_name_dst) and makedirs: os.makedirs(dir_name_dst) template_opts = {"extra_script_head": "", "body_pre": "", "body_post": ""} template_opts.update(dict(template_options)) if all_states: state = None else: state = wembed.dependency_state(widgets, drop_defaults=drop_defaults) # if not offline: # # # we have to get the snippet (rather than just call embed_minimal_html), because if the new template includes # # {} characters (such as in the bokeh example) then an error is raised when trying to format # snippet = wembed.embed_snippet(widgets, state=state, requirejs=True, drop_defaults=drop_defaults) # directory = os.path.dirname(filepath) #else: if True: #if not os.path.isabs(scripts_path): # scripts_path = os.path.join(os.path.dirname(filepath), scripts_path) # ensure script path is above filepath # rel_script_path = os.path.relpath(scripts_path, os.path.dirname(filepath)) # if rel_script_path.startswith(".."): # raise ValueError("The scripts_path must have the same root directory as the filepath") # elif rel_script_path=='.': # rel_script_path = '' # else: # rel_script_path += '/' scripts_path = path rel_script_path = path if not rel_script_path.endswith("/"): rel_script_path += "/" fname_pyv = save_ipyvolumejs(scripts_path, devmode=devmode) fname_require = save_requirejs(os.path.join(scripts_path)) fname_embed = save_embed_js(os.path.join(scripts_path)) fname_fontawe = save_font_awesome(os.path.join(scripts_path)) subsnippet = wembed.embed_snippet(widgets, embed_url=rel_script_path+fname_embed, requirejs=False, drop_defaults=drop_defaults, state=state) if not offline_cors: # TODO DIRTY hack, we need to do this cleaner upstream subsnippet = subsnippet.replace(' crossorigin="anonymous"', '') cors_attribute = 'crossorigin="anonymous"' if offline_cors else ' ' snippet = """ <link href="{rel_script_path}{fname_fontawe}/css/font-awesome.min.css" rel="stylesheet"> <script src="{rel_script_path}{fname_require}"{cors} data-main='./{rel_script_path}' ></script> <script> require.config({{ map: {{ '*': {{ 'ipyvolume': '{fname_pyv}', }} }}}}) </script> {subsnippet} """.format(rel_script_path=rel_script_path, fname_fontawe=fname_fontawe, fname_require=fname_require, fname_pyv=os.path.splitext(fname_pyv)[0], subsnippet=subsnippet, cors=cors_attribute) # Generate HTML template_opts['snippet'] = snippet template_opts['title'] = title # Give if as_dict: return template_opts elif only_body: html_code = html_body_template.format(**template_opts) return html_code else: html_code = html_template.format(**template_opts) return html_code
def embed_html( filepath, widgets, makedirs=True, title=u'IPyVolume Widget', all_states=False, offline=False, scripts_path='js', drop_defaults=False, template=html_template, template_options=(("extra_script_head", ""), ("body_pre", ""), ("body_post", "")), devmode=False, offline_cors=False, ): """Write a minimal HTML file with widget views embedded. :param str filepath: The file to write the HTML output to. :type widgets: widget or collection of widgets or None :param widgets:The widgets to include views for. If None, all DOMWidgets are included (not just the displayed ones). :param makedirs: whether to make directories in the filename path, if they do not already exist :param title: title for the html page :param all_states: if True, the state of all widgets know to the widget manager is included, else only those in widgets :param offline: if True, use local urls for required js/css packages and download all js/css required packages (if not already available), such that the html can be viewed with no internet connection :param scripts_path: the directory to save required js/css packages to (relative to the filepath) :param bool drop_defaults: Whether to drop default values from the widget states :param template: template string for the html, must contain at least {title} and {snippet} place holders :param template_options: list or dict of additional template options :param devmode: if True, attempt to get index.js from local js/dist directory :param devmode: if True, attempt to get index.js from local js/dist folder :param offline_cors: if True, sets crossorigin attribute to anonymous, this allows for the return of error data from js scripts but can block local loading of the scripts in some browsers """ dir_name_dst = os.path.dirname(os.path.abspath(filepath)) if not os.path.exists(dir_name_dst) and makedirs: os.makedirs(dir_name_dst) template_opts = {"extra_script_head": "", "body_pre": "", "body_post": ""} template_opts.update(dict(template_options)) if all_states: state = None else: state = wembed.dependency_state(widgets, drop_defaults=drop_defaults) if not offline: # we have to get the snippet (rather than just call embed_minimal_html), because if the new template includes # {} characters (such as in the bokeh example) then an error is raised when trying to format snippet = wembed.embed_snippet(widgets, state=state, requirejs=True, drop_defaults=drop_defaults) else: if not os.path.isabs(scripts_path): scripts_path = os.path.join(os.path.dirname(filepath), scripts_path) # ensure script path is above filepath rel_script_path = os.path.relpath(scripts_path, os.path.dirname(filepath)) if rel_script_path.startswith(".."): raise ValueError("The scripts_path must have the same root directory as the filepath") elif rel_script_path == '.': rel_script_path = '' else: rel_script_path += '/' fname_pyv = save_ipyvolumejs(scripts_path, devmode=devmode) fname_require = save_requirejs(os.path.join(scripts_path)) fname_embed = save_embed_js(os.path.join(scripts_path)) fname_fontawe = save_font_awesome(os.path.join(scripts_path)) subsnippet = wembed.embed_snippet( widgets, embed_url=rel_script_path + fname_embed, requirejs=False, drop_defaults=drop_defaults, state=state ) if not offline_cors: # TODO DIRTY hack, we need to do this cleaner upstream subsnippet = subsnippet.replace(' crossorigin="anonymous"', '') cors_attribute = 'crossorigin="anonymous"' if offline_cors else ' ' snippet = """ <link href="{rel_script_path}{fname_fontawe}/css/font-awesome.min.css" rel="stylesheet"> <script src="{rel_script_path}{fname_require}"{cors} data-main='./{rel_script_path}' ></script> <script> require.config({{ map: {{ '*': {{ 'ipyvolume': '{fname_pyv}', }} }}}}) </script> {subsnippet} """.format( rel_script_path=rel_script_path, fname_fontawe=fname_fontawe, fname_require=fname_require, fname_pyv=os.path.splitext(fname_pyv)[0], subsnippet=subsnippet, cors=cors_attribute, ) template_opts['snippet'] = snippet template_opts['title'] = title html_code = template.format(**template_opts) with io.open(filepath, "w", encoding='utf8') as f: f.write(html_code)
activity_data = activity_data.dropna() locations = list( zip(activity_data.latitude_degrees.values, activity_data.longitude_degrees.values)) # Create Map from ipyleaflet import Map, Marker, AntPath center = (34.1137553, -118.2001699) m = Map(center=center, zoom=12) marker = Marker(location=center, draggable=False) m.add_layer(marker) ant_path = AntPath(locations=locations, dash_array=[1, 10], delay=1000, color='#7590ba', pulse_color='#3f6fba') m.add_layer(ant_path) # Export Map into HTML from ipywidgets.embed import embed_minimal_html, dependency_state embed_minimal_html('export.html', views=[m], state=dependency_state([m]))