graphid.util package

Submodules

Module contents

mkinit graphid.util

class graphid.util.Color(color, alpha=None, space=None)[source]

Bases: NiceRepr

move to colorutil?

Example

>>> print(Color('g'))
>>> print(Color('orangered'))
>>> print(Color('#AAAAAA').as255())
>>> print(Color([0, 255, 0]))
>>> print(Color([1, 1, 1.]))
>>> print(Color([1, 1, 1]))
>>> print(Color(Color([1, 1, 1])).as255())
>>> print(Color(Color([1., 0, 1, 0])).ashex())
>>> print(Color([1, 1, 1], alpha=255))
>>> print(Color([1, 1, 1], alpha=255, space='lab'))
ashex(space=None)[source]
as255(space=None)[source]
as01(space=None)[source]

self = mplutil.Color(‘red’) mplutil.Color(‘green’).as01(‘rgba’)

classmethod _is_base01()[source]

check if a color is in base 01

classmethod _is_base255(channels)[source]

there is a one corner case where all pixels are 1 or less

classmethod _hex_to_01(hex_color)[source]

hex_color = ‘#6A5AFFAF’

_ensure_color01(color)[source]

Infer what type color is and normalize to 01

classmethod _255_to_01(color255)[source]

converts base 255 color to base 01 color

classmethod _string_to_01('green')[source]
classmethod _string_to_01('red') None
classmethod named_colors()[source]
classmethod distinct(num, space='bgr')[source]

Make multiple distinct colors

adjust_hsv(hue_adjust=0.0, sat_adjust=0.0, val_adjust=0.0)[source]

Performs adaptive changes to the HSV values of the color.

Parameters:
  • hue_adjust (float) – addative

  • sat_adjust (float)

  • val_adjust (float)

Returns:

new_rgb

Return type:

list

CommandLine

python -m graphid.util.mplutil Color.adjust_hsv

Example

>>> rgb_list = [Color(c).as01() for c in ['pink', 'yellow', 'green']]
>>> hue_adjust = -0.1
>>> sat_adjust = +0.5
>>> val_adjust = -0.1
>>> # execute function
>>> new_rgb_list = [Color(rgb).adjust_hsv(hue_adjust, sat_adjust, val_adjust) for rgb in rgb_list]
>>> print(ub.urepr(new_rgb_list, nl=1, sv=True))
[
    <Color(rgb: 0.90, 0.23, 0.75)>,
    <Color(rgb: 0.90, 0.36, 0.00)>,
    <Color(rgb: 0.24, 0.40, 0.00)>,
]
>>> # xdoc: +REQUIRES(--show)
>>> color_list = rgb_list + new_rgb_list
>>> testshow_colors(color_list)
convert(space)[source]

Converts to a new colorspace

class graphid.util.PanEvents(ax=None)[source]

Bases: object

pan_on_press(event)[source]
pan_on_release(event)[source]
pan_on_motion(event)[source]
class graphid.util.PlotNums(nRows=None, nCols=None, nSubplots=None, start=0)[source]

Bases: object

Convinience class for dealing with plot numberings (pnums)

Example

>>> pnum_ = PlotNums(nRows=2, nCols=2)
>>> # Indexable
>>> print(pnum_[0])
(2, 2, 1)
>>> # Iterable
>>> print(ub.urepr(list(pnum_), nl=0, nobr=1))
(2, 2, 1), (2, 2, 2), (2, 2, 3), (2, 2, 4)
>>> # Callable (iterates through a default iterator)
>>> print(pnum_())
(2, 2, 1)
>>> print(pnum_())
(2, 2, 2)
classmethod _get_num_rc(nSubplots=None, nRows=None, nCols=None)[source]

Gets a constrained row column plot grid

Parameters:
  • nSubplots (None) – (default = None)

  • nRows (None) – (default = None)

  • nCols (None) – (default = None)

Returns:

(nRows, nCols)

Return type:

tuple

Example

>>> cases = [
>>>     dict(nRows=None, nCols=None, nSubplots=None),
>>>     dict(nRows=2, nCols=None, nSubplots=5),
>>>     dict(nRows=None, nCols=2, nSubplots=5),
>>>     dict(nRows=None, nCols=None, nSubplots=5),
>>> ]
>>> for kw in cases:
>>>     print('----')
>>>     size = PlotNums._get_num_rc(**kw)
>>>     if kw['nSubplots'] is not None:
>>>         assert size[0] * size[1] >= kw['nSubplots']
>>>     print('**kw = %s' % (ub.urepr(kw),))
>>>     print('size = %r' % (size,))
_get_square_row_cols(max_cols=None, fix=False, inclusive=True)[source]
Parameters:
  • nSubplots (int)

  • max_cols (int)

Returns:

(int, int)

Return type:

tuple

Example

>>> nSubplots = 9
>>> nSubplots_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
>>> max_cols = None
>>> rc_list = [PlotNums._get_square_row_cols(nSubplots, fix=True) for nSubplots in nSubplots_list]
>>> print(repr(np.array(rc_list).T))
array([[1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3],
       [1, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4]])
graphid.util.adjust_subplots(left=None, right=None, bottom=None, top=None, wspace=None, hspace=None, fig=None)[source]
Kwargs:

left (float): left side of the subplots of the figure right (float): right side of the subplots of the figure bottom (float): bottom of the subplots of the figure top (float): top of the subplots of the figure wspace (float): width reserved for blank space between subplots hspace (float): height reserved for blank space between subplots

graphid.util.axes_extent(axs, pad=0.0)[source]

Get the full extent of a group of axes, including axes labels, tick labels, and titles.

graphid.util.colorbar(scalars, colors, custom=False, lbl=None, ticklabels=None, float_format='%.2f', **kwargs)[source]

adds a color bar next to the axes based on specific scalars

Parameters:
  • scalars (ndarray)

  • colors (ndarray)

  • custom (bool) – use custom ticks

Kwargs:

See plt.colorbar

Returns:

matplotlib colorbar object

Return type:

cb

graphid.util.deterministic_shuffle(list_, rng=0)[source]
Parameters:
  • list_ (list)

  • seed (int)

Returns:

list_

Return type:

list

Example

>>> list_ = [1, 2, 3, 4, 5, 6]
>>> seed = 1
>>> list_ = deterministic_shuffle(list_, seed)
>>> result = str(list_)
>>> print(result)
[3, 2, 5, 1, 4, 6]
graphid.util.dict_intersection(dict1, dict2)[source]

Key AND Value based dictionary intersection

Parameters:
  • dict1 (dict)

  • dict2 (dict)

Returns:

mergedict_

Return type:

dict

Example

>>> dict1 = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
>>> dict2 = {'b': 2, 'c': 3, 'd': 5, 'e': 21, 'f': 42}
>>> mergedict_ = dict_intersection(dict1, dict2)
>>> print(ub.urepr(mergedict_, nl=0, sort=1))
{'b': 2, 'c': 3}
graphid.util.distinct_colors(N, brightness=0.878, randomize=True, hue_range=(0.0, 1.0), cmap_seed=None)[source]
Parameters:
  • N (int)

  • brightness (float)

Returns:

RGB_tuples

Return type:

list

CommandLine

python -m color_funcs --test-distinct_colors --N 2 --show --hue-range=0.05,.95
python -m color_funcs --test-distinct_colors --N 3 --show --hue-range=0.05,.95
python -m color_funcs --test-distinct_colors --N 4 --show --hue-range=0.05,.95
python -m .color_funcs --test-distinct_colors --N 3 --show --no-randomize
python -m .color_funcs --test-distinct_colors --N 4 --show --no-randomize
python -m .color_funcs --test-distinct_colors --N 6 --show --no-randomize
python -m .color_funcs --test-distinct_colors --N 20 --show

References

http://blog.jianhuashao.com/2011/09/generate-n-distinct-colors.html

graphid.util.distinct_markers(num, style='astrisk', total=None, offset=0)[source]
Parameters:

num (?)

graphid.util.draw_border(ax, color, lw=2, offset=None, adjust=True)[source]

draws rectangle border around a subplot

graphid.util.draw_boxes(boxes, box_format='xywh', color='blue', labels=None, textkw=None, ax=None)[source]
Parameters:
  • boxes (list) – list of coordindates in xywh, tlbr, or cxywh format

  • box_format (str) – specify how boxes are formated xywh is the top left x and y pixel width and height cxywh is the center xy pixel width and height tlbr is the top left xy and the bottom right xy

  • color (str) – edge color of the boxes

  • labels (list) – if specified, plots a text annotation on each box

Example

>>> qtensure()  # xdoc: +SKIP
>>> bboxes = [[.1, .1, .6, .3], [.3, .5, .5, .6]]
>>> col = draw_boxes(bboxes)
graphid.util.draw_line_segments(pts1, pts2, ax=None, **kwargs)[source]

draws N line segments between N pairs of points

Parameters:
  • pts1 (ndarray) – Nx2

  • pts2 (ndarray) – Nx2

  • ax (None) – (default = None)

  • **kwargs – lw, alpha, colors

Example

>>> pts1 = np.array([(.1, .8), (.6, .8)])
>>> pts2 = np.array([(.6, .7), (.4, .1)])
>>> figure(fnum=None)
>>> draw_line_segments(pts1, pts2)
>>> # xdoc: +REQUIRES(--show)
>>> import matplotlib.pyplot as plt
>>> ax = plt.gca()
>>> ax.set_xlim(0, 1)
>>> ax.set_ylim(0, 1)
>>> show_if_requested()
_images/fig_graphid_util_draw_line_segments_002.jpeg
graphid.util.ensure_fnum(fnum)[source]
graphid.util.extract_axes_extents(fig, combine=False, pad=0.0)[source]
graphid.util.figure(fnum=None, pnum=(1, 1, 1), title=None, figtitle=None, doclf=False, docla=False, projection=None, **kwargs)[source]

http://matplotlib.org/users/gridspec.html

Parameters:
  • fnum (int) – fignum = figure number

  • pnum (int, str, or tuple(int, int, int)) – plotnum = plot tuple

  • title (str) – (default = None)

  • figtitle (None) – (default = None)

  • docla (bool) – (default = False)

  • doclf (bool) – (default = False)

Returns:

fig

Return type:

mpl.Figure

Example

>>> import matplotlib.pyplot as plt
>>> fnum = 1
>>> fig = figure(fnum, (2, 2, 1))
>>> plt.gca().text(0.5, 0.5, "ax1", va="center", ha="center")
>>> fig = figure(fnum, (2, 2, 2))
>>> plt.gca().text(0.5, 0.5, "ax2", va="center", ha="center")
>>> show_if_requested()

Example

>>> import matplotlib.pyplot as plt
>>> fnum = 1
>>> fig = figure(fnum, (2, 2, 1))
>>> plt.gca().text(0.5, 0.5, "ax1", va="center", ha="center")
>>> fig = figure(fnum, (2, 2, 2))
>>> plt.gca().text(0.5, 0.5, "ax2", va="center", ha="center")
>>> fig = figure(fnum, (2, 4, (1, slice(1, None))))
>>> plt.gca().text(0.5, 0.5, "ax3", va="center", ha="center")
>>> show_if_requested()
graphid.util.get_axis_xy_width_height(ax=None, xaug=0, yaug=0, waug=0, haug=0)[source]

gets geometry of a subplot

graphid.util.imshow(img, fnum=None, title=None, figtitle=None, pnum=None, interpolation='nearest', cmap=None, heatmap=False, data_colorbar=False, xlabel=None, redraw_image=True, colorspace='bgr', ax=None, alpha=None, norm=None, **kwargs)[source]
Parameters:
  • img (ndarray) – image data

  • fnum (int) – figure number

  • colorspace (str) – if the data is 3-4 channels, this indicates the colorspace 1 channel data is assumed grayscale. 4 channels assumes alpha.

  • title (str)

  • figtitle (None)

  • pnum (tuple) – plot number

  • interpolation (str) – other interpolations = nearest, bicubic, bilinear

  • cmap (None)

  • heatmap (bool)

  • data_colorbar (bool)

  • darken (None)

  • redraw_image (bool) – used when calling imshow over and over. if false doesnt do the image part.

Returns:

(fig, ax)

Return type:

tuple

Kwargs:

docla, doclf, projection

Returns:

(fig, ax)

Return type:

tuple

graphid.util.legend(loc='best', fontproperties=None, size=None, fc='w', alpha=1, ax=None, handles=None)[source]
Parameters:
  • loc (str) – (default = ‘best’)

  • fontproperties (None) – (default = None)

  • size (None) – (default = None)

graphid.util.make_heatmask(probs, cmap='plasma', with_alpha=True)[source]

Colorizes a single-channel intensity mask (with an alpha channel)

graphid.util.multi_plot(xdata=None, ydata=[], **kwargs)[source]

plots multiple lines, bars, etc…

This is the big function that implements almost all of the heavy lifting in this file. Any function not using this should probably find a way to use it. It is pretty general and relatively clean.

Parameters:
  • xdata (ndarray) – can also be a list of arrays

  • ydata (list or dict of ndarrays) – can also be a single array

  • **kwargs

    Misc:

    fnum, pnum, use_legend, legend_loc

    Labels:

    xlabel, ylabel, title, figtitle ticksize, titlesize, legendsize, labelsize

    Grid:

    gridlinewidth, gridlinestyle

    Ticks:

    num_xticks, num_yticks, tickwidth, ticklength, ticksize

    Data:

    xmin, xmax, ymin, ymax, spread_list # can append _list to any of these # these can be dictionaries if ydata was also a dict

    plot_kw_keys = [‘label’, ‘color’, ‘marker’, ‘markersize’,

    ‘markeredgewidth’, ‘linewidth’, ‘linestyle’]

    any plot_kw key can be a scalar (corresponding to all ydatas), a list if ydata was specified as a list, or a dict if ydata was specified as a dict.

    kind = [‘bar’, ‘plot’, …]

    if kind=’plot’:

    spread

    if kind=’bar’:

    stacked, width

References

matplotlib.org/examples/api/barchart_demo.html

Example

>>> xdata = [1, 2, 3, 4, 5]
>>> ydata_list = [[1, 2, 3, 4, 5], [3, 3, 3, 3, 3], [5, 4, np.nan, 2, 1], [4, 3, np.nan, 1, 0]]
>>> kwargs = {'label': ['spamΣ', 'eggs', 'jamµ', 'pram'],  'linestyle': '-'}
>>> #fig = multi_plot(xdata, ydata_list, title='$\phi_1(\\vec{x})$', xlabel='\nfds', **kwargs)
>>> fig = multi_plot(xdata, ydata_list, title='ΣΣΣµµµ', xlabel='\nfdsΣΣΣµµµ', **kwargs)
>>> show_if_requested()

Example

>>> fig1 = multi_plot([1, 2, 3], [4, 5, 6])
>>> fig2 = multi_plot([1, 2, 3], [4, 5, 6], fnum=4)
>>> show_if_requested()
graphid.util.next_fnum(new_base=None)[source]
graphid.util.pan_factory(ax=None)[source]
graphid.util.pandas_plot_matrix(df, rot=90, ax=None, grid=True, label=None, zerodiag=False, cmap='viridis', showvals=False, logscale=True)[source]
graphid.util.qtensure()[source]
graphid.util.relative_text(pos, text, ax=None, offset=None, **kwargs)[source]

Places text on axes in a relative position

Parameters:
  • pos (tuple) – relative xy position

  • text (str) – text

  • ax (None) – (default = None)

  • offset (None) – (default = None)

  • **kwargs – horizontalalignment, verticalalignment, roffset, ha, va, fontsize, fontproperties, fontproperties, clip_on

CommandLine

python -m graphid.util.mplutil relative_text --show

Example

>>> from graphid import util
>>> import matplotlib as mpl
>>> x = .5
>>> y = .5
>>> util.figure()
>>> txt = 'Hello World'
>>> family = 'monospace'
>>> family = 'CMU Typewriter Text'
>>> fontproperties = mpl.font_manager.FontProperties(family=family,
>>>                                                  size=42)
>>> relative_text((x, y), txt, halign='center',
>>>               fontproperties=fontproperties)
>>> util.show_if_requested()
graphid.util.reverse_colormap(cmap)[source]

References

http://nbviewer.ipython.org/github/kwinkunks/notebooks/blob/master/Matteo_colourmaps.ipynb

graphid.util.save_parts(fig, fpath, grouped_axes=None, dpi=None)[source]

FIXME: this works in mpl 2.0.0, but not 2.0.2

Parameters:
  • fig (?)

  • fpath (str) – file path string

  • dpi (None) – (default = None)

Returns:

subpaths

Return type:

list

CommandLine

python -m draw_func2 save_parts
graphid.util.scores_to_cmap(scores, colors=None, cmap_='hot')[source]
graphid.util.scores_to_color(score_list, cmap_='hot', logscale=False, reverse_cmap=False, custom=False, val2_customcolor=None, score_range=None, cmap_range=(0.1, 0.9))[source]

Other good colormaps are ‘spectral’, ‘gist_rainbow’, ‘gist_ncar’, ‘Set1’, ‘Set2’, ‘Accent’ # TODO: plasma

Parameters:
  • score_list (list)

  • cmap_ (str) – defaults to hot

  • logscale (bool)

  • cmap_range (tuple) – restricts to only a portion of the cmap to avoid extremes

Returns:

<class ‘_ast.ListComp’>

graphid.util.set_figtitle(figtitle, subtitle='', forcefignum=True, incanvas=True, size=None, fontfamily=None, fontweight=None, fig=None)[source]
Parameters:
  • figtitle (?)

  • subtitle (str) – (default = ‘’)

  • forcefignum (bool) – (default = True)

  • incanvas (bool) – (default = True)

  • fontfamily (None) – (default = None)

  • fontweight (None) – (default = None)

  • size (None) – (default = None)

  • fig (None) – (default = None)

CommandLine

python -m .custom_figure set_figtitle --show

Example

>>> # DISABLE_DOCTEST
>>> fig = figure(fnum=1, doclf=True)
>>> result = set_figtitle(figtitle='figtitle', fig=fig)
>>> # xdoc: +REQUIRES(--show)
>>> show_if_requested()
_images/fig_graphid_util_set_figtitle_002.jpeg
graphid.util.show_if_requested(N=1)[source]

Used at the end of tests. Handles command line arguments for saving figures

Referencse:

http://stackoverflow.com/questions/4325733/save-a-subplot-in-matplotlib

graphid.util.zoom_factory(ax=None, zoomable_list=[], base_scale=1.1)[source]

References

https://gist.github.com/tacaswell/3144287 http://stackoverflow.com/questions/11551049/matplotlib-plot-zooming-with-scroll-wheel

graphid.util.demodata_oldnames(n_incon_groups=10, n_con_groups=2, n_per_con=5, n_per_incon=5, con_sep=4, n_empty_groups=0)[source]
graphid.util.find_consistent_labeling(grouped_oldnames, extra_prefix='_extra_name', verbose=False)[source]

Solves a a maximum bipirtite matching problem to find a consistent name assignment that minimizes the number of annotations with different names. For each new grouping of annotations we assign

For each group of annotations we must assign them all the same name, either from

To reduce the running time

Parameters:

gropued_oldnames (list) – A group of old names where the grouping is based on new names. For instance:

Given:

aids = [1, 2, 3, 4, 5] old_names = [0, 1, 1, 1, 0] new_names = [0, 0, 1, 1, 0]

The grouping is

[[0, 1, 0], [1, 1]]

This lets us keep the old names in a split case and re-use exising names and make minimal changes to current annotation names while still being consistent with the new and improved grouping.

The output will be:

[0, 1]

Meaning that all annots in the first group are assigned the name 0 and all annots in the second group are assigned the name 1.

References

http://stackoverflow.com/questions/1398822/assignment-problem-numpy

Example

>>> grouped_oldnames = demodata_oldnames(25, 15,  5, n_per_incon=5)
>>> new_names = find_consistent_labeling(grouped_oldnames, verbose=1)
>>> grouped_oldnames = demodata_oldnames(0, 15,  5, n_per_incon=1)
>>> new_names = find_consistent_labeling(grouped_oldnames, verbose=1)
>>> grouped_oldnames = demodata_oldnames(0, 0, 0, n_per_incon=1)
>>> new_names = find_consistent_labeling(grouped_oldnames, verbose=1)

Example

>>> # xdoctest: +REQUIRES(module:timerit)
>>> import timerit
>>> ydata = []
>>> xdata = list(range(10, 150, 50))
>>> for x in xdata:
>>>     print('x = %r' % (x,))
>>>     grouped_oldnames = demodata_oldnames(x, 15,  5, n_per_incon=5)
>>>     t = timerit.Timerit(3, verbose=1)
>>>     for timer in t:
>>>         with timer:
>>>             new_names = find_consistent_labeling(grouped_oldnames)
>>>     ydata.append(t.min())
>>> # xdoc: +REQUIRES(--show)
>>> import plottool_ibeis as pt
>>> pt.qtensure()
>>> pt.multi_plot(xdata, [ydata])
>>> util.show_if_requested()

Example

>>> grouped_oldnames = [['a', 'b', 'c'], ['b', 'c'], ['c', 'e', 'e']]
>>> new_names = find_consistent_labeling(grouped_oldnames, verbose=1)
>>> result = ub.urepr(new_names)
>>> print(new_names)
['a', 'b', 'e']

Example

>>> grouped_oldnames = [['a', 'b'], ['a', 'a', 'b'], ['a']]
>>> new_names = find_consistent_labeling(grouped_oldnames)
>>> result = ub.urepr(new_names)
>>> print(new_names)
['b', 'a', '_extra_name0']

Example

>>> grouped_oldnames = [['a', 'b'], ['e'], ['a', 'a', 'b'], [], ['a'], ['d']]
>>> new_names = find_consistent_labeling(grouped_oldnames)
>>> result = ub.urepr(new_names)
>>> print(new_names)
['b', 'e', 'a', '_extra_name0', '_extra_name1', 'd']

Example

>>> grouped_oldnames = [[], ['a', 'a'], [],
>>>                     ['a', 'a', 'a', 'a', 'a', 'a', 'a', 'b'], ['a']]
>>> new_names = find_consistent_labeling(grouped_oldnames)
>>> result = ub.urepr(new_names)
>>> print(new_names)
['_extra_name0', 'a', '_extra_name1', 'b', '_extra_name2']
graphid.util.simple_munkres(part_oldnames)[source]

Defines a munkres problem to solve name rectification.

Notes

We create a matrix where each rows represents a group of annotations in the same PCC and each column represents an original name. If there are more PCCs than original names the columns are padded with extra values. The matrix is first initialized to be negative infinity representing impossible assignments. Then for each column representing a padded name, we set we its value to $1$ indicating that each new name could be assigned to a padded name for some small profit. Finally, let $f_{rc}$ be the the number of annotations in row $r$ with an original name of $c$. Each matrix value $(r, c)$ is set to $f_{rc} + 1$ if $f_{rc} > 0$, to represent how much each name ``wants’’ to be labeled with a particular original name, and the extra one ensures that these original names are always preferred over padded names.

Example

>>> part_oldnames = [['a', 'b'], ['b', 'c'], ['c', 'a', 'a']]
>>> new_names = simple_munkres(part_oldnames)
>>> result = ub.urepr(new_names)
>>> print(new_names)
['b', 'c', 'a']

Example

>>> part_oldnames = [[], ['a', 'a'], [],
>>>                  ['a', 'a', 'a', 'a', 'a', 'a', 'a', 'b'], ['a']]
>>> new_names = simple_munkres(part_oldnames)
>>> result = ub.urepr(new_names)
>>> print(new_names)
[None, 'a', None, 'b', None]

Example

>>> part_oldnames = [[], ['b'], ['a', 'b', 'c'], ['b', 'c'], ['c', 'e', 'e']]
>>> new_names = find_consistent_labeling(part_oldnames)
>>> result = ub.urepr(new_names)
>>> print(new_names)
['_extra_name0', 'b', 'a', 'c', 'e']
Profit Matrix

b a c e _0

0 -10 -10 -10 -10 1 1 2 -10 -10 -10 1 2 2 2 2 -10 1 3 2 -10 2 -10 1 4 -10 -10 2 3 1

class graphid.util.DynConnGraph(*args, **kwargs)[source]

Bases: Graph, GraphHelperMixin

Dynamically connected graph.

Maintains a data structure parallel to a normal networkx graph that maintains dynamic connectivity for fast connected compoment queries.

Underlying Data Structures and limitations are

Data Structure | Insertion | Deletion | CC Find |

UnionFind | lg(n) | n | No UnionFind2 | n* | n | 1 EulerTourForest | lg^2(n) | lg^2(n) | lg(n) / lglg(n) - - Ammortized

  • O(n) is worst case, but it seems to be very quick in practice. The average runtime should be close to lg(n), but I’m writing this doc 8 months after working on this algo, so I may not remember exactly.

References

https://courses.csail.mit.edu/6.851/spring14/lectures/L20.pdf https://courses.csail.mit.edu/6.851/spring14/lectures/L20.html http://cs.stackexchange.com/questions/33595/maintaining-connecte https://en.wikipedia.org/wiki/Dynamic_connectivity#Fully_dynamic_connectivity

Example

>>> self = DynConnGraph()
>>> self.add_edges_from([(1, 2), (2, 3), (4, 5), (6, 7), (7, 4)])
>>> self.add_edges_from([(10, 20), (20, 30), (40, 50), (60, 70), (70, 40)])
>>> self._ccs
>>> u, v = 20, 1
>>> assert self.node_label(u) != self.node_label(v)
>>> assert self.connected_to(u) != self.connected_to(v)
>>> self.add_edge(u, v)
>>> assert self.node_label(u) == self.node_label(v)
>>> assert self.connected_to(u) == self.connected_to(v)
>>> self.remove_edge(u, v)
>>> assert self.node_label(u) != self.node_label(v)
>>> assert self.connected_to(u) != self.connected_to(v)
>>> ccs = list(self.connected_components())
>>> # xdoctest: +REQUIRES(--show)
>>> import plottool_ibeis as pt
>>> pt.qtensure()
>>> pt.show_nx(self)

# todo: check if nodes exist when adding

clear()[source]
number_of_components()[source]
component(label)[source]
component_nodes(label)
connected_to(node)[source]
node_label(node)[source]

Example

>>> self = DynConnGraph()
>>> self.add_edges_from([(1, 2), (2, 3), (4, 5), (6, 7)])
>>> assert self.node_label(2) == self.node_label(1)
>>> assert self.node_label(2) != self.node_label(4)
node_labels(*nodes)[source]
are_nodes_connected(u, v)[source]
connected_components()[source]

Example

>>> self = DynConnGraph()
>>> self.add_edges_from([(1, 2), (2, 3), (4, 5), (6, 7)])
>>> ccs = list(self.connected_components())
>>> result = 'ccs = {}'.format(ub.urepr(ccs, nl=0))
>>> print(result)
ccs = [{1, 2, 3}, {4, 5}, {6, 7}]
component_labels()[source]
_cut(u, v)[source]

Decremental connectivity (slow)

_union(u, v)[source]

Incremental connectivity (fast)

_add_node(n)[source]
_remove_node(n)[source]
add_edge(u, v, **attr)[source]

Example

>>> self = DynConnGraph()
>>> self.add_edges_from([(1, 2), (2, 3), (4, 5), (6, 7), (7, 4)])
>>> assert self._ccs == {1: {1, 2, 3}, 4: {4, 5, 6, 7}}
>>> self.add_edge(1, 5)
>>> assert self._ccs == {1: {1, 2, 3, 4, 5, 6, 7}}
add_edges_from(ebunch, **attr)[source]
add_node(n, **attr)[source]
add_nodes_from(nodes, **attr)[source]
remove_edge(u, v)[source]

Example

>>> self = DynConnGraph()
>>> self.add_edges_from([(1, 2), (2, 3), (4, 5), (6, 7), (7, 4)])
>>> assert self._ccs == {1: {1, 2, 3}, 4: {4, 5, 6, 7}}
>>> self.add_edge(1, 5)
>>> assert self._ccs == {1: {1, 2, 3, 4, 5, 6, 7}}
>>> self.remove_edge(1, 5)
>>> assert self._ccs == {1: {1, 2, 3}, 4: {4, 5, 6, 7}}
remove_edges_from(ebunch)[source]
remove_nodes_from(nodes)[source]
remove_node(n)[source]

Example

>>> self = DynConnGraph()
>>> self.add_edges_from([(1, 2), (2, 3), (4, 5), (5, 6), (6, 7), (7, 8), (8, 9)])
>>> assert self._ccs == {1: {1, 2, 3}, 4: {4, 5, 6, 7, 8, 9}}
>>> self.remove_node(2)
>>> assert self._ccs == {1: {1}, 3: {3}, 4: {4, 5, 6, 7, 8, 9}}
>>> self.remove_node(7)
>>> assert self._ccs == {1: {1}, 3: {3}, 4: {4, 5, 6}, 8: {8, 9}}
subgraph(nbunch, dynamic=False)[source]
class graphid.util.GraphHelperMixin[source]

Bases: NiceRepr

Ensures that we always return edges in a consistent order

has_nodes(nodes)[source]
has_edges(edges)[source]
edges(nbunch=None, data=False, default=None)[source]
class graphid.util.NiceGraph(incoming_graph_data=None, **attr)[source]

Bases: Graph, GraphHelperMixin

Initialize a graph with edges, name, or graph attributes.

Parameters:
  • incoming_graph_data (input graph (optional, default: None)) – Data to initialize graph. If None (default) an empty graph is created. The data can be an edge list, or any NetworkX graph object. If the corresponding optional Python packages are installed the data can also be a 2D NumPy array, a SciPy sparse array, or a PyGraphviz graph.

  • attr (keyword arguments, optional (default= no attributes)) – Attributes to add to graph as key=value pairs.

See also

convert

Examples

>>> G = nx.Graph()  # or DiGraph, MultiGraph, MultiDiGraph, etc
>>> G = nx.Graph(name="my graph")
>>> e = [(1, 2), (2, 3), (3, 4)]  # list of edges
>>> G = nx.Graph(e)

Arbitrary graph attribute pairs (key=value) may be assigned

>>> G = nx.Graph(e, day="Friday")
>>> G.graph
{'day': 'Friday'}
class graphid.util.nx_UnionFind(elements=None)[source]

Bases: object

Based off code in networkx

clear()[source]
rebalance(elements=None)[source]
to_sets()[source]
union(*objects)[source]

Find the sets containing the objects and merge them all.

remove_entire_cc(elements)[source]
add_element(x)[source]
add_elements(elements)[source]
graphid.util.assert_raises(ex_type, func, *args, **kwargs)[source]

Checks that a function raises an error when given specific arguments.

Parameters:
  • ex_type (Exception) – exception type

  • func (callable) – live python function

Example

>>> ex_type = AssertionError
>>> func = len
>>> assert_raises(ex_type, assert_raises, ex_type, func, [])
>>> assert_raises(ValueError, [].index, 0)
graphid.util.bfs_conditional(G, source, reverse=False, keys=True, data=False, yield_nodes=True, yield_if=None, continue_if=None, visited_nodes=None, yield_source=False)[source]

Produce edges in a breadth-first-search starting at source, but only return nodes that satisfiy a condition, and only iterate past a node if it satisfies a different condition.

conditions are callables that take (G, child, edge) and return true or false

Example

>>> import networkx as nx
>>> G = nx.Graph()
>>> G.add_edges_from([(1, 2), (1, 3), (2, 3), (2, 4)])
>>> continue_if = lambda G, child, edge: True
>>> result = list(bfs_conditional(G, 1, yield_nodes=False))
>>> print(result)
[(1, 2), (1, 3), (2, 1), (2, 3), (2, 4), (3, 1), (3, 2), (4, 2)]

Example

>>> import networkx as nx
>>> G = nx.Graph()
>>> continue_if = lambda G, child, edge: (child % 2 == 0)
>>> yield_if = lambda G, child, edge: (child % 2 == 1)
>>> G.add_edges_from([(0, 1), (1, 3), (3, 5), (5, 10),
>>>                   (4, 3), (3, 6),
>>>                   (0, 2), (2, 4), (4, 6), (6, 10)])
>>> result = list(bfs_conditional(G, 0, continue_if=continue_if,
>>>                                  yield_if=yield_if))
>>> print(result)
[1, 3, 5]
graphid.util.complement_edges(G)[source]
graphid.util.demodata_bridge()[source]
graphid.util.demodata_tarjan_bridge()[source]

Example

>>> from graphid import util
>>> G = demodata_tarjan_bridge()
>>> # xdoc: +REQUIRES(--show)
>>> util.show_nx(G)
>>> util.show_if_requested()
_images/fig_graphid_util_demodata_tarjan_bridge_002.jpeg
graphid.util.diag_product(s1, s2)[source]

Does product, but iterates over the diagonal first

graphid.util.dict_take_column(list_of_dicts_, colkey, default=None)[source]
graphid.util.e_(u, v)[source]
graphid.util.edge_df(graph, edges, ignore=None)[source]
graphid.util.edges_between(graph, nodes1, nodes2=None, assume_disjoint=False, assume_dense=True)[source]

Get edges between two components or within a single component

Parameters:
  • graph (nx.Graph) – the graph

  • nodes1 (set) – list of nodes

  • nodes2 (set) – if None it is equivlanet to nodes2=nodes1 (default=None)

  • assume_disjoint (bool) – skips expensive check to ensure edges arnt returned twice (default=False)

Example

>>> edges = [
>>>     (1, 2), (2, 3), (3, 4), (4, 1), (4, 3),  # cc 1234
>>>     (1, 5), (7, 2), (5, 1),  # cc 567 / 5678
>>>     (7, 5), (5, 6), (8, 7),
>>> ]
>>> digraph = nx.DiGraph(edges)
>>> graph = nx.Graph(edges)
>>> nodes1 = [1, 2, 3, 4]
>>> nodes2 = [5, 6, 7]
>>> n2 = sorted(edges_between(graph, nodes1, nodes2))
>>> n4 = sorted(edges_between(graph, nodes1))
>>> n5 = sorted(edges_between(graph, nodes1, nodes1))
>>> n1 = sorted(edges_between(digraph, nodes1, nodes2))
>>> n3 = sorted(edges_between(digraph, nodes1))
>>> print('n2 == %r' % (n2,))
>>> print('n4 == %r' % (n4,))
>>> print('n5 == %r' % (n5,))
>>> print('n1 == %r' % (n1,))
>>> print('n3 == %r' % (n3,))
>>> assert n2 == ([(1, 5), (2, 7)]), '2'
>>> assert n4 == ([(1, 2), (1, 4), (2, 3), (3, 4)]), '4'
>>> assert n5 == ([(1, 2), (1, 4), (2, 3), (3, 4)]), '5'
>>> assert n1 == ([(1, 5), (5, 1), (7, 2)]), '1'
>>> assert n3 == ([(1, 2), (2, 3), (3, 4), (4, 1), (4, 3)]), '3'
>>> n6 = sorted(edges_between(digraph, nodes1 + [6], nodes2 + [1, 2], assume_dense=False))
>>> print('n6 = %r' % (n6,))
>>> n6 = sorted(edges_between(digraph, nodes1 + [6], nodes2 + [1, 2], assume_dense=True))
>>> print('n6 = %r' % (n6,))
>>> assert n6 == ([(1, 2), (1, 5), (2, 3), (4, 1), (5, 1), (5, 6), (7, 2)]), '6'
graphid.util.edges_cross(graph, nodes1, nodes2)[source]

Finds edges between two sets of disjoint nodes. Running time is O(len(nodes1) * len(nodes2))

Parameters:
  • graph (nx.Graph) – an undirected graph

  • nodes1 (set) – set of nodes disjoint from nodes2

  • nodes2 (set) – set of nodes disjoint from nodes1.

graphid.util.edges_inside(graph, nodes)[source]

Finds edges within a set of nodes Running time is O(len(nodes) ** 2)

Parameters:
  • graph (nx.Graph) – an undirected graph

  • nodes1 (set) – a set of nodes

graphid.util.edges_outgoing(graph, nodes)[source]

Finds edges leaving a set of nodes. Average running time is O(len(nodes) * ave_degree(nodes)) Worst case running time is O(G.number_of_edges()).

Parameters:
  • graph (nx.Graph) – a graph

  • nodes (set) – set of nodes

Example

>>> G = demodata_bridge()
>>> nodes = {1, 2, 3, 4}
>>> outgoing = edges_outgoing(G, nodes)
>>> assert outgoing == {(3, 5), (4, 8)}
graphid.util.ensure_multi_index(index, names)[source]
graphid.util.graph_info(graph, ignore=None, stats=False, verbose=False)[source]
graphid.util.group_name_edges(g, node_to_label)[source]
graphid.util.is_complete(G, self_loops=False)[source]
graphid.util.is_k_edge_connected(G, k)[source]
graphid.util.itake_column(list_, colx)[source]

iterator version of get_list_column

graphid.util.k_edge_augmentation(G, k, avail=None, partial=False)[source]
graphid.util.list_roll(list_, n)[source]

Like numpy.roll for python lists

Parameters:
  • list_ (list)

  • n (int)

Return type:

list

References

http://stackoverflow.com/questions/9457832/python-list-rotation

Example

>>> list_ = [1, 2, 3, 4, 5]
>>> n = 2
>>> result = list_roll(list_, n)
>>> print(result)
[4, 5, 1, 2, 3]
graphid.util.nx_delete_None_edge_attr(graph, edges=None)[source]
graphid.util.nx_delete_None_node_attr(graph, nodes=None)[source]
graphid.util.nx_delete_edge_attr(graph, name, edges=None)[source]

Removes an attributes from specific edges in the graph

Doctest

>>> G = nx.karate_club_graph()
>>> nx.set_edge_attributes(G, name='spam', values='eggs')
>>> nx.set_edge_attributes(G, name='foo', values='bar')
>>> assert len(nx.get_edge_attributes(G, 'spam')) == 78
>>> assert len(nx.get_edge_attributes(G, 'foo')) == 78
>>> nx_delete_edge_attr(G, ['spam', 'foo'], edges=[(1, 2)])
>>> assert len(nx.get_edge_attributes(G, 'spam')) == 77
>>> assert len(nx.get_edge_attributes(G, 'foo')) == 77
>>> nx_delete_edge_attr(G, ['spam'])
>>> assert len(nx.get_edge_attributes(G, 'spam')) == 0
>>> assert len(nx.get_edge_attributes(G, 'foo')) == 77

Doctest

>>> G = nx.MultiGraph()
>>> G.add_edges_from([(1, 2), (2, 3), (3, 4), (4, 5), (4, 5), (1, 2)])
>>> nx.set_edge_attributes(G, name='spam', values='eggs')
>>> nx.set_edge_attributes(G, name='foo', values='bar')
>>> assert len(nx.get_edge_attributes(G, 'spam')) == 6
>>> assert len(nx.get_edge_attributes(G, 'foo')) == 6
>>> nx_delete_edge_attr(G, ['spam', 'foo'], edges=[(1, 2, 0)])
>>> assert len(nx.get_edge_attributes(G, 'spam')) == 5
>>> assert len(nx.get_edge_attributes(G, 'foo')) == 5
>>> nx_delete_edge_attr(G, ['spam'])
>>> assert len(nx.get_edge_attributes(G, 'spam')) == 0
>>> assert len(nx.get_edge_attributes(G, 'foo')) == 5
graphid.util.nx_delete_node_attr(graph, name, nodes=None)[source]

