-
-
Notifications
You must be signed in to change notification settings - Fork 8.2k
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
matplotlib/lib/matplotlib/axes/_base.py
Lines 1469 to 1485 in 699f35e
| 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
matplotlib/lib/matplotlib/axes/_base.py
Lines 1502 to 1505 in 699f35e
| 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