# Making matplotlib look like ggplot

When I first started using matplotlib, the output looked very crisp and polished compared to excel, however after seeing ggplot2, I realized that matplotlib’s default presentation settings leave a lot to be desired. I have put together a quick script that will restyle an axes to look more or less like ggplot2′s.

def rstyle(ax):
"""Styles an axes to appear like ggplot2
Must be called after all plot and axis manipulation operations have been carried out (needs to know final tick spacing)
"""

#set the style of the major and minor grid lines, filled blocks
ax.grid(True, 'major', color='w', linestyle='-', linewidth=1.4)
ax.grid(True, 'minor', color='0.92', linestyle='-', linewidth=0.7)
ax.patch.set_facecolor('0.85')
ax.set_axisbelow(True)

#set minor tick spacing to 1/2 of the major ticks
ax.xaxis.set_minor_locator(MultipleLocator( (plt.xticks()[0][1]-plt.xticks()[0][0]) / 2.0 ))
ax.yaxis.set_minor_locator(MultipleLocator( (plt.yticks()[0][1]-plt.yticks()[0][0]) / 2.0 ))

#remove axis border
for child in ax.get_children():
if isinstance(child, matplotlib.spines.Spine):
child.set_alpha(0)

#restyle the tick lines
for line in ax.get_xticklines() + ax.get_yticklines():
line.set_markersize(5)
line.set_color("gray")
line.set_markeredgewidth(1.4)

#remove the minor tick lines
for line in ax.xaxis.get_ticklines(minor=True) + ax.yaxis.get_ticklines(minor=True):
line.set_markersize(0)

#only show bottom left ticks, pointing out of axis
rcParams['xtick.direction'] = 'out'
rcParams['ytick.direction'] = 'out'
ax.xaxis.set_ticks_position('bottom')
ax.yaxis.set_ticks_position('left')

if ax.legend_ <> None:
lg = ax.legend_
lg.get_frame().set_linewidth(0)
lg.get_frame().set_alpha(0.5)

def rhist(ax, data, **keywords):
"""Creates a histogram with default style parameters to look like ggplot2
Is equivalent to calling ax.hist and accepts the same keyword parameters.
If style parameters are explicitly defined, they will not be overwritten
"""

defaults = {
'facecolor' : '0.3',
'edgecolor' : '0.28',
'linewidth' : '1',
'bins' : 100
}

for k, v in defaults.items():
if k not in keywords: keywords[k] = v

return ax.hist(data, **keywords)

def rbox(ax, data, **keywords):
"""Creates a ggplot2 style boxplot, is eqivalent to calling ax.boxplot with the following additions:

Keyword arguments:
colors -- array-like collection of colours for box fills
names -- array-like collection of box names which are passed on as tick labels

"""

hasColors = 'colors' in keywords
if hasColors:
colors = keywords['colors']
keywords.pop('colors')

if 'names' in keywords:
ax.tickNames = plt.setp(ax, xticklabels=keywords['names'] )
keywords.pop('names')

bp = ax.boxplot(data, **keywords)
pylab.setp(bp['boxes'], color='black')
pylab.setp(bp['whiskers'], color='black', linestyle = 'solid')
pylab.setp(bp['fliers'], color='black', alpha = 0.9, marker= 'o', markersize = 3)
pylab.setp(bp['medians'], color='black')

numBoxes = len(data)
for i in range(numBoxes):
box = bp['boxes'][i]
boxX = []
boxY = []
for j in range(5):
boxX.append(box.get_xdata()[j])
boxY.append(box.get_ydata()[j])
boxCoords = zip(boxX,boxY)

if hasColors:
boxPolygon = Polygon(boxCoords, facecolor = colors[i % len(colors)])
else:
boxPolygon = Polygon(boxCoords, facecolor = '0.95')

return bp

Usage is very simple, call rstyle(axes) just before showing or saving your figure. It is key to call it after all drawing and axis manipulation has been done, because it will be reading the major tick positions to work out where to put the minors.

from pylab import *
import scipy.stats

t = arange(0.0, 100.0, 0.1)
s = sin(0.1*pi*t)*exp(-t*0.01)
fig = plt.figure()

plot(t,s, label = "Original")
plot(t,s*2, label = "Doubled")

