Hi there,

I'm sorry to ask such a newbie question, but I'd like to format a custom box 
plot and although there are numerous examples on the web and tons of docstrings 
in matplotlib, I'm stuck somehow. My problems center around axes / spines. In 
detail, my problems are:

1) I want an y-axis on the left that spans from -0.6 to 1.1, ends in an arrow, 
has major ticks at 0 and 1 and minor ticks at [0.1...0.9]
As far as I understand, there is no option to let spines end in an arrow head, 
so I have to draw the myself. I get the ticks to appear at the right positions 
and the y-range to be as desired - however, the spine line is not drawn over 
the full y-range, but only where there is data in the diagram. Also, I copied 
the arrow annotation code blindly from an older post on this list, but do not 
understand how I can adapt the arrow head to appear at a data position (instead 
of at the corner of the Axes area). One problem is, that I get ticks on the 
right although that spine was disabled.

2) I want some kind of x-axis at y==0, without ticks and without arrow
Using some methods on the spines, I can disable the top spine and move the 
bottom spine to zero. However, as with the y-axis, I cannot control from where 
to where the line itself is drawn.

As attachments, you'll find a hand sketch of what my graph should look like and 
matplotlib code that goes nearly all the way.

I would be very happy about a hint on how to fix the problems left.

Thanks an advance,
Mark

[cid:ed2f1b56-2e4e-4cb3-9a9e-4b2b2388781b@exch.iais.fraunhofer.de]

<<inline: boxplot_sketch.png>>

#! /usr/bin/env python

"""Example code for custom box diagram

2012-06-15, mark.asb...@iais.fraunhofer.de
"""

import numpy
from matplotlib import pylab


def draw_bars(data, descriptions=None, colors=None, reverse_coords=False, position=0, axes=pylab):
    
    # if no descriptions are given, use data to annotate itself
    if descriptions == None:
        descriptions = data
    
    # if no colors are given, all boxes will be white
    if colors == None:
        colors = len(data) * ('white',)
    
    # sort data for finding y centers and drawing in right order
    assert numpy.all(numpy.array(data) >= 0)
    idx = numpy.argsort(data)[::-1]
    data         = numpy.array(data)[idx]
    descriptions = numpy.array(descriptions)[idx]
    colors       = numpy.array(colors)[idx]
    
    # reverse y-position if desired
    if reverse_coords:
        data = -data
    
    # draw boxes
    for top, color in zip (data, colors):
        axes.bar (position + 0.2, top, 0.4, color=color)
    
    # put labels on boxes
    tops = data.tolist()
    bots = data.tolist()[1:] + [0,]
    for top, bottom, description in zip(tops, bots, descriptions):
        axes.text (position + 0.4, 0.5 * (top + bottom), description, 
                   horizontalalignment='center', verticalalignment='center')


def draw_dataset(dataset, titles=None, descriptions=None, colors=None, axes=pylab):
    
    # ensure data is in numpy format
    dataset = numpy.require(dataset, dtype=float)
    titles  = numpy.require(titles, dtype=str)
    descriptions = numpy.require(descriptions, dtype=str)
    
    # draw bar by bar, separating positive from negative values
    position = 0
    for row, descr in zip(dataset, descriptions):
        row_data   = numpy.array(row)
        descr_data = numpy.array (descr)
        positives  = numpy.array(row) > 0
        draw_bars( row_data[ positives], descr_data[ positives], colors, False, position, axes)
        draw_bars(-row_data[-positives], descr_data[-positives], colors, True,  position, axes)
        position += 1
    
    # finally, but title above bars
    if titles != None:
        for position, title in enumerate(titles):
            axes.text (position + 0.4, 1.1, title, 
                       horizontalalignment='center', verticalalignment='center')


# create new figure
fig = pylab.figure()
ax = fig.add_subplot(1,1,1)

# plot my data
datasets = [(0.8, 0.6, 0.4, -0.2),
            (0.7, 0.5, 0.3, -0.3)]
descriptions = [('A', 'B', 'C', 'D'),
                ('A\'', 'B\'', 'C\'', 'D\'')]
colors    = ['0.3', '0.5', '0.75', '0.1']
draw_dataset(datasets, ['Some Text\nLines', 'Other Text'], descriptions, colors, ax)

# use left spine and x-axis at zero
ax.spines['left'].set_position('zero')
ax.spines['left'].set_smart_bounds(True)
ax.spines['bottom'].set_position('zero')
ax.spines['bottom'].set_smart_bounds(True)
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')

# try to add arrow to left spine
# (http://www.mailinglistarchive.com/html/matplotlib-users@lists.sourceforge.net/2011-02/msg00065.html)
al = 7 # arrow length in points
arrowprops=dict(clip_on=False, # plotting outside axes on purpose
  frac=1., # make end arrowhead the whole size of arrow
  headwidth=al, # in points
  facecolor='k')
kwargs = dict(  
              xycoords='axes fraction',
              textcoords='offset points',
              arrowprops= arrowprops,
           )
ax.annotate("",(0,1),xytext=(0,-al), **kwargs) # left spin arrow

# format rest of figure
pylab.ylabel('Rate')
pylab.yticks(numpy.arange(0.0, 1.1, 0.1)) #, ['%d' % val for val in vals])
pylab.xticks([])
ax.set_ylim(-0.6, 1.4)
ax.set_xlim( 0.0, 2.0)
ax.set_aspect('equal')
pylab.title('Diagram Title')

# done
pylab.show()

------------------------------------------------------------------------------
Live Security Virtual Conference
Exclusive live event will cover all the ways today's security and 
threat landscape has changed and how IT managers can respond. Discussions 
will include endpoint security, mobile security and the latest in malware 
threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/
_______________________________________________
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-users

Reply via email to