Data + Graph for books per month per genre
This commit is contained in:
parent
cc371244ef
commit
2318f741a4
|
@ -0,0 +1,65 @@
|
||||||
|
book;author;genre;pages;readed;rating
|
||||||
|
Omnia in Omnibus;Lisa Pennings;Sciencefiction;166;05-2013;4
|
||||||
|
Het leven van Pi;Yann Martel;Roman;317;10-2020;4
|
||||||
|
Ze komt nooit meer terug;Hans Koppel;Thriller;220;10-2020;5
|
||||||
|
Vriendschapsverzoek;Laura Marshall;Thriller;368;10-2020;4
|
||||||
|
De analist;John Katzenbach;Thriller;518;11-2020;4
|
||||||
|
Komt een vrouw bij de hacker;Maria Genova;Thriller;224;11-2020;4
|
||||||
|
Niemand hoort het;Linwood Barclay;Thriller;304;11-2020;5
|
||||||
|
Lift;Linwood Barclay;Thriller;480;11-2020;3
|
||||||
|
Kijk niet weg;Linwood Barclay;Thriller;400;12-2020;5
|
||||||
|
Het duistere net;Carmen Mola;Thriller;415;12-2020;5
|
||||||
|
De 50/50-moorden;Steve Mosby;Thriller;344;12-2020;3
|
||||||
|
Zonder een woord;Linwood Barclay;Thriller;368;01-2021;5
|
||||||
|
Geen veilige plek;Linwood Barclay;Thriller;368;01-2021;3
|
||||||
|
Op slot;Chris McGeorge;Thriller;320;01-2021;5
|
||||||
|
Alles is eventueel / 1408;Stephen King;Thriller;462;02-2021;3
|
||||||
|
Waarom je niet zomaar moet stemmen waar je ouders op stemmen;Titia Hoogendoorn&Nienke Schuitemaker;Non-fictie;125;02-2021;4
|
||||||
|
Geloof je ogen;Linwood Barclay;Thriller;384;02-2021;4
|
||||||
|
Voor ik ga slapen;SJ Watson;Thriller;333;03-2021;5
|
||||||
|
Echo;Tamara Geraeds;Thriller;280;03-2021;5
|
||||||
|
Niemand vertellen;Harlan Coben;Thriller;302;03-2021;4
|
||||||
|
Ik zie je;Michael Berg;Thriller;320;04-2021;4
|
||||||
|
Toevluchtsoord;Jerome Loubry;Thriller;355;04-2021;5
|
||||||
|
In een donker donker bos;Ruth Ware;Thriller;320;04-2021;3
|
||||||
|
Een voor een;Ruth Ware;Thriller;368;04-2021;4
|
||||||
|
Vrees het ergste;Linwood Barclay;Thriller;400;05-2021;4
|
||||||
|
Het poppenhuis;W.R. Dantz;Thriller;270;05-2021;3
|
||||||
|
Malorie;Josh Malerman;Thriller;320;05-2021;4
|
||||||
|
Opgejaagd;Gabriel Bergmoser;Thriller;256;06-2021;4
|
||||||
|
Reset;Blake Crouch;Thriller;352;06-2021;4
|
||||||
|
Wacht maar af;Loes den Hollander;Thriller;300;06-2021;4
|
||||||
|
De Russische connectie;Gerrit Barendrecht;Thriller;320;06-2021;4
|
||||||
|
Wat jij niet ziet;M.J. Arlidge;Thriller;95;07-2021;3
|
||||||
|
Het ongeluk;Linwood Barclay;Thriller;382;07-2021;4
|
||||||
|
Slapen in een zee van sterren;Christopher Paolini;Sciencefiction;880;07-2021;2
|
||||||
|
Tik Tak;Chris McGeorge;Thriller;320;07-2021;4
|
||||||
|
Gegijzeld;Clare Mackintosh;Thriller;397;08-2021;5
|
||||||
|
Eindbestemming;Marjolein van der Gaag&Marcella Kleine;Thriller;158;08-2021;4
|
||||||
|
Een kille rilling;Bernard Minier;Thriller;582;09-2021;4
|
||||||
|
De nachtdienst;Esther Verhoef;Thriller;365;09-2021;5
|
||||||
|
Kiekeboe;Chris McGeorge;Thriller;352;10-2021;3
|
||||||
|
Noorderlicht;Mariska Overman;Thriller;313;10-2021;4
|
||||||
|
De kleine getuige;Jilliane Hoffman;Thriller;368;11-2021;4
|
||||||
|
De marathon;Stephen King;Thriller;261;11-2021;4
|
||||||
|
Het appartement;Tatiana de Rosnay;Roman;215;11-2021;4
|
||||||
|
De intrigant;Patricia Snel;Thriller;189;12-2021;4
|
||||||
|
Een schuldig huis;Robert Goddard;Thriller;384;12-2021;5
|
||||||
|
Te koop;Eva Monte;Thriller;350;12-2021;3
|
||||||
|
Prison Break S1B1;Paul T. Scheuring;Thriller;221;01-2022;5
|
||||||
|
Prison Break S1B2;Ed van Eeden;Thriller;272;01-2022;4
|
||||||
|
Prison Break S1B3;Paul T. Scheuring;Thriller;285;01-2022;4
|
||||||
|
Herfstlied;Simone van der Vlugt;Thriller;277;02-2022;5
|
||||||
|
De gastenlijst;Lucy Foley;Thriller;352;02-2022;2
|
||||||
|
Anomalie;Herve le Tellier;Thriller;302;02-2022;2
|
||||||
|
Prison Break S2B1;Paul T. Scheuring;Thriller;207;03-2022;4
|
||||||
|
Prison Break S2B2;Paul T. Scheuring;Thriller;205;03-2022;4
|
||||||
|
Prison Break S2B3;Paul T. Scheuring;Thriller;245;03-2022;4
|
||||||
|
Ik weet je wachtwoord;Daniel Verlaan;Non-fictie;347;04-2022;5
|
||||||
|
De vrouw die een jaar in bed ging liggen;Sue Townsend;Roman;368;04-2022;3
|
||||||
|
Moord in de bibliotheek;Agatha Christie;Thriller;256;04-2022;3
|
||||||
|
Geestdrift;Daniel Hecht;Thriller;509;05-2022;1
|
||||||
|
Moord in de Orient Expres;Agatha Christie;Thriller;222;05-2022;4
|
||||||
|
Crash;Jack Bowman;Thriller;344;05-2022;3
|
||||||
|
Erken mij;Esther Verhoef;Thriller;91;06-2022;4
|
||||||
|
Gestrand;Sarah Goodwin;Thriller;352;06-2022;5
|
|
|
@ -3,5 +3,5 @@ from .views import *
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('books', api_all_books),
|
path('books', api_all_books),
|
||||||
path('books/<int:_id>', api_get_book),
|
path('books/genres', books_per_genre_per_month)
|
||||||
]
|
]
|
|
@ -1,26 +1,55 @@
|
||||||
from rest_framework.decorators import api_view
|
from rest_framework.decorators import api_view
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from .models import Books
|
from .models import Books
|
||||||
|
import pandas as pd
|
||||||
|
|
||||||
from .serializers import BooksSerializer
|
from .serializers import BooksSerializer
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
|
from django.templatetags.static import static
|
||||||
|
import json
|
||||||
|
|
||||||
@api_view(['GET'])
|
@api_view(['GET'])
|
||||||
def api_all_books(request):
|
def api_all_books(request):
|
||||||
all_books = Books.objects.all()
|
df = pd.read_csv("api/static/books2.csv", encoding = "utf-8")
|
||||||
if all_books:
|
books = []
|
||||||
serializer = BooksSerializer(all_books, many=True)
|
for book in df['Books']:
|
||||||
return Response(serializer.data)
|
info = book.split(';')
|
||||||
else:
|
books.append({
|
||||||
return Response({"Message": 'Books Not Found'})
|
"name": info[0],
|
||||||
|
"author": info[1],
|
||||||
|
"genre": info[2],
|
||||||
|
"pages": info[3],
|
||||||
|
"readed": info[4],
|
||||||
|
"rating": info[5]
|
||||||
|
})
|
||||||
|
return Response(books)
|
||||||
|
|
||||||
@api_view(['GET'])
|
@api_view(['GET'])
|
||||||
def api_get_book(request, _id):
|
def books_per_genre_per_month(request):
|
||||||
|
|
||||||
obj = Books.objects.filter(id = _id)[0]
|
datayear = request.META.get('HTTP_YEAR')
|
||||||
if obj:
|
|
||||||
serializer = BooksSerializer(obj)
|
if datayear:
|
||||||
return Response(serializer.data)
|
|
||||||
|
data = []
|
||||||
|
|
||||||
|
# Get CSV file with book data
|
||||||
|
df = pd.read_csv("api/static/books2.csv", encoding = "utf-8", header = 0, sep=';')
|
||||||
|
|
||||||
|
# Filter data on year
|
||||||
|
df = df.where(df['readed'].str.contains(datayear))
|
||||||
|
|
||||||
|
# Filter array on genre and date
|
||||||
|
booksPerMonth = df.groupby(['genre','readed'])['genre'].count().reset_index(name="count")
|
||||||
|
booksPerMonth = booksPerMonth.sort_values(by='readed')
|
||||||
|
|
||||||
|
for index, row in booksPerMonth.iterrows():
|
||||||
|
data.append({
|
||||||
|
"genre": row['genre'],
|
||||||
|
"readed": row['readed'],
|
||||||
|
"count": row['count']
|
||||||
|
})
|
||||||
|
|
||||||
|
return Response(data)
|
||||||
else:
|
else:
|
||||||
return Response({"Message": 'Book Not Found'})
|
return Response("No year header included")
|
|
@ -1,15 +1,119 @@
|
||||||
import React, { Component } from "react"
|
import React, { Component } from "react";
|
||||||
import {render} from "react-dom"
|
|
||||||
|
|
||||||
export default class App extends Component {
|
export default class App extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
}
|
}
|
||||||
|
|
||||||
render(){
|
initChart(data, year) {
|
||||||
return <p>Soon here comes the Reading Analytics System!</p>
|
|
||||||
|
var genres = [];
|
||||||
|
|
||||||
|
var colors = [
|
||||||
|
'#d0b2cf', '#b66f2b', '#003C72', '#ecdb0e'
|
||||||
|
]
|
||||||
|
|
||||||
|
var dataSet = [];
|
||||||
|
|
||||||
|
data.forEach(book => {
|
||||||
|
if (!genres.includes(book.genre)) {
|
||||||
|
genres.push(book.genre)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (genres && genres.length > 0) {
|
||||||
|
genres.forEach((genre, index) => {
|
||||||
|
var genreData = [];
|
||||||
|
|
||||||
|
for (var i = 0; i < 12; i++) {
|
||||||
|
|
||||||
|
genreData[i] = 0;
|
||||||
|
|
||||||
|
if ((i + 1) < 10) {
|
||||||
|
var month = "0" + (i + 1);
|
||||||
|
} else {
|
||||||
|
month = (i + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var j = 0; j < data.length; j++) {
|
||||||
|
if (data && data[j] && data[j].readed == month + '-' + year) {
|
||||||
|
if (data[j].genre == genre) {
|
||||||
|
genreData[i] = data[j].count;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const appDiv = document.getElementById("app");
|
dataSet.push({
|
||||||
render(<App />, appDiv);
|
label: genre,
|
||||||
|
data: genreData,
|
||||||
|
backgroundColor: colors[index]
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
new Chart(document.getElementById('chart'), {
|
||||||
|
type: 'bar',
|
||||||
|
data: {
|
||||||
|
labels: ["Januari", "Februari", "Maart", "April", "Mei", "Juni", "Juli", "Augustus", "September", "Oktober", "November", "December"],
|
||||||
|
datasets: dataSet
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
legend: {
|
||||||
|
display: true,
|
||||||
|
},
|
||||||
|
tooltips: {
|
||||||
|
mode: 'index',
|
||||||
|
intersect: true,
|
||||||
|
axis: 'y'
|
||||||
|
},
|
||||||
|
scales: {
|
||||||
|
x: {
|
||||||
|
ticks: {
|
||||||
|
beginAtZero: true,
|
||||||
|
|
||||||
|
},
|
||||||
|
stacked: true,
|
||||||
|
},
|
||||||
|
y: {
|
||||||
|
ticks: {
|
||||||
|
beginAtZero: true,
|
||||||
|
stepSize: 1
|
||||||
|
},
|
||||||
|
stacked: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
|
||||||
|
var currentyear = new Date().getFullYear()
|
||||||
|
|
||||||
|
console.log(currentyear);
|
||||||
|
|
||||||
|
fetch('/api/books/genres', {
|
||||||
|
"method": "GET",
|
||||||
|
"headers": {
|
||||||
|
"year": currentyear
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
this.initChart(data, currentyear);
|
||||||
|
console.log(data);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<canvas id="chart"></canvas>
|
||||||
|
<p>Soon here comes the Reading Analytics System! test</p>
|
||||||
|
</React.Fragment>
|
||||||
|
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1 +1,5 @@
|
||||||
|
import React from 'react';
|
||||||
|
import ReactDOM from 'react-dom';
|
||||||
import App from "./App";
|
import App from "./App";
|
||||||
|
|
||||||
|
ReactDOM.render(<App />, document.getElementById('app'));
|
File diff suppressed because one or more lines are too long
|
@ -26,6 +26,7 @@
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="{% static "frontend/main.js" %}"></script>
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||||
|
<script src="{% static "js/main.js" %}"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
|
@ -11,6 +11,7 @@ https://docs.djangoproject.com/en/4.1/ref/settings/
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
import os
|
||||||
|
|
||||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||||
|
@ -131,6 +132,10 @@ USE_TZ = True
|
||||||
# https://docs.djangoproject.com/en/4.1/howto/static-files/
|
# https://docs.djangoproject.com/en/4.1/howto/static-files/
|
||||||
|
|
||||||
STATIC_URL = 'static/'
|
STATIC_URL = 'static/'
|
||||||
|
STATICFILES_DIR = [
|
||||||
|
BASE_DIR / 'static'
|
||||||
|
]
|
||||||
|
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
|
||||||
|
|
||||||
# Default primary key field type
|
# Default primary key field type
|
||||||
# https://docs.djangoproject.com/en/4.1/ref/settings/#default-auto-field
|
# https://docs.djangoproject.com/en/4.1/ref/settings/#default-auto-field
|
||||||
|
|
Loading…
Reference in New Issue