score:1

Accepted answer

added a refresh button next to chart which adjust the data labels. below is the code behind the button.

 sub movelabels()

    dim sh as worksheet
    dim ch as chart
    dim sers as seriescollection
    dim ser as series
    dim i as long, pt as long
    dim dlabels() as datalabel

    set sh = activesheet
    set ch = sh.chartobjects("chart 1").chart
    set sers = ch.seriescollection

    redim dlabels(1 to sers.count)
    for pt = 1 to sers(1).points.count
        for i = 1 to sers.count
            set dlabels(i) = sers(i).points(pt).datalabel
        next

        resetlabels dlabels
        adjustlabels dlabels  ' this sub is to deal with the overlaps
    next
end sub


private sub adjustlabels(byref v() as datalabel)

    application.screenupdating = false

    dim i as long, j as long, adj as long
    dim temp_a as string, temp_b as string

    for i = lbound(v) to ubound(v) - 1
    for j = lbound(v) + 1 to ubound(v)

        temp_a = v(i).caption
        temp_b = v(j).caption

        debug.print temp_a & " - | - " & temp_b


        v(i).caption = "a"
        v(j).caption = iif(temp_a = temp_b, "a", "b")
        activesheet.chartobjects("chart 1").activate


        if ((v(j).top = v(i).top) and (v(i).caption <> v(j).caption) and (v(j).left = v(i).left)) then

            select case v(j).position
            case xllabelpositionabove
                    v(j).position = xllabelpositionright
            case xllabelpositionright
                    v(j).position = xllabelpositionbelow
            case xllabelpositionbelow
                    v(j).position = xllabelpositionleft
            case xllabelpositionleft
                    v(j).position = xllabelpositionabove
            end select

        end if


        v(i).caption = temp_a
        v(j).caption = temp_b

       temp_a = vbnullstring
       temp_b = vbnullstring


    next j, i

     application.screenupdating = true

end sub



sub resetlabels(byref v() as datalabel)

    for i = lbound(v) to ubound(v) - 1
        v(i).position = xllabelpositionabove
    next

end sub

score:1

you can:

  1. select a single data label. click on any data label, and it will select the set of data labels. click again on any data label of that set, and it will select that specific label. or click on any object in the chart, and use the left/right arrows to change the selection, until you have selected the label of interest.*
  2. move it. click and drag.

see https://stackoverflow.com/a/27813339/2707864 (related).

for an automated work, i suggest you get the awesome xy chart labeler and use it as a basis for your vba code. the required code will not be short. i give you here a schematics:

  1. detect whether there would be an overlap (you have to check not only for exact coincidence-complete overlap-, but within some x-y box-partial overlap-). you might need to detect multiple complete/partial overlaps. under some circumstances (perhaps unlikely for you), this might be quite complex. in an extreme case, all data points may form a chain of partial overlaps.
  2. decide on an algorithm for moving labels, depending on the detected cases above.
  3. use the code in xy chart labeler to perform the move.

* it is quite instructive to see how this works, sometimes you would be able to select an object that would be otherwise difficult/impossible to select with the mouse.


Related Query

More Query from same tag