I currently wish to make a tricontorf plot for a large 2D dataset
import matplotlib.pyplot as plt
import numpy as np
# Load the 3D data file
data = np.genfromtxt("data.txt", skip_header=14, delimiter="\t", dtype = float)
reflect = data[:,0]
emiss = data[:,1]
tempdiff = data[:,4]
fig, ax = plt.subplots()
cb = ax.tricontourf(reflect, emiss, tempdiff, 200, vmin = -800, vmax = 800, cmap = "seismic")
cbar = plt.colorbar(cb)
cbar.set_label(r'z', rotation = 270, labelpad = 13)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_xlim([0.6,1])
ax.set_ylim([0,0.4])
plt.savefig('plot.pdf', bbox_inches='tight', format='pdf')
plt.savefig('plot.png', dpi=300, bbox_inches='tight', format='png')
plt.show()
However, we can see that there is a large negative tail to z as the dataset has some large negative values in z. I wish to use a divergent color map so the white line in the "Seismic" color map lies at z=0. Is there a way to force a symmetric color bar from -800 to 800 without this large tail we see in the image?
I have tried using the vmin and vmax options in tricontorf but this only scales the range of the color map itself rather than the color bar.
Data file can be found here: https://drive.google.com/file/d/1ydPkAwtYkq7xeQxdw3t5obTAkXsdCrIS/view?usp=sharing
I played around with this problem for a while but wasn't able to get the desired results using the normal methods. So, I resorted to using the function from this answer, but I made the following modifications:
fig
and ax
as optional arguments. If they aren't provided, then it will automatically find them. For tricontourf
, it seems to need CS.axes
instead of CS.ax
that was in the original answer.kwargs.get("extend")
, which returns None
if "extend"
is not a key. This avoids the verbose check for "extend"
being a key and then checking the value.So, the code now becomes:
import matplotlib.pyplot as plt
import numpy as np
plt.close("all")
reflect, emiss, _, _, tempdiff = np.genfromtxt("data.txt",
skip_header=14,
delimiter="\t",
dtype=float,
unpack=True)
def clippedcolorbar(CS, fig=None, ax=None, **kwargs):
"""https://stackoverflow.com/a/55403314/12131013"""
from matplotlib.cm import ScalarMappable
from numpy import arange, floor, ceil
if ax is None:
ax = CS.axes
if fig is None:
fig = ax.get_figure()
vmin = CS.get_clim()[0]
vmax = CS.get_clim()[1]
m = ScalarMappable(cmap=CS.get_cmap())
m.set_array(CS.get_array())
m.set_clim(CS.get_clim())
step = CS.levels[1] - CS.levels[0]
cliplower = CS.zmin < vmin
clipupper = CS.zmax > vmax
noextend = kwargs.get("extend") == "neither"
# set the colorbar boundaries
boundaries = arange((floor(vmin/step)-1+1*(cliplower and noextend))
* step, (ceil(vmax/step)+1-1*(clipupper and noextend))*step, step)
kwargs["boundaries"] = boundaries
# if the z-values are outside the colorbar range, add extend marker(s)
# This behavior can be disabled by providing extend="neither" to the function call
if kwargs.get("extend") in [None, "min", "max"]:
extend_min = cliplower or kwargs.get("extend") == "min"
extend_max = clipupper or kwargs.get("extend") == "max"
if extend_min and extend_max:
kwargs["extend"] = "both"
elif extend_min:
kwargs["extend"] = "min"
elif extend_max:
kwargs["extend"] = "max"
return fig.colorbar(m, ax=ax, **kwargs)
fig, ax = plt.subplots()
cb = ax.tricontourf(reflect, emiss, tempdiff, 200,
vmin=-800, vmax=800,
cmap="seismic")
cbar = clippedcolorbar(cb, fig, ax, extend="neither")
cbar.set_label(r"z", rotation=270, labelpad=13)
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.set_xlim([0.6, 1])
ax.set_ylim([0, 0.4])
fig.show()
Also, I'm not sure if you shared a different dataset than the one used to make your plot because the contour levels are slightly different, even when I run your exact code.