Removes node attributes

Doctest

>>> G = nx.karate_club_graph()
>>> nx.set_node_attributes(G, name='foo', values='bar')
>>> datas = nx.get_node_attributes(G, 'club')
>>> assert len(nx.get_node_attributes(G, 'club')) == 34
>>> assert len(nx.get_node_attributes(G, 'foo')) == 34
>>> nx_delete_node_attr(G, ['club', 'foo'], nodes=[1, 2])
>>> assert len(nx.get_node_attributes(G, 'club')) == 32
>>> assert len(nx.get_node_attributes(G, 'foo')) == 32
>>> nx_delete_node_attr(G, ['club'])
>>> assert len(nx.get_node_attributes(G, 'club')) == 0
>>> assert len(nx.get_node_attributes(G, 'foo')) == 32
graphid.util.nx_edges(graph, keys=False, data=False)[source]
graphid.util.nx_gen_edge_attrs(G, key, edges=None, default=NoParam, on_missing='error', on_keyerr='default')[source]

Improved generator version of nx.get_edge_attributes

Parameters:
  • on_missing (str) – Strategy for handling nodes missing from G. Can be {‘error’, ‘default’, ‘filter’}. defaults to ‘error’. is on_missing is not error, then we allow any edge even if the endpoints are not in the graph.

  • on_keyerr (str) – Strategy for handling keys missing from node dicts. Can be {‘error’, ‘default’, ‘filter’}. defaults to ‘default’ if default is specified, otherwise defaults to ‘error’.

CommandLine

python -m graphid.util.nx_utils nx_gen_edge_attrs

Example

>>> from graphid import util
>>> from functools import partial
>>> G = nx.Graph([(1, 2), (2, 3), (3, 4)])
>>> nx.set_edge_attributes(G, name='part', values={(1, 2): 'bar', (2, 3): 'baz'})
>>> edges = [(1, 2), (2, 3), (3, 4), (4, 5)]
>>> func = partial(nx_gen_edge_attrs, G, 'part', default=None)
>>> #
>>> assert len(list(func(on_missing='error', on_keyerr='default'))) == 3
>>> assert len(list(func(on_missing='error', on_keyerr='filter'))) == 2
>>> util.assert_raises(KeyError, list, func(on_missing='error', on_keyerr='error'))
>>> #
>>> assert len(list(func(edges, on_missing='filter', on_keyerr='default'))) == 3
>>> assert len(list(func(edges, on_missing='filter', on_keyerr='filter'))) == 2
>>> util.assert_raises(KeyError, list, func(edges, on_missing='filter', on_keyerr='error'))
>>> #
>>> assert len(list(func(edges, on_missing='default', on_keyerr='default'))) == 4
>>> assert len(list(func(edges, on_missing='default', on_keyerr='filter'))) == 2
>>> util.assert_raises(KeyError, list, func(edges, on_missing='default', on_keyerr='error'))
graphid.util.nx_gen_edge_values(G, key, edges=None, default=NoParam, on_missing='error', on_keyerr='default')[source]

Generates attributes values of specific edges

Parameters:
  • on_missing (str) – Strategy for handling nodes missing from G. Can be {‘error’, ‘default’}. defaults to ‘error’.

  • on_keyerr (str) – Strategy for handling keys missing from node dicts. Can be {‘error’, ‘default’}. defaults to ‘default’ if default is specified, otherwise defaults to ‘error’.

graphid.util.nx_gen_node_attrs(G, key, nodes=None, default=NoParam, on_missing='error', on_keyerr='default')[source]

Improved generator version of nx.get_node_attributes

Parameters:
  • on_missing (str) – Strategy for handling nodes missing from G. Can be {‘error’, ‘default’, ‘filter’}. defaults to ‘error’.

  • on_keyerr (str) – Strategy for handling keys missing from node dicts. Can be {‘error’, ‘default’, ‘filter’}. defaults to ‘default’ if default is specified, otherwise defaults to ‘error’.

Notes

strategies are:

error - raises an error if key or node does not exist default - returns node, but uses value specified by default filter - skips the node

Example

>>> # ENABLE_DOCTEST
>>> from graphid import util
>>> G = nx.Graph([(1, 2), (2, 3)])
>>> nx.set_node_attributes(G, name='part', values={1: 'bar', 3: 'baz'})
>>> nodes = [1, 2, 3, 4]
>>> #
>>> assert len(list(nx_gen_node_attrs(G, 'part', default=None, on_missing='error', on_keyerr='default'))) == 3
>>> assert len(list(nx_gen_node_attrs(G, 'part', default=None, on_missing='error', on_keyerr='filter'))) == 2
>>> assert_raises(KeyError, list, nx_gen_node_attrs(G, 'part', on_missing='error', on_keyerr='error'))
>>> #
>>> assert len(list(nx_gen_node_attrs(G, 'part', nodes, default=None, on_missing='filter', on_keyerr='default'))) == 3
>>> assert len(list(nx_gen_node_attrs(G, 'part', nodes, default=None, on_missing='filter', on_keyerr='filter'))) == 2
>>> assert_raises(KeyError, list, nx_gen_node_attrs(G, 'part', nodes, on_missing='filter', on_keyerr='error'))
>>> #
>>> assert len(list(nx_gen_node_attrs(G, 'part', nodes, default=None, on_missing='default', on_keyerr='default'))) == 4
>>> assert len(list(nx_gen_node_attrs(G, 'part', nodes, default=None, on_missing='default', on_keyerr='filter'))) == 2
>>> assert_raises(KeyError, list, nx_gen_node_attrs(G, 'part', nodes, on_missing='default', on_keyerr='error'))

Example

>>> # DISABLE_DOCTEST
>>> # ALL CASES
>>> from graphid import util
>>> G = nx.Graph([(1, 2), (2, 3)])
>>> nx.set_node_attributes(G, name='full', values={1: 'A', 2: 'B', 3: 'C'})
>>> nx.set_node_attributes(G, name='part', values={1: 'bar', 3: 'baz'})
>>> nodes = [1, 2, 3, 4]
>>> attrs = dict(nx_gen_node_attrs(G, 'full'))
>>> input_grid = {
>>>     'nodes': [None, (1, 2, 3, 4)],
>>>     'key': ['part', 'full'],
>>>     'default': [ub.NoParam, None],
>>> }
>>> inputs = util.all_dict_combinations(input_grid)
>>> kw_grid = {
>>>     'on_missing': ['error', 'default', 'filter'],
>>>     'on_keyerr': ['error', 'default', 'filter'],
>>> }
>>> kws = util.all_dict_combinations(kw_grid)
>>> for in_ in inputs:
>>>     for kw in kws:
>>>         kw2 = ub.dict_union(kw, in_)
>>>         #print(kw2)
>>>         on_missing = kw['on_missing']
>>>         on_keyerr = kw['on_keyerr']
>>>         if on_keyerr == 'default' and in_['default'] is ub.NoParam:
>>>             on_keyerr = 'error'
>>>         will_miss = False
>>>         will_keyerr = False
>>>         if on_missing == 'error':
>>>             if in_['key'] == 'part' and in_['nodes'] is not None:
>>>                 will_miss = True
>>>             if in_['key'] == 'full' and in_['nodes'] is not None:
>>>                 will_miss = True
>>>         if on_keyerr == 'error':
>>>             if in_['key'] == 'part':
>>>                 will_keyerr = True
>>>             if on_missing == 'default':
>>>                 if in_['key'] == 'full' and in_['nodes'] is not None:
>>>                     will_keyerr = True
>>>         want_error = will_miss or will_keyerr
>>>         gen = nx_gen_node_attrs(G, **kw2)
>>>         try:
>>>             attrs = list(gen)
>>>         except KeyError:
>>>             if not want_error:
>>>                 raise AssertionError('should not have errored')
>>>         else:
>>>             if want_error:
>>>                 raise AssertionError('should have errored')
graphid.util.nx_gen_node_values(G, key, nodes, default=NoParam)[source]

Generates attributes values of specific nodes

graphid.util.nx_node_dict(G)[source]
graphid.util.random_k_edge_connected_graph(size, k, p=0.1, rng=None)[source]

Super hacky way of getting a random k-connected graph

Example

>>> from graphid import util
>>> size, k, p = 25, 3, .1
>>> rng = util.ensure_rng(0)
>>> gs = []
>>> for x in range(4):
>>>     G = random_k_edge_connected_graph(size, k, p, rng)
>>>     gs.append(G)
>>> # xdoc: +REQUIRES(--show)
>>> pnum_ = util.PlotNums(nRows=2, nSubplots=len(gs))
>>> fnum = 1
>>> for g in gs:
>>>     util.show_nx(g, fnum=fnum, pnum=pnum_())
_images/fig_graphid_util_random_k_edge_connected_graph_002.jpeg
graphid.util.take_column(list_, colx)[source]

accepts a list of (indexables) and returns a list of indexables can also return a list of list of indexables if colx is a list

Parameters:
  • list_ (list) – list of lists

  • colx (int or list) – index or key in each sublist get item

Returns:

list of selected items

Return type:

list

Example0:
>>> list_ = [['a', 'b'], ['c', 'd']]
>>> colx = 0
>>> result = take_column(list_, colx)
>>> result = ub.urepr(result, nl=False)
>>> print(result)
['a', 'c']
Example1:
>>> list_ = [['a', 'b'], ['c', 'd']]
>>> colx = [1, 0]
>>> result = take_column(list_, colx)
>>> result = ub.urepr(result, nl=False)
>>> print(result)
[['b', 'a'], ['d', 'c']]
Example2:
>>> list_ = [{'spam': 'EGGS', 'ham': 'SPAM'}, {'spam': 'JAM', 'ham': 'PRAM'}]
>>> # colx can be a key or list of keys as well
>>> colx = ['spam']
>>> result = take_column(list_, colx)
>>> result = ub.urepr(result, nl=False)
>>> print(result)
[['EGGS'], ['JAM']]
class graphid.util.PriorityQueue(items=None, ascending=True)[source]

Bases: NiceRepr

abstracted priority queue for our needs

Combines properties of dicts and heaps Uses a heap for fast minimum/maximum value search Uses a dict for fast read only operations

References

http://code.activestate.com/recipes/522995-priority-dict-a-priority-queue-with-updatable-prio/ https://stackoverflow.com/questions/33024215/built-in-max-heap-api-in-python

Example

>>> items = dict(a=42, b=29, c=40, d=95, e=10)
>>> self = PriorityQueue(items)
>>> print(self)
>>> assert len(self) == 5
>>> print(self.pop())
>>> assert len(self) == 4
>>> print(self.pop())
>>> assert len(self) == 3
>>> print(self.pop())
>>> print(self.pop())
>>> print(self.pop())
>>> assert len(self) == 0

Example

>>> items = dict(a=(1.0, (2, 3)), b=(1.0, (1, 2)), c=(.9, (3, 2)))
>>> self = PriorityQueue(items)
_rebuild()[source]
get(key, default=None)[source]
clear()[source]
update(items)[source]
delete_items(key_list)[source]
peek()[source]

Peek at the next item in the queue

peek_many(n)[source]

Actually this can be quite inefficient

Example

>>> from graphid import util
>>> items = list(zip(range(256), range(256)))
>>> n = 32
>>> util.shuffle(items)
>>> self = PriorityQueue(items, ascending=False)
>>> self.peek_many(56)
pop_many(n)[source]
pop(key=NoParam, default=NoParam)[source]

Pop the next item off the queue

class graphid.util.Boxes(data, format='xywh')[source]

Bases: NiceRepr

Converts boxes between different formats as long as the last dimension contains 4 coordinates and the format is specified.

This is a convinience class, and should not not store the data for very long. The general idiom should be create class, convert data, and then get the raw data and let the class be garbage collected. This will help ensure that your code is portable and understandable if this class is not available.

Example

>>> # xdoctest: +IGNORE_WHITESPACE
>>> Boxes([25, 30, 15, 10], 'xywh')
<Boxes(xywh, array([25, 30, 15, 10]))>
>>> Boxes([25, 30, 15, 10], 'xywh').to_xywh()
<Boxes(xywh, array([25, 30, 15, 10]))>
>>> Boxes([25, 30, 15, 10], 'xywh').to_cxywh()
<Boxes(cxywh, array([32.5, 35. , 15. , 10. ]))>
>>> Boxes([25, 30, 15, 10], 'xywh').to_tlbr()
<Boxes(tlbr, array([25, 30, 40, 40]))>
>>> Boxes([25, 30, 15, 10], 'xywh').scale(2).to_tlbr()
<Boxes(tlbr, array([50., 60., 80., 80.]))>

Example

