Artist graph improvements
- title - full artist name on multiple lines - responsive and fit screen (#63) Other: - added creating db to README - added script to update requirements - updated requirements
This commit is contained in:
7
.gitignore
vendored
7
.gitignore
vendored
@@ -4,11 +4,12 @@
|
|||||||
media/history/*
|
media/history/*
|
||||||
spotifyvis/static/graphs/sass/*
|
spotifyvis/static/graphs/sass/*
|
||||||
|
|
||||||
*.pyc
|
|
||||||
*.log
|
|
||||||
*.bak
|
*.bak
|
||||||
*.txt
|
*.log
|
||||||
*.map
|
*.map
|
||||||
|
*.orig
|
||||||
|
*.pyc
|
||||||
|
*.txt
|
||||||
|
|
||||||
api-keys.sh
|
api-keys.sh
|
||||||
db.sqlite3
|
db.sqlite3
|
||||||
|
|||||||
16
README.md
16
README.md
@@ -26,7 +26,11 @@ pip install --user pipenv
|
|||||||
python3 -m venv /path/to/new/virtual/environment
|
python3 -m venv /path/to/new/virtual/environment
|
||||||
```
|
```
|
||||||
|
|
||||||
3. `cd` into the directory you just created a virtual environment in, and clone the GitHub repo.
|
3. `cd` into the directory you just created a virtual environment in, and clone the GitHub repo:
|
||||||
|
|
||||||
|
```
|
||||||
|
git clone https://github.com/Kevin-Mok/spotify-lib-vis
|
||||||
|
```
|
||||||
|
|
||||||
4. Activate the virtual environment from the command line.
|
4. Activate the virtual environment from the command line.
|
||||||
|
|
||||||
@@ -40,16 +44,10 @@ source bin/activate
|
|||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
```
|
```
|
||||||
|
|
||||||
6. Run Django migrations.
|
6. Run `reset_db.sh` to create the database and start the server.
|
||||||
|
|
||||||
```
|
```
|
||||||
manage.py migrate
|
cd src && ./reset_db.sh
|
||||||
```
|
|
||||||
|
|
||||||
7. Start the server.
|
|
||||||
|
|
||||||
```
|
|
||||||
python manage.py runserver
|
|
||||||
```
|
```
|
||||||
|
|
||||||
<!--- }}} installation steps -->
|
<!--- }}} installation steps -->
|
||||||
|
|||||||
@@ -1,9 +1,81 @@
|
|||||||
|
const log = console.log
|
||||||
|
const width = 1366
|
||||||
|
const height = 768
|
||||||
|
// const width = 1000
|
||||||
|
// const height = 500
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draws the artist count graph as a bubble chart, and appends it the a designated parent element
|
* Draws the artist count graph as a bubble chart, and appends it the a designated parent element
|
||||||
* @param artistData: the artist counts data as an array of objects, of the format {'name': artist name, 'num_songs': 50}
|
* @param artistData: the artist counts data as an array of objects, of the format {'name': artist name, 'num_songs': 50}
|
||||||
* @param parentElem: the DOM element to append the artist graph to (as a string)
|
* @param parentElem: the DOM element to append the artist graph to (as a string)
|
||||||
*/
|
*/
|
||||||
function drawArtistGraph(artistData, parentElem) {
|
function drawArtistGraph(artistData, parentElem) {
|
||||||
|
// const color = d3.scaleOrdinal(d3.schemeCategory10);
|
||||||
|
const color = d3.scaleOrdinal().range(randomColor({//{{{
|
||||||
|
count: Object.keys(artistData.children).length,
|
||||||
|
luminosity: 'light',
|
||||||
|
}))//}}}
|
||||||
|
|
||||||
|
const svg = d3.select(parentElem)//{{{
|
||||||
|
// const svg = d3.select(DOM.svg(width, height))
|
||||||
|
.append("div")
|
||||||
|
.classed("svg-container", true) //container class to make it responsive
|
||||||
|
.append("svg")
|
||||||
|
//responsive SVG needs these 2 attributes and no width and height attr
|
||||||
|
.attr("preserveAspectRatio", "xMinYMin meet")
|
||||||
|
.attr("viewBox", `0 0 ${width} ${height}`)
|
||||||
|
//class to make it responsive
|
||||||
|
.classed("svg-content-responsive", true)
|
||||||
|
.style("width", "100%")
|
||||||
|
.style("height", "100%")
|
||||||
|
.attr("font-size", 12)
|
||||||
|
.attr("text-anchor", "middle")//}}}
|
||||||
|
|
||||||
|
const root = d3.pack()//{{{
|
||||||
|
.size([width - 2, height - 2])
|
||||||
|
.padding(3)
|
||||||
|
(d3.hierarchy(artistData)
|
||||||
|
.sum(d => d.num_songs))
|
||||||
|
|
||||||
|
const leaf = svg.selectAll("g")
|
||||||
|
.data(root.leaves())
|
||||||
|
.join("g")
|
||||||
|
.attr("transform", d => `translate(${d.x + 1},${d.y + 1})`);//}}}
|
||||||
|
|
||||||
|
leaf.append("circle")//{{{
|
||||||
|
.attr("r", d => d.r)
|
||||||
|
// .attr("fill-opacity", 0.9)
|
||||||
|
.attr("fill", (d, id) => color(id))//}}}
|
||||||
|
|
||||||
|
leaf.append("text")//{{{
|
||||||
|
.selectAll("tspan")
|
||||||
|
.data(d => d.data.name.split(/\s/g).concat([d.data.num_songs]))
|
||||||
|
.join("tspan")
|
||||||
|
.attr("x", 0)
|
||||||
|
.attr("y", (d, i, nodes) => `${i - nodes.length / 2 + 0.8}em`)
|
||||||
|
// .attr("fill", "white")
|
||||||
|
.text(d => d)//}}}
|
||||||
|
|
||||||
|
// hover text {{{ //
|
||||||
|
leaf.append("title")
|
||||||
|
.text(d => `${d.data.name}: ${d.data.num_songs}`)
|
||||||
|
// }}} hover text //
|
||||||
|
|
||||||
|
// graph title {{{ //
|
||||||
|
svg.append("text")
|
||||||
|
.attr('x', (width / 2.2))
|
||||||
|
.attr('y', 50)
|
||||||
|
.attr('fill', "white")
|
||||||
|
.attr('text-anchor', 'middle')
|
||||||
|
.attr("font-weight", "bold")
|
||||||
|
.attr("font-size", 28)
|
||||||
|
.text('Artists in Library');
|
||||||
|
// }}} graph title //
|
||||||
|
|
||||||
|
return svg.node();
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawArtistGraphOld(artistData, parentElem) {//{{{
|
||||||
let margin = {top: 20, right: 30, bottom: 30, left: 40};
|
let margin = {top: 20, right: 30, bottom: 30, left: 40};
|
||||||
// let width = 1000 - margin.right - margin.left;
|
// let width = 1000 - margin.right - margin.left;
|
||||||
// let height = 1000 - margin.top - margin.bottom;
|
// let height = 1000 - margin.top - margin.bottom;
|
||||||
@@ -36,7 +108,7 @@ function drawArtistGraph(artistData, parentElem) {
|
|||||||
.append("svg")
|
.append("svg")
|
||||||
//responsive SVG needs these 2 attributes and no width and height attr
|
//responsive SVG needs these 2 attributes and no width and height attr
|
||||||
.attr("preserveAspectRatio", "xMinYMin meet")
|
.attr("preserveAspectRatio", "xMinYMin meet")
|
||||||
.attr("viewBox", "0 0 600 250")
|
.attr("viewBox", "0 0 1024 768")
|
||||||
//class to make it responsive
|
//class to make it responsive
|
||||||
.classed("svg-content-responsive", true);
|
.classed("svg-content-responsive", true);
|
||||||
|
|
||||||
@@ -61,9 +133,7 @@ function drawArtistGraph(artistData, parentElem) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
node.append("circle")
|
node.append("circle")
|
||||||
.attr("r", function(d) {
|
.attr("r", d => d.r)
|
||||||
return d.r;
|
|
||||||
})
|
|
||||||
.style("fill", function(d,i) {
|
.style("fill", function(d,i) {
|
||||||
return color(i);
|
return color(i);
|
||||||
});
|
});
|
||||||
@@ -73,7 +143,8 @@ function drawArtistGraph(artistData, parentElem) {
|
|||||||
.attr("dy", ".2em")
|
.attr("dy", ".2em")
|
||||||
.style("text-anchor", "middle")
|
.style("text-anchor", "middle")
|
||||||
.text(function(d) {
|
.text(function(d) {
|
||||||
return d.data.name.substring(0, d.r / 3);
|
return d.data.name.substring(0, d.r / 1.5);
|
||||||
|
// return formatArtistName(d.data.name)
|
||||||
})
|
})
|
||||||
.attr("font-family", "sans-serif")
|
.attr("font-family", "sans-serif")
|
||||||
.attr("font-size", function(d){
|
.attr("font-size", function(d){
|
||||||
@@ -97,7 +168,4 @@ function drawArtistGraph(artistData, parentElem) {
|
|||||||
d3.select(self.frameElement)
|
d3.select(self.frameElement)
|
||||||
// .style("height", height + "px");
|
// .style("height", height + "px");
|
||||||
.style("height", "100%")
|
.style("height", "100%")
|
||||||
|
}//}}}
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ function create_genre_graph(data) {
|
|||||||
// hue: '#00ced1',
|
// hue: '#00ced1',
|
||||||
hue: '#0099CC',
|
hue: '#0099CC',
|
||||||
}));
|
}));
|
||||||
|
// colorScale = d3.scaleOrdinal(d3.schemeCategory10);
|
||||||
|
// colorScale = d3.scaleOrdinal(d3.schemeDark2);
|
||||||
|
|
||||||
// }}} setup bar colors //
|
// }}} setup bar colors //
|
||||||
|
|
||||||
|
|||||||
@@ -8,20 +8,22 @@
|
|||||||
<link rel="stylesheet" href="{% sass_src 'scss/custom.scss' %}">
|
<link rel="stylesheet" href="{% sass_src 'scss/custom.scss' %}">
|
||||||
<link rel="stylesheet" href="{% sass_src 'graphs/sass/responsive_graph.scss' %}">
|
<link rel="stylesheet" href="{% sass_src 'graphs/sass/responsive_graph.scss' %}">
|
||||||
<link rel="stylesheet" href="{% sass_src 'graphs/sass/max-height.scss' %}">
|
<link rel="stylesheet" href="{% sass_src 'graphs/sass/max-height.scss' %}">
|
||||||
|
{% comment %} <script type="text/javascript" src="http://livejs.com/live.js"></script> {% endcomment %}
|
||||||
|
<script src="https://d3js.org/d3.v5.js"></script>
|
||||||
|
<script src="{% static "graphs/scripts/artist_graph.js" %}"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/randomcolor/0.5.2/randomColor.min.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
</div>
|
</div>
|
||||||
<script src="https://d3js.org/d3.v5.js"></script>
|
|
||||||
<script src="{% static "graphs/scripts/artist_graph.js" %}"></script>
|
|
||||||
<script>
|
<script>
|
||||||
d3.json("{% url "api:get_artist_data" user_secret %}").then(function(data) {
|
d3.json("{% url "api:get_artist_data" user_secret %}").then(function(data) {
|
||||||
// this is the data format needed for bubble charts
|
// this is the data format needed for bubble charts
|
||||||
data = {
|
data = {
|
||||||
children: data
|
children: data
|
||||||
};
|
};
|
||||||
{% comment %} drawArtistGraph(data, "body"); {% endcomment %}
|
|
||||||
drawArtistGraph(data, ".container-fluid");
|
drawArtistGraph(data, ".container-fluid");
|
||||||
|
{% comment %} drawArtistGraphOld(data, ".container-fluid"); {% endcomment %}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -15,13 +15,13 @@
|
|||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="stylesheet" href="{% sass_src 'scss/custom.scss' %}">
|
<link rel="stylesheet" href="{% sass_src 'scss/custom.scss' %}">
|
||||||
|
<script src="https://d3js.org/d3.v5.min.js"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/randomcolor/0.5.2/randomColor.min.js"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<!-- }}} header -->
|
<!-- }}} header -->
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<script src="https://d3js.org/d3.v5.min.js"></script>
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/randomcolor/0.5.2/randomColor.min.js"></script>
|
|
||||||
|
|
||||||
{% load static %}
|
{% load static %}
|
||||||
<script src="{% static "graphs/scripts/genre_graph.js" %}"></script>
|
<script src="{% static "graphs/scripts/genre_graph.js" %}"></script>
|
||||||
|
|||||||
40
requirements.txt
Normal file
40
requirements.txt
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
astroid==2.2.5
|
||||||
|
backports.csv==1.0.7
|
||||||
|
certifi==2019.3.9
|
||||||
|
chardet==3.0.4
|
||||||
|
defusedxml==0.5.0
|
||||||
|
Django==2.2
|
||||||
|
django-appconf==1.0.3
|
||||||
|
django-compressor==2.2
|
||||||
|
django-crispy-forms==1.7.2
|
||||||
|
django-filter==2.1.0
|
||||||
|
django-sass-processor==0.7.3
|
||||||
|
django-tables2==2.0.6
|
||||||
|
djangorestframework==3.9.2
|
||||||
|
et-xmlfile==1.0.1
|
||||||
|
idna==2.8
|
||||||
|
isort==4.3.17
|
||||||
|
jdcal==1.4
|
||||||
|
lazy-object-proxy==1.3.1
|
||||||
|
libsass==0.18.0
|
||||||
|
mccabe==0.6.1
|
||||||
|
odfpy==1.4.0
|
||||||
|
openpyxl==2.6.2
|
||||||
|
psycopg2==2.8.2
|
||||||
|
psycopg2-binary==2.8.2
|
||||||
|
pylint==2.3.1
|
||||||
|
python-dateutil==2.8.0
|
||||||
|
pytz==2019.1
|
||||||
|
PyYAML==5.1
|
||||||
|
rcssmin==1.0.6
|
||||||
|
requests==2.21.0
|
||||||
|
rjsmin==1.0.12
|
||||||
|
six==1.12.0
|
||||||
|
sqlparse==0.3.0
|
||||||
|
tablib==0.13.0
|
||||||
|
typed-ast==1.3.1
|
||||||
|
unicodecsv==0.14.1
|
||||||
|
urllib3==1.24.1
|
||||||
|
wrapt==1.11.1
|
||||||
|
xlrd==1.2.0
|
||||||
|
xlwt==1.3.0
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
/home/kevin/coding/spotify-lib-vis/bin/python /home/kevin/coding/spotify-lib-vis/src/manage.py update-history >> /home/kevin/coding/spotify-lib-vis/src/api/management/commands/update-history.log
|
# /home/kevin/coding/spotify-lib-vis/bin/python /home/kevin/coding/spotify-lib-vis/src/manage.py update-history >> /home/kevin/coding/spotify-lib-vis/src/api/management/commands/update-history.log 2>&1
|
||||||
|
python /home/kevin/coding/spotify-lib-vis/src/manage.py update-history >> /home/kevin/coding/spotify-lib-vis/src/api/management/commands/update-history.log 2>&1
|
||||||
|
|||||||
7
todo.md
Normal file
7
todo.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
- genre graph
|
||||||
|
- convert to bar graph
|
||||||
|
- sizing
|
||||||
|
- ordering
|
||||||
|
- loading/progress indicator
|
||||||
|
- change js tabs to 2 spaces
|
||||||
|
- Heroku?
|
||||||
4
upgrade-pip-reqs.sh
Executable file
4
upgrade-pip-reqs.sh
Executable file
@@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
pip list --outdated --format=freeze | grep -v '^\-e' | cut -d = -f 1 | xargs -n1 pip install -U
|
||||||
|
pip freeze --local > requirements.txt
|
||||||
Reference in New Issue
Block a user