I made a histogram of array x with each bar color-coded according to the average of another property y in that bin. How can I make an associated colorbar?
norm = matplotlib.colors.Normalize(vmin=np.min(y), vmax=np.max(y))
cmap = cm.jet
m = cm.ScalarMappable(norm=norm, cmap=cmap)
fig = plt.figure()
n, bins, patches= plt.hist(x, bins = np.arange(0,max_x) + 0.5)
for i in range(np.size(patches)):
plt.setp(patches[i],color=m.to_rgba(y[i]))
plt.colorbar(norm=norm,cmap=cmap)
plt.show()
This colorbar returns an error message " No mappable was found to use for colorbar creation. First define a mappable such as an image (with imshow) or a contour set (with contourf)."
Found a way using a "ScalarMappable":
sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm)
sm._A = []
plt.colorbar(sm)
Related
I have several plots and one of these showed below:
Example plot
Problem is I have many plots and I need to put the legend differently according to the position where x=0 and line of x=0 may vary in different plots.
How can I achieve this?
besides, bbox_to_anchor just allow me locate relatively to the fig, but have no idea of the inside (x,y) coordinate.
This is the part plotting:
ax.errorbar(x=x, y=y_erd, yerr=e_erd, fmt='-o',ecolor='orange',elinewidth=1,ms=5,mfc='wheat',mec='salmon',capsize=3)
ax.errorbar(x=x, y=y_ers, yerr=e_ers, fmt='-o',ecolor='blue',elinewidth=1,ms=5,mfc='wheat',mec='salmon',capsize=3)
ax.legend(['ERD', 'ERS'], loc="upper left", bbox_to_anchor=(1, 0.85),fontsize='x-small')
ax.axhline(y=0, color='r', linestyle='--')
We have created a code to calculate the zero position of the x and y axes using a simple sample as an example. First, get the tick values for each axis. Then, use the obtained value to get the index of zero. The next step is to calculate the position of the tick marks for the difference between the minimum and maximum values. From the array, we obtain the coordinates based on the zero index we obtained earlier. Set the obtained coordinates to bbox_to_anchor=[].
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(-10, 10, 500)
y = np.sin(x)
fig, ax = plt.subplots()
ax.plot(x, y, label='x=0,y=0')
xticks, yticks = ax.get_xticks(), ax.get_yticks()
xpos, ypos = 0, 0
for i,(x,y) in enumerate(zip(xticks, yticks)):
if x == 0:
xpos = i
if y == 0:
ypos = i
print(xpos, ypos)
x_min, x_max = ax.get_xlim()
xticks = [(tick - x_min)/(x_max - x_min) for tick in xticks]
y_min, y_max = ax.get_ylim()
yticks = [(tick - y_min)/(y_max - y_min) for tick in yticks]
print(xticks[xpos], yticks[ypos])
ax.legend(bbox_to_anchor=[xticks[xpos], yticks[ypos]], loc='center')
plt.show()
In Matplotlib, there is the colorbar property extend that makes pointed end(s) for out-of- range values. How would you do the third subplots with Bokeh or Holoview?
I added a Matplotlib example below:
import numpy as np
import matplotlib.pyplot as plt
# setup some generic data
N = 37
x, y = np.mgrid[:N, :N]
Z = (np.cos(x*0.2) + np.sin(y*0.3))
# mask out the negative and positive values, respectively
Zpos = np.ma.masked_less(Z, 0)
Zneg = np.ma.masked_greater(Z, 0)
fig, (ax1, ax2, ax3) = plt.subplots(figsize=(13, 3), ncols=3)
# plot just the positive data and save the
# color "mappable" object returned by ax1.imshow
pos = ax1.imshow(Zpos, cmap='Blues', interpolation='none')
# add the colorbar using the figure's method,
# telling which mappable we're talking about and
# which axes object it should be near
fig.colorbar(pos, ax=ax1)
# repeat everything above for the negative data
neg = ax2.imshow(Zneg, cmap='Reds_r', interpolation='none')
fig.colorbar(neg, ax=ax2)
# Plot both positive and negative values between +/- 1.2
pos_neg_clipped = ax3.imshow(Z, cmap='RdBu', vmin=-1.2, vmax=1.2,
interpolation='none')
# Add minorticks on the colorbar to make it easy to read the
# values off the colorbar.
cbar = fig.colorbar(pos_neg_clipped, ax=ax3, extend='both')
cbar.minorticks_on()
plt.show()
Example plot, colorbar with pointed ends to point out higher values:
Bokeh has a current PR (not finished) to try to add functionality like this: https://github.com/bokeh/bokeh/pull/10781
A quite basic question about ticks' labels for x and y-axis. According to this code
fig, axes = plt.subplots(6,12, figsize=(50, 24), constrained_layout=True, sharex=True , sharey=True)
fig.subplots_adjust(hspace = .5, wspace=.5)
custom_xlim = (-1, 1)
custom_ylim = (-0.2,0.2)
for i in range(72):
x_data = ctheta[i]
y_data = phi[i]
y_err = err_phi[i]
ax = fig.add_subplot(6, 12, i+1)
ax.plot(x_data_new, bspl(x_data_new))
ax.axis('off')
ax.errorbar(x_data,y_data, yerr=y_err, fmt="o")
ax.set_xlim(custom_xlim)
ax.set_ylim(custom_ylim)
I get the following output:
With y labels for plots on the first column and x labels for theone along the last line, although I call them off.
Any idea?
As #BigBen wrote in their comment, your issue is caused by you adding axes to your figure twice, once via fig, axes = plt.subplots() and then once again within your loop via fig.add_subplot(). As a result, the first set of axes is still visible even after you applied .axis('off') to the second set.
Instead of the latter, you could change your loop to:
for i in range(6):
for j in range(12):
ax = axes[i,j] # these are the axes created via plt.subplots(6,12,...)
ax.axis('off')
# … your other code here
I have generated a plot that shows a topographic profile with points along the profile that represent dated points. However, these dated points also have symmetric uncertainty values/error bars (that typically vary for each point).
In this example, I treat non-dated locations as 'np.nan'. I would like to add uncertainty values to the y2 axis (Mean Age) with defined uncertainty values as y2err.
Everytime I use the ax2.errorbar( ... ) line, my graph is squeezed and distorted.
import numpy as np
import matplotlib.pyplot as plt
fig, ax1 = plt.subplots()
#Longitude = x; Elevation = y
x = (-110.75696,-110.75668,-110.75640,-110.75612,-110.75584,-110.75556,-110.75528)
y = (877,879,878,873,871,872,872)
ax1.plot(x, y)
ax1.set_xlabel('Longitude')
# Make the y-axis label, ticks and tick labels match the line color.
ax1.set_ylabel('Elevation', color='b')
ax1.tick_params('y', colors='b')
ax2 = ax1.twinx()
# Mean Age, np.nan = 0.0
y2 = (np.nan,20,np.nan,np.nan,np.nan,np.nan,np.nan)
y2err = (np.nan,5,np.nan,np.nan,np.nan,np.nan,np.nan)
ax2.scatter(x, y2, color='r')
#add error bars to scatter plot points
# (??????) ax2.errorbar(x, y, y2, y2err, capsize = 0, color='black')
ax2.set_ylim(10,30)
ax2.set_ylabel('Mean Age', color='r')
ax2.tick_params('y', colors='r')
fig.tight_layout()
plt.show()
If I do not apply the ax2.errorbar... line my plot looks like the first image, which is what I want but with the points showing uncertainty values (+/- equal on both side of point in the y-axis direction).
Plot of Elevation vs Age without error bars
When I use the ax2.errorbar line it looks like the second image:
Plot when using ax2.errorbar line
Thanks!
I am trying to plot some data with a discrete color bar. I was following the example given (https://gist.github.com/jakevdp/91077b0cae40f8f8244a) but the issue is this example does not work 1-1 with different spacing. For example, the spacing in the example in the link is for only increasing by 1 but my data is increasing by 0.5. You can see the output from the code I have.. Any help with this would be appreciated. I know I am missing something key here but cant figure it out.
import matplotlib.pylab as plt
import numpy as np
def discrete_cmap(N, base_cmap=None):
"""Create an N-bin discrete colormap from the specified input map"""
# Note that if base_cmap is a string or None, you can simply do
# return plt.cm.get_cmap(base_cmap, N)
# The following works for string, None, or a colormap instance:
base = plt.cm.get_cmap(base_cmap)
color_list = base(np.linspace(0, 1, N))
cmap_name = base.name + str(N)
return base.from_list(cmap_name, color_list, N)
num=11
x = np.random.randn(40)
y = np.random.randn(40)
c = np.random.randint(num, size=40)
plt.figure(figsize=(10,7.5))
plt.scatter(x, y, c=c, s=50, cmap=discrete_cmap(num, 'jet'))
plt.colorbar(ticks=np.arange(0,5.5,0.5))
plt.clim(-0.5, num - 0.5)
plt.show()
Not sure what version of matplotlib/pyplot introduced this, but plt.get_cmap now supports an int argument specifying the number of colors you want to get, for discrete colormaps.
This automatically results in the colorbar being discrete.
By the way, pandas has an even better handling of the colorbar.
import numpy as np
from matplotlib import pyplot as plt
plt.style.use('ggplot')
# remove if not using Jupyter/IPython
%matplotlib inline
# choose number of clusters and number of points in each cluster
n_clusters = 5
n_samples = 20
# there are fancier ways to do this
clusters = np.array([k for k in range(n_clusters) for i in range(n_samples)])
# generate the coordinates of the center
# of each cluster by shuffling a range of values
clusters_x = np.arange(n_clusters)
clusters_y = np.arange(n_clusters)
np.random.shuffle(clusters_x)
np.random.shuffle(clusters_y)
# get dicts like cluster -> center coordinate
x_dict = dict(enumerate(clusters_x))
y_dict = dict(enumerate(clusters_y))
# get coordinates of cluster center for each point
x = np.array(list(x_dict[k] for k in clusters)).astype(float)
y = np.array(list(y_dict[k] for k in clusters)).astype(float)
# add noise
x += np.random.normal(scale=0.5, size=n_clusters*n_samples)
y += np.random.normal(scale=0.5, size=n_clusters*n_samples)
### Finally, plot
fig, ax = plt.subplots(figsize=(12,8))
# get discrete colormap
cmap = plt.get_cmap('viridis', n_clusters)
# scatter points
scatter = ax.scatter(x, y, c=clusters, cmap=cmap)
# scatter cluster centers
ax.scatter(clusters_x, clusters_y, c='red')
# add colorbar
cbar = plt.colorbar(scatter)
# set ticks locations (not very elegant, but it works):
# - shift by 0.5
# - scale so that the last value is at the center of the last color
tick_locs = (np.arange(n_clusters) + 0.5)*(n_clusters-1)/n_clusters
cbar.set_ticks(tick_locs)
# set tick labels (as before)
cbar.set_ticklabels(np.arange(n_clusters))
Ok so this is the hack I found for my own question. I am sure there is a better way to do this but this works for what I am doing. Feel free to suggest a better way to do this.
import numpy as np
import matplotlib.pylab as plt
def discrete_cmap(N, base_cmap=None):
"""Create an N-bin discrete colormap from the specified input map"""
# Note that if base_cmap is a string or None, you can simply do
# return plt.cm.get_cmap(base_cmap, N)
# The following works for string, None, or a colormap instance:
base = plt.cm.get_cmap(base_cmap)
color_list = base(np.linspace(0, 1, N))
cmap_name = base.name + str(N)
return base.from_list(cmap_name, color_list, N)
num=11
plt.figure(figsize=(10,7.5))
x = np.random.randn(40)
y = np.random.randn(40)
c = np.random.randint(num, size=40)
plt.scatter(x, y, c=c, s=50, cmap=discrete_cmap(num, 'jet'))
cbar=plt.colorbar(ticks=range(num))
plt.clim(-0.5, num - 0.5)
cbar.ax.set_yticklabels(np.arange(0.0,5.5,0.5))
plt.show()
For some reason I cannot upload the image associated with the code above. I get an error when uploading so not sure how to show the final example. But simply I set the color bar axes for tick labels for a vertical color bar and passed in the labels I want and it produced the correct output.