Skip to content
Open
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
2 changes: 2 additions & 0 deletions dash/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
venv/
.idea/
1 change: 1 addition & 0 deletions dash/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
venv/
10 changes: 10 additions & 0 deletions dash/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
FROM python:3.10
WORKDIR /code

COPY requirements.txt /
RUN pip install -r /requirements.txt
COPY ./ ./

EXPOSE 8050

CMD ["python", "./app.py"]
75 changes: 75 additions & 0 deletions dash/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import logging
import os

import dash
import dash_bootstrap_components as dbc
from dash import Dash, Output, Input, dcc
from dash import html

from util import get_authz

external_stylesheets = [dbc.themes.SKETCHY]

logger = logging.getLogger('dash')

print('DASH_URL_BASE_PATHNAME', os.environ.get('DASH_URL_BASE_PATHNAME', default="~not set~"))
app = Dash(__name__, external_stylesheets=external_stylesheets, use_pages=True)


@app.server.before_request
def check_privileges():
"""Do this before every call"""
get_authz()


# Clientside callback: refresh token by calling fence's /user endpoint
app.clientside_callback(
"""
// Call fence's /user endpoint, parse the response and update the profile
async function(n_intervals, data) {
const response = await fetch(location.origin + '/user/user');
if (!response.ok) {
console.log('error retrieving user', response )
return 'Profile (unauthorized)';
} else {
const user = await response.json();
console.log('clientside_callback you are logged in as:', user.username);
return 'Profile (' + user.username + ')';
}
}
""",
Output('nav_item-profile', 'children'),
Input('clientside-interval', 'n_intervals')
)


app.layout = dbc.Container([
html.H1("ACED", className="display-3"),
html.P(
"A simple dash app.",
className="lead",
),

dbc.Nav(
[
dbc.NavItem(
dbc.NavLink(f"{page['name']}", href=page["relative_path"], id=f'nav_item-{page["name"].lower()}')
)
for page in dash.page_registry.values()
]
),

html.Hr(className="my-2"),
# define a timed client side action here
dcc.Interval(
id='clientside-interval',
n_intervals=0,
interval=60 * 1000 # in milliseconds check every minute
),
# other page contents goes here
dash.page_container
])


if __name__ == '__main__':
app.run_server(host="0.0.0.0", debug=True) #
Binary file added dash/assets/gitops-logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
123 changes: 123 additions & 0 deletions dash/figures/histogram.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import logging

import dash_bootstrap_components as dbc
import pandas as pd
import plotly.express as px
from dash import html, dcc

logger = logging.getLogger('dash')


def histogram_figures(histograms):
"""An array of histograms figures, dataframes and names.
@return fig[], df[], name[]"""

dfs = []
figs = []
names = []

assert len(histograms._aggregation.keys()) == 1 # noqa
entity = list(histograms._aggregation.keys())[0] # noqa
for k, v in histograms._aggregation[entity].items(): # noqa
v.name = k
df = pd.DataFrame(v.histogram)
fig = px.histogram(df, x="key", y="count", title=v.name, log_y=len(v.histogram) > 1,
id={
'index': f"{entity}-{k}",
'type': 'query-parameter'
}
)
fig.update_layout(legend=dict(orientation="h", title=None),
yaxis_title=None, xaxis_title=None,
plot_bgcolor='rgba(0,0,0,0)'
)

figs.append(fig)
dfs.append(df)
names.append(v.name)

return figs, dfs, names


def histogram_selects(histograms):
"""An array of histograms checklists dataframes, and names.
@return fig[], df[], name[]"""

dfs = []
checklists = []
names = []

assert len(histograms._aggregation.keys()) == 1 # noqa
entity = list(histograms._aggregation.keys())[0] # noqa
for k, v in histograms._aggregation[entity].items(): # noqa
v.name = k
if not any([isinstance(h.key, str) for h in v.histogram]):
continue
df = pd.DataFrame(v.histogram)
checklist = dcc.Checklist(
id={
'index': f"{entity}-{k}",
'type': 'query-parameter'
},
options=[
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this a style structure?

{
'value': str(h.key),
'label': html.Div(
[
html.Div(h.key),
dbc.Badge(h.count, className="ms-1 term-count", color="info",
id={
'index': f"{entity}-{k}-{h.key}",
'type': 'term-count'
})
],
style={'display': 'inline-flex', 'paddingLeft': '2em'}
)
}
for h in v.histogram
],
labelStyle={'display': 'flex'}
)

