I want to plot a Ramachandron plot. On this kind of graph, x goes from -180° to 180°, and so does y. I want a tick every 60 degrees. So here is the code I use:
import matplotlib.pyplot as plt
from matplotlib.colors import LogNorm
x = [-179, 179]
y = [-179, 179]
fig = plt.figure(1)
ax = plt.subplot(111)
ax.axis([-180, 180, -180, 180])
ax.set_xticks([-180, -120, -60, 0, 60, 120, 180])
ax.set_yticks([-180, -120, -60, 0, 60, 120, 180])
# 1 bim = 1 degree
# !!! Logarithmic normalization of the colors
plt.hist2d(x, y, bins=180, norm=LogNorm())
plt.colorbar()
plt.show()
On this working example, I'm plotting only two points. But the ticks -180 and 180 are not shown, for none of the axes:
If I change x and y to:
x = [-180, 180]
y = [-180, 180]
I get what I want:
Is there a way to achieve the second result without altering the data ?
You use hist2d, set axis ticks after plotting:
import matplotlib.pyplot as plt
from matplotlib.colors import LogNorm
x = [-179, 179]
y = [-179, 179]
fig = plt.figure(1)
ax = plt.subplot(111)
# 1 bim = 1 degree
# !!! Logarithmic normalization of the colors
plt.hist2d(x, y, bins=180, norm=LogNorm())
plt.colorbar()
ax.axis([-180, 180, -180, 180])
ax.set_xticks([-180, -120, -60, 0, 60, 120, 180])
ax.set_yticks([-180, -120, -60, 0, 60, 120, 180])
plt.show()
Related
I want to build a colormap and a colorbar with specific values for a map of accumulated rainfall, as shown in the image:
enter image description here
This is the function that I have that graphs the map, however, it does not work correctly for me, currently it is not graphing the blue color, which goes between the values 1 to 5:
def plot_acumradar(path_plot, name_plot,lon, lat, lon_plot, lat_plot, radaracum):
data_g1 = radaracum
data_g1[data_g1==0] = np.nan
maxlon = -74.4000
minlon = -76.7000
minlat = 5.1000
maxlat = 7.3000
RR = [0, 0, 70, 44,255,255,255,255,128, 255]
GG = [255, 0,220,141,255,200,142, 0, 0, 153]
BB = [255,255, 45, 29, 75, 50, 0, 0,128, 255]
VariableLimits = np.array([1.,5.,10.,20.,30.,40.,50.,65., 80., 100.])
Custom_Color = list(zip(RR, GG,BB))
scale_factor = ((255-0.)/(VariableLimits.max() - VariableLimits.min()))
new_Limits = list(np.array(np.round((VariableLimits-VariableLimits.min())*\
scale_factor/255.,3),dtype = float))
Custom_Color = list(map(lambda x: tuple(ti/255. for ti in x) ,\
Custom_Color))
nueva_tupla = [((new_Limits[i]),Custom_Color[i],) for i in range(len(Custom_Color))]
my_colorbar = clr.LinearSegmentedColormap.from_list('RADAR',nueva_tupla)
norm = clr.BoundaryNorm(VariableLimits, ncolors=256)
print ('Plot imagen')
plt.close()
plt.cla()
plt.clf()
fig = plt.figure(figsize=(5.1,4.9))
fig.subplots_adjust(left = 0.0,right = 1.,top = 0.9, bottom = 0.15, hspace = 0.2,\
wspace = 0.2)
ax = fig.add_subplot(1, 1, 1, projection=ccrs.Mercator(central_longitude=lon.mean(),
min_latitude=min(lat),
max_latitude=max(lat)))
projection = ccrs.PlateCarree()
ax.set_extent([minlon,maxlon,minlat,maxlat], crs=projection)
ax.tick_params(top='off', right='off', bottom ='off', left='off')
pm = ax.pcolormesh(lon_plot, lat_plot, data_g1, transform=projection, cmap = my_colorbar,\
norm = norm)
fig.colorbar(pm, ax=ax, extend='both', orientation='vertical')
plt.savefig(path_plot+name_plot, transparent=True)
and the graph looks like this:
enter image description here
How do I make it exactly the same as the first figure?
The first figure shows 10 colors, so 11 boundaries are needed. The code below temporarily adds an extra boundary, but doesn't display its tick label. cbar.ax.set_title() is used to add text on top of the colorbar. When working with a BoundaryNorm, the ListedColormap can be created without providing tuples.
To set the ticks and their labels at the left of the colorbar, cbar.ax.tick_params can be used. Some extra padding is needed, which can be added via fig.colorbar(..., padding=).
The example code uses a scatterplot to test the colorbar
import matplotlib.pyplot as plt
import matplotlib.colors as clr
import numpy as np
RR = [0, 0, 70, 44, 255, 255, 255, 255, 128, 255]
GG = [255, 0, 220, 141, 255, 200, 142, 0, 0, 153]
BB = [255, 255, 45, 29, 75, 50, 0, 0, 128, 255]
colors = np.c_[RR, GG, BB] / 255
my_colormap = clr.LinearSegmentedColormap.from_list('RADAR', colors)
VariableLimits = np.array([1, 5, 10, 20, 30, 40, 50, 65, 80, 100])
norm = clr.BoundaryNorm(np.append(VariableLimits, 1000), ncolors=256)
fig, ax = plt.subplots()
pm = ax.scatter(np.random.rand(100), np.random.rand(100), c=np.random.uniform(0, 120, 100),
cmap=my_colormap, norm=norm)
cbar = fig.colorbar(pm, ticks=VariableLimits, pad=0.1, ax=ax)
cbar.ax.set_title('(mm)', size=8)
cbar.ax.tick_params(left=True, right=False, labelleft=True, labelright=False)
plt.show()
I have a time-longitude array which I am plotting using the matplotlib contourf function. My longitude values span from [-180, 180] and as such appear on the x-axis in this order.
I would like my x-axis to run from 0 degrees to 0 degrees, so my x-axis ticks would be (0, 60, 120, 180, -120, -60, 0). Is there an easy way to do this?
My current code is:
levels = np.arange(0, 5+0.5, 0.5)
lon_ticks = np.array([0, 60, 120, 180, -120, -60, 0])
for i in range(3):
fig = plt.figure(figsize = (15, 15))
ax = fig.add_subplot(1, 1, 1)
im = ax.contourf(lon,date_list,TRMM_lat_mean[:,:,i],
levels = levels, extend = 'both', cmap = 'gist_ncar')
cb = plt.colorbar(im)
plt.savefig("C:/Users/amcna/Desktop/fig{number}.png".format(number = i))
Which outputs:
!(https://imgur.com/epedcTu)
As you can see my longitude array spans from [-180, 180], however I wish it to be arranged in the order I specified above.
Since your data is cyclic, a representation through polar coordinates might work:
Example:
def f(x, y):
return np.sin(x) ** 10 + np.cos(10 + y * x) * np.cos(x)
x = np.radians([0, 60, 120, 180, -120, -60, 0])
y = np.arange(0, 5+0.5, 0.5)
X, Y = np.mesh
grid(x, y)
Z = f(X, Y)
#-- Plot... ------------------------------------------------
fig, ax = plt.subplots(subplot_kw=dict(projection='polar'))
ax.contourf(Y, X, Z)
plt.show()
If you don't want to do that, this thread might help you: Handling cyclic data with matplotlib contour/contourf
This question already has answers here:
Matplotlib fill between multiple lines
(3 answers)
Closed 2 years ago.
How do I fill the color between two curves? I want to fill the area bounded by the curve above the horizontal line with one color, and the area bounded by the curve below the horizontal line with a second different color..
random_x = [-180, -160, -140, -100, -70, -40, -10, 20, 50, 80, 110, 120, 140, 165,175, 180]
random_y = [2000000, 700000, 2800000, 4200000, 1000000, 1200000, 3500000, 2000000, 800000, 3900000, 2500000, 1000000,3400000,2400000,2100000, 2000000]
interp1d_cubic = interp1d(random_x, random_y, kind='cubic')
x3 = np.linspace(-180, 180, 100000)
plt.plot(x3, interp1d_cubic(x3), c='k')
y_coord = np.linspace(980000,980000,100000)
plt.plot(x3, y_coord, c='k', linestyle='--')
plt.show()
The resulting current plot looks as follows:
This is definetly not a perfect way but it does work. Simply plot lines between the two points on the lines in the specified color. Then you can change the width of the lines and the spacing of the lines to "fill" the area between them while keeping a good enough resolution.
import matplotlib.pyplot as plt
from scipy.interpolate import interp1d
import numpy as np
random_x = [-180, -160, -140, -100, -70, -40, -10, 20, 50, 80, 110, 120, 140, 165,175, 180]
random_y = [2000000, 700000, 2800000, 4200000, 1000000, 1200000, 3500000, 2000000, 800000, 3900000, 2500000, 1000000,3400000,2400000,2100000, 2000000]
interp1d_cubic = interp1d(random_x, random_y, kind='cubic')
x3 = np.linspace(-180, 180, 100000)
plt.plot(x3, interp1d_cubic(x3), c='k')
y_coord = np.linspace(980000,980000,100000)
plt.plot(x3, y_coord, c='k', linestyle='--')
# Variable names changed for convenience
y1 = interp1d_cubic(x3)
y2 = y_coord
x = x3
# With default linewidth, plotting a line at every
# 200th point was just fine
for i in range(0,len(x3),200):
if y1[i] > y2[i]:
c = 'r'
else:
c = 'b'
plt.plot([x[i],x[i]], [y1[i], y2[i]], color = c, zorder=0)
plt.show()
Which gives the following result:
If you are simply looking for a visual representation and time complexity is not an issue, this should do just fine.
Here's what I came up with by plotting thick line segments.
The coloration is blue, with varying alpha, 0 < alpha < 1.
My workaround doens't work as I'd like because I don't have a legend (I want a legend that shows a gradient of the blue at varying alpha).
Additionally, I've found that matplotlib scales funny. There should be no overlap of the bars, but if I adjust the window size, the gap between the line segments will change.This is the same figure as the earlier one, just after I've resized the figure window with my mouse.
I'm not sure if there's a better way to go about accomplishing this, or if there's a different package I can use.
Here's the snippet of code that I'm using.
import matplotlib.pyplot as plt
x1 =[0, 19, 39, 46, 60, 79]
x2 = [19, 39, 46, 60, 79, 90]
alpha_list = [-0.8402, -0.6652, 0.0, -0.5106, -0.8074, 0.0]
plt.figure()
for idx,x in enumerate(x1):
plt.plot([x1[idx],x2[idx]],[0,0],color = 'blue',alpha=alpha_list[idx],linewidth =20)
plt.show()
I suppose alpha is just a workaround for using different shades of blue? In that case the Blues colormap can be used instead.
Several lines can be plotted using a LineCollection.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
x1 =[0, 19, 39, 46, 60, 79]
x2 = [19, 39, 46, 60, 79, 90]
alpha_list = [-0.8402, -0.6652, 0.0, -0.5106, -0.8074, 0.0]
verts = np.dstack((np.c_[x1, x2], np.zeros((len(x1), 2))))
fig, ax = plt.subplots()
lc = LineCollection(verts, linewidth=40, cmap="Blues_r", array=np.array(alpha_list))
ax.add_collection(lc)
ax.autoscale()
ax.set_ylim(-1,1)
fig.colorbar(lc)
plt.show()
I think a workaround would be to use plt.barh. Here is an example using normalized color maps. Each color gets converted to RGBA before it can be passed to plt.barh.
import matplotlib.pyplot as plt
from matplotlib import colors
import matplotlib.cm as cmx
x1 =[0, 19, 39, 46, 60, 79]
x2 = [19, 39, 46, 60, 79, 90]
values = range(len(x1))
jet = cm = plt.get_cmap('jet')
cNorm = colors.Normalize(vmin=0, vmax=values[-1])
scalarMap = cmx.ScalarMappable(norm=cNorm, cmap=jet)
fig, ax = plt.subplots()
for idx, x, y in zip(values,x1, x2):
colorVal = scalarMap.to_rgba(values[idx])
start = x
end = y
width=end-start
ax.barh(y = 0, width = width, left=start, height = 0.1, label = str(idx), color=colorVal)
ax.set_ylim(-.5,0.5)
ax.legend()
which returns:
If you really want to just change the alpha transparency of a single color, you would just have to input alpha_list[idx] for the last element to the RGBA tuple colorVal. For some reason, RGBA did not like negative alpha values, so notice I changed them all to positive
fig, ax = plt.subplots()
alpha_list = [0.8402, 0.6652, 0.01, 0.5106, 0.8074, 0.0]
for idx, x, y in zip(values,x1, x2):
colorVal = (0.0, 0.3, 1.0, alpha_list[idx])
start = x
end = y
width=end-start
ax.barh(y = 0, width = width, left=start, height = 0.1, label = str(idx), color=colorVal)
ax.set_ylim(-.5,0.5)
ax.legend()
I have been trying to center the x and y ticks of my imshow but without success.
The desired yticks should be: [ 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000] and xticks: [ 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55] but aligned/centered. E.g. line 1 should have the 100 value exactly in the middle of the line space (middle of the yellow box/pixel).
import numpy as np
import matplotlib.pyplot as plt
X = np.random.rand(10,11)
plt.figure(dpi=130)
plt.imshow(X, cmap = 'jet', interpolation=None, extent=[5,55,1000,100], aspect='auto')
Here, the values 5 does not appear at all in the x axis.
I have also tried the following, x axis if fine but not the y axis
plt.figure(dpi=130)
X = np.random.rand(10,11)
plt.imshow(X, cmap = 'jet', interpolation=None, extent=[2.5,57.5,1000,100], aspect='auto')
ax = plt.gca()
xticks = cluster_space
yticks = space_segment
ax.set_xticks(xticks)
ax.set_yticks(yticks)
In general, to have the pixels centered, you need to set the extent to range from the lowest pixel coordinate minus half the pixel width to the highest pixel coordinate plus half the pixel width.
import numpy as np; np.random.seed(42)
import matplotlib.pyplot as plt
X = np.random.rand(10,11)
plt.figure()
centers = [5,55,1000,100]
dx, = np.diff(centers[:2])/(X.shape[1]-1)
dy, = -np.diff(centers[2:])/(X.shape[0]-1)
extent = [centers[0]-dx/2, centers[1]+dx/2, centers[2]+dy/2, centers[3]-dy/2]
plt.imshow(X, cmap = 'jet', interpolation=None, extent=extent, aspect='auto')
plt.xticks(np.arange(centers[0], centers[1]+dx, dx))
plt.yticks(np.arange(centers[3], centers[2]+dy, dy))
plt.show()