MEP 29 Axes Refactor

Dear matplotlibers,
Here I announce the creation of MEP29 to tidy up the Axes classes, and
other classes that relate specifically to the Axes.

See https://github.com/matplotlib/matplotlib/pull/5029 which you can
click through to
https://github.com/OceanWolf/matplotlib/blob/MEP-Axes-API/doc/devel/MEP/MEP29.rst
to see the text itself.

This MEP outlines how I see the Axes class progressing and tbh I feel
very excited about what I have written, allowing people to write all
sorts of exotic Axes such as those that employ non-Euclidian geometry;
and also allowing for us to add multiple x,y,z axes to a 3d plot to name
but a few of the features this MEP will add.

Check out the MEP for more details, and please feel free to give
comment. I should also point out that while I know about the existence
of non-Euclidian geometry, my background comes from ocean-physics, not
mathematics, so I have no knowledge beyond that considered popular
mathematics.

Also due to the complexity of the Axes classes at the moment, and how it
spreads out into many files and beyond the core-matplotlib, I think this
will take quite some time to implement, at the moment I just want to
collate the most salient points into this MEP, I don't know how many
features unknown to me exist, so help welcome, and then sort through,
decide on a stratagy of how to split this up into more bitesized PRs and
get going.

Best,
OceanWolf

First off, I don't intend this to come across as overly critical! I think
this is a very good discussion to have.
Also, I tend to have a bad "knee-jerk" reaction to change and tend to come
around over time, so keep that in mind too. :slight_smile:

However, while I agree that `Axes` is quite a beast, I'm not sure this
proposal simplifies things. From my perspective, it adds complexity. If
I'm understanding correctly, this would effectively tie the Transform stack
to the Axes, instead of having the Axes generate a Transform object that
may or may not be used by the artists in the Axes.

First we define our coordinate transformation functions: axes_to_base(self,

*q) base_to_axes(self, x, y)

The term base could get replaced with screen but for now we will keep it
simple to reflect another transformation from base coords to screen coords,
e.g. perhaps to differentiate between window and screen coords.

This is my main concern. We have a (i.m.o.) very flexible and actually
quite clean Transform system to handle this. Why shift away from it?
`ax.transData` may be non-PEP8 naming, but it's a good way to do this. The
concept of having Transform objects that handle this but are separate from
the Axes gives a lot of flexibility. In my opinion, the core concept of
having this transformation handled by a Transform object that's separate
from the Axes is one of the best things about matplotlib's design.

Or am I misunderstanding, and this is just a refactoring of
`_get_core_transform` and `_get_affine_transform` into one method?

···

---------------------

My other main concern centers on map projections. The MEP currently
mentions:

an anticipated structure of a base mapping class with a coordinate system

in lat/lon coordinates, but with different mapping projections available
for the conversion between the Axes coordinate system and the screen.

However, this is a bad approach for cartographic data. Geographic is not
the base for a projected coordinate system. There are several reasons for
that.

1. Map data is usually _in the projected coordinate system_. Lat, long
data is actually not terribly common unless you're working with global
datasets.
2. Raster data (i.e. anything displayed with imshow) is typically going to
be gridded on a regular grid in the projected coordinate system. Forcing a
transformation back to a non-uniform grid in lat, long space then back onto
a different uniform grid than the original in display space is
unnecessarily expensive.

One of the great things about Cartopy is that it leaves the fundamental
Cartesian projected space unchanged, and let's you specify the transform if
you want to use geographic coordinates. Basemap handles it a bit
differently but has the same core concept. Latitudes and longitudes aren't
the data coordinate system. The projected coordinate system is.

There's a reason for that approach. Forcing people to convert their data
into a geographic coordinate system before plotting it is a bad idea. It's
good to have plotting methods that allow geographic coordinates, but bad to
require that transformation. (I'll skip the very important datum part for
the moment. Just be aware that a lat, long only gets you to within ~1km of
a location without more information.)

----------------

At any rate, I may very well have misunderstood the changes that are being
proposed here! My apologies if I have.
Cheers,
-Joe

