Align colorbar with GeoAxes subplot edges - python

I have a figure with 3 subplots, two of which share a colorbar and the third has has it's own colorbar.
I would like the colorbars to align with the vertical limits of their respective plots, and for the top two plots to have the same vertical limits.
Googling, I have found ways to do this with a single plot, but am stuck trying to make it work for my fig. My figure currently looks like this:
The code for which is as follows:
import cartopy.io.shapereader as shpreader
import cartopy.crs as ccrs
import pandas as pd
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
shpfilename = shpreader.natural_earth(resolution='50m',
category='cultural',
name='admin_0_countries')
reader = shpreader.Reader(shpfilename)
countries = reader.records()
projection = ccrs.PlateCarree()
fig = plt.figure()
axs = [plt.subplot(2, 2, x + 1, projection = projection) for x in range(2)]\
+ [plt.subplot(2, 2, (3, 4), projection = projection)]
def cmap_seg(cmap, value, k):
cmaplist = [cmap(i) for i in range(cmap.N)]
cmap = mpl.colors.LinearSegmentedColormap.from_list(
'Custom cmap', cmaplist, cmap.N)
bounds = np.linspace(0, k, k + 1)
norm = mpl.colors.BoundaryNorm(bounds, cmap.N)
color = cmap(norm(value))
return color, cmap
for country in countries:
c_name = country.attributes["SOVEREIGNT"]
country_dat = df.loc[c_name]
cmap = matplotlib.cm.get_cmap("plasma")
cmap_blues = matplotlib.cm.get_cmap("Blues")
ax_extent = [-170, 180, -65, 85]
alpha = 1.0
edgecolor = "k"
linewidth = 0.5
ax = axs[0]
value = country_dat.loc["wgi_bin"]
ax.add_geometries([country.geometry],
projection,
facecolor = cmap_seg(cmap, value, 5)[0],
alpha = alpha,
edgecolor = edgecolor,
linewidth = linewidth)
ax.set_xlabel("WGI group")
ax.set_extent(ax_extent)
ax = axs[1]
value = country_dat.loc["epi_bin"]
ax.add_geometries([country.geometry],
projection,
facecolor = cmap_seg(cmap, value, 5)[0],
alpha = alpha,
edgecolor = edgecolor,
linewidth = linewidth)
ax.set_xlabel("EPI group")
ax.set_extent(ax_extent)
ax = axs[2]
value = country_dat.loc["diff"]
ax.add_geometries([country.geometry],
projection,
facecolor = cmap_seg(cmap_blues, value, 4)[0],
alpha = alpha,
edgecolor = edgecolor,
linewidth = linewidth)
ax.set_xlabel("difference")
ax.set_extent(ax_extent)
subplot_labels = ["WGI group", "EPI group", "Metric difference"]
for i, ax in enumerate(axs):
ax.text(0.5, -0.07, subplot_labels[i], va='bottom', ha='center',
rotation='horizontal', rotation_mode='anchor',
transform=ax.transAxes)
sm = plt.cm.ScalarMappable(cmap=cmap_seg(cmap, 5, 5)[1], norm = plt.Normalize(0, 5))
sm._A = []
cb = plt.colorbar(sm, ax = axs[1], values = [1,2,3,4, 5], ticks = [1,2,3,4,5])
sm2 = plt.cm.ScalarMappable(cmap=cmap_seg(cmap_blues, 5, 4)[1], norm = plt.Normalize(0, 4))
sm2._A = []
cb2 = plt.colorbar(sm2, ax = axs[2], values = [0,1,2,3], ticks = [0,1,2,3])

Try this:
# update your code for this specific line (added shrink option)
cb = plt.colorbar(sm, ax=axs[1], values=[1,2,3,4,5], ticks=[1,2,3,4,5], shrink=0.6)
And add these lines of code towards the end:
p00 = axs[0].get_position()
p01 = axs[1].get_position()
p00_new = [p00.x0, p01.y0, p00.width, p01.height]
axs[0].set_position(p00_new)
The plot should be similar to this:

Related

