A little toy for you
If you want to play about with
a little toy I’ve been messing around with then you can find it
here.
It’s a little Python app (requiring pygame
to be installed, on Debian systems like Ubuntu this is provided by the
python-pygame package) which, when given a band name, connects to
last.fm and gets related artists, and their related
artists, etc. putting them all in a graph weighted to their relative
strengths to make a map of musicians (for an explanation of the algorith
see below).
This is
very buggy, unbelievably inefficient, and could likely cause a lot of
stress for last.fm, so use sparingly (remember, if someone wants to DOS
attack last.fm this is not the most efficient way of doing so, so don’t
think of it at warez or anything because it’s not meant to
be).
To
use:
Extract the archive,
then run the file Visualiser.py. I would recommend running it in a way
that can be killed easily (for example from within the Geany IDE, which
has an Execute and Stop button), since it is an experiment with
threading for me and killing those threads can be annoying if (when) the
(increasingly complex) graphics thread dies (although if you do run it
from a commandline then you can give it a band name directly, like
“./Visualiser.py Children of Bodom”)
When the window comes up click on the Artist
Entry field to select it, use backspace to get rid of the default text,
then enter the artist you want to start with and press return. The
program should then start downloading images and relationships between
artists, adding them to the graph as it does. The deeper the
relationship matching the more accurate the map, at the expense of
coverage, the more artists modelled the more accurate the map, at the
expense of speed (there’s a stupid-ass bug in the total artists down
button at the moment because I’m an idiot). You can choose to see images
(which, if disabled, will also disable image downloading), text labels
and the underlying web of connections (the lighter the strand the
stronger the connection). Note that enabling and disabling images shifts
the nodes in the rendering of the web only, it doesn’t affect the
modelling in any way (the artists are modelled with their position as
the top-left corner of the image/text, which doesn’t
change).
What it’s
doing:
The artists exist
in a python dictionary, with various different lists of the keys
existing for different purposes (the main one being usableArtists).
Connections between artists are stored in a separate dictionary, and
pairs of artists with no connection between each other are stored in
another dictionary.
The Handling thread goes through a list of
artists which are known to exist but who are not yet modelled. It then
puts each artist in turn into the dictionary and appropriate lists,
creating connections as far as the link depth goes (a link depth of zero
only connects the most related artist to each artist, which makes
forming closed systems easier (eg. Edguy is most related to Avantasia,
Avantasia is most related to Edguy, resulting in only those two being
modelled for a link depth of zero)). After the connections have been
made it sets up a repulsion between the new artist and every artist
which it is not connected to. It continues like this until there are
either no more artists left to process (a closed system has been made)
or until the total artists limit is reached (cutting short a complete
modelling of the given variables).
The Image Fetching thread, as long as images
are enabled, fetches images for those artists which haven’t been
assigned one yet. The Relation Fetching thread does the same thing for
artists without relationship information.
The Drawing thread draws the graphics and
handles user interaction.
The Force thread goes through the list of
modelled artists, setting the force on each to zero and halving their
velocities (which gives a little bounce to the system). It then goes
through the list of connections, assigning an optimum distance apart for
the artists (100% similar artists should be close, 20% similar artists
should be further away. The distance is direction-independent), then
adds a force to each based on how far away they are from this optimum
distance, further away means greater force, and the stronger the
connection the stronger the force. This means that weakly related
artists will tend to move a good distance apart over time, but if other
factors can easily overpower this tendency. The list of repulsions is
then gone through, forcing apart any not connected artists which are
closer than a certain distance.
The Linear thread constantly updates the
movement of the artists, calculating their acceleration based on their
experienced force and a set mass, from that calculating their velocity
and from that calculating their position (which in turn feeds back to
the Force thread)
Well, that’s basically it for the time
being. There are many bugs with it (due to the repulsion’s cut-off point
some arms of the map can arc around and become close to other areas to
which they have no relation, non-English alphanumeric characters cause
problems, the total artists down button is broken, there is a rare
tendency for the artists to shoot off and crash PyGame by having
extremely massive coordinates and probably a lot more needs seeing to as
well) but it is purely experimental at the
moment.
And the
point of this? Well, firstly I think it is pretty cool. Aside from that
I think it would be a nice way of browsing one’s music collection. By
hooking into the multiple genre tags that last.fm gives to artists then
this information could be used to map out genres, thus letting users
select an area of music they want to listen to, rather than having to
specify Speed Metal OR Thrash, and playlists could be defined by drawing
a path through the map, moving gradually from one genre to another
without obvious jumps. Anyway, that is work for the future. At the
moment have fun watching the pictures bounce aroud on strings
:)