ax.legend()
rstyle(ax)
plt.show()

I have also included a function that creates a ggplot style histogram for you. This is nothing more than setting some default parameters to the hist function.

from pylab import *
import scipy.stats

t = arange(0.0, 100.0, 0.1)
s = sin(0.1*pi*t)*exp(-t*0.01)

fig = plt.figure()

data = scipy.stats.norm.rvs(size = 1000)
rhist(ax, data, label = "Histogram")
ax.legend()
rstyle(ax)
plt.show()

There is also a slightly more involved boxplot function which handles fill colours and names for you.

from pylab import *
import scipy.stats
data = [scipy.stats.norm.rvs(size = 100), scipy.stats.norm.rvs(size = 100), scipy.stats.norm.rvs(size = 100)]
fig = plt.figure()
ax.legend()
rbox(ax, data, names = ("One", "Two", "Three"), colors = ('white', 'cyan'))
rstyle(ax)

Finally, with a bit of help from Justin Peel over at StackOverflow, you can get some really nice graphics going that you won’t be ashamed to put in your published material or presentation.

I have only used these scripts in my fairly limited scenario and there are several obvious things such as the requirement to pass an axes, the enforcement of minor ticks at 1/2 majors, and the fact that I haven’t really done much with the legend, but it should be enough to get you started in your projects. Happy visualizating!

# Why you should use Sublime Text 2

Haven’t heard of Sublime Text 2? Well, I guess you’ve been living under a rock. Oh… you have? Well, in that case – why aren’t you using it yet?

Somewhere between a text editor and a IDE, Sublime Text 2 has been somewhat of an eye-opener into what text editors can really be.

Really, it can make a little nerd’s heart race just seeing this program in action. More than being pretty, it’s been a huge increase in productivity for me, and every day I find something new that I can either download as a plugin, or it’ll be released by the developers at a rather intense pace.

Not convinced? Well, this is why I use it. Hopefully I can make you use it too. First of all, it’s extremely fast. It’s extremely flexible. It’s also sort of free… well, more like an unlimited trial with a ‘buy me now’ nag every 10 or so saves. It’s also cross-platform!

I recommend buying it for the paltry \$59 though, and this is why:

It’s fast:

Loading the program itself is practically immediate, depending on your system. It’ll open up your last project in little more than a heartbeat. Clicking open files shows the source code immediately (even for large amounts of text), and allows you to quickly glance over large amounts of code.

Not only is it fast in the most literal of sense… getting places is really quick too. Seriously, check these keyboard shortcuts out:

CTRL + P: Quickly select files from your open project using a very quick fuzzy match searching algorithm. You can type the filename or start writing the file path… it’ll find it and immediately preview the selected file as you scroll through your search.

CTRL + Shift + P: Run different commands from your installed addons, change themes, insert snippets… this is your go to command for this sort of thing.

CTRL + Shift + F: Quick find, search all open documents and list the files and an excerpt almost instantly. Double click the excerpt or the filename and you’ve found your chosen piece of code.

CTRL + G: Goto line number.

It’s flexible:

More to the point, you’ll want to install the Sublime Package Control plugin. With this, you can search and install plugins from a rather large list, often coming straight from the github/bitbucket repositories. The addon system alone is a reason you’ll want Sublime Text 2. From installing new themes, to adding missing or useful features, to just making the development process that little bit nicer: you want this.

As a django/python developer, I recommend a few apps:

Djaneiro: Your one stop for django syntax and code highlighting for django templates. If you’re a django developer, get this.

SublimeRope: Code completion – and a nifty ‘go to definition’ feature… though not without some initial setup. I’ll briefly tell you how to set rope up to actually work… because it doesn’t unless you do the following:

Press CTRL + Shift + P and type “rope”, and find “New Project”. At the bottom it will ask you for project details. Press enter for the first one, and you may have success with the next if you use a virtualenv (I always get errors). If you do too, continue on:

Go to your new .ropeproject folder in your project and edit the config.py. Find the section that looks like this:

# You can extend python path for looking up modules
#prefs.add('python_path', '~/python/')

prefs.add('python_path', '/path/to/site-packages')
prefs.add('python_path', '/path/to/your/project')