Skip to content
Sam Howes edited this page Aug 29, 2016 · 2 revisions
  1. Writing a Python script
  2. What to import
  3. VIS components
  4. Inputs and outputs
  5. Job settings
  6. Managing results

1. Writing a Python script

Using the VIS-Framework is all about building a custom analysis machine. This is done by selecting any number of jobs that can gather, organize, process, or display musical data from a piece or corpus of pieces, and combining them to create a single workflow. Writing a Python script allows you to save and edit your workflow bit by bit. This way, you can even come back to an old workflow and modify it to work with other pieces or corpora if need be.

Writing a Python script can be done in any text editor, but certain ones are specifically designed for writing code. Sublime Text is a good choice for beginners or veterans. Whenever you write a Python script, there are a few important things to remember:

  • Make sure to give your script the file extension .py the first time you save it; if you don't, Python will not recognize it
  • Give your script a descriptive name and save it in a familiar and well-organized location; this will help avoid confusion with other Python scripts
  • Always type # -*- coding: utf-8 -*- in the first line of any Python script; this will tell Python what kind of encoding to use

Top

2. What to import

Now you've created a script and you're ready to start coding. The first step is to import the tools that you will use in your analysis.

When importing an entire library, simply type import followed by the name of the library, e.g.,

import music21
import pandas
import csv
etc.

When importing a specific tool, such as an analyzer from the VIS-Framework, you must specify its location with the keyword from, e.g.,

from vis.analyzers.indexers import noterest

If you know you will be using multiple analyzers from the same place, you can import them all at once in a single line of code, e.g.,

from vis.analyzers.idexers import noterest, offset, interval

It is important that all of your import statements appear together at the beginning of your script. This will make it immediately clear to you (and other programmers, should your code become public) which libraries are necessary when running your script.

Top

3. VIS components

Analyzers

Analyzers, like the ones you saw in the import statements above, make up the bulk of VIS-Framework. There are two different kinds of analyzers in VIS: indexers and experimenters.

To get a feel for the number and variety of analyzers that are available to you, explore the different file folders in the VIS-Framework. These can be found in Python27\Lib\site-packages\vis.

Most workflows will begin with one or more indexers to extract and organize data from symbolic music files such as MusicXML, MEI, or Midi. The NoteRest indexer, for example, is a good way to begin. It indexes all of the notes and rests in a piece and stores them in a pandas.DataFrame.

Once you have obtained some data, you can use experimenters to interpret them in various ways. The Frequency experimenter can track the frequency of certain user-defined events in a piece. Other experimenters can be used to generate visualizations of your data, such as the Dendogram and Barchart experimenters.

Models

Scripts

Scripts are the most specific components of the VIS-Framework. Rather than combining them together to create a workflow, scripts can be used on their own. Like the scripts that you will write, many of the scripts included in the VIS-Framework were written to address a specific research question.

Top

4. Inputs and outputs

Every job in the VIS-Framework, whether an indexer, an experimenter, or a model, has an input and an output. When constructing your workflow, it is important to know which jobs require which inputs to run properly. Many jobs require a single input in the form of a pandas.DataFrame generated by some other job upstream.

The NoteRest indexer, for example, takes a symbolic music file as its input and generates a pandas.DataFrame. The VerticalInterval indexer takes a pandas.DataFrame as its input, but it must be a DataFrame generated by the NoteRest indexer. Providing an indexer with the wrong input (whether the wrong instance, or simply the wrong type) will produce an error message. This way, you will never inadvertently produce meaningless results by running a workflow of VIS-Framework jobs. If you do encounter any error messages, read them carefully to see where in your workflow a problem might be.

The table below lists the input and output for every different job. Refer to it frequently so you know which jobs should be connected and in what order.

Table 1

As you can see, some jobs require multiple inputs. The Dissonance indexer, for example, requires four separate pandas.DataFrames generated by four different jobs in a specific order. These DataFrames are passed to the Dissonance indexer as a list.

Top

5. Job settings

Apart from an input (or in some cases, multiple inputs), almost every job in the VIS-Framework has settings. Job settings allow you to fine-tune your analysis without having to change the number or order of jobs in your workflow. You might decide that simple intervals are easier to read than compound intervals, or that you would rather look for four-note motives instead of five-note motives. You might even decide that you only want to consider events that occur on downbeats for your analysis. All of these decisions can be effected in the settings you pass to a job.

The settings for any job in the VIS-Framework must be passed to that job as a dictionary. You should define the settings for each job only once within the body of your script. That way, if you decide to change a setting, you only have to change it in one place. The following format is ideal:

offset_settings = {'quarterLength': 4, method': 'ffill', 'mp': True}
offsets = offset.FilterByOffsetIndexer(notes, offset_settings).run()

As you can see, the FilterByOffset indexer has three settings: quarterlength, method, and mp, each of which is assigned some value in the dictionary in the first line. The indexer itself is called in the second line: offset.FilterByOffsetIndexer().run() and two objects, notes and offset_settings, are passed to it in the first pair of round brackets. The notes object is the input: a pandas.DataFrame generated by the NoteRest indexer (an upstream job not shown in this snippet) and the offset_settings object is the dictionary of settings that was defined in the first line.

If you don't assign a value to every setting of every job, your workflow will probably still run. This is because all jobs in the VIS-Framework have default settings that allow them to run even if no settings are provided by the user. The table below lists the settings for every different job, along with their types (in red) and default values (in blue).

Table 2

Top

6. Managing results