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

Fixes evidentlyai/evidently#1030 negative values on axes #1183

Merged
Show file tree
Hide file tree
Changes from all 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
8 changes: 0 additions & 8 deletions src/evidently/renderers/notebook_utils.py

This file was deleted.

40 changes: 30 additions & 10 deletions src/evidently/suite/base_suite.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
from evidently.renderers.base_renderer import MetricRenderer
from evidently.renderers.base_renderer import RenderersDefinitions
from evidently.renderers.base_renderer import TestRenderer
from evidently.renderers.notebook_utils import determine_template
from evidently.tests.base_test import Test
from evidently.tests.base_test import TestParameters
from evidently.tests.base_test import TestResult
Expand All @@ -44,6 +43,8 @@
from evidently.utils.dashboard import SaveMode
from evidently.utils.dashboard import SaveModeMap
from evidently.utils.dashboard import TemplateParams
from evidently.utils.dashboard import file_html_template
from evidently.utils.dashboard import inline_iframe_html_template
from evidently.utils.dashboard import save_data_file
from evidently.utils.dashboard import save_lib_files
from evidently.utils.data_preprocessing import DataDefinition
Expand Down Expand Up @@ -124,7 +125,10 @@ def get_data_definition(
if self.engine is None:
raise ValueError("Cannot create data definition when engine is not set")
self.data_definition = self.engine.get_data_definition(
current_data, reference_data, column_mapping, categorical_features_cardinality
current_data,
reference_data,
column_mapping,
categorical_features_cardinality,
)
return self.data_definition

Expand Down Expand Up @@ -207,7 +211,7 @@ def _repr_html_(self):
dashboard_info=dashboard_info,
additional_graphs=graphs,
)
return self._render(determine_template("auto"), template_params)
return self._render(inline_iframe_html_template, template_params)