How to reduce the gap between a pcolormesh and a colorbar in matplotlib?

I have a dataset that I want to plot as 4 panels (each a pcolormesh with its associated colorbar). This is the code I'm using to do this, with some mocked up data
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import gridspec
xs = np.linspace(0.1, 0.2, 100)
ys = np.linspace(0, 2*np.pi*0.1, 400)
x_mesh, y_mesh = np.meshgrid(xs, ys)
# mocked up data arrays
A = np.full_like(x_mesh, 1.0)
B = np.full_like(x_mesh, 1.0)
C = np.full_like(x_mesh, 1.0)
D = np.full_like(x_mesh, 1.0)
fig = plt.figure()
gs = gridspec.GridSpec(nrows = 2, ncols = 4, height_ratios = (0.5, 0.5), width_ratios = (0.45, 0.05, 0.45, 0.05))
ax0 = fig.add_subplot(gs[0,0])
ax0_cbar = fig.add_subplot(gs[0,1])
ax1 = fig.add_subplot(gs[0,2])
ax1_cbar = fig.add_subplot(gs[0,3])
ax2 = fig.add_subplot(gs[1,0])
ax2_cbar = fig.add_subplot(gs[1,1])
ax3 = fig.add_subplot(gs[1,2])
ax3_cbar = fig.add_subplot(gs[1,3])
a = ax0.pcolormesh(x_mesh/1.0e-2, y_mesh/1.0e-2, A, \
shading = 'auto')
cb1 = plt.colorbar(a, cax=ax0_cbar)
cb1.set_label(r"A")
b = ax1.pcolormesh(x_mesh/1.0e-2, y_mesh/1.0e-2, B, \
shading = 'auto')
cb1 = plt.colorbar(b, cax=ax1_cbar)
cb1.set_label(r"B")
c = ax2.pcolormesh(x_mesh/1.0e-2, y_mesh/1.0e-2, C, \
shading = 'auto')
cb1 = plt.colorbar(c, cax=ax2_cbar)
cb1.set_label(r"C")
d = ax3.pcolormesh(x_mesh/1.0e-2, y_mesh/1.0e-2, D, \
shading = 'auto')
cb1 = plt.colorbar(d, cax=ax3_cbar)
cb1.set_label(r"D")
ax0.xaxis.set_ticklabels([])
ax1.xaxis.set_ticklabels([])
fig.tight_layout()
But when I actually do this, I find that there are really large gaps between the pcolormesh and the colorbars that are really unappealing (picture attached). How can I reduce these? I though I would be able to do it with fig.tight_layout() and width_ratios in gridspec
You don't require new axes elements for your colorbars, simply use the ax keyword argument to specify the colorbars for each subplot. The matplotlib documentation shows that using ax will produce a colorbar axis stolen from the parent axes ax (https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.colorbar.html). The documentation should be your first port of call, always!
Here I have written a working version of your code:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import gridspec
xs = np.linspace(0.1, 0.2, 100)
ys = np.linspace(0, 2*np.pi*0.1, 400)
x_mesh, y_mesh = np.meshgrid(xs, ys)
# mocked up data arrays
A = np.full_like(x_mesh, 1.0)
B = np.full_like(x_mesh, 1.0)
C = np.full_like(x_mesh, 1.0)
D = np.full_like(x_mesh, 1.0)
fig = plt.figure(figsize=(6,4))
gs = gridspec.GridSpec(nrows = 2, ncols = 2, height_ratios = (0.5, 0.5), width_ratios = (0.5, 0.5))
ax0 = fig.add_subplot(gs[0,0])
ax1 = fig.add_subplot(gs[0,1])
ax2 = fig.add_subplot(gs[1,0])
ax3 = fig.add_subplot(gs[1,1])
a = ax0.pcolormesh(x_mesh/1.0e-2, y_mesh/1.0e-2, A, \
shading = 'auto')
cb1 = plt.colorbar(a, ax=ax0)
cb1.set_label(r"A")
b = ax1.pcolormesh(x_mesh/1.0e-2, y_mesh/1.0e-2, B, \
shading = 'auto')
cb1 = plt.colorbar(b, ax=ax1)
cb1.set_label(r"B")
c = ax2.pcolormesh(x_mesh/1.0e-2, y_mesh/1.0e-2, C, \
shading = 'auto')
cb1 = plt.colorbar(c, ax=ax2)
cb1.set_label(r"C")
d = ax3.pcolormesh(x_mesh/1.0e-2, y_mesh/1.0e-2, D, \
shading = 'auto')
cb1 = plt.colorbar(d, ax=ax3)
cb1.set_label(r"D")
ax0.xaxis.set_ticklabels([])
ax1.xaxis.set_ticklabels([])
fig.tight_layout()
plt.show()
Happy coding
The approach above is correct. It can break down if you have equal aspect axes, for which you can now use layout='compressed' for simple cases to remove white space:
fig, axs = plt.subplots(2, 2, layout='compressed', figsize=(6, 3))
for ax in axs.flat:
pc = ax.pcolormesh(np.random.randn(10, 10))
ax.set_aspect(1)
fig.colorbar(pc, ax=ax)
plt.show()
See also: https://matplotlib.org/stable/gallery/subplots_axes_and_figures/colorbar_placement.html

