3D scatter plots don't work in logscale #209

Open
ddale opened this Issue Jun 20, 2011 · 21 comments

Comments

Projects
None yet
@ddale
Contributor

ddale commented Jun 20, 2011

Original report at SourceForge, opened Fri Jun 10 12:29:24 2011

If you enable a log scale when doing a 3D scatter plot, nothing is created and the program crashes. Attached is the error output.

You can easily reproduce this by taking the example scatter3d_demo.py and adding the line "ax.set_xscale('log')".

SourceForge History

  • On Fri Jun 10 12:29:40 2011, by qulogic: File Added: 414517: mpl-3d-log-error.txt

@ghost ghost assigned WeatherGod Jun 21, 2011

@WeatherGod

This comment has been minimized.

Show comment
Hide comment
@WeatherGod

WeatherGod Jun 22, 2011

Member

Confirmed, however the problem is more nuanced than this. First, the problem does not error-out if one does ax.w_xscale.set_scale('log'), however, this does not set the scale properly because the projection never takes it into account.

Calling ax.set_xscale (or ax.set_yscale) appears to trigger some other stuff that leads to an error for displaying the coordinates in the corner. ax.set_zscale does not appear to exist. However, given that scaling does not appear to work properly right now, I am not inclined to add it.

Member

WeatherGod commented Jun 22, 2011

Confirmed, however the problem is more nuanced than this. First, the problem does not error-out if one does ax.w_xscale.set_scale('log'), however, this does not set the scale properly because the projection never takes it into account.

Calling ax.set_xscale (or ax.set_yscale) appears to trigger some other stuff that leads to an error for displaying the coordinates in the corner. ax.set_zscale does not appear to exist. However, given that scaling does not appear to work properly right now, I am not inclined to add it.

@gllort

This comment has been minimized.

Show comment
Hide comment
@gllort

gllort May 17, 2013

Problem seems to persist. I'm setting:

ax.xaxis.set_scale('log')
ax.yaxis.set_scale('log')
ax.zaxis.set_scale('log')

And then the ticks of the axes change to logarithmic scale:

scatter3d_log

While I'd expect the ticks to be equidistant and the data re-scaled, as it happens when using 2D plotting.

gllort commented May 17, 2013

Problem seems to persist. I'm setting:

ax.xaxis.set_scale('log')
ax.yaxis.set_scale('log')
ax.zaxis.set_scale('log')

And then the ticks of the axes change to logarithmic scale:

scatter3d_log

While I'd expect the ticks to be equidistant and the data re-scaled, as it happens when using 2D plotting.

@WeatherGod

This comment has been minimized.

Show comment
Hide comment
@WeatherGod

WeatherGod May 17, 2013

Member

Well... it is better than it used to be. The issue is that there is a lot of code in mplot3d that just completely ignores the projection information of the axes. While significant progress has been made in axes3d.py, it is axis3d.py that still needs a lot of TLC.

Member

WeatherGod commented May 17, 2013

Well... it is better than it used to be. The issue is that there is a lot of code in mplot3d that just completely ignores the projection information of the axes. While significant progress has been made in axes3d.py, it is axis3d.py that still needs a lot of TLC.

@ghost

This comment has been minimized.

Show comment
Hide comment
@ghost

ghost Oct 2, 2013

@gllor or @WeatherGod t, I am facing the same problem (and hence is happy to find this discussion).. could you finally got it to work? Getting the 3d plot with data logarithmically rescaled??

ghost commented Oct 2, 2013

@gllor or @WeatherGod t, I am facing the same problem (and hence is happy to find this discussion).. could you finally got it to work? Getting the 3d plot with data logarithmically rescaled??

@gllort

This comment has been minimized.

Show comment
Hide comment
@gllort

gllort Oct 2, 2013

@Panchie I'm sorry I cannot shed more light into the issue, I didn't get it working and didn't find any solution googling around.

gllort commented Oct 2, 2013

@Panchie I'm sorry I cannot shed more light into the issue, I didn't get it working and didn't find any solution googling around.

@ibell

This comment has been minimized.

Show comment
Hide comment
@ibell

ibell Oct 3, 2013

+1 on this issue, stuck with exactly this problem

ibell commented Oct 3, 2013

+1 on this issue, stuck with exactly this problem

@troyrock

This comment has been minimized.

Show comment
Hide comment
@troyrock

troyrock Nov 6, 2013

I would also like to see this issue resolved.

troyrock commented Nov 6, 2013

I would also like to see this issue resolved.

@BenjAbecassis

This comment has been minimized.

Show comment
Hide comment
@BenjAbecassis

