1

I am trying to reposition and stretch a curvilinear coordinate axis created with floating_axes.FloatingSubplot after the axis has been created. In an older version of matplotlib, I was able to do this successfully with code the following code:

horiz   = [Size.Scaled(1.0)]
vert    = [Size.Scaled(1.0)]
ax1_div = Divider(fig,[0.0, 0.0, 1.0, 0.45],horiz,vert,aspect=False) # Curvilinear Coordinates
ax1_loc = ax1_div.new_locator(nx=0,ny=0) # Curvilinear Coordinates
ax1.set_axes_locator(ax1_loc) # Curvilinear Coordinates

In the image below, I want to be able to stretch the curvilinear coordinate system so that its x-axis is aligned with the rectangular coordinate system. Older versions of matplotlib did this, but in matplotlib version 3.3.4 I can only get the axis to translate, but not stretch.

Figure Showing Axes

Does anyone know how to do this? ax.set_position() does not work here. My problem is similar to this question which received no answers.

Here is my code that generated the figure:

#!/usr/bin/env python3
from matplotlib import pyplot as plt
from matplotlib.transforms import Affine2D, Transform
import mpl_toolkits.axisartist.floating_axes as floating_axes
from matplotlib.projections import polar
from mpl_toolkits.axisartist.grid_finder import FixedLocator, DictFormatter
import mpl_toolkits.axes_grid1.axes_size as Size
from mpl_toolkits.axes_grid1 import Divider

fig = plt.figure()

# Generate first axis using normal methods.
ax0 = fig.add_subplot(111)
ax0.set_xticks([0,500,1000,1500,2000])

# Generate a curvilear axis for the second axis.
angle_ticks     = [(0, '0'), (0.079, '500'), (0.157, '1000'), (0.235, '1500'), (0.314, '2000')]
grid_locator1   = FixedLocator([v for v, s in angle_ticks])
tick_formatter1 = DictFormatter(dict(angle_ticks))

alt_ticks       = [(6371.0, '0'), (6671.0, '300'), (6971.0, '600'), (7271.0, '900'), (7571.0, '1200')]
grid_locator2   = FixedLocator([v for v, s in alt_ticks])
tick_formatter2 = DictFormatter(dict(alt_ticks))

tr_rotate       = Affine2D().rotate(1.414)
tr_shift        = Affine2D().translate(0, 6371)
tr              = polar.PolarTransform() + tr_rotate

grid_helper = \
    floating_axes.GridHelperCurveLinear(tr, extremes=(0, 0.314, 6371, 7871),
                                        grid_locator1=grid_locator1,
                                        grid_locator2=grid_locator2,
                                        tick_formatter1=tick_formatter1,
                                        tick_formatter2=tick_formatter2,)

ax1 = floating_axes.FloatingSubplot(fig, 111, grid_helper=grid_helper)
ax1.invert_xaxis()
fig.add_subplot(ax1, transform=tr)

horiz   = [Size.Scaled(1.0)]
vert    = [Size.Scaled(1.0)]
ax0_div = Divider(fig,[0.0, 0.5, 1.0, 0.45],horiz,vert,aspect=False) # Rectangular Coordinates
ax1_div = Divider(fig,[0.0, 0.0, 1.0, 0.45],horiz,vert,aspect=False) # Curvilinear Coordinates

ax0_loc = ax0_div.new_locator(nx=0,ny=0) # Rectangular Coordinates
ax1_loc = ax1_div.new_locator(nx=0,ny=0) # Curvilinear Coordinates

ax0.set_axes_locator(ax0_loc) # Rectangular Coordinates
ax1.set_axes_locator(ax1_loc) # Curvilinear Coordinates

fig.savefig('bug_report.png',bbox_inches='tight')

1 Answers1

0

I am wondering if you actually need an axes divider. Would not just using a grid of subplots be sufficient? Please have a look at the snippet below and the figure it generates.

#!/usr/bin/env python3
from matplotlib.projections.polar import PolarTransform
from matplotlib.pyplot import figure
from matplotlib.transforms import Affine2D
from mpl_toolkits.axisartist.floating_axes import (
    FloatingAxes, GridHelperCurveLinear)
from mpl_toolkits.axisartist.grid_finder import FixedLocator, DictFormatter


def get_locator_formatter(ticks):
    return FixedLocator([v for v, s in ticks]), DictFormatter(dict(ticks))


fig = figure(figsize=(8, 8), constrained_layout=True)

ax0 = fig.add_subplot(211)
ax0.set_xticks([0, 500, 1000, 1500, 2000])
ax0.set_yticks([0, 300, 600, 900, 1200])
ax0.set_aspect('equal', adjustable='box')

angle_ticks = [(0, '0'), (0.079, '500'), (0.157, '1000'),
               (0.235, '1500'), (0.314, '2000')]
alt_ticks = [(6371.0, '0'), (6671.0, '300'), (6971.0, '600'),
             (7271.0, '900'), (7571.0, '1200')]
grid_locator1, tick_formatter1 = get_locator_formatter(angle_ticks)
grid_locator2, tick_formatter2 = get_locator_formatter(alt_ticks)

tr = PolarTransform() + Affine2D().rotate(1.414)

grid_helper = GridHelperCurveLinear(
    tr, extremes=(0, 0.314, 6371, 7871),
    grid_locator1=grid_locator1, grid_locator2=grid_locator2,
    tick_formatter1=tick_formatter1, tick_formatter2=tick_formatter2,)

ax1 = fig.add_subplot(212, axes_class=FloatingAxes, grid_helper=grid_helper)
ax1.invert_xaxis()

fig.savefig('bug_report.png', bbox_inches='tight')

enter image description here

Patol75
  • 4,342
  • 1
  • 17
  • 28
  • Dear @Patol75, would you be so kind as to explain why you applied below 1.0 fractional values for the "angle_ticks", but not for the "alt_ticks"? From your example, I could not understand their differences, or meaning. Sincerely, – Philipe Riskalla Leal May 13 '21 at 14:49
  • This was already included in the OP. However, I believe it is a simple mapping. Notice how 6371 is the average radius of the Earth, expressed in kilometres. Potentially, the OP wanted to represent physical fields within the ionosphere. As such, the ordinates should depict altitude in kilometres. For the abscissa, they probably represent a distance at the surface of the Earth. However, the axis being curved, it is natural to tick it with angle values. Being at the surface of the Earth, the angle representing 500 km is equal to `500 / 6371`, which gives you approximately 0.079. – Patol75 May 14 '21 at 02:30