Ejemplo n.º 1
0
def draw_text(ax, x, y, text, scale=0.1, **kwargs):
    fs = kwargs.get("fontsize", 2) * scale * 0.75
    t_path = TextPath((x - 0.1, y), s=text, size=fs)
    center = centroid(t_path)
    dist = -1 * (center - (x, y))
    t_path_shifted = t_path.transformed(Affine2D().translate(*dist))
    patch = patches.PathPatch(t_path_shifted, facecolor="black", lw=line_weight / 20., zorder=4)
    a = ax.add_patch(patch)
    return a
Ejemplo n.º 2
0
def add_bar_labels(fig, ax, bars, bottom=0):
    transOffset = offset_copy(ax.transData, fig=fig,
                              x=0., y= -2., units='points')
    transOffsetUp = offset_copy(ax.transData, fig=fig,
                              x=0., y=1., units='points')
    for bar in bars:
        for i, [patch, num] in enumerate(zip(bar.patches, np.arange(len(bar.patches)))):
            if len(bottom) == len(bar): b = bottom[i]
            else: b = bottom
            height = patch.get_height() + b
            xi = patch.get_x() + patch.get_width() / 2.
            va = 'top'
            c = 'w'
            t = TextPath((0, 0), "${xi}$".format(xi=xi), rotation=0, ha='center')
            transform = transOffset
            if patch.get_extents().height <= t.get_extents().height + 5:
                va = 'bottom'
                c = 'k'
                transform = transOffsetUp
            ax.text(xi, height, "${xi}$".format(xi=int(num)), color=c, rotation=0, ha='center', va=va, transform=transform)

    ax.set_xticks([])
Ejemplo n.º 3
0
 def formatDateAxis(self,ax):
     """Formatuje etykiety osi czasu."""
     chartWidth=int(self.fig.get_figwidth()*self.fig.get_dpi()*self.maxSize)        
     t = TextPath((0,0), '9999-99-99', size=7)
     labelWidth = int(t.get_extents().width)    
     num_ticks=chartWidth/labelWidth/2          
     length=len(self.data.date)
     if(length>num_ticks):
         step=length/num_ticks        
     else:
         step=1
     x=range(0,length,step)
     ax.xaxis.set_major_locator(FixedLocator(x))
     ticks=ax.get_xticks()        
     labels=[]        
     for i, label in enumerate(ax.get_xticklabels()):
         label.set_size(7)                       
         index=int(ticks[i])            
         if(index>=len(self.data.date)):
             labels.append('')
         else:
             labels.append(self.data.date[index].strftime("%Y-%m-%d"))            
         label.set_horizontalalignment('center')                                    
     ax.xaxis.set_major_formatter(FixedFormatter(labels))        
 def draw_protein_main_sequence(self, current_position):
     next_row = current_position + self.row_width
     transform = self._make_text_scaler()
     for i, aa in enumerate(self.protein.protein_sequence[current_position:next_row]):
         color = self.n_glycosite_bar_color if (i + current_position) in self.glycosites\
             else self.default_protein_bar_color
         rect = mpatches.Rectangle(
             (self.protein_pad + i, self.layer_height + .05 + self.cur_y),
             width=self.sequence_font_size / 4.5,
             height=self.sequence_font_size / 30.,
             facecolor=color)
         self.ax.add_patch(rect)
         if i % 100 == 0 and i != 0:
             xy = np.array((self.protein_pad + i, self.layer_height + .35 + self.cur_y))
             text_path = TextPath(
                 xy,
                 str(current_position + i), size=self.sequence_font_size / 7.5,
                 prop=font_options)
             text_path = text_path.transformed(transform)
             new_center = transform.transform(xy)
             delta = xy - new_center - (1, 0)
             text_path = text_path.transformed(Affine2D().translate(*delta))
             patch = mpatches.PathPatch(text_path, facecolor='grey', lw=0.04)
             self.ax.add_patch(patch)
Ejemplo n.º 5
0
def _str_to_paths(s: str, fp: FontProperties, size: float = 1.0) -> List[Path]:
    text_path = TextPath((0, 0), s, size=size, prop=fp, usetex=False)
    return list(path.from_matplotlib_path(text_path))
Ejemplo n.º 6
0
def draw_envelope_subgraph(envelopes,
                           scale_factor=1.0,
                           overlap_fn=peak_overlap,
                           ax=None,
                           **kwargs):
    layers = layout_layers(envelopes)
    max_score = max(e.score for e in envelopes)
    peaks = set()

    for e in envelopes:
        peaks.update(e.fit.experimental)

    peaks = sorted(peaks, key=lambda x: x.mz)
    peaks = [p.clone() for p in peaks]
    total_intensity = sum(p.intensity for p in peaks)

    start = peaks[0].mz
    end = peaks[-1].mz

    if ax is None:
        figure, ax = plt.subplots(1, 1)

    row_width = float('inf')
    annotation_text_size = 3. * scale_factor
    layer_height = 0.56 * scale_factor
    y_step = (layer_height + 0.05) * -scale_factor
    origin_y = cur_y = -layer_height - 0.075

    cur_position = peaks[0].mz

    for layer in layers:
        layer.sort(key=lambda x: x.start)

    while cur_position < end:
        next_row = cur_position + row_width

        for layer in layers:
            c = 0
            for envelope in layer:
                if envelope.start < cur_position:
                    continue
                elif envelope.start > next_row:
                    break
                c += 1
                rect = mpatches.Rectangle(
                    (envelope.start - 0.01, cur_y),
                    width=0.01 + envelope.end - envelope.start,
                    height=layer_height,
                    facecolor='lightblue',
                    edgecolor='black',
                    linewidth=0.15,
                    alpha=min(max(envelope.score / max_score, 0.2), 0.8))
                ax.add_patch(rect)
                text_path = TextPath(
                    (envelope.start + 0.1, cur_y + 0.2),
                    "%0.2f, %d" % (envelope.score, envelope.fit.charge),
                    size=annotation_text_size / 14.5,
                    prop=font_options,
                    stretch=200)
                patch = mpatches.PathPatch(text_path,
                                           facecolor='grey',
                                           lw=0.04)
                ax.add_patch(patch)

            if c > 0:
                cur_y += y_step
        cur_y += y_step / 5
        cur_position = next_row

    for p in peaks:
        p.intensity = (p.intensity / total_intensity) * abs(origin_y -
                                                            cur_y) * 8

    draw_peaklist(peaks, ax=ax)

    ax.set_ylim(cur_y, max(p.intensity for p in peaks) + 0.2)
    ax.set_xlim(start - 0.2, end + 0.2)
    ax.axes.get_yaxis().set_visible(False)
    return ax