BenjAbecassis Nov 19, 2013

The problem is till there apparently. It is a big issue for me. I hope someone could resolve it soon.

The problem is till there apparently. It is a big issue for me. I hope someone could resolve it soon.

@hyperbowl

This comment has been minimized.

Show comment
Hide comment
@hyperbowl

hyperbowl Mar 16, 2014

any progress 3 years later? set_(x,y,z)scale still just sets axis labels, not axis scaling.

any progress 3 years later? set_(x,y,z)scale still just sets axis labels, not axis scaling.

@WeatherGod

This comment has been minimized.

Show comment
Hide comment
@WeatherGod

WeatherGod Mar 17, 2014

Member

Unfortunately, no. I have not had the time or the resources to address this
issue. However, I would be more than happy to review any patches from those
who can figure this tough nut out.

On Sat, Mar 15, 2014 at 9:51 PM, hyperbowl notifications@github.com wrote:

any progress 3 years later? set_(x,y,z)scale still just sets axis labels,
not axis scaling.

Reply to this email directly or view it on GitHubhttps://github.com/matplotlib/matplotlib/issues/209#issuecomment-37745464
.

Member

WeatherGod commented Mar 17, 2014

Unfortunately, no. I have not had the time or the resources to address this
issue. However, I would be more than happy to review any patches from those
who can figure this tough nut out.

On Sat, Mar 15, 2014 at 9:51 PM, hyperbowl notifications@github.com wrote:

any progress 3 years later? set_(x,y,z)scale still just sets axis labels,
not axis scaling.

Reply to this email directly or view it on GitHubhttps://github.com/matplotlib/matplotlib/issues/209#issuecomment-37745464
.

@tacaswell tacaswell added this to the unassigned milestone Aug 18, 2014

@OceanWolf

This comment has been minimized.

Show comment
Hide comment
@OceanWolf

OceanWolf Apr 15, 2015

Contributor

-1, just kidding, the log won't work with that 😉.

The problem described sounds like a very simple problem, I mean as all the axes exist orthogonal to one another the problem should in theory exist no different for 3d as for 2d or for that matter any number of plotable dimensions. The fact that this problem has lasted so long tells me that the code says otherwise, in which case I imagine, as with a lot of the codebase, it needs a refactor, the good news I like doing.

The biggest problem though lies in the amount that needs refactoring. Starting at the base and working our way up, with bringing tools out of the backend (MEP 22) finished and general backend refactoring (MEP 27) on its way, I guess the main plotting functions will come next.

As @WeatherGod says, if anyone feels like jump in and looking through the code, then feel free (I only jumped in about a month or two ago myself), we can give guidance if needed and it works a lot better than +1s 😉.

Contributor

OceanWolf commented Apr 15, 2015

-1, just kidding, the log won't work with that 😉.

The problem described sounds like a very simple problem, I mean as all the axes exist orthogonal to one another the problem should in theory exist no different for 3d as for 2d or for that matter any number of plotable dimensions. The fact that this problem has lasted so long tells me that the code says otherwise, in which case I imagine, as with a lot of the codebase, it needs a refactor, the good news I like doing.

The biggest problem though lies in the amount that needs refactoring. Starting at the base and working our way up, with bringing tools out of the backend (MEP 22) finished and general backend refactoring (MEP 27) on its way, I guess the main plotting functions will come next.

As @WeatherGod says, if anyone feels like jump in and looking through the code, then feel free (I only jumped in about a month or two ago myself), we can give guidance if needed and it works a lot better than +1s 😉.

@tommyhlw

This comment has been minimized.

Show comment
Hide comment
@tommyhlw

tommyhlw May 6, 2015

how hard would it be to make a workaround which prevents all set_scale('log') in 3D and calls a module which calculates the affected data array log (e.g. np.log(data) ) and changes the ticks labels to decimal power?
As long the bug exists a patch like this could help.

I will try to add an extra module in my 3D Scripts, where the data and fixed scale values will be modified, sth like this:

def scalelog(scale,scalename):
newscale = []
newscale = np.power(10,scale)
if scalename=='x':
plt.xticks(scale,newscale)
if scalename=='y':
plt.yticks(scale,newscale)
if scalename=='z':
plt.zticks(scale,newscale)

scalelog([1,2,3,4],'z')
ax.scatter(xs., ys, np.log(zs), c=c, marker=m)

tommyhlw commented May 6, 2015

how hard would it be to make a workaround which prevents all set_scale('log') in 3D and calls a module which calculates the affected data array log (e.g. np.log(data) ) and changes the ticks labels to decimal power?
As long the bug exists a patch like this could help.

