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

Add interaction to open visualizations in full view #364

Open
wants to merge 37 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
05a71eb
Responding to issue #67, Added color for bar charts.
jerrysong1324 Oct 3, 2020
a195b2e
Minor: Updated spacing
jerrysong1324 Oct 3, 2020
56e04b3
Updated BarChar.py to disable legends for basic bar plots
jerrysong1324 Oct 5, 2020
70b70e6
changing colors for bar charts
jerrysong1324 Oct 19, 2020
a66dd63
added colors for bar charts
jerrysong1324 Oct 19, 2020
1bf8c0f
Merge branch 'master' into master
jerrysong1324 Oct 23, 2020
c5f3678
Merge remote-tracking branch 'upstream/master'
jerrysong1324 Oct 23, 2020
f53fd9d
fixing merge error
jerrysong1324 Oct 23, 2020
f550382
Merge remote-tracking branch 'upstream/master'
jerrysong1324 Oct 26, 2020
1d47f74
Merge remote-tracking branch 'upstream/master'
jerrysong1324 Oct 29, 2020
7600d1c
merged
jerrysong1324 Nov 23, 2020
2488ff5
Merge remote-tracking branch 'upstream/master'
jerrysong1324 Dec 3, 2020
a66734e
Merge remote-tracking branch 'upstream/master'
jerrysong1324 Dec 10, 2020
bf8347e
Merge remote-tracking branch 'upstream/master'
jerrysong1324 Jan 8, 2021
d17cd7e
Merge remote-tracking branch 'upstream/master'
jerrysong1324 Jan 13, 2021
c06a4c2
Merge remote-tracking branch 'upstream/master'
jerrysong1324 Jan 17, 2021
bb4a2ce
started adding in long descriptions
jerrysong1324 Jan 25, 2021
0cbdf8b
fixed style
jerrysong1324 Jan 25, 2021
e97eefb
Changed naming to conform w/ PEP8
jerrysong1324 Feb 12, 2021
3a6812a
Merge remote-tracking branch 'upstream/master'
jerrysong1324 Feb 13, 2021
febc103
rename
jerrysong1324 Feb 13, 2021
5eeaff9
rename
jerrysong1324 Feb 13, 2021
f0c14fa
Update correlation.py
jerrysong1324 Feb 13, 2021
0744a63
Update univariate.py
jerrysong1324 Feb 13, 2021
8c67338
made required fields dynamic
jerrysong1324 Feb 13, 2021
afff077
added links
jerrysong1324 Feb 16, 2021
e510ada
added to description length
jerrysong1324 Feb 16, 2021
f973f8b
Merge remote-tracking branch 'upstream/master'
jerrysong1324 Feb 20, 2021
a6bb617
Merge remote-tracking branch 'upstream/master'
jerrysong1324 Mar 5, 2021
4bfdb40
able to feed in vpec to backend
jerrysong1324 Mar 27, 2021
9e5a3fd
backend for running user code
jerrysong1324 Mar 28, 2021
ec19c4b
modifying plotting style default
jerrysong1324 Apr 8, 2021
f2199ca
fixing tests
jerrysong1324 Apr 10, 2021
94b3594
merging
jerrysong1324 Apr 10, 2021
cb6e1c0
custom function for style works for matplotlib
jerrysong1324 Apr 10, 2021
6d7ea65
lint code blocks
jerrysong1324 Apr 18, 2021
b01f6f4
change style
jerrysong1324 Apr 18, 2021
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
5 changes: 5 additions & 0 deletions lux/_config/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class Config:
def __init__(self):
self._default_display = "pandas"
self.plotting_style = None
self.plotting_style_code = ""
self.SQLconnection = ""
self.executor = None
# holds registered option metadata
Expand Down Expand Up @@ -277,8 +278,12 @@ def plotting_backend(self, type: str) -> None:
"""
if type.lower() == "vegalite" or type.lower() == "altair":
self._plotting_backend = "vegalite"
self.plotting_style = None
self.plotting_style_code = ""
elif type.lower() == "matplotlib":
self._plotting_backend = "matplotlib"
self.plotting_style = None
self.plotting_style_code = ""
else:
warnings.warn(
"Unsupported plotting backend. Lux currently only support 'altair', 'vegalite', or 'matplotlib'",
Expand Down
66 changes: 66 additions & 0 deletions lux/core/frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,71 @@ def set_intent_on_click(self, change):

self._widget.observe(self.remove_deleted_recs, names="deletedIndices")
self._widget.observe(self.set_intent_on_click, names="selectedIntentIndex")
self._widget.observe(self.get_graphing_code, names="selectedFullScreenIndex")

# Gets graphing code to be displayed in full screen view
def get_graphing_code(self, change):
import inspect

full_screen_vis_idx = self._widget.selectedFullScreenIndex
full_screen_action = list(self._widget.selectedFullScreenIndex.keys())[0]
# Using visList to support eventual full view display of multiple graphs
full_screen_vis = VisList(
list(
map(
self._recommendation[full_screen_action].__getitem__,
full_screen_vis_idx[full_screen_action],
)
)
)
if lux.config.plotting_backend == "vegalite":
self._widget.unobserve(self.apply_full_view_changes)
self._widget.visGraphCode = (
"import pandas as pd\n" + full_screen_vis[0].get_Altair_vis_code()
)
self._widget.visStyleCode = lux.config.plotting_style_code
self._widget.observe(self.apply_full_view_changes, names="visGraphCode")
self._widget.observe(self.apply_full_view_changes, names="visStyleCode")
self._widget.observe(self.change_style_config, names="configPlottingStyle")
else:
self._widget.visGraphCode = (
"# " + lux.config.plotting_backend + " not supported in full screen yet"
)
self._widget.visStyleCode = ""

def apply_full_view_changes(self, change):
from IPython.display import display, clear_output

code = self._widget.visGraphCode + self._widget.visStyleCode
df = self
loc = {"df": df}
exec(code, {}, loc)
chart = loc["chart"]
vspec = chart.to_json()
self._widget.visGraphSpec = vspec

def change_style_config(self, change):
from IPython.display import display, clear_output

code = "\n" + self._widget.configPlottingStyle
code = "def custom_config(chart):" + code + "\nreturn chart"
code = code.replace("\n", "\n ")

loc = {}
exec(code, {}, loc)
custom_config = loc["custom_config"]
lux.config.plotting_style = custom_config
lux.config.plotting_style_code = code

self.expire_recs()
self.maintain_recs()
with self.output:
clear_output()
display(self._widget)

self._widget.observe(self.remove_deleted_recs, names="deletedIndices")
self._widget.observe(self.set_intent_on_click, names="selectedIntentIndex")
self._widget.observe(self.get_graphing_code, names="selectedFullScreenIndex")

def _ipython_display_(self):
from IPython.display import display
Expand Down Expand Up @@ -644,6 +709,7 @@ def _ipython_display_(self):
# Observers(callback_function, listen_to_this_variable)
self._widget.observe(self.remove_deleted_recs, names="deletedIndices")
self._widget.observe(self.set_intent_on_click, names="selectedIntentIndex")
self._widget.observe(self.get_graphing_code, names="selectedFullScreenIndex")

button = widgets.Button(
description="Toggle Pandas/Lux",
Expand Down
17 changes: 17 additions & 0 deletions lux/vis/Vis.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,23 @@ def to_Altair(self, standalone=False) -> str:
"""
Generate minimal Altair code to visualize the Vis

