I am pretty new to python and want to plot a dataset using a histogram and a heatmap below. However, I am a bit confused about
How to put a title above both plots and
How to insert some text into bots plots
How to reference the upper and the lower plot
For my first task I used the title instruction, which inserted a caption in between both plots instead of putting it above both plots
For my second task I used the figtext instruction. However, I could not see the text anywhere in the plot. I played a bit with the x, y and fontsize parameters without any success.
Here is my code:
def drawHeatmap(xDim, yDim, plot, threshold, verbose):
global heatmapList
stableCells = 0
print("\n[I] - Plotting Heatmaps ...")
for currentHeatmap in heatmapList:
if -1 in heatmapList[currentHeatmap]:
continue
print("[I] - Plotting heatmap for PUF instance", currentHeatmap,"(",len(heatmapList[currentHeatmap])," values)")
# Convert data to ndarray
#floatMap = list(map(float, currentHeatmap[1]))
myArray = np.array(heatmapList[currentHeatmap]).reshape(xDim,yDim)
# Setup two plots per page
fig, ax = plt.subplots(2)
# Histogram
weights = np.ones_like(heatmapList[currentHeatmap]) / len(heatmapList[currentHeatmap])
hist, bins = np.histogram(heatmapList[currentHeatmap], bins=50, weights=weights)
width = 0.7 * (bins[1] - bins[0])
center = (bins[:-1] + bins[1:]) / 2
ax[0].bar(center, hist, align='center', width=width)
stableCells = calcPercentageStable(threshold, verbose)
plt.figtext(100,100,"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!", fontsize=40)
heatmap = ax[1].pcolor(myArray, cmap=plt.cm.Blues, alpha=0.8, vmin=0, vmax=1)
cbar = fig.colorbar(heatmap, shrink=0.8, aspect=10, fraction=.1,pad=.01)
#cbar.ax.tick_params(labelsize=40)
for y in range(myArray.shape[0]):
for x in range(myArray.shape[1]):
plt.text(x + 0.5, y + 0.5, '%.2f' % myArray[y, x],
horizontalalignment='center',
verticalalignment='center',
fontsize=(xDim/yDim)*5
)
#fig = plt.figure()
fig = matplotlib.pyplot.gcf()
fig.set_size_inches(60.5,55.5)
plt.savefig(dataDirectory+"/"+currentHeatmap+".pdf", dpi=800, papertype="a3", format="pdf")
#plt.title("Heatmap for PUF instance "+str(currentHeatmap[0][0])+" ("+str(numberOfMeasurements)+" measurements; "+str(sizeOfMeasurements)+" bytes)")
if plot:
plt.show()
print("\t[I] - Done ...")
And here is my current output:
Perhaps this example will make things easier to understand. Things to note are:
Use fig.suptitle to add a title to the top of a figure.
Use ax[i].text(x, y, str) to add text to an Axes object
Each Axes object, ax[i] in your case, holds all the information about a single plot. Use them instead of calling plt, which only really works well with one subplot per figure or to modify all subplots at once. For example, instead of calling plt.figtext, call ax[0].text to add text to the top plot.
Try following the example code below, or at least read through it to get a better idea how to use your ax list.
import numpy as np
import matplotlib.pyplot as plt
histogram_data = np.random.rand(1000)
heatmap_data = np.random.rand(10, 100)
# Set up figure and axes
fig = plt.figure()
fig.suptitle("These are my two plots")
top_ax = fig.add_subplot(211) #2 rows, 1 col, 1st plot
bot_ax = fig.add_subplot(212) #2 rows, 1 col, 2nd plot
# This is the same as doing 'fig, (top_ax, bot_ax) = plt.subplots(2)'
# Histogram
weights = np.ones_like(histogram_data) / histogram_data.shape[0]
hist, bins = np.histogram(histogram_data, bins=50, weights=weights)
width = 0.7 * (bins[1] - bins[0])
center = (bins[:-1] + bins[1:]) / 2
# Use top_ax to modify anything with the histogram plot
top_ax.bar(center, hist, align='center', width=width)
# ax.text(x, y, str). Make sure x,y are within your plot bounds ((0, 1), (0, .5))
top_ax.text(0.5, 0.5, "Here is text on the top plot", color='r')
# Heatmap
heatmap_params = {'cmap':plt.cm.Blues, 'alpha':0.8, 'vmin':0, 'vmax':1}
# Use bot_ax to modify anything with the heatmap plot
heatmap = bot_ax.pcolor(heatmap_data, **heatmap_params)
cbar = fig.colorbar(heatmap, shrink=0.8, aspect=10, fraction=.1,pad=.01)
# See how it looks
plt.show()
Related
I am using matplotlib in Python and want to use the same plot but with several different axes that are all functions of the first one, but that do not linearly depend on the first y value.
As an example, let's assume a plot that shows a simple line y=x.
Now I have a random function like f(y)=5y^2 + 2.
My ideal output graph should now still be a line, but the equidistant ticks should not be y=1, 2, 3, 4, but f(y)=7, 22, 47, 82, so that I can overlay the two graphs with 2 different axes.
Is this even possible, as the distance between the ticks is not even nor can it be expressed in a log plot? Therefore I simply want to put a function on each tick value, without changing the graph nor the ticks' positions.
In a graphics program this would be straightforward, by simply using the same plot and manually rewriting each tick.
https://drive.google.com/file/d/1fp2vrFvlz-9xdJPmqdQjyMQK7gzPX24G/view?usp=sharing
Thank you in advance! The example code is not really helpful, as it is just the standard matplotlib code but the most important scaling part is missing.
I know that I can set the ticks manually with yticks, but this does not solve the scaling problem and all ticks would appear very close together.
plt.plot(["time_max_axis"], ["position_max_axis"])
plt.xlabel("Time (ms)")
plt.ylabel("Max position (mm)")
plt.ylim(0, z0_mm)
plt.show()
plt.plot(["time_max_axis"], ["frequency_axis"])
plt.xlabel("Oscillation frequency (kHz)")
plt.ylabel("Max position (mm)")
plt.ylim(fion_kHz, fion_kHz * (1 + (f_shift4 + f_shift6) / 100))
plt.show()
import matplotlib.pyplot as plt
from matplotlib.ticker import (MultipleLocator, AutoMinorLocator)
x = np.arange(50)
y = x/10 + np.random.rand(50)
fig, axs = plt.subplots(1,2, gridspec_kw={'width_ratios': [1, 20]})
plt.subplots_adjust(wspace=0, hspace=0)
axs[1].plot(x, y)
axs[1].plot(x, 2*y)
axs[1].plot(x, 3*y)
axs[1].grid()
axs[1].set_ylim(0)
axs[1].set_xlim(0)
axs[1].set_ylabel('max displacement $z_{max}$ (mm)')
ymin, ymax = axs[1].get_ylim()
majorlocator = ymax // 8 # 8 horizontal grid lines
ytickloc = np.arange(0, int(ymax), majorlocator)
axs[1].yaxis.set_major_locator(MultipleLocator(majorlocator))
ax1 = axs[1].twinx() # ghost axis of axs[1]
ax1.yaxis.set_ticks_position('left')
ax1.set_yticks([ymin, ymax])
ax1.set_yticklabels(['', f'$z_0$ = {round(ymax,2)}'])
axs[0].spines['top'].set_visible(False)
axs[0].spines['right'].set_visible(False)
axs[0].spines['bottom'].set_visible(False)
axs[0].spines['left'].set_visible(False)
axs[0].set_xticks([])
axs[0].set_yticks(ytickloc)
ytick2 = 5 * ytickloc**2 + 2 # f = 5y^2 + 2
ytick2 = list(ytick2)
ymin2 = ytick2[0]
ytick2[0] = ''
axs[0].set_yticklabels(ytick2)
axs[0].set_ylim(ymin, ymax)
axs[0].set_ylim(0)
axs[0].set_ylabel('Oscillation frequency $f_{osc}$ (kHz)')
ymax2 = 5 * ymax**2 + 2 # f = 5y^2 + 2
ax0 = axs[0].twinx() # ghost axis of axs[0]
ax0.yaxis.set_ticks_position('left')
ax0.spines['top'].set_visible(False)
ax0.spines['right'].set_visible(False)
ax0.spines['bottom'].set_visible(False)
ax0.spines['left'].set_visible(False)
ax0.set_yticks([ymin, ymax])
ax0.set_yticklabels([f'$\\bf{{f_{{ion}}}} = {round(ymin2, 2)}$', f'$f_{{max}}$ = {round(ymax2,2)}'])
plt.tight_layout()
Output:
I have this script to extract data from an image and roi. I have everything working perfectly except the end when I output the graphs. Basically I'm having trouble with the windowing of both histograms. It doesn't matter if I change the gridsize, mincount, figure size, or x and y limits one of the histograms will always be slightly stretched. When I plot them individually they aren't stretched. Is there a way to make the hexagons on the same plot a consistent "non-stretched" shape?
Down below is my graph and plotting methods. (I left out my data extraction methods because it was quite specialized).
plt.ion()
plt.figure(figsize=(16,8))
plt.title('2D Histogram of Entorhinal Cortex ROIs')
plt.xlabel(x_inputs)
plt.ylabel(y_inputs)
colors = ['Reds','Blues']
x = []
y= []
#image extraction code
hist1 = plt.hexbin(x[0],y[0], gridsize=100,cmap='Reds',mincnt=10, alpha=0.35)
hist2 = plt.hexbin(x[1],y[1], gridsize=100,cmap='Blues',mincnt=10, alpha=0.35)
plt.colorbar(hist1, orientation="vertical")
plt.colorbar(hist2, orientation="vertical")
plt.ioff()
plt.show()
enter image description here
This issue can be solved by setting limits for the bins with the extent parameter. This can be done automatically by computing the minimum and maximum x and y values across all the data being plotted. In cases where gridsize is small (e.g. 10), this approach may result in some of the bins being partially outside of the plot limits. If so, setting a margin with plt.margins can help display all the bins within the plot.
import numpy as np # v 1.20.2
import matplotlib.pyplot as plt # v 3.3.4
# Create a random dataset
rng = np.random.default_rng(seed=123) # random number generator
size = 10000
x1 = rng.normal(loc=5, scale=10, size=size)
y1 = rng.normal(loc=5, scale=2, size=size)
x2 = rng.normal(loc=-30, scale=5, size=size)
y2 = rng.normal(loc=-20, scale=5, size=size)
# Define hexbin grid extent
xmin = min(*x1, *x2)
xmax = max(*x1, *x2)
ymin = min(*y1, *y2)
ymax = max(*y1, *y2)
ext = (xmin, xmax, ymin, ymax)
# Draw figure with colorbars
plt.figure(figsize=(10, 6))
hist1 = plt.hexbin(x1, y1, gridsize=30, cmap='Reds', mincnt=10, alpha=0.3, extent=ext)
hist2 = plt.hexbin(x2, y2, gridsize=30, cmap='Blues', mincnt=10, alpha=0.3, extent=ext)
plt.colorbar(hist1, orientation='vertical')
plt.colorbar(hist2, orientation='vertical')
# plt.margins(0.1) # Uncomment this if hex bins are partially outside of plot limits
plt.show()
I want to plot a graph representing the changes as per the varying variables. The sample figure is shown below.
The idea is to plot subplot within a subplot. Note It is different from plotting a graph using subplot with a predefined number of rows and columns, i.e matplotlib.pyplot.subplots(nrows=2, ncols=2)
Can I plot such figures using matplotlib/seaborn?
I have drawn the frames and placed the axes inside the frames, everything is based on the no. of subplots/frame, the no. of rows and columns of the frames' grid and the physical dimensions of the different elements.
I imagine that most of the code is self explanatory, except the part where we place the axes in the precise locations, that's stolen from the Demo Fixed Size Axes, if you see points in need of elucidation please ask
import matplotlib
from mpl_toolkits.axes_grid1 import Divider, Size
from mpl_toolkits.axes_grid1.mpl_axes import Axes
import matplotlib.pyplot as plt
import numpy as np
from itertools import product
mm = lambda d: d/25.4
nplots = 2
wp, hp = mm(40), mm(28)
dxp, dyp = mm(16), mm(12)
nrows, ncols = 3, 2
wf, hf = nplots*(wp+dxp), hp+dyp
dxf, dyf = mm(10), mm(8)
xcorners, ycorners = (np.arange(dxf/2,ncols*(wf+dxf),wf+dxf),
np.arange(dyf/2,nrows*(hf+dyf),hf+dyf))
# plus 10 mm for suptitle
fig = plt.figure(figsize=(ncols*(wf+dxf), nrows*(hf+dyf)+mm(10)))
rect = lambda xy: plt.Rectangle(xy, wf, hf,
transform=fig.dpi_scale_trans,
figure=fig,
edgecolor='k', facecolor='none')
fig.patches.extend([rect(xy) for xy in product(xcorners, ycorners)])
t = np.linspace(0,3.14,315); s = np.sin(t)
for nframe, (y, x) in enumerate(product(ycorners, xcorners), 1):
for n in range(nplots):
divider = Divider(fig, (0.0, 0.0, 1., 1.),
[Size.Fixed(x+0.7*dxp+n*(wp+dxp)), Size.Fixed(wp)],
[Size.Fixed(y+0.7*dyp ), Size.Fixed(hp)],
aspect=False)
ax = Axes(fig, divider.get_position())
ax.set_axes_locator(divider.new_locator(nx=1, ny=1))
ax.plot(t, s)
fig.add_axes(ax)
fig.text(x, y, 'Frame %d'%nframe, transform=fig.dpi_scale_trans)
figsize = fig.get_size_inches()
width = figsize[0]*25.4 # mm
fig.suptitle('Original figure width is %.2f mm - everything is scaled'%width)
fig.savefig('pippo.png', dpi=118, facecolor='#f8f8f0')
You will need to use Matplotlib to plot these graphs
You can follow the following example to create your own figure with the graphs:
import matplotlib.pyplot as plt
plt.subplot(1, 2, 1) # Args ( Lines, Columns, Reference )
plt.plot(x, y, 'r') # Reference will say what graph we are modding
plt.subplot(1, 2, 2)
plt.plot(y, x, 'g')
plt.show()
The code will create one graph like this:
And you can use plt.xlabel('name'), plt.ylabel('name') and plt.title('name') to define the labels and the title of your figure
Note: The code above will create one image with 2 graphs, and you can use this code inside another block of code to create the image that you want.
You can also use the following code:
import matplotlib.pyplot as plt
fig, ax = plt.subplots(nrows=5, ncols=5, figsize=(5, 5))
ax[0, 0].plot(x, y) # The method ax is now one array and is referred by indexes
ax[0, 0].set_title('Title')
ax[1, 1].plot(x, y)
ax[1, 1].set_title('Title')
plt.tight_layout() # It will separate the graphs to avoid overlays
plt.show()
It will create the following image:
I want to visualise mathematical domains, or intervals. Equivalently, I want to visualise a boolean array. There are multiple such arrays, that ideally are plotted one above the other.
What I have is some data: several recordings, over a period of, say, 100 min. Each recording satisfies a given condition only part of the time. I want to visualise the times at which each recording is "True". Some simpler variant of:
In my case, each recording can be the union of multiple intervals. For example:
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sb
sb.set_context("paper")
times = np.arange(0, 100)
mask1 = (times >= 0) * (times <= 30) + (times >= 70) * (times <= 100)
mask2 = (times >= 20) * (times <= 80)
I can plot each recording separately, with these two functions I have written:
def bool2extreme(mask, times) :
"""return xmins and xmaxs for intervals in times"""
binary = 1*mask
slope = np.diff(binary)
extr = (slope != 0)
signs = slope[extr]
mins = list(times[1:][slope==1])
maxs = list(times[:-1][slope==-1])
if signs[0]==-1:
mins = [times[0]] + mins
if signs[-1]==1:
maxs = maxs + [times[-1]]
return mins, maxs
def plot_interval(mask, times, y=0, color='k', ax=None) :
if ax==None:
print('None')
ax = plt.gca()
xmins, xmaxs = bool2extreme(mask, times)
for xmin, xmax in zip(xmins, xmaxs):
ax.plot([xmin, xmax], [y,y], lw=6, color=color)
return ax
My problem is to control the vertical spacing between the various intervals. Indeed, when I plot one of them, there is a vertical axis which I don't want. Even if I set its visibility to False, it exists and takes space. So, when I put each recording on a different subplot, the vertical spacing between them is much too big:
masks = [mask1, mask2]
labels = ['domain1', 'domain2']
n_plots = len(masks)
fig, axs = plt.subplots(n_plots, sharex=True)
for i, mask in enumerate(masks) :
axs[i] = plot_interval(mask, times, ax=axs[i])
axs[-1].set_xlabel('Time (min)')
sb.despine()
Another option I tried: have all the intervals in the same axis, but at different y values. But the problem of the vertical spacing between the intervals remains the same.
masks = [mask1, mask2]
labels = ['domain1', 'domain2']
n_plots = len(masks)
fig, ax = plt.subplots(sharex=True)
for i, mask in enumerate(masks) :
ax = plot_interval(mask, times, y=i, ax=ax)
ax.set_xlabel('Time (min)')
ax.set_yticks(range(n_plots))
ax.set_yticklabels(labels)
ax.grid(axis="x")
sb.despine(left=True)
How can I control the vertical spacing between these intervals?
Some ideas:
figsize with a small height when creating the subplots; the height of figsize controls the distance between the horizontal axes: they will be height/num_axes separated when measured in inches
ax.yaxis.set_visible(False) to hide the ticks from the y-axis
ax.spines['left'].set_color('None') to make the spine of the y-axis invisible
ax.spines['bottom'].set_position(('data', 0)) to place the x-axis at the y=0 height
(optionally) ax.tick_params(labelbottom=True) to have labels for the xticks on all subplots (instead of only on the last)
use a rectangle instead of a thick line to better control the exact start and end of the line as well as the thickness above and under the axis
to control the height of the rectangle, the ylims need to be fixed; I propose (-1.5, .5) so a thickness can be chosen appropriately; there is more space below making room for the labels of the xticks
as drawing a rectangle doesn't automatically update the xlims, they need to be set explicitly
(optionally) ax.tick_params(which='both', direction='in') to get tick marks above instead below (both mayor and minor ticks)
To have labels on the left, the following worked for me:
# ax.yaxis.set_visible(False) # removed, as it also hides the ylabel
ax.set_ylabel('my ylabel', rotation=0, ha='right', labelpad=10)
ax.set_yticks([]) # to remove the ticks, the spine was already removed
In the demo code, more xticks and some type of arrow at the ends are added. There are 7 masks in the demo, to better see the effect of distance between the axes. Trying to get the axes as close as possible, a distance of 0.4 inches seems doable. (The bool2extreme function is untouched, as it is closely related to the format used as input.)
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle, Polygon
import matplotlib.ticker as plticker
import seaborn as sbs
sbs.set_context("paper")
times = np.arange(0, 101)
num_masks = 7
masks = [np.zeros_like(times, dtype=bool) for _ in range(num_masks)]
for i in range(num_masks):
for j in range(50):
masks[i] += (times >= (i+3)*j) * (times <= (i+3)*j+i+1)
masks = masks[::-1] # reverse to get the masks plotted from bottom to top
def bool2extreme(mask, times) :
"""return xmins and xmaxs for intervals in times"""
binary = 1*mask
slope = np.diff(binary)
extr = (slope != 0)
signs = slope[extr]
mins = list(times[1:][slope==1])
maxs = list(times[:-1][slope==-1])
if signs[0]==-1:
mins = [times[0]] + mins
if signs[-1]==1:
maxs = maxs + [times[-1]]
return mins, maxs
def plot_interval(mask, times, xlim=None, y=0, thickness=0.4, color='k', ax=None):
if ax is None:
ax = plt.gca()
ax.yaxis.set_visible(False)
ax.spines['left'].set_color('None')
ax.spines['right'].set_color('None')
ax.spines['top'].set_color('None')
ax.spines['bottom'].set_position(('data', 0))
ax.tick_params(labelbottom=True) # to get tick labels on all axes
# ax.tick_params(which='both', direction='in')` # tick marks above instead below the axis
ax.xaxis.set_major_locator(plticker.MultipleLocator(base=10)) # major ticks in steps of 10
ax.xaxis.set_minor_locator(plticker.MultipleLocator(base=1)) # minor ticks in steps of 1
ax.set_ylim(-1.5,.5)
if xlim is None:
xlim = (times[0]-0.9, times[-1]+0.9)
ax.set_xlim(xlim)
xmins, xmaxs = bool2extreme(mask, times)
for xmin, xmax in zip(xmins, xmaxs):
#ax.add_patch(Rectangle((xmin, y-thickness), xmax-xmin, 2*thickness, linewidth=0, color=color))
ax.add_patch(Rectangle((xmin, y), xmax-xmin, thickness, linewidth=0, color=color))
triangle1 = [(xlim[0]-0.5, y), (xlim[0], y-thickness), (xlim[0], y+thickness)]
ax.add_patch(Polygon(triangle1, linewidth=0, color='black', clip_on=False))
triangle2 = [(xlim[1]+0.5, y), (xlim[1], y-thickness), (xlim[1], y+thickness)]
ax.add_patch(Polygon(triangle2, linewidth=0, color='black', clip_on=False))
return ax
n_plots = len(masks)
dist_between_axis_in_inches = 0.4
fig, axs = plt.subplots(n_plots, sharex=True, figsize=(10, dist_between_axis_in_inches*len(masks)))
for i, mask in enumerate(masks) :
axs[i] = plot_interval(mask, times, xlim=(times[0]-0.5, times[-1]+0.5), ax=axs[i], color='lime')
axs[-1].set_xlabel('Time (min)')
plt.show()
Result with axes close together:
PS: This post contains more proposals about adding arrows.
I am trying to plot both a circular histogram and a vector (overlapping) on the same polar plot, but cannot get the vector to show up.
Basically, my data set consists of the times at which unitary events occur during a repeating cycle. This data is in the array "all_phases", which is just a list of degree values for each of these events. I want to show (1) the overall distribution of events w/ a circular histogram (bins corresponding to degree ranges) and (2) a vector sum as a measure of the coherence of all of these values (treating each event as a unit vector).
I can plot either one of these things individually on the subplot titled "histo", but when I try to plot both, only the histogram shows up. I have tried playing with the z-indexes of both objects to no use. The code is:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib
import math
array = np.array
all_phases = [array([-38.24240218]), array([-120.51570738]), array([-23.70224663]),
array([114.9540152]), array([ 2.94523445]), array([-2.16112692]), array([-18.72274284]),
array([13.2292216]), array([-95.5659992]), array([15.69046269]), array([ 51.12022047]),
array([-89.10567276]), array([ 41.77283949]), array([-9.92584921]), array([-7.59680678]),
array([166.71824996]), array([-178.94642752]), array([-23.75819463]), array([38.69481261]),
array([-52.26651244]), array([-57.40976514]), array([33.68226762]), array([-122.1818295]),
array([ 10.17007425]), array([-38.03726335]),array([44.9504975]), array([ 134.63972923]),
array([ 63.02516932]),array([-106.54049292]), array([-25.6527599])]
number_bins = 60
bin_size = 360/number_bins
cluster_num = 1
counts, theta = np.histogram(all_phases, np.arange(-180, 180 + bin_size, bin_size), density=True)
theta = theta[:-1]+ bin_size/2.
theta = theta * np.pi / 180
a_deg = map(lambda x: np.ndarray.item(x), all_phases)
a_rad = map(lambda x: math.radians(x), a_deg)
a_cos = map(lambda x: math.cos(x), a_rad)
a_sin = map(lambda x: math.sin(x), a_rad)
uv_x = sum(a_cos)/len(a_cos)
uv_y = sum(a_sin)/len(a_sin)
uv_radius = np.sqrt((uv_x*uv_x) + (uv_y*uv_y))
uv_phase = np.angle(complex(uv_x, uv_y))
"""
plot histogram and vector sum
"""
fig = plt.figure()
ax1 = fig.add_axes([0.1, 0.16, 0.05, 0.56])
histo = fig.add_subplot(111, polar=True)
histo.yaxis.set_ticks(())
histo.arrow(0,0,0.11, 1, head_width=.01, zorder=2)
plt.suptitle("Phase distribution for Neuron #" + str(cluster_num), fontsize=15, y=.94)
plt.subplots_adjust(bottom=0.12, right=0.95, top=0.78, wspace=0.4)
width = (2*np.pi) / number_bins
bars = histo.bar(theta, counts, width = width, bottom=0.002)
for r, bar in zip(counts, bars):
bar.set_facecolor(plt.cm.jet(r / max(counts)))
bar.set_alpha(0.7)
bar.set_zorder(1)
norm = matplotlib.colors.Normalize(vmin (counts.min())*len(all_phases)*bin_size, vmax=(counts.max())*len(all_phases)*bin_size)
cb1 = matplotlib.colorbar.ColorbarBase(ax1, cmap=plt.cm.jet,
orientation='vertical', norm=norm, alpha=0.4,
ticks=np.arange(0, (counts.max())*len(all_phases)*bin_size)+1, )
cb1.ax.tick_params(labelsize=9)
cb1.solids.set_rasterized(True)
cb1.set_label("# spikes")
cb1.ax.yaxis.set_label_position('left')
plt.show()
cluster_num = cluster_num + 1
vs_radius and vs_phase are the parameters for the vector sum arrow I want to put on the polar plot, which I end up calling w/ histo.arrow().
My suspicion is that it might have something to do with trying to put two things on a subplot object?
Any help or thoughts would be very much appreciated!!
The problem is that the FancyArrow that is used by Axes.arrow() does not play well with polar plots.
Instead, you could use the annotate() function to draw a simple arrow that works better in the case of polar plots.
for example:
# Compute pie slices
N = 20
theta = np.linspace(0.0, 2 * np.pi, N, endpoint=False)
radii = 10 * np.random.rand(N)
width = np.pi / 4 * np.random.rand(N)
ax = plt.subplot(111, projection='polar')
bars = ax.bar(theta, radii, width=width, bottom=0.0)
# Use custom colors and opacity
for r, bar in zip(radii, bars):
bar.set_facecolor(plt.cm.viridis(r / 10.))
bar.set_alpha(0.5)
v_angle = 0.275*np.pi
v_length = 4
ax.annotate('',xy=(v_angle, v_length), xytext=(v_angle,0), xycoords='data', arrowprops=dict(width=5, color='red'))
plt.show()
As a general rule, when you deal with polar plot, you have to work just as if you were working with a linear plot. That is to say, you shouldn't try to draw your arrow from (0,0) but rather from (uv_phase, 0)
fig, ax = plt.subplots()
bars = ax.bar(theta, radii, width=width, bottom=0.0)
# Use custom colors and opacity
for r, bar in zip(radii, bars):
bar.set_facecolor(plt.cm.viridis(r / 10.))
bar.set_alpha(0.5)
ax.annotate('',xy=(v_angle, v_length), xytext=(v_angle,0), xycoords='data', arrowprops=dict(width=5, color='red'))