I tried to put some code to check overlapping texts.
The code runs, but I'm not sure if the code is correct. Texts still
overlap but I haven't checked if this is due to the incorrect code or
the input.
But I believe it gives you enough idea how to fix things.

You have several hundreds of candidate points for a few cases. No
doubt it takes so long.

Regards,

-JJ

On Mon, Mar 1, 2010 at 6:07 AM, Andrea Gavana <andrea.gav...@gmail.com> wrote:
> Hi Jae-Joon & All,
>
> On 28 February 2010 03:09, Jae-Joon Lee wrote:
>> If I read your correctly,
>>
>>       for l, b in zip(x, y):
>>
>>          # And here  I work with data coordinates (!)
>>
>>           dashBox = Bbox.from_bounds(l, b, width+5, height+5)
>>           badness = 0
>>           for line in lines:
>>               if line.intersects_bbox(dashBox):
>>                   badness += 1
>>
>> x, y (therefore l, b) in data coordinate.
>> width, height?? this seems to be some wx specific coordinate, i have no idea.
>> lines (therefore line)  in display coordinate.
>>
>> converting x,y to display coordinate should straight forward. But I'm
>> not sure what kind of coordinate width and height has. Is it a method
>> of some class derived from matplotlib's Text?? If then, the extent of
>> the text can be measured using the get_window_extent method. This
>> requires a renderer instance, which should be known if the method is
>> called during the drawing time.
>>
>> Again, post a complete but simple(!) code.
>
> OK, I think I got a complete code. Not super-simple, but simple enough
> I believe. After you run it you'll see a bunch of points and lines
> with some text. If you left-click inside the axis this will start the
> calculations for the "optimal positioning". There are a couple of
> problems:
>
> 1) The code I have looks only for optimal positioning with respect to
> lines in the plot, it doesn't include texts (I don't know how to do
> it); You'll see what I mean if you run the code, the "optimally"
> positioned texts overlap with other text in the plot, and with
> themselves too (i.e., one "optimally" positioned text overlap with
> another "optimally" positioned text);
> 2) The code as it stands it's veeeeery slow. On my (relatively fast)
> computer, it takes almost 6 seconds to "optimally" position 14 labels.
>
> In order to run the code, you'll also need the "lines.txt" file, which
> contains the main lines coordinates. Sorry about this extra file but I
> wanted it to be as close as possible to my use-case.
>
> Thank you in advance for your suggestions.
>
> Andrea.
>
> "Imagination Is The Only Weapon In The War Against Reality."
> http://xoomer.alice.it/infinity77/
> http://thedoomedcity.blogspot.com/
>
import wx
import numpy
import matplotlib
import time

matplotlib.use("WXAGG")

from matplotlib.transforms import Bbox
from matplotlib.pyplot import figure, show

from matplotlib.pyplot import rcParams
rcParams["text.usetex"]=False

x = [71, 75, 56, 61, 42, 73, 89, 17, 70, 89, 26.2, 77, 82, 80, 53, 47,
     54, 46, 84, 29, 26, 89, 50, 71, 62, 69, 75, 76, 66, 70, 71, 85, 60]
y = [42, 31, 42, 43, 34, 31, 13, 39, 58, 47, 42.5, 39, 25, 12, 34, 46,
     13, 17.7, 59, 26, 33, 57, 40, 22, 47, 40, 45, 17, 55, 51, 63, 24, 16.5]

pointNames = ["Point_%d"%indx for indx in xrange(1, len(x)+1)]

fid = open("lines.txt", "rt")
xLines = eval(fid.readline().strip())
yLines = eval(fid.readline().strip())
fid.close()

lineNames = ["Line_%d"%indx for indx in xrange(1, len(xLines)+1)]

lineText = "MODEL 1: %0.6g\nMODEL 2: %0.6g"
multValues = numpy.random.random((len(x), 2))


