Change range of colors in plot(imshow)? - python

Values in my matrix called 'energy' are close enough to each other: e.g. one value can be 500, another one 520. And i want to see the color difference on my plot more precisely. Like for the smallest value in my data it should be the very dark color and for the highest value it should be the very bright color.
I have the following code:
fig = plt.figure(figsize=(10, 10))
ax = fig.add_subplot(111)
plt.imshow(energy[0:60, 0:5920], cmap='Reds')
ax.axes.set_aspect(aspect=100)
plt.grid(color='yellow')
plt.title('My plot')
plt.xlabel('Length points')
plt.ylabel('Time points(seconds)')
import matplotlib.ticker as plticker
loc = plticker.MultipleLocator(base=500)
ax.xaxis.set_major_locator(loc)
plt.show()
I get the following plot:
plot of energy
Other words i'd love to get this plot more colorful.
Thanks in advance.

You can set a custom range either through a custom colormap or adjusting the range value to show using the keywords vmin and vmax. For example:
from matplotlib.pyplot import subplots
import numpy as np
fig, ax = subplots()
h = ax.imshow(np.random.rand(10,10) * 10, vmin = 0,\
vmax = 2, cmap = 'Reds')
fig.colorbar(h)
fig.show()
Which produces the colors within 0, 2 value
Alternatively you can rescale your data or adjust your colormap, see the maplotlib docs for more info.

Related

How to overlay two 2D-histograms in Matplotlib?

I have two datasets (corresponding with the time-positional data of hydrogen atoms and time-positional data of alumina atoms) in the same system.
I want to plot the density of each element by overlaying two hist2d plots using matplotlib.
I am currently doing this by setting an alpha value on the second hist2d:
fig, ax = plt.subplots(figsize=(4, 4))
v = ax.hist2d(x=alx, y=aly,
bins=50, cmap='Reds')
h = ax.hist2d(x=hx, y=hy,
bins=50, cmap='Blues',
alpha=0.7)
ax.set_title('Adsorption over time, {} K'.format(temp))
ax.set_xlabel('picoseconds')
ax.set_ylabel('z-axis')
fig.colorbar(h[3], ax=ax)
fig.savefig(savename, dpi=300)
I do get the plot that I want, however the colors seem washed out due to the alpha value.
Is there a more correct way to do generate such plots?
One way to achieve this would be a to add fading alphas towards lower levels to the existing color maps:
import numpy as np
import matplotlib.pylab as pl
from matplotlib import pyplot as plt
from matplotlib.colors import ListedColormap
# modify existing Reds colormap with a linearly fading alpha
red = pl.cm.Reds # original colormap
fading_red = red(np.arange(red.N)) # extract colors
fading_red[:, -1] = np.linspace(0, 1, red.N) # modify alpha
fading_red = ListedColormap(fading_red) # convert to colormap
# data generation
random_1 = np.random.randn(10000)+1
random_2 = np.random.randn(10000)+1
random_3 = np.random.randn(10000)
random_4 = np.random.randn(10000)
# plot
fig, ax = plt.subplots(1,1)
plt.hist2d(x=random_3, y=random_4, bins=100, cmap="Blues")
plt.hist2d(x=random_1, y=random_2, bins=50, cmap=fading_red)
plt.show()

Change cmap transition points in matplotlib

Is there a way to change the transition values of a continuous colormap (cmap) in matplotlib? I want to use "vlag" to color a heatmap, however my values only typically range from 0 to 0.6 (instead of 0-1). I could renormalize my data or use vmin & vmax, however I was curious if there was a way to set transition points for vlag between 0-1. There are three colors in vlag (blue, white, and red). Having set transition points will allow for an apples to apples comparison between different heatmaps.
If the colormap only contains few colors, a BoundaryNorm lets you specify the transition points.
For a colormap with a smooth range of colors, a TwoSlopeNorm lets you move the spots where the transitions start happening.
from matplotlib.colors import TwoSlopeNorm
import seaborn as sns # for the 'vlag' colormap
import numpy as np
x = np.linspace(0, 10, 200)
y = np.sin(x)**2
fig, axs = plt.subplots(ncols=2, figsize=(12, 4))
scat0 = axs[0].scatter(x, y, c=y, cmap='vlag')
axs[0].set_title('default norm')
plt.colorbar(scat0, ax=axs[0])
norm = TwoSlopeNorm(vmin=0., vcenter=0.3, vmax=1)
scat1 = axs[1].scatter(x, y, c=y, cmap='vlag', norm=norm)
axs[1].set_title('TwoSlopeNorm')
plt.colorbar(scat1, ax=axs[1])
plt.tight_layout()
plt.show()