On Sat, Sep 5, 2015 at 10:16 AM, OceanWolf <juichenieder-nabb at yahoo.co.uk> wrote:

Dear matplotlibers,
Here I announce the creation of MEP29 to tidy up the Axes classes, and
other classes that relate specifically to the Axes.

See https://github.com/matplotlib/matplotlib/pull/5029 which you can
click through to
https://github.com/OceanWolf/matplotlib/blob/MEP-Axes-API/doc/devel/MEP/MEP29.rst
to see the text itself.

This MEP outlines how I see the Axes class progressing and tbh I feel very
excited about what I have written, allowing people to write all sorts of
exotic Axes such as those that employ non-Euclidian geometry; and also
allowing for us to add multiple x,y,z axes to a 3d plot to name but a few
of the features this MEP will add.

Check out the MEP for more details, and please feel free to give comment.
I should also point out that while I know about the existence of
non-Euclidian geometry, my background comes from ocean-physics, not
mathematics, so I have no knowledge beyond that considered popular
mathematics.

Also due to the complexity of the Axes classes at the moment, and how it
spreads out into many files and beyond the core-matplotlib, I think this
will take quite some time to implement, at the moment I just want to
collate the most salient points into this MEP, I don't know how many
features unknown to me exist, so help welcome, and then sort through,
decide on a stratagy of how to split this up into more bitesized PRs and
get going.

Best,
OceanWolf
_______________________________________________
Matplotlib-devel mailing list
Matplotlib-devel at python.org
https://mail.python.org/mailman/listinfo/matplotlib-devel

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/matplotlib-devel/attachments/20150905/6aea3fff/attachment.html>

Not too sure what you meant by ````.

First off, I don't intend this to come across as overly critical! I
think this is a very good discussion to have.
Also, I tend to have a bad "knee-jerk" reaction to change and tend to
come around over time, so keep that in mind too. :slight_smile:

No worries, I experience the same, and yes I wanted to open this up for
just this kind of interrogation, especially as we have a lot of axes
related code, and I have only touched a fraction of it to date.

To explain where I come from, I should say that I like to work
bottom-up. I find designing good code starts with asking probing
questions about what you want to model, in this case we have an
``_AxesBase`` class and so by definition it should model an abstract
Axes, because of this in the "Detailed Description" of this MEP I begin
by asking the question probing the definition of an Axes. I believe
that if we model the world intutitively as we see it, everything else
will fall into place. I find the most direct route in code usually
contains lots of inflexibility, like building a road through the
mountain, you might go the direct route, but it becomes very difficult
to maintain and expand upon. Hence the focus lies in the journey.

However, while I agree that `Axes` is quite a beast, I'm not sure this
proposal simplifies things. From my perspective, it adds complexity.
If I'm understanding correctly, this would effectively tie the
Transform stack to the Axes, instead of having the Axes generate a
Transform object that may or may not be used by the artists in the Axes.

If I understand you correctly you don't like the idea of forcing Artists
to use the transform. I don't see this as a problem (at the moment).
As far as I see it, all coordinates supplied to an Artist will come in
the form of Axes coordinates, i.e. Axes space, and thus we need to
transform those coordinates to screen coordinates... at least at some
point, probably when it comes to drawing... I especially think of
drawing a triangle onto a spherical geometry, see
https://en.wikipedia.org/wiki/Spherical_geometry. We create a Polygon
patch and supply the three vertices that define our Triangle... however
on a spherical geometry, these "straight" lines do not conform to the
Euclid definition of straight, we need to draw them curved. Because of
this the transform will need to come very late in the drawing process.

    First we define our coordinate transformation functions:
    axes_to_base(self, *q) base_to_axes(self, x, y)

    The term |base| could get replaced with |screen| but for now we
    will keep it simple to reflect another transformation from base
    coords to screen coords, e.g. perhaps to differentiate between
    window and screen coords.

This is my main concern. We have a (i.m.o.) very flexible and
actually quite clean Transform system to handle this. Why shift away
from it? `ax.transData` may be non-PEP8 naming, but it's a good way to
do this. The concept of having Transform objects that handle this but
are separate from the Axes gives a lot of flexibility. In my opinion,
the core concept of having this transformation handled by a Transform
object that's separate from the Axes is one of the best things about
matplotlib's design.