>>> datas = [
>>>     [1, 2, 3, 4],
>>>     [[1, 2, 3, 4], [4, 5, 6, 7]],
>>>     [[[1, 2, 3, 4], [4, 5, 6, 7]]],
>>> ]
>>> formats = ['xywh', 'cxywh', 'tlbr']
>>> for format1 in formats:
>>>     for data in datas:
>>>         self = box1 = Boxes(data, format1)
>>>         for format2 in formats:
>>>             box2 = box1.toformat(format2)
>>>             back = box2.toformat(format1)
>>>             assert box1 == back
classmethod random(num=1, scale=1.0, format='xywh', rng=None)[source]

Makes random boxes

Example

>>> # xdoctest: +IGNORE_WHITESPACE
>>> Boxes.random(3, rng=0, scale=100)
<Boxes(xywh,
    array([[27, 35, 30, 27],
           [21, 32, 21, 44],
           [48, 19, 39, 26]]))>
copy()[source]
scale(factor)[source]

works with tlbr, cxywh, xywh, xy, or wh formats

Example

>>> # xdoctest: +IGNORE_WHITESPACE
>>> Boxes(np.array([1, 1, 10, 10])).scale(2).data
array([ 2.,  2., 20., 20.])
>>> Boxes(np.array([[1, 1, 10, 10]])).scale((2, .5)).data
array([[ 2. ,  0.5, 20. ,  5. ]])
>>> Boxes(np.array([[10, 10]])).scale(.5).data
array([[5., 5.]])
shift(amount)[source]

Example

>>> # xdoctest: +IGNORE_WHITESPACE
>>> Boxes([25, 30, 15, 10], 'xywh').shift(10)
<Boxes(xywh, array([35., 40., 15., 10.]))>
>>> Boxes([25, 30, 15, 10], 'xywh').shift((10, 0))
<Boxes(xywh, array([35., 30., 15., 10.]))>
>>> Boxes([25, 30, 15, 10], 'tlbr').shift((10, 5))
<Boxes(tlbr, array([35., 35., 25., 15.]))>
property center
property shape
property area
property components
classmethod _cat(datas)[source]
toformat(format, copy=True)[source]
to_extent(copy=True)[source]
to_xywh(copy=True)[source]
to_cxywh(copy=True)[source]
to_tlbr(copy=True)[source]
clip(x_min, y_min, x_max, y_max, inplace=False)[source]

Clip boxes to image boundaries. If box is in tlbr format, inplace operation is an option.

Example

>>> # xdoctest: +IGNORE_WHITESPACE
>>> boxes = Boxes(np.array([[-10, -10, 120, 120], [1, -2, 30, 50]]), 'tlbr')
>>> clipped = boxes.clip(0, 0, 110, 100, inplace=False)
>>> assert np.any(boxes.data != clipped.data)
>>> clipped2 = boxes.clip(0, 0, 110, 100, inplace=True)
>>> assert clipped2.data is boxes.data
>>> assert np.all(clipped2.data == clipped.data)
>>> print(clipped)
<Boxes(tlbr,
    array([[  0,   0, 110, 100],
           [  1,   0,  30,  50]]))>
transpose()[source]
compress(flags, axis=0, inplace=False)[source]

Filters boxes based on a boolean criterion

Example

>>> self = Boxes([[25, 30, 15, 10]], 'tlbr')
>>> flags = [False]
graphid.util.box_ious_py(boxes1, boxes2, bias=1)[source]

This is the fastest python implementation of bbox_ious I found

graphid.util.grab_test_imgpath(key='astro.png', allow_external=True, verbose=True)[source]

Gets paths to standard / fun test images. Downloads them if they dont exits

Parameters:
  • key (str) – one of the standard test images, e.g. astro.png, carl.jpg, …

  • allow_external (bool) – if True you can specify existing fpaths

Returns:

testimg_fpath - filepath to the downloaded or cached test image.

Return type:

str

Example

>>> testimg_fpath = grab_test_imgpath('carl.jpg')
>>> assert exists(testimg_fpath)
class graphid.util.GRAPHVIZ_KEYS[source]

Bases: object

N = {'URL', 'area', 'color', 'colorscheme', 'comment', 'distortion', 'fillcolor', 'fixedsize', 'fontcolor', 'fontname', 'fontsize', 'gradientangle', 'group', 'height', 'href', 'id', 'image', 'imagepos', 'imagescale', 'label', 'labelloc', 'layer', 'margin', 'nojustify', 'ordering', 'orientation', 'penwidth', 'peripheries', 'pin', 'pos', 'rects', 'regular', 'root', 'samplepoints', 'shape', 'shapefile', 'showboxes', 'sides', 'skew', 'sortv', 'style', 'target', 'tooltip', 'vertices', 'width', 'xlabel', 'xlp', 'z'}
E = {'URL', 'arrowhead', 'arrowsize', 'arrowtail', 'color', 'colorscheme', 'comment', 'constraint', 'decorate', 'dir', 'edgeURL', 'edgehref', 'edgetarget', 'edgetooltip', 'fillcolor', 'fontcolor', 'fontname', 'fontsize', 'headURL', 'head_lp', 'headclip', 'headhref', 'headlabel', 'headport', 'headtarget', 'headtooltip', 'href', 'id', 'label', 'labelURL', 'labelangle', 'labeldistance', 'labelfloat', 'labelfontcolor', 'labelfontname', 'labelfontsize', 'labelhref', 'labeltarget', 'labeltooltip', 'layer', 'len', 'lhead', 'lp', 'ltail', 'minlen', 'nojustify', 'penwidth', 'pos', 'samehead', 'sametail', 'showboxes', 'style', 'tailURL', 'tail_lp', 'tailclip', 'tailhref', 'taillabel', 'tailport', 'tailtarget', 'tailtooltip', 'target', 'tooltip', 'weight', 'xlabel', 'xlp'}
G = {'Damping', 'K', 'URL', '_background', 'bb', 'bgcolor', 'center', 'charset', 'clusterrank', 'colorscheme', 'comment', 'compound', 'concentrate', 'defaultdist', 'dim', 'dimen', 'diredgeconstraints', 'dpi', 'epsilon', 'esep', 'fontcolor', 'fontname', 'fontnames', 'fontpath', 'fontsize', 'forcelabels', 'gradientangle', 'href', 'id', 'imagepath', 'inputscale', 'label', 'label_scheme', 'labeljust', 'labelloc', 'landscape', 'layerlistsep', 'layers', 'layerselect', 'layersep', 'layout', 'levels', 'levelsgap', 'lheight', 'lp', 'lwidth', 'margin', 'maxiter', 'mclimit', 'mindist', 'mode', 'model', 'mosek', 'newrank', 'nodesep', 'nojustify', 'normalize', 'notranslate', 'nslimit\nnslimit1', 'ordering', 'orientation', 'outputorder', 'overlap', 'overlap_scaling', 'overlap_shrink', 'pack', 'packmode', 'pad', 'page', 'pagedir', 'quadtree', 'quantum', 'rankdir', 'ranksep', 'ratio', 'remincross', 'repulsiveforce', 'resolution', 'root', 'rotate', 'rotation', 'scale', 'searchsize', 'sep', 'showboxes', 'size', 'smoothing', 'sortv', 'splines', 'start', 'style', 'stylesheet', 'target', 'truecolor', 'viewport', 'voro_margin', 'xdotversion'}
graphid.util.apply_graph_layout_attrs(graph, layout_info)[source]
graphid.util.bbox_from_extent(extent)[source]
Parameters:

extent (ndarray) – tl_x, br_x, tl_y, br_y

Returns:

tl_x, tl_y, w, h

Return type:

bbox (ndarray)

Example

>>> extent = [0, 10, 0, 10]
>>> bbox = bbox_from_extent(extent)
>>> print('bbox = {}'.format(ub.urepr(list(bbox), nl=0)))
bbox = [0, 0, 10, 10]
graphid.util.draw_network2(graph, layout_info, ax, as_directed=None, hacknoedge=False, hacknode=False, verbose=None, **kwargs)[source]
Kwargs:

use_image, arrow_width, fontsize, fontweight, fontname, fontfamilty, fontproperties

fancy way to draw networkx graphs without directly using networkx

graphid.util.dump_nx_ondisk(graph, fpath)[source]
graphid.util.ensure_nonhex_color(orig_color)[source]
graphid.util.get_explicit_graph(graph)[source]
Parameters:

graph (nx.Graph)

graphid.util.get_graph_bounding_box(graph)[source]

Example

>>> # xdoctest: +REQUIRES(module:pygraphviz)
>>> graph = nx.path_graph([1, 2, 3, 4])
>>> nx_agraph_layout(graph, inplace=True)
>>> bbox = get_graph_bounding_box(graph)
>>> print(ub.urepr(bbox, nl=0))
[0.0, 0.0, 54.0, 252.0]
graphid.util.get_nx_layout(graph, layout, layoutkw=None, verbose=None)[source]
graphid.util.get_pointset_extents(pts)[source]
graphid.util.make_agraph(graph_)[source]
graphid.util.netx_draw_images_at_positions(img_list, pos_list, size_list, color_list, framewidth_list)[source]

Overlays images on a networkx graph

References

https://gist.github.com/shobhit/3236373 http://matplotlib.org/examples/pylab_examples/demo_annotation_box.html http://stackoverflow.com/questions/11487797/mpl-overlay-small-image http://matplotlib.org/api/text_api.html http://matplotlib.org/api/offsetbox_api.html

graphid.util.nx_agraph_layout(orig_graph, inplace=False, verbose=None, return_agraph=False, groupby=None, **layoutkw)[source]

Uses graphviz and custom code to determine position attributes of nodes and edges.

Parameters:

groupby (str) – if not None then nodes will be grouped by this attributes and groups will be layed out separately and then stacked together in a grid

References

http://www.graphviz.org/content/attrs http://www.graphviz.org/doc/info/attrs.html

CommandLine

python -m graphid.util.util_graphviz nx_agraph_layout --show

Doctest

>>> # xdoctest: +REQUIRES(module:pygraphviz)
>>> from graphid.util.util_graphviz import *  # NOQA
>>> import networkx as nx
>>> import itertools as it
>>> from graphid import util
>>> n, s = 9, 4
>>> offsets = list(range(0, (1 + n) * s, s))
>>> node_groups = [list(map(str, range(*o))) for o in ub.iter_window(offsets, 2)]
>>> edge_groups = [it.combinations(nodes, 2) for nodes in node_groups]
>>> graph = nx.Graph()
>>> [graph.add_nodes_from(nodes) for nodes in node_groups]
>>> [graph.add_edges_from(edges) for edges in edge_groups]
>>> for count, nodes in enumerate(node_groups):
...     nx.set_node_attributes(graph, name='id', values=ub.dzip(nodes, [count]))
>>> layoutkw = dict(prog='neato')
>>> graph1, info1 = nx_agraph_layout(graph.copy(), inplace=True, groupby='id', **layoutkw)
>>> graph2, info2 = nx_agraph_layout(graph.copy(), inplace=True, **layoutkw)
>>> graph3, _ = nx_agraph_layout(graph1.copy(), inplace=True, **layoutkw)
>>> nx.set_node_attributes(graph1, name='pin', values='true')
>>> graph4, _ = nx_agraph_layout(graph1.copy(), inplace=True, **layoutkw)
>>> # xdoc: +REQUIRES(--show)
>>> util.show_nx(graph1, layout='custom', pnum=(2, 2, 1), fnum=1)
>>> util.show_nx(graph2, layout='custom', pnum=(2, 2, 2), fnum=1)
>>> util.show_nx(graph3, layout='custom', pnum=(2, 2, 3), fnum=1)
>>> util.show_nx(graph4, layout='custom', pnum=(2, 2, 4), fnum=1)
>>> util.show_if_requested()
>>> g1pos = nx.get_node_attributes(graph1, 'pos')['1']
>>> g4pos = nx.get_node_attributes(graph4, 'pos')['1']
>>> g2pos = nx.get_node_attributes(graph2, 'pos')['1']
>>> g3pos = nx.get_node_attributes(graph3, 'pos')['1']
>>> print('g1pos = {!r}'.format(g1pos))
>>> print('g4pos = {!r}'.format(g4pos))
>>> print('g2pos = {!r}'.format(g2pos))
>>> print('g3pos = {!r}'.format(g3pos))
>>> assert np.all(g1pos == g4pos), 'points between 1 and 4 were pinned so they should be equal'
>>> #assert np.all(g2pos != g3pos), 'points between 2 and 3 were not pinned, so they should be different'

assert np.all(nx.get_node_attributes(graph1, ‘pos’)[‘1’] == nx.get_node_attributes(graph4, ‘pos’)[‘1’]) assert np.all(nx.get_node_attributes(graph2, ‘pos’)[‘1’] == nx.get_node_attributes(graph3, ‘pos’)[‘1’])

graphid.util.nx_ensure_agraph_color(graph)[source]

changes colors to hex strings on graph attrs

graphid.util.parse_aedge_layout_attrs(aedge, translation=None)[source]

parse grpahviz splineType

graphid.util.parse_anode_layout_attrs(anode)[source]
graphid.util.parse_html_graphviz_attrs()[source]
graphid.util.parse_point(ptstr)[source]
graphid.util.patch_pygraphviz()[source]

Hacks around a python3 problem in 1.3.1 of pygraphviz

