Skip to content

Commit

Permalink
setContextAsView function; raise cusom error when no data loaded into…
Browse files Browse the repository at this point in the history
… View; Spec documentation
  • Loading branch information
dorisjlee committed Jun 13, 2020
1 parent 46b2467 commit 84a29a7
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 27 deletions.
26 changes: 26 additions & 0 deletions doc/source/guide/spec.rst
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,29 @@ So far, we have seen examples of how to express existing use cases based on `lux
.. code-block:: python
df.setContext([lux.Spec(attribute='AverageCost', channel='y')])
Specifying wildcards
~~~~~~~~~~~~~~~~~~~~~
Let's say that you are interested in *any* attribute with respect to `AverageCost`. Lux support *wildcards* (based on .. _CompassQL: https://idl.cs.washington.edu/papers/compassql/), which specifies the enumeration of any possible attribute or values that satisfies the provided constraints.
.. code-block:: python
df.setContext(['AverageCost',lux.Spec('?')])
The space of enumeration can be narrowed based on constraints. For example, you might only be interested in looking at scatterplots of `AverageCost` with respect to quantitative attributes.
.. code-block:: python
df.setContext(['AverageCost',lux.Spec('?',dataType='quantitative')])
The enumeration specifier can also be placed on the value field. For example, you might be interested in looking at how the distribution of `AverageCost` varies for all possible values of `Geography`.
.. code-block:: python
df.setContext(['AverageCost','Geography=?')])
or
.. code-block:: python
df.setContext(['AverageCost',lux.Spec(attribute='Geography',filterOp='=',value='?')])
7 changes: 4 additions & 3 deletions lux/compiler/Compiler.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from lux.context import Spec
from typing import List, Dict
from typing import List, Dict, Union
from lux.view.View import View
from lux.luxDataFrame.LuxDataframe import LuxDataFrame
from lux.view.ViewCollection import ViewCollection
Expand Down Expand Up @@ -43,7 +43,8 @@ def compile(ldf: LuxDataFrame,specLst:List[Spec], viewCollection: ViewCollection
if (enumerateCollection):
viewCollection = Compiler.enumerateCollection(specLst,ldf)
viewCollection = Compiler.expandUnderspecified(ldf, viewCollection) # autofill data type/model information
viewCollection = Compiler.removeAllInvalid(viewCollection) # remove invalid views from collection
if len(viewCollection)>1:
viewCollection = Compiler.removeAllInvalid(viewCollection) # remove invalid views from collection
for view in viewCollection:
Compiler.determineEncoding(ldf, view) # autofill viz related information
return viewCollection
Expand Down Expand Up @@ -133,7 +134,7 @@ def expandUnderspecified(ldf, viewCollection):
return views

@staticmethod
def removeAllInvalid(viewCollection):
def removeAllInvalid(viewCollection:ViewCollection) -> ViewCollection:
"""
Given an expanded view collection, remove all views that are invalid.
Currently, the invalid views are ones that contain temporal by temporal attributes or overlapping attributes.
Expand Down
15 changes: 14 additions & 1 deletion lux/luxDataFrame/LuxDataframe.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import pandas as pd
from lux.context.Spec import Spec
from lux.view.View import View
from lux.view.ViewCollection import ViewCollection
from lux.utils.utils import checkImportLuxWidget
#import for benchmarking
Expand Down Expand Up @@ -47,7 +48,7 @@ def setExecutorType(self, exe):
if (exe =="SQL"):
import pkgutil
if (pkgutil.find_loader("psycopg2") is None):
raise Exception("psycopg2 is not installed. Run `pip install psycopg2' to install psycopg2 to enable the Postgres connection.")
raise ImportError("psycopg2 is not installed. Run `pip install psycopg2' to install psycopg2 to enable the Postgres connection.")
else:
import psycopg2
from lux.executor.SQLExecutor import SQLExecutor
Expand Down Expand Up @@ -87,6 +88,18 @@ def setContext(self,context:typing.List[typing.Union[str,Spec]]):
"""
self.context = context
self._refreshContext()
def setContextAsView(self,view:View):
"""
Set context of the dataframe as the View
Parameters
----------
view : View
[description]
"""
self.context = view.specLst
self._refreshContext()

def clearContext(self):
self.context = []
self.viewCollection = []
Expand Down
54 changes: 31 additions & 23 deletions lux/view/View.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from __future__ import annotations
from typing import List
from lux.context.Spec import Spec
from lux.utils.utils import checkImportLuxWidget
class View:
Expand All @@ -20,21 +21,25 @@ def __repr__(self):
filter_spec = None
channels, additional_channels = [], []
for spec in self.specLst:
if spec.value != "":
filter_spec = spec
if spec.attribute != "":
if spec.aggregation != "":
attribute = spec.aggregation.upper() + "(" + spec.attribute + ")"
elif spec.binSize > 0:
attribute = "BIN(" + spec.attribute + ")"
else:
attribute = spec.attribute
if spec.channel == "x":
channels.insert(0, [spec.channel, attribute])
elif spec.channel == "y":
channels.insert(1, [spec.channel, attribute])
elif spec.channel != "":
additional_channels.append([spec.channel, attribute])

if hasattr(spec,"value"):
if spec.value != "":
filter_spec = spec
if hasattr(spec,"attribute"):
if spec.attribute != "":
if spec.aggregation != "":
attribute = spec.aggregation.upper() + "(" + spec.attribute + ")"
elif spec.binSize > 0:
attribute = "BIN(" + spec.attribute + ")"
else:
attribute = spec.attribute
if spec.channel == "x":
channels.insert(0, [spec.channel, attribute])
elif spec.channel == "y":
channels.insert(1, [spec.channel, attribute])
elif spec.channel != "":
additional_channels.append([spec.channel, attribute])

channels.extend(additional_channels)
str_channels = ""
for channel in channels:
Expand All @@ -48,14 +53,17 @@ def _repr_html_(self):
from IPython.display import display
checkImportLuxWidget()
import luxWidget
from lux.luxDataFrame.LuxDataframe import LuxDataFrame
# widget = LuxDataFrame.renderWidget(inputCurrentView=self,renderTarget="viewOnly")
widget = luxWidget.LuxWidget(
currentView= LuxDataFrame.currentViewToJSON([self]),
recommendations=[],
context={}
)
display(widget)
if (self.data is None):
raise Exception("No data populated in View. Use the 'load' function (e.g., view.load(df)) to populate the view with a data source.")
else:
from lux.luxDataFrame.LuxDataframe import LuxDataFrame
# widget = LuxDataFrame.renderWidget(inputCurrentView=self,renderTarget="viewOnly")
widget = luxWidget.LuxWidget(
currentView= LuxDataFrame.currentViewToJSON([self]),
recommendations=[],
context={}
)
display(widget)
def getAttrByAttrName(self,attrName):
return list(filter(lambda x: x.attribute == attrName, self.specLst))

Expand Down

0 comments on commit 84a29a7

Please sign in to comment.