I will try to add an extra module in my 3D Scripts, where the data and fixed scale values will be modified, sth like this:

def scalelog(scale,scalename):
newscale = []
newscale = np.power(10,scale)
if scalename=='x':
plt.xticks(scale,newscale)
if scalename=='y':
plt.yticks(scale,newscale)
if scalename=='z':
plt.zticks(scale,newscale)

scalelog([1,2,3,4],'z')
ax.scatter(xs., ys, np.log(zs), c=c, marker=m)

@Teque5

This comment has been minimized.

Show comment
Hide comment
@Teque5

Teque5 Aug 25, 2015

4 year old bug

workaround:

Z = np.log10(Z)
ax.plot_surface(X,Y,Z,cmap=cm.viridis)
zticks = [1e-15, 1e-14, 1e-13, 1e-12, 1e-11, 1e-10]
ax.set_zticks(np.log10(zticks))
ax.set_zticklabels(zticks)

Teque5 commented Aug 25, 2015

4 year old bug

workaround:

Z = np.log10(Z)
ax.plot_surface(X,Y,Z,cmap=cm.viridis)
zticks = [1e-15, 1e-14, 1e-13, 1e-12, 1e-11, 1e-10]
ax.set_zticks(np.log10(zticks))
ax.set_zticklabels(zticks)
@tommyhlw

This comment has been minimized.

Show comment
Hide comment
@tommyhlw

tommyhlw Sep 8, 2015

@Teque5
that's kind of the same I wanted to solve this issue.
But neither with my way nor yours I was able to show log date in 3d plot correctly.
Could you post a full example?

tommyhlw commented Sep 8, 2015

@Teque5
that's kind of the same I wanted to solve this issue.
But neither with my way nor yours I was able to show log date in 3d plot correctly.
Could you post a full example?

@Teque5

This comment has been minimized.

Show comment
Hide comment
@Teque5

Teque5 Sep 8, 2015

@tommyhlw
Toggle enablelog to see the difference.
Note that if you are working with time data things can be tricky and you might want to put it into unix epoch instead of messing with various datetime objects.

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

enablelog = True

snr=15
fig = plt.figure(figsize=(12,12))
ax = fig.gca(projection='3d')

realsnr = 10**(snr/10)
B,T = np.mgrid[100e3:10e6:100e3, 1:60:1]
C = .55 / (np.sqrt(2) * B * np.sqrt(B * T * realsnr) )
if enablelog: C = np.log10(C)
surf = ax.plot_surface(
    B/1e6, T, C, cmap='rainbow',cstride=1,
    rstride=1,linewidth=0,antialiased=False)
ax.set_xlabel("Bandwidth MHz")
ax.set_ylabel("Integration Time")
ax.set_zlabel("Cramer-Rao Lower Bound")
if enablelog:zticks = [1e-13,1e-12,1e-11,1e-10,1e-9]
if enablelog:ax.set_zticks(np.log10(zticks))
if enablelog:ax.set_zticklabels(zticks)
plt.show()

To those watching from the bleachers, ideally we would just have to add ax.set_zscale('log') to achieve this effect.

Teque5 commented Sep 8, 2015

@tommyhlw
Toggle enablelog to see the difference.
Note that if you are working with time data things can be tricky and you might want to put it into unix epoch instead of messing with various datetime objects.

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

enablelog = True

snr=15
fig = plt.figure(figsize=(12,12))
ax = fig.gca(projection='3d')

realsnr = 10**(snr/10)
B,T = np.mgrid[100e3:10e6:100e3, 1:60:1]
C = .55 / (np.sqrt(2) * B * np.sqrt(B * T * realsnr) )
if enablelog: C = np.log10(C)
surf = ax.plot_surface(
    B/1e6, T, C, cmap='rainbow',cstride=1,
    rstride=1,linewidth=0,antialiased=False)
ax.set_xlabel("Bandwidth MHz")
ax.set_ylabel("Integration Time")
ax.set_zlabel("Cramer-Rao Lower Bound")
if enablelog:zticks = [1e-13,1e-12,1e-11,1e-10,1e-9]
if enablelog:ax.set_zticks(np.log10(zticks))
if enablelog:ax.set_zticklabels(zticks)
plt.show()

To those watching from the bleachers, ideally we would just have to add ax.set_zscale('log') to achieve this effect.

@efiring

This comment has been minimized.

Show comment
Hide comment
@efiring

efiring Nov 25, 2016

Member

@tommyhlw, @JesterEE, and @erikliland, you are invited to submit a pull request that solves the problem cleanly. It might be relatively easy, by following how the scale is handled on the x and y axes in normal mpl 2-D plotting, using the appropriate Locator and Formatter. Or it might get tricky and complicated--I suspect it would. But until you or one of the other people interested in this feature submit a pull request, then chances are the feature will not be added.

