Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] No subclasses refactor v2 #437

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions lux/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
# limitations under the License.

# Register the commonly used modules (similar to how pandas does it: https://github.com/pandas-dev/pandas/blob/master/pandas/__init__.py)
# fmt: off
from lux.vis.Clause import Clause
from lux.core.frame import LuxDataFrame
from lux.core.sqltable import LuxSQLTable
Expand All @@ -29,3 +30,6 @@
from lux.action.default import register_default_actions

register_default_actions()

import lux.patch.frame
import lux.patch.series
5 changes: 3 additions & 2 deletions lux/action/correlation.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def correlation(ldf: LuxDataFrame, ignore_transpose: bool = True):

import numpy as np

filter_specs = utils.get_filter_specs(ldf._intent)
filter_specs = utils.get_filter_specs(ldf.lux._intent)
intent = [
lux.Clause("?", data_model="measure"),
lux.Clause("?", data_model="measure"),
Expand Down Expand Up @@ -93,7 +93,8 @@ def correlation(ldf: LuxDataFrame, ignore_transpose: bool = True):
def check_transpose_not_computed(vlist: VisList, a: str, b: str):
transpose_exist = list(
filter(
lambda x: (x._inferred_intent[0].attribute == b) and (x._inferred_intent[1].attribute == a),
lambda x: (x._inferred_intent[0].attribute == b) and (
x._inferred_intent[1].attribute == a),
vlist,
)
)
Expand Down
10 changes: 6 additions & 4 deletions lux/action/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ def custom(ldf):
"long_description": "Shows the list of visualizations generated based on user specified intent",
}

recommendation["collection"] = ldf.current_vis
recommendation["collection"] = ldf.lux.current_vis

vlist = ldf.current_vis
vlist = ldf.lux.current_vis
lux.config.executor.execute(vlist, ldf)
for vis in vlist:
vis.score = interestingness(vis, ldf)
Expand Down Expand Up @@ -71,9 +71,11 @@ def custom_actions(ldf):
if display_condition is None or (display_condition is not None and display_condition(ldf)):
args = lux.config.actions[action_name].args
if args:
recommendation = lux.config.actions[action_name].action(ldf, args)
recommendation = lux.config.actions[action_name].action(
ldf, args)
else:
recommendation = lux.config.actions[action_name].action(ldf)
recommendation = lux.config.actions[action_name].action(
ldf)
recommendations.append(recommendation)
return recommendations
else:
Expand Down
18 changes: 12 additions & 6 deletions lux/action/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,24 @@ def register_default_actions():
from lux.action.temporal import temporal

