Skip to content

Aspect ratio for not so common scales #13819

Closed
@ImportanceOfBeingErnest

Description

Bug report

Bug summary

Bringing up this stackoverflow question on the issue tracker.

Setting an equal aspect for symlog scales results in an UnboundLocalError. This should never happen, independent on how meaningful the notion of "aspect" would be such case.

Code for reproduction

import matplotlib.pyplot as plt
import numpy as np

dt = 0.01
x = np.arange(-50.0, 50.0, dt)
y = np.arange(0, 100.0, dt)

fig = plt.figure()
ax = fig.add_subplot(111,aspect='equal')

plt.plot(x, np.sin(x / 3.0))
plt.xscale('symlog')
plt.yscale('symlog', linthreshy=0.015)
plt.grid(True)
plt.ylabel('symlog both')

plt.show()

Actual outcome

UnboundLocalError: local variable 'aspect_scale_mode' referenced before assignment

Expected outcome

Either of the following:

  • An error telling that symlog does not support equal aspect.
  • A warning of the above and a fallback to `aspect="auto".
  • A meaningful plot, in case someone has an idea of what "aspect" could mean in the case of two symlog scales.

Analysis

The problem comes from

if self.name != 'polar':
xscale, yscale = self.get_xscale(), self.get_yscale()
if xscale == "linear" and yscale == "linear":
aspect_scale_mode = "linear"
elif xscale == "log" and yscale == "log":
aspect_scale_mode = "log"
elif ((xscale == "linear" and yscale == "log") or
(xscale == "log" and yscale == "linear")):
if aspect != "auto":
cbook._warn_external(
'aspect is not supported for Axes with xscale=%s, '
'yscale=%s' % (xscale, yscale))
aspect = "auto"
else: # some custom projections have their own scales.
pass
else:
aspect_scale_mode = "linear"

where there are a lot of cases for which the variable aspect_scale_mode isn't defined. I.e. each case that ends up in the pass section.
When later accessing aspect_scale_mode in

if aspect_scale_mode == "log":
box_aspect = A * self.get_data_ratio_log()
else:
box_aspect = A * self.get_data_ratio()

the above error is raised.

This brings up a more general question: Wouldn't the axis and its Scale actually need to be asked about their data limits? Something like (in pseudo code)

box_aspect = A * (tranformed(self.yaxis.bounds[1]) -  tranformed(self.yaxis.bounds[1]))/
                    (tranformed(self.xaxis.bounds[0]) -  tranformed(self.xaxis.bounds[0]))

such that other / custom scales can have an aspect defined?

Related issue: #8878

Matplotlib version

  • Matplotlib version: master

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions