I am trying to overlay a pie chart over radial gradient as a background. It does work, but I want the figure to show the entire radial gradient (without the figure boundary being cut as a square).
How do I acheive this?
I want something like this to this
Thank you.
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
delta = 0.02
x = y = np.arange(-1.0, 1.0, delta)
X, Y = np.meshgrid(x, y)
plt.imshow(-X**2+-Y**2, interpolation='bicubic', cmap=plt.cm.Blues,
origin='lower',extent=[-1.2, 1.2, -1.2, 1.2])
plt.pie([1] , explode=None, radius=1.2 \
, labels=['H'] \
, labeldistance=0.9 \
, startangle=270 \
, colors=[g(0.70)])
plt.show()
It will be hard to get this to work in the same axes. Better create two axes, one for the background image and one for the pie. This allows to tweak them individually, i.e. the background axes should range over the complete figure and have an adjustable aspect ratio, while the pie axes should have some margins and an equal aspect.
The following is an example that positions the pie chart (ax) on top of the imshow plot (ax2).
import numpy as np
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
fig.subplots_adjust(.1,.1,.9,.9)
ax.set_aspect("equal")
ax.pie([1,2], radius=1.2 , labels=['H',"A"] , labeldistance=0.9,
startangle=270 , colors=[plt.cm.Blues(1.), plt.cm.Blues(0.5)])
ax2 = fig.add_axes([0,0,1,1], zorder=-1)
ax2.axis("off")
w,h = fig.get_size_inches()
x = np.linspace(-1, 1)*w/h
y = np.linspace(-1, 1)
X, Y = np.meshgrid(x, y)
ax2.imshow(-X**2-Y**2, interpolation='bicubic', cmap=plt.cm.Blues,
origin='lower', aspect="auto", vmin=-0.99)
plt.show()
Related
I have a question about the X and Y Position in figures. How you can see I am working with gridspec for a better layout and adding Text to a figure. The problem is that I am trying to get the exact Position manually. Which means I am changing the X and Y in fig.text(0.2, 0.5, 'matplotlib') until I get the final figure.
import matplotlib.pylab as plt
import numpy as np
vector = np.arange(0,100)
time = np.arange(0,vector.shape[0])
fig = plt.figure(figsize=(10,10))
plt.rcParams['axes.grid'] = True
gs = fig.add_gridspec(2, 2)
ax1 = fig.add_subplot(gs[0, :])
ax1.plot(time,vector)
fig.text(0.2, 0.5, 'matplotlib')
At Link I already found an interactive solution but its only working for the Plot.
Does someone have an idea how to manage this?
You can create a blended transform, where the y-coordinates have a figure transform. And the x-coordinates have a axes transform. The figure transform is measured 0 at the left/bottom and 1 at the right/top of the figure. The axes transform is similar, but regarding the axes. The parameter clip_on=False allows to draw outside the axes region (text allows this by default).
import matplotlib.transforms as mtransforms
import matplotlib.patches as mpatches
import matplotlib.pyplot as plt
fig, ax = plt.subplots(gridspec_kw={})
# the x coords of this transformation are axes, and the y coord are fig
trans = mtransforms.blended_transform_factory(ax.transAxes, fig.transFigure)
x, w = 1, -0.3 # axes coordinates
y, h = 0.04, 0.06 # figure coordinates
ax.text(x + w / 2, y + h / 2, 'hello', transform=trans, ha='center', va='center')
rect = mpatches.Rectangle((x, y), w, h, transform=trans, edgecolor='crimson', facecolor='yellow', clip_on=False)
ax.add_patch(rect)
fig.tight_layout(pad=2)
plt.show()
PS: You can set the vertical alignment va='right' to have the right margin of the text align with the right axis. You can also use transform=ax.transAxes with negative y-coordinates to plot everything relative to the axes.
I create a custom cmap and ticklabels to make a plot with contourf, but not all the ticklabels nor all the colors are considered by the colorbar, however when I use imshow, I get the result that I want.
This is my code.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap, LinearSegmentedColormap
from matplotlib.colors import BoundaryNorm
x = np.arange(-6,6,0.25)
y = np.arange(-6,6,0.25)
x, y = np.meshgrid(x,y)
z = np.sqrt(x**2+y**2)
newcolors = np.vstack((plt.cm.YlGn(np.linspace(0, 1, 4))[1:,:], plt.cm.Blues(np.linspace(0, 1, 6))))
palette = ListedColormap(newcolors, name='test')
palette.set_over('darkred')
palette.set_under('yellow')
tickslabels=[0.5,1.0,1.5,2.0,4.0,6.0,8.0,10.0,12.0,14.0]
norm=BoundaryNorm(tickslabels, len(tickslabels)-1)
fig1 = plt.figure('imshow')
img=plt.imshow(z, cmap=palette, norm=norm)
plt.colorbar(img, ticks=tickslabels, spacing='proportional', extend='both')
plt.title('imshow')
fig2 = plt.figure('contourf')
img=plt.contourf(x, y, z, cmap=palette, levels=tickslabels, extend='both') #norm=norm)
plt.colorbar(img, ticks=tickslabels, spacing='proportional', extend='both')
plt.title('contourf')
plt.show()
This are the results using imshow and contourf. Pay attention on colorbar of imshow, the green colors go from 0.5 until 2.0 and the blue colors go from 2.0 until 14.0, this is the result that I want. However using contourf the result is not the same.
What is my error? I forget set any parameter?
You have to use the defined norm=norm when plotting the contour plot img=plt.contourf(...). When used in the following way, both color bars are same
img=plt.contourf(x, y, z, cmap=palette, levels=tickslabels, extend='both',
norm=norm) # <--- pass the norm here
I have a 2D power-law like dataset:
import numpy as np
X = 1 / np.random.power(2, size=1000)
Y = 1 / np.random.power(2, size=1000)
I can plot it using a scatter plot in loglog scale
import matplotlib.pyplot as plt
plt.figure()
plt.scatter(X, Y, alpha=0.3)
plt.loglog()
plt.show()
getting:
However, it does not show properly the data near the origin where the density is high. Hence, I converted this plot in a heatmap. I did that:
from matplotlib.colors import LogNorm
heatmap, xedges, yedges = np.histogram2d(X, Y, bins=np.logspace(0, 2, 30))
plt.figure()
plt.imshow(heatmap.T, origin='lower', norm=LogNorm())
plt.colorbar()
plt.show()
getting:
The plot looks great but the axis ticks are not good. To change the scale I tried to add extent = [xedges[0], xedges[-1], yedges[0], yedges[-1]] in the imshow but it only does an affine transformation, the scale is still linear not logarithmic. Do you know how can I get the heatmap plot but with ticks of the scatter one?
You can use pcolormesh like JohanC advised.
Here is an example with you code using pcolormesh:
import numpy as np
import matplotlib.pyplot as plt
X = 1 / np.random.power(2, size=1000)
Y = 1 / np.random.power(2, size=1000)
heatmap, xedges, yedges = np.histogram2d(X, Y, bins=np.logspace(0, 2, 30))
fig = plt.figure()
ax = fig.add_subplot(111)
ax.pcolormesh(xedges, yedges, heatmap)
ax.loglog()
ax.set_xlim(1, 50)
ax.set_ylim(1, 50)
plt.show()
And the output is:
I want to use a scatter plot to describe the relationship between X, Y and Z. Z is p-value so it is better to denote it as log values.
Following the instructions here, I can plot a logarithmic scatter plot, but the color bar seems wrong. The color bar is almost totally blue, but there should be some red! Below is the figure and my codes.
import matplotlib
import matplotlib.pyplot as plt
import seaborn as sns
from matplotlib.colors import LogNorm
fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)
ax1.set_title("P-value")
Z1 = pos_spearmanr['pval']
X = pos_spearmanr['X']
Y = pos_spearmanr['Y']
im = ax1.scatter(X,
Y,
edgecolors=None,
c=Z1,
norm=LogNorm(),
cmap=plt.get_cmap('bwr'), alpha=0.2)
ax1.set_xlabel('X')
ax1.set_ylabel('Y')
ax1.set_xlim(0, 1)
ax1.set_ylim(0, 1)
cbar = fig.colorbar(im,ax=ax1)
I am using matplotlib to make some plots and I have run into a few difficulties that I need help with.
problem 1) In order to keep a consistent colorscheme I need to only use half of the color axis. There are only positive values, so I want the zero values to be green, the mid values to be yellow and the highest values to be red. The color scheme that most closely matches this is gist_rainbow_r, but I only want the top half of it.
problem 2) I can't seem to figure out how to get the colorbar on the right hand side of the plot to show up or how to get it to let me label the axes.
If it helps, I am using the latest version of Anaconda wth the latext version of matplotlib
cmap = plt.get_cmap('gist_rainbow_r')
edosfig2 = plt.figure(2)
edossub2 = edosfig.add_subplot(1,1,1)
edossub2 = plt.contourf(eVec,kints,smallEDOS,cmap=cmap)
edosfig2.show()
If you have a specific set of colors that you want to use for you colormap, you can build it based on those. For example:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap
cmap = LinearSegmentedColormap.from_list('name', ['green', 'yellow', 'red'])
# Generate some data similar to yours
y, x = np.mgrid[-200:1900, -300:2000]
z = np.cos(np.hypot(x, y) / 100) + 1
fig, ax = plt.subplots()
cax = ax.contourf(x, y, z, cmap=cmap)
cbar = fig.colorbar(cax)
cbar.set_label('Z-Values')
plt.show()
However, if you did just want the top half of some particularly complex colormap, you can copy a portion of it by evaluating the colormap over the range you're interested in. For example, if you wanted the "top" half, you'd evaluate it from 0.5 to 1:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap
# Evaluate an existing colormap from 0.5 (midpoint) to 1 (upper end)
cmap = plt.get_cmap('gist_earth')
colors = cmap(np.linspace(0.5, 1, cmap.N // 2))
# Create a new colormap from those colors
cmap2 = LinearSegmentedColormap.from_list('Upper Half', colors)
y, x = np.mgrid[-200:1900, -300:2000]
z = np.cos(np.hypot(x, y) / 100) + 1
fig, axes = plt.subplots(ncols=2)
for ax, cmap in zip(axes.flat, [cmap, cmap2]):
cax = ax.imshow(z, cmap=cmap, origin='lower',
extent=[x.min(), x.max(), y.min(), y.max()])
cbar = fig.colorbar(cax, ax=ax, orientation='horizontal')
cbar.set_label(cmap.name)
plt.show()