def button_press_callback(event):

    if event.inaxes is not None:
        start = time.clock()
        ax = event.inaxes
        position_labels(ax)
        print "\nElapsed Time:", time.clock() - start
        ax.get_figure().canvas.mpl_disconnect('button_press_event')
    

def position_labels(ax):

    renderer = ax.figure._cachedRenderer

    inv = ax.transData.inverted()
    count = 0

    lines_in_displaycoord = []
    textbbox_in_displaycoord = []
    
    
    for handle in ax.lines:
        path = handle.get_path()
        trans = handle.get_transform()
        tpath = trans.transform_path(path)
        lines_in_displaycoord.append(tpath)


    for xl, yl in zip(xLines, yLines):
        name = lineText%(multValues[count][0], multValues[count][1])

        txt = ax.text(xl[0], yl[0], name, fontsize=8, withdash=True, dashdirection=1,
                      dashlength=10, rotation=0, dashrotation=90, dashpush=10)
        txt.set_backgroundcolor((1, 1, 1))
        txt.set_multialignment("left")

        ox, oy = position_annotation(renderer, ax, name, txt, xl, yl,
                                     lines_in_displaycoord,
                                     textbbox_in_displaycoord)
        txt.set_position((ox, oy))
        textbbox_in_displaycoord.append(txt.get_window_extent(renderer))
        count += 1

    ax.get_figure().canvas.draw()


def position_annotation(renderer, ax, name, txt, xl, yl,
                        lines_in_displaycoord, textbbox_in_displaycoord):


    candidates = []

    for l, b in zip(xl, yl):
        txt.set_position((l, b))
        dashBox = txt.get_window_extent(renderer)
        badness1 = len([1 for line in lines_in_displaycoord if line.intersects_bbox(dashBox)])
        badness2 = dashBox.count_overlaps(textbbox_in_displaycoord)
        badness = badness1 + badness2

        if badness == 0:
            return l, b

        candidates.append(((badness, badness2, badness1), (l, b)))


    # rather than use min() or list.sort(), do this so that we are assured
    # that in the case of two equal badnesses, the one first considered is
    # returned.
    # NOTE: list.sort() is stable.But leave as it is for now. -JJL
    candidates.sort()
    ox, oy = candidates[0][1]
    total_badness, overlapping_bbox, line_badness =  candidates[0][0]

    print "overlapping bbxo = %d, line badness=%d" % (overlapping_bbox, line_badness)
    return ox, oy


def main():

    fig = figure(figsize=(13, 10))
    ax = fig.add_axes([0.05, 0.05, 0.9, 0.9])

    for i in xrange(len(x)):
        ax.plot([x[i]], [y[i]], color="k", linestyle="None", marker=".", ms=16, zorder=10)
        ax.text(x[i]+0.5, y[i]+1, pointNames[i], color="k", fontsize=9,
                va="center", ha="center", zorder=10)

    count = 0
    for xl, yl in zip(xLines, yLines):
        ax.plot(xl, yl, color="r", zorder=6)
        ax.text(xl[0]+0.2, yl[0]+0.2, lineNames[count], color="r", fontsize=7,
                va="bottom", ha="center", zorder=5)
        ax.text(xl[-1]+0.2, yl[-1]+0.2, lineNames[count], color="r", fontsize=7,
                va="bottom", ha="center", zorder=5)
        count += 1

    minX, maxX = ax.get_xlim()
    minY, maxY = ax.get_ylim()

    ax.set_xlim([minX-2, maxX+2])
    ax.set_ylim([minY-2, maxY+2])

    ax.invert_yaxis()

    fig.canvas.mpl_connect('button_press_event', button_press_callback)

    show()


if __name__ == "__main__":
    main()

    

------------------------------------------------------------------------------
Download Intel&#174; Parallel Studio Eval
Try the new software tools for yourself. Speed compiling, find bugs
proactively, and fine-tune applications for parallel performance.
See why Intel Parallel Studio got high marks during beta.
http://p.sf.net/sfu/intel-sw-dev
_______________________________________________
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-users

Reply via email to