Or am I misunderstanding, and this is just a refactoring of
`_get_core_transform` and `_get_affine_transform` into one method?

As far as I know, I want to keep the transform system. I think I do
just mean refactoring that into one method. I say think as I still
don't feel fully understand how it all works, the Transform system,
brilliant, but very mind-boggling. I had to delve into it to find a bug
reported by a user on github, and went through around 50 (perhaps more)
Transform operations before I got to the problem. If you need to debug
part of it, like i had to, it becomes a tangled mess, luckily for most
people they don't have to, and the usage works quite simply. When I
tracked down the bug I also spent quite some time trying to figure out
the Transform classes, prior to the bug I only knew of Rotation, Shear
and Reflection Transforms. Anyway my point here comes that while great,
it can become quite the head-ache for the average user developer,
especially for those who know even less then I do about transforms, and
so I want to blackbox the transforms in the Axes with simple names such
as axes_to_***_coords(self, *q), and ***_to_axes_coords(self, x, y).

So I want to make it easy for people to write their own axes with their
own transform methods without having to worry about how the rest of the
Artist code and plot methods work (unless it works really bizarrely);
and I want people to work on Artist code, and creating their own tools
and user interaction stuff without having to worry about learning about
transforms (they just need to know that these two methods will do the
conversion for them from data coordinates, which they understand, to the
location on the screen or whatever, which they will also understand,
start talking about AffineTransforms and I think we will scare people off).

---------------------

My other main concern centers on map projections. The MEP currently
mentions:

    an anticipated structure of a base mapping class with a coordinate
    system in lat/lon coordinates, but with different mapping
    projections available for the conversion between the Axes
    coordinate system and the screen.

However, this is a bad approach for cartographic data. Geographic is
not the base for a projected coordinate system. There are several
reasons for that.

1. Map data is usually _in the projected coordinate system_. Lat,
long data is actually not terribly common unless you're working with
global datasets.
2. Raster data (i.e. anything displayed with imshow) is typically
going to be gridded on a regular grid in the projected coordinate
system. Forcing a transformation back to a non-uniform grid in lat,
long space then back onto a different uniform grid than the original
in display space is unnecessarily expensive.

One of the great things about Cartopy is that it leaves the
fundamental Cartesian projected space unchanged, and let's you specify
the transform if you want to use geographic coordinates. Basemap
handles it a bit differently but has the same core concept. Latitudes
and longitudes aren't the data coordinate system. The projected
coordinate system is.

There's a reason for that approach. Forcing people to convert their
data into a geographic coordinate system before plotting it is a bad
idea. It's good to have plotting methods that allow geographic
coordinates, but bad to require that transformation. (I'll skip the
very important datum part for the moment. Just be aware that a lat,
long only gets you to within ~1km of a location without more information.)

Hmm, when I have used Basemap, the data files I work with I always get
in lat/lon format. One of my biggest annoyances with Basemap comes from
having to work projection coordinates. I move the mouse over the map
and statusbar shows me useless projection coordinate information; I want
to rotate the globe (in 'ortho' projection), but I can't, it becomes
very difficult to use from a user interface point of view.

I think the solution here comes from using a dual approach. With the
functions above I used the term base, as in the ``axes_to_base`` and
``base_to_axes`` functions. Here ``base`` defines the projected
coordinates. We can then leave it up to the user to decide whether to
plot in axes coordinates or base coordinates. We can start of leaving
the axes side unimplemented, and perhaps we will never implement the
axes side for some Axes classes... what do you think?

Best,
OceanWolf
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/matplotlib-devel/attachments/20150905/65d5d746/attachment-0001.html>

···

On 05/09/15 19:25, Joe Kington wrote:

Damn, forgot to delete the top part before I sent, I started writing at
the top, before cutting and pasting to below and forgot to delete the rest.

Anyway thank you again for your positive constructive criticism. As I
say, exactly what I wanted, food for thought, use cases that I didn't
know about that I can now research and feed into the "Detailed
Description" section. I now see some more inconsistencies that we need
to solve.