graphid.util.show_nx(graph, with_labels=True, fnum=None, pnum=None, layout='agraph', ax=None, pos=None, img_dict=None, title=None, layoutkw=None, verbose=None, **kwargs)[source]
Parameters:
  • graph (networkx.Graph)

  • with_labels (bool) – (default = True)

  • fnum (int) – figure number(default = None)

  • pnum (tuple) – plot number(default = None)

  • layout (str) – (default = ‘agraph’)

  • ax (None) – (default = None)

  • pos (None) – (default = None)

  • img_dict (dict) – (default = None)

  • title (str) – (default = None)

  • layoutkw (None) – (default = None)

  • verbose (bool) – verbosity flag(default = None)

Kwargs:

use_image, framewidth, modify_ax, as_directed, hacknoedge, hacknode, arrow_width, fontsize, fontweight, fontname, fontfamilty, fontproperties

CommandLine

python -m graphid.util.util_graphviz show_nx --show

Example

>>> # xdoctest: +REQUIRES(module:pygraphviz)
>>> from graphid.util.util_graphviz import *  # NOQA
>>> graph = nx.DiGraph()
>>> graph.add_nodes_from(['a', 'b', 'c', 'd'])
>>> graph.add_edges_from({'a': 'b', 'b': 'c', 'b': 'd', 'c': 'd'}.items())
>>> nx.set_node_attributes(graph, name='shape', values='rect')
>>> nx.set_node_attributes(graph, name='image', values={'a': util.grab_test_imgpath('carl.jpg')})
>>> nx.set_node_attributes(graph, name='image', values={'d': util.grab_test_imgpath('astro.png')})
>>> #nx.set_node_attributes(graph, name='height', values=100)
>>> with_labels = True
>>> fnum = None
>>> pnum = None
>>> e = show_nx(graph, with_labels, fnum, pnum, layout='agraph')
>>> util.show_if_requested()
graphid.util.stack_graphs(graph_list, vert=False, pad=None)[source]
graphid.util.translate_graph(graph, t_xy)[source]
graphid.util.translate_graph_to_origin(graph)[source]
graphid.util.group_pairs(pair_list)[source]

Groups a list of items using the first element in each pair as the item and the second element as the groupid.

Parameters:

pair_list (list) – list of 2-tuples (item, groupid)

Returns:

groupid_to_items: maps a groupid to a list of items

Return type:

dict

graphid.util.grouping_delta(old, new, pure=True)[source]

Finds what happened to the old groups to form the new groups.

Parameters:
  • old (set of frozensets) – old grouping

  • new (set of frozensets) – new grouping

  • pure (bool) – hybrids are separated from pure merges and splits if pure is True, otherwise hybrid cases are grouped in merges and splits.

Returns:

delta: dictionary of changes containing the merges, splits,

unchanged, and hybrid cases. Except for unchanged, case a subdict with new and old keys. For splits / merges, one of these contains nested sequences to indicate what the split / merge is. Also reports elements added and removed between old and new if the flattened sets are not the same.

Return type:

dict

Notes

merges - which old groups were merged into a single new group. splits - which old groups were split into multiple new groups. hybrid - which old groups had split/merge actions applied. unchanged - which old groups are the same as new groups.

Example

>>> # xdoc: +IGNORE_WHITESPACE
>>> old = [
>>>     [20, 21, 22, 23], [1, 2], [12], [13, 14], [3, 4], [5, 6,11],
>>>     [7], [8, 9], [10], [31, 32], [33, 34, 35], [41, 42, 43, 44, 45]
>>> ]
>>> new = [
>>>   [20, 21], [22, 23], [1, 2], [12, 13, 14], [4], [5, 6, 3], [7, 8],
>>>   [9, 10, 11], [31, 32, 33, 34, 35],   [41, 42, 43, 44], [45],
>>> ]
>>> delta = grouping_delta(old, new)
>>> assert set(old[0]) in delta['splits']['old']
>>> assert set(new[3]) in delta['merges']['new']
>>> assert set(old[1]) in delta['unchanged']
>>> result = ub.urepr(delta, nl=2, sort=True, nobr=1, sk=True)
>>> print(result)
hybrid: {
    merges: [{{10}, {11}, {9}}, {{3}, {5, 6}}, {{4}}, {{7}, {8}}],
    new: {{3, 5, 6}, {4}, {7, 8}, {9, 10, 11}},
    old: {{10}, {3, 4}, {5, 6, 11}, {7}, {8, 9}},
    splits: [{{10}}, {{11}, {5, 6}}, {{3}, {4}}, {{7}}, {{8}, {9}}],
},
items: {
    added: {},
    removed: {},
},
merges: {
    new: [{12, 13, 14}, {31, 32, 33, 34, 35}],
    old: [{{12}, {13, 14}}, {{31, 32}, {33, 34, 35}}],
},
splits: {
    new: [{{20, 21}, {22, 23}}, {{41, 42, 43, 44}, {45}}],
    old: [{20, 21, 22, 23}, {41, 42, 43, 44, 45}],
},
unchanged: {
    {1, 2},
},

Example

>>> old = [
>>>     [1, 2, 3], [4], [5, 6, 7, 8, 9], [10, 11, 12]
>>> ]
>>> new = [
>>>     [1], [2], [3, 4], [5, 6, 7], [8, 9, 10, 11, 12]
>>> ]
>>> # every case here is hybrid
>>> pure_delta = grouping_delta(old, new, pure=True)
>>> assert len(list(ub.flatten(pure_delta['merges'].values()))) == 0
>>> assert len(list(ub.flatten(pure_delta['splits'].values()))) == 0
>>> delta = grouping_delta(old, new, pure=False)
>>> delta = order_dict_by(delta, ['unchanged', 'splits', 'merges'])
>>> result = ub.urepr(delta, nl=2, sort=True, sk=True)
>>> print(result)
{
    items: {
        added: {},
        removed: {},
    },
    merges: [
        [{3}, {4}],
        [{10, 11, 12}, {8, 9}],
    ],
    splits: [
        [{1}, {2}, {3}],
        [{5, 6, 7}, {8, 9}],
    ],
    unchanged: {},
}

Example

>>> delta = grouping_delta([[1, 2, 3]], [])
>>> assert len(delta['items']['removed']) == 3
>>> delta = grouping_delta([], [[1, 2, 3]])
>>> assert len(delta['items']['added']) == 3
>>> delta = grouping_delta([[1]], [[1, 2, 3]])
>>> assert len(delta['items']['added']) == 2
>>> assert len(delta['unchanged']) == 1
graphid.util.order_dict_by(dict_, key_order)[source]

Reorders items in a dictionary according to a custom key order

Parameters:
  • dict_ (dict_) – a dictionary

  • key_order (list) – custom key order

Returns:

sorted_dict

Return type:

OrderedDict

Example

>>> dict_ = {1: 1, 2: 2, 3: 3, 4: 4}
>>> key_order = [4, 2, 3, 1]
>>> sorted_dict = order_dict_by(dict_, key_order)
>>> result = ('sorted_dict = %s' % (ub.urepr(sorted_dict, nl=False),))
>>> print(result)
>>> assert result == 'sorted_dict = {4: 4, 2: 2, 3: 3, 1: 1}'
graphid.util.sort_dict(dict_, part='keys', key=None, reverse=False)[source]

sorts a dictionary by its values or its keys

Parameters:
  • dict_ (dict_) – a dictionary

  • part (str) – specifies to sort by keys or values

  • key (Optional[func]) – a function that takes specified part and returns a sortable value

  • reverse (bool) – (Defaults to False) - True for descinding order. False for ascending order.

Returns:

sorted dictionary

Return type:

OrderedDict

Example

>>> dict_ = {'a': 3, 'c': 2, 'b': 1}
>>> results = []
>>> results.append(sort_dict(dict_, 'keys'))
>>> results.append(sort_dict(dict_, 'vals'))
>>> results.append(sort_dict(dict_, 'vals', lambda x: -x))
>>> result = ub.urepr(results)
>>> print(result)
[
    {'a': 3, 'b': 1, 'c': 2},
    {'b': 1, 'c': 2, 'a': 3},
    {'a': 3, 'c': 2, 'b': 1},
]
graphid.util.sortedby(item_list, key_list, reverse=False)[source]

sorts item_list using key_list

Parameters:
  • list_ (list) – list to sort

  • key_list (list) – list to sort by

  • reverse (bool) – sort order is descending (largest first) if reverse is True else acscending (smallest first)

Returns:

list_ sorted by the values of another list. defaults to ascending order

Return type:

list

SeeAlso:

sortedby2

Examples

>>> list_    = [1, 2, 3, 4, 5]
>>> key_list = [2, 5, 3, 1, 5]
>>> result = sortedby(list_, key_list, reverse=True)
>>> print(result)
[5, 2, 3, 1, 4]
graphid.util.convert_colorspace(img, dst_space, src_space='BGR', copy=False, dst=None)[source]

Converts colorspace of img. Convinience function around cv2.cvtColor

Parameters:
  • img (ndarray[uint8_t, ndim=2]) – image data

  • colorspace (str) – RGB, LAB, etc

  • dst_space (unicode) – (default = u’BGR’)

Returns:

img - image data

Return type:

ndarray[uint8_t, ndim=2]

Example

>>> convert_colorspace(np.array([[[0, 0, 1]]], dtype=np.float32), 'LAB', src_space='RGB')
>>> convert_colorspace(np.array([[[0, 1, 0]]], dtype=np.float32), 'LAB', src_space='RGB')
>>> convert_colorspace(np.array([[[1, 0, 0]]], dtype=np.float32), 'LAB', src_space='RGB')
>>> convert_colorspace(np.array([[[1, 1, 1]]], dtype=np.float32), 'LAB', src_space='RGB')
>>> convert_colorspace(np.array([[[0, 0, 1]]], dtype=np.float32), 'HSV', src_space='RGB')
graphid.util.ensure_float01(img, dtype=<class 'numpy.float32'>, copy=True)[source]

Ensure that an image is encoded using a float properly

graphid.util.get_num_channels(img)[source]

Returns the number of color channels

graphid.util.imread(fpath, **kw)[source]

reads image data in BGR format

Example

>>> # xdoctest: +SKIP("use kwimage.imread")
>>> import ubelt as ub
>>> import tempfile
>>> from os.path import splitext  # NOQA
>>> fpath = ub.grabdata('https://i.imgur.com/oHGsmvF.png', fname='carl.png')
>>> #fpath = ub.grabdata('http://www.topcoder.com/contest/problem/UrbanMapper3D/JAX_Tile_043_DTM.tif')
>>> ext = splitext(fpath)[1]
>>> img1 = imread(fpath)
>>> # Check that write + read preserves data
>>> tmp = tempfile.NamedTemporaryFile(suffix=ext)
>>> imwrite(tmp.name, img1)
>>> img2 = imread(tmp.name)
>>> assert np.all(img2 == img1)

Example

>>> # xdoctest: +SKIP("use kwimage.imread")
>>> import tempfile
>>> import ubelt as ub
>>> #img1 = (np.arange(0, 12 * 12 * 3).reshape(12, 12, 3) % 255).astype(np.uint8)
>>> img1 = imread(ub.grabdata('http://i.imgur.com/iXNf4Me.png', fname='ada.png'))
>>> tmp_tif = tempfile.NamedTemporaryFile(suffix='.tif')
>>> tmp_png = tempfile.NamedTemporaryFile(suffix='.png')
>>> imwrite(tmp_tif.name, img1)
>>> imwrite(tmp_png.name, img1)
>>> tif_im = imread(tmp_tif.name)
>>> png_im = imread(tmp_png.name)
>>> assert np.all(tif_im == png_im)

Example

>>> # xdoctest: +SKIP("use kwimage.imread")
>>> from graphid.util.util_image import *
>>> import tempfile
>>> import ubelt as ub
>>> #img1 = (np.arange(0, 12 * 12 * 3).reshape(12, 12, 3) % 255).astype(np.uint8)
>>> tif_fpath = ub.grabdata('https://ghostscript.com/doc/tiff/test/images/rgb-3c-16b.tiff')
>>> img1 = imread(tif_fpath)
>>> tmp_tif = tempfile.NamedTemporaryFile(suffix='.tif')
>>> tmp_png = tempfile.NamedTemporaryFile(suffix='.png')
>>> imwrite(tmp_tif.name, img1)
>>> imwrite(tmp_png.name, img1)
>>> tif_im = imread(tmp_tif.name)
>>> png_im = imread(tmp_png.name)
>>> assert np.all(tif_im == png_im)
graphid.util.imwrite(fpath, image, **kw)[source]

writes image data in BGR format

class graphid.util.KWSpec(spec)[source]

Bases: object

Safer keyword arguments with keyword specifications.

graphid.util.all_dict_combinations(varied_dict)[source]
Parameters:

varied_dict (dict) – a dict with lists of possible parameter settings

Returns:

dict_list a list of dicts correpsonding to all combinations of params settings

Return type:

list

Example