Parameters
----------
standalone : bool, optional
Flag to determine if outputted code uses user-defined variable names or can be run independently, by default False

Returns
-------
str
String version of the Altair code. Need to print out the string to apply formatting.
"""
self._code = self.get_Altair_vis_code(standalone)
return self._code + lux.config.plotting_style_code + "\nchart"

def get_Altair_vis_code(self, standalone=False) -> str:
"""
Returns code specific to the visualization without styling

Parameters
----------
standalone : bool, optional
Expand Down
53 changes: 26 additions & 27 deletions lux/vislib/altair/AltairChart.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import lux
import pandas as pd
import numpy as np
import altair as alt
Expand Down Expand Up @@ -51,33 +52,31 @@ def add_tooltip(self):
self.chart = self.chart.encode(tooltip=list(self.vis.data.columns))

def apply_default_config(self):
self.chart = self.chart.configure_title(fontWeight=500, fontSize=13, font="Helvetica Neue")
self.chart = self.chart.configure_axis(
titleFontWeight=500,
titleFontSize=11,
titleFont="Helvetica Neue",
labelFontWeight=400,
labelFontSize=9,
labelFont="Helvetica Neue",
labelColor="#505050",
)
self.chart = self.chart.configure_legend(
titleFontWeight=500,
titleFontSize=10,
titleFont="Helvetica Neue",
labelFontWeight=400,
labelFontSize=9,
labelFont="Helvetica Neue",
)
self.chart = self.chart.properties(width=160, height=150)
self.code += (
"\nchart = chart.configure_title(fontWeight=500,fontSize=13,font='Helvetica Neue')\n"
)
self.code += "chart = chart.configure_axis(titleFontWeight=500,titleFontSize=11,titleFont='Helvetica Neue',\n"
self.code += "\t\t\t\t\tlabelFontWeight=400,labelFontSize=8,labelFont='Helvetica Neue',labelColor='#505050')\n"
self.code += "chart = chart.configure_legend(titleFontWeight=500,titleFontSize=10,titleFont='Helvetica Neue',\n"
self.code += "\t\t\t\t\tlabelFontWeight=400,labelFontSize=8,labelFont='Helvetica Neue')\n"
self.code += "chart = chart.properties(width=160,height=150)\n"
def default_config(chart):
chart = chart.configure_title(fontWeight=500, fontSize=13, font="Helvetica Neue")
chart = chart.configure_axis(
titleFontWeight=500,
titleFontSize=11,
titleFont="Helvetica Neue",
labelFontWeight=400,
labelFontSize=9,
labelFont="Helvetica Neue",
labelColor="#505050",
)
chart = chart.configure_legend(
titleFontWeight=500,
titleFontSize=10,
titleFont="Helvetica Neue",
labelFontWeight=400,
labelFontSize=9,
labelFont="Helvetica Neue",
)
chart = chart.properties(width=160, height=150)
return chart