Ejemplo n.º 7
0
    def plot_ARD(self, fignum=None, ax=None, title='', legend=False):
        """If an ARD kernel is present, plot a bar representation using matplotlib

        :param fignum: figure number of the plot
        :param ax: matplotlib axis to plot on
        :param title:
            title of the plot,
            pass '' to not print a title
            pass None for a generic title
        """
        if ax is None:
            fig = pb.figure(fignum)
            ax = fig.add_subplot(111)
        else:
            fig = ax.figure
        from GPy.util import Tango
        from matplotlib.textpath import TextPath
        Tango.reset()
        xticklabels = []
        bars = []
        x0 = 0
        for p in self.parts:
            c = Tango.nextMedium()
            if hasattr(p, 'ARD') and p.ARD:
                if title is None:
                    ax.set_title('ARD parameters, %s kernel' % p.name)
                else:
                    ax.set_title(title)
                if p.name == 'linear':
                    ard_params = p.variances
                else:
                    ard_params = 1. / p.lengthscale

                x = np.arange(x0, x0 + len(ard_params))
                bars.append(
                    ax.bar(x,
                           ard_params,
                           align='center',
                           color=c,
                           edgecolor='k',
                           linewidth=1.2,
                           label=p.name))
                xticklabels.extend([
                    r"$\mathrm{{{name}}}\ {x}$".format(name=p.name, x=i)
                    for i in np.arange(len(ard_params))
                ])
                x0 += len(ard_params)
        x = np.arange(x0)
        transOffset = offset_copy(ax.transData,
                                  fig=fig,
                                  x=0.,
                                  y=-2.,
                                  units='points')
        transOffsetUp = offset_copy(ax.transData,
                                    fig=fig,
                                    x=0.,
                                    y=1.,
                                    units='points')
        for bar in bars:
            for patch, num in zip(bar.patches, np.arange(len(bar.patches))):
                height = patch.get_height()
                xi = patch.get_x() + patch.get_width() / 2.
                va = 'top'
                c = 'w'
                t = TextPath((0, 0),
                             "${xi}$".format(xi=xi),
                             rotation=0,
                             ha='center')
                transform = transOffset
                if patch.get_extents().height <= t.get_extents().height + 3:
                    va = 'bottom'
                    c = 'k'
                    transform = transOffsetUp
                ax.text(xi,
                        height,
                        "${xi}$".format(xi=int(num)),
                        color=c,
                        rotation=0,
                        ha='center',
                        va=va,
                        transform=transform)
        # for xi, t in zip(x, xticklabels):
        #    ax.text(xi, maxi / 2, t, rotation=90, ha='center', va='center')
        # ax.set_xticklabels(xticklabels, rotation=17)
        ax.set_xticks([])
        ax.set_xlim(-.5, x0 - .5)
        if legend:
            if title is '':
                mode = 'expand'
                if len(bars) > 1:
                    mode = 'expand'
                ax.legend(bbox_to_anchor=(0., 1.02, 1., 1.02),
                          loc=3,
                          ncol=len(bars),
                          mode=mode,
                          borderaxespad=0.)
                fig.tight_layout(rect=(0, 0, 1, .9))
            else:
                ax.legend()
        return ax
Ejemplo n.º 8
0
 def to_mpath(self, text: str):
     return TextPath((0, 0), text, size=1, prop=self.fp, usetex=False)
Ejemplo n.º 9
0
from matplotlib.textpath import TextPath
from matplotlib.font_manager import FontProperties

fp = FontProperties(fname="行楷-简 细体.ttf")
size = 1000

text = "计算几何 2021"
path1 = TextPath((size, size), text, size, prop=fp)

text = "Computational Geometry"
path2 = TextPath((0, 0), text, size, prop=fp)

points = set()
with open("text/poly_all.pts", "w") as f1:
    n = 0
    for path in [path1, path2]:
        print(len(path.to_polygons()))
        for poly in path.to_polygons():
            with open("text/poly%d.pts" % n, "w") as f2:
                for p in poly:
                    p = (p[0], p[1])
                    if not p in points:
                        points.add(p)
                        f1.write("%f %f\n" % (p[0], p[1]))
                        f2.write("%f %f\n" % (p[0], p[1]))
            f1.write("\n")
            n += 1
Ejemplo n.º 10
0
def build_cloud(wordweights, 
        loose=False, seed=None, split_limit=2**-3, pad=1.10, visual_limit=2**-5,
        highest_weight=None ):
    """Convert a list of words and weights into a list of paths and weights.

    You should only use this function if you know what you're doing, or if
    you really don't want to cache the generated paths.  Otherwise just use
    the WordCloud class.

    Args:
        wordweights: An iterator of the form 
                [ (word, weight), (word, weight), ... ]
            such that the weights are in decreasing order.
        loose: If `true', words won't be broken up into rectangles after
            insertion.  This results in a looser cloud, generated faster.
        seed: A random seed to use
        split_limit: When words are approximated by rectangles, the rectangles
            will have dimensions less than split_limit.  Higher values result
            in a tighter cloud, at a cost of more CPU time.  The largest word
            has height 1.0.
        pad: Expand a word's bounding box by a factor of `pad' before
            inserting it.  This can actually result in a tighter cloud if you
            have many small words by leaving space between large words.
        visual_limit: Words with height smaller than visual_limit will be
            discarded.
        highest_weight: Experimental feature.  If you provide an upper bound
            on the weights that will be seen you don't have to provide words
            and weights sorted.  The resulting word cloud will be noticeably
            uglier.

    Generates:
        Tuples of the form (path, weight) such that:
            * No two paths intersect
            * Paths are fairly densely packed around the origin
            * All weights are normalized to fall in the interval [0, 1]
    """
    if seed is not None:
        random.seed(seed)

    font_properties = font_manager.FontProperties(
                family="sans", weight="bold", stretch="condensed")
    xheight = TextPath((0,0), "x", prop=font_properties).get_extents().expanded(pad,pad).height

    # These are magic numbers.  Most wordclouds will not exceed these bounds.
    # If they do, it will have to re-index all of the bounding boxes.
    index_bounds = (-16, -16, 16, 16)
    index = BboxQuadtree(index_bounds)

    if highest_weight is None:
        # Attempt to pull the first word and weight.  If we fail, the wordweights
        # list is empty and we should just quit.
        #
        # All this nonsense is to ensure it accepts an iterator of words
        # correctly.
        iterwords = iter(wordweights)
        try:
            first_word, first_weight = iterwords.next()
            iterwords = chain([(first_word, first_weight)], iterwords)
        except StopIteration:
            return

        # We'll scale all of the weights down by this much.
        weight_scale = 1.0/first_weight
    else:
        weight_scale = 1.0/highest_weight
        iterwords = iter(wordweights)

    bboxes = list()

    bounds = transforms.Bbox(((-0.5, -0.5), (-0.5, -0.5)))
    for tword, tweight in iterwords:
        weight = tweight*weight_scale
        if weight < visual_limit:
            # You're not going to be able to see the word anyway.  Quit
            # rendering words now.
            continue

        word_path = TextPath((0,0), tword, prop=font_properties)
        word_bbox = word_path.get_extents().expanded(pad, pad)
        # word_scale = weight/float(word_bbox.height)
        word_scale = weight/float(xheight)
        
        # When we build a TextPath at (0,0) it doesn't necessarily have
        # its corner at (0,0).  So we have to translate to the origin,
        # scale down, then translate to center it.  Feel free to simplify
        # this if you want.
        word_trans = Affine2D.identity().translate(
                                -word_bbox.xmin,
                                -word_bbox.ymin
                            ).scale(word_scale).translate(
                                -0.5*abs(word_bbox.width)*word_scale,
                                -0.5*abs(word_bbox.height)*word_scale )

        word_path = word_path.transformed(word_trans)

        word_bbox = word_path.get_extents().expanded(pad, pad)

        if weight > split_limit:
            # Big words we place carefully, trying to make the dimensions of
            # the cloud equal and center it around the origin.
            gaps = ( 
                    ("left", bounds.xmin), ("bottom", bounds.ymin), 
                    ("right", bounds.xmax), ("top", bounds.ymax) )
            direction = min(gaps, key=lambda g: abs(g[1]))[0]
        else:
            # Small words we place randomly.
            direction = random.choice( [ "left", "bottom", "right", "top" ] )

        # Randomly place the word along an edge...
        if direction in ( "top", "bottom" ):
            center = random_position(bounds.xmin, bounds.xmax)
        elif direction in ( "right", "left" ):
            center = random_position(bounds.ymin, bounds.ymax)

        # And push it toward an axis.
        if direction == "top":
            bbox = word_bbox.translated( center, index_bounds[3] )
            xpos, ypos = push_bbox_down( bbox, bboxes, index )
        elif direction == "right":
            bbox = word_bbox.translated( index_bounds[2], center )
            xpos, ypos = push_bbox_left( bbox, bboxes, index )
        elif direction == "bottom":
            bbox = word_bbox.translated( center, index_bounds[1] )
            xpos, ypos = push_bbox_up( bbox, bboxes, index )
        elif direction == "left":
            bbox = word_bbox.translated( index_bounds[0], center )
            xpos, ypos = push_bbox_right( bbox, bboxes, index )
    
        # Now alternate pushing the word toward different axes until either
        # it stops movign or we get sick of it.
        max_moves = 2
        moves = 0
        while moves < max_moves and (moves == 0 or prev_xpos != xpos or prev_ypos != ypos):
            moves += 1
            prev_xpos = xpos
            prev_ypos = ypos
            if direction in ["top", "bottom", "vertical"]:
                if xpos > 0:
                    bbox = word_bbox.translated( xpos, ypos )
                    xpos, ypos = push_bbox_left( bbox, bboxes, index )
                elif xpos < 0:
                    bbox = word_bbox.translated( xpos, ypos )
                    xpos, ypos = push_bbox_right( bbox, bboxes, index )
                direction = "horizontal"
            elif direction in ["left", "right", "horizontal"]:
                if ypos > 0:
                    bbox = word_bbox.translated( xpos, ypos )
                    xpos, ypos = push_bbox_down( bbox, bboxes, index )
                elif ypos < 0:
                    bbox = word_bbox.translated( xpos, ypos )
                    xpos, ypos = push_bbox_up( bbox, bboxes, index )
                direction = "vertical"

        wordtrans = Affine2D.identity().translate( xpos, ypos )

        transpath = word_path.transformed(wordtrans)
        bbox = transpath.get_extents()

        # Swallow the new word into the bounding box for the word cloud.
        bounds = matplotlib.transforms.Bbox.union( [ bounds, bbox ] )

        # We need to check if we've expanded past the bounds of our quad tree.
        # If so we'll need to expand the bounds and then re-index.
        new_bounds = index_bounds
        while not BoxifyWord.bbox_covers(
            # FIXME: Why am I not just doing this with a couple of logarithms?
                    matplotlib.transforms.Bbox(((new_bounds[0], new_bounds[1]),
                                                (new_bounds[2], new_bounds[3]))),
                    bounds ):
            new_bounds = tuple( map( lambda x: 2*x, index_bounds ) )

        if new_bounds != index_bounds:
            # We need to re-index.
            index_bounds = new_bounds
            index = BboxQuadtree(index_bounds)
            for i, b in enumerate(bboxes):
                index.add_bbox(i, b)

        # Approximate the new word by rectangles (unless it's too small) and
        # insert them into the index.
        if not loose and max(abs(bbox.width), abs(bbox.height)) > split_limit:
            for littlebox in BoxifyWord.splitword( 
                    bbox, transpath, limit=split_limit ):
                bboxes.append( littlebox )
                index.add_bbox( len(bboxes)-1, littlebox )
        else:
            bboxes.append( bbox )
            index.add_bbox( len(bboxes)-1, bbox )

        yield (transpath, weight)