Removing legend from mpl parallel coordinates plot?

I have a parallel coordinates plot with lots of data points so I'm trying to use a continuous colour bar to represent that, which I think I have worked out. However, I haven't been able to remove the default key that is put in when creating the plot, which is very long and hinders readability. Is there a way to remove this table to make the graph much easier to read?
This is the code I'm currently using to generate the parallel coordinates plot:
parallel_coordinates(data[[' male_le','
female_le','diet','activity','obese_perc','median_income']],'median_income',colormap = 'rainbow',
alpha = 0.5)
fig, ax = plt.subplots(figsize=(6, 1))
fig.subplots_adjust(bottom=0.5)
cmap = mpl.cm.rainbow
bounds = [0.00,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0]
norm = mpl.colors.BoundaryNorm(bounds, cmap.N,)
plt.colorbar(mpl.cm.ScalarMappable(norm = norm, cmap=cmap),cax = ax, orientation = 'horizontal',
label = 'normalised median income', alpha = 0.5)
plt.show()
Current Output:
I want my legend to be represented as a color bar, like this:
Any help would be greatly appreciated. Thanks.
You can use ax.legend_.remove() to remove the legend.
The cax parameter of plt.colorbar indicates the subplot where to put the colorbar. If you leave it out, matplotlib will create a new subplot, "stealing" space from the current subplot (subplots are often referenced to by ax in matplotlib). So, here leaving out cax (adding ax=ax isn't necessary, as here ax is the current subplot) will create the desired colorbar.
The code below uses seaborn's penguin dataset to create a standalone example.
import matplotlib.pyplot as plt
import matplotlib as mpl
import seaborn as sns
import numpy as np
from pandas.plotting import parallel_coordinates
penguins = sns.load_dataset('penguins')
fig, ax = plt.subplots(figsize=(10, 4))
cmap = plt.get_cmap('rainbow')
bounds = np.arange(penguins['body_mass_g'].min(), penguins['body_mass_g'].max() + 200, 200)
norm = mpl.colors.BoundaryNorm(bounds, 256)
penguins = penguins.dropna(subset=['body_mass_g'])
parallel_coordinates(penguins[['bill_length_mm', 'bill_depth_mm', 'flipper_length_mm', 'body_mass_g']],
'body_mass_g', colormap=cmap, alpha=0.5, ax=ax)
ax.legend_.remove()
plt.colorbar(mpl.cm.ScalarMappable(norm=norm, cmap=cmap),
ax=ax, orientation='horizontal', label='body mass', alpha=0.5)
plt.show()

matplotlib: Why is my multi-colored line plot ignoring boundary values?

I have an anomaly threshold, annotated by an axhline in my plot. I wish to add markers and/or change the color of the line above this threshold. I have followed the following matplotlib tutorial:
https://matplotlib.org/3.1.1/gallery/lines_bars_and_markers/multicolored_line.html
As well as this utilized this question/answer here on SO:
How to plot multi-color line if x-axis is date time index of pandas
To produce this plot:
That looks pretty good, until you zoom in on a subset of the data:
Unfortunately, this solution doesn't seem to work for my purposes. I'm not sure if this is an error on my part or not, but clearly the lines are red below the threshold. An additional problem in my view is how clunky and long the code is:
import matplotlib.dates as mdates
from matplotlib.collections import LineCollection
from matplotlib.colors import ListedColormap, BoundaryNorm
fig, ax = plt.subplots(figsize=(15,4))
inxval = mdates.date2num(dates.to_pydatetime())
points = np.array([inxval, scores]).T.reshape(-1,1,2)
segments = np.concatenate([points[:-1],points[1:]], axis=1)#[-366:]
cmap = ListedColormap(['b', 'r'])
norm = BoundaryNorm([0, thresh, 40], cmap.N)
lc = LineCollection(segments, cmap=cmap, norm=norm)
lc.set_array(scores)
ax.add_collection(lc)
monthFmt = mdates.DateFormatter("%Y")
ax.xaxis.set_major_formatter(monthFmt)
ax.xaxis.set_major_locator(mdates.YearLocator())
ax.autoscale_view()
# ax.axhline(y=thresh, linestyle='--', c='r')
plt.show()
dates and scores, and thresh generation aren't shown here, but can be re-produced with random numbers to make this code run
Question:
Why are the red lines in my chart sometimes falling below the threshold value? And is there a way to abbreviate the amount of code required for this purpose?
One option would be to draw two lines with the same data then use an invisible axhspan object to clip one of the lines under the threshold:
f, ax = plt.subplots()
x = np.random.exponential(size=500)
line_over, = ax.plot(x, color="b")
line_under, = ax.plot(x, color="r")
poly = ax.axhspan(0, 1, color="none")
line_under.set_clip_path(poly)

Setting colorbar to show values outside of data range in matplotlib

I am trying to create a figure in which the colorbar will extend beyond the data range (go higher than the max value of data). The ultimate purpose is that I need to plot a series of images (as time progresses) of model output, and each hour is stored in a separate file. I would like the colorbar for all the figures to be the same, so that they can be joined into an animation.
Here is a sample script:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 360, 1.5)
y = np.arange(-90, 90, 1.5)
lon, lat = np.meshgrid(x, y)
noise = np.random.random(lon.shape) # values in range [0, 1)
fig = plt.figure()
ax = fig.add_subplot(111)
plt.hold(True)
plt.contourf(lon, lat, noise)
plt.colorbar()
This produces the following figure:
I've been trying to set the limits of the colorbar to values outside the data range (for example, from -1. to 2.) using two methods that I've found online:
Setting vmin=-1 and vmax=2 inside the plotting line:
fig = plt.figure()
ax = fig.add_subplot(111)
plt.hold(True)
plt.contourf(lon, lat, noise, vmin=-1., vmax=2.)
plt.colorbar()
This seems to only change the colors displayed, so that the first color in the colormap would correspond to -1 and the last one to 2, but it does not extend the colorbar to show those values (left figure in link below).
The other one was to try and enforce ticks in the colorbar to extend to that range:
fig = plt.figure()
ax = fig.add_subplot(111)
plt.hold(True)
plt.contourf(lon, lat, noise)
plt.colorbar(ticks=np.arange(-1,2.1, .2))
This results in tick position as defined, but only for the range in which there's data, i.e., the colorbar still doesn't extend from -1 to 2 (middle figure in link below).
Does anyone know how I would get it to do what I want? Something like the right figure at this link: http://orca.rsmas.miami.edu/~ajdas1/SOF/n.html
For most 2D plotting function (such as imshow, pcolor, etc.) setting vmin and vmax does the job. However, contourf (and also contour) take the levels at which you ask it to draw the contours into account when mapping the colors:
If you don't specify the levels argument, then the function automatically generates 10 equally spaced levels from the minimal to maximal value of your data. So to achieve what you want (consistency over varying input data) you have to specify the levels explicitly:
import matplotlib.pyplot as plt
import numpy as np
# generate data
x = np.arange(0, 360, 1.5)
y = np.arange(-90, 90, 1.5)
lon, lat = np.meshgrid(x, y)
noise = np.random.random(lon.shape)
# specify levels from vmim to vmax
levels = np.arange(-1, 2.1, 0.2)
# plot
fig = plt.figure()
ax = fig.add_subplot(111)
plt.contourf(lon, lat, noise, levels=levels)
plt.colorbar(ticks=levels)
plt.show()
Result:
Colorbar limits are not respecting set vmin/vmax in plt.contourf. How can I more explicitly set the colorbar limits? gives a good example to solve this problem.
These can be done if the colorbars of a series of images share a same ScalarMappable instance, but not the corresponding ContourSet instance which is created by each plt.contourf().
More details in https://matplotlib.org/3.2.1/api/_as_gen/matplotlib.figure.Figure.html#matplotlib.figure.Figure.colorbar
We can solve the problem like this:
import matplotlib.pyplot as plt
import matplotlib.cm as cm
fig = plt.figure()
ax = fig.add_subplot(111)
m0=ax.contourf(lon, lat, noise, vmin=-1., vmax=2.)
m = plt.cm.ScalarMappable(cmap=cm.coolwarm)
m.set_clim(-1, 2)
fig.colorbar(m,ax=ax)
Instead of using m0 (QuadContourSet instance created by contourf), we use m (ScalarMappable instance) in fig.colorbar(), because colorbar is used to describe the mappable parameter.
https://matplotlib.org/3.2.1/api/_as_gen/matplotlib.figure.Figure.html#matplotlib.figure.Figure.colorbar
clim in m.set_clim should be matched to vmin/vmax in contourf.

Categories

Resources