self.chart = default_config(self.chart)
if not lux.config.plotting_style:
lux.config.plotting_style = default_config

def encode_color(self):
color_attr = self.vis.get_attr_by_channel("color")
Expand Down
28 changes: 25 additions & 3 deletions lux/vislib/altair/AltairRenderer.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,12 +104,34 @@ def create_vis(self, vis, standalone=True):
elif self.output_type == "Altair":
import inspect

source = ""
if lux.config.plotting_style:
chart.code += "\n".join(
inspect.getsource(lux.config.plotting_style).split("\n ")[1:-1]
if "def custom_config(chart):" in lux.config.plotting_style_code:
source = lux.config.plotting_style_code
else:
source = inspect.getsource(lux.config.plotting_style)
default_vis_style_code = "# Default Lux Style \nchart = chart.configure_title(fontWeight=500,fontSize=13,font='Helvetica Neue')\n"
default_vis_style_code += "chart = chart.configure_axis(titleFontWeight=500,titleFontSize=11,titleFont='Helvetica Neue',\n"
default_vis_style_code += "\t\t\t\t\tlabelFontWeight=400,labelFontSize=9,labelFont='Helvetica Neue',labelColor='#505050')\n"
default_vis_style_code += "chart = chart.configure_legend(titleFontWeight=500,titleFontSize=10,titleFont='Helvetica Neue',\n"
default_vis_style_code += (
"\t\t\t\t\tlabelFontWeight=400,labelFontSize=9,labelFont='Helvetica Neue')\n"
)
chart.code += "\nchart"
default_vis_style_code += "chart = chart.properties(width=160,height=150)\n"
vis_style_code = "\n# Custom Style Additions"
# TODO: improve parsing such that it splits based on line of logic instead of line of code
for line in source.split("\n ")[1:-1]:
if line.strip() not in default_vis_style_code:
vis_style_code += "\n" + line
if vis_style_code == "\n# Custom Style Additions":
vis_style_code = default_vis_style_code
else:
vis_style_code = default_vis_style_code + vis_style_code
vis_style_code = vis_style_code.replace("\n\t\t", "\n")
vis_style_code = vis_style_code.replace("\n ", "\n")
lux.config.plotting_style_code = vis_style_code
chart.code = chart.code.replace("\n\t\t", "\n")
chart.code = chart.code.replace("\n ", "\n")

var = vis._source
if var is not None:
Expand Down
1 change: 1 addition & 0 deletions lux/vislib/matplotlib/MatplotlibChart.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import pandas as pd
import matplotlib.pyplot as plt
import lux


class MatplotlibChart:
Expand Down
31 changes: 17 additions & 14 deletions tests/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ def add_title(fig, ax):
lux.config.plotting_style = add_title
df._ipython_display_()
title_addition = 'ax.set_title("Test Title")'
exported_code_str = df.recommendation["Correlation"][0].to_Altair()
exported_code_str = df.recommendation["Correlation"][0].to_matplotlib_code()
assert title_addition in exported_code_str


Expand Down Expand Up @@ -289,19 +289,22 @@ def test_sort(global_var):
lux.config.sort = "descending"


# TODO: This test does not pass in pytest but is working in Jupyter notebook.
# def test_plot_setting(global_var):
# df = pytest.car_df
# df["Year"] = pd.to_datetime(df["Year"], format='%Y')
# def change_color_add_title(chart):
# chart = chart.configure_mark(color="green") # change mark color to green
# chart.title = "Custom Title" # add title to chart
# return chart
def test_plot_setting(global_var):
lux.config._plotting_backend = "vegalite"
df = pytest.car_df
df["Year"] = pd.to_datetime(df["Year"], format="%Y")

# df.plot_config = change_color_add_title
def change_color_add_title(chart):
chart = chart.configure_mark(color="green") # change mark color to green
chart.title = "Custom Title" # add title to chart
return chart

lux.config.plotting_style = change_color_add_title

# df._ipython_display_()
# df._ipython_display_()

# vis_code = df.recommendation["Correlation"][0].to_Altair()
# print (vis_code)
# assert 'chart = chart.configure_mark(color="green")' in vis_code, "Exported chart does not have additional plot style setting."
vis_code = df.recommendation["Correlation"][0].to_Altair()
print(vis_code)
assert (
'chart = chart.configure_mark(color="green")' in vis_code
), "Exported chart does not have additional plot style setting."