geowatch.utils.util_kwplot module

Many of these have been moved to kwplot and can be removed.

SeeAlso:

~/code/kwplot/kwplot/managers.py

Todo

  • [ ] from kwplot.managers import LabelManager as LabelModifier

  • [ ] from kwplot.managers import FigureManager

  • [ ] from kwplot.managers import FigureFinalizer

  • [ ] from kwplot.managers import Palette

  • [ ] from kwplot.managers import PaletteManager

  • [ ] from kwplot.managers import ArtistManager

  • [ ] etc…

class geowatch.utils.util_kwplot.TitleBuilder[source]

Bases: object

Simple class for adding information to a line, and then adding new lines.

Example

>>> from geowatch.utils.util_kwplot import *  # NOQA
>>> builder = TitleBuilder()
>>> builder.add_part('Part 1')
>>> builder.add_part('Part 2')
>>> builder.ensure_newline()
>>> builder.add_part('Part 3')
>>> text = builder.finalize()
>>> print(text)
Part 1, Part 2
Part 3
add_part(part)[source]
newline()[source]
ensure_newline()[source]
finalize()[source]
geowatch.utils.util_kwplot.cropwhite_ondisk(fpath)[source]
geowatch.utils.util_kwplot.dataframe_table(table, fpath, title=None, fontsize=12, table_conversion='auto', dpi=None, fnum=None, show=False)[source]

Use dataframe_image (dfi) to render a pandas dataframe.

Parameters:
  • table (pandas.DataFrame | pandas.io.formats.style.Styler)

  • fpath (str | PathLike) – where to save the image

  • table_conversion (str) – can be auto, chrome, or matplotlib (auto tries to default to chrome)

Example

>>> # xdoctest: +REQUIRES(module:dataframe_image)
>>> from geowatch.utils.util_kwplot import *  # NOQA
>>> import ubelt as ub
>>> dpath = ub.Path.appdir('kwplot/tests/test_dfi').ensuredir()
>>> import pandas as pd
>>> table = pd.DataFrame({'foo': ['one', 'one', 'one', 'two', 'two', 'two'],
...                       'bar': ['A', 'B', 'C', 'A', 'B', 'C'],
...                       'baz': [1, 2, 3, 4, 5, 6],
...                       'zoo': ['x', 'y', 'z', 'q', 'w', 't']})
>>> fpath = dpath / 'dfi.png'
>>> dataframe_table(table, fpath, title='A caption / title')
geowatch.utils.util_kwplot.humanize_dataframe(df, col_formats=None, human_labels=None, index_format=None, title=None)[source]
geowatch.utils.util_kwplot.scatterplot_highlight(data, x, y, highlight, size=10, color='orange', marker='*', val_to_color=None, ax=None, linewidths=None)[source]
geowatch.utils.util_kwplot.humanize_labels()[source]
geowatch.utils.util_kwplot.relabel_xticks(mapping, ax=None)[source]

Change the tick labels on the x-axis.

Parameters:
  • mapping (dict)

  • ax (Axes | None)

class geowatch.utils.util_kwplot.LabelModifier(mapping=None)[source]

Bases: object

Registers multiple ways to relabel text on axes

Todo

  • [ ] Maybe rename to label manager?

Example

