matplotlib legend label under key? - python

How to adjust label location relate to key?I reclassified the data and displayed a discrete corbar which looks like multi-handles legend. Actually ,I couldn't find any parameters about the location of labels(text or numbers).The default setting is keys in left while label in right. Could I change the position? such as labels under keys or above. My purpose is to show the legend as follows (label under key and no space between keys:
import matplotlib.patches as mpatches
import matplotlib.pyplot as plt
import numpy as np
data = np.random.randint(8, size=(100,100))
cmap = plt.cm.get_cmap('PiYG', 8)
plt.pcolormesh(data,cmap = cmap,alpha = 0.75)
# Set borders in the interval [0, 1]
bound = np.linspace(0, 1, 9)
# Preparing borders for the legend
bound_prep = np.round(bound * 7, 2)
# Creating 8 Patch instances
plt.legend([mpatches.Patch(color=cmap(b)) for b in bound[:-1]],
['{}'.format(bound_prep[i]) for i in range(8)],
bbox_to_anchor=(0,-0.25,1,0.2),ncol=len(bound))
It seems that there is no parameters to adjust location of labels.

import matplotlib.pyplot as plt
import numpy as np
data = np.random.randint(8, size=(100,100))
cmap = plt.cm.get_cmap('PiYG', 8)
fig, ax = plt.subplots()
pcm = ax.pcolormesh(data,cmap = cmap,alpha = 0.75, vmin=0, vmax=8)
fig.colorbar(pcm, ax=ax)
plt.show()

Related

How to make colormap of this colorbar image attached?

0
I want to make a colormap used in the attached image.
img = imread('/path/Screenshot 2022-04-12 at 2.14.16 PM.png')
colors_from_img = img[:, 0, :]
my_cmap = LinearSegmentedColormap.from_list('my_cmap', colors_from_img, N=651)
y = random_sample((100, 100))
imshow(y, cmap=my_cmap);plt.colorbar().png')
Looking forward to your inputs
You just have to transpose the strategy linked in my comment from vertical to horizontal. To avoid random guessing, you analyze first the image dimensions, then guesstimate what level the horizontal line should be (ca 66/3) and what the step for the color bars is (ca 616/11). Finally, you have to normalize the image for the range -0.3 ... 0.5 and tell matplotlib that values above and below should also be considered (extend="both"). This leads us to:
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap, BoundaryNorm
import numpy as np
img = plt.imread('test.png')
#analyze image dimensions
#print(img.shape)
#>>> (66, 616, 4)
colors_from_img = img[22, 60::56, :]
#generate color map
my_cmap = LinearSegmentedColormap.from_list("my_cmap", colors_from_img, N=len(colors_from_img))
#normalize with boundaries
my_norm = BoundaryNorm(np.linspace(-0.3, 0.5, 9), my_cmap.N, extend="both")
y = 2*np.random.random_sample((20, 20))-1
plt.imshow(y, cmap=my_cmap, norm=my_norm)
plt.colorbar()
plt.show()
Sample output:
If you want only the color bar to be an image, I would suggest the tutorial in the formula for an example. I have set the color names similar to the colors in your image, but you can change them to whatever colors you like.
import matplotlib.pyplot as plt
import matplotlib as mpl
fig, ax = plt.subplots(figsize=(6, 0.5))
fig.subplots_adjust(bottom=0.5)
c = ['darkblue', 'lightblue', 'aquamarine', 'green', 'lime', 'yellow','orange','red']
cmap = (mpl.colors.ListedColormap(c)
.with_extremes(over='purple', under='white'))
bounds = [-0.3,-0.2,-0.1,0,0.1,0.2,0.3,0.4,0.5]
norm = mpl.colors.BoundaryNorm(bounds, cmap.N)
fig.colorbar(
mpl.cm.ScalarMappable(cmap=cmap, norm=norm),
cax=ax,
boundaries=[-10] + bounds + [10],
extend='both',
extendfrac='auto',
ticks=bounds,
spacing='uniform',
orientation='horizontal',
#label='Custom extension lengths, some other units',
)
fig.savefig('my_colorbar.png')
plt.show()

Customise my own colour palette and use in geopandas map