Adjusting the color intervals of Heat Map and removing color bar ticks

I am trying to do this heat map using the following code:
breast_cancer = load_breast_cancer()
data = breast_cancer.data
features = breast_cancer.feature_names
df = pd.DataFrame(data, columns = features)
df_small = df.iloc[:,:6]
correlation_mat = df_small.corr()
#Create color pallete:
def NonLinCdict(steps, hexcol_array):
cdict = {'red': (), 'green': (), 'blue': ()}
for s, hexcol in zip(steps, hexcol_array):
rgb =matplotlib.colors.hex2color(hexcol)
cdict['red'] = cdict['red'] + ((s, rgb[0], rgb[0]),)
cdict['green'] = cdict['green'] + ((s, rgb[1], rgb[1]),)
cdict['blue'] = cdict['blue'] + ((s, rgb[2], rgb[2]),)
return cdict
#https://www.december.com/html/spec/colorshades.html
hc = ['#e5e5ff', '#acacdf', '#7272bf', '#39399f', '#000080','#344152']
th = [0, 0.2, 0.4, 0.6, 0.8,1]
cdict = NonLinCdict(th, hc)
cm = matplotlib.colors.LinearSegmentedColormap('test', cdict)
#plot correlation matrix:
plt.figure(figsize = (12,10))
ax=sns.heatmap(correlation_mat,center=0, linewidths=.2, annot = True,cmap=cm , vmin=-1, vmax=1,cbar=True)
plt.title("title", y=-1.5,fontsize = 18)
plt.xlabel("X_parameters",fontsize = 18)
plt.ylabel("Y_paramaters",fontsize = 18)
ax.tick_params(axis='both', which='both', length=0)
#choose colors
#change ticks size and remove colorbar ticks
#ad saving option
#change to 5 portions instead of four (0.2,0.4,0.6,0.8)
plt.show()
I have two unsolved problems:
1- How to remove the colorbar ticks?
2- How to set the intevals of the color and color bar to (-1,-0.8,-0.6,-0.4,-0.2,0,0.2,0.6,0.8,1) if the vmax=1 and v min=-1).
here is my current output in the attached photo.Output
You can grab the colorbar via ax.collections[0].colorbar. From there you can change the tick properties.
Here is a minimal example:
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
def NonLinCdict(steps, hexcol_array):
cdict = {'red': (), 'green': (), 'blue': ()}
for s, hexcol in zip(steps, hexcol_array):
rgb = matplotlib.colors.hex2color(hexcol)
cdict['red'] = cdict['red'] + ((s, rgb[0], rgb[0]),)
cdict['green'] = cdict['green'] + ((s, rgb[1], rgb[1]),)
cdict['blue'] = cdict['blue'] + ((s, rgb[2], rgb[2]),)
return cdict
hc = ['#e5e5ff', '#acacdf', '#7272bf', '#39399f', '#000080', '#344152']
hc = hc[:0:-1] + hc # prepend a reversed copy, but without repeating the central value
cdict = NonLinCdict(np.linspace(0, 1, len(hc)), hc)
cm = matplotlib.colors.LinearSegmentedColormap('test', cdict)
fig = plt.figure(figsize=(8, 6))
ax = sns.heatmap(np.random.uniform(-1, 1, (10, 10)), center=0, linewidths=.2, annot=True, fmt='.2f', cmap=cm, vmin=-1, vmax=1, cbar=True)
ax.tick_params(axis='both', which='both', length=0)
cbar = ax.collections[0].colorbar
cbar.ax.tick_params(labelsize=15, axis='both', which='both', length=0)
cbar.set_ticks(np.linspace(-1, 1, 11))
# cbar.set_label('correlation')
plt.show()

Basemap is returning blank after add meridians, paralles and scale

I am trying to plot a depth map using Basemap in python. The contour and pcolormesh are working, but them when I add meridians, parallels and scale is returning a blank image.
I have tried to plot one by one, excluding meridians and paralles, and adding just scale, but returns a blank map and it is the same with the others. I used the same code before and it was working...
import netCDF4 as nc
from netCDF4 import Dataset
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
from matplotlib import ticker
grid = nc.Dataset('remo_grd.nc', mode='r')
h = grid.variables['h'][:]
h = h.astype(int)
h=-h
lon= grid.variables['lon_rho'][:]
lat= grid.variables['lat_rho'][:]
latmin = np.min(lat)
latmax= np.max(lat)
lonmax= np.max(lon)
lonmin= np.min(lon)
fig = plt.figure(1, figsize = (7,5.4), dpi = 100)
ax = fig.add_subplot(111)
m = Basemap(projection='merc', llcrnrlon=lonmin-0.2, urcrnrlon=lonmax+0.2, llcrnrlat=latmin-0.2, urcrnrlat=latmax+0.2, lat_ts=0, resolution='i')
xi, yi = m(lon,lat)
m.ax = ax
cs= m.pcolormesh(xi, yi, np.squeeze(h), shading = 'flat', zorder = 2)
levels = [-1000, -200]
a = m.contour(xi, yi, np.squeeze(h), levels, colors = 'black', linestyles = 'solid', linewidth= 1.5, extend = 'both', zorder = 3 )
plt.clabel(a, inline=2, fontsize= 10, linewidth= 1.0, fmt = '%.f', zorder= 4)
ax.text(0.5, -0.07, 'Longitude', transform=ax.transAxes, ha='center', va='center', fontsize = '10')
ax.text(-0.15, 0.5, 'Latitude', transform=ax.transAxes, ha= 'center', va='center', rotation='vertical', fontsize = '10')
m.drawcoastlines(linewidth=1.5, color = '0.1',zorder=5)
m.fillcontinents(color=('gray'),zorder=5 )
m.drawstates(linewidth = 0.5, zorder = 7)
m.drawmapboundary(color = 'black', zorder = 8, linewidth =1.2)
m.drawparallels(np.arange(int(latmin),int(latmax),3),labels=[1,0,0,0], linewidth=0.0, zorder =0)
m.drawmeridians(np.arange(int(lonmin),int(lonmax),3),labels=[0,0,0,1], linewidth=0.0)
cbar = plt.colorbar(cs, shrink=0.97, extend = 'both')
cbar.set_ticks([-10, -250, -500, -750, -1000, -1250, -1500, -1750, -2000, -2250, -2500])
cbar.set_ticklabels([-10, -250, -500, -750, -1000, -1250, -1500, -1750, -2000, -2250, -2500])
cbar.set_label('Meters (m)' , size = 10, labelpad = 20, rotation = 270)
ax = cbar.ax.tick_params(labelsize = 9)
titulo='Depth'
plt.title(titulo, va='bottom', fontsize='12')
#plot scale
dref=200
# Coordinates
lat0=m.llcrnrlat+0.9
lon0=m.llcrnrlon+1.9
#Tricked distance to provide to the the function
distance=dref/np.cos(lat0*np.pi/180.)
# Due to the bug, the function will draw a bar of length dref
scale=m.drawmapscale(lon0,lat0,lon0,lat0,distance, barstyle='fancy', units='km', labelstyle='simple',fillcolor1='w', fillcolor2='#555555', fontcolor='#555555', zorder = 8)
#Modify the labels with dref instead of distance
scale[12].set_text(dref/2)
scale[13].set_text(dref)
plt.show()
I've solved the problem! I was setting a specific order to plot each one of the details using the function zorder, so I was overlapping the data

