Commit 63b8dd70 authored by bhmeyer's avatar bhmeyer Committed by msrr18
Browse files

Resolve "Criar visualizator"

parent bb0da3cf
......@@ -3,6 +3,14 @@ SITE-OWNER-GROUP = www-data
all:
# The follows commands permit to use manage.py and
# docker-compose up with make. Examples:
# make docker-manage migrate
# make docker-manage makemigrations uploads
# make docker-up --build
%:
@:
args = `arg="$(filter-out $@,$(MAKECMDGOALS))" && echo $${arg:-${1}}`
clean:
@rm -rf *~ *.pyc *.backup
......@@ -47,7 +55,7 @@ docker-production:
docker-compose --project-directory . -f docker_scripts/docker-production.yml -p adega up
docker-remove-all:
docker rm adega_web adega_db_1
docker rm adega_web adega_db
docker rmi adega_web
......@@ -57,15 +65,6 @@ docker-install:
apt-get install docker-compose
# The follows commands permit to use manage.py with make. Examples:
# make docker-manage migrate
# make docker-manage makemigrations uploads
%:
@:
args = `arg="$(filter-out $@,$(MAKECMDGOALS))" && echo $${arg:-${1}}`
docker-manage:
@echo $(call args,"")
docker exec -it adega_web bash -c "cd src; python3 manage.py $(call args,'')"
......
......@@ -92,9 +92,12 @@ footer h3 {
background-color: #132940;
}
.sidebar > li > .dropdown-menu { background-color:#1a2c3f; }
.sidebar > li > a { background-color:#1a2c3f; }
.sidebar > li > button { background-color:#1a2c3f; }
.sidebar > li > .dropdown-menu { background-color:#1a2c3f;
}
.sidebar > li > a { background-color:#1a2c3f;
}
.sidebar > li > button { background-color:#1a2c3f;
}
.sidebar ul {
list-style:none;
......@@ -181,4 +184,171 @@ footer h3 {
margin-left:10px;
margin-right:10px;
cursor: pointer;
}
\ No newline at end of file
}
/* =========================== PAINEIS ============= */
/* =============================================== PANEL */
.panel-container {
display: -webkit-flex;
display: flex;
justify-content: space-between;
}
.data-panel {
padding: 10px 10px 20px;
margin: 10px;
border-bottom: 2px solid #3c3c3c;
font-size: 1.3em;
flex: 1;
box-shadow: 0 0 1px #DDD;
}
span.data {
margin: 0 1.5em;
}
.panel-line {
display: flex;
}
.data-panel .data-panel {
margin: 2px;
font-size: 1em;
border-bottom: 1px solid #3c3c3c;
box-shadow: none;
}
/* =================================================== GRADE */
/* ============================================== GRADE */
.grade {
/* width: 100%; */
display: flex;
overflow-x: auto;
overflow-y: hidden;
}
.grade-head {
padding: 5px;
text-align: center;
font-weight: bold; }
.grade .code,
.grade .name {
display: block; }
/* ============================================== MATERIA */
.materia {
background-color: #FFF;
padding: 6px 6px 0px;
margin: 1px 1px 2px;
font-size: small;
border-bottom: 4px solid white; }
.materia.approved {
border-color: #6B8E23;
}
.materia.equivalence {
border-color: rgb(138, 64, 207);
}
.materia.failed {
border-color: #B22222;
}
.materia.cancelled {
border-color: #FFD700;
}
.materia.registered {
border-color: #ADD8E6;
}
.materia .info {
margin: 2px;
text-align: center;
}
.materia .details {
margin: 2px;
text-align: center;
}
.materia .code {
display: none; }
.materia .cursadas {
display: none; }
.materia .detail-name {
font-variant: small-caps; }
.materia .details {
border-top: 1px solid #F4F4F4;
padding-top: 4px;
margin-top: 3px;
display: flex;
height: 4em;
}
.materia .code {
color: #444; }
.materia .detail-name {
font-size: x-small; }
.materia .detail {
padding: 0 3px; }
.materia .detail span {
display: block;
width: 100%;
text-align: center; }
#materias-atuais {
display: flex;
background-color: #EEE; }
#materias-atuais .materia {
min-width: 170px; }
/* ============================================== SEMESTRE */
.semestre {
min-width: 100px;
/* max-width: 250px; */
margin: 1px;
background-color: #EEE;
display: flex;
flex-direction: column;
align-content: flex-start;
align-items: stretch; }
/* ============================================== HISTORICO */
#desenvolvimento {
overflow-x: auto;
overflow-y: hidden;
display: flex; }
#desenvolvimento .desc {
padding: 6px 8px; }
#desenvolvimento .res {
padding: 6px 8px;
display: absolute;
bottom: 0; }
.desc .periodo {
display: block;
text-align: center;
font-weight: bold;
font-size: 1.2em;
margin: 10px; }
......@@ -4,4 +4,12 @@ register = template.Library()
@register.filter
def to_percent(value):
return "{:.2f}".format(float(value)*100) + "%"
\ No newline at end of file
return "{:.2f}".format(float(value)*100) + "%"
@register.filter
def fix_2digit(value):
return "{:.2f}".format(float(value))
@register.filter
def remove_spaces(value):
return value.replace(' ', '')
\ No newline at end of file
......@@ -39,24 +39,24 @@
{% endblock content %}
</section>
<footer>
<div class="container">
<div class="row">
<div class="col-md-4">
<h3>Links</h3>
<ul>
<li><a href="http://pet.inf.ufpr.br/projetos/adega.html">Página oficial do projeto</a></li>
<li><a href="http://gitlab.c3sl.ufpr.br/pet/adega">Código fonte</a></li>
<li><a href="#">Desenvolvedores</a></li>
</ul>
</div>
<div class="col-md-4 offset-md-4">
<h3>Mantido por</h3>
<a href="http://pet.inf.ufpr.br">
<img src="/static/pet/logo_preto.png" width="75%">
</a>
<div class="container container-fluid">
<div class="row">
<div class="col-md-4">
<h3>Links</h3>
<ul>
<li><a href="http://pet.inf.ufpr.br/doku.php?id=adega">Página oficial do projeto</a></li>
<li><a href="https://gitlab.c3sl.ufpr.br/adega/adega">Código fonte</a></li>
<!-- <li><a href="#">Desenvolvedores</a></li> -->
</ul>
</div>
<div class="col-md-4 offset-md-4">
<h3>Mantido por</h3>
<a href="http://pet.inf.ufpr.br">
<img src="{% static 'pet/logo_pet_h_branco.png' %}" width="50%">
</a>
</div>
</div>
</div>
</div>
</footer>
</footer>
</body>
</html>
\ No newline at end of file
from submission.analysis.utils.situations import Situation
import numpy as np
class CourseGrid:
def __init__(self, obj):
self.situation = obj["situacao"]
self.code = obj["codigo"]
self.name = obj["nome"]
self.year = obj["ano"]
self.semester = obj["semestre"]
self.grade = obj["nota"]
def is_approved(self):
sit = Situation.str_to_code(self.situation)
return sit in Situation.SITUATION_PASS
def is_failed(self):
sit = Situation.str_to_code(self.situation)
return sit in Situation.SITUATION_FAIL
def is_registered(self):
sit = Situation.str_to_code(self.situation)
return sit == Situation.SIT_MATRICULA
def is_cancelled(self):
sit = Situation.str_to_code(self.situation)
return sit in Situation.SITUATION_CANCELLED
def is_equivalence(self):
sit = Situation.str_to_code(self.situation)
return sit == Situation.SIT_EQUIVALENCIA
# This is different of Situation.COURSED
# Check situations.py to confer the difference
def is_coursed(self):
return self.is_approved() or self.is_failed()
class CourseGridCollection:
def __init__(self, code, grid):
self.grid = grid
self.code = code
self.name = grid.code_to_name[code]
self.historic = []
self.is_real_code = grid.is_real_code(code)
self.is_repeated_code = grid.is_repeated_code(code)
def add(self, course_obj):
code = course_obj["codigo"]
# If the course_obj was related to this course or an equivalent
if self.grid.is_equivalence(code, self.code):
cg = CourseGrid(course_obj)
self.historic.append(cg)
def reset(self):
self.historic = []
def get_failed_historic(self):
return [x for x in self.historic if x.is_failed()]
def get_approved_historic(self):
return [x for x in self.historic if x.is_approved()]
def get_registered_historic(self):
return [x for x in self.historic if x.is_registered()]
def get_coursed_historic(self):
return [x for x in self.historic if x.is_coursed()]
def get_cancelled_historic(self):
return [x for x in self.historic if x.is_cancelled()]
def get_equivalence_historic(self):
return [x for x in self.historic if x.is_equivalence()]
def count_approved(self):
hist = self.get_approved_historic()
return len(hist)
def count_failed(self):
hist = self.get_failed_historic()
return len(hist)
def count_registered(self):
hist = self.get_registered_historic()
return len(hist)
def count_equivalence(self):
hist = self.get_equivalence_historic()
return len(hist)
def count_coursed(self):
hist = self.get_coursed_historic()
return len(hist)
def count_cancelled(self):
hist = self.get_cancelled_historic()
return len(hist)
def mean_grade(self):
grades = [x.grade for x in self.get_coursed_historic()]
return np.mean(grades)
def get_prevalent_situation(self):
# If this is an course that repeat on grid, then this doesnt have any
# situation
if(self.is_repeated_code):
return ""
# If there is an approved, registered or equivalence situation,
# then it is the prevalent
if self.count_approved() > 0:
return "approved"
if self.count_equivalence() > 0:
return "equivalence"
if self.count_registered() > 0:
return "registered"
# If there is at least one failure, and there is no
# approve or registered, then the prevalent situation is "failed"
if self.count_failed() > 0:
return "failed"
# Cancelled has an lesser importance
if self.count_cancelled() > 0:
return "cancelled"
return ""
def has_detail(self):
p_sit = self.get_prevalent_situation()
return p_sit == "approved" or p_sit == "failed" or p_sit == "approved"
def get_info(self):
p_sit = self.get_prevalent_situation()
info = {
"name": self.name,
"code": self.code,
"situation": p_sit,
"is_real_code": self.is_real_code
}
if self.has_detail():
info["detail"] = {
"count": self.count_coursed(),
"mean_grade": self.mean_grade(),
}
return info
class DegreeGridDescription:
def __init__(self, obj):
self.year = obj["year"]
self.grid = obj["grid"]
self.code_to_name = obj["code_to_name"]
self.equiv_codes = obj["equiv_codes"]
self.fake_codes = obj["fake_codes"]
# Codes that show more then one time on grid, like OPT
self.repeated_codes = obj["repeated_codes"]
def count_code_on_grid(self, code):
count = 0
for line in self.grid:
for code2 in line:
if(code2 == code):
count+=1
return count
def is_repeated_code(self, code):
return code in self.repeated_codes
def is_real_code(self, code):
return not code in self.fake_codes
def is_equivalence(self, code1, code2):
if(code1 in self.equiv_codes and code2 in self.equiv_codes[code1]):
return True
if(code2 in self.equiv_codes and code1 in self.equiv_codes[code2]):
return True
if(code1 == code2):
return True
return False
class DegreeGrid:
def __init__(self, grid_detail):
self.grid_detail = grid_detail
self.cgc = {}
def compute_cgc(self, hist):
# Create an instance for each cell in grid
cgc = {}
for semester in self.grid_detail.grid:
for code in semester:
cgc[code] = CourseGridCollection(code, self.grid_detail)
for h in hist:
code = h["codigo"]
# For each code and equivalent codes from an course in historic
# and it self
all_codes = [code]
if code in self.grid_detail.equiv_codes:
all_codes += self.grid_detail.equiv_codes[code]
for code in all_codes:
# Count it on each grid course only if it is on grid
# Eletive courses will not be considered
if(code in cgc):
cgc[code].add(h)
return cgc
def get_grid(self, cgc):
new_grid = np.array(self.grid_detail.grid, dtype=np.dtype(object))
for i, line in enumerate(self.grid_detail.grid):
for j, course_code in enumerate(line):
# TODO: Add possibility to insert others grids
new_grid[i, j] = cgc[course_code].get_info()
return new_grid
def get_repeated_course_info(self, cgc):
info = []
for code in self.grid_detail.repeated_codes:
info.append({
"code": cgc[code].code,
"name": cgc[code].name,
"approves": cgc[code].count_approved(),
"registered": cgc[code].count_registered(),
"fails": cgc[code].count_failed(),
"equivalences" : cgc[code].count_equivalence(),
"cancelled" : cgc[code].count_cancelled(),
"necessary": self.grid_detail.count_code_on_grid(code),
"grade": cgc[code].mean_grade(),
})
return info
def get_situation(self, hist):
cgc = self.compute_cgc(hist)
return self.get_grid(cgc), self.get_repeated_course_info(cgc)
bcc_grid_2011 = DegreeGridDescription({
"year": 2011,
"grid": [
["CI068", "CI055", "CM046", "CM045", "CM201", ],
["CI210", "CI056", "CI067", "CM005", "CM202", ],
["CI212", "CI057", "CI064", "CI237", "CI166", ],
["CI215", "CI062", "CE003", "CI058", "CI164", ],
["CI162", "CI065", "CI059", "CI061", "SA214", ],
["CI163", "CI165", "CI209", "CI218", "CI220", ],
["CI221", "CI211", "OPT", "OPT", "TG I", ],
["OPT", "OPT", "OPT", "OPT", "TG II", ],
],
"repeated_codes": ["OPT"],
"fake_codes": ["OPT", "TG I", "TG II"],
"code_to_name": {
"CE003": "Estatística II",
"CI055": "Algoritmos e Estruturas de Dados I",
"CI056": "Algoritmos e Estruturas de Dados II",
"CI057": "Algoritmos e Estruturas de Dados III",
"CI058": "Redes de Computadores I",
"CI059": "Introdução à Teoria da Computação",
"CI061": "Redes de Computadores II",
"CI062": "Técnicas Alternativas de Programação",
"CI064": "Software Básico",
"CI065": "Algoritmos e Teoria dos Grafos",
"CI067": "Oficina de Computação",
"CI068": "Circuitos Lógicos",
"CI162": "Engenharia de Requisitos",
"CI163": "Projeto de Software",
"CI164": "Introdução à Computação Científica",
"CI165": "Análise de Algoritmos",
"CI166": "Metodologia Científica",
"CI209": "Inteligência Artificial",
"CI210": "Projetos Digitais e Microprocessadores",
"CI211": "Construção de Compilares",
"CI212": "Organização e Arquitetura de Computadores",
"CI215": "Sistemas Operacionais",
"CI218": "Sistemas de Bancos de Dados",
"CI220": "Teoria de Sistemas",
"CI221": "Engenharia de Software",
"CI237": "Matemática Discreta",
"CM005": "Álgebra Linear",
"CM045": "Geometria Analítica",
"CM046": "Introdução à Álgebra",
"CM201": "Cálculo Diferencial e Integral I",
"CM202": "Cálculo Diferencial e Integral II",
"SA214": "Introdução à Teoria Geral da Administração",
"CI069": "Administração de Empresas de Informática",
"CI084": "Tópicos em Teoria dos Grafos",
"CI085": "Tópicos em Computação Gráfica",
"CI086": "Tópicos em Arquitetura de Computadores",
"CI087": "Tópicos em Banco de Dados",
"CI088": "Tópicos em Sistemas Distribuídos",
"CI089": "Tópicos em Teoria da Computação",
"CI090": "Tópicos em Engenharia de Software>",
"CI091": "Tópicos em Avaliação de Desempenho",
"CI092": "Tópicos em Tecnologias e Aplicações",
"CI093": "Tópicos em Análise Numérica",
"CI094": "Tópicos em Processamento de Imagens",
"CI095": "Tópicos em Compiladores",
"CI097": "Tópicos em Sistemas Digitais",
"CI167": "Sistemas de Informação em Saúde",
"CI168": "Tópicos em Sistemas de Informação em Saúde",
"CI169": "Bioinformática",
"CI170": "Tópicos em Bioinformática",
"CI171": "Aprendizado de Máquina",
"CI172": "Processamento de Imagens Biomédicas",
"CI173": "Computação Gráfica",
"CI174": "Tópicos em Engenharia da Computação",
"CI204": "Administração de Informática",
"CI205": "Administração de Produção para Informática",
"CI214": "Estrutura de Linguagens de Programação",
"CI301": "Tópicos em Ciência da Computação I",
"CI302": "Tópicos em Ciência da Computação II",
"CI303": "Tópicos em Ciência da Computação III",
"CI304": "Tópicos em Ciência da Computação IV",
"CI305": "Tópicos em Ciência da Computação V",
"CI306": "Tópicos em Ciência da Computação VI"