I want to define a colour palette to use in a geopandas map. I want to fade between two colors, RGB 0-0-90 and RGB 126-193-61.
I've checked out this page: https://matplotlib.org/stable/tutorials/colors/colormap-manipulation.html
but I don't understand how I can use customized colours based on that information.
fig, ax = plt.subplots(1, figsize=(10, 16))
matplotlib.rcParams["figure.dpi"] = 100
ax.axis('off')
ax.set_title('TITLE', fontdict={'fontsize': '16', 'fontweight' : '3'})
ax.annotate('Källa: Datalagret', xy=(0.7, .05), xycoords='figure fraction', fontsize=11, color='#555555')
sm = plt.cm.ScalarMappable(cmap='GnBu', norm=plt.Normalize(vmin=vmin, vmax=vmax))
fig.colorbar(sm, orientation="horizontal", fraction=0.036, pad=0.015, aspect = 30)
geo_df1.plot(edgecolor='black', column=variable, cmap='GnBu', linewidth=0.2, ax=ax)
# I'm using GnBu right now, wish to change this to a custom palette.
To create a custom colormap from 2 given colors, ListedColormap can be used. Here is an example code.
import matplotlib
import matplotlib.cm as cm
#from matplotlib.colors import Normalize
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
# Required colors: from_RGB(0-0-90) to_RGB(126-193-61)
RGB1 = [0,0,90] # dark blue
RGB2 = [126,193,61] # pale green
N = 256 #number of discrete levels
vals = np.ones((N,4))
vals[:, 0] = np.linspace(RGB1[0]/256, RGB2[0]/256, N)
vals[:, 1] = np.linspace(RGB1[1]/256, RGB2[1]/256, N)
vals[:, 2] = np.linspace(RGB1[2]/256, RGB2[2]/256, N)
# finally, create the required colormap that ranges from
# -- dark blue to pale green
my_cmp = ListedColormap(vals)
# test plot using random data
fig, ax = plt.subplots(figsize=(4, 4))
np.random.seed(1470)
arrdata = 3 + 2.5 * np.random.randn(20, 20)
minv = np.min(arrdata)
maxv = np.max(arrdata)
psm = ax.pcolormesh(arrdata, cmap=my_cmp, rasterized=True, vmin=minv, vmax=maxv)
fig.colorbar(psm, ax=ax)
plt.show()

Bar Chart using Matlplotlib

I have two values:
test1 = 0.75565
test2 = 0.77615
I am trying to plot a bar chart (using matlplotlib in jupyter notebook) with the x-axis as the the two test values and the y-axis as the resulting values but I keep getting a crazy plot with just one big box
here is the code I've tried:
plt.bar(test1, 1, width = 2, label = 'test1')
plt.bar(test2, 1, width = 2, label = 'test2')
As you can see in this example, you should define X and Y in two separated arrays, so you can do it like this :
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(2)
y = [0.75565,0.77615]
fig, ax = plt.subplots()
plt.bar(x, y)
# set your labels for the x axis here :
plt.xticks(x, ('test1', 'test2'))
plt.show()
the final plot would be like :
UPDATE
If you want to draw each bar with a different color, you should call the bar method multiple times and give it colors to draw, although it has default colors :
import matplotlib.pyplot as plt
import numpy as np
number_of_points = 2
x = np.arange(number_of_points)
y = [0.75565,0.77615]
fig, ax = plt.subplots()
for i in range(number_of_points):
plt.bar(x[i], y[i])
# set your labels for the x axis here :
plt.xticks(x, ('test1', 'test2'))
plt.show()
or you can do it even more better and choose the colors yourself :
import matplotlib.pyplot as plt
import numpy as np
number_of_points = 2
x = np.arange(number_of_points)
y = [0.75565,0.77615]
# choosing the colors and keeping them in a list
colors = ['g','b']
fig, ax = plt.subplots()
for i in range(number_of_points):
plt.bar(x[i], y[i],color = colors[i])
# set your labels for the x axis here :
plt.xticks(x, ('test1', 'test2'))
plt.show()
The main reason your plot is showing one large value is because you are setting a width for the columns that is greater than the distance between the explicit x values that you have set. Reduce the width to see the individual columns. The only advantage to doing it this way is if you need to set the x values (and y values) explicitly for some reason on a bar chart. Otherwise, the other answer is what you need for a "traditional bar chart".
import matplotlib.pyplot as plt
test1 = 0.75565
test2 = 0.77615
plt.bar(test1, 1, width = 0.01, label = 'test1')
plt.bar(test2, 1, width = 0.01, label = 'test2')

Remove lowest color from colorbar in Seaborn/Matplotlib