How to efficiently animate multiple patches from a list of lists

I am trying to animate multiple patches as efficiently as possible when reading data from a list?
The code below displays an animation of the scatter plot but not the patches. Each point in scatter plot contains various sizes of circles. This example would require 6 different circles to be animated at 2 subjects each time point. But what if there were 20 subjects that each had 3 circles around them.
What is the most efficient way to animate all 60 circles for each frame?
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import matplotlib as mpl
x_data = np.random.randint(80, size=(400, 4))
y_data = np.random.randint(80, size=(400, 4))
fig, ax = plt.subplots(figsize = (8,6))
ax.set_xlim(0,80)
ax.set_ylim(0,80)
scatter = ax.scatter(x_data[0], y_data[0], zorder = 5) #Scatter plot
Player_1 = x_data[0][0], y_data[0][0]
Player_2 = x_data[0][1], y_data[0][1]
Player_1_IR = mpl.patches.Circle(Player_1, radius = 2, color = 'black', lw = 1, alpha = 0.8, zorder = 4)
Player_1_MR = mpl.patches.Circle(Player_1, radius = 4, color = 'gray', lw = 1, alpha = 0.8, zorder = 3)
Player_1_OR = mpl.patches.Circle(Player_1, radius = 6, color = 'lightgrey', lw = 1, alpha = 0.8, zorder = 2)
Player_2_IR = mpl.patches.Circle(Player_2, radius = 2, color = 'black', lw = 1, alpha = 0.8, zorder = 4)
Player_2_MR = mpl.patches.Circle(Player_2, radius = 4, color = 'gray', lw = 1, alpha = 0.8, zorder = 3)
Player_2_OR = mpl.patches.Circle(Player_2, radius = 6, color = 'lightgrey', lw = 1, alpha = 0.8, zorder = 2)
ax.add_patch(Player_1_IR)
ax.add_patch(Player_1_MR)
ax.add_patch(Player_1_OR)
ax.add_patch(Player_2_IR)
ax.add_patch(Player_2_MR)
ax.add_patch(Player_2_OR)
def animate(i) :
scatter.set_offsets(np.c_[x_data[i,:], y_data[i,:]])
ani = animation.FuncAnimation(fig, animate, frames=len(x_data),
interval = 700, blit = False)
plt.show()
You can store all patches that you want to update in a list through which you then iterate through every iteration step. Note that the size of the Circle patches is in data units/coordinates while the scatter plot points are in points (one point = 1/72 inch), which means that the relative size between scatter points and circles depends on the figure size and axes limits and will change when you re-scale the figure.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import matplotlib as mpl
x_data = np.random.randint(80, size=(400, 20))
y_data = np.random.randint(80, size=(400, 20))
fig, ax = plt.subplots(figsize = (8,6))
ax.set_xlim(0,80)
ax.set_ylim(0,80)
scatter = ax.scatter(x_data[0], y_data[0], zorder = 5) #Scatter plot
##creating list of patches
players = []
for n in range(10):
##as there are always 3 circles, append all three patches as a list at once
players.append([
mpl.patches.Circle((x_data[0,n],y_data[0,n]), radius = 2, color = 'black', lw = 1, alpha = 0.8, zorder = 4),
mpl.patches.Circle((x_data[0,n],y_data[0,n]), radius = 4, color = 'gray', lw = 1, alpha = 0.8, zorder = 3),
mpl.patches.Circle((x_data[0,n],y_data[0,n]), radius = 6, color = 'lightgrey', lw = 1, alpha = 0.8, zorder = 2)
])
##adding patches to axes
for player in players:
for circle in player:
ax.add_patch(circle)
def animate(i):
scatter.set_offsets(np.c_[x_data[i,:], y_data[i,:]])
##updating players:
for n,player in enumerate(players):
for circle in player:
circle.center = (x_data[i,n],y_data[i,n])
ani = animation.FuncAnimation(fig, animate, frames=len(x_data),
interval = 700, blit = False)
plt.show()
Old Answer (slightly different visual effect, but could be tuned to look the same):
If you really just want circles around your scatter points, you can actually forget about the Circle patches and just overlay several scatter plots with different marker sizes.
In the example below I only mark part of the scatter points with circles by slicing the array of random numbers. Also remember that in scatter plots the marker size is given as points square, so if you want to increase the circle radius from, say, 5 to 6, the given marker size should change from 25 to 36.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import matplotlib as mpl
x_data = np.random.randint(80, size=(400, 20))
y_data = np.random.randint(80, size=(400, 20))
fig, ax = plt.subplots(figsize = (8,6))
ax.set_xlim(0,80)
ax.set_ylim(0,80)
scatter = ax.scatter(x_data[0], y_data[0], zorder = 5) #Scatter plot
scatter_IR = ax.scatter(
x_data[0,:10], y_data[0,:10], zorder = 4,
facecolor='black', edgecolor = 'black',
alpha = 0.8, s = 100
)
scatter_MR = ax.scatter(
x_data[0,:10], y_data[0,:10], zorder = 3,
facecolor='grey', edgecolor = 'grey',
alpha = 0.8, s = 225
)
scatter_OR = ax.scatter(
x_data[0,:10], y_data[0,:10], zorder = 2,
facecolor='lightgrey', edgecolor = 'lightgrey',
alpha = 0.8, s = 400
)
def animate(i) :
scatter.set_offsets(np.c_[x_data[i,:], y_data[i,:]])
scatter_IR.set_offsets(np.c_[x_data[i,:10], y_data[i,:10]])
scatter_MR.set_offsets(np.c_[x_data[i,:10], y_data[i,:10]])
scatter_OR.set_offsets(np.c_[x_data[i,:10], y_data[i,:10]])
ani = animation.FuncAnimation(fig, animate, frames=len(x_data),
interval = 700, blit = False)
plt.show()