Ejemplo n.º 11
0
def draw_layers(layers,
                protein,
                scale_factor=1.0,
                ax=None,
                row_width=50,
                **kwargs):
    '''
    Render fixed-width stacked peptide identifications across
    a protein. Each shape is rendered with a unique identifier.
    '''
    if ax is None:
        figure, ax = plt.subplots(1, 1)
    id_mapper = IDMapper()
    i = 0

    layer_height = 0.56 * scale_factor
    y_step = (layer_height + 0.15) * -scale_factor
    cur_y = -3

    cur_position = 0

    mod_text_x_offset = 0.50 * scale_factor
    sequence_font_size = 6. * scale_factor
    mod_font_size = 2.08 * scale_factor
    mod_text_y_offset = 0.1 * scale_factor
    mod_width = 0.5 * scale_factor
    mod_x_offset = 0.60 * scale_factor
    total_length = len(protein.protein_sequence or '')
    protein_pad = -0.365 * scale_factor
    peptide_pad = protein_pad * (1.2)
    peptide_end_pad = 0.35 * scale_factor

    glycosites = set(protein.n_glycan_sequon_sites)
    for layer in layers:
        layer.sort(key=lambda x: x.start_position)

    while cur_position < total_length:
        next_row = cur_position + row_width
        i = -2
        text_path = TextPath((protein_pad + i, layer_height + .2 + cur_y),
                             str(cur_position + 1),
                             size=sequence_font_size / 7.5,
                             prop=font_options,
                             stretch=1000)
        patch = mpatches.PathPatch(text_path, facecolor='grey', lw=0.04)
        ax.add_patch(patch)

        i = row_width + 2
        text_path = TextPath((protein_pad + i, layer_height + .2 + cur_y),
                             str(next_row),
                             size=sequence_font_size / 7.5,
                             prop=font_options,
                             stretch=1000)
        patch = mpatches.PathPatch(text_path, facecolor='grey', lw=0.04)
        ax.add_patch(patch)

        for i, aa in enumerate(
                protein.protein_sequence[cur_position:next_row]):
            text_path = TextPath((protein_pad + i, layer_height + .2 + cur_y),
                                 aa,
                                 size=sequence_font_size / 7.5,
                                 prop=font_options,
                                 stretch=1000)
            color = 'red' if any(
                (((i + cur_position) in glycosites),
                 ((i + cur_position - 1) in glycosites),
                 ((i + cur_position - 2) in glycosites))) else 'black'
            patch = mpatches.PathPatch(text_path, facecolor=color, lw=0.04)
            ax.add_patch(patch)

        for layer in layers:
            c = 0
            for gpm in layer:
                if gpm.start_position < cur_position and gpm.end_position < cur_position:
                    continue
                elif gpm.start_position >= next_row:
                    break
                c += 1

                color = "lightblue"
                alpha = min(max(gpm.ms2_score * 2, 0.2), 0.8)

                interval_start = max(gpm.start_position - cur_position, 0)
                interval_end = min(
                    len(gpm.structure) + gpm.start_position - cur_position,
                    row_width)

                rect = mpatches.Rectangle(
                    (interval_start + peptide_pad, cur_y),
                    width=(interval_end - interval_start) - peptide_end_pad,
                    height=layer_height,
                    facecolor=color,
                    edgecolor='none',
                    alpha=alpha)

                id_mapper.add(
                    "glycopeptide-%d", rect, {
                        "sequence": str(gpm.structure),
                        "start-position": gpm.start_position,
                        "end-position": gpm.end_position,
                        "ms2-score": gpm.ms2_score,
                        "q-value": gpm.q_value,
                        "record-id": gpm.id if hasattr(gpm, 'id') else None,
                        "calculated-mass": gpm.structure.total_mass,
                        "spectra-count": len(gpm.spectrum_matches)
                    })
                ax.add_patch(rect)

                # Compute offsets into the peptide sequence to select
                # PTMs to draw for this row
                if (cur_position) > gpm.start_position:
                    start_index = cur_position - gpm.start_position
                    if gpm.end_position - start_index > row_width:
                        end_index = min(row_width, len(gpm.structure))
                    else:
                        end_index = gpm.end_position - start_index
                else:
                    start_index = min(0, gpm.start_position - cur_position)
                    end_index = min(
                        gpm.end_position - cur_position,
                        row_width - (gpm.start_position - cur_position))

                # Extract PTMs from the peptide sequence to draw over the
                # peptide rectangle
                seq = gpm.structure

                for i, pos in enumerate(seq[start_index:end_index]):
                    if len(pos[1]) > 0:
                        color = get_color(pos[1][0].name)
                        facecolor, edgecolor = lighten(color), darken(
                            color, 0.6)

                        mod_patch = mpatches.Rectangle(
                            (gpm.start_position - cur_position + i -
                             mod_x_offset + 0.3 + start_index, cur_y),
                            width=mod_width,
                            height=layer_height,
                            alpha=0.4,
                            facecolor=facecolor,
                            edgecolor=edgecolor,
                            linewidth=0.5,
                        )

                        id_mapper.add("modification-%d", mod_patch, {
                            "modification-type": pos[1][0].name,
                            "parent": gpm.id
                        })
                        ax.add_patch(mod_patch)
                        text_path = TextPath(
                            (gpm.start_position - cur_position + i -
                             mod_text_x_offset + 0.3 + start_index,
                             cur_y + mod_text_y_offset),
                            str(pos[1][0])[0],
                            size=mod_font_size / 4.5,
                            prop=font_options)
                        patch = mpatches.PathPatch(text_path,
                                                   facecolor='black',
                                                   lw=0.04)
                        ax.add_patch(patch)
            if c > 0:
                cur_y += y_step
        cur_y += y_step * 3
        cur_position = next_row

    ax.set_ylim(cur_y - 5, 5)
    ax.set_xlim(-5, row_width + 5)
    ax.axis('off')
    return ax, id_mapper