I feel I came to quick in my last email to bring about solutions,
possibly they will become the solution, perhaps not, but first I need to
flesh out the description section... hopefully over the next week I will
add information about the inconsistencies your email reply brought to
light (I know I speak in riddles, but I have to first clarify it for
myself with examples). The rest of the MEP will take time to develop,
probably with some simple diagrams too.

And when I say "I" feel free to interpret it as "we", if you have ideas
please feel free to post them here, or make PRs, for example against my
PR and we can flesh the Description section out even more :).

Best
OceanWolf

···

On 05/09/15 22:10, OceanWolf wrote:

Not too sure what you meant by ````.

On 05/09/15 19:25, Joe Kington wrote:

First off, I don't intend this to come across as overly critical! I
think this is a very good discussion to have.
Also, I tend to have a bad "knee-jerk" reaction to change and tend to
come around over time, so keep that in mind too. :slight_smile:

No worries, I experience the same, and yes I wanted to open this up
for just this kind of interrogation, especially as we have a lot of
axes related code, and I have only touched a fraction of it to date.

To explain where I come from, I should say that I like to work
bottom-up. I find designing good code starts with asking probing
questions about what you want to model, in this case we have an
``_AxesBase`` class and so by definition it should model an abstract
Axes, because of this in the "Detailed Description" of this MEP I
begin by asking the question probing the definition of an Axes. I
believe that if we model the world intutitively as we see it,
everything else will fall into place. I find the most direct route in
code usually contains lots of inflexibility, like building a road
through the mountain, you might go the direct route, but it becomes
very difficult to maintain and expand upon. Hence the focus lies in
the journey.

However, while I agree that `Axes` is quite a beast, I'm not sure
this proposal simplifies things. From my perspective, it adds
complexity. If I'm understanding correctly, this would effectively
tie the Transform stack to the Axes, instead of having the Axes
generate a Transform object that may or may not be used by the
artists in the Axes.

If I understand you correctly you don't like the idea of forcing
Artists to use the transform. I don't see this as a problem (at the
moment). As far as I see it, all coordinates supplied to an Artist
will come in the form of Axes coordinates, i.e. Axes space, and thus
we need to transform those coordinates to screen coordinates... at
least at some point, probably when it comes to drawing... I especially
think of drawing a triangle onto a spherical geometry, see
https://en.wikipedia.org/wiki/Spherical_geometry. We create a Polygon
patch and supply the three vertices that define our Triangle...
however on a spherical geometry, these "straight" lines do not conform
to the Euclid definition of straight, we need to draw them curved.
Because of this the transform will need to come very late in the
drawing process.

    First we define our coordinate transformation functions:
    axes_to_base(self, *q) base_to_axes(self, x, y)

    The term |base| could get replaced with |screen| but for now we
    will keep it simple to reflect another transformation from base
    coords to screen coords, e.g. perhaps to differentiate between
    window and screen coords.

This is my main concern. We have a (i.m.o.) very flexible and
actually quite clean Transform system to handle this. Why shift away
from it? `ax.transData` may be non-PEP8 naming, but it's a good way
to do this. The concept of having Transform objects that handle this
but are separate from the Axes gives a lot of flexibility. In my
opinion, the core concept of having this transformation handled by a
Transform object that's separate from the Axes is one of the best
things about matplotlib's design.

Or am I misunderstanding, and this is just a refactoring of
`_get_core_transform` and `_get_affine_transform` into one method?

As far as I know, I want to keep the transform system. I think I do
just mean refactoring that into one method. I say think as I still
don't feel fully understand how it all works, the Transform system,
brilliant, but very mind-boggling. I had to delve into it to find a
bug reported by a user on github, and went through around 50 (perhaps
more) Transform operations before I got to the problem. If you need
to debug part of it, like i had to, it becomes a tangled mess, luckily
for most people they don't have to, and the usage works quite simply.
When I tracked down the bug I also spent quite some time trying to
figure out the Transform classes, prior to the bug I only knew of
Rotation, Shear and Reflection Transforms. Anyway my point here comes
that while great, it can become quite the head-ache for the average
user developer, especially for those who know even less then I do
about transforms, and so I want to blackbox the transforms in the Axes
with simple names such as axes_to_***_coords(self, *q), and
***_to_axes_coords(self, x, y).

