Skip to content

[Bug]: Corruption of 3D surface plot at log scale with negative or zero values (v3.11.0rc2) #31726

@mrARGJ

Description

@mrARGJ

Bug summary

Strange behavior of 3D surface plot axes in log scale if the data contains negative or zero values. With values >0 surface plot output is correct. ( Also tried with PyQt5 UI backend )

Code for reproduction

import os, sys, re
import math as m
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.colors import LogNorm

# path to test file with data
fpath = r'D:\Desktop\MODES\test NUMBER3 CL 0_03 -150 TO 120 STEP 5.TXT'

fpath = os.path.normpath(fpath) 
fname = os.path.split(fpath)[1]

# data search
pattern = r"[-+]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][-+]?\d+)?"

headlines = 0
with open(fpath, 'r', encoding='ansi') as (f):
    # head lines
    while not re.match(pattern, f.readline().split()[0]):
        headlines += 1
            
data = pd.read_table(fpath, sep='\t', skiprows=headlines, 
            names=['freq', 'temp', "eps_real", "eps_imag","sigma"],                        
            encoding = "ISO-8859-1") 
            
# str to float
try:
    data.applymap(lambda x: float(x))
except:
    # pandas ver. > 2.1.0, map instead applymap !
    data.map(lambda x: float(x))
    
data.sort_values(by=["temp", "freq"], ascending=[True, False], 
                                                   inplace=True)

#----------------------------------------

fig, axes = plt.subplots(2,3, figsize=(18, 12),subplot_kw={"projection": "3d"})

y = data.temp.unique()
y_len = len(y)

fr = data.loc[data['freq'] == data['freq'][0]]
x_len = (fr).index[1]

x = (data['freq'].values)[0:x_len]

z = data['eps_imag'].values

colormap = 'coolwarm' #,  
log_norm = LogNorm(vmin=0.1, vmax=z.max())

def Plot_3D(ax):
    X, Y = np.meshgrid(x, y)   
    Z = np.reshape(z, (y_len, x_len))
    ax.set_xscale('log')
    ax.set_yscale('log')
    ax.set_zscale('log')
    ax.set_xlabel("Freq")
    ax.set_ylabel("Temp")
    ax.set_zlabel("Eps")
    ax.plot_surface(X, Y, Z, cmap= colormap, norm =log_norm)

axes[0,0].remove()

axes[0,1].set_title("X,Y,Z log scale")
Plot_3D(axes[0,1])

axes[0,2].set_title("y >= 0")
y = np.maximum(y, 0)
Plot_3D(axes[0,2])

axes[1,0].set_title("y and z >= 0")
z = np.maximum(z, 0)
Plot_3D(axes[1,0])

axes[1,1].set_title("y >= 1, z >= 0")
y = np.maximum(y, 1)
Plot_3D(axes[1,1])

axes[1,2].set_title("y and z >= 1")
z = np.maximum(z, 1)
Plot_3D(axes[1,2])

Actual outcome

Image

Expected outcome

Correct 3d surface plot even with negative of zero input values. (Probably with discarded negative data). And/Or warning about inappropriate data .

Additional information

I created this test example to observe an issue.

Hi, I wrote a program for output experimental 3D dielectric spectra from text data (with a PyQt5 interface). To make the data more understandable, they should be displayed in log scale. Matplotlib v3.11.0rc2 just added this feature. I would like to thank everyone who contributes to matplotlib.

The input data file is a Eps values ​​versus frequency and temperature. Temperature values ​​in the test data (attached to report) range from -150 to 120°C. Eps values ​​can be negative (although this is incorrect "overshoot", I used it to observe an issue).

I noticed that, 3D surface plot axes are behaving strangely, in log scale if the data contains negative or zero values.

test NUMBER3 CL 0_03 -150 TO 120 STEP 5.TXT

Operating system

Windows 10 / 11

Matplotlib Version

3.11.0rc2

Matplotlib Backend

module://matplotlib_inline.backend_inline

Python version

3.13 / 3.14.2

Jupyter version

Installation

pip

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions