Commit 0f7d671a authored by lambdamusic's avatar lambdamusic

activated 'alpha' dataviz

parent c266a086
......@@ -2,6 +2,11 @@
Summary of changes.
## December, 2018: v1.9.8
- small bug fixes
- refactor action visualize / activated 'alpha' dataviz
## December, 2018: v1.9.7
- removed support for Python 2
......
......@@ -97,6 +97,127 @@ Ontospy is a command line inspector for RDF/OWL models. Use the --help option wi
# click.echo('I am about to invoke %s' % ctx.invoked_subcommand)
##
## GENDOCS COMMAND (wrapper around ontodocs)
##
@main_cli.command()
@click.argument('source', nargs=-1)
@click.option(
'--outputpath',
'-o',
help=
'OUTPUT-PATH: where to save the visualization files (default: home folder).'
)
@click.option(
'--type',
help=
'VIZ-TYPE: specify which viz type to use as an integer (eg 1=single-page html, 2=multi-page etc..).'
)
@click.option(
'--title',
help='TITLE: custom title for the visualization (default=graph uri).')
@click.option(
'--theme',
help=
'THEME: bootstrap css style for the html-multi-page visualization (random=use a random theme).'
)
@click.option(
'--lib',
is_flag=True,
help='LIBRARY: choose an ontology from the local library.')
@click.option(
'--showtypes',
is_flag=True,
help='SHOW-TYPES: show the available visualization types.')
@click.option(
'--showthemes',
is_flag=True,
help='SHOW-THEMES: show the available css theme choices.')
@click.pass_context
def gendocs(ctx,
source=None,
outputpath="",
lib=False,
type="",
title="",
theme="",
showthemes=False,
showtypes=False):
"""Generate documentation for an ontology in html or markdown format
"""
verbose = ctx.obj['VERBOSE']
sTime = ctx.obj['STIME']
print_opts = {
'labels': verbose,
}
from .ontodocs.builder import show_themes, random_theme, show_types
try:
# check that we have the required dependencies
import django
except:
click.secho(
"WARNING: this functionality requires the Django package and other extra dependecies.",
fg="red")
click.secho("Install with `pip install ontospy[HTML] -U`")
sys.exit(0)
if not source and not showthemes and not showtypes and not lib:
click.echo(ctx.get_help())
return
if showthemes:
show_themes()
sys.exit(0)
if showtypes:
show_types()
sys.exit(0)
if theme and theme == "random":
theme = random_theme()
if outputpath:
if not (os.path.exists(outputpath)) or not (os.path.isdir(outputpath)):
click.secho(
"WARNING: the -o option must include a valid directory path.",
fg="red")
sys.exit(0)
if source and len(source) > 1:
click.secho(
'Note: currently only one argument can be passed', fg='red')
if lib:
click.secho("Local library => '%s'" % get_home_location(), fg='white')
ontouri = action_listlocal(all_details=False)
if ontouri:
source = [os.path.join(get_home_location(), ontouri)]
else:
raise SystemExit(1)
# note: the local ontospy library gets displayed via this method too
url = action_visualize(
source,
fromshell=False,
path=outputpath,
title=title,
viztype=type,
theme=theme,
verbose=verbose)
if url: # open browser
import webbrowser
webbrowser.open(url)
eTime = time.time()
tTime = eTime - sTime
printDebug("\n-----------\n" + "Time: %0.2fs" % tTime, "comment")
##
## LIBRARY COMMAND
##
......@@ -382,90 +503,6 @@ if __name__ == '__main__':
except KeyboardInterrupt as e: # Ctrl-C
raise e
##
## GENDOCS COMMAND (wrapper around ontodocs)
##
@main_cli.command()
@click.argument('source', nargs=-1)
@click.option('--outputpath', '-o', help='Output path (default: home folder).')
@click.option(
'--title', '-t', help='Title for the visualization (default=graph uri).')
@click.option(
'--theme',
help=
'CSS Theme for the html-complex visualization (random=use a random theme).'
)
@click.option(
'--showthemes', is_flag=True, help='Show the available CSS theme choices.')
@click.pass_context
def gendocs(ctx,
source=None,
outputpath="",
title="",
theme="",
showthemes=False):
"""Generate documentation for an ontology in html or markdown format
"""
verbose = ctx.obj['VERBOSE']
sTime = ctx.obj['STIME']
print_opts = {
'labels': verbose,
}
from .ontodocs.builder import action_visualize, show_themes, random_theme
try:
# check that we have the required dependencies
import django
except:
click.secho(
"WARNING: this functionality requires the Django package and other extra dependecies.",
fg="red")
click.secho("Install with `pip install ontospy[HTML] -U`")
sys.exit(0)
if not source and not showthemes:
click.echo(ctx.get_help())
return
if showthemes:
show_themes()
sys.exit(0)
if theme and theme == "random":
theme = ontodocs.random_theme()
if outputpath:
if not (os.path.exists(outputpath)) or not (os.path.isdir(outputpath)):
click.secho(
"WARNING: the -o option must include a valid directory path.",
fg="red")
sys.exit(0)
if source and len(source) > 1:
click.secho(
'Note: currently only one argument can be passed', fg='red')
# note: the local ontospy library gets displayed via this method too
url = action_visualize(
source,
fromshell=False,
path=outputpath,
title=title,
theme=theme,
verbose=verbose)
if url: # open browser
import webbrowser
webbrowser.open(url)
eTime = time.time()
tTime = eTime - sTime
printDebug("\n-----------\n" + "Time: %0.2fs" % tTime, "comment")
if __name__ == '__main__':
import sys
try:
......
......@@ -599,3 +599,55 @@ def action_erase():
"""
get_or_create_home_repo(reset=True)
return True
def action_visualize(args,
fromshell=False,
path=None,
title="",
viztype="",
theme="",
verbose=False):
"""
export model into another format eg html, d3 etc...
<fromshell> : the local name is being passed from ontospy shell
"""
from ..ontodocs.builder import ask_visualization, select_visualization, VISUALIZATIONS_LIST, build_visualization
if fromshell:
ontouri = args
islocal = True
else:
ontouri = args[0]
islocal = False
# select a visualization
if viztype:
viztype = select_visualization(viztype)
else:
viztype = ask_visualization()
if viztype == "":
return None
# raise SystemExit, 1
# 2017-01-23: bypass pickled stuff as it has wrong counts etc..
# get ontospy graph
printDebug("Loading graph...", dim=True)
g = Ontospy(ontouri, verbose=verbose)
# put in home folder by default: <ontouri>/<viztype>/files..
if not path:
from os.path import expanduser
home = expanduser("~")
onto_path = slugify(unicode(ontouri))
viz_path = slugify(unicode(VISUALIZATIONS_LIST[viztype]['Title']))
path = os.path.join(home, "ontospy-viz/" + onto_path + "/" + viz_path)
if not os.path.exists(path):
os.makedirs(path)
# url = build_viz(ontouri, g, viztype, path)
printDebug("Building visualization...", dim=True)
url = build_visualization(ontouri, g, viztype, path, title, theme)
return url
......@@ -2,29 +2,62 @@
# -*- coding: utf-8 -*-
VISUALIZATIONS_LIST = {
"Visualizations":
[{
"Visualizations": [{
"ID": "html-simple",
"Title": "Html: single-page",
"Title": "Html: single page",
"Description": "@todo",
} , {
"ID": "html-complex",
"Title": "Html: multi-page",
"Description": "@todo",
} , {
"ID": "markdown",
"Title": "Markdown: multi-page",
"Description": "@todo",
} , {
"ID": "d3-tree",
"Title": "D3 Dendogram",
"Description": "@todo",
}
]
},
{
"ID": "html-complex",
"Title": "Html: multi page",
"Description": "@todo",
},
{
"ID": "markdown",
"Title": "Markdown: multi page",
"Description": "@todo",
},
{
"ID": "d3-tree",
"Title": "D3 Dendogram",
"Description": "@todo",
},
{
"ID": "d3-bubble-chart",
"Title": "D3 Bubble chart [alpha]",
"Description": "@todo",
},
{
"ID": "d3-pack-hierarchy",
"Title": "D3 Pack hierarchy [alpha]",
"Description": "@todo",
},
{
"ID": "d3-bar-hierarchy",
"Title": "D3 Bar hierarchy [alpha]",
"Description": "@todo",
},
{
"ID": "d3-partition-table",
"Title": "D3 Partition table [alpha]",
"Description": "@todo",
},
{
"ID": "d3-rotating-cluster",
"Title": "D3 Rotating cluster [alpha]",
"Description": "@todo",
},
{
"ID": "sigma-force-directed",
"Title": "Sigma.js Force directed graph [alpha]",
"Description": "@todo",
}]
}
BOOTSWATCH_THEMES = ['cerulean' , 'flatly' , 'lumen' , 'sandstone' , 'spacelab' , 'yeti' , 'cosmo' , 'darkly' , 'paper' , 'simplex' , 'superhero' , 'readable' , 'slate' , 'united']
BOOTSWATCH_THEMES = [
'cerulean', 'flatly', 'lumen', 'sandstone', 'spacelab', 'yeti', 'cosmo',
'darkly', 'paper', 'simplex', 'superhero', 'readable', 'slate', 'united'
]
BOOTSWATCH_THEME_DEFAULT = "simplex"
# 'cyborg' , 'journal'
......@@ -81,6 +81,13 @@ except: # Mother of all exceptions
raise
def show_types():
for n, t in enumerate(VISUALIZATIONS_LIST):
printDebug("%d. %s" % (n + 1, t['Title']), "green")
printDebug("Note: select a viz type by using its numerical index.",
"comment")
def show_themes():
for t in BOOTSWATCH_THEMES:
printDebug(t, "green")
......@@ -127,71 +134,18 @@ def ask_visualization():
continue
# MAIN METHOD
def action_visualize(args,
fromshell=False,
path=None,
title="",
theme="",
verbose=False):
def select_visualization(n):
"""
export model into another format eg html, d3 etc...
<fromshell> : the local name is being passed from ontospy shell
get viz choice based on numerical index
"""
# get argument
if not (args):
ontouri = ontospy_actions.action_listlocal(all_details=False)
if ontouri:
islocal = True
else:
raise SystemExit(1)
elif fromshell:
ontouri = args
islocal = True
else:
ontouri = args[0]
islocal = False
# select a visualization
viztype = ask_visualization()
if viztype == "":
return None
# raise SystemExit, 1
# 2017-01-23: bypass pickled stuff as it has wrong counts etc..
USE_CACHE = False
# get ontospy graph
if islocal and USE_CACHE:
g = get_pickled_ontology(ontouri)
if not g:
g = do_pickle_ontology(ontouri)
else:
printDebug("Loading graph...", dim=True)
if islocal:
g = Ontospy(
os.path.join(ontospy_manager.get_home_location(), ontouri),
verbose=verbose)
else:
g = Ontospy(ontouri, verbose=verbose)
# put in home folder by default: <ontouri>/<viztype>/files..
if not path:
from os.path import expanduser
home = expanduser("~")
onto_path = slugify(unicode(ontouri))
viz_path = slugify(unicode(VISUALIZATIONS_LIST[viztype]['Title']))
path = os.path.join(home, "ontospy-viz/" + onto_path + "/" + viz_path)
if not os.path.exists(path):
os.makedirs(path)
# url = build_viz(ontouri, g, viztype, path)
printDebug("Building visualization...", dim=True)
url = build_visualization(ontouri, g, viztype, path, title, theme)
return url
try:
n = int(n) - 1
test = VISUALIZATIONS_LIST[n] # throw exception if number wrong
return n
except:
printDebug("Invalid viz-type option. Valid options are:", "red")
show_types()
raise SystemExit(1)
# ===========
......@@ -224,8 +178,32 @@ def build_visualization(ontouri, g, viz_index, path=None, title="", theme=""):
v = MarkdownViz(g, title)
elif this_viz['ID'] == "d3-tree":
from .viz.viz_d3tree import D3TreeViz
v = D3TreeViz(g, title)
from .viz.viz_d3tree import Dataviz
v = Dataviz(g, title)
elif this_viz['ID'] == "d3-bubble-chart":
from .viz.viz_d3bubbleChart import Dataviz
v = Dataviz(g, title)
elif this_viz['ID'] == "d3-pack-hierarchy":
from .viz.viz_d3packHierarchy import Dataviz
v = Dataviz(g, title)
elif this_viz['ID'] == "d3-bar-hierarchy":
from .viz.viz_d3barHierarchy import Dataviz
v = Dataviz(g, title)
elif this_viz['ID'] == "d3-partition-table":
from .viz.viz_d3partitionTable import Dataviz
v = Dataviz(g, title)
elif this_viz['ID'] == "d3-rotating-cluster":
from .viz.viz_d3rotatingCluster import Dataviz
v = Dataviz(g, title)
elif this_viz['ID'] == "sigma-force-directed":
from .viz.viz_sigmajs import Dataviz
v = Dataviz(g, title)
else:
return False
......@@ -257,7 +235,7 @@ def saveVizGithub(contents, ontouri):
'content':
"""The MIT License (MIT)
Copyright (c) 2016 OntoSpy project [http://ontospy.readthedocs.org/]
Copyright (c) 2016 OntoSpy project [http://lambdamusic.github.io/Ontospy//]
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
......
......@@ -67,7 +67,7 @@
<h1 class="title">Ontology:&nbsp;<a href="javascript:showpanel('ontoinfo');">{{main_uri}}</a></h1>
<h3>{{ontology.bestDescription}}</h3>
<p><small>Ontology documentation automatically generated by <a class="greylink" href="http://ontospy.readthedocs.org/">OntoSpy</a> on {% now "jS F Y H:i" %}</small></p>
<p><small>Ontology documentation automatically generated by <a class="greylink" href="http://lambdamusic.github.io/Ontospy//">OntoSpy</a> on {% now "jS F Y H:i" %}</small></p>
<hr>
......
......@@ -72,7 +72,7 @@ circle.child:hover {
<h1 class="title">Ontology:&nbsp;<a href="javascript:showpanel('ontoinfo');">{{main_uri}}</a></h1>
<h3>{{ontology.bestDescription}}</h3>
<p><small>Ontology documentation automatically generated by <a class="greylink" href="http://ontospy.readthedocs.org/">OntoSpy</a> on {% now "jS F Y H:i" %}</small></p>
<p><small>Ontology documentation automatically generated by <a class="greylink" href="http://lambdamusic.github.io/Ontospy//">OntoSpy</a> on {% now "jS F Y H:i" %}</small></p>
<hr>
......
......@@ -162,7 +162,7 @@ circle.child:hover {
<h1 class="title">Ontology:&nbsp;<a href="javascript:showpanel('ontoinfo');">{{main_uri}}</a></h1>
<h3>{{ontology.bestDescription}}</h3>
<p><small>Ontology documentation automatically generated by <a class="greylink" href="http://ontospy.readthedocs.org/">OntoSpy</a> on {% now "jS F Y H:i" %}</small></p>
<p><small>Ontology documentation automatically generated by <a class="greylink" href="http://lambdamusic.github.io/Ontospy//">OntoSpy</a> on {% now "jS F Y H:i" %}</small></p>
<hr>
......
......@@ -140,7 +140,7 @@ text {
<h1 class="title">Ontology:&nbsp;<a href="javascript:showpanel('ontoinfo');">{{main_uri}}</a></h1>
<h3>{{ontology.bestDescription}}</h3>
<p><small>Ontology documentation automatically generated by <a class="greylink" href="http://ontospy.readthedocs.org/">OntoSpy</a> on {% now "jS F Y H:i" %}</small></p>
<p><small>Ontology documentation automatically generated by <a class="greylink" href="http://lambdamusic.github.io/Ontospy//">OntoSpy</a> on {% now "jS F Y H:i" %}</small></p>
<hr>
......
......@@ -91,7 +91,7 @@ circle.child:hover {
<h1 class="title">Ontology:&nbsp;<a href="javascript:showpanel('ontoinfo');">{{main_uri}}</a></h1>
<h3>{{ontology.bestDescription}}</h3>
<p><small>Ontology documentation automatically generated by <a class="greylink" href="http://ontospy.readthedocs.org/">OntoSpy</a> on {% now "jS F Y H:i" %}</small></p>
<p><small>Ontology documentation automatically generated by <a class="greylink" href="http://lambdamusic.github.io/Ontospy//">OntoSpy</a> on {% now "jS F Y H:i" %}</small></p>
<hr>
......
......@@ -56,7 +56,7 @@
<h1 class="title">Ontology:&nbsp;<a href="javascript:showpanel('ontoinfo');">{{main_uri}}</a></h1>
<h3>{{ontology.bestDescription}}</h3>
<p><small>Ontology documentation automatically generated by <a class="greylink" href="http://ontospy.readthedocs.org/">OntoSpy</a> on {% now "jS F Y H:i" %}</small></p>
<p><small>Ontology documentation automatically generated by <a class="greylink" href="http://lambdamusic.github.io/Ontospy//">OntoSpy</a> on {% now "jS F Y H:i" %}</small></p>
<hr>
......
......@@ -58,7 +58,7 @@
<h1 class="title">Ontology:&nbsp;<a href="javascript:showpanel('ontoinfo');">{{main_uri}}</a></h1>
<h3>{{ontology.bestDescription}}</h3>
<p><small class="credits">Ontology documentation automatically generated with <a class="greylink" href="http://ontospy.readthedocs.org/" target="_blank">OntoSpy</a> on {% now "jS F Y H:i" %}</small></p>
<p><small class="credits">Ontology documentation automatically generated with <a class="greylink" href="http://lambdamusic.github.io/Ontospy//" target="_blank">OntoSpy</a> on {% now "jS F Y H:i" %}</small></p>
......
### How To add a new viz
- add .py file named as 'viz_%s'
- add .html templates (if in new folder, updated also settings.TEMPLATES in builder.py)
- update catalogue in `CONFIG.py`
- add .py file named as 'viz\_%s'
- add .html templates (if in new folder, updated also settings.TEMPLATES in builder.py)
- update catalogue in `CONFIG.py`
### Testing locally
### Testing locally
- ```python -m ontodocs.viz.viz_d3barHierarchy``` picks a random ontology and runs the script
\ No newline at end of file
- `python -m ontospy.ontodocs.viz.viz_d3barHierarchy` picks a random ontology and runs the script
......@@ -13,7 +13,7 @@ from ..viz_factory import VizFactory
# ===========
class D3BarHierarchyViz(VizFactory):
class Dataviz(VizFactory):
"""
D3 Bar HierarchyViz
......@@ -23,7 +23,7 @@ class D3BarHierarchyViz(VizFactory):
"""
Init
"""
super(D3BarHierarchyViz, self).__init__(ontospy_graph, title)
super(Dataviz, self).__init__(ontospy_graph, title)
self.static_files = ["libs/d3-v3", "libs/jquery"]
def _buildTemplates(self):
......@@ -64,7 +64,7 @@ if __name__ == '__main__':
g = get_onto_for_testing(TEST_ONLINE)
v = D3BarHierarchyViz(g, title="")
v = Dataviz(g, title="")
v.build()
v.preview()
......
......@@ -13,7 +13,7 @@ from ..viz_factory import VizFactory
# ===========
class D3BubbleChartViz(VizFactory):
class Dataviz(VizFactory):
"""
D3 Bubbles
......@@ -23,7 +23,7 @@ class D3BubbleChartViz(VizFactory):
"""
Init
"""
super(D3BubbleChartViz, self).__init__(ontospy_graph, title)
super(Dataviz, self).__init__(ontospy_graph, title)
self.static_files = ["libs/d3-v3", "libs/jquery"]
def _buildTemplates(self):
......@@ -64,7 +64,7 @@ if __name__ == '__main__':
g = get_onto_for_testing(TEST_ONLINE)
v = D3BubbleChartViz(g, title="")
v = Dataviz(g, title="")
v.build()
v.preview()
......
......@@ -8,68 +8,59 @@ from ..utils import *
from ..builder import * # loads and sets up Django
from ..viz_factory import VizFactory
# TEMPLATE: D3 PACK HIERARCHY
# http://mbostock.github.io/d3/talk/20111116/pack-hierarchy.html
# https://github.com/d3/d3/wiki/Pack-Layout
# http://bl.ocks.org/nilanjenator/4950148
class D3PackHierarchyViz(VizFactory):
class Dataviz(VizFactory):
"""
D3 PackHierarchyViz
"""
def __init__(self, ontospy_graph, title=""):
"""
Init
"""
super(D3PackHierarchyViz, self).__init__(ontospy_graph, title)
super(Dataviz, self).__init__(ontospy_graph, title)
self.static_files = ["libs/d3-v3", "libs/jquery"]
def _buildTemplates(self):
"""
OVERRIDING THIS METHOD from Factory
"""
jsontree_classes = build_D3treeStandard(0, 99, 1, self.ontospy_graph.toplayer_classes)
jsontree_classes = build_D3treeStandard(
0, 99, 1, self.ontospy_graph.toplayer_classes)
c_total = len(self.ontospy_graph.all_classes)
if len(self.ontospy_graph.toplayer_classes) == 1:
# the first element can be the single top level
JSON_DATA_CLASSES = json.dumps(jsontree_classes[0])
else:
# hack to make sure that we have a default top level object
JSON_DATA_CLASSES = json.dumps({'children': jsontree_classes, 'name': 'owl:Thing',})
JSON_DATA_CLASSES = json.dumps({
'children': jsontree_classes,
'name': 'owl:Thing',
})
extra_context = {
"ontograph": self.ontospy_graph,
"TOTAL_CLASSES": c_total,
'JSON_DATA_CLASSES' : JSON_DATA_CLASSES,
}
"ontograph": self.ontospy_graph,
"TOTAL_CLASSES": c_total,
'JSON_DATA_CLASSES': JSON_DATA_CLASSES,
}
# Ontology - MAIN PAGE
contents = self._renderTemplate("d3/d3_packHierarchy.html", extraContext=extra_context)
contents = self._renderTemplate(
"d3/d3_packHierarchy.html", extraContext=extra_context)
FILE_NAME = "index.html"
main_url = self._save2File(contents, FILE_NAME, self.output_path)
return main_url
# if called directly, for testing purposes pick a random ontology
if __name__ == '__main__':
......@@ -79,7 +70,7 @@ if __name__ == '__main__':
g = get_onto_for_testing(TEST_ONLINE)
v = D3PackHierarchyViz(g, title="")