Member

efiring commented Nov 25, 2016

@tommyhlw, @JesterEE, and @erikliland, you are invited to submit a pull request that solves the problem cleanly. It might be relatively easy, by following how the scale is handled on the x and y axes in normal mpl 2-D plotting, using the appropriate Locator and Formatter. Or it might get tricky and complicated--I suspect it would. But until you or one of the other people interested in this feature submit a pull request, then chances are the feature will not be added.

@w1th0utnam3

This comment has been minimized.

Show comment
Hide comment
@w1th0utnam3

w1th0utnam3 Nov 28, 2016

For anyone stumbling on this issue, the easiest workaround IMO is to plot the data using np.log10, like suggested above, and then use a custom tick formatter to display the desired labels. E.g.:

import matplotlib.ticker as mticker

ax.plot_surface(x, y, np.log10(z))

def log_tick_formatter(val, pos=None):
    return "{:.2e}".format(10**val)

ax.zaxis.set_major_formatter(mticker.FuncFormatter(log_tick_formatter))

Unfortunately I don't have the time at the moment to solve the problem in mplot3d and submit a pull request.

w1th0utnam3 commented Nov 28, 2016

For anyone stumbling on this issue, the easiest workaround IMO is to plot the data using np.log10, like suggested above, and then use a custom tick formatter to display the desired labels. E.g.:

import matplotlib.ticker as mticker

ax.plot_surface(x, y, np.log10(z))

def log_tick_formatter(val, pos=None):
    return "{:.2e}".format(10**val)

ax.zaxis.set_major_formatter(mticker.FuncFormatter(log_tick_formatter))

Unfortunately I don't have the time at the moment to solve the problem in mplot3d and submit a pull request.

@phobson

This comment has been minimized.

Show comment
Hide comment
@phobson

phobson Apr 29, 2017

Member

I just removed about 16 comments with no content other than "+1",

If you run into this issue and would like to express that you've experienced the same issue, please do not add a comment simply saying "+1". It adds nothing to move progress forward and alerts at least 30 developers with a new, notification that isn't worth much.

Instead, please use the reaction buttons in the upper right corner of the boxes of the already posted comments.

Member

phobson commented Apr 29, 2017

I just removed about 16 comments with no content other than "+1",

If you run into this issue and would like to express that you've experienced the same issue, please do not add a comment simply saying "+1". It adds nothing to move progress forward and alerts at least 30 developers with a new, notification that isn't worth much.

Instead, please use the reaction buttons in the upper right corner of the boxes of the already posted comments.

@anntzer

This comment has been minimized.

Show comment
Hide comment
@anntzer

anntzer Oct 23, 2017

Contributor

In #9545 @stevengj suggested explicitly throwing an error rather than plotting nonsense.

Contributor

anntzer commented Oct 23, 2017

In #9545 @stevengj suggested explicitly throwing an error rather than plotting nonsense.

@dstansby dstansby deleted a comment from kr11 Feb 13, 2018

@jklymak jklymak removed the SF label Mar 7, 2018

@mglerner

This comment has been minimized.

Show comment
Hide comment
@mglerner

mglerner Jun 6, 2018

The lack of resolution is frustrating to someone who wants to make log-scaled 3d histograms ... but completely understandable. It would be cool if we could do something like donate to matplotlib with some small percentage of the donation earmarked as a bounty for particular bugs.

Speaking of which, I just donated a small amount to matplotlib because matplotlib is awesome, as are the developers.

mglerner commented Jun 6, 2018

The lack of resolution is frustrating to someone who wants to make log-scaled 3d histograms ... but completely understandable. It would be cool if we could do something like donate to matplotlib with some small percentage of the donation earmarked as a bounty for particular bugs.

Speaking of which, I just donated a small amount to matplotlib because matplotlib is awesome, as are the developers.

@OceanWolf

This comment has been minimized.

Show comment
Hide comment
@OceanWolf

OceanWolf Jun 6, 2018

Contributor

Thank you very much for your donation @mglerner.

I very much understand your frustration. I would very much like to resolve this bug, but as a freelancer I don't have the time at the moment to volunteer my services to actively develop MPL. One day I hope to return :).

Contributor

OceanWolf commented Jun 6, 2018

Thank you very much for your donation @mglerner.

I very much understand your frustration. I would very much like to resolve this bug, but as a freelancer I don't have the time at the moment to volunteer my services to actively develop MPL. One day I hope to return :).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment