Commit e4aaee56 authored by Odair M.'s avatar Odair M.

Merge branch '114-integrar-analises-relacionada-ao-curso-com-o-sistema-web' into 'development'

Resolve "integrar analises relacionada ao curso com o sistema web"

See merge request adega/adega!43
parents d2a9892f e362ce07
// This module simplify the use of Plotly library on this project
class AdegaChart{ class AdegaChart{
constructor(config){ constructor(config){
...@@ -9,6 +11,8 @@ class AdegaChart{ ...@@ -9,6 +11,8 @@ class AdegaChart{
this.legend = config.legend || null; this.legend = config.legend || null;
this.barmode = config.barmode || "stack";
if(config.data == null){ if(config.data == null){
this.data_x = config.data_x; this.data_x = config.data_x;
...@@ -18,8 +22,8 @@ class AdegaChart{ ...@@ -18,8 +22,8 @@ class AdegaChart{
else{ else{
this.data_x = []; this.data_x = [];
this.data_y = []; this.data_y = [];
var first_element; var first_element = Object.keys(this.data)[0];
for (first_element in this.data) break;
first_element = this.data[first_element]; first_element = this.data[first_element];
var multiplePlots = Array.isArray(first_element); var multiplePlots = Array.isArray(first_element);
...@@ -53,7 +57,7 @@ class AdegaChart{ ...@@ -53,7 +57,7 @@ class AdegaChart{
this.type = config.type || "scatter"; this.type = config.type || "scatter";
this.title = config.title || ""; this.title = config.title || "";
if(typeof(this.data_y[0]) == "number"){ if(typeof(this.data_y[0]) == "number"){
this.data_y = [this.data_y]; this.data_y = [this.data_y];
this.type = [this.type]; this.type = [this.type];
...@@ -63,6 +67,9 @@ class AdegaChart{ ...@@ -63,6 +67,9 @@ class AdegaChart{
this.error_y = [this.error_y]; this.error_y = [this.error_y];
} }
this.data_axis_y = config.data_axis_y || this.data_y.map(function(x){return "y1";});
this.reloadGraph(); this.reloadGraph();
} }
...@@ -88,10 +95,11 @@ class AdegaChart{ ...@@ -88,10 +95,11 @@ class AdegaChart{
continue; continue;
data.push( data.push(
{ {
x: this.data_x, x: this.data_x,
y: this.data_y[i], y: this.data_y[i],
type: this.type[i], type: this.type[i],
fill: this.fill fill: this.fill,
yaxis: this.data_axis_y[i]
} }
); );
...@@ -110,9 +118,34 @@ class AdegaChart{ ...@@ -110,9 +118,34 @@ class AdegaChart{
var layout = { var layout = {
title: this.title, title: this.title,
showlegend: true showlegend: true,
yaxis: {
// title: 'yaxis title',
rangemode: 'tozero'
// overlaying: 'y'
},
yaxis2: {
// title: 'yaxis2 title',
// titlefont: {color: 'rgb(148, 103, 189)'},
// tickfont: {color: 'rgb(148, 103, 189)'},
overlaying: 'y1',
side: 'right',
rangemode: 'tozero'
},
barmode: this.barmode
}; };
Plotly.newPlot(this.div_target, data, layout); Plotly.newPlot(this.div_target, data, layout);
} }
}
AdegaChart.sort_object_by_key = function(obj){
keys = Object.keys(obj);
keys.sort();
values = keys.map(function(x){
return obj[x];
});
return [keys,values];
} }
\ No newline at end of file
<div class="sidebar left hidden-sm hidden-xs"> <div class="sidebar left hidden-sm hidden-xs">
<ul class="list-sidebar"> <ul class="list-sidebar">
<li><a href="{% url 'student:index' degree_id=degree.code%}">Alunos</a></li> <li><a class="btn btn-primary text-left" href="{% url 'student:index' degree_id=degree.code%}">Alunos</a></li>
<li style="display: block;"> <li style="display: block;">
<div> <div>
<a href="{% url 'course:index' degree_id=degree.code%}">Disciplinas</a> <a class="btn btn-primary text-left" href="{% url 'course:index' degree_id=degree.code%}">Disciplinas</a>
<a href="course" class="drop" data-toggle="collapse" data-target="#side-disciplinas"> <a class="btn btn-primary text-left" href="course" class="drop" data-toggle="collapse" data-target="#side-disciplinas">
<span class="rotate"><i class="fa fa-angle-left"></i></span> <span class="rotate"><i class="fa fa-angle-left"></i></span>
</a> </a>
</div> </div>
<ul class="sub-menu collapse" id="side-disciplinas"> <ul class="sub-menu collapse" id="side-disciplinas">
<li><a href="#">Comparar</a></li> <li><a class="btn btn-primary text-left disabled" href="compare">Comparar</a></li>
</ul> </ul>
</li> </li>
<li class="disabled"><a href="#">Professores</a></li> <li><a class="btn btn-primary disabled text-left" href="#">Professores</a></li>
<li class="disabled"><a href="#">Turmas</a></li> <li><a class="btn btn-primary disabled text-left" href="#">Turmas</a></li>
<li><a href="{% url 'admission:index' degree_id=degree.code%}">Turmas de Ingresso</a></li> <li><a class="btn btn-primary text-left" href="{% url 'admission:index' degree_id=degree.code%}">Turmas de Ingresso</a></li>
<li style="display: block;" > <li style="display: block;" >
<a href="#" data-toggle="collapse" data-target="#side-outros" style="display:flex" class="drop"> <a href="#" data-toggle="collapse" data-target="#side-outros" style="display:flex" class="drop">
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
<span style="padding-top:3px" class="rotate"><i class="fa fa-angle-left"></i></span> <span style="padding-top:3px" class="rotate"><i class="fa fa-angle-left"></i></span>
</a> </a>
<ul class="sub-menu collapse" id="side-outros"> <ul class="sub-menu collapse" id="side-outros">
<li><a href="#">Cepe 96/15</a></li> <li><a class="btn btn-primary disabled text-left" href="#">Cepe 96/15</a></li>
</ul> </ul>
</li> </li>
</ul> </ul>
......
...@@ -30,7 +30,9 @@ ...@@ -30,7 +30,9 @@
<section id="wrap-page" class="container-fluid"> <section id="wrap-page" class="container-fluid">
<div class="row" style="min-height:100%"> <div class="row" style="min-height:100%">
<aside class="col-md-2 sidebar"> <aside class="col-md-2 sidebar">
{% include 'adega/sidebar.html' %} {% if not hide_navbar %}
{% include 'adega/sidebar.html' %}
{% endif %}
</aside> </aside>
<section class="col-md-10"> <section class="col-md-10">
{% if messages %} {% if messages %}
......
...@@ -10,7 +10,7 @@ from django.contrib.auth import logout as process_logout ...@@ -10,7 +10,7 @@ from django.contrib.auth import logout as process_logout
def dashboard(request): def dashboard(request):
degree = request.user.educator.degree.all() degree = request.user.educator.degree.all()
return render(request, 'adega/dashboard.html', {'title': 'Dashboard', return render(request, 'adega/dashboard.html', {'title': 'Dashboard',
"degrees":degree "degrees":degree, "hide_navbar": True
}) })
......
...@@ -78,53 +78,21 @@ ...@@ -78,53 +78,21 @@
</div> </div>
{% endcomment %} {% endcomment %}
{% comment %}
<div id="graficos"> <div id="graficos">
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-md-12">
<h3>Quantidade alunos/IRA</h3> <h3>IRA/Semestre</h3>
<canvas id="ira_semestral" data-data='{{ degree_data.ira_medio_grafico|safe }}'></canvas> <div id="ira_semestral"></div>
</div> </div>
<div class="col-md-6"> <div class="col-md-12">
<h3>Quantidade evasão/período</h3> <h3>Quantidade de alunos/Semestre</h3>
<canvas id="evasao_semestre" data-data='{{ degree_data.evasao_grafico|safe }}'></canvas> <div id="students_per_semester"></div>
</div>
<!--
<div class="col-md-6">
<h3>Nota Média/Periodo</h3>
<canvas id="nota_media_semestre"
data-data='{{ degree_data.media_disc|safe }}'></canvas>
</div> essa analise foi feita de uma maneira ruim no adega
antigo -->
<!-- analises sa02 -->
<div class="col-md-6">
<h3>Alunos/Periodo</h3>
<canvas id="aluno_periodo"
data-data='{{ degree_data.aluno_periodo|safe }}'></canvas>
</div>
<div class="col-md-6">
<h3>Nota Média/Periodo</h3>
<canvas id="nota_media_periodo"
data-data='{{ degree_data.nota_media_periodo|safe }}'></canvas>
</div>
<div class="col-md-6">
<h3>Taxa Aprovação/Periodo</h3>
<canvas id="taxa_aprovacao_periodo"
data-data='{{ degree_data.taxa_aprovacao_periodo|safe }}'></canvas>
</div>
<!-- fim analise sa02 -->
</div> </div>
</div>
</div> </div>
{% endcomment %} </div>
</div>
</div>
<div id="myChart"></div>
<div id="myChart2"></div> <div id="myChart2"></div>
{% endblock content %} {% endblock content %}
...@@ -133,23 +101,45 @@ ...@@ -133,23 +101,45 @@
{% block js-foot %} {% block js-foot %}
<script> <script>
var admission_info = {{admission_info|safe}};
// ira_per_semester contains an object with year/semester
// as keys, and an tuple (mean,std) as values
// So, we need to transform this data before use on AdegaChart
var sorted = AdegaChart.sort_object_by_key(admission_info.ira_per_semester);
ira_per_semester_x = sorted[0];
ira_per_semester_y = sorted[1];
ira_per_semester_error = [];
ira_per_semester_y = ira_per_semester_y.map(function(x){
ira_per_semester_error.push(x[1]);
return x[0];
});
var chart1 = new AdegaChart({ var chart1 = new AdegaChart({
data_x: [0,1,2], data_x: ira_per_semester_x,
data_y: [6,10,2], data_y: ira_per_semester_y,
div_target: "myChart", error_y: ira_per_semester_error,
error_y: [1,2,3], div_target: "ira_semestral",
//type: "bar", type: "scatter",
title: "Exemplo 1" legend: "IRA",
title: "IRA/Semestre"
}); });
var chart1 = new AdegaChart({ var sorted = AdegaChart.sort_object_by_key(admission_info.students_per_semester);
data_x: [0,1,2], students_per_semester_x = sorted[0];
data_y: [[6,10,2], [7,9,2.5]], students_per_semester_y = sorted[1];
div_target: "myChart2",
error_y: [[1,2,3], [1.5,0.1,0.5]], var chart2 = new AdegaChart({
type:["bar", "scatter"], data_x: students_per_semester_x,
title: "Exemplo 2", data_y: students_per_semester_y,
legend: ["linha 1", "linha 2"] div_target: "students_per_semester",
type:["scatter"],
title: "Quantidade de alunos/Semestre",
legend: "Quantidade de alunos"
}); });
</script> </script>
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
{{ ti.ano }}/{{ ti.semestre }} {{ ti.ano }}/{{ ti.semestre }}
</a> </a>
</td> </td>
<td>{{ti.ira|floatformat:2}} &plusmn {{ti.desvio_padrao|floatformat:2}}</td> <td>{{ti.ira|floatformat:2}} &plusmn {{ti.std|floatformat:2}}</td>
<td> NO </td> <td> NO </td>
<td> NO </td> <td> NO </td>
<td> NO </td> <td> NO </td>
......
...@@ -13,8 +13,15 @@ def detail(request, degree_id, ano, semestre): ...@@ -13,8 +13,15 @@ def detail(request, degree_id, ano, semestre):
if not (degree in request.user.educator.degree.all()): if not (degree in request.user.educator.degree.all()):
return redirect("adega:dashboard") return redirect("adega:dashboard")
for admission in get_list_admission(request.session, degree):
if(admission["ano"] == ano and admission["semestre"] == semestre):
admission_info = admission
break
return render(request, 'admission/detail.html',{ return render(request, 'admission/detail.html',{
"degree": degree "degree": degree,
"admission_info": admission_info
}) })
......
...@@ -116,34 +116,50 @@ ...@@ -116,34 +116,50 @@
{% endif %}</td> {% endif %}</td>
</td> </td>
</table> </table>
<div id="graficos">
<div class="row">
<div class="col-md-12">
<h3>Indice de aprovação/Semestre</h3>
<div id="aprovacao_semestre"></div>
</div>
<div class="col-md-12">
<h3>Quantidade de Alunos/Vezes Cursadas</h3>
<div id="qtd_cursada_aprov"></div>
</div>
</div>
</div>
</div>
<div id="aprovacao_semestre"></div>
<div id="myChart2"></div>
{% endblock content %} {% endblock content %}
{% block js-foot %} {% block js-foot %}
<script> <script>
var grafico_qtd_cursada_aprov = AdegaChart.sort_object_by_key(
{{analysis_result.grafico_qtd_cursada_aprov|safe}}
);
var grafico_qtd_cursada_aprov_x = grafico_qtd_cursada_aprov[0];
var grafico_qtd_cursada_aprov_y = grafico_qtd_cursada_aprov[1];
var chart1 = new AdegaChart({ var chart1 = new AdegaChart({
data: {{analysis_result.aprovacao_semestral|safe}}, data: {{analysis_result.aprovacao_semestral|safe}},
div_target: "aprovacao_semestre", div_target: "aprovacao_semestre",
//type: "bar", title: "Indice de aprovação/Semestre",
title: "Índice de aprovação/Semestre",
fill: "none", fill: "none",
legend: ["Aprovação %","Quantidade de alunos"] legend: ["Taxa de aprovação","Quantidade de alunos"],
type:["scatter", "bar"],
data_axis_y: ["y2", "y"]
}); });
var chart1 = new AdegaChart({ var chart1 = new AdegaChart({
data_x: [0,1,2], data_x: grafico_qtd_cursada_aprov_x,
data_y: [[6,10,2], [7,9,2.5]], data_y: grafico_qtd_cursada_aprov_y,
div_target: "myChart2", div_target: "qtd_cursada_aprov",
error_y: [[1,2,3], [1.5,0.1,0.5]], type:["scatter"],
type:["bar", "scatter"], title: "Quantidade de Alunos/Vezes Cursadas",
title: "Exemplo 2", legend: "Quantidade de alunos"
legend: ["linha 1", "linha 2"]
}); });
</script> </script>
......
...@@ -30,7 +30,10 @@ def index(request, degree_id): ...@@ -30,7 +30,10 @@ def index(request, degree_id):
analysis_result = get_list_courses(request.session, degree) analysis_result = get_list_courses(request.session, degree)
courses_list = analysis_result["cache"] courses_list = analysis_result["cache"]
code_to_name = analysis_result["disciplinas"]
for code in courses_list:
courses_list[code]["name"] = code_to_name[code]
return render(request, 'course/index.html', { return render(request, 'course/index.html', {
"courses": courses_list, "courses": courses_list,
"degree": degree "degree": degree
......
...@@ -60,6 +60,7 @@ ...@@ -60,6 +60,7 @@
<span class="data">{{ degree_data.taxa_reprovacao.0|floatformat:2 }}% &#177; {{degree_data.taxa_reprovacao.1|floatformat:2 }}%</span> <span class="data">{{ degree_data.taxa_reprovacao.0|floatformat:2 }}% &#177; {{degree_data.taxa_reprovacao.1|floatformat:2 }}%</span>
</div> </div>
</div> </div>
<br>
<div class="panel-container"> <div class="panel-container">
<div class="data-panel"> <div class="data-panel">
<h3>Aprovação Aproveitamento de Conhecimento</h3> <h3>Aprovação Aproveitamento de Conhecimento</h3>
...@@ -74,11 +75,14 @@ ...@@ -74,11 +75,14 @@
{% endcomment %} {% endcomment %}
<div id="graficos"> <div id="graficos">
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-md-12">
<!-- <h3>Quantidade alunos/IRA</h3> --> <!-- <h3>Quantidade alunos/IRA</h3> -->
<div id="ira_semestral"></div> <div id="ira_semestral"></div>
</div> </div>
<div class="col-md-6"> </div>
</div class="row">
<div class="col-md-12">
<!-- <h3>Quantidade evasão/período</h3> --> <!-- <h3>Quantidade evasão/período</h3> -->
<div id="evasao_semestre"></div> <div id="evasao_semestre"></div>
</div> </div>
...@@ -96,14 +100,13 @@ ...@@ -96,14 +100,13 @@
<canvas id="aluno_periodo" <canvas id="aluno_periodo"
data-data='{{ degree_data.aluno_periodo|safe }}'></canvas> data-data='{{ degree_data.aluno_periodo|safe }}'></canvas>
</div> </div>
<br>
<div class="col-md-6"> <div class="col-md-6">
<h3>Nota Média/Periodo</h3> <h3>Nota Média/Periodo</h3>
<canvas id="nota_media_periodo" <canvas id="nota_media_periodo"
data-data='{{ degree_data.nota_media_periodo|safe }}'></canvas> data-data='{{ degree_data.nota_media_periodo|safe }}'></canvas>
</div> </div>
<br>
<div class="col-md-6"> <div class="col-md-6">
<h3>Taxa Aprovação/Periodo</h3> <h3>Taxa Aprovação/Periodo</h3>
<canvas id="taxa_aprovacao_periodo" <canvas id="taxa_aprovacao_periodo"
...@@ -158,14 +161,20 @@ ...@@ -158,14 +161,20 @@
div_target: "ira_semestral", div_target: "ira_semestral",
title: "Quantidade alunos/IRA", title: "Quantidade alunos/IRA",
fill: "none", fill: "none",
legend: ["Ira médio", "Alunos sem evasão", "Formados"] legend: [
"Quantidade total de alunos",
"Quantidade total de alunos sem evasão",
"Quantidade total de alunos formados"
],
}); });
var chart2 = new AdegaChart({ var chart2 = new AdegaChart({
data: evasao_semestre_data, data: evasao_semestre_data,
div_target: "evasao_semestre", div_target: "evasao_semestre",
title: "Quantidade evasão/período", title: "Quantidade evasão/período",
fill: "none", fill: "none",
legend: ["Taxa", "Quantidade"] type: ["scatter","bar"],
legend: ["Taxa", "Quantidade"],
data_axis_y: ["y2","y1"]
}); });
......
...@@ -51,14 +51,25 @@ def admission_class_ira_per_semester(df): ...@@ -51,14 +51,25 @@ def admission_class_ira_per_semester(df):
for semester in semester_grouped: for semester in semester_grouped:
student_grouped = semester[1].groupby('ID_ALUNO') student_grouped = semester[1].groupby('ID_ALUNO')
ira_class = 0 ira_class = []
# Compute all individual IRA from an class
for student in student_grouped: for student in student_grouped:
#TODO: Verify if this can be calculated without groupby #TODO: Verify if this can be calculated without groupby
ira_individual =( (student[1].MEDIA_FINAL*student[1].TOTAL_CARGA_HORARIA).sum() )/(100*student[1].TOTAL_CARGA_HORARIA.sum()) ira_individual =(
ira_class += ira_individual (student[1].MEDIA_FINAL*student[1].TOTAL_CARGA_HORARIA).sum() )/(100*student[1].TOTAL_CARGA_HORARIA.sum()
ira_class = ira_class / len(student_grouped) )
dict_ira_semester.update({semester[0]:ira_class}) ira_class.append(ira_individual)
# Compute the mean and standard variation from an class
# semester[0] represents a semester/year key
dict_ira_semester.update({
semester[0]: [
np.mean(ira_class),
np.std(ira_class)
]
})
dict_admission.update({admission[0]:dict_ira_semester}) dict_admission.update({admission[0]:dict_ira_semester})
return dict_admission return dict_admission
......
...@@ -145,20 +145,50 @@ def period_evasion_graph(df): ...@@ -145,20 +145,50 @@ def period_evasion_graph(df):
di_qtd = {} di_qtd = {}
dic = {} dic = {}
evasions_total = 0 evasions_total = 0
# Discover the minimum and maximum values for year
year_start = int(df['ANO'].min()) year_start = int(df['ANO'].min())
year_end = int(df['ANO'].max()) + 1 year_end = int(df['ANO'].max()) + 1
students = df.drop_duplicates() students = df.drop_duplicates()
# Iterate between all semester/year possible
for year in range(year_start, year_end): for year in range(year_start, year_end):
for semester in range(1, 3): for semester in range(1, 3):
evasions = students.loc[(df['ANO_EVASAO'] == str(year)) & (df['SEMESTRE_EVASAO'] == str(semester))].shape[0]
# Filter the rows and mantain only the registers
# that match with year and semester of this iteration
evasions = students.loc[
(df['ANO_EVASAO'] == str(year)) &
(df['SEMESTRE_EVASAO'] == str(semester))
]
# Count only one row per student by removing
# all duplicate rows with same MATR_ALUNO
# and keeping the first row founded
# Than, get the number of rows computed
evasions = evasions.drop_duplicates(
subset="MATR_ALUNO",
keep='first'
).shape[0]
# Name of string on dictionary generated
date = str(year) + ' {}º Período'.format(semester) date = str(year) + ' {}º Período'.format(semester)
di_qtd[date] = evasions di_qtd[date] = evasions
# Count the total of evasions identified, that will be
# used to compute the rate
evasions_total += evasions evasions_total += evasions
# If at least one evasion was computed
if evasions_total: if evasions_total:
# Compute the ratio of evasion per
# semester and name the attributes
for di in di_qtd: for di in di_qtd:
qtd = di_qtd[di] qtd = di_qtd[di]
dic[di] = {'qtd': qtd, 'taxa': (qtd/evasions_total)*100} dic[di] = {'qtd': qtd, 'taxa': (float(qtd)/evasions_total)*100}
return dic return dic
def build_dict_ira_medio(alunos): def build_dict_ira_medio(alunos):
...@@ -182,14 +212,26 @@ def build_dict_ira_medio(alunos): ...@@ -182,14 +212,26 @@ def build_dict_ira_medio(alunos):
return dic return dic
def build_degree_json(path,df): def build_degree_json(path,df):
def merge_dicts(dict1, dict2, dict3): def merge_dicts(dict1, dict2, dict3):
dict_out = {} dict_out = {}
for key, value in dict1.items(): for key, value in dict1.items():
v2 = dict2[key] if key in dict2 else None v2 = dict2[key] if key in dict2 else None
v3 = dict3[key] if key in dict3 else None v3 = dict3[key] if key in dict3 else None
dict_out[key] = {'ira_medio': value, 'sem_evasao': v2, 'formatura': v3} dict_out[key] = {
'ira_medio': value,
'sem_evasao': v2,
'formatura': v3
}
return dict_out return dict_out
dic = merge_dicts(average_ira_graph(df),current_students_average_ira_graph(df),graduates_average_ira_graph(df))
dic = merge_dicts(
average_ira_graph(df),
current_students_average_ira_graph(df),
graduates_average_ira_graph(df)
)
degree_json = { degree_json = {
"ira_medio_grafico": json.dumps(sorted(dic.items())), "ira_medio_grafico": json.dumps(sorted(dic.items())),
"evasao_grafico": json.dumps(sorted(period_evasion_graph(df).items())), "evasao_grafico": json.dumps(sorted(period_evasion_graph(df).items())),
......
...@@ -115,24 +115,48 @@ class StudentAnalysis: ...@@ -115,24 +115,48 @@ class StudentAnalysis:
return aprovacoes_semestres