>>> # xdoctest: +SKIP
>>> import sys, ubelt
>>> from geowatch.utils.util_kwplot import *  # NOQA
>>> import pandas as pd
>>> import kwarray
>>> rng = kwarray.ensure_rng(0)
>>> models = ['category1', 'category2', 'category3']
>>> data = pd.DataFrame([
>>>     {
>>>         'node.metrics.tpr': rng.rand(),
>>>         'node.metrics.fpr': rng.rand(),
>>>         'node.metrics.f1': rng.rand(),
>>>         'node.param.model': rng.choice(models),
>>>     } for _ in range(100)])
>>> # xdoctest: +REQUIRES(env:PLOTTING_DOCTESTS)
>>> import kwplot
>>> sns = kwplot.autosns()
>>> fig = kwplot.figure(fnum=1, pnum=(1, 2, 1), doclf=1)
>>> ax1 = sns.boxplot(data=data, x='node.param.model', y='node.metrics.f1')
>>> ax1.set_title('My node.param.model boxplot')
>>> kwplot.figure(fnum=1, pnum=(1, 2, 2))
>>> ax2 = sns.scatterplot(data=data, x='node.metrics.tpr', y='node.metrics.f1', hue='node.param.model')
>>> ax2.set_title('My node.param.model scatterplot')
>>> ax = ax2
>>> #
>>> def mapping(text):
>>>     text = text.replace('node.param.', '')
>>>     text = text.replace('node.metrics.', '')
>>>     return text
>>> #
>>> self = LabelModifier(mapping)
>>> self.add_mapping({'category2': 'FOO', 'category3': 'BAR'})
>>> #fig.canvas.draw()
>>> #
>>> self.relabel(ax=ax1)
>>> self.relabel(ax=ax2)
>>> fig.canvas.draw()
copy()[source]
add_mapping(mapping)[source]
update(dict_mapping)[source]
relabel_yticks(ax=None)[source]
relabel_xticks(ax=None)[source]
relabel_axes_labels(ax=None)[source]
relabel_legend(ax=None)[source]
relabel(ax=None, ticks=True, axes_labels=True, legend=True)[source]
class geowatch.utils.util_kwplot.FigureFinalizer(dpath='.', size_inches=None, cropwhite=True, tight_layout=True, verbose=0, **kwargs)[source]

Bases: NiceRepr

Helper for defining where and how figures will be saved on disk.

Known Parameters:

dpi : float format : str metadata : dict bbox_inches : str pad_inches : float facecolor : color edgecolor : color backend : str orientation : papertype : transparent : bbox_extra_artists : pil_kwargs :

Example

from geowatch.utils.util_kwplot import * # NOQA self = FigureFinalizer() print(‘self = {}’.format(ub.urepr(self, nl=1))) self.update(dpi=300)

copy()[source]

Create a copy of this object.

update(*args, **kwargs)[source]

Modify this config

finalize(fig, fpath, **kwargs)[source]

Sets the figure properties, like size, tight layout, etc, writes to disk, and then crops the whitespace out.

Parameters:
  • fig (matplotlib.figure.Figure) – figure to safe

  • fpath (str | PathLike) – where to save the figure image

  • **kwargs – overrides this config for this finalize only

geowatch.utils.util_kwplot.fix_matplotlib_dates(dates, format='mdate')[source]
Parameters:
  • dates (List[None | Coerceble[datetime]]) – input dates to fixup

  • format (str) – can be mdate for direct matplotlib usage or datetime for seaborn usage.

Note

seaborn seems to do just fine with timestamps… todo:

add regular matplotlib test for a real demo of where this is useful

Example

>>> from geowatch.utils.util_kwplot import *  # NOQA
>>> from kwutil.util_time import coerce_datetime
>>> from kwutil.util_time import coerce_timedelta
>>> import pandas as pd
>>> import numpy as np
>>> delta = coerce_timedelta('1 day')
>>> n = 100
>>> min_date = coerce_datetime('2020-01-01').timestamp()
>>> max_date = coerce_datetime('2021-01-01').timestamp()
>>> from kwarray.distributions import Uniform
>>> distri = Uniform(min_date, max_date)
>>> timestamps = distri.sample(n)
>>> timestamps[np.random.rand(n) > 0.5] = np.nan
>>> dates = list(map(coerce_datetime, timestamps))
>>> scores = np.random.rand(len(dates))
>>> table = pd.DataFrame({
>>>     'isodates': [None if d is None else d.isoformat() for d in dates],
>>>     'dates': dates,
>>>     'timestamps': timestamps,
>>>     'scores': scores
>>> })
>>> table['fixed_dates'] = fix_matplotlib_dates(table.dates, format='datetime')
>>> table['fixed_timestamps'] = fix_matplotlib_dates(table.timestamps, format='datetime')
>>> table['fixed_isodates'] = fix_matplotlib_dates(table.isodates, format='datetime')
>>> table['mdate_dates'] = fix_matplotlib_dates(table.dates, format='mdate')
>>> table['mdate_timestamps'] = fix_matplotlib_dates(table.timestamps, format='mdate')
>>> table['mdate_isodates'] = fix_matplotlib_dates(table.isodates, format='mdate')
>>> # xdoctest: +REQUIRES(env:PLOTTING_DOCTESTS)
>>> import kwplot
>>> sns = kwplot.autosns()
>>> pnum_ = kwplot.PlotNums(nSubplots=8)
>>> ax = kwplot.figure(fnum=1, doclf=1)
>>> for key in table.columns.difference({'scores'}):
>>>     ax = kwplot.figure(fnum=1, doclf=0, pnum=pnum_()).gca()
>>>     sns.scatterplot(data=table, x=key, y='scores', ax=ax)
>>>     if key.startswith('mdate_'):
>>>         # TODO: make this formatter fixup work better.
>>>         import matplotlib.dates as mdates
>>>         ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d'))
>>>         ax.xaxis.set_major_locator(mdates.DayLocator(interval=90))
geowatch.utils.util_kwplot.fix_matplotlib_timedeltas(deltas)[source]
geowatch.utils.util_kwplot.extract_legend(ax)[source]