So I want to make it easy for people to write their own axes with
their own transform methods without having to worry about how the rest
of the Artist code and plot methods work (unless it works really
bizarrely); and I want people to work on Artist code, and creating
their own tools and user interaction stuff without having to worry
about learning about transforms (they just need to know that these two
methods will do the conversion for them from data coordinates, which
they understand, to the location on the screen or whatever, which they
will also understand, start talking about AffineTransforms and I think
we will scare people off).

---------------------

My other main concern centers on map projections. The MEP currently
mentions:

    an anticipated structure of a base mapping class with a
    coordinate system in lat/lon coordinates, but with different
    mapping projections available for the conversion between the Axes
    coordinate system and the screen.

However, this is a bad approach for cartographic data. Geographic is
not the base for a projected coordinate system. There are several
reasons for that.

1. Map data is usually _in the projected coordinate system_. Lat,
long data is actually not terribly common unless you're working with
global datasets.
2. Raster data (i.e. anything displayed with imshow) is typically
going to be gridded on a regular grid in the projected coordinate
system. Forcing a transformation back to a non-uniform grid in lat,
long space then back onto a different uniform grid than the original
in display space is unnecessarily expensive.

One of the great things about Cartopy is that it leaves the
fundamental Cartesian projected space unchanged, and let's you
specify the transform if you want to use geographic coordinates.
Basemap handles it a bit differently but has the same core concept.
Latitudes and longitudes aren't the data coordinate system. The
projected coordinate system is.

There's a reason for that approach. Forcing people to convert their
data into a geographic coordinate system before plotting it is a bad
idea. It's good to have plotting methods that allow geographic
coordinates, but bad to require that transformation. (I'll skip the
very important datum part for the moment. Just be aware that a lat,
long only gets you to within ~1km of a location without more
information.)

Hmm, when I have used Basemap, the data files I work with I always get
in lat/lon format. One of my biggest annoyances with Basemap comes
from having to work projection coordinates. I move the mouse over the
map and statusbar shows me useless projection coordinate information;
I want to rotate the globe (in 'ortho' projection), but I can't, it
becomes very difficult to use from a user interface point of view.

I think the solution here comes from using a dual approach. With the
functions above I used the term base, as in the ``axes_to_base`` and
``base_to_axes`` functions. Here ``base`` defines the projected
coordinates. We can then leave it up to the user to decide whether to
plot in axes coordinates or base coordinates. We can start of leaving
the axes side unimplemented, and perhaps we will never implement the
axes side for some Axes classes... what do you think?

Best,
OceanWolf

_______________________________________________
Matplotlib-devel mailing list
Matplotlib-devel at python.org
https://mail.python.org/mailman/listinfo/matplotlib-devel

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/matplotlib-devel/attachments/20150906/058043fd/attachment.html>

My main concern is that this proposal would change the role of Axes.
Currently, it's primarily a container.

If I understand you correctly you don't like the idea of forcing Artists to

use the transform.

Actually, my key problem is having the Axes responsible for going between
"data" coordinates and "screen"/"display" coordinates. Right now, the Axes
is not at all responsible for that. If I'm understanding this proposal
correctly, it would shift even more into Axes.

As far as I see it, all coordinates supplied to an Artist will come in the

form of Axes coordinates, i.e. Axes space, and thus we need to transform
those coordinates to screen coordinates...

The problem here is that most Artists don't work in data coordinates. Only
a very small number, such as those produced by user-focused plotting
methods, are actually in data coordinates. Most of the artists that belong
to the Axes actually don't have `ax.transData` as their transform. For
example, consider the Axes patch, the ticks, tick labels, spines, titles
and labels, etc. Even artists produced by user-facing functions often
aren't in "data" space. Consider `annotate`, for example.

however on a spherical geometry, these "straight" lines do not conform to
the Euclid definition of straight, we need to draw them curved. Because of
this the transform will need to come very late in the drawing process.

