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® 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