Vectorized version of text()

This is something that I constantly wish for and keep having to hack
around when I remember there's nothing to do it. Or is there? Am I
missing something?

  What I want is the ability to provide a vector of x, y, and text, so
that *with a single call* I can display specified bits of text at a
specified points.

  Currently text() only puts a single text at a single point, so to plot
multiple texts you have to call it in a loop. This is especially
annoying because, when you have everything in a pandas DataFrame, the
points and text are often already aligned as separate columns. I'd like
to be able to do pyplot.multitext(df.x, df.y, df.label) or whatever and
just have it work. Better yet, just be able to pass an extra
"pointlabel" argument directly to scatter, which would specify a
sequence of labels, one for each point. The labels could then be turned
off with some method on the scatter artist (and perhaps a shortcut
pyplot method as well).

  I seem to recall there are some performance issues with plotting many
different Text objects, but that doesn't seem reason enough in itself
not to provide this, since lots of things can cause performance issues
with large datasetrs. Does anyone else think this would be worth adding?

-- Brendan Barnwell
"Do not follow where the path may lead. Go, instead, where there is no
path, and leave a trail."

There is some work in this direction already (
https://github.com/matplotlib/matplotlib/pull/4063).

More generally, I was thinking about this problem earlier today! One of
the things that bokeh does really will is broadcast all the things.
Because we have a huge code base I am biased towards decorators and
higher-level functions to solve these sorts of things. Would a function
that looks like

def broadcast_all_the_things(func, *args, static_kwargs=None, **kwargs):
        kwarg_cycler = map(add, cycler(k, v) for k, v in kwargs)
        ret = []
        if static_kwargs is None:
            static_kwargs = {}
        for arg, kwarg in zip(zip(args), kwarg_cycler):
            total_kwargs = {**kwarg_cycler, **static_kwargs} # this works
in 3.5!
            ret.append(func(*arg, **total_kwargs))
        return ret

be useful / an acceptable solution?

The call would look something like:

broadcast_all_the_things(ax.text, x_vec, y_vec, s_vec,
fontsize=font_size_vec, static_kwargs={'color':'r'})

There clearly needs to be a bit more thought put into this (like to support
automatic unpacking from a data kwarg), but I like the rough idea. It
might also make sense to provide a decorator to make easy to provide
`bulk_*` functions in the mpl name spaces.

Tom

···

On Sat, Sep 12, 2015 at 9:02 PM Brendan Barnwell <brenbarn at brenbarn.net> wrote:

        This is something that I constantly wish for and keep having to
hack
around when I remember there's nothing to do it. Or is there? Am I
missing something?

        What I want is the ability to provide a vector of x, y, and text,
so
that *with a single call* I can display specified bits of text at a
specified points.

        Currently text() only puts a single text at a single point, so to
plot
multiple texts you have to call it in a loop. This is especially
annoying because, when you have everything in a pandas DataFrame, the
points and text are often already aligned as separate columns. I'd like
to be able to do pyplot.multitext(df.x, df.y, df.label) or whatever and
just have it work. Better yet, just be able to pass an extra
"pointlabel" argument directly to scatter, which would specify a
sequence of labels, one for each point. The labels could then be turned
off with some method on the scatter artist (and perhaps a shortcut
pyplot method as well).

        I seem to recall there are some performance issues with plotting
many
different Text objects, but that doesn't seem reason enough in itself
not to provide this, since lots of things can cause performance issues
with large datasetrs. Does anyone else think this would be worth adding?

-- Brendan Barnwell
"Do not follow where the path may lead. Go, instead, where there is no
path, and leave a trail."
_______________________________________________
Matplotlib-users mailing list
Matplotlib-users at python.org
https://mail.python.org/mailman/listinfo/matplotlib-users

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/matplotlib-users/attachments/20150913/c977466d/attachment.html>

That would be better than nothing. The bulk_blah would be much better
than a single generic do_in_bulk function. When working interactively I
often rely on IDE/shell features that let me, for instance, look at the
docstring and argument signature of the function I'm calling, so it's
helpful to have the function know what arguments it accepts and know
their names, instead of showing me a generic *args, **kwargs signature.

  I do think it would be good, though, to devote some thought to
vectorizing the arguments of existing API calls wherever possible. That
is, if there isn't an overarching principle for when function arguments
should accept a sequence instead of a single value, we should formulate one.

···

On 2015-09-12 18:23, Thomas Caswell wrote:

There is some work in this direction already
(https://github.com/matplotlib/matplotlib/pull/4063).

More generally, I was thinking about this problem earlier today! One of
the things that bokeh does really will is broadcast all the things.
Because we have a huge code base I am biased towards decorators and
higher-level functions to solve these sorts of things. Would a function
that looks like

def broadcast_all_the_things(func, *args, static_kwargs=None, **kwargs):
         kwarg_cycler = map(add, cycler(k, v) for k, v in kwargs)
         ret = []
         if static_kwargs is None:
             static_kwargs = {}
         for arg, kwarg in zip(zip(args), kwarg_cycler):
             total_kwargs = {**kwarg_cycler, **static_kwargs} # this
works in 3.5!
             ret.append(func(*arg, **total_kwargs))
         return ret

be useful / an acceptable solution?

The call would look something like:

broadcast_all_the_things(ax.text, x_vec, y_vec, s_vec,
fontsize=font_size_vec, static_kwargs={'color':'r'})

There clearly needs to be a bit more thought put into this (like to
support automatic unpacking from a data kwarg), but I like the rough
idea. It might also make sense to provide a decorator to make easy to
provide `bulk_*` functions in the mpl name spaces.

--
Brendan Barnwell
"Do not follow where the path may lead. Go, instead, where there is no
path, and leave a trail."
    --author unknown