If I set shade_lowest = False, the colorbar still contains the lowest level (purple-ish). Is there any generic way to remove it entirely?
import seaborn as sns
import numpy as np
import matplotlib.pyplot as plt
a = np.random.normal(0, 1, 100)
b = np.random.normal(0, 1, 100)
fig, ax = plt.subplots()
sns.kdeplot(a, b, shade = True, shade_lowest = False, cmap = "viridis", cbar = True, n_levels = 4, ax = ax)
plt.show()
A solution is for sure to not create this level from the beginning.
Here we choose maximally 5 levels according to a locator and remove the lowest one when calling the contourf plot, such that this level does not even exist in the first place. Then the automatic colorbar creation works flawlessly.
import numpy as np; np.random.seed(5)
import matplotlib.pyplot as plt
from matplotlib import ticker
from scipy import stats
x = np.random.normal(3, 1, 100)
y = np.random.normal(0, 2, 100)
X, Y = np.mgrid[x.min():x.max():100j, y.min():y.max():100j]
positions = np.vstack([X.ravel(),Y.ravel()])
values = np.vstack([x,y])
kernel = stats.gaussian_kde(values)
Z = np.reshape(kernel(positions).T, X.shape)
N=4
locator = ticker.MaxNLocator(N + 1, min_n_ticks=N)
lev = locator.tick_values(Z.min(), Z.max())
fig, ax = plt.subplots()
c = ax.contourf(X,Y,Z,levels=lev[1:])
ax.scatter(x,y, s=9, c="k")
fig.colorbar(c)
plt.show()

How to use and plot only a part of a colorbar in matplotlib?

I have multiple curves that differ in one parameter and which I want to plot in one figure. To distinguish them, I want to use one of matplotlib's colorbars. To do so I produce a list of colors depending on said parameter. Additionally, I want to add a colorbar to explain the colors that are used. I can easily do all of that. The problem is now, that I want to use only a part of the available colormap, as it gets too bright and thus barely visible above some threshold. But when I now choose the colors only in a subrange, I did not find a way to adjust the range of the displayed colorbar.
Here is a (nearly) minimal example of what I want to achieve:
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
gs = gridspec.GridSpec(2, 1,
height_ratios=[1, 4]
)
ax = [plt.subplot(g) for g in gs]
parameterToColorBy = np.linspace(5, 10, 6, dtype=float)
maxColor = 0.85
colors = [plt.get_cmap("inferno")(i)
for i in np.linspace(0, maxColor, parameterToColorBy.shape[0])]
norm = mpl.colors.Normalize(parameterToColorBy[0],
parameterToColorBy[0]+
(parameterToColorBy[-1]-parameterToColorBy[0])/
maxColor)
cb = mpl.colorbar.ColorbarBase(ax[0],
cmap="inferno",
norm=norm,
ticks=parameterToColorBy,
orientation='horizontal')
ax[0].xaxis.set_ticks_position('top')
for p, c in zip(parameterToColorBy, colors):
ax[1].plot(np.arange(2)/p, c=c)
plt.show()
The result looks at follows:
I now want the colorbar to stop at 10. But if I just adjust the xlim of the subplot by adding the line ax[0].set_xlim(0, maxColor), the colored part is adjusted correctly, but the surrounding box is messed up:
Alternatively, I found a function for colorbars set_clim. But this only changes the normalization and does not seem to work as I want. Adding cb.set_clim(parameterToColorBy[0], parameterToColorBy[-1]) results in an changed colors but unchanged axis:
What I seem to need is either an appropriate way to adjust the limits of the displayed colorbar, or a way to create an own colorbar as a subset of an available colorbar. Is there any way to achieve one of these things?
You can truncate the colormap by using the truncate_colormap function I have written in the code below. It creates a new matplotlib.colors.LinearSegmentedColormap from an existing colormap.
Note that you then don't need to scale the Normalise instance by maxColor, and you need to use this new colormap instance when creating your colors list and the colorbar.
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import matplotlib.colors as mcolors
gs = gridspec.GridSpec(2, 1,
height_ratios=[1, 4]
)
ax = [plt.subplot(g) for g in gs]
parameterToColorBy = np.linspace(5, 10, 6, dtype=float)
def truncate_colormap(cmap, minval=0.0, maxval=1.0, n=-1):
if n == -1:
n = cmap.N
new_cmap = mcolors.LinearSegmentedColormap.from_list(
'trunc({name},{a:.2f},{b:.2f})'.format(name=cmap.name, a=minval, b=maxval),
cmap(np.linspace(minval, maxval, n)))
return new_cmap
minColor = 0.00
maxColor = 0.85
inferno_t = truncate_colormap(plt.get_cmap("inferno"), minColor, maxColor)
colors = [inferno_t(i)
for i in np.linspace(0, 1, parameterToColorBy.shape[0])]
norm = mpl.colors.Normalize(parameterToColorBy[0],
parameterToColorBy[-1])
cb = mpl.colorbar.ColorbarBase(ax[0],
cmap=inferno_t,
norm=norm,
ticks=parameterToColorBy,
orientation='horizontal')
ax[0].xaxis.set_ticks_position('top')
for p, c in zip(parameterToColorBy, colors):
ax[1].plot(np.arange(2)/p, c=c)
plt.show()

Categories

Resources