Changeset 1456:3ce497e10d7d in orange-bioinformatics


Ignore:
Timestamp:
07/13/11 13:11:05 (3 years ago)
Author:
ales_erjavec <ales.erjavec@…>
Branch:
default
Convert:
95c0f36a30e6c43f89aefb56b005dcccc81746dd
Message:

Added axis labels.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • widgets/prototypes/OWDifferentiationScale.py

    r1454 r1456  
    55import os, sys 
    66import numpy 
     7import random 
    78 
    89import obiDifscale 
     
    256257            self.scene.addItem(title) 
    257258             
    258             for center, (label, _) in zip(centers, self.time_samples): 
     259            rects = [] 
     260            ticks = [] 
     261            axis_label_items = [] 
     262            labels = [(center, label) for center, (label, _) in zip(centers, self.time_samples)] 
     263            labels = sorted(labels, key=lambda (c, l): c[0]) 
     264            for center, label in labels: 
    259265                x, y = center 
     266                item = QGraphicsSimpleTextItem(label) 
     267                w = item.boundingRect().width() 
     268                item.setPos(x - w / 2.0, 4.0) 
     269                rects.append(item.sceneBoundingRect().normalized()) 
     270                ticks.append(QPointF(x - w / 2.0, 4.0)) 
     271                axis_label_items.append(item) 
     272             
     273#            rects = SA_axis_label_layout(ticks, rects, max_time=0.5, 
     274#                                         x_factor=scene_size_hint.width() / 50.0, 
     275#                                         y_factor=10, 
     276#                                         random=random.Random(0)) 
     277 
     278            rects = greedy_scale_label_layout(ticks, rects, spacing=5) 
     279             
     280            for (tick, label), rect, item in zip(labels, rects, axis_label_items): 
     281                x, y = tick 
    260282                self.scene.addLine(x, -2, x, 2) 
    261                 text = QGraphicsSimpleTextItem(label) 
    262                 w = text.boundingRect().width() 
    263                 text.setPos(x - w / 2.0, 4) 
     283                if rect.top() - item.pos().y() > 5: 
     284                    self.scene.addLine(x, 2, rect.center().x(), 14.0) 
     285                if rect.top() - item.pos().y() > 15: 
     286                    self.scene.addLine(rect.center().x(), 14.0, rect.center().x(), rect.top()) 
     287#                item.setPos(rect.topLeft()) 
     288                 
     289#                text = QGraphicsSimpleTextItem(label) 
     290#            for tick, rect, item in zip(ticks, rects, axis_label_items): 
     291                item.setPos(rect.topLeft()) 
     292                self.scene.addItem(item) 
     293#                w = text.boundingRect().width() 
     294#                text.setPos(x - w / 2.0, 4) 
    264295                # Need to compute axis label layout. 
    265296#                self.scene.addItem(text) 
     
    288319        print self.selected_time_samples 
    289320        self.commit_if() 
    290                  
    291321             
    292322    def commit_if(self): 
     
    393423         
    394424    return list(groups.items()) 
    395      
     425 
     426     
     427def greedy_scale_label_layout(ticks, rects, spacing=3): 
     428    """ Layout the labels at ticks on a linear scale, by raising the 
     429    overlapping labels. 
     430     
     431    """ 
     432    def adjust_interval(start, end, min_v, max_v): 
     433        """ Adjust (start, end) interval to fit inside the (min_v, max_v). 
     434        """ 
     435        if start < min_v: 
     436            return (min_v, min_v + (end - start)) 
     437        elif max_v > end: 
     438            return (max_v - (end - start), max_v) 
     439        else: 
     440            return (start, end) 
     441         
     442    def center_interval(start, end, center): 
     443        """ Center the interval on `center` 
     444        """ 
     445        span = end - start 
     446        return centered(center, span) 
     447     
     448    def centered(center, span): 
     449        """ Return an centered interval with span. 
     450        """ 
     451        return (center - span / 2.0, center + span / 2.0) 
     452     
     453    def contains((start, end), (start1, end1)): 
     454        return start <= start1  and end >= end1 
     455     
     456    def fit(work, ticks, min_x, max_x): 
     457        """ Fit the work set between min_x and max_x  and centered on the 
     458        ticks, if possible. 
     459        """ 
     460        fits = False 
     461        work_set = map(QRectF, work) 
     462        tick_center = sum([r.center().x() for r in work_set]) / len(work_set) 
     463        if len(work_set) == 1: 
     464            if work_set[0].left() >= min_x and work_set[0].right() <= max_x: 
     465                return work_set 
     466            else: 
     467                return [] 
     468         
     469        elif len(work_set) == 2: # TODO: MErge this with the > 2 
     470            w_sum = sum([r.width() for r in work_set]) + spacing 
     471            if w_sum < max_x - min_x: 
     472                r1, r2 = work_set 
     473                interval = centered(tick_center, w_sum) 
     474                 
     475                if not contains((min_x, max_x), interval): 
     476                    interval = adjust_interval(*(interval + (min_x, max_x))) 
     477                     
     478                if contains((min_x, max_x), interval): 
     479                    r1.moveLeft(interval[0]) 
     480                    r2.moveLeft(interval[1] - r2.width()) 
     481                    r1.moveTop(r1.top() + 10) 
     482                    r2.moveTop(r2.top() + 10) 
     483                    return work_set 
     484                else: 
     485                    return [] 
     486            else: 
     487                return [] 
     488         
     489        elif len(work_set) > 2: 
     490            center = (work_set[0].center().x() + work_set[-1].center().x()) / 2.0 
     491            w_sum = work_set[0].width() / 2.0 + work_set[-1].width() / 2.0 + spacing 
     492            for i, r in enumerate(work_set[1:-1]): 
     493                w_sum += r.width() + spacing 
     494            interval = centered(center, w_sum) 
     495             
     496            if not contains((min_x, max_x), interval): 
     497                interval = adjust_interval(*(interval + (min_x, max_x))) 
     498                 
     499            if contains((min_x, max_x), interval): 
     500                istart, iend = interval 
     501                rstart, rend = work_set[0], work_set[-1] 
     502                rstart.moveLeft(istart) 
     503                rstart.moveTop(rstart.top() + 10) 
     504                rend.moveLeft(iend - rend.width()) 
     505                rend.moveTop(rend.top() + 10) 
     506                istart += rstart.width() / 2.0 
     507                iend -= rend.width() / 2.0 
     508                for r in work_set[1: -1]: 
     509                    r.moveLeft(istart) 
     510                    r.moveTop(r.top() + 20) 
     511                    istart += r.width() + spacing 
     512                return work_set 
     513            else: 
     514                return [] 
     515             
     516    queue = sorted(zip(ticks, rects), 
     517                   key=lambda (t, _): t.x(), 
     518                   reverse=True) 
     519    done = False 
     520    rects = [] 
     521     
     522    min_x = -1e30 
     523    max_x = 1e30 
     524     
     525    while queue: 
     526        work_set = [queue.pop(-1)] 
     527        set_fits = False 
     528        max_x = queue[-1][1].left() if queue else 1e30 
     529        while not set_fits: 
     530            new_rects = fit(map(itemgetter(1), work_set), 
     531                            map(itemgetter(0), work_set), 
     532                            min_x, max_x) 
     533            if new_rects: # Can the work set be fit. 
     534                set_fits = True 
     535                rects.extend(new_rects) 
     536                min_x = work_set[-1][1].right() 
     537                 
     538            else: 
     539                # Extend the work set with one more label rect 
     540                work_set.append(queue.pop(-1)) 
     541                max_x = queue[-1][1].left() if queue else 1e30 
     542    return rects 
    396543         
    397544     
Note: See TracChangeset for help on using the changeset viewer.