Custom scale for radial contour plot in matplotlib

I have a sample script to generate a polar contour plot in matplotlib:
import os
import math
import numpy as np
import matplotlib.pyplot as plt
import mpl_toolkits.axisartist.floating_axes as floating_axes
from matplotlib.projections import PolarAxes
from mpl_toolkits.axisartist.grid_finder import FixedLocator, MaxNLocator, DictFormatter
import random
# ------------------------------------ #
def setup_arc_radial_axes(fig, rect, angle_ticks, radius_ticks, min_rad, max_rad):
tr = PolarAxes.PolarTransform()
pi = np.pi
grid_locator1 = FixedLocator([v for v, s in angle_ticks])
tick_formatter1 = DictFormatter(dict(angle_ticks))
grid_locator2 = FixedLocator([a for a, b in radius_ticks])
tick_formatter2 = DictFormatter(dict(radius_ticks))
grid_helper = floating_axes.GridHelperCurveLinear(tr,
extremes=((370.0*(pi/180.0)), (170.0*(pi/180.0)), max_rad, min_rad),
grid_locator1=grid_locator1,
grid_locator2=grid_locator2,
tick_formatter1=tick_formatter1,
tick_formatter2=tick_formatter2,
)
ax1 = floating_axes.FloatingSubplot(fig, rect, grid_helper=grid_helper)
fig.add_subplot(ax1)
ax1.grid(True)
# create a parasite axes whose transData in RA, cz
aux_ax = ax1.get_aux_axes(tr)
aux_ax.patch = ax1.patch
ax1.patch.zorder=0.9
#ax1.axis["left"].set_ticklabel_direction("+")
return ax1, aux_ax
# ------------------------------------ #
# write angle values to the plotting array
angles = []
for mic_num in range(38):
angle = float(mic_num)*(180.0/36.0)*(math.pi/180.0)+math.pi
angles.append(angle)
# ------------------------------------ #
### these are merely the ticks that appear on the plot axis
### these don't actually get plotted
angle_ticks = range(0,190,10)
angle_ticks_rads = [a*math.pi/180.0 for a in angle_ticks]
angle_ticks_rads_plus_offset = [a+math.pi for a in angle_ticks_rads]
angle_ticks_for_plot = []
for i in range(len(angle_ticks)):
angle_ticks_for_plot.append((angle_ticks_rads_plus_offset[i],r"$"+str(angle_ticks[i])+"$"))
# ------------------------------------ #
scale = 1.0
aspect = 1.50
height = 8.0
fig = plt.figure(1, figsize=(height*aspect*scale, height*scale))
fig.subplots_adjust(wspace=0.3, left=0.05, right=0.95, top=0.84)
fig.subplots_adjust()
plot_real_min = 30.0
plot_real_max = 100.0
plot_fake_min = 0.0
plot_fake_max = 5000.0
rad_tick_increment = 500.0
radius_ticks = []
for i in range(int(plot_fake_min),int(plot_fake_max)+int(rad_tick_increment),int(rad_tick_increment)):
plot_fake_val = ((i-plot_fake_min)/(plot_fake_max-plot_fake_min))*(plot_real_max-plot_real_min)+plot_real_min
radius_ticks.append((plot_fake_val, r"$"+str(i)+"$"))
ax2, aux_ax2 = setup_arc_radial_axes(fig, 111, angle_ticks_for_plot, radius_ticks, plot_real_min, plot_real_max)
azimuths = np.radians(np.linspace(0, 180, 91))
azimuths_adjusted = [ (x + math.pi) for x in azimuths ]
zeniths = np.arange(0, 5050, 50)
zeniths_adjusted = [((x-plot_fake_min)/(plot_fake_max-plot_fake_min))*(plot_real_max-plot_real_min)+plot_real_min for x in zeniths]
r, theta = np.meshgrid(zeniths_adjusted, azimuths_adjusted)
values = 90.0+5.0*np.random.random((len(azimuths), len(zeniths)))
aux_ax2.contourf(theta, r, values)
cbar = plt.colorbar(aux_ax2.contourf(theta, r, values), orientation='vertical')
cbar.ax.set_ylabel('Contour Value [Unit]', fontsize = 16)
plt.suptitle('Plot Title ', fontsize = 24, weight="bold")
plt.legend(loc=3,prop={'size':20})
plt.xlabel('Angle [deg]', fontsize=20, weight="bold")
plt.ylabel('Frequency [Hz]', fontsize=20, weight="bold")
# plt.show()
plt.savefig('test.png', dpi=100)
plt.close()
This script will generate a plot that looks something like:
My question is how can I plot with an alternate color bar scale? Is it possible to define a custom scale?
Something like a blue-white-red scale where deltas around a central value can easily be shown would be the best, something like:
You can create a custom scale, but matplotlib already has what you want. All you have to do is add an argument to contourf:
aux_ax2.contourf(theta, r, values, cmap = 'bwr')
If you don't like bwr, coolwarm and seismic are also blue to red. If you need to reverse the scale, just add _r to the colormap name. You can find more colormaps here: http://matplotlib.org/examples/color/colormaps_reference.html
I can't run your code, but I think you could solve your problem this way:
from matplotlib import pyplot as plt
import matplotlib as mpl
f = plt.figure(figsize=(5,10))
ax = f.add_axes([0.01, 0.01, 0.4, 0.95])
#here we create custom colors
cmap = mpl.colors.LinearSegmentedColormap.from_list(name='Some Data',colors=['b', 'w','w', 'r'])
cb = mpl.colorbar.ColorbarBase(ax, cmap=cmap, orientation='vertical')
cb.set_label('Some Data')
plt.show()
And if linear way is not what you are looking for here is some other types:
http://matplotlib.org/api/colors_api.html#module-matplotlib.colors

Categories

Resources