>>> varied_dict = {'logdist_weight': [0.0, 1.0], 'pipeline_root': ['vsmany'], 'sv_on': [True, False, None]}
>>> dict_list = all_dict_combinations(varied_dict)
>>> result = str(ub.urepr(dict_list))
>>> print(result)
[
    {'logdist_weight': 0.0, 'pipeline_root': 'vsmany', 'sv_on': True},
    {'logdist_weight': 0.0, 'pipeline_root': 'vsmany', 'sv_on': False},
    {'logdist_weight': 0.0, 'pipeline_root': 'vsmany', 'sv_on': None},
    {'logdist_weight': 1.0, 'pipeline_root': 'vsmany', 'sv_on': True},
    {'logdist_weight': 1.0, 'pipeline_root': 'vsmany', 'sv_on': False},
    {'logdist_weight': 1.0, 'pipeline_root': 'vsmany', 'sv_on': None},
]
graphid.util.aslist(sequence)[source]

Ensures that the sequence object is a Python list. Handles, numpy arrays, and python sequences (e.g. tuples, and iterables).

Parameters:

sequence (sequence) – a list-like object

Returns:

list_ - sequence as a Python list

Return type:

list

Example

>>> s1 = [1, 2, 3]
>>> s2 = (1, 2, 3)
>>> assert aslist(s1) is s1
>>> assert aslist(s2) is not s2
>>> aslist(np.array([[1, 2], [3, 4], [5, 6]]))
[[1, 2], [3, 4], [5, 6]]
>>> aslist(range(3))
[0, 1, 2]
class graphid.util.classproperty(fget=None, fset=None, fdel=None, doc=None)[source]

Bases: property

Decorates a method turning it into a classattribute

References

https://stackoverflow.com/questions/1697501/python-staticmethod-with-property

graphid.util.cprint(text, color=None)[source]

provides some color to terminal output

Parameters:
  • text (str)

  • color (str)

Example0:
>>> import pygments.console
>>> msg_list = list(pygments.console.codes.keys())
>>> color_list = list(pygments.console.codes.keys())
>>> [cprint(text, color) for text, color in zip(msg_list, color_list)]
Example1:
>>> import pygments.console
>>> print('line1')
>>> cprint('line2', 'red')
>>> cprint('line3', 'blue')
>>> cprint('line4', 'magenta')
>>> cprint('line5', 'reset')
>>> cprint('line5', 'magenta')
>>> print('line6')
graphid.util.delete_dict_keys(dict_, key_list)[source]

Removes items from a dictionary inplace. Keys that do not exist are ignored.

Parameters:
  • dict_ (dict) – dict like object with a __del__ attribute

  • key_list (list) – list of keys that specify the items to remove

Example

>>> dict_ = {'bread': 1, 'churches': 1, 'cider': 2, 'very small rocks': 2}
>>> key_list = ['duck', 'bread', 'cider']
>>> delete_dict_keys(dict_, key_list)
>>> result = ub.urepr(dict_, nl=False)
>>> print(result)
{'churches': 1, 'very small rocks': 2}
graphid.util.delete_items_by_index(list_, index_list, copy=False)[source]

Remove items from list_ at positions specified in index_list The original list_ is preserved if copy is True

Parameters:
  • list_ (list)

  • index_list (list)

  • copy (bool) – preserves original list if True

Example

>>> list_ = [8, 1, 8, 1, 6, 6, 3, 4, 4, 5, 6]
>>> index_list = [2, -1]
>>> result = delete_items_by_index(list_, index_list)
>>> print(result)
[8, 1, 1, 6, 6, 3, 4, 4, 5]
graphid.util.ensure_iterable(obj)[source]
Parameters:

obj (scalar or iterable)

Returns:

obj if it was iterable otherwise [obj]

Return type:

it3erable

Timeit:

%timeit util.ensure_iterable([1]) %timeit util.ensure_iterable(1) %timeit util.ensure_iterable(np.array(1)) %timeit util.ensure_iterable([1]) %timeit [1]

Example

>>> obj_list = [3, [3], '3', (3,), [3,4,5]]
>>> result = [ensure_iterable(obj) for obj in obj_list]
>>> result = str(result)
>>> print(result)
[[3], [3], ['3'], (3,), [3, 4, 5]]
graphid.util.estarmap(func, iter_, **kwargs)[source]

Eager version of it.starmap from itertools

Note this is inefficient and should only be used when prototyping and debugging.

graphid.util.flag_None_items(list_)[source]
graphid.util.get_timestamp(format_='iso', use_second=False, delta_seconds=None, isutc=False, timezone=False)[source]
Parameters:
  • format_ (str) – (tag, printable, filename, other)

  • use_second (bool)

  • delta_seconds (None)

Returns:

stamp

Return type:

str

Example

>>> format_ = 'printable'
>>> use_second = False
>>> delta_seconds = None
>>> stamp = get_timestamp(format_, use_second, delta_seconds)
>>> print(stamp)
>>> assert len(stamp) == len('15:43:04 2015/02/24')
graphid.util.highlight_regex(str_, pat, reflags=0, color='red')[source]

FIXME Use pygments instead

graphid.util.isect(list1, list2)[source]

returns list1 elements that are also in list2. preserves order of list1

intersect_ordered

Parameters:
  • list1 (list)

  • list2 (list)

Returns:

new_list

Return type:

list

Example

>>> list1 = ['featweight_rowid', 'feature_rowid', 'config_rowid', 'featweight_forground_weight']
>>> list2 = [u'featweight_rowid']
>>> result = isect(list1, list2)
>>> print(result)
['featweight_rowid']
graphid.util.iteritems_sorted(dict_)[source]

change to iteritems ordered

graphid.util.make_index_lookup(list_, dict_factory=<class 'dict'>)[source]
Parameters:

list_ (list) – assumed to have unique items

Returns:

mapping from item to index

Return type:

dict

Example

>>> list_ = [5, 3, 8, 2]
>>> idx2_item = make_index_lookup(list_)
>>> result = ub.urepr(idx2_item, nl=False, sort=1)
>>> assert list(ub.take(idx2_item, list_)) == list(range(len(list_)))
>>> print(result)
{2: 3, 3: 1, 5: 0, 8: 2}
graphid.util.partial_order(list_, part)[source]
graphid.util.randn(mean=0, std=1, shape=[], a_max=None, a_min=None, rng=None)[source]
graphid.util.regex_word(w)[source]
graphid.util.replace_nones(list_, repl=-1)[source]

Recursively removes Nones in all lists and sublists and replaces them with the repl variable

Parameters:
  • list_ (list)

  • repl (obj) – replacement value

Returns:

list

Example

>>> list_ = [None, 0, 1, 2]
>>> repl = -1
>>> repl_list = replace_nones(list_, repl)
>>> result = str(repl_list)
>>> print(result)
[-1, 0, 1, 2]
graphid.util.safe_argmax(arr, fill=nan, finite=False, nans=True)[source]

Doctest

>>> assert safe_argmax([np.nan, np.nan], nans=False) == 0
>>> assert safe_argmax([-100, np.nan], nans=False) == 0
>>> assert safe_argmax([np.nan, -100], nans=False) == 1
>>> assert safe_argmax([-100, 0], nans=False) == 1
>>> assert np.isnan(safe_argmax([]))
graphid.util.safe_extreme(arr, op, fill=nan, finite=False, nans=True)[source]

Applies an exterme operation to an 1d array (typically max/min) but ensures a value is always returned even in operations without identities. The default identity must be specified using the fill argument.

Parameters:
  • arr (ndarray) – 1d array to take extreme of

  • op (func) – vectorized operation like np.max to apply to array

  • fill (float) – return type if arr has no elements (default = nan)

  • finite (bool) – if True ignores non-finite values (default = False)

  • nans (bool) – if False ignores nans (default = True)

graphid.util.safe_max(arr, fill=nan, finite=False, nans=True)[source]
Parameters:
  • arr (ndarray) – 1d array to take max of

  • fill (float) – return type if arr has no elements (default = nan)

  • finite (bool) – if True ignores non-finite values (default = False)

  • nans (bool) – if False ignores nans (default = True)

Example

>>> arrs = [[], [np.nan], [-np.inf, np.nan, np.inf], [np.inf], [np.inf, 1], [0, 1]]
>>> arrs = [np.array(arr) for arr in arrs]
>>> fill = np.nan
>>> results1 = [safe_max(arr, fill, finite=False, nans=True) for arr in arrs]
>>> results2 = [safe_max(arr, fill, finite=True, nans=True) for arr in arrs]
>>> results3 = [safe_max(arr, fill, finite=True, nans=False) for arr in arrs]
>>> results4 = [safe_max(arr, fill, finite=False, nans=False) for arr in arrs]
>>> results = [results1, results2, results3, results4]
>>> result = ('results = %s' % (ub.urepr(results, nl=1, sv=1),))
>>> print(result)
results = [
    [nan, nan, nan, inf, inf, 1],
    [nan, nan, nan, nan, 1.0, 1],
    [nan, nan, nan, nan, 1.0, 1],
    [nan, nan, inf, inf, inf, 1],
]
graphid.util.safe_min(arr, fill=nan, finite=False, nans=True)[source]

Example

>>> arrs = [[], [np.nan], [-np.inf, np.nan, np.inf], [np.inf], [np.inf, 1], [0, 1]]
>>> arrs = [np.array(arr) for arr in arrs]
>>> fill = np.nan
>>> results1 = [safe_min(arr, fill, finite=False, nans=True) for arr in arrs]
>>> results2 = [safe_min(arr, fill, finite=True, nans=True) for arr in arrs]
>>> results3 = [safe_min(arr, fill, finite=True, nans=False) for arr in arrs]
>>> results4 = [safe_min(arr, fill, finite=False, nans=False) for arr in arrs]
>>> results = [results1, results2, results3, results4]
>>> result = ('results = %s' % (ub.urepr(results, nl=1, sv=1),))
>>> print(result)
results = [
    [nan, nan, nan, inf, 1.0, 0],
    [nan, nan, nan, nan, 1.0, 0],
    [nan, nan, nan, nan, 1.0, 0],
    [nan, nan, -inf, inf, 1.0, 0],
]
graphid.util.setdiff(list1, list2)[source]

returns list1 elements that are not in list2. preserves order of list1

Parameters:
  • list1 (list)

  • list2 (list)

Returns:

new_list

Return type:

list

Example

>>> list1 = ['featweight_rowid', 'feature_rowid', 'config_rowid', 'featweight_forground_weight']
>>> list2 = [u'featweight_rowid']
>>> new_list = setdiff(list1, list2)
>>> result = ub.urepr(new_list, nl=False)
>>> print(result)
['feature_rowid', 'config_rowid', 'featweight_forground_weight']
graphid.util.snapped_slice(size, frac, n)[source]

Creates a slice spanning n items in a list of length size at position frac.

Parameters:
  • size (int) – length of the list

  • frac (float) – position in the range [0, 1]

  • n (int) – number of items in the slice

Returns:

slice object that best fits the criteria

Return type:

slice

SeeAlso:

take_percentile_parts

Example:

Example

>>> # DISABLE_DOCTEST
>>> print(snapped_slice(0, 0, 10))
>>> print(snapped_slice(1, 0, 10))
>>> print(snapped_slice(100, 0, 10))
>>> print(snapped_slice(9, 0, 10))
>>> print(snapped_slice(100, 1, 10))
pass
graphid.util.stats_dict(list_, axis=None, use_nan=False, use_sum=False, use_median=False, size=False)[source]
Parameters:
  • list_ (listlike) – values to get statistics of

  • axis (int) – if list_ is ndarray then this specifies the axis

Returns:

stats: dictionary of common numpy statistics

(min, max, mean, std, nMin, nMax, shape)

Return type:

OrderedDict

Examples0:
>>> # xdoctest: +IGNORE_WHITESPACE
>>> import numpy as np
>>> axis = 0
>>> np.random.seed(0)
>>> list_ = np.random.rand(10, 2).astype(np.float32)
>>> stats = stats_dict(list_, axis, use_nan=False)
>>> result = str(ub.urepr(stats, nl=1, precision=4, with_dtype=True))
>>> print(result)
{
    'mean': np.array([0.5206, 0.6425], dtype=np.float32),
    'std': np.array([0.2854, 0.2517], dtype=np.float32),
    'max': np.array([0.9637, 0.9256], dtype=np.float32),
    'min': np.array([0.0202, 0.0871], dtype=np.float32),
    'nMin': np.array([1, 1], dtype=np.int32),
    'nMax': np.array([1, 1], dtype=np.int32),
    'shape': (10, 2),
}
Examples1:
>>> import numpy as np
>>> axis = 0
>>> rng = np.random.RandomState(0)
>>> list_ = rng.randint(0, 42, size=100).astype(np.float32)
>>> list_[4] = np.nan
>>> stats = stats_dict(list_, axis, use_nan=True)
>>> result = str(ub.urepr(stats, precision=1, sk=True))
>>> print(result)
{mean: 20.0, std: 13.2, max: 41.0, min: 0.0, nMin: 7, nMax: 3, shape: (100,), num_nan: 1,}
graphid.util.take_percentile_parts(arr, front=None, mid=None, back=None)[source]

Take parts from front, back, or middle of a list

Example

>>> arr = list(range(20))
>>> front = 3
>>> mid = 3
>>> back = 3
>>> result = take_percentile_parts(arr, front, mid, back)
>>> print(result)
[0, 1, 2, 9, 10, 11, 17, 18, 19]
graphid.util.where(flag_list)[source]

