Linewidths in data space?

I have a collection of Patches and Lines that have their coordinates in
data space, i.e. like in the following example:

import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
import matplotlib.collections as mcollections
import matplotlib.lines as mlines

fig = plt.figure()
ax = fig.add_subplot(111)

patches = []
patches.append(mlines.Line2D((0,1),(0,1), linewidth=1))
patches.append(mpatches.Circle((0,0), 0.25, linewidth=1))
patches.append(mpatches.Circle((1,1), 0.25, linewidth=1))

coll = mcollections.PatchCollection(patches)
ax.add_collection(coll)
ax.autoscale_view()

plt.show()

Now, in this example the line width is always given with respect to the
screen space, i.e. does not change when I zoom into the plot. Is it
possible to specify a linewidth with respect to data space? I.e. to say
that a line (in both the Line2D and the Circle) should be let's say 0.1
in data space, and thus scale accordingly if I zoom in?

-Michael

Unfortunately, I don't think there is a way to do this at present. Out of curiosity, what is the use case?

I wonder if the best way to do this would be to expose the stroking to the Python level, so given a line one could get a filled path that is the stroked line. I'm not sure how else this could work, since the zooming could be different in each direction, etc., or could even by log-scaled etc.

Would you mind creating an issue ticket for this? (Patches welcome, too, of course, and I can provide pointers if you want to take this on yourself...)

Mike

···

On 04/12/2013 05:34 AM, Michael Wimmer wrote:

I have a collection of Patches and Lines that have their coordinates in
data space, i.e. like in the following example:

import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
import matplotlib.collections as mcollections
import matplotlib.lines as mlines

fig = plt.figure()
ax = fig.add_subplot(111)

patches = []
patches.append(mlines.Line2D((0,1),(0,1), linewidth=1))
patches.append(mpatches.Circle((0,0), 0.25, linewidth=1))
patches.append(mpatches.Circle((1,1), 0.25, linewidth=1))

coll = mcollections.PatchCollection(patches)
ax.add_collection(coll)
ax.autoscale_view()

plt.show()

Now, in this example the line width is always given with respect to the
screen space, i.e. does not change when I zoom into the plot. Is it
possible to specify a linewidth with respect to data space? I.e. to say
that a line (in both the Line2D and the Circle) should be let's say 0.1
in data space, and thus scale accordingly if I zoom in?

-Michael

------------------------------------------------------------------------------
Precog is a next-generation analytics platform capable of advanced
analytics on semi-structured data. The platform includes APIs for building
apps and a phenomenal toolset for data science. Developers can use
our toolset for easy data analysis & visualization. Get a free account!
http://www2.precog.com/precogplatform/slashdotnewsletter
_______________________________________________
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-users

Dear Mike,

thanks for your quick answer! Sorry for the late reply, I was away over the
weekend.

We are using matplotlib to plot two-dimensional and three-dimensional
(mostly regular) lattices (it's a physics application), with grid sites being
represented by a symbol and links representes by lines. The size of these
grids varies strongly (i.e. how many symbols and lines are plotted), and it
would be easiest if I could specify linewidths relative to some data coordinate
system (e.g. the line width being 5% of the grid spacing).

Arguably, this is not what matplotlib is intended for, but sometimes we also
want to plot data information on top of that lattice, and then the
tools of matplotlib are extremely handy.

Also, what I have in mind will always be for a linear-scale, unit
aspect-ratio plot, so that the problems you mentioned (log-scale,
different scaling in different directions) would not be applicable.
In the general case I agree one would need to make the lines
actually a filled stroke.

I'll nevertheless file a ticket. On github?

Apart from implementing this natively in matplotlib, I was thinking if
I could work around this limitation for our purposes in the following
way: My objects to draw will always sit in a Collection. I could derive
my own Collection class with a draw() method that changes the
linewidth of the collections, taking into account the current
axes.transData and figure.dpi. Using that I should be able to
achieve my goal, right? (given that I restrict myself to plots with
the same scaling in all directions)

Michael

2013/4/12 Michael Droettboom <mdroe@...86...>:

···

Unfortunately, I don't think there is a way to do this at present. Out
of curiosity, what is the use case?

I wonder if the best way to do this would be to expose the stroking to
the Python level, so given a line one could get a filled path that is
the stroked line. I'm not sure how else this could work, since the
zooming could be different in each direction, etc., or could even by
log-scaled etc.

Would you mind creating an issue ticket for this? (Patches welcome,
too, of course, and I can provide pointers if you want to take this on
yourself...)

Mike

On 04/12/2013 05:34 AM, Michael Wimmer wrote:

I have a collection of Patches and Lines that have their coordinates in
data space, i.e. like in the following example:

import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
import matplotlib.collections as mcollections
import matplotlib.lines as mlines

fig = plt.figure()
ax = fig.add_subplot(111)

patches = []
patches.append(mlines.Line2D((0,1),(0,1), linewidth=1))
patches.append(mpatches.Circle((0,0), 0.25, linewidth=1))
patches.append(mpatches.Circle((1,1), 0.25, linewidth=1))

coll = mcollections.PatchCollection(patches)
ax.add_collection(coll)
ax.autoscale_view()

plt.show()

Now, in this example the line width is always given with respect to the
screen space, i.e. does not change when I zoom into the plot. Is it
possible to specify a linewidth with respect to data space? I.e. to say
that a line (in both the Line2D and the Circle) should be let's say 0.1
in data space, and thus scale accordingly if I zoom in?

-Michael

------------------------------------------------------------------------------
Precog is a next-generation analytics platform capable of advanced
analytics on semi-structured data. The platform includes APIs for building
apps and a phenomenal toolset for data science. Developers can use
our toolset for easy data analysis & visualization. Get a free account!
http://www2.precog.com/precogplatform/slashdotnewsletter
_______________________________________________
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-users

------------------------------------------------------------------------------
Precog is a next-generation analytics platform capable of advanced
analytics on semi-structured data. The platform includes APIs for building
apps and a phenomenal toolset for data science. Developers can use
our toolset for easy data analysis & visualization. Get a free account!
http://www2.precog.com/precogplatform/slashdotnewsletter
_______________________________________________
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-users

Apart from implementing this natively in matplotlib, I was thinking if
I could work around this limitation for our purposes in the following
way: My objects to draw will always sit in a Collection. I could derive
my own Collection class with a draw() method that changes the
linewidth of the collections, taking into account the current
axes.transData and figure.dpi. Using that I should be able to
achieve my goal, right? (given that I restrict myself to plots with
the same scaling in all directions)

Not to plug one of my own answers, but there's an example of using a
callback to keep linewidths in data coordinates here:
http://stackoverflow.com/a/15673254/325565

Have a look at the second example in the answer for the callback approach.
Using something like ``shapely`` to buffer your lines as the first example
does is also an option.

Hope that helps a bit anyway,
-Joe