Skip to content

Commit

Permalink
Merge pull request #14 from jan-behrends/main
Browse files Browse the repository at this point in the history
Several bug fixes and a new option.
  • Loading branch information
jblattgerste authored Aug 2, 2024
2 parents cd408ae + 0fb4336 commit 2e3ee18
Show file tree
Hide file tree
Showing 7 changed files with 171 additions and 165 deletions.
242 changes: 120 additions & 122 deletions ChartLayouts.py

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# syntax=docker/dockerfile:1

FROM python:3.8-slim-buster
FROM python:3.9-slim-buster

WORKDIR /dashApp

Expand Down
3 changes: 2 additions & 1 deletion Helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from dash import html, dcc
import io
from dash.dash_table.Format import Format, Scheme
from plotly.graph_objs import Figure

import ChartLayouts
from Result import Result
Expand Down Expand Up @@ -62,7 +63,7 @@ def stringListToFloat(stringList):


def downloadChartContentSingleStudy(fig):
fig = copy.copy(fig)
fig: Figure = copy.copy(fig)
fig.update_layout(
paper_bgcolor='rgba(255,255,255,255)',
font=dict(
Expand Down
13 changes: 10 additions & 3 deletions SUSStud.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ def __init__(self, results, name):
self.avgScorePerQuestion, self.scoresPerQuestion = self.calcSUSScorePerQuestion()
self.name = name
self.standardDevPerQuestion = self.calcStandardDevPerQuestion()
self.popStandardDevOverall = self.calcPopulationStandardDev()
self.standardDevOverall = self.calcStandardDev()
self.median = self.calcMedian()
self.rawResultPerQuestion = self.getRawResultPerQuestion()
Expand Down Expand Up @@ -80,16 +81,15 @@ def calcStandardDevPerQuestion(self):
standardDeviations = []
for question in self.scoresPerQuestion.values():
try:
standardDeviations.append(statistics.pstdev(question))
standardDeviations.append(statistics.stdev(question))
except statistics.StatisticsError:
standardDeviations.append(0)

return standardDeviations

def calcStandardDev(self):
standardDev = 0
try:
standardDev = statistics.pstdev(self.getAllSUSScores())
standardDev = statistics.stdev(self.getAllSUSScores())
except statistics.StatisticsError:
standardDev = 0
return standardDev
Expand All @@ -100,3 +100,10 @@ def calcMedian(self):
except statistics.StatisticsError:
median = 0
return median

def calcPopulationStandardDev(self):
try:
standardDev = statistics.pstdev(self.getAllSUSScores())
except statistics.StatisticsError:
standardDev = 0
return standardDev
66 changes: 33 additions & 33 deletions dashApp.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import copy
import traceback
import dash
import plotly
from dash import dcc
from dash import html
from dash.dependencies import Input, Output, State
Expand All @@ -19,7 +20,7 @@
import zipfile
import tempfile

VERSION = '1.0.101.23'
VERSION = '1.0.207.24'

app = dash.Dash(__name__)
app.title = 'SUS Analysis Toolkit'
Expand Down Expand Up @@ -263,16 +264,28 @@ def update_single_study(contents_single, table_data, table_columns, add_row_butt


@app.callback(
Output('download-single-study-chart', 'children'),
Output('single-study-chart', 'figure'),
Input('sessionPlotData-single', 'data'),
Input('preset-single-study', 'value'),
Input('preset-single-study', 'value')
)
def update_SingleStudyMainplot(data_single, presetValue):
df = pd.read_json(data_single, orient='split')
SUSData = SUSDataset(Helper.parseDataFrameToSUSDataset(df))
fig = SingleStudyCharts.singleStudyPresetDict[presetValue](SUSData.SUSStuds[0])
return Helper.downloadChartContentSingleStudy(fig), fig
return fig

@app.callback(
Output("download-single-study-chart", "data"),
Input("download-single-study-chart-button", "n_clicks"),
State('single-study-chart', 'figure'),
prevent_initial_call=True,
)
def download_singlestudy_chart(n_clicks, figure):
figure = plotly.graph_objects.Figure(figure)
img_bytes = figure.to_image(format="png", width=1530, height=1048)
return dcc.send_bytes(src=img_bytes,
filename="single_study_plot.png")



@app.callback(
Expand All @@ -294,16 +307,18 @@ def update_SingleStudyMainplot(data_single, presetValue):
Input('axis-title-mainplot', 'value'),
Input('download-type-mainplot', 'value'),
Input('sort-by-mainplot', 'value'),
Input('colorize-by-scale', 'value')
Input('colorize-by-scale', 'value'),
Input('sd_type-mainplot', 'value')
)
def update_Mainplot(systemsToPlot, data, datapointsValues, scaleValue, orientationValue, plotStyle, mean_sdValue,
axis_title, download_format, sort_value, colorizeByScale):
axis_title, download_format, sort_value, colorizeByScale, sd_type):
df = pd.read_json(data, orient='split', dtype='int16')
SUSData = SUSDataset(Helper.parseDataFrameToSUSDataset(df))
SUSData.sortBy(sort_value)

filteredSUSData = Helper.filterSUSStuds(SUSData, systemsToPlot)
mainplot_table = ChartLayouts.createMainplotTable(filteredSUSData, scaleValue)
mainplot_table = ChartLayouts.createMainplotTable(filteredSUSData, scaleValue,
sd_type == 'population')
fig = Charts.CreateMainplot(filteredSUSData, datapointsValues, scaleValue, orientationValue, plotStyle,
mean_sdValue, axis_title, colorizeByScale)
if plotStyle == 'per-question-chart':
Expand All @@ -329,7 +344,6 @@ def update_Mainplot(systemsToPlot, data, datapointsValues, scaleValue, orientati
Output('per-question-chart', 'figure'),
Output('orientation-label', 'style'),
Output('systems-label', 'style'),
Output('sort-by-label', 'style'),
Output('per-question-context', 'style'),
Output('systems-label-radio', 'style'),
Output('per-item-table-div', 'children'),
Expand All @@ -340,20 +354,16 @@ def update_Mainplot(systemsToPlot, data, datapointsValues, scaleValue, orientati
Input('orientation-per-question-chart', 'value'),
Input('plotstyle-per-question-chart', 'value'),
Input('download-type-perquestion', 'value'),
Input('sort-by-perquestion', 'value'),
Input('systems-per-question-chart-radio', 'value'),
)
def update_PerQuestionChart(systemsToPlot, questionsTicked, data, orientationValue, plotStyle, download_format,
sort_value, systemToPlotRadio):
systemToPlotRadio):
df = pd.read_json(data, orient='split', dtype='int16')
SUSData = SUSDataset(Helper.parseDataFrameToSUSDataset(df))
SUSData.sortBy(sort_value)
# SUSData.sortBy(sort_value)
SUSData = Helper.filterSUSStuds(SUSData, systemsToPlot)

colorizeByMeaningLabelStyle = {'display': 'none'}
orientationLabelStyle = {'display': 'none'}
systemsLabelStyle = {'display': 'none'}
sortByLabelStyle = {'display': 'none'}
perQuestionContextStyle = {'float': 'left'}
systemsLabelRadioStyle = {'display': 'none'}

Expand All @@ -367,9 +377,6 @@ def update_PerQuestionChart(systemsToPlot, questionsTicked, data, orientationVal
systemsLabelStyle = {'display': 'block',
'font-weight': 'bold',
'padding': '10px 10px 10px 10px'}
sortByLabelStyle = {'display': 'block',
'font-weight': 'bold',
'padding': '10px 10px 10px 10px'}
elif plotStyle == 'boxplot':
fig = Charts.CreatePerQuestionBoxPlot(SUSData, questionsTicked, systemsToPlot, orientationValue)
orientationLabelStyle = {'display': 'block',
Expand All @@ -378,26 +385,17 @@ def update_PerQuestionChart(systemsToPlot, questionsTicked, data, orientationVal
systemsLabelStyle = {'display': 'block',
'font-weight': 'bold',
'padding': '10px 10px 10px 10px'}
sortByLabelStyle = {'display': 'block',
'font-weight': 'bold',
'padding': '10px 10px 10px 10px'}
elif plotStyle == 'radar':
fig = Charts.CreateRadarChart(SUSData, questionsTicked, systemsToPlot)
systemsLabelStyle = {'display': 'block',
'font-weight': 'bold',
'padding': '10px 10px 10px 10px'}
sortByLabelStyle = {'display': 'block',
'font-weight': 'bold',
'padding': '10px 10px 10px 10px'}
elif plotStyle == 'likert':
systemsLabelRadioStyle = {'display': 'block',
'font-weight': 'bold',
'padding': '10px 10px 10px 10px',
}
perQuestionContextStyle = {'display': 'none'}
colorizeByMeaningLabelStyle = {'display': 'block',
'font-weight': 'bold',
'padding': '10px 10px 10px 10px'}
fig = Charts.CreateLikertChart(SUSData.getIndividualStudyData(systemToPlotRadio), questionsTicked)

if download_format == 'customSize':
Expand All @@ -406,7 +404,7 @@ def update_PerQuestionChart(systemsToPlot, questionsTicked, data, orientationVal
'padding': '10px 10px 10px 10px'}
else:
custom_image_label_style = {'display': 'none'}
return fig, orientationLabelStyle, systemsLabelStyle, sortByLabelStyle, perQuestionContextStyle, systemsLabelRadioStyle, perItemTable, custom_image_label_style
return fig, orientationLabelStyle, systemsLabelStyle, perQuestionContextStyle, systemsLabelRadioStyle, perItemTable, custom_image_label_style


@app.callback(
Expand Down Expand Up @@ -478,10 +476,11 @@ def update_mainplot_table(scaleValue):
State('percentilePlot', 'figure'),
State('conclusivenessPlot', 'figure'),
State('sessionPlotData-multi', 'data'),
State('questions-per-question-chart', 'value'),
prevent_initial_call=True
)
def download_all_charts(n_clicks, n_clicks_2, n_clicks_3, n_clicks_4, mainplot, per_question, percentile,
conclusiveness, data):
conclusiveness, data, questions_ticked):
# This is needed because prevent_initial_call=True doesnt't work, if the input component is generated by another callback
if n_clicks is None and n_clicks_2 is None and n_clicks_3 is None and n_clicks_4 is None:
return dash.no_update
Expand All @@ -495,7 +494,7 @@ def download_all_charts(n_clicks, n_clicks_2, n_clicks_3, n_clicks_4, mainplot,
df_mainplot = ChartLayouts.createMainplotDataframe(SUSData)

# Per Question Dataframe
df_per_question = ChartLayouts.createPerItemDataFrame(SUSData)
df_per_question = ChartLayouts.createPerItemDataFrame(SUSData, questions_ticked)

# Percentile Dataframe
df_percentile = ChartLayouts.createPercentilePlotDataFrame(SUSData)
Expand Down Expand Up @@ -624,12 +623,13 @@ def download_csv_mainplot(n_clicks, data):
Output('download-csv-per-question', 'data'),
Input('csv-per-question-button', 'n_clicks'),
State('sessionPlotData-multi', 'data'),
State('questions-per-question-chart', 'value'),
prevent_initial_call=True
)
def download_csv_per_question(n_clicks, data):
def download_csv_per_question(n_clicks, data, questions_ticked):
df = pd.read_json(data, orient='split')
SUSData = SUSDataset(Helper.parseDataFrameToSUSDataset(df))
df = ChartLayouts.createPerItemDataFrame(SUSData)
df = ChartLayouts.createPerItemDataFrame(SUSData, questions_ticked)
return dcc.send_data_frame(df.to_csv, "per_question.csv", index=False)


Expand Down Expand Up @@ -695,6 +695,6 @@ def download_csv_data_single(nclicks, data, table_columns):

if __name__ == '__main__':
if debugMode:
app.run_server(host='0.0.0.0', debug=True)
app.run(host='0.0.0.0', debug=True)
else:
app.run_server(port=80, host='0.0.0.0')
app.run(port=80, host='0.0.0.0')
4 changes: 3 additions & 1 deletion docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,7 @@ services:
build:
context: ./
dockerfile: Dockerfile
image: result/latest
ports:
- "8050:8050"
image: sus-test

6 changes: 2 additions & 4 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
plotly==5.3.1
dash==2.5.1
numpy==1.19.5
pandas==1.3.1
dash==2.15.0
kaleido==0.2.1
pandas==2.2.2
beautifulsoup4~=4.11.1

0 comments on commit 2e3ee18

Please sign in to comment.