takes flags returns indexes of True values

graphid.util.apply_grouping(items, groupxs, axis=0)[source]

applies grouping from group_indicies apply_grouping

Parameters:
  • items (ndarray)

  • groupxs (list of ndarrays)

Returns:

grouped items

Return type:

list of ndarrays

SeeAlso:

group_indices invert_apply_grouping

Example

>>> # xdoctest: +IGNORE_WHITESPACE
>>> idx2_groupid = np.array([2, 1, 2, 1, 2, 1, 2, 3, 3, 3, 3])
>>> items        = np.array([1, 8, 5, 5, 8, 6, 7, 5, 3, 0, 9])
>>> (keys, groupxs) = group_indices(idx2_groupid)
>>> grouped_items = apply_grouping(items, groupxs)
>>> result = str(grouped_items)
>>> print(result)
[array([8, 5, 6]), array([1, 5, 8, 7]), array([5, 3, 0, 9])]
graphid.util.atleast_nd(arr, n, front=False)[source]

View inputs as arrays with at least n dimensions. TODO: Submit as a PR to numpy

Parameters:
  • arr (array_like) – One array-like object. Non-array inputs are converted to arrays. Arrays that already have n or more dimensions are preserved.

  • n (int) – number of dimensions to ensure

  • tofront (bool) – if True new dimensions are added to the front of the array. otherwise they are added to the back.

Returns:

An array with a.ndim >= n. Copies are avoided where possible, and views with three or more dimensions are returned. For example, a 1-D array of shape (N,) becomes a view of shape (1, N, 1), and a 2-D array of shape (M, N) becomes a view of shape (M, N, 1).

Return type:

ndarray

Example

>>> n = 2
>>> arr = np.array([1, 1, 1])
>>> arr_ = atleast_nd(arr, n)
>>> result = ub.urepr(arr_.tolist(), nl=0)
>>> print(result)
[[1], [1], [1]]

Example

>>> n = 4
>>> arr1 = [1, 1, 1]
>>> arr2 = np.array(0)
>>> arr3 = np.array([[[[[1]]]]])
>>> arr1_ = atleast_nd(arr1, n)
>>> arr2_ = atleast_nd(arr2, n)
>>> arr3_ = atleast_nd(arr3, n)
>>> result1 = ub.urepr(arr1_.tolist(), nl=0)
>>> result2 = ub.urepr(arr2_.tolist(), nl=0)
>>> result3 = ub.urepr(arr3_.tolist(), nl=0)
>>> result = '\n'.join([result1, result2, result3])
>>> print(result)
[[[[1]]], [[[1]]], [[[1]]]]
[[[[0]]]]
[[[[[1]]]]]

Benchmark

import ubelt N = 100

t1 = ubelt.Timerit(N, label=’mine’) for timer in t1:

arr = np.empty((10, 10)) with timer:

atleast_nd(arr, 3)

t2 = ubelt.Timerit(N, label=’baseline’) for timer in t2:

arr = np.empty((10, 10)) with timer:

np.atleast_3d(arr)

graphid.util.group_indices(idx2_groupid, assume_sorted=False)[source]
Parameters:

idx2_groupid (ndarray) – numpy array of group ids (must be numeric)

Returns:

(keys, groupxs)

Return type:

tuple (ndarray, list of ndarrays)

Example0:
>>> # xdoctest: +IGNORE_WHITESPACE
>>> idx2_groupid = np.array([2, 1, 2, 1, 2, 1, 2, 3, 3, 3, 3])
>>> (keys, groupxs) = group_indices(idx2_groupid)
>>> result = ub.urepr((keys, groupxs), nobr=True, with_dtype=True)
>>> print(result)

np.array([1, 2, 3], dtype=np.int64), [

np.array([1, 3, 5], dtype=np.int64), np.array([0, 2, 4, 6], dtype=np.int64), np.array([ 7, 8, 9, 10], dtype=np.int64)…

Example1:
>>> # xdoctest: +IGNORE_WHITESPACE
>>> idx2_groupid = np.array([[  24], [ 129], [ 659], [ 659], [ 24],
...       [659], [ 659], [ 822], [ 659], [ 659], [24]])
>>> # 2d arrays must be flattened before coming into this function so
>>> # information is on the last axis
>>> (keys, groupxs) = group_indices(idx2_groupid.T[0])
>>> result = ub.urepr((keys, groupxs), nobr=True, with_dtype=True)
>>> print(result)

np.array([ 24, 129, 659, 822], dtype=np.int64), [

np.array([ 0, 4, 10], dtype=np.int64), np.array([1], dtype=np.int64), np.array([2, 3, 5, 6, 8, 9], dtype=np.int64), np.array([7], dtype=np.int64)…

Example2:
>>> # xdoctest: +IGNORE_WHITESPACE
>>> idx2_groupid = np.array([True, True, False, True, False, False, True])
>>> (keys, groupxs) = group_indices(idx2_groupid)
>>> result = ub.urepr((keys, groupxs), nobr=True, with_dtype=True)
>>> print(result)

np.array([False, True], dtype=bool), [

np.array([2, 4, 5], dtype=np.int64), np.array([0, 1, 3, 6], dtype=np.int64)…

Timeit:

import numba group_indices_numba = numba.jit(group_indices) group_indices_numba(idx2_groupid)

SeeAlso:

apply_grouping

References

http://stackoverflow.com/questions/4651683/ numpy-grouping-using-itertools-groupby-performance

Todo

Look into np.split http://stackoverflow.com/questions/21888406/ getting-the-indexes-to-the-duplicate-columns-of-a-numpy-array

graphid.util.group_items(item_list, groupid_list, assume_sorted=False, axis=None)[source]
graphid.util.isect_flags(arr, other)[source]

Example

>>> arr = np.array([
>>>     [1, 2, 3, 4],
>>>     [5, 6, 3, 4],
>>>     [1, 1, 3, 4],
>>> ])
>>> other = np.array([1, 4, 6])
>>> mask = isect_flags(arr, other)
>>> print(mask)
[[ True False False  True]
 [False  True False  True]
 [ True  True False  True]]
graphid.util.iter_reduce_ufunc(ufunc, arr_iter, out=None)[source]

constant memory iteration and reduction

applys ufunc from left to right over the input arrays

Example

>>> arr_list = [
...     np.array([0, 1, 2, 3, 8, 9]),
...     np.array([4, 1, 2, 3, 4, 5]),
...     np.array([0, 5, 2, 3, 4, 5]),
...     np.array([1, 1, 6, 3, 4, 5]),
...     np.array([0, 1, 2, 7, 4, 5])
... ]
>>> memory = np.array([9, 9, 9, 9, 9, 9])
>>> gen_memory = memory.copy()
>>> def arr_gen(arr_list, gen_memory):
...     for arr in arr_list:
...         gen_memory[:] = arr
...         yield gen_memory
>>> print('memory = %r' % (memory,))
>>> print('gen_memory = %r' % (gen_memory,))
>>> ufunc = np.maximum
>>> res1 = iter_reduce_ufunc(ufunc, iter(arr_list), out=None)
>>> res2 = iter_reduce_ufunc(ufunc, iter(arr_list), out=memory)
>>> res3 = iter_reduce_ufunc(ufunc, arr_gen(arr_list, gen_memory), out=memory)
>>> print('res1       = %r' % (res1,))
>>> print('res2       = %r' % (res2,))
>>> print('res3       = %r' % (res3,))
>>> print('memory     = %r' % (memory,))
>>> print('gen_memory = %r' % (gen_memory,))
>>> assert np.all(res1 == res2)
>>> assert np.all(res2 == res3)
graphid.util.ensure_rng(rng, api='numpy')[source]

Returns a random number generator

Parameters:

seed – if None, then the rng is unseeded. Otherwise the seed can be an integer or a RandomState class

Example

>>> rng = ensure_rng(None)
>>> ensure_rng(0).randint(0, 1000)
684
>>> ensure_rng(np.random.RandomState(1)).randint(0, 1000)
37

Example

>>> num = 4
>>> print('--- Python as PYTHON ---')
>>> py_rng = random.Random(0)
>>> pp_nums = [py_rng.random() for _ in range(num)]
>>> print(pp_nums)
>>> print('--- Numpy as PYTHON ---')
>>> np_rng = ensure_rng(random.Random(0), api='numpy')
>>> np_nums = [np_rng.rand() for _ in range(num)]
>>> print(np_nums)
>>> print('--- Numpy as NUMPY---')
>>> np_rng = np.random.RandomState(seed=0)
>>> nn_nums = [np_rng.rand() for _ in range(num)]
>>> print(nn_nums)
>>> print('--- Python as NUMPY---')
>>> py_rng = ensure_rng(np.random.RandomState(seed=0), api='python')
>>> pn_nums = [py_rng.random() for _ in range(num)]
>>> print(pn_nums)
>>> assert np_nums == pp_nums
>>> assert pn_nums == nn_nums
graphid.util.random_combinations(items, size, num=None, rng=None)[source]

Yields num combinations of length size from items in random order

Parameters:
  • items (List) – pool of items to choose from

  • size (int) – number of items in each combination

  • num (None, default=None) – number of combinations to generate

  • rng (int | RandomState, default=None) – seed or random number generator

Yields:

tuple – combo

Example

>>> import ubelt as ub  # NOQA
>>> items = list(range(10))
>>> size = 3
>>> num = 5
>>> rng = 0
>>> combos = list(random_combinations(items, size, num, rng))
>>> result = ('combos = %s' % (ub.urepr(combos),))
>>> print(result)

Example

>>> import ubelt as ub  # NOQA
>>> items = list(zip(range(10), range(10)))
>>> size = 3
>>> num = 5
>>> rng = 0
>>> combos = list(random_combinations(items, size, num, rng))
>>> result = ('combos = %s' % (ub.urepr(combos),))
>>> print(result)
graphid.util.random_product(items, num=None, rng=None)[source]

Yields num items from the cartesian product of items in a random order.

Parameters:

items (list of sequences) – items to get caresian product of packed in a list or tuple. (note this deviates from api of it.product)

Example

>>> items = [(1, 2, 3), (4, 5, 6, 7)]
>>> rng = 0
>>> list(random_product(items, rng=0))
>>> list(random_product(items, num=3, rng=0))
graphid.util.shuffle(items, rng=None)[source]

Shuffles a list inplace and then returns it for convinience

Parameters:
  • items (list or ndarray) – list to shuffl

  • rng (RandomState or int) – seed or random number gen

Returns:

this is the input, but returned for convinience

Return type:

list

Example

>>> list1 = [1, 2, 3, 4, 5, 6]
>>> list2 = shuffle(list(list1), rng=1)
>>> assert list1 != list2
>>> result = str(list2)
>>> print(result)
[3, 2, 5, 1, 4, 6]
graphid.util.alias_tags(tags_list, alias_map)[source]

update tags to new values

Parameters:
  • tags_list (list)

  • alias_map (list) – list of 2-tuples with regex, value

Returns:

updated tags

Return type:

list

graphid.util.build_alias_map(regex_map, tag_vocab)[source]

Constructs explicit mapping. Order of items in regex map matters. Items at top are given preference.

graphid.util.filterflags_general_tags(tags_list, has_any=None, has_all=None, has_none=None, min_num=None, max_num=None, any_startswith=None, any_endswith=None, in_any=None, any_match=None, none_match=None, logic='and', ignore_case=True)[source]
Parameters:
  • tags_list (list)

  • has_any (None) – (default = None)

  • has_all (None) – (default = None)

  • min_num (None) – (default = None)

  • max_num (None) – (default = None)

Notes

in_any should probably be ni_any

Example1:
>>> # ENABLE_DOCTEST
>>> tags_list = [['v'], [], ['P'], ['P'], ['n', 'o'], [], ['n', 'N'], ['e', 'i', 'p', 'b', 'n'], ['n'], ['n'], ['N']]
>>> has_all = 'n'
>>> min_num = 1
>>> flags = filterflags_general_tags(tags_list, has_all=has_all, min_num=min_num)
>>> result = list(ub.compress(tags_list, flags))
>>> print('result = %r' % (result,))
Example2:
>>> tags_list = [['vn'], ['vn', 'no'], ['P'], ['P'], ['n', 'o'], [], ['n', 'N'], ['e', 'i', 'p', 'b', 'n'], ['n'], ['n', 'nP'], ['NP']]
>>> kwargs = {
>>>     'any_endswith': 'n',
>>>     'any_match': None,
>>>     'any_startswith': 'n',
>>>     'has_all': None,
>>>     'has_any': None,
>>>     'has_none': None,
>>>     'max_num': 3,
>>>     'min_num': 1,
>>>     'none_match': ['P'],
>>> }
>>> flags = filterflags_general_tags(tags_list, **kwargs)
>>> filtered = list(ub.compress(tags_list, flags))
>>> result = ('result = %s' % (ub.urepr(filtered, nl=0),))
>>> print(result)
result = [['vn', 'no'], ['n', 'o'], ['n', 'N'], ['n'], ['n', 'nP']]
graphid.util.tag_hist(tags_list)[source]