# Copyright 2021 AI Singapore. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from typing import Union
import dash
import dash_core_components as dcc
import dash_html_components as html
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output
from rarity.app import app
from rarity.data_loader import CSVDataLoader, DataframeLoader
from rarity.features import GeneralMetrics, MissPredictions, LossClusters, FeatureDistribution, SimilaritiesCF
[docs]class GapAnalyzer:
'''
GapAnalyzer is the main class object collating all developed feature components for Rarity.
Auto-generated error analysis supports single model and bimodal (max at comparison of 2 models side by side) on tasks
such as regression, binary classification and multiclass classification
Args:
data_loader (:class:`~rarity.data_loader.CSVDataLoader` or :class:`~rarity.data_loader.DataframeLoader`):
This is the class object from data_loader compiling ``xfeatures``, ``yTrue``, ``yPredict`` via either ``CSVDataLoader`` \
(for both offline and inline analysis) or ``DataframeLoader`` (for inline analysis)
user_defined_title (str):
Title of analysis, text field defined by user
user_defined_port (int):
Port defined by user to spin up Rarity's gap analysis. If not mentioned, defaults to 8000.
Important Attributes:
analysis_type (str):
Analysis type defined by user. Corresponding feature components will be auto-populated based on the \
specified analysis type. Supported analysis types : ``Regression``, ``Binary Classification``, ``Multiclass Classification``
'''
def __init__(self, data_loader: Union[CSVDataLoader, DataframeLoader], user_defined_title: str = None, user_defined_port=8000):
self.data_loader = data_loader
self.analysis_type = self.data_loader.get_analysis_type().replace('-', ' ').title()
self.usr_defined_title = user_defined_title
self.usr_defined_port = user_defined_port
[docs] def _layout(self) -> dbc.Container:
'''
The main app layout of Rarity
'''
main_layout = dbc.Container([
dbc.Jumbotron(
dbc.Container([
dbc.Row([
dbc.Col(html.Div([
# html.Img(className='header__rarity-logo', src='assets/rarity-icon.png'),
html.Img(className='header__rarity-logo', src=app.get_asset_url('rarity-icon.png')),
html.H4('Gap Analysis with Rarity 1.0', className='header__rarity-title'),
html.Pre(f'| {self.usr_defined_title}', className='header__usr-pjt-title'),
]), width=8, md=8, sm=9, className='header__first-row-col-left align-self-center'),
dbc.Col(html.Div(
html.H4(self.analysis_type, className='header__analysis-type')),
width='auto', className='align-self-center'),
], className='justify-content-between'),
dbc.Row([
html.Div([
dcc.Tabs(id='tabs-feature-page', value='gen-metrics', children=[
dcc.Tab(label='General Metrics',
value='gen-metrics',
className='header__nav-tab',
selected_className='header__nav-tab-selected',),
dcc.Tab(label='Miss Predictions',
value='miss-pred',
className='header__nav-tab',
selected_className='header__nav-tab-selected',),
dcc.Tab(label='Loss Clusters',
value='loss-clust',
className='header__nav-tab',
selected_className='header__nav-tab-selected'),
dcc.Tab(label='xFeature Distribution',
value='xfeat-dist',
className='header__nav-tab',
selected_className='header__nav-tab-selected'),
dcc.Tab(label='Similarities',
value='similarities-cf',
className='header__nav-tab',
selected_className='header__nav-tab-selected'),
], className='header__nav-row'),
]),
], className='header__nav-row')
], fluid=True), fluid=True, className='sticky-top'),
dbc.Container(html.Div(id='feature-page', children=[]), fluid=True),
], fluid=True)
return main_layout
[docs] def run(self) -> dash.Dash:
'''
Spin up Rarity web application built with ``dash`` components
'''
app.layout = self._layout()
@app.callback(Output('feature-page', 'children'),
[Input('tabs-feature-page', 'value')])
def display_page(pathname='gen-metrics'):
if pathname == 'gen-metrics':
return GeneralMetrics(self.data_loader).show()
elif pathname == 'miss-pred':
return MissPredictions(self.data_loader).show()
elif pathname == 'loss-clust':
return LossClusters(self.data_loader).show()
elif pathname == 'xfeat-dist':
return FeatureDistribution(self.data_loader).show()
elif pathname == 'similarities-cf':
return SimilaritiesCF(self.data_loader).show()
else:
return html.Div([html.H3('feature page {}'.format(pathname))], style={'padding-left': '30px'})
MissPredictions(self.data_loader).callbacks()
LossClusters(self.data_loader).callbacks()
FeatureDistribution(self.data_loader).callbacks()
SimilaritiesCF(self.data_loader).callbacks()
app.run_server(debug=False, port=self.usr_defined_port)