For what it's worth, that's exactly the type of thing that I don't think it
makes sense to have the Axes responsible for. Right now, Transform handles
this. Specifically the `tranform_path_non_affine` method. This allows
these sort of transformations to happen at draw time.

I think the solution here comes from using a dual approach. With the

functions above I used the term base, as in the ``axes_to_base`` and
``base_to_axes`` functions. Here ``base`` defines the projected
coordinates. We can then leave it up to the user to decide whether to plot
in axes coordinates or base coordinates. We can start of leaving the axes
side unimplemented, and perhaps we will never implement the axes side for
some Axes classes... what do you think?

For what it's worth, that's what we currently have, in my opinion.

Each artist has a Transform. Its only role is to convert points and paths
(to handle non-euclidian geometries) from whatever the data for the artist
is in to display coordinates. The Transform that the artist has defines
what coordinates system that artist's data is in.

This makes it easy to do things like:

import matplotlib.pyplot as plt

fig, ax = plt.subplots()

ax.text(0.1, 0.9, 'This will stay in-place', transform=ax.transAxes)

ax.plot(range(10), color='royalblue', lw=3)
ax.set(title='Be sure to pan and zoom')

plt.show()

Cartopy is another fantastic example. Have a look at how Cartopy handles
the difference between projected coordinates and geodetic coordinates:
http://scitools.org.uk/cartopy/docs/latest/matplotlib/intro.html#adding-data-to-the-map
Which transform you specify defines which coordinate system is being used
for the data.

The key here is that the Axes isn't doing the transformation at all.
Making the Axes responsible for the transformation between "data" and
"display" coordinates makes it much harder to implement things such as
this. There are a lot of artists that are logically a part of the Axes but
aren't in the "data" coordinate system.

Hopefully that helps clarify my viewpoint, at any rate.
Cheers!
-Joe

···

On Sat, Sep 5, 2015 at 3:10 PM, OceanWolf <juichenieder-nabb at yahoo.co.uk> wrote:

Not too sure what you meant by ````.

On 05/09/15 19:25, Joe Kington wrote:

First off, I don't intend this to come across as overly critical! I think
this is a very good discussion to have.
Also, I tend to have a bad "knee-jerk" reaction to change and tend to come
around over time, so keep that in mind too. :slight_smile:

No worries, I experience the same, and yes I wanted to open this up for
just this kind of interrogation, especially as we have a lot of axes
related code, and I have only touched a fraction of it to date.

To explain where I come from, I should say that I like to work bottom-up.
I find designing good code starts with asking probing questions about what
you want to model, in this case we have an ``_AxesBase`` class and so by
definition it should model an abstract Axes, because of this in the
"Detailed Description" of this MEP I begin by asking the question probing
the definition of an Axes. I believe that if we model the world
intutitively as we see it, everything else will fall into place. I find
the most direct route in code usually contains lots of inflexibility, like
building a road through the mountain, you might go the direct route, but it
becomes very difficult to maintain and expand upon. Hence the focus lies
in the journey.

However, while I agree that `Axes` is quite a beast, I'm not sure this
proposal simplifies things. From my perspective, it adds complexity. If
I'm understanding correctly, this would effectively tie the Transform stack
to the Axes, instead of having the Axes generate a Transform object that
may or may not be used by the artists in the Axes.

If I understand you correctly you don't like the idea of forcing Artists
to use the transform. I don't see this as a problem (at the moment). As
far as I see it, all coordinates supplied to an Artist will come in the
form of Axes coordinates, i.e. Axes space, and thus we need to transform
those coordinates to screen coordinates... at least at some point, probably
when it comes to drawing... I especially think of drawing a triangle onto a
spherical geometry, see https://en.wikipedia.org/wiki/Spherical_geometry.
We create a Polygon patch and supply the three vertices that define our
Triangle... however on a spherical geometry, these "straight" lines do not
conform to the Euclid definition of straight, we need to draw them curved.
Because of this the transform will need to come very late in the drawing
process.

First we define our coordinate transformation functions:

axes_to_base(self, *q) base_to_axes(self, x, y)

