Control space between bars

Hi all,

I've searched in examples and archives and could not find anything
about manual control of space between bars.

By default, the bars in the following script overlap.

So I guess the behaviour is :
specify chart width (8in) + bar width (0.8) => auto bar space

And I would like to know how to do :
specify chart width + bar space => auto bar width
specify bar space + bar width => auto chart width (fixed margins)

But I can't figure it out, especially the latter. Can
matplotlib.transforms help me about the former ?

Do you have documentation reference or some hints about that please ?
Thanks!

I am plotting a chronological bar chart like this one :

#!/usr/bin/env python
import matplotlib, pylab, numpy
import datetime

def rangedates( hourstep ):
  dates = []
  for d in range(1,31):
    for h in range(0,24,hourstep):
      dt = datetime.datetime(2008,06,d,h)
      dates.append(dt)
  return pylab.date2num(dates)

# Plot value every 12H
abscissa = rangedates(12)

barstep = abscissa[1] - abscissa[0]
barspace = 0.5 * barstep
barwidth = barstep - barspace

fig = pylab.figure()
ax = fig.add_subplot(111)
fmt = matplotlib.dates.DateFormatter('%b %d')
ax.xaxis.set_major_formatter( fmt )
fig.autofmt_xdate()

pylab.bar( abscissa, numpy.random.randn( len(abscissa) ),
           width = barwidth)
pylab.show()

I am still investigating and I am stuck at converting transAxes values to data.

If my axes goes from 10.0 to 20.0 then transAxes 0.5 should give me 15.0.

This would allow me to compute bar width and space, since I am able to
convert inches to transAxes values.

I tried many combinations of transAxes, transData, ...,
inverse_xy_tup, xy_tup, inverted(), transform(), ... without success
:frowning:

Any ideas please ?

···

-----
import pylab as P
import matplotlib.transforms as T

x = P.arange(5)
y = P.rand(5) * 4
ax = P.subplot(1,1,1)
P.plot(x,y)
ax.set_ylim(0.0, 4.0)

trans = ax.transAxes
valx = valy = 0.5
actualcoords = "%s" % trans.transform([valx, valy])
#Gives me [328, 240] instead of [2.0, 2.0]

ax.text(valx, valy, actualcoords, transform=trans)
P.show()

-----

On Wed, Aug 13, 2008 at 10:34 AM, Mathieu Leplatre <leplatre@...287...> wrote:

Hi all,

I've searched in examples and archives and could not find anything
about manual control of space between bars.

By default, the bars in the following script overlap.

So I guess the behaviour is :
specify chart width (8in) + bar width (0.8) => auto bar space

And I would like to know how to do :
specify chart width + bar space => auto bar width
specify bar space + bar width => auto chart width (fixed margins)

But I can't figure it out, especially the latter. Can
matplotlib.transforms help me about the former ?

Do you have documentation reference or some hints about that please ?
Thanks!

I am plotting a chronological bar chart like this one :

#!/usr/bin/env python
import matplotlib, pylab, numpy
import datetime

def rangedates( hourstep ):
       dates = []
       for d in range(1,31):
               for h in range(0,24,hourstep):
                       dt = datetime.datetime(2008,06,d,h)
                       dates.append(dt)
       return pylab.date2num(dates)

# Plot value every 12H
abscissa = rangedates(12)

barstep = abscissa[1] - abscissa[0]
barspace = 0.5 * barstep
barwidth = barstep - barspace

fig = pylab.figure()
ax = fig.add_subplot(111)
fmt = matplotlib.dates.DateFormatter('%b %d')
ax.xaxis.set_major_formatter( fmt )
fig.autofmt_xdate()

pylab.bar( abscissa, numpy.random.randn( len(abscissa) ),
          width = barwidth)
pylab.show()

Hi Mathieu,

It seems to me that you're confused with the meaning of the transAxes.
It is a transform from the Axes coordinate to the Canvas(?) coordinate.
As far as I can see, what you seemed to want is a transform between
Data coordinate and Axes coordinate, and that would be transScale +
transLimits (from Data to Axes).

So, try

   trans = (ax.transScale + ax.transLimits).inverted()
   # trans = ax.transLimits.inverted() will also work in this case.

and you will get 2.0, 2.0 as you expected.

The "transform" argument should be transAxes still.

   ax.text(valx, valy, actualcoords, transform=ax.transAxes)

As far as your original question is concerned, I have little idea what
you are trying to do, so I'll leave that question to others.

Regards,

-JJ

···

On Thu, Aug 14, 2008 at 3:43 PM, Mathieu Leplatre <leplatre@...287...> wrote:

I am still investigating and I am stuck at converting transAxes values to data.

If my axes goes from 10.0 to 20.0 then transAxes 0.5 should give me 15.0.

This would allow me to compute bar width and space, since I am able to
convert inches to transAxes values.

I tried many combinations of transAxes, transData, ...,
inverse_xy_tup, xy_tup, inverted(), transform(), ... without success
:frowning:

Any ideas please ?

-----
import pylab as P
import matplotlib.transforms as T

x = P.arange(5)
y = P.rand(5) * 4
ax = P.subplot(1,1,1)
P.plot(x,y)
ax.set_ylim(0.0, 4.0)

trans = ax.transAxes
valx = valy = 0.5
actualcoords = "%s" % trans.transform([valx, valy])
#Gives me [328, 240] instead of [2.0, 2.0]

ax.text(valx, valy, actualcoords, transform=trans)
P.show()

-----

On Wed, Aug 13, 2008 at 10:34 AM, Mathieu Leplatre <leplatre@...287...> wrote:

Hi all,

I've searched in examples and archives and could not find anything
about manual control of space between bars.

By default, the bars in the following script overlap.

So I guess the behaviour is :
specify chart width (8in) + bar width (0.8) => auto bar space

And I would like to know how to do :
specify chart width + bar space => auto bar width
specify bar space + bar width => auto chart width (fixed margins)

But I can't figure it out, especially the latter. Can
matplotlib.transforms help me about the former ?

Do you have documentation reference or some hints about that please ?
Thanks!

I am plotting a chronological bar chart like this one :

#!/usr/bin/env python
import matplotlib, pylab, numpy
import datetime

def rangedates( hourstep ):
       dates = []
       for d in range(1,31):
               for h in range(0,24,hourstep):
                       dt = datetime.datetime(2008,06,d,h)
                       dates.append(dt)
       return pylab.date2num(dates)

# Plot value every 12H
abscissa = rangedates(12)

barstep = abscissa[1] - abscissa[0]
barspace = 0.5 * barstep
barwidth = barstep - barspace

fig = pylab.figure()
ax = fig.add_subplot(111)
fmt = matplotlib.dates.DateFormatter('%b %d')
ax.xaxis.set_major_formatter( fmt )
fig.autofmt_xdate()

pylab.bar( abscissa, numpy.random.randn( len(abscissa) ),
          width = barwidth)
pylab.show()

-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-users

Hi Mathieu,

I just wanted to add a little bit to Jae-Joon's example. I feel like I have to relearn the axes transformations every time I deal with them. Your email reminded me to write things down, and I thought I'd share it, in case others find it useful. Let me know if anything is wrong/unclear.

Best,
-Tony

···

On Aug 14, 2008, at 4:51 PM, Jae-Joon Lee wrote:

Hi Mathieu,

It seems to me that you're confused with the meaning of the transAxes.
It is a transform from the Axes coordinate to the Canvas(?) coordinate.
As far as I can see, what you seemed to want is a transform between
Data coordinate and Axes coordinate, and that would be transScale +
transLimits (from Data to Axes).

So, try

  trans = (ax.transScale + ax.transLimits).inverted()
  # trans = ax.transLimits.inverted() will also work in this case.

and you will get 2.0, 2.0 as you expected.

The "transform" argument should be transAxes still.

  ax.text(valx, valy, actualcoords, transform=ax.transAxes)

As far as your original question is concerned, I have little idea what
you are trying to do, so I'll leave that question to others.

Regards,

-JJ

On Thu, Aug 14, 2008 at 3:43 PM, Mathieu Leplatre > <leplatre@...287...> wrote:

I am still investigating and I am stuck at converting transAxes values to data.

If my axes goes from 10.0 to 20.0 then transAxes 0.5 should give me 15.0.

This would allow me to compute bar width and space, since I am able to
convert inches to transAxes values.

I tried many combinations of transAxes, transData, ...,
inverse_xy_tup, xy_tup, inverted(), transform(), ... without success
:frowning:

Any ideas please ?

=============================
Axes Transformations Tutorial

The new transformations infrastructure is documented in the `new docs`_ (still
in progress...), which talks about transformations *in general*. This document
talks about transforms that are pre-defined attributes of `axes`. The following
explanation is partially stolen from a mailing list reply by Michael Droettboom.

In the following,

data space
     the actual `x, y` input data coordinates

axes space
     the axes coordinates which are `([0, 0], [1, 1])` at `([xmin,ymin], [xmax,
     ymax])`

figure space
     the screen pixel coordinates.

.. _new docs:
    http://matplotlib.sourceforge.net/doc/html/devel/transformations.html

`matplotlib.axes` transforms

`transScale`
     scales data to account for nonlinearities (non-affine) in the axis scales,
     e.g. log-log and semi-log scales. For example, `transScale.transform` would
     convert `x = [1, 10, 100, 1000]` to `[1, 2, 3, 4]` (powers of ten) if the
     x-axis is logarithmically spaced.

`transLimits`
     scales the data to the currently "zoomed" in portion of the data.

`transScale + transLimits`
     maps data space to axes space.

`transAxes`
     maps axes space to figure space.

`transData`
     maps data space to the figure space. `transData` is a composite of
     `transScale`, `transLimits`, and `transAxes`. It's the "fast lane" between
     the data and the screen.

Transforms example

If you want to draw a dot in the middle of the plot, you know that

>>> x = y = 0.5

in axes space.

Since the default transform for `matplotlib.pyplot.plot` is `transData`, you can
either either change the transform of the plot operation

>>> import matplotlib.pyplot as plt
>>> ax = plt.subplot(111)
>>> ax.plot([x], [y], 'ro', transform=ax.transAxes)

Or you can transform the midpoint to data coordinates then plot them

>>> trans_data2axes = ax.transScale + ax.transLimits
>>> trans_axes2data = trans_data2axes.inverted()
>>> mid_point = trans_axes2data.transform([x, y])
>>> x_trans, y_trans = mid_point
>>> ax.plot([x_trans], [y_trans], 'gs')

It's important to note that these are two **very different** approaches. The
first point (red dot) above is always referenced to axes space and will remain
in the center of the plot, even if you change the axes limits (try panning in
interactive mode).

On the other hand, the second point (green square) is referenced to the data
space and will move with the data if the axes limits are changed.

Thank you so much Jae-Joon and Tony. You saved me so much time ! The
whole transforms system was very obscure (to me !).

···

trans = (ax.transScale + ax.transLimits).inverted()

----
barspace = 0.32 #inches
barstep = abscissa[1] - abscissa[0]
trans = (ax.transScale + ax.transLimits).inverted()
barspacedata = trans.transform([barspace,0.0])
barwidth = barstep - barspacedata[0]
----
Works great !

I just wanted to add a little bit to Jae-Joon's example. I feel like I have
to relearn the axes transformations every time I deal with them. Your email
reminded me to write things down, and I thought I'd share it, in case others
find it useful. Let me know if anything is wrong/unclear.

Everything is very clear now. Thanks for taking the time to detail
everything, it's priceless.

It's important to note that these are two **very different** approaches. The
first point (red dot) above is always referenced to axes space and will
remain
in the center of the plot, even if you change the axes limits (try panning
in
interactive mode).

On the other hand, the second point (green square) is referenced to the data
space and will move with the data if the axes limits are changed.

I really liked your small example. I wish we could publish it on scipy
or something.

Best regards.
Mat.