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/*
|
||||
spotifyvis/static/graphs/sass/*
|
||||
|
||||
*.pyc
|
||||
*.log
|
||||
*.bak
|
||||
*.txt
|
||||
*.log
|
||||
*.map
|
||||
*.orig
|
||||
*.pyc
|
||||
*.txt
|
||||
|
||||
api-keys.sh
|
||||
db.sqlite3
|
||||
|
||||
16
README.md
16
README.md
@@ -26,7 +26,11 @@ pip install --user pipenv
|
||||
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.
|
||||
|
||||
@@ -40,16 +44,10 @@ source bin/activate
|
||||
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
|
||||
```
|
||||
|
||||
7. Start the server.
|
||||
|
||||
```
|
||||
python manage.py runserver
|
||||
cd src && ./reset_db.sh
|
||||
```
|
||||
|
||||
<!--- }}} 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
|
||||
* @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)
|
||||
*/
|
||||
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 width = 1000 - margin.right - margin.left;
|
||||
// let height = 1000 - margin.top - margin.bottom;
|
||||
@@ -36,7 +108,7 @@ function drawArtistGraph(artistData, parentElem) {
|
||||
.append("svg")
|
||||
//responsive SVG needs these 2 attributes and no width and height attr
|
||||
.attr("preserveAspectRatio", "xMinYMin meet")
|
||||
.attr("viewBox", "0 0 600 250")
|
||||
.attr("viewBox", "0 0 1024 768")
|
||||
//class to make it responsive
|
||||
.classed("svg-content-responsive", true);
|
||||
|
||||
@@ -61,9 +133,7 @@ function drawArtistGraph(artistData, parentElem) {
|
||||
});
|
||||
|
||||
node.append("circle")
|
||||
.attr("r", function(d) {
|
||||
return d.r;
|
||||
})
|
||||
.attr("r", d => d.r)
|
||||
.style("fill", function(d,i) {
|
||||
return color(i);
|
||||
});
|
||||
@@ -73,7 +143,8 @@ function drawArtistGraph(artistData, parentElem) {
|
||||
.attr("dy", ".2em")
|
||||
.style("text-anchor", "middle")
|
||||
.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-size", function(d){
|
||||
@@ -97,7 +168,4 @@ function drawArtistGraph(artistData, parentElem) {
|
||||
d3.select(self.frameElement)
|
||||
// .style("height", height + "px");
|
||||
.style("height", "100%")
|
||||
|
||||
|
||||
|
||||
}
|
||||
}//}}}
|
||||
|
||||
@@ -41,6 +41,8 @@ function create_genre_graph(data) {
|
||||
// hue: '#00ced1',
|
||||
hue: '#0099CC',
|
||||
}));
|
||||
// colorScale = d3.scaleOrdinal(d3.schemeCategory10);
|
||||
// colorScale = d3.scaleOrdinal(d3.schemeDark2);
|
||||
|
||||
// }}} setup bar colors //
|
||||
|
||||
|
||||
@@ -8,20 +8,22 @@
|
||||
<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/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>
|
||||
<body>
|
||||
<div class="container-fluid">
|
||||
</div>
|
||||
<script src="https://d3js.org/d3.v5.js"></script>
|
||||
<script src="{% static "graphs/scripts/artist_graph.js" %}"></script>
|
||||
<script>
|
||||
d3.json("{% url "api:get_artist_data" user_secret %}").then(function(data) {
|
||||
// this is the data format needed for bubble charts
|
||||
data = {
|
||||
children: data
|
||||
};
|
||||
{% comment %} drawArtistGraph(data, "body"); {% endcomment %}
|
||||
drawArtistGraph(data, ".container-fluid");
|
||||
{% comment %} drawArtistGraphOld(data, ".container-fluid"); {% endcomment %}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
@@ -15,13 +15,13 @@
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<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>
|
||||
|
||||
<!-- }}} header -->
|
||||
|
||||
<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 %}
|
||||
<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
|
||||
|
||||
/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