checklists.append(checklist)
dfs.append(df)
names.append(v.name)

return checklists, dfs, names


def histogram_sliders(histograms):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what are histogram sliders?

"""An array of histograms sliders dataframes, and names.
@return slider[], df[], name[]"""

dfs = []
sliders = []
names = []

assert len(histograms._aggregation.keys()) == 1 # noqa
entity = list(histograms._aggregation.keys())[0] # noqa
for k, v in histograms._aggregation[entity].items(): # noqa
v.name = k
if any([isinstance(h.key, str) for h in v.histogram]):
continue
if not any([isinstance(h.key, list) for h in v.histogram]):
continue

assert len(v.histogram) == 1
df = pd.DataFrame(v.histogram)
min_ = int(v.histogram[0].key[0])
max_ = int(v.histogram[0].key[1])
# value = max_,
sliders.append(
dcc.RangeSlider(min_, max_, int((max_ - min_) / 10),
id={
'index': f"{entity}-{k}",
'type': 'query-parameter'
}
)
)

dfs.append(df)
names.append(v.name)

return sliders, dfs, names
31 changes: 31 additions & 0 deletions dash/figures/project.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

import pandas as pd
import plotly.express as px
from inflection import titleize, pluralize
from models.project import project_detail_counts


def counts():
"""Horizontal bar graph.
@return fig, df"""

project_counts = list(project_detail_counts())
flattened = []
for p in project_counts:
for k, v in p.items():
f = {'name': p.project[0].name}
if k == 'project':
continue
f['entity'] = titleize(pluralize(k.replace('_count', '')))
f['count'] = v
flattened.append(f)
df = pd.DataFrame(flattened)
fig = px.bar(df, x="count", y="entity", color='name', orientation='h',
hover_data=["name", "count"],
height=400,
log_x=True)
fig.update_layout(legend=dict(orientation="h", title=None), yaxis_title=None, xaxis_title=None,
# paper_bgcolor='rgba(0,0,0,0)',
plot_bgcolor='rgba(0,0,0,0)'
)
return fig, df
Empty file added dash/models/__init__.py
Empty file.
126 changes: 126 additions & 0 deletions dash/models/file.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@

from dotwiz import DotWiz
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is DotWiz?

from util import get_guppy_service

import logging
logger = logging.getLogger('dash')


def get_files(dot_notation=True, variables={"filter": {"AND": []}, "sort": []}):
"""Fetch histogram of counts for all projects.
@param variables: a graphql filter and sort
@type dot_notation: bool render results as a lightweight class"""
query = """
query ($sort: JSON,$filter: JSON,) {
file (accessibility: all, offset: 0, first: 1000, , sort: $sort, filter: $filter,) {
file_id
patient_id
file_category
file_name
file_size
object_id
}
_aggregation {
file (filter: $filter, accessibility: all) {
_totalCount
}
}
}
"""
guppy_service = get_guppy_service()
data = guppy_service.graphql_query(query, variables=variables)['data']
data = DotWiz(data)
return [f for f in data.file]


def get_file_histograms(dot_notation=True, variables={"filter": {"AND": []}}):
"""Fetch histogram of counts for all projects.
@param variables: a graphql filter
@type dot_notation: bool render results as a lightweight class"""

histogram_query = """
query ($filter: JSON) {
_aggregation {
file (filter: $filter, filterSelf: false, accessibility: all) {

project_id {
histogram {
key
count
}
},
file_category {
histogram {
key
count
}
},
data_type {
histogram {
key
count
}
},
data_format {
histogram {
key
count
}
},
patient_id {
histogram {
key
count
}
},
patient_gender {
histogram {
key
count
}
},
patient_disability_adjusted_life_years {
histogram {
key
count
}
},
patient_ombCategory {
histogram {
key
count
}
},
patient_ombCategory_detail {
histogram {
key
count
}
},
patient_us_core_birthsex {
histogram {
key
count
}
},
patient_quality_adjusted_life_years {
histogram {
key
count
}
},
patient_maritalStatus_coding_0_display {
histogram {
key
count
}
}
}
}
}
"""
guppy_service = get_guppy_service()
data = guppy_service.graphql_query(histogram_query, variables=variables)['data']
if dot_notation:
return DotWiz(data)
return data
Loading