# display conditions for default actions
no_vis = lambda ldf: (ldf.current_vis is None) or (
ldf.current_vis is not None and len(ldf.current_vis) == 0
def no_vis(ldf): return (ldf.lux.current_vis is None) or (
ldf.lux.current_vis is not None and len(ldf.lux.current_vis) == 0
)
one_current_vis = lambda ldf: ldf.current_vis is not None and len(ldf.current_vis) == 1
multiple_current_vis = lambda ldf: ldf.current_vis is not None and len(ldf.current_vis) > 1

def one_current_vis(ldf): return ldf.lux.current_vis is not None and len(
ldf.lux.current_vis) == 1

def multiple_current_vis(ldf): return ldf.lux.current_vis is not None and len(
ldf.lux.current_vis) > 1

# globally register default actions
lux.config.register_action("correlation", correlation, no_vis)
lux.config.register_action("distribution", univariate, no_vis, "quantitative")
lux.config.register_action(
"distribution", univariate, no_vis, "quantitative")
lux.config.register_action("occurrence", univariate, no_vis, "nominal")
lux.config.register_action("temporal", temporal, no_vis)
lux.config.register_action("geographical", univariate, no_vis, "geographical")
lux.config.register_action(
"geographical", univariate, no_vis, "geographical")

lux.config.register_action("Enhance", enhance, one_current_vis)
lux.config.register_action("Filter", add_filter, one_current_vis)
Expand Down
10 changes: 6 additions & 4 deletions lux/action/enhance.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,12 @@ def enhance(ldf):
object with a collection of visualizations that result from the Enhance action.
"""

filters = utils.get_filter_specs(ldf._intent)
filters = utils.get_filter_specs(ldf.lux._intent)
# Collect variables that already exist in the intent
attr_specs = list(filter(lambda x: x.value == "" and x.attribute != "Record", ldf._intent))
fltr_str = [fltr.attribute + fltr.filter_op + str(fltr.value) for fltr in filters]
attr_specs = list(filter(lambda x: x.value ==
"" and x.attribute != "Record", ldf.lux._intent))
fltr_str = [fltr.attribute + fltr.filter_op +
str(fltr.value) for fltr in filters]
attr_str = [str(clause.attribute) for clause in attr_specs]
intended_attrs = f'<p class="highlight-intent">{", ".join(attr_str + fltr_str)}</p>'
if len(attr_specs) == 1:
Expand All @@ -56,7 +58,7 @@ def enhance(ldf):
recommendation = {"action": "Enhance"}
recommendation["collection"] = []
return recommendation
intent = ldf._intent.copy()
intent = ldf.lux._intent.copy()
# Clear channel so that channel not enforced based on input vis intent
for clause in intent:
clause.channel = ""
Expand Down
34 changes: 18 additions & 16 deletions lux/action/filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,33 +35,34 @@ def add_filter(ldf):
recommendations : Dict[str,obj]
object with a collection of visualizations that result from the Filter action.
"""
filters = utils.get_filter_specs(ldf._intent)
filters = utils.get_filter_specs(ldf.lux._intent)
filter_values = []
output = []
# if fltr is specified, create visualizations where data is filtered by all values of the fltr's categorical variable
column_spec = utils.get_attrs_specs(ldf._intent)
column_spec = utils.get_attrs_specs(ldf.lux._intent)
column_spec_attr = list(map(lambda x: x.attribute, column_spec))
if len(filters) == 1:
# get unique values for all categorical values specified and creates corresponding filters
fltr = filters[0]

if ldf.data_type[fltr.attribute] == "nominal":
if ldf.lux.data_type[fltr.attribute] == "nominal":
recommendation = {
"action": "Filter",
"description": f"Changing the <p class='highlight-intent'>{fltr.attribute}</p> filter to an alternative value.",
"long_description": f"Swap out the filter value for {fltr.attribute} to other possible values, while keeping all else the same. Visualizations are ranked based on interestingness",
}
unique_values = ldf.unique_values[fltr.attribute]
unique_values = ldf.lux.unique_values[fltr.attribute]
filter_values.append(fltr.value)
# creates vis with new filters
for val in unique_values:
if val not in filter_values:
new_spec = column_spec.copy()
new_filter = lux.Clause(attribute=fltr.attribute, value=val)
new_filter = lux.Clause(
attribute=fltr.attribute, value=val)
new_spec.append(new_filter)
temp_vis = Vis(new_spec)
output.append(temp_vis)
elif ldf.data_type[fltr.attribute] == "quantitative":
elif ldf.lux.data_type[fltr.attribute] == "quantitative":
recommendation = {
"action": "Filter",
"description": f"Changing the <p class='highlight-intent'>{fltr.attribute}</p> filter to an alternative inequality operation.",
Expand Down Expand Up @@ -94,7 +95,7 @@ def get_complementary_ops(fltr_op):
intended_attrs = ", ".join(
[
str(clause.attribute)
for clause in ldf._intent
for clause in ldf.lux._intent
if clause.value == "" and clause.attribute != "Record"
]
)
Expand All @@ -106,29 +107,30 @@ def get_complementary_ops(fltr_op):
categorical_vars = []
for col in list(ldf.columns):
# if cardinality is not too high, and attribute is not one of the X,Y (specified) column
if 1 < ldf.cardinality[col] < 30 and col not in column_spec_attr:
if 1 < ldf.lux.cardinality[col] < 30 and col not in column_spec_attr:
categorical_vars.append(col)
for cat in categorical_vars:
unique_values = ldf.unique_values[cat]
unique_values = ldf.lux.unique_values[cat]
for val in unique_values:
new_spec = column_spec.copy()
new_filter = lux.Clause(attribute=cat, filter_op="=", value=val)
new_filter = lux.Clause(
attribute=cat, filter_op="=", value=val)
new_spec.append(new_filter)
temp_vis = Vis(new_spec)
output.append(temp_vis)
if (
ldf.current_vis is not None
and len(ldf.current_vis) == 1
and ldf.current_vis[0].mark == "line"
and len(get_filter_specs(ldf.intent)) > 0
ldf.lux.current_vis is not None
and len(ldf.lux.current_vis) == 1
and ldf.lux.current_vis[0].mark == "line"
and len(get_filter_specs(ldf.lux.intent)) > 0
):
recommendation = {
"action": "Similarity",
"description": "Show other charts that are visually similar to the Current vis.",
"long_description": "Show other charts that are visually similar to the Current vis.",
}
last = get_filter_specs(ldf.intent)[-1]
output = ldf.intent.copy()[0:-1]
last = get_filter_specs(ldf.lux.intent)[-1]
output = ldf.lux.intent.copy()[0:-1]
# array of possible values for attribute
arr = ldf[last.attribute].unique().tolist()
output.append(lux.Clause(last.attribute, last.attribute, arr))
Expand Down
21 changes: 13 additions & 8 deletions lux/action/generalize.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,12 @@ def generalize(ldf):

output = []
excluded_columns = []
attributes = list(filter(lambda x: x.value == "" and x.attribute != "Record", ldf._intent))
filters = utils.get_filter_specs(ldf._intent)
attributes = list(filter(lambda x: x.value ==
"" and x.attribute != "Record", ldf.lux._intent))
filters = utils.get_filter_specs(ldf.lux._intent)

fltr_str = [fltr.attribute + fltr.filter_op + str(fltr.value) for fltr in filters]
fltr_str = [fltr.attribute + fltr.filter_op +
str(fltr.value) for fltr in filters]
attr_str = [str(clause.attribute) for clause in attributes]
intended_attrs = f'<p class="highlight-intent">{", ".join(attr_str + fltr_str)}</p>'

Expand All @@ -64,22 +66,24 @@ def generalize(ldf):
for column in columns:
if column not in excluded_columns:
temp_vis = Vis(ldf.copy_intent(), score=1)
temp_vis.remove_column_from_spec(column, remove_first=True)
temp_vis.remove_column_from_spec(
column, remove_first=True)
excluded_columns.append(column)
output.append(temp_vis)
else:
if columns not in excluded_columns:
temp_vis = Vis(ldf.copy_intent(), score=1)
temp_vis.remove_column_from_spec(columns, remove_first=True)
temp_vis.remove_column_from_spec(
columns, remove_first=True)
excluded_columns.append(columns)
output.append(temp_vis)
# for each filter specification, create a copy of the ldf's current vis and remove the filter specification,
# then append the vis to the output
for clause in filters:
# new_spec = ldf._intent.copy()
# new_spec = ldf.lux._intent.copy()
# new_spec.remove_column_from_spec(new_spec.attribute)
temp_vis = Vis(
ldf.current_vis[0]._inferred_intent.copy(),
ldf.lux.current_vis[0]._inferred_intent.copy(),
source=ldf,
title="Overall",
score=0,
Expand All @@ -94,6 +98,7 @@ def generalize(ldf):

vlist.remove_duplicates()
vlist.sort(remove_invalid=True)
vlist._collection = list(filter(lambda x: x.score != -1, vlist._collection))
vlist._collection = list(
filter(lambda x: x.score != -1, vlist._collection))
recommendation["collection"] = vlist
return recommendation
16 changes: 10 additions & 6 deletions lux/action/temporal.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def temporal(ldf):
"long_description": "Temporal displays line charts for all attributes related to datetimes in the dataframe.",
}
for c in ldf.columns:
if ldf.data_type[c] == "temporal":
if ldf.lux.data_type[c] == "temporal":
try:
generated_vis = create_temporal_vis(ldf, c)
vlist.extend(generated_vis)
Expand All @@ -50,7 +50,7 @@ def temporal(ldf):
# If no temporal visualizations were generated via parsing datetime, fallback to default behavior.
if len(vlist) == 0:
intent = [lux.Clause("?", data_type="temporal")]
intent.extend(utils.get_filter_specs(ldf._intent))
intent.extend(utils.get_filter_specs(ldf.lux._intent))
vlist = VisList(intent, ldf)
for vis in vlist:
vis.score = interestingness(vis, ldf)
Expand Down Expand Up @@ -88,11 +88,14 @@ def create_temporal_vis(ldf, col):
"""
formatted_date = pd.to_datetime(ldf[col], format="%Y-%m-%d")

overall_vis = Vis([lux.Clause(col, data_type="temporal")], source=ldf, score=5)
overall_vis = Vis(
[lux.Clause(col, data_type="temporal")], source=ldf, score=5)

year_col = col + " (year)"
year_df = LuxDataFrame({year_col: pd.to_datetime(formatted_date.dt.year, format="%Y")})
year_vis = Vis([lux.Clause(year_col, data_type="temporal")], source=year_df, score=4)
year_df = LuxDataFrame(
{year_col: pd.to_datetime(formatted_date.dt.year, format="%Y")})
year_vis = Vis([lux.Clause(year_col, data_type="temporal")],
source=year_df, score=4)

month_col = col + " (month)"
month_df = LuxDataFrame({month_col: formatted_date.dt.month})
Expand All @@ -105,7 +108,8 @@ def create_temporal_vis(ldf, col):
day_df.set_data_type(
{day_col: "nominal"}
) # Since day is high cardinality 1-31, it can get recognized as quantitative
day_vis = Vis([lux.Clause(day_col, data_type="temporal", timescale="day")], source=day_df, score=2)
day_vis = Vis([lux.Clause(day_col, data_type="temporal",
timescale="day")], source=day_df, score=2)

week_col = col + " (day of week)"
week_df = lux.LuxDataFrame({week_col: formatted_date.dt.dayofweek})
Expand Down
11 changes: 6 additions & 5 deletions lux/action/univariate.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,11 @@ def univariate(ldf, *args):
else:
data_type_constraint = args[0][0]

filter_specs = utils.get_filter_specs(ldf._intent)
filter_specs = utils.get_filter_specs(ldf.lux._intent)
ignore_rec_flag = False
if data_type_constraint == "quantitative":
possible_attributes = [
c for c in ldf.columns if ldf.data_type[c] == "quantitative" and c != "Number of Records"
c for c in ldf.columns if ldf.lux.data_type[c] == "quantitative" and c != "Number of Records"
]
intent = [lux.Clause(possible_attributes)]
intent.extend(filter_specs)
Expand All @@ -63,7 +63,7 @@ def univariate(ldf, *args):
ignore_rec_flag = True
elif data_type_constraint == "nominal":
possible_attributes = [
c for c in ldf.columns if ldf.data_type[c] == "nominal" and c != "Number of Records"
c for c in ldf.columns if ldf.lux.data_type[c] == "nominal" and c != "Number of Records"
]
examples = ""
if len(possible_attributes) >= 1:
Expand All @@ -77,12 +77,13 @@ def univariate(ldf, *args):
}
elif data_type_constraint == "geographical":
possible_attributes = [
c for c in ldf.columns if ldf.data_type[c] == "geographical" and c != "Number of Records"
c for c in ldf.columns if ldf.lux.data_type[c] == "geographical" and c != "Number of Records"
]
examples = ""
if len(possible_attributes) >= 1:
examples = f" (e.g., {possible_attributes[0]})"
intent = [lux.Clause("?", data_type="geographical"), lux.Clause("?", data_model="measure")]
intent = [lux.Clause("?", data_type="geographical"),
lux.Clause("?", data_model="measure")]
intent.extend(filter_specs)
recommendation = {
"action": "Geographical",
Expand Down
Loading