Ejemplo n.º 12
0
def test_copy():
    tp = TextPath((0, 0), ".")
    assert copy.deepcopy(tp).vertices is not tp.vertices
    assert (copy.deepcopy(tp).vertices == tp.vertices).all()
    assert copy.copy(tp).vertices is tp.vertices
Ejemplo n.º 13
0
#!/usr/bin/env python
# coding: utf-8

# In[2]:

import matplotlib.pyplot as plt
from matplotlib.textpath import TextPath
from matplotlib.patches import PathPatch

plt.plot((0, 0, 1, 1, 0), (1, 0, 0, 1, 1), color="gray")

tp = TextPath((0, 0), "TextPath", size=0.2)
plt.gca().add_patch(PathPatch(tp, color="blue"))

plt.show()

# In[ ]:
Ejemplo n.º 14
0
This example shows how to use different properties of markers to plot
multivariate datasets. Here we represent a successful baseball throw as a
smiley face with marker size mapped to the skill of thrower, marker rotation to
the take-off angle, and thrust to the marker color.
"""

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.markers import MarkerStyle
from matplotlib.transforms import Affine2D
from matplotlib.textpath import TextPath
from matplotlib.colors import Normalize

SUCCESS_SYMBOLS = [
    TextPath((0, 0), "☹"),
    TextPath((0, 0), "😒"),
    TextPath((0, 0), "☺"),
]

N = 25
np.random.seed(42)
skills = np.random.uniform(5, 80, size=N) * 0.1 + 5
takeoff_angles = np.random.normal(0, 90, N)
thrusts = np.random.uniform(size=N)
successfull = np.random.randint(0, 3, size=N)
positions = np.random.normal(size=(N, 2)) * 5
data = zip(skills, takeoff_angles, thrusts, successfull, positions)

cmap = plt.cm.get_cmap("plasma")
fig, ax = plt.subplots()
Ejemplo n.º 15
0
    def make_patch(self):
        height = self.y1 - self.y0
        # If height is zero, return None
        if height == 0.0:
            return None

        # Set bounding box for character,
        # leaving requested amount of padding above and below the character
        char_xmin = self.x - self.width / 2.0
        char_ymin = self.y0 + self.pad * height / 2.0
        char_width = self.width
        char_height = height - self.pad * height
        bbox = Bbox.from_bounds(char_xmin,
                                char_ymin,
                                char_width,
                                char_height)

        # Set font properties of Glyph
        font_properties = FontProperties(family=self.font_name,
                                         weight=self.font_weight)

        # Create a path for Glyph that does not yet have the correct
        # position or scaling
        tmp_path = TextPath((0, 0), self.character,
                            size=1,
                            prop=font_properties)

        # Create create a corresponding path for a glyph representing
        # the max stretched character
        msc_path = TextPath((0, 0), self.dont_stretch_more_than, size=1,
                            prop=font_properties)

        # Get bounding box for temporary character and max_stretched_character
        tmp_bbox = tmp_path.get_extents()
        msc_bbox = msc_path.get_extents()

        # Compute horizontal stretch factor needed for tmp_path
        hstretch_tmp = bbox.width / tmp_bbox.width

        # Compute horizontal stretch factor needed for msc_path
        hstretch_msc = bbox.width / msc_bbox.width

        # Choose the MINIMUM of these two horizontal stretch factors.
        # This prevents very narrow characters, such as 'I', from being
        # stretched too much.
        hstretch = min(hstretch_tmp, hstretch_msc)

        # Compute the new character width, accounting for the
        # limit placed on the stretching factor
        char_width = hstretch * tmp_bbox.width

        # Compute how much to horizontally shift the character path
        char_shift = (bbox.width - char_width) / 2.0

        # Compute vertical stetch factor needed for tmp_path
        vstretch = bbox.height / tmp_bbox.height

        # THESE ARE THE ESSENTIAL TRANSFORMATIONS
        # 1. First, translate char path so that lower left corner is at origin
        # 2. Then scale char path to desired width and height
        # 3. Finally, translate char path to desired position
        # char_path is the resulting path used for the Glyph
        transformation = Affine2D() \
            .translate(tx=-tmp_bbox.xmin, ty=-tmp_bbox.ymin) \
            .scale(sx=hstretch, sy=vstretch) \
            .translate(tx=bbox.xmin + char_shift, ty=bbox.ymin)
        char_path = transformation.transform_path(tmp_path)

        # Convert char_path to a patch, which can now be drawn on demand
        return m_patches.PathPatch(char_path,
                                   facecolor=self.color,
                                   zorder=self.zorder,
                                   alpha=self.opacity,
                                   edgecolor=self.edgecolor,
                                   linewidth=self.edgewidth)
Ejemplo n.º 16
0
def get_text_path(text: str, font: FontProperties, size=1) -> TextPath:
    """ Returns a matplotlib :class:`TextPath` object. """
    return TextPath((0, 0), text.replace('$', '\\$'), size=size, prop=font,
                    usetex=False)
Ejemplo n.º 17
0
    return boxes

if __name__ == '__main__':

    import numpy
    from pprint import pprint
    from itertools import islice

    import matplotlib.pyplot as pyplot

    axes = pyplot.gca()

    test_word = "Phillip Seymore Hoffman" # "pearly"

    test_path = TextPath( (0,0), test_word )

    top_box = test_path.get_extents()
    boxes = splitword(top_box, test_path, limit=1)

    # axes.add_patch( PathPatch( test_path, lw=1, facecolor="grey" ) )

    
    for p in cleaned_textpath(test_path):
        axes.add_patch( PathPatch( p, lw=1, facecolor='red', alpha=0.2 ) )

    for box in boxes:
        axes.add_patch( 
                FancyBboxPatch( 
                    (box.xmin, box.ymin), 
                    abs(box.width), abs(box.height),
Ejemplo n.º 18
0
    def instantiate(self, pcb, transformer, translate, rotate):

        # Determine scale.
        ref_coord = transrot(self._translate, translate, rotate)
        ref_rot = rotate + self._rotate
        scale_x, scale_y = transformer.get_scale(ref_coord, ref_rot)
        scale_x = self._scale * 0.1 / scale_x
        scale_y = self._scale * 0.1 / scale_y

        # Determine whether the text needs to be flipped to be readable.
        _, angle = transformer.part_to_global((0, 0), 0, ref_coord, ref_rot)
        angle += 0.5 * math.pi
        while angle >= 2*math.pi:
            angle -= 2*math.pi
        while angle < 0:
            angle += 2*math.pi
        flip_x = -1 if angle > math.pi else 1
        flip_y = -1 if angle > math.pi else 1

        # Render an overbar if the text ends in a backslash, sort of like
        # Altium (except not on character-basis).
        overbar = self._text.endswith('\\')
        if overbar:
            text = self._text[:-1]
        else:
            text = self._text

        # Abuse matplotlib to render some text.
        fp = FontProperties(self._family, self._style, weight=self._weight)
        path = TextPath((0, 0), text, 12, prop=fp)
        polys = [[tuple(x) for x in poly] for poly in path.to_polygons()]

        # Determine extents.
        x_min = 0
        y_min = 0
        x_max = 0
        y_max = 0
        for poly in polys:
            for coord in poly:
                x_min = min(x_min, coord[0])
                x_max = max(x_max, coord[0])
                #y_min = min(y_min, coord[1])
                #y_max = max(y_max, coord[1])
        for poly in TextPath((0, 0), 'jf', 12, prop=fp).to_polygons():
            for _, y in poly:
                y_min = min(y_min, y)
                y_max = max(y_max, y)

        # Render the overbar.
        if overbar:
            polys.append([
                (x_min, y_max + 1.5),
                (x_min, y_max + 3),
                (x_max, y_max + 3),
                (x_max, y_max + 1.5),
                (x_min, y_max + 1.5)
            ])
            y_max += 3

        # Flip if needed.
        for poly in polys:
            for i in range(len(poly)):
                poly[i] = (poly[i][0] * flip_x, poly[i][1] * flip_y)
        x_min *= flip_x
        x_max *= flip_x
        y_min *= flip_y
        y_max *= flip_y

        # Shift based on alignment and apply transformation.
        ox = (x_min + (x_max - x_min) * (self._halign if flip_x > 0 else 1.0 - self._halign)) if self._halign is not None else 0
        oy = (y_min + (y_max - y_min) * (self._valign if flip_y > 0 else 1.0 - self._valign)) if self._valign is not None else 0
        for poly in polys:
            for i in range(len(poly)):
                poly[i] = transrot((
                    from_mm((poly[i][0] - ox) * scale_x),
                    from_mm((poly[i][1] - oy) * scale_y),
                ), self._translate, self._rotate)

        # Determine winding order to detect whether to render as dark or clear.
        dark = []
        clear = []
        for poly in polys:
            poly = [tuple(x) for x in poly]
            winding = 0
            for (x1, y1), (x2, y2) in zip(poly[1:], poly[:-1]):
                winding += (x2 - x1) * (y2 + y1)
            if winding < 0:
                dark.append(poly)
            else:
                clear.append(poly)

        # Add the paths to the PCB.
        for path in dark:
            path = transformer.path_to_global(path, translate, rotate, True)
            pcb.add_region(self._layer, True, *path)
        for path in clear:
            path = transformer.path_to_global(path, translate, rotate, True)
            pcb.add_region(self._layer, False, *path)
Ejemplo n.º 19
0
def _text_path(text: str, font: FontProperties) -> TextPath:
    return TextPath((0, 0), text, size=1, prop=font)
Ejemplo n.º 20
0
Archivo: kern.py Proyecto: Dalar/GPy
    def plot_ARD(self, fignum=None, ax=None, title='', legend=False):
        """If an ARD kernel is present, plot a bar representation using matplotlib

        :param fignum: figure number of the plot
        :param ax: matplotlib axis to plot on
        :param title:
            title of the plot,
            pass '' to not print a title
            pass None for a generic title
        """
        if ax is None:
            fig = pb.figure(fignum)
            ax = fig.add_subplot(111)
        else:
            fig = ax.figure
        from GPy.util import Tango
        from matplotlib.textpath import TextPath
        Tango.reset()
        xticklabels = []
        bars = []
        x0 = 0
        for p in self.parts:
            c = Tango.nextMedium()
            if hasattr(p, 'ARD') and p.ARD:
                if title is None:
                    ax.set_title('ARD parameters, %s kernel' % p.name)
                else:
                    ax.set_title(title)
                if p.name == 'linear':
                    ard_params = p.variances
                else:
                    ard_params = 1. / p.lengthscale

                x = np.arange(x0, x0 + len(ard_params))
                bars.append(ax.bar(x, ard_params, align='center', color=c, edgecolor='k', linewidth=1.2, label=p.name))
                xticklabels.extend([r"$\mathrm{{{name}}}\ {x}$".format(name=p.name, x=i) for i in np.arange(len(ard_params))])
                x0 += len(ard_params)
        x = np.arange(x0)
        transOffset = offset_copy(ax.transData, fig=fig,
                                  x=0., y= -2., units='points')
        transOffsetUp = offset_copy(ax.transData, fig=fig,
                                  x=0., y=1., units='points')
        for bar in bars:
            for patch, num in zip(bar.patches, np.arange(len(bar.patches))):
                height = patch.get_height()
                xi = patch.get_x() + patch.get_width() / 2.
                va = 'top'
                c = 'w'
                t = TextPath((0, 0), "${xi}$".format(xi=xi), rotation=0, ha='center')
                transform = transOffset
                if patch.get_extents().height <= t.get_extents().height + 3:
                    va = 'bottom'
                    c = 'k'
                    transform = transOffsetUp
                ax.text(xi, height, "${xi}$".format(xi=int(num)), color=c, rotation=0, ha='center', va=va, transform=transform)
        # for xi, t in zip(x, xticklabels):
        #    ax.text(xi, maxi / 2, t, rotation=90, ha='center', va='center')
        # ax.set_xticklabels(xticklabels, rotation=17)
        ax.set_xticks([])
        ax.set_xlim(-.5, x0 - .5)
        if legend:
            if title is '':
                mode = 'expand'
                if len(bars) > 1:
                    mode = 'expand'
                ax.legend(bbox_to_anchor=(0., 1.02, 1., 1.02), loc=3,
                          ncol=len(bars), mode=mode, borderaxespad=0.)
                fig.tight_layout(rect=(0, 0, 1, .9))
            else:
                ax.legend()
        return ax
Ejemplo n.º 21
0
def plot_dendrogram(neurite,
                    axis=None,
                    show_node_id=False,
                    aspect_ratio=None,
                    vertical_diam_frac=0.2,
                    ignore_diameter=False,
                    show=True,
                    **kwargs):
    '''
    Plot the dendrogram of a neurite.

    Parameters
    ----------
    neurite : :class:`~dense.elements.Neurite` object
        Neurite for which the dendrogram should be plotted.
    axis : matplotlib.Axes.axis object, optional (default: new one)
        Axis on which the dendrogram should be plotted.
    show : bool, optional (default: True)
        Whether the figure should be shown right away.
    show_node_id : bool, optional (default: False)
        Display each node number on the branching points.
    aspect_ratio : float, optional (default: variable)
        Whether to use a fixed aspect ratio. Automatically set to 1 if
        `show_node_id` is True.
    vertical_diam_frac : float, optional (default: 0.2)
        Fraction of the vertical spacing taken by the branch diameter.
    ignore_diameter : bool, optional (default: False)
        Plot all the branches with the same width.
    **kwargs : arguments for :class:`matplotlib.patches.Rectangle`
        For instance `facecolor` or `edgecolor`.
    '''
    import matplotlib.pyplot as plt

    tree = neurite.get_tree()

    if axis is None:
        fig, axis = plt.subplots()

    fig = axis.get_figure()

    if "facecolor" not in kwargs:
        kwargs["facecolor"] = "k"

    if "edgecolor" not in kwargs:
        kwargs["edgecolor"] = "none"

    # get the number of tips
    num_tips = len(tree.tips)

    # compute the size of the vertical spacing between branches
    # this should be 5 times the diameter of the first section and there
    # are num_tips + 1 spacing in total.
    init_diam = tree.root.children[0].diameter
    vspace = init_diam / vertical_diam_frac
    tot_height = (num_tips + 0.5) * vspace

    # compute the total length which is 1.1 times the longest distance
    # to soma
    max_dts = np.max([n.distance_to_soma() for n in tree.tips])
    tot_length = 1.02 * max_dts

    # we need to find the number of up and down children for each node
    up_children = {}
    down_children = {}

    diams = []

    root = tree.root
    tips = set(tree.tips)

    # if diameter is ignored, set all values to default_diam
    default_diam = 0.2 * vspace

    if ignore_diameter:
        tree.root.diameter = default_diam

    # get root as first node with 2 children
    while len(root.children) == 1:
        root.children[0].dist_to_parent += root.dist_to_parent
        root = root.children[0]

        if ignore_diameter:
            root.diameter = default_diam

    queue = deque([root])

    while queue:
        node = queue.popleft()
        queue.extend(node.children)

        if ignore_diameter:
            node.diameter = default_diam

        if len(node.children) == 1:
            # gc died there, transfer children and update them
            parent = node.parent

            child_pos = 0

            for i, child in enumerate(parent.children):
                if child == node:
                    parent.children[i] = node.children[0]
                    child_pos = i
                    break

            # use loop to keep child memory and update properties
            child = parent.children[child_pos]
            child.dist_to_parent += node.dist_to_parent
            child.parent = node.parent
            child.diameter = 0.5 * (node.diameter + child.diameter)

            # check up/down_children and replace node by child
            for key, val in up_children.items():
                if node in val:
                    up_children[key] = {n for n in val if n is not node}
                    up_children[key].add(child)

            for key, val in down_children.items():
                if node in val:
                    down_children[key] = {n for n in val if n is not node}
                    down_children[key].add(child)
        else:
            if len(node.children) == 2:
                up_children[node] = {node.children[0]}
                down_children[node] = {node.children[1]}

            for val in up_children.values():
                if node.parent in val:
                    val.add(node)

            for val in down_children.values():
                if node.parent in val:
                    val.add(node)

            diams.append(node.diameter)

    # keep only tips in up/down_children
    up_tips, down_tips = {}, {}

    for key, val in up_children.items():
        up_tips[key] = val.intersection(tips)

    for key, val in down_children.items():
        down_tips[key] = val.intersection(tips)

    # get max diameter for node plotting
    max_d = np.max(diams)

    # aspect ratios
    vbar_diam_ratio = 0.5
    hv_ratio = tot_length / tot_height

    if show_node_id:
        axis.set_aspect(1.)
        hv_ratio = 1.
        vbar_diam_ratio = 1.
    elif aspect_ratio is not None:
        axis.set_aspect(aspect_ratio)
        hv_ratio = aspect_ratio
        vbar_diam_ratio /= aspect_ratio

    # making horizontal branches
    x0 = 0.01 * max_dts

    parent_x = {}
    parent_y = {}
    children_y = {tree.root: []}

    queue = deque([root])

    while queue:
        node = queue.popleft()
        queue.extend(node.children)

        parent_diam = 0 if node.parent is None else node.parent.diameter

        x = x0 + node.parent.distance_to_soma() \
            - vbar_diam_ratio*parent_diam*hv_ratio

        # get parent y
        y = parent_y.get(node.parent, 0.)

        num_up, num_down = 0.5, 0.5

        if node.children:
            num_up = len(up_tips[node])
            num_down = len(down_tips[node])

            children_y[node] = []

        if node in up_children.get(node.parent, [node]):
            y += num_down * vspace - 0.5 * node.diameter
        else:
            y -= num_up * vspace + 0.5 * node.diameter

        parent_y[node] = y
        parent_x[node] = x + node.dist_to_parent

        children_y[node.parent].append(y)

        axis.add_artist(
            Rectangle((x, y),
                      node.dist_to_parent,
                      node.diameter,
                      fill=True,
                      **kwargs))

    # last iteration for vertical connections
    queue = deque([root])

    while queue:
        node = queue.popleft()
        queue.extend(node.children)

        if node.children:
            x = parent_x[node]
            y = parent_y[node] + 0.5 * node.diameter
            y1, y2 = children_y[node]

            y1, y2 = min(y1, y2), max(y1, y2)

            dx = 0.5 * vbar_diam_ratio * node.diameter * hv_ratio

            if show_node_id:
                circle = plt.Circle((x + dx, y),
                                    max_d,
                                    color=kwargs["facecolor"])

                artist = axis.add_artist(circle)
                artist.set_zorder(5)

                str_id = str(node)
                xoffset = len(str_id) * 0.3 * max_d
                text = TextPath((x + dx - xoffset, y - 0.3 * max_d),
                                str_id,
                                size=max_d)

                textpatch = PathPatch(text,
                                      edgecolor="w",
                                      facecolor="w",
                                      linewidth=0.01 * max_d)

                axis.add_artist(textpatch)
                textpatch.set_zorder(6)

            axis.add_artist(
                Rectangle((x, y1),
                          vbar_diam_ratio * node.diameter * hv_ratio,
                          (y2 - y1) + 0.5 * node.diameter,
                          fill=True,
                          **kwargs))

    axis.set_xlim(0, tot_length)
    axis.set_ylim(
        np.min(list(parent_y.values())) - 0.75 * vspace,
        np.max(list(parent_y.values())) + 0.75 * vspace)

    plt.axis('off')
    fig.patch.set_alpha(0.)

    if show:
        plt.show()
Ejemplo n.º 22
0
    def create_picture_from(self, text, format, asbytes=True, context=None):
        """
        Creates a picture from text.

        @param      text        the text
        @param      format      text, json, ...
        @param      context     (str) indication on the content of text (error, ...)
        @param      asbytes     results as bytes or as an image
        @return                 tuple (picture, format) or PIL.Image (if asbytes is False)

        The picture will be bytes, the format png, bmp...
        The size of the picture will depend on the text.
        The longer, the bigger. The method relies on matplotlib
        and then convert the image into a PIL image.

        HTML could be rendered with QWebPage from PyQt (not implemented).
        """
        if not isinstance(text, (str, bytes)):
            text = str(text)
            if "\n" not in text:
                rows = []
                for i in range(0, len(text), 20):
                    end = min(i + 20, len(text))
                    rows.append(text[i:end])
                text = "\n".join(text)
        if len(text) > 200:
            text = text[:200]
        size = len(text) // 10
        figsize = (3 + size, 3 + size)
        lines = text.replace("\t", " ").replace("\r", "").split("\n")

        import matplotlib.pyplot as plt
        from matplotlib.textpath import TextPath
        from matplotlib.font_manager import FontProperties
        fig = plt.figure(figsize=figsize)
        ax = fig.add_subplot(111)
        fp = FontProperties(size=200)

        dx = 0
        dy = 0
        for i, line in enumerate(lines):
            if len(line.strip()) > 0:
                ax.text(0, -dy, line, fontproperties=fp, va='top')
                tp = TextPath((0, -dy), line, prop=fp)
                bb = tp.get_extents()
                dy += bb.height
                dx = max(dx, bb.width)

        ratio = abs(dx) / max(abs(dy), 1)
        ratio = max(min(ratio, 3), 1)
        fig.set_size_inches(int((1 + size) * ratio), 1 + size)
        ax.set_xlim([0, dx])
        ax.set_ylim([-dy, 0])
        ax.set_axis_off()
        sio = BytesIO()
        fig.savefig(sio, format="png")
        plt.close()

        if asbytes:
            b = sio.getvalue(), "png"
            self._check_thumbnail_tuple(b)
            return b
        else:
            try:
                from PIL import Image
            except ImportError:
                import Image
            img = Image.open(sio)
            return img
Ejemplo n.º 23
0
    def overplot(self, cps):
        """
        Add overplot elements into figure

        :param cps: Craterplotset instance
        :return: none
        """
        if not self.cratercount or self.hide: return

        p = self.cratercount.getplotdata(
            cps.presentation,
            self.binning,
            range=self.range,
            resurfacing=self.resurf_showall
            if self.resurf and self.type == 'c-fit' else None,
            pf=cps.pf)

        self.n = p['n']
        self.n_event = p['n_event']
        legend_label = []

        if self.error_bars:
            cps.ax.errorbar(np.log10(p['d']),
                            p['y'],
                            yerr=p['err'],
                            fmt='none',
                            linewidth=.7,
                            ecolor=cps.grey[0])

        if self.type in ['c-fit', 'd-fit', 'poisson', 'b-poisson']:
            self.calculate_age(cps)

            if self.isochron:
                iso = cps.pf.getisochron(cps.presentation, self.a0[0], cps.ef)
                cps.ax.plot(np.log10(iso['d']),
                            iso['y'],
                            label=None,
                            color=cps.grey[0],
                            lw=.4,
                            zorder=.9)

            expansion = np.array([.99, 1.01])
            fit = cps.pf.getplotdata(cps.presentation,
                                     self.a0[0],
                                     range=self.range * expansion)
            cps.ax.plot(np.log10(fit['d']),
                        fit['y'],
                        label='fit',
                        color=cps.palette[self.colour],
                        lw=.7)

            if self.display_age:
                st = cst.str_age(self.t[0],
                                 self.t[2] - self.t[0],
                                 self.t[0] - self.t[1],
                                 cps.sig_figs,
                                 mu=cps.mu)
                xy = cps.data_to_axis((np.log10(fit['d'][0]), fit['y'][0]))
                x, y = xy + 0.02 * np.ones(2) * (
                    -1 if self.age_left else 1) + np.array(self.offset_age) / (
                        cps.decades[0] * 20)  #(cps.decades[0]*10).
                cps.ax.text(
                    x,
                    y,
                    st,
                    transform=cps.ax.transAxes,
                    color=cps.palette[self.colour],
                    size=cps.scaled_pt_size * 1.2,
                    horizontalalignment='right' if self.age_left else 'left',
                )

                if self.type in ['poisson', 'b-poisson']:
                    text_extent = TextPath(
                        (0, 0), st,
                        size=cps.scaled_pt_size * 1.2).get_extents()
                    h, w = text_extent.height, text_extent.width
                    f = 1 / (cps.cm2inch *
                             (cps.position[2] - cps.position[0]) * 100
                             )  #conversion for axes coord
                    offset = self.pdf.offset(
                        self.age_left
                    )  # normalised units of mini-plot width in +x direction
                    box = np.array([
                        .12, .05
                    ]) * cps.pt_size / 9.  # dimensions of plot box

                    if self.age_left:  # offset from string write position
                        dx = -(f * w + .03) + (-1 + offset) * box[0]
                    else:
                        dx = f * w + .03 + offset * box[0]
                    dy = f * h / 2

                    pos = np.array(
                        [x + dx, y - dy, x + dx + box[0], y - dy + box[1]])
                    pos2 = cps.axis_to_fig(pos)
                    pos3 = np.concatenate([pos2[0:2], pos2[2:4] - pos2[0:2]])
                    ax = cps.fig.add_axes(pos3)
                    self.pdf.plot(ax,
                                  pt_size=cps.scaled_pt_size,
                                  color=cps.palette[self.colour])

            if '#' in cps.legend:
                if self.cratercount.buffered:
                    legend_label += ['{:.1f}'.format(self.n_event)]
                else:
                    if np.abs(self.n_event - self.n) < .001:
                        legend_label += ['{:0g}'.format(self.n)]
                    else:
                        legend_label += [
                            '{0:.1f} (of {1:d})'.format(self.n, self.n_event)
                        ]
                legend_label[-1] += " craters"
            if 'r' in cps.legend:
                if not self.cratercount.prebinned and self.type in [
                        'poisson', 'b-poisson'
                ]:
                    r = self.range
                else:
                    r = gm.range(
                        self.cratercount.generate_bins(self.binning,
                                                       self.range,
                                                       expand=False))
                legend_label += [cst.str_diameter_range(r)]
            if 'N' in cps.legend:
                legend_label += [
                    'N({0:0g})'.format(cps.ref_diameter) + '$=' +
                    gm.scientific_notation(self.n_d, sf=3) + '$ km$^{-2}$'
                ]

        if self.type == 'data':
            if 'n' in cps.legend:
                legend_label += [
                    self.name if self.name != '' else gm.filename(
                        self.source, "n")
                ]
            if 'a' in cps.legend:
                legend_label += [
                    '$' + gm.scientific_notation(self.cratercount.area, sf=3) +
                    '$ km$^{2}$'
                ]

        cps.ax.plot(np.log10(p['d']),
                    p['y'],
                    label=', '.join(legend_label) if legend_label else None,
                    **cps.marker_def[self.psym],
                    ls='',
                    color=cps.palette[self.colour],
                    markeredgewidth=.5)
Ejemplo n.º 24
0
def plot_neurons(gid=None,
                 mode="sticks",
                 show_nodes=False,
                 show_active_gc=True,
                 culture=None,
                 show_culture=True,
                 aspect=1.,
                 soma_radius=None,
                 active_gc="d",
                 gc_size=2.,
                 soma_color='k',
                 scale=50 * um,
                 scale_text=True,
                 axon_color="indianred",
                 dendrite_color="royalblue",
                 subsample=1,
                 save_path=None,
                 title=None,
                 axis=None,
                 show_density=False,
                 dstep=20.,
                 dmin=None,
                 dmax=None,
                 colorbar=True,
                 show_neuron_id=False,
                 show=True,
                 xy_steps=None,
                 x_min=None,
                 x_max=None,
                 y_min=None,
                 y_max=None,
                 **kwargs):
    '''
    Plot neurons in the network.

    Parameters
    ----------
    gid : int or list, optional (default: all neurons)
        Id(s) of the neuron(s) to plot.
    mode : str, optional (default: "sticks")
        How to draw the neurons. By default, the "sticks" mode shows the real
        width of the neurites. Switching to "lines" only leaves the trajectory
        of the growth cones, without information about the neurite width.
        Eventually, the "mixed" mode shows both informations superimposed.
    culture :  :class:`~dense.environment.Shape`, optional (default: None)
        Shape of the environment; if the environment was already set using
        :func:`~dense.CreateEnvironment`.
    show_nodes : bool, optional (default: False)
        Show the branching nodes.
    show_active_gc : bool, optional (default: True)
        If True, display the tip (growth cone) of actively growing branches.
    show_culture : bool, optional (default: True)
        If True, displays the culture in which the neurons are embedded.
    aspect : float, optional (default: 1.)
        Set the aspect ratio between the `x` and `y` axes.
    soma : str, optional (default: "o")
        Shape of the soma marker using the matplotlib conventions.
    soma_radius : float, optional (default: real neuron radius)
        Size of the soma marker.
    active_gc : str, optional (default: "d")
        Shape of the active growth cone marker using the matplotlib
        conventions.
    gc_size : float, optional (default: 2.)
        Size of the growth cone marker.
    axon_color : valid matplotlib color, optional (default: "indianred")
        Color of the axons.
    dendrite_color : valid matplotlib color, optional (default: "royalblue")
        Color of the dendrites.
    soma_color : valid matplotlib color, optional (default: "k")
        Color of the soma.
    scale : length, optional (default: 50 microns)
        Whether a scale bar should be displayed, with axes hidden. If ``None``,
        then spatial measurements will be given through standard axes.
    subsample : int, optional (default: 1)
        Subsample the neurites to save memory.
    save_path : str, optional (default: not saved)
        Path where the plot should be saved, including the filename, pdf only.
    title : str, optional (default: no title)
        Title of the plot.
    axis : :class:`matplotlib.pyplot.Axes`, optional (default: None)
        Axis on which the plot should be drawn, otherwise a new one will be
        created.
    show_neuron_id : bool, optional (default: False)
        Whether the GID of the neuron should be displayed inside the soma.
    show : bool, optional (default: True)
        Whether the plot should be displayed immediately or not.
    dstep : number of bins for density level histogram
    dmin : minimal density for density  histogram
    dmax : maximal scale for density
    xy_steps : number of spatial bins for density plot
    x_min, x_max, y_min, y_max : bounding bix for spatial density map
    **kwargs : optional arguments
        Details on how to plot the environment, see :func:`plot_environment`.

    Returns
    -------
    axes : axis or tuple of axes if `density` is True.
    '''
    import matplotlib.pyplot as plt

    from shapely.geometry import (Polygon, MultiPolygon)

    assert mode in ("lines", "sticks", "mixed"),\
        "Unknown `mode` '" + mode + "'. Accepted values are 'lines', " +\
        "'sticks' or 'mixed'."

    if show_density:
        subsample = 1

    # plot
    fig, ax, ax2 = None, None, None
    if axis is None:
        fig, ax = plt.subplots()
    else:
        ax = axis
        fig = axis.get_figure()

    fig.patch.set_alpha(0.)
    new_lines = 0

    # plotting options
    soma_alpha = kwargs.get("soma_alpha", 0.8)
    axon_alpha = kwargs.get("axon_alpha", 0.6)
    dend_alpha = kwargs.get("dend_alpha", 0.6)
    gc_color = kwargs.get("gc_color", "g")

    # get the objects describing the neurons
    if gid is None:
        gid = _pg.get_neurons(as_ints=True)
    elif not is_iterable(gid):
        gid = [gid]

    somas, growth_cones, nodes = None, None, None
    axon_lines, dend_lines = None, None
    axons, dendrites = None, None

    if mode in ("lines", "mixed"):
        somas, axon_lines, dend_lines, growth_cones, nodes = \
            _pg._get_pyskeleton(gid, subsample)
    if mode in ("sticks", "mixed"):
        axons, dendrites, somas = _pg._get_geom_skeleton(gid)

    # get the culture if necessary
    env_required = _pg.get_kernel_status('environment_required')
    if show_culture and env_required:
        if culture is None:
            culture = _pg.get_environment()
        plot_environment(culture, ax=ax, show=False, **kwargs)
        new_lines += 1

    # plot the elements
    if mode in ("sticks", "mixed"):
        for a in axons.values():
            plot_shape(a,
                       axis=ax,
                       fc=axon_color,
                       show_contour=False,
                       zorder=2,
                       alpha=axon_alpha,
                       show=False)

        for vd in dendrites.values():
            for d in vd:
                plot_shape(d,
                           axis=ax,
                           fc=dendrite_color,
                           show_contour=False,
                           alpha=dend_alpha,
                           zorder=2,
                           show=False)

    if mode in ("lines", "mixed"):
        ax.plot(axon_lines[0], axon_lines[1], ls="-", c=axon_color)
        ax.plot(dend_lines[0], dend_lines[1], ls="-", c=dendrite_color)
        new_lines += 2

    # plot the rest if required
    if show_nodes and mode in ("lines", "mixed"):
        ax.plot(nodes[0], nodes[1], ls="", marker="d", ms="1", c="k", zorder=4)
        new_lines += 1

    if show_active_gc and mode in ("lines", "mixed"):
        ax.plot(growth_cones[0],
                growth_cones[1],
                ls="",
                marker=active_gc,
                c=gc_color,
                ms=gc_size,
                zorder=4)
        new_lines += 1

    # plot the somas
    n = len(somas[2])
    radii = somas[2] if soma_radius is None else np.repeat(soma_radius, n)

    if mode in ("sticks", "mixed"):
        radii *= 1.05

    r_max = np.max(radii)
    r_min = np.min(radii)

    size = (1.5 * r_min if len(gid) <= 10 else
            (r_min if len(gid) <= 100 else 0.7 * r_min))

    for i, x, y, r in zip(gid, somas[0], somas[1], radii):
        circle = plt.Circle((x, y), r, color=soma_color, alpha=soma_alpha)
        artist = ax.add_artist(circle)
        artist.set_zorder(5)
        if show_neuron_id:
            str_id = str(i)
            xoffset = len(str_id) * 0.35 * size
            text = TextPath((x - xoffset, y - 0.35 * size), str_id, size=size)
            textpatch = PathPatch(text,
                                  edgecolor="w",
                                  facecolor="w",
                                  linewidth=0.01 * size)
            ax.add_artist(textpatch)
            textpatch.set_zorder(6)

    # set the axis limits
    if (not show_culture or not env_required) and len(ax.lines) == new_lines:
        if mode in ("lines", "mixed"):
            _set_ax_lim(ax,
                        axon_lines[0] + dend_lines[0],
                        axon_lines[1] + dend_lines[1],
                        offset=2 * r_max)
        else:
            xx = []
            yy = []

            for a in axons.values():
                xmin, ymin, xmax, ymax = a.bounds
                xx.extend((xmin, xmax))
                yy.extend((ymin, ymax))

            for vd in dendrites.values():
                for d in vd:
                    xmin, ymin, xmax, ymax = d.bounds
                    xx.extend((xmin, xmax))
                    yy.extend((ymin, ymax))

            _set_ax_lim(ax, xx, yy, offset=2 * r_max)

    ax.set_aspect(aspect)

    if title is not None:
        fig.suptitle(title)

    if save_path is not None:
        if not save_path.endswith('pdf'):
            save_path += ".pdf"
        plt.savefig(save_path, format="pdf", dpi=300)

    if show_density:
        from matplotlib.colors import LogNorm

        fig, ax2 = plt.subplots()

        # https://stackoverflow.com/questions/20474549/extract-points-coordinates-from-a-polygon-in-shapely#20476150
        #        x,y= axons[].exterior.coords.xy

        def extract_neurites_coordinate(neurites):
            '''
            from a neurite defined as polynom extract the coordinates of each
            segment
            input : p neuron or dendrite, as shapely polygon
                    x_neurites, y_neurites : numpy arrays of x and y coordinates of
                                       axons segments
                    y_dendrites, y_dendrites : numpy arrays of x and y
                                               coordinates of dendrites
            outputs : updates lists of coordinates
            '''
            x_neurites = np.array([])
            y_neurites = np.array([])
            if isinstance(neurites, MultiPolygon):
                for p in neurites:
                    x_neurite, y_neurite = extract_neurites_coordinate(p)
                    x_neurites = np.concatenate((x_neurites, x_neurite))
                    y_neurites = np.concatenate((y_neurites, y_neurite))
            elif isinstance(neurites, Polygon):
                x_neurite, y_neurite = neurites.exterior.coords.xy
                x_neurites = np.concatenate((x_neurites, x_neurite))
                y_neurites = np.concatenate((y_neurites, y_neurite))
            else:
                for index in range(len(neurites)):
                    x_neurite, y_neurite = extract_neurites_coordinate(
                        neurites[index])
                    x_neurites = np.concatenate((x_neurites, x_neurite))
                    y_neurites = np.concatenate((y_neurites, y_neurite))

            return x_neurites, y_neurites

        # extract axons segments
        # if isinstance(axons, MultiPolygon):
        #     for p in axons:
        #         x_axons, y_axons = extract_neurites_coordinate(p)
        # else:
        x, y = extract_neurites_coordinate(axons)

        # x = x_axons
        # y = y_axons

        # extract dendrites segments
        if len(dendrites) > 0:  # this depends if dendrites present
            # if isinstance(dendrites, MultiPolygon):
            #     for p in dendrites:
            #         x_dendrites, y_dendrites = extract_neurites_coordinate(p)
            # else:
            #     x_dendrites, y_dendrites = extract_neurites_coordinate(
            #                             dendrites)
            x_dendrites, y_dendrites = extract_neurites_coordinate(dendrites)

            x = np.concatenate(x, x_dendrites)
            y = np.concatenate(y, y_dendrites)

        # Scaling density levels
        xbins = int((np.max(x) - np.min(x)) / dstep)
        ybins = int((np.max(y) - np.min(y)) / dstep)

        dstep = int(dstep)
        counts, xbins, ybins = np.histogram2d(x,
                                              y,
                                              bins=(dstep, dstep),
                                              range=[[x_min, x_max],
                                                     [y_min, y_max]])
        lims = [xbins[0], xbins[-1], ybins[0], ybins[-1]]
        counts[counts == 0] = np.NaN

        cmap = get_cmap(kwargs.get("cmap", "viridis"))
        cmap.set_bad((0, 0, 0, 1))
        norm = None
        dmax = np.nanmax(counts)
        print("Maximal density : {}".format(dmax))

        if dmin is not None and dmax is not None:
            n = int(dmax - dmin)
            norm = matplotlib.colors.BoundaryNorm(
                np.arange(dmin - 1, dmax + 1, 0), cmap.N)
        elif dmax is not None:
            n = int(dmax)
            norm = matplotlib.colors.BoundaryNorm(np.arange(0, dmax + 1, 1),
                                                  cmap.N)

        # data = ax2.imshow(counts.T, extent=lims, origin="lower",
        #                   vmin=0 if dmin is None else dmin, vmax=dmax,
        #                   cmap=cmap)

        data = ax2.imshow(counts.T,
                          extent=lims,
                          origin="lower",
                          norm=norm,
                          cmap=cmap)

        if colorbar:
            extend = "neither"
            if dmin is not None and dmax is not None:
                extend = "both"
            elif dmax is not None:
                extend = "max"
            elif dmin is not None:
                extend = "min"
            cb = plt.colorbar(data, ax=ax2, extend=extend)
            cb.set_label("Number of neurites per bin")
        ax2.set_aspect(aspect)
        ax2.set_xlabel(r"x ($\mu$ m)")
        ax2.set_ylabel(r"y ($\mu$ m)")

    if scale is not None:
        xmin, xmax = ax.get_xlim()
        ymin, ymax = ax.get_ylim()

        length = scale.m_as("micrometer")

        if xmax - xmin < 2 * length:
            scale *= 0.2
            length = scale.m_as("micrometer")

        x = xmin + 0.2 * length
        y = ymin + (ymax - ymin) * 0.05

        ax.add_artist(
            Rectangle((x, y),
                      length,
                      0.1 * length,
                      fill=True,
                      facecolor='k',
                      edgecolor='none'))

        plt.axis('off')

        stext = "(scale is {} $\mu$m)".format(length)
        if title is not None and scale_text:
            fig.suptitle(title + " " + stext)
        elif scale_text:
            fig.suptitle(stext)

    if show:
        plt.show()

    if show_density:
        return ax, ax2

    return ax