def show(self, mode="auto"):
"""
Expand All @@ -227,7 +231,7 @@ def show(self, mode="auto"):
try:
from IPython.display import HTML

return HTML(self._render(determine_template(mode), template_params))
return HTML(self._render(inline_iframe_html_template, template_params))
except ImportError as err:
raise Exception("Cannot import HTML from IPython.display, no way to show html") from err

Expand All @@ -238,9 +242,13 @@ def get_html(self):
dashboard_info=dashboard_info,
additional_graphs=graphs,
)
return self._render(determine_template("inline"), template_params)
return self._render(file_html_template, template_params)

def save_html(self, filename: Union[str, IO], mode: Union[str, SaveMode] = SaveMode.SINGLE_FILE):
def save_html(
self,
filename: Union[str, IO],
mode: Union[str, SaveMode] = SaveMode.SINGLE_FILE,
):
dashboard_id, dashboard_info, graphs = self._build_dashboard_info()
if isinstance(mode, str):
_mode = SaveModeMap.get(mode)
Expand All @@ -253,7 +261,7 @@ def save_html(self, filename: Union[str, IO], mode: Union[str, SaveMode] = SaveM
dashboard_info=dashboard_info,
additional_graphs=graphs,
)
render = self._render(determine_template("inline"), template_params)
render = self._render(file_html_template, template_params)
if isinstance(filename, str):
with open(filename, "w", encoding="utf-8") as out_file:
out_file.write(render)
Expand All @@ -275,7 +283,7 @@ def save_html(self, filename: Union[str, IO], mode: Union[str, SaveMode] = SaveM
include_js_files=[lib_file, data_file],
)
with open(filename, "w", encoding="utf-8") as out_file:
out_file.write(self._render(determine_template("inline"), template_params))
out_file.write(self._render(file_html_template, template_params))

@abc.abstractmethod
def as_dict(
Expand All @@ -296,7 +304,14 @@ def _get_json_content(
) -> dict:
"""Return all data for json representation"""
result = {"version": evidently.__version__}
result.update(self.as_dict(include_render=include_render, include=include, exclude=exclude, **kwargs))
result.update(
self.as_dict(
include_render=include_render,
include=include,
exclude=exclude,
**kwargs,
)
)
return result

def json(
Expand All @@ -307,7 +322,12 @@ def json(
**kwargs,
) -> str:
return json.dumps(
self._get_json_content(include_render=include_render, include=include, exclude=exclude, **kwargs),
self._get_json_content(
include_render=include_render,
include=include,
exclude=exclude,
**kwargs,
),
cls=NumpyEncoder,
allow_nan=True,
)
Expand Down
71 changes: 57 additions & 14 deletions src/evidently/ui/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
from evidently._pydantic_compat import PrivateAttr
from evidently._pydantic_compat import parse_obj_as
from evidently.model.dashboard import DashboardInfo
from evidently.renderers.notebook_utils import determine_template
from evidently.suite.base_suite import MetadataValueType
from evidently.suite.base_suite import ReportBase
from evidently.suite.base_suite import Snapshot
Expand All @@ -50,6 +49,7 @@
from evidently.ui.type_aliases import UserID
from evidently.utils import NumpyEncoder
from evidently.utils.dashboard import TemplateParams
from evidently.utils.dashboard import inline_iframe_html_template


class BlobMetadata(BaseModel):
Expand Down Expand Up @@ -208,12 +208,16 @@ def get_snapshot_metadata(self, id: SnapshotID) -> SnapshotMetadata:
return self.project_manager.get_snapshot_metadata(self._user_id, self.id, id)

def build_dashboard_info(
self, timestamp_start: Optional[datetime.datetime], timestamp_end: Optional[datetime.datetime]
self,
timestamp_start: Optional[datetime.datetime],
timestamp_end: Optional[datetime.datetime],
) -> DashboardInfo:
return self.dashboard.build(self.project_manager.data, self.id, timestamp_start, timestamp_end)

def show_dashboard(
self, timestamp_start: Optional[datetime.datetime] = None, timestamp_end: Optional[datetime.datetime] = None
self,
timestamp_start: Optional[datetime.datetime] = None,
timestamp_end: Optional[datetime.datetime] = None,
):
dashboard_info = self.build_dashboard_info(timestamp_start, timestamp_end)
template_params = TemplateParams(
Expand All @@ -225,7 +229,7 @@ def show_dashboard(
try:
from IPython.display import HTML

return HTML(determine_template("inline")(params=template_params))
return HTML(inline_iframe_html_template(params=template_params))
except ImportError as err:
raise Exception("Cannot import HTML from IPython.display, no way to show html") from err

Expand Down Expand Up @@ -257,7 +261,11 @@ def list_projects(self, project_ids: Optional[Set[ProjectID]]) -> List[Project]:

@abstractmethod
def add_snapshot(
self, project_id: ProjectID, snapshot: Snapshot, blob: "BlobMetadata", out_dataset_id: Optional[str] = None
self,
project_id: ProjectID,
snapshot: Snapshot,
blob: "BlobMetadata",
out_dataset_id: Optional[str] = None,
):
raise NotImplementedError

Expand All @@ -271,7 +279,10 @@ def search_project(self, project_name: str, project_ids: Optional[Set[ProjectID]

@abstractmethod
def list_snapshots(
self, project_id: ProjectID, include_reports: bool = True, include_test_suites: bool = True
self,
project_id: ProjectID,
include_reports: bool = True,
include_test_suites: bool = True,
) -> List[SnapshotMetadata]:
raise NotImplementedError

Expand Down Expand Up @@ -485,7 +496,10 @@ class AuthManager(ABC):
allow_default_user: bool = True

def refresh_default_roles(self):
for (default_role, entity_type), permissions in DEFAULT_ROLE_PERMISSIONS.items():
for (
default_role,
entity_type,
), permissions in DEFAULT_ROLE_PERMISSIONS.items():
role = self.get_default_role(default_role, entity_type)
if role.permissions != permissions:
role.permissions = permissions
Expand All @@ -503,7 +517,11 @@ def get_available_project_ids(

@abstractmethod
def check_entity_permission(
self, user_id: UserID, entity_type: EntityType, entity_id: EntityID, permission: Permission
self,
user_id: UserID,
entity_type: EntityType,
entity_id: EntityID,
permission: Permission,
) -> bool:
raise NotImplementedError

Expand Down Expand Up @@ -607,7 +625,12 @@ def _revoke_entity_role(self, entity_type: EntityType, entity_id: EntityID, user
raise NotImplementedError

def revoke_entity_role(
self, manager: UserID, entity_type: EntityType, entity_id: EntityID, user_id: UserID, role: Role
self,
manager: UserID,
entity_type: EntityType,
entity_id: EntityID,
user_id: UserID,
role: Role,
):
if not self.check_entity_permission(manager, entity_type, entity_id, Permission.REVOKE_ROLE):
raise NotEnoughPermissions()
Expand Down Expand Up @@ -663,7 +686,13 @@ def list_roles(self, entity_type: Optional[EntityType]) -> List[Role]:


class ProjectManager:
def __init__(self, metadata: MetadataStorage, blob: BlobStorage, data: DataStorage, auth: AuthManager):
def __init__(
self,
metadata: MetadataStorage,
blob: BlobStorage,
data: DataStorage,
auth: AuthManager,
):
self.metadata: MetadataStorage = metadata
self.blob: BlobStorage = blob
self.data: DataStorage = data
Expand All @@ -680,7 +709,10 @@ def create_project(

project = self.add_project(
Project(
name=name, description=description, dashboard=DashboardConfig(name=name, panels=[]), team_id=team_id
name=name,
description=description,
dashboard=DashboardConfig(name=name, panels=[]),
team_id=team_id,
),
user_id,
team_id,
Expand Down Expand Up @@ -753,14 +785,22 @@ def delete_snapshot(self, user_id: UserID, project_id: ProjectID, snapshot_id: S
self.metadata.delete_snapshot(project_id, snapshot_id)

def search_project(
self, user_id: UserID, project_name: str, team_id: Optional[TeamID], org_id: Optional[OrgID]
self,
user_id: UserID,
project_name: str,
team_id: Optional[TeamID],
org_id: Optional[OrgID],
) -> List[Project]:
user = self.auth.get_or_default_user(user_id)
project_ids = self.auth.get_available_project_ids(user.id, team_id, org_id)
return [p.bind(self, user.id) for p in self.metadata.search_project(project_name, project_ids)]

def list_snapshots(
self, user_id: UserID, project_id: ProjectID, include_reports: bool = True, include_test_suites: bool = True
self,
user_id: UserID,
project_id: ProjectID,
include_reports: bool = True,
include_test_suites: bool = True,
) -> List[SnapshotMetadata]:
if not self.auth.check_entity_permission(user_id, EntityType.Project, project_id, Permission.PROJECT_READ):
raise NotEnoughPermissions()
Expand All @@ -770,7 +810,10 @@ def list_snapshots(
return snapshots

def load_snapshot(
self, user_id: UserID, project_id: ProjectID, snapshot: Union[SnapshotID, SnapshotMetadata]
self,
user_id: UserID,
project_id: ProjectID,
snapshot: Union[SnapshotID, SnapshotMetadata],
) -> Snapshot:
if isinstance(snapshot, SnapshotID):
snapshot = self.get_snapshot_metadata(user_id, project_id, snapshot)
Expand Down
Loading
Loading