Skip to content

Commit

Permalink
Adding a command to load a sample dataset
Browse files Browse the repository at this point in the history
  • Loading branch information
mistercrunch committed Sep 19, 2015
1 parent 4edbbd3 commit e0d6d20
Show file tree
Hide file tree
Showing 7 changed files with 180 additions and 76 deletions.
10 changes: 5 additions & 5 deletions README.md
Expand Up @@ -7,7 +7,7 @@ and interactive.
Buzz Phrases
------------

* Analytics at the speed of thought!
* Analytics at the speed of thought!
* Instantaneous learning curve
* Realtime analytics when querying [Druid.io](http://druid.io)
* Extentsible to infinity
Expand Down Expand Up @@ -67,11 +67,11 @@ pip install panoramix
# Create an admin user
fabmanager create-admin --app panoramix
# Clone the github repo
git clone https://github.com/mistercrunch/panoramix.git
# Load some data to play with
panoramix load_examples
# Start the web server
panoramix
# Start the development web server
panoramix runserver -d
```

After installation, you should be able to point your browser to the right
Expand Down
67 changes: 65 additions & 2 deletions panoramix/bin/panoramix
Expand Up @@ -4,6 +4,12 @@ from flask.ext.script import Manager
from panoramix import app, config
from subprocess import Popen
from flask.ext.migrate import MigrateCommand
from panoramix import db
from flask.ext.appbuilder import Base
from sqlalchemy import Column, Integer, String
from panoramix import config, models
import csv
import gzip


manager = Manager(app)
Expand Down Expand Up @@ -33,9 +39,66 @@ def runserver(debug, port):
Popen(cmd, shell=True).wait()

@manager.command
def load_examples(self):
def load_examples():
"""Loads a set of Slices and Dashboards and a supporting dataset """
print("Loading examples")
print("Loading examples into {}".format(db))
class BirthNames(Base):
__tablename__ = "birth_names"
id = Column(Integer, primary_key=True)
state = Column(String(10))
year = Column(Integer)
name = Column(String(128))
num = Column(Integer)
ds = Column(String(20))
gender = Column(String(10))
try:
BirthNames.__table__.drop(db.engine)
except:
pass
Base.metadata.create_all(db.engine)
session = db.session()

with gzip.open(config.basedir + '/data/birth_names.csv.gz') as f:
bb_csv = csv.reader(f)
for i, (state, year, name, num, gender) in enumerate(bb_csv):
if i == 0 or not name or name=="\xc2\xa0":
continue
if num == "NA":
num = 0
ds = str(year) + '-01-01'
session.add(
BirthNames(
state=state, year=year,
ds=ds,
name=name, num=num, gender=gender))
if i % 1000 == 0:
print("{} loaded out of 502619 rows".format(i))
session.commit()
session.commit()
print("Done loading table!")
DB = models.Database
dbobj = session.query(DB).filter_by(database_name='main').first()
if not dbobj:
dbobj = DB()
dbobj.database_name = "main"
dbobj.sqlalchemy_uri = config.SQLALCHEMY_DATABASE_URI
session.merge(dbobj)
session.commit()

TBL = models.Table
obj = session.query(TBL).filter_by(table_name='birth_names').first()
if not obj:
obj = TBL()
obj.table_name = 'birth_names'
obj.main_dttm_col = 'ds'
obj.default_endpoint = "/panoramix/datasource/table/1/?viz_type=table&granularity=one+day&since=100+years&until=now&row_limit=10&where=&flt_col_0=ds&flt_op_0=in&flt_eq_0=&flt_col_1=ds&flt_op_1=in&flt_eq_1=&slice_name=TEST&datasource_name=birth_names&datasource_id=1&datasource_type=table"
obj.database = dbobj
obj.fetch_metadata()
session.merge(obj)
session.commit()

session.close()


if __name__ == "__main__":
manager.run()
Binary file added panoramix/data/birth_names.csv.gz
Binary file not shown.
55 changes: 36 additions & 19 deletions panoramix/models.py
Expand Up @@ -24,11 +24,23 @@

from panoramix import db, get_session, config, utils
from panoramix.viz import viz_types
from sqlalchemy.ext.declarative import declared_attr

QueryResult = namedtuple('namedtuple', ['df', 'query', 'duration'])


class Slice(Model, AuditMixin):
class AuditMixinNullable(AuditMixin):
@declared_attr
def created_by_fk(cls):
return Column(Integer, ForeignKey('ab_user.id'),
default=cls.get_user_id, nullable=True)
@declared_attr
def changed_by_fk(cls):
return Column(Integer, ForeignKey('ab_user.id'),
default=cls.get_user_id, onupdate=cls.get_user_id, nullable=True)


class Slice(Model, AuditMixinNullable):
"""A slice is essentially a report or a view on data"""
__tablename__ = 'slices'
id = Column(Integer, primary_key=True)
Expand Down Expand Up @@ -75,6 +87,10 @@ def slice_url(self):
"{self.datasource_id}/".format(self=self))
return href(d)

@property
def edit_url(self):
return "/slicemodelview/edit/{}".format(self.id)

@property
def slice_link(self):
url = self.slice_url
Expand All @@ -101,7 +117,7 @@ def get_viz(self):
)


class Dashboard(Model, AuditMixin):
class Dashboard(Model, AuditMixinNullable):
"""A dash to slash"""
__tablename__ = 'dashboards'
id = Column(Integer, primary_key=True)
Expand Down Expand Up @@ -146,7 +162,7 @@ def filterable_column_names(self):
return sorted([c.column_name for c in self.columns if c.filterable])


class Database(Model, AuditMixin):
class Database(Model, AuditMixinNullable):
__tablename__ = 'dbs'
id = Column(Integer, primary_key=True)
database_name = Column(String(250), unique=True)
Expand All @@ -166,15 +182,13 @@ def get_table(self, table_name):
autoload_with=self.get_sqla_engine())


class Table(Model, Queryable, AuditMixin):
class Table(Model, Queryable, AuditMixinNullable):
type = "table"

__tablename__ = 'tables'
id = Column(Integer, primary_key=True)
table_name = Column(String(255), unique=True)
main_datetime_column_id = Column(Integer, ForeignKey('table_columns.id'))
main_datetime_column = relationship(
'TableColumn', foreign_keys=[main_datetime_column_id])
table_name = Column(String(250), unique=True)
main_dttm_col = Column(String(250))
default_endpoint = Column(Text)
database_id = Column(Integer, ForeignKey('dbs.id'), nullable=False)
database = relationship(
Expand Down Expand Up @@ -308,8 +322,11 @@ def query(
extras=None):

qry_start_dttm = datetime.now()
if not self.main_dttm_col:
raise Exception(
"Datetime column not provided as part table configuration")
timestamp = literal_column(
self.main_datetime_column.column_name).label('timestamp')
self.main_dttm_col).label('timestamp')
metrics_exprs = [
literal_column(m.expression).label(m.metric_name)
for m in self.metrics if m.metric_name in metrics]
Expand Down Expand Up @@ -420,7 +437,7 @@ def fetch_metadata(self):
self.columns.append(dbcol)

if not any_date_col and 'date' in datatype.lower():
any_date_col = dbcol
any_date_col = col.name

if dbcol.sum:
metrics.append(M(
Expand Down Expand Up @@ -464,18 +481,18 @@ def fetch_metadata(self):
m = (
db.session.query(M)
.filter(M.metric_name == metric.metric_name)
.filter(M.table == self)
.filter(M.table_id == self.id)
.first()
)
metric.table = self
metric.table_id = self.id
if not m:
db.session.add(metric)
db.session.commit()
if not self.main_datetime_column:
self.main_datetime_column = any_date_col
if not self.main_dttm_col:
self.main_dttm_col = any_date_col


class SqlMetric(Model, AuditMixin):
class SqlMetric(Model, AuditMixinNullable):
__tablename__ = 'sql_metrics'
id = Column(Integer, primary_key=True)
metric_name = Column(String(512))
Expand All @@ -488,7 +505,7 @@ class SqlMetric(Model, AuditMixin):
description = Column(Text)


class TableColumn(Model, AuditMixin):
class TableColumn(Model, AuditMixinNullable):
__tablename__ = 'table_columns'
id = Column(Integer, primary_key=True)
table_id = Column(Integer, ForeignKey('tables.id'))
Expand All @@ -513,7 +530,7 @@ def isnum(self):
return self.type in ('LONG', 'DOUBLE', 'FLOAT')


class Cluster(Model, AuditMixin):
class Cluster(Model, AuditMixinNullable):
__tablename__ = 'clusters'
id = Column(Integer, primary_key=True)
cluster_name = Column(String(250), unique=True)
Expand Down Expand Up @@ -560,7 +577,7 @@ class Datasource(Model, AuditMixin, Queryable):
user_id = Column(Integer, ForeignKey('ab_user.id'))
owner = relationship('User', backref='datasources', foreign_keys=[user_id])
cluster_name = Column(
String(255), ForeignKey('clusters.cluster_name'))
String(250), ForeignKey('clusters.cluster_name'))
cluster = relationship(
'Cluster', backref='datasources', foreign_keys=[cluster_name])

Expand Down Expand Up @@ -783,7 +800,7 @@ def json_obj(self):
return obj


class Column(Model, AuditMixin):
class Column(Model, AuditMixinNullable):
__tablename__ = 'columns'
id = Column(Integer, primary_key=True)
datasource_name = Column(
Expand Down
2 changes: 1 addition & 1 deletion panoramix/templates/panoramix/dashboard.html
Expand Up @@ -95,7 +95,7 @@ <h2>
<div class="col-md-4 text-right" style="position: relative;">
<a href="{{ slice.slice_url }}"><i class="fa fa-play"></i></a>
<a class="refresh"><i class="fa fa-refresh"></i></a>
<a><i class="fa fa-gear"></i></a>
<a href="{{ slice.edit_url }}"><i class="fa fa-gear"></i></a>
<a class="closewidget"><i class="fa fa-close"></i></a>
</div>
</div>
Expand Down
27 changes: 17 additions & 10 deletions panoramix/templates/panoramix/viz_table.html
Expand Up @@ -26,8 +26,7 @@
</tbody>
</table>
{% else %}
<div id="{{ viz.token }}" style="display: none;">
</div>
<div id="{{ viz.token }}" style="display: none;"></div>
<img src="{{ url_for("static", filename="loading.gif") }}" class="loading">
{% endif %}
{% endmacro %}
Expand All @@ -37,14 +36,22 @@
<script>
var url = "{{ viz.get_url(async="true", standalone="true", skip_libs="true")|safe }}";
console.log(url);
$("#{{ viz.token }}").load(url, function(){
var table = $('table').DataTable({
paging: false,
searching: false,
});
$("#{{ viz.token }}").show();
table.column('-1').order( 'desc' ).draw();
$("#{{ viz.token }} img.loading").hide();
var token = $("#{{ viz.token }}");
token.load(url, function(response, status, xhr){
if(status=="error"){
var err = '<div class="alert alert-danger">' + xhr.responseText + '</div>';
token.html(err);
token.show();
}
else{
var table = $('table').DataTable({
paging: false,
searching: false,
});
table.column('-1').order( 'desc' ).draw();
}
token.show();
token.parent().find("img.loading").hide();
});
</script>
{% endif %}
Expand Down

0 comments on commit e0d6d20

Please sign in to comment.