The term base could get replaced with screen but for now we will keep it
simple to reflect another transformation from base coords to screen coords,
e.g. perhaps to differentiate between window and screen coords.

This is my main concern. We have a (i.m.o.) very flexible and actually
quite clean Transform system to handle this. Why shift away from it?
`ax.transData` may be non-PEP8 naming, but it's a good way to do this. The
concept of having Transform objects that handle this but are separate from
the Axes gives a lot of flexibility. In my opinion, the core concept of
having this transformation handled by a Transform object that's separate
from the Axes is one of the best things about matplotlib's design.

Or am I misunderstanding, and this is just a refactoring of
`_get_core_transform` and `_get_affine_transform` into one method?

As far as I know, I want to keep the transform system. I think I do just
mean refactoring that into one method. I say think as I still don't feel
fully understand how it all works, the Transform system, brilliant, but
very mind-boggling. I had to delve into it to find a bug reported by a
user on github, and went through around 50 (perhaps more) Transform
operations before I got to the problem. If you need to debug part of it,
like i had to, it becomes a tangled mess, luckily for most people they
don't have to, and the usage works quite simply. When I tracked down the
bug I also spent quite some time trying to figure out the Transform
classes, prior to the bug I only knew of Rotation, Shear and Reflection
Transforms. Anyway my point here comes that while great, it can become
quite the head-ache for the average user developer, especially for those
who know even less then I do about transforms, and so I want to blackbox
the transforms in the Axes with simple names such as
axes_to_***_coords(self, *q), and ***_to_axes_coords(self, x, y).

So I want to make it easy for people to write their own axes with their
own transform methods without having to worry about how the rest of the
Artist code and plot methods work (unless it works really bizarrely); and I
want people to work on Artist code, and creating their own tools and user
interaction stuff without having to worry about learning about transforms
(they just need to know that these two methods will do the conversion for
them from data coordinates, which they understand, to the location on the
screen or whatever, which they will also understand, start talking about
AffineTransforms and I think we will scare people off).

---------------------

My other main concern centers on map projections. The MEP currently
mentions:

an anticipated structure of a base mapping class with a coordinate system

in lat/lon coordinates, but with different mapping projections available
for the conversion between the Axes coordinate system and the screen.

However, this is a bad approach for cartographic data. Geographic is not
the base for a projected coordinate system. There are several reasons for
that.

1. Map data is usually _in the projected coordinate system_. Lat, long
data is actually not terribly common unless you're working with global
datasets.
2. Raster data (i.e. anything displayed with imshow) is typically going to
be gridded on a regular grid in the projected coordinate system. Forcing a
transformation back to a non-uniform grid in lat, long space then back onto
a different uniform grid than the original in display space is
unnecessarily expensive.

One of the great things about Cartopy is that it leaves the fundamental
Cartesian projected space unchanged, and let's you specify the transform if
you want to use geographic coordinates. Basemap handles it a bit
differently but has the same core concept. Latitudes and longitudes aren't
the data coordinate system. The projected coordinate system is.

There's a reason for that approach. Forcing people to convert their data
into a geographic coordinate system before plotting it is a bad idea. It's
good to have plotting methods that allow geographic coordinates, but bad to
require that transformation. (I'll skip the very important datum part for
the moment. Just be aware that a lat, long only gets you to within ~1km of
a location without more information.)

Hmm, when I have used Basemap, the data files I work with I always get in
lat/lon format. One of my biggest annoyances with Basemap comes from
having to work projection coordinates. I move the mouse over the map and
statusbar shows me useless projection coordinate information; I want to
rotate the globe (in 'ortho' projection), but I can't, it becomes very
difficult to use from a user interface point of view.

I think the solution here comes from using a dual approach. With the
functions above I used the term base, as in the ``axes_to_base`` and
``base_to_axes`` functions. Here ``base`` defines the projected
coordinates. We can then leave it up to the user to decide whether to plot
in axes coordinates or base coordinates. We can start of leaving the axes
side unimplemented, and perhaps we will never implement the axes side for
some Axes classes... what do you think?

Best,
OceanWolf

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/matplotlib-devel/attachments/20150906/ef0d46fb/attachment-0001.html>