Skip to content

Commit

Permalink
feat: display in remote ssl
Browse files Browse the repository at this point in the history
  • Loading branch information
islxyqwe committed Dec 2, 2024
1 parent af99e0f commit 8166c3a
Show file tree
Hide file tree
Showing 7 changed files with 268 additions and 21 deletions.
2 changes: 1 addition & 1 deletion pygwalker/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from pygwalker.services.global_var import GlobalVarManager
from pygwalker.services.kaggle import show_tips_user_kaggle as __show_tips_user_kaggle

__version__ = "0.4.9.13"
__version__ = "0.4.9.13a0"
__hash__ = __rand_str()

from pygwalker.adapter import walk, render, table
Expand Down
15 changes: 12 additions & 3 deletions pygwalker/adapter/render.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from pygwalker.adapter.utils import is_notebook
import pygwalker.api.repl as repl
import pygwalker.api.jupyter as jupyter
from pygwalker.adapter.utils import can_open_window, is_notebook
from pygwalker.api import repl, webview, jupyter
from typing import Optional, Union
from pygwalker._typing import DataFrame, IAppearance, IThemeKey
from pygwalker.data_parsers.database_parser import Connector
Expand Down Expand Up @@ -37,6 +36,16 @@ def render(
kanaries_api_key=kanaries_api_key,
**kwargs
)
elif can_open_window():
return webview.render(
dataset,
spec,
theme_key=theme_key,
appearance=appearance,
kernel_computation=kernel_computation,
kanaries_api_key=kanaries_api_key,
**kwargs
)
else:
return repl.render(
dataset,
Expand Down
18 changes: 13 additions & 5 deletions pygwalker/adapter/table.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from pygwalker.adapter.utils import is_notebook
import pygwalker.api.repl as repl
import pygwalker.api.jupyter as jupyter
from typing import Optional, Union
from pygwalker.adapter.utils import can_open_window, is_notebook
from pygwalker.api import repl, webview, jupyter
from typing import Optional, Union
from pygwalker._typing import DataFrame, IAppearance, IThemeKey
from pygwalker.data_parsers.database_parser import Connector

Expand Down Expand Up @@ -34,6 +33,15 @@ def table(
kanaries_api_key=kanaries_api_key,
**kwargs
)
elif can_open_window():
return webview.table(
dataset,
theme_key=theme_key,
appearance=appearance,
kernel_computation=kernel_computation,
kanaries_api_key=kanaries_api_key,
**kwargs
)
else:
return repl.table(
dataset,
Expand All @@ -42,4 +50,4 @@ def table(
kernel_computation=kernel_computation,
kanaries_api_key=kanaries_api_key,
**kwargs
)
)
22 changes: 22 additions & 0 deletions pygwalker/adapter/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,25 @@ def is_notebook() -> bool:
return False # Other type (?)
except NameError:
return False # Probably standard Python interpreter

def can_open_window() -> bool:
import os
import platform

# Check if running in SSH session
if 'SSH_CONNECTION' in os.environ:
return False

system = platform.system()

if system == 'Darwin': # macOS
# macOS can typically always open windows unless in remote session
return True
elif system == 'Linux':
# Check for X11 or Wayland display
return bool(os.environ.get('DISPLAY') or os.environ.get('WAYLAND_DISPLAY'))
elif system == 'Windows':
# Windows can typically always open windows unless in remote session
return True
else:
return False # Unknown OS, assume no GUI capability
22 changes: 19 additions & 3 deletions pygwalker/adapter/walk.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from pygwalker.adapter.utils import is_notebook
import pygwalker.api.repl as repl
import pygwalker.api.jupyter as jupyter
from pygwalker.adapter.utils import is_notebook, can_open_window
from pygwalker.api import repl, webview, jupyter
from typing import List, Optional, Union
from pygwalker._typing import DataFrame, IAppearance, IThemeKey
from pygwalker.data_parsers.database_parser import Connector
Expand Down Expand Up @@ -59,6 +58,23 @@ def walk(
default_tab=default_tab,
**kwargs
)
elif can_open_window():
return webview.walk(
dataset,
gid,
env=env,
field_specs=field_specs,
theme_key=theme_key,
appearance=appearance,
spec=spec,
use_kernel_calc=use_kernel_calc,
kernel_computation=kernel_computation,
cloud_computation=cloud_computation,
show_cloud_tool=show_cloud_tool,
kanaries_api_key=kanaries_api_key,
default_tab=default_tab,
**kwargs
)
else:
return repl.walk(
dataset,
Expand Down
25 changes: 16 additions & 9 deletions pygwalker/api/repl.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,12 @@
from pygwalker.data_parsers.base import FieldSpec
from pygwalker.data_parsers.database_parser import Connector
from pygwalker._typing import DataFrame, IAppearance, IThemeKey
from bottle import Bottle, request, response
from bottle import Bottle, request, response, run
from pygwalker.utils.check_walker_params import check_expired_params
from pygwalker.utils import fallback_value
from pygwalker.utils.encode import DataFrameEncoder
import webview

def start_webview(walker: PygWalker):
def start_server(walker: PygWalker):
comm = BaseCommunication(walker.gid)
walker._init_callback(comm)
app = Bottle()
Expand All @@ -35,9 +34,17 @@ def pyg_html():
props["communicationUrl"] = "comm"
html = walker._get_render_iframe(props, True)
return html

webview.create_window('Pygwalker', app)
webview.start(debug=True)

port = 3000
while True:
try:
run(app, host='0.0.0.0', port=port)
break
except OSError as e:
if e.errno == 98: # Address already in use
port += 1
else:
raise


def walk(
Expand Down Expand Up @@ -97,7 +104,7 @@ def walk(
cloud_computation=cloud_computation,
gw_mode="explore",
)
start_webview(walker)
start_server(walker)

def render(
dataset: Union[DataFrame, Connector, str],
Expand Down Expand Up @@ -141,7 +148,7 @@ def render(
**kwargs
)

start_webview(walker)
start_server(walker)

def table(
dataset: Union[DataFrame, Connector, str],
Expand Down Expand Up @@ -182,4 +189,4 @@ def table(
**kwargs
)

start_webview(walker)
start_server(walker)
185 changes: 185 additions & 0 deletions pygwalker/api/webview.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
from typing import Union, List, Optional, Dict, Any
from pygwalker.communications.base import BaseCommunication

from typing_extensions import Literal
import json
from .pygwalker import PygWalker
from pygwalker.data_parsers.base import FieldSpec
from pygwalker.data_parsers.database_parser import Connector
from pygwalker._typing import DataFrame, IAppearance, IThemeKey
from bottle import Bottle, request, response
from pygwalker.utils.check_walker_params import check_expired_params
from pygwalker.utils import fallback_value
from pygwalker.utils.encode import DataFrameEncoder
import webview

def start_webview(walker: PygWalker):
comm = BaseCommunication(walker.gid)
walker._init_callback(comm)
app = Bottle()
# api path and html path need to have the same prefix
@app.route("/comm/", methods=["POST"])
@app.route("/comm/<gid>", methods=["POST"])
def pygwalker_comm(gid):
payload = request.json
comm_obj = walker.comm
result = comm_obj._receive_msg(payload["action"], payload["data"])
response.content_type = 'application/json'
return json.dumps(result, cls=DataFrameEncoder)


# api path and html path need to have the same prefix
@app.route("/")
def pyg_html():
props = walker._get_props("web_server")
props["communicationUrl"] = "comm"
html = walker._get_render_iframe(props, True)
return html

webview.create_window('Pygwalker', app)
webview.start(debug=True)


def walk(
dataset: Union[DataFrame, Connector, str],
gid: Union[int, str] = None,
*,
env: Literal['Jupyter', 'JupyterWidget'] = 'JupyterWidget',
field_specs: Optional[List[FieldSpec]] = None,
theme_key: IThemeKey = 'g2',
appearance: IAppearance = 'media',
spec: str = "",
use_kernel_calc: Optional[bool] = None,
kernel_computation: Optional[bool] = None,
cloud_computation: bool = False,
show_cloud_tool: bool = True,
kanaries_api_key: str = "",
default_tab: Literal["data", "vis"] = "vis",
**kwargs
):
"""Walk through pandas.DataFrame df with Graphic Walker
Args:
- dataset (pl.DataFrame | pd.DataFrame | Connector, optional): dataframe.
- gid (Union[int, str], optional): GraphicWalker container div's id ('gwalker-{gid}')
Kargs:
- env: (Literal['Jupyter' | 'JupyterWidget'], optional): The enviroment using pygwalker. Default as 'JupyterWidget'
- field_specs (List[FieldSpec], optional): Specifications of some fields. They'll been automatically inferred from `df` if some fields are not specified.
- theme_key ('vega' | 'g2' | 'streamlit'): theme type.
- appearance (Literal['media' | 'light' | 'dark']): 'media': auto detect OS theme.
- spec (str): chart config data. config id, json, remote file url
- use_kernel_calc(bool): Whether to use kernel compute for datas, Default to None, automatically determine whether to use kernel calculation.
- kanaries_api_key (str): kanaries api key, Default to "".
- default_tab (Literal["data", "vis"]): default tab to show. Default to "vis"
- cloud_computation(bool): Whether to use cloud compute for datas, it upload your data to kanaries cloud. Default to False.
"""
check_expired_params(kwargs)

if field_specs is None:
field_specs = []

walker = PygWalker(
gid=gid,
dataset=dataset,
field_specs=field_specs,
spec=spec,
source_invoke_code="",
theme_key=theme_key,
appearance=appearance,
show_cloud_tool=show_cloud_tool,
use_preview=False,
kernel_computation=(isinstance(dataset, (Connector, str)) or fallback_value(kernel_computation, use_kernel_calc)),
is_export_dataframe=False,
use_save_tool=False,
kanaries_api_key=kanaries_api_key,
default_tab=default_tab,
cloud_computation=cloud_computation,
gw_mode="explore",
)
start_webview(walker)

def render(
dataset: Union[DataFrame, Connector, str],
spec: str,
*,
theme_key: IThemeKey = 'g2',
appearance: IAppearance = 'media',
kernel_computation: Optional[bool] = None,
kanaries_api_key: str = "",
**kwargs
):
"""
Args:
- dataset (pl.DataFrame | pd.DataFrame | Connector, optional): dataframe.
- spec (str): chart config data. config id, json, remote file url
Kargs:
- theme_key ('vega' | 'g2'): theme type.
- appearance (Literal['media' | 'light' | 'dark']): 'media': auto detect OS theme.
- kernel_computation(bool): Whether to use kernel compute for datas, Default to None.
- kanaries_api_key (str): kanaries api key, Default to "".
"""

walker = PygWalker(
gid=None,
dataset=dataset,
field_specs=[],
spec=spec,
source_invoke_code="",
theme_key=theme_key,
appearance=appearance,
show_cloud_tool=False,
use_preview=False,
kernel_computation=isinstance(dataset, (Connector, str)) or kernel_computation,
use_save_tool=False,
gw_mode="filter_renderer",
is_export_dataframe=True,
kanaries_api_key=kanaries_api_key,
default_tab="vis",
cloud_computation=False,
**kwargs
)

start_webview(walker)

def table(
dataset: Union[DataFrame, Connector, str],
*,
theme_key: IThemeKey = 'g2',
appearance: IAppearance = 'media',
kernel_computation: Optional[bool] = None,
kanaries_api_key: str = "",
**kwargs
):
"""
Args:
- dataset (pl.DataFrame | pd.DataFrame | Connector, optional): dataframe.
Kargs:
- theme_key ('vega' | 'g2'): theme type.
- appearance (Literal['media' | 'light' | 'dark']): 'media': auto detect OS theme.
- kernel_computation(bool): Whether to use kernel compute for datas, Default to None.
- kanaries_api_key (str): kanaries api key, Default to "".
"""
walker = PygWalker(
gid=None,
dataset=dataset,
field_specs=[],
spec="",
source_invoke_code="",
theme_key=theme_key,
appearance=appearance,
show_cloud_tool=False,
use_preview=False,
kernel_computation=isinstance(dataset, (Connector, str)) or kernel_computation,
use_save_tool=False,
gw_mode="table",
is_export_dataframe=True,
kanaries_api_key=kanaries_api_key,
default_tab="vis",
cloud_computation=False,
**kwargs
)

start_webview(walker)

0 comments on commit 8166c3a

Please sign in to comment.