Creates a new figure that contains the original legend.

class geowatch.utils.util_kwplot.ArtistManager[source]

Bases: object

Accumulates artist collections (e.g. lines, patches, ellipses) the user is interested in drawing so we can draw them efficiently.

References

https://matplotlib.org/stable/api/collections_api.html https://matplotlib.org/stable/gallery/shapes_and_collections/ellipse_collection.html https://stackoverflow.com/questions/32444037/how-can-i-plot-many-thousands-of-circles-quickly

Example

>>> # xdoctest: +SKIP
>>> from geowatch.utils.util_kwplot import *  # NOQA
>>> # xdoctest: +REQUIRES(env:PLOTTING_DOCTESTS)
>>> import kwplot
>>> sns = kwplot.autosns()
>>> fig = kwplot.figure(fnum=1)
>>> self = ArtistManager()
>>> import kwimage
>>> points = kwimage.Polygon.star().data['exterior'].data
>>> self.add_linestring(points)
>>> ax = fig.gca()
>>> self.add_to_axes(ax)
>>> ax.relim()
>>> ax.set_xlim(-1, 1)
>>> ax.set_ylim(-1, 1)

Example

>>> # xdoctest: +SKIP
>>> from geowatch.utils.util_kwplot import *  # NOQA
>>> # xdoctest: +REQUIRES(env:PLOTTING_DOCTESTS)
>>> import kwplot
>>> sns = kwplot.autosns()
>>> fig = kwplot.figure(fnum=1)
>>> self = ArtistManager()
>>> import kwimage
>>> points = kwimage.Polygon.star().data['exterior'].data
>>> y = 1
>>> self.add_linestring([(0, y), (1, y)], color='kitware_blue')
>>> y = 2
>>> self.add_linestring([(0, y), (1, y)], color='kitware_green')
>>> y = 3
>>> self.add_circle((0, y), r=.1, color='kitware_darkgreen')
>>> self.add_circle((0.5, y), r=.1, color='kitware_darkblue')
>>> self.add_circle((0.2, y), r=.1, color='kitware_darkblue')
>>> self.add_circle((1.0, y), r=.1, color='kitware_darkblue')
>>> self.add_ellipse((0.2, 1), .1, .2, angle=10, color='kitware_gray')
>>> self.add_linestring([(0, y), (1, y)], color='kitware_blue')
>>> y = 4
>>> self.add_linestring([(0, y), (1, y)], color='kitware_blue')
>>> self.add_circle_marker((0, y), r=10, color='kitware_darkgreen')
>>> self.add_circle_marker((0.5, y), r=10, color='kitware_darkblue')
>>> self.add_circle_marker((0.2, y), r=10, color='kitware_darkblue')
>>> self.add_circle_marker((1.0, y), r=10, color='kitware_darkblue')
>>> self.add_ellipse_marker((0.2, 2), 10, 20, angle=10, color='kitware_gray')
>>> self.add_linestring(np.array([
...     (0.2, 0.5),
...     (0.45, 1.6),
...     (0.62, 2.3),
...     (0.82, 4.9),
>>> ]), color='kitware_yellow')
>>> self.add_to_axes()
>>> ax = fig.gca()
>>> ax.set_xlim(0, 1)
>>> ax.set_ylim(0, 5)
>>> ax.autoscale_view()
plot(xs, ys, **attrs)[source]

Alternative way to add lines

add_linestring(points, **attrs)[source]
Parameters:

points (List[Tuple[float, float]] | ndarray) – an Nx2 set of ordered points

Note

perhaps allow adding markers based on ax.scatter?

add_ellipse(xy, rx, ry, angle=0, **attrs)[source]

Real ellipses in dataspace

add_circle(xy, r, **attrs)[source]

Real ellipses in dataspace

add_ellipse_marker(xy, rx, ry, angle=0, color=None, **attrs)[source]
Parameters:
  • xy – center

  • rx – radius in the first axis (size is in points, i.e. same way plot markers are sized)

  • ry – radius in the second axis

  • angle (float) – The angles of the first axes, degrees CCW from the x-axis.

add_circle_marker(xy, r, **attrs)[source]
Parameters:
  • xy (List[Tuple[float, float]] | ndarray) – an Nx2 set of circle centers

  • r (List[float] | ndarray) – an Nx1 set of circle radii

build_collections(ax=None)[source]
add_to_axes(ax=None)[source]
bounds()[source]
setlims(ax=None)[source]
geowatch.utils.util_kwplot.time_sample_arcplot(time_samples, yloc=1, ax=None)[source]

Example

>>> from geowatch.utils.util_kwplot import *  # NOQA
>>> time_samples = [
>>>     [1, 3, 5, 7, 9],
>>>     [2, 3, 4, 6, 8],
>>>     [1, 5, 6, 7, 9],
>>> ]
>>> import kwplot
>>> kwplot.autompl()
>>> time_sample_arcplot(time_samples)
>>> kwplot.show_if_requested()

References

class geowatch.utils.util_kwplot.Palette[source]

Bases: UDict

Dictionary subclass that maps a label to a particular color.

Explicit colors per label can be given, but for other unspecified labels we attempt to generate a distinct color.

Example

>>> from geowatch.utils.util_kwplot import *  # NOQA
>>> self1 = Palette()
>>> self1.add_labels(labels=['a', 'b'])
>>> self1.update({'foo': 'blue'})
>>> self1.update(['bar', 'baz'])
>>> self2 = Palette.coerce({'foo': 'blue'})
>>> self2.update(['a', 'b', 'bar', 'baz'])
>>> self1 = self1.sorted_keys()
>>> self2 = self2.sorted_keys()
>>> # xdoctest: +REQUIRES(env:PLOTTING_DOCTESTS)
>>> import kwplot
>>> kwplot.autoplt()
>>> canvas1 = self1.make_legend_img()
>>> canvas2 = self2.make_legend_img()
>>> canvas = kwimage.stack_images([canvas1, canvas2])
>>> kwplot.imshow(canvas)
classmethod coerce(data)[source]
update(other)[source]
add_labels(label_to_color=None, labels=None)[source]

Forces particular labels to take a specific color and then chooses colors for any other unspecified label.

Parameters:
  • label_to_color (Dict[str, Any] | None) – mapping to colors that are forced

  • labels (List[str] | None) – new labels that should take distinct colors

make_legend_img(dpi=300, **kwargs)[source]
sorted_keys()[source]
reorder(head=None, tail=None)[source]
class geowatch.utils.util_kwplot.PaletteManager[source]

Bases: object

Manages colors that should be kept constant across different labels for multiple parameters.

self = PaletteManager() self.update_params(‘region_id’, {‘region1’: ‘red’})

geowatch.utils.util_kwplot.color_new_labels(label_to_color, labels)[source]
geowatch.utils.util_kwplot.autompl2()[source]

New autompl with inline logic for notebooks

class geowatch.utils.util_kwplot.FigureManager(**kwargs)[source]

Bases: object

figure(*args, **kwargs)[source]
finalize(fpath, **kwargs)[source]
set_figtitle(*args, **kwargs)[source]
geowatch.utils.util_kwplot.fix_seaborn_palette_issue(x, snskw)[source]

Modifies the sns keyword arguments to fix a warning

Fix the warning:

Passing palette without assigning hue is deprecated and will be removed in v0.14.0. Assign the x variable to hue and set legend=False for the same effect.