I am trying to plot live data from incoming data packet. I have four subplots which on one of the subplot, i want to plot data as Stem plot however i am receiving following error:
self.stemlines.set_data(z, y)
AttributeError: 'list' object has no attribute 'set_data'
plt.plot works fine but I am not able to get it to work for plt.steam.
import matplotlib
matplotlib.use('Qt5Agg')
import matplotlib.pyplot as plt
from matplotlib.widgets import TextBox
import matplotlib
class PlotEngine:
def __init__(self, axisChanged):
# plt.style.use('seaborn-whitegrid')
# style.use('fivethirtyeight')
initialMinValue = '14.4'
initialMaxValue = '14.9'
plt.style.use('ggplot')
matplotlib.rc('axes', titlesize=8) # fontsize of the axes title
matplotlib.rc('axes', labelsize=8)
matplotlib.rc('xtick', labelsize=8) # fontsize of the tick labels
matplotlib.rc('ytick', labelsize=8) # fontsize of the tick labels axes.titlesize
matplotlib.rc('figure', titlesize=8)
self.fig, self.ax = plt.subplots(2, 2)
plt.ion()
# plt.subplot(2, 2, 4, polar=True)
self.fig.patch.set_facecolor('gray')
self.axpolar = plt.subplot(2, 2, 4, projection='polar')
self.axpolar.set_facecolor('black')
# self.ax[1, 1] = fig.add_subplot(2, 2, 4, projection='polar')
self.ax[0, 0].set_facecolor('black')
self.ax[0, 1].set_facecolor('black')
self.ax[1, 0].set_facecolor('black')
self.ax[1, 1].set_facecolor('black')
self.axisChanged = axisChanged
self.slider_freq = plt.axes([0.1, 0.01, 0.3, 0.01])
self.slider_azi = plt.axes([0.5, 0.01, 0.3, 0.01])
self.freqAxBoxMin = plt.axes([0.55, 0.33, 0.04, 0.03])
self.freqAxBoxMax = plt.axes([0.55, 0.28, 0.04, 0.03])
self.freqMinValueBox = TextBox(self.freqAxBoxMin, 'Min Freq:', initial=initialMinValue)
self.freqMaxValueBox = TextBox(self.freqAxBoxMax, 'Max Freq:', initial=initialMaxValue)
self.aziAxBoxMin = plt.axes([0.55, 0.18, 0.04, 0.03])
self.aziAxBoxMax = plt.axes([0.55, 0.10, 0.04, 0.03])
self.aziMinValueBox = TextBox(self.aziAxBoxMin, 'Min Dir:', initial='-180')
self.aziMaxValueBox = TextBox(self.aziAxBoxMax, 'Max Dir:', initial='180')
self.zeroOne, = self.ax[0, 1].plot([], [], 'ro')
self.oneOne, = self.axpolar.plot([], [], 'ro')
self.markerline, self.stemlines, self.baseline, = self.ax[1, 0].stem([1], [1], bottom=-140)
self.ax[0, 1].set_xlim([0, 60])
self.ax[0, 1].set_ylim([-140, -40])
self.axpolar.set_yticks(range(-90, -30, 10)) # Define the yticks
# self.axpolar.set_yticklabels(map(str, range(-90, -30, -10))) # Change the labels
self.ax[1, 0].set_xlim([14, 14.8])
self.ax[1, 0].set_ylim([-140, -40])
# self.background = fig.canvas.copy_from_bbox(self.ax.bbox)
def animateZeroOne(self, i, azimuth, rss, freqGhz):
x = azimuth
y = rss
z = freqGhz
self.zeroOne.set_data(x, y)
self.oneOne.set_data(x, y)
self.stemlines.set_data(z, y)
self.markerline.set_data(z, y)
return self.zeroOne, self.oneOne, self.stemlines, self.markerline
According to StemContainer, stemlines is a list (of Line2D), so it does not have attribute set_data, like markerline or baseline (of type Line2D). Maybe you want to apply that function over every member of the list at your animateZeroOne function?:
def animateZeroOne(self, i, azimuth, rss, freqGhz):
x = azimuth
y = rss
z = freqGhz
self.zeroOne.set_data(x, y)
self.oneOne.set_data(x, y)
[x.set_data(z, y) for x in self.stemlines]
self.markerline.set_data(z, y)
return self.zeroOne, self.oneOne, self.stemlines, self.markerline
Related
I'm trying to have the following plot to appear like the second plot.
Without the axises (vertical, horizontal) that have no meaning for this plot and range from 0 to 1.
This is the code I'm using to generate to plot:
import matplotlib.pyplot as plt
import numpy as np
x_lim = (0, 1)
y_lim = (0, 1)
z_lim = (0, 1)
list_points = [[0.3, 0.3, 0], [0.4, 0.4, 0], [0, 0, 0], [.1, .1, .5], [0.3, 0.3, .2]]
def plot_tracking_map():
"""
Visualize all grapes centers on a 3d map.
This function generates a plot that represents the TB in 3D.
"""
x_cors, y_cors, z_cors = [], [], []
for i in range(len(list_points)):
x_cor, y_cor, z_cor = list_points[i][0], list_points[i][1], list_points[i][2]
x_cors.append(x_cor)
y_cors.append(y_cor)
z_cors.append(z_cor)
fig, ax = plt.subplots(figsize=(12, 12))
ax = fig.add_subplot(projection='3d')
yy, zz = np.meshgrid(range(2), range(2))
xx = yy
s = ax.scatter(x_cors, y_cors, z_cors, s=400, marker='o') # x,y,z coordinates, size of each point, colors.
# controls the alpha channel. all points have the same value, ignoring their distance
s.set_edgecolors = s.set_facecolors = lambda *args: None
ax.title.set_text(f'Imgae number 1')
plt.show()
plot_tracking_map()
edit
I changed the lines
fig, ax = plt.subplots(figsize=(12, 12))
ax = fig.add_subplot(projection='3d')
to
fig, ax = plt.subplots(figsize=(12, 12), subplot_kw={'projection': '3d'})
And it solved the problem.
Why does my colorbar label "y1" disappear when I add the second colorbar?
If I remove the colorbar for ax2, then the label shows on the first colorbar.
Using Python 3.8
Stand-Alone Code
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import matplotlib.colors as mcolors
%matplotlib inline
plt.style.use('seaborn-whitegrid')
x = [-15000, -2000, 0, 5000, 6000, 11000, 18000, 21000, 25000, 36000, 62000]
beta = [1000, 200, -800, 100, 1000, -2000, -5000, -5000, -15000, -21000, -1500]
y = [0.01, 0.2, 1.3, 0.35, 0.88, 2.2, 2.5, 1.25, 3.4, 4.1, 2.1]
fig = plt.figure(figsize=(10, 7.5), constrained_layout=True)
gs = fig.add_gridspec(2, 1)
ax1 = fig.add_subplot(gs[0, 0])
ax2 = fig.add_subplot(gs[1, 0], sharex = ax1)
fig.execute_constrained_layout()
fig.suptitle('Suptitle')
vals = ax1.scatter(x, beta, c=y, norm=mcolors.LogNorm(), cmap='rainbow')
ax1.set_title('ax1', style='italic');
cbax1=ax1.inset_axes([1.1, 0, 0.03, 1], transform=ax1.transAxes)
cbar1=fig.colorbar(vals, cax=cbax1, format = '%1.2g', orientation='vertical')
cbar1.ax.set_ylabel('y1')
cbar1.ax.yaxis.set_label_position('left')
ax2.scatter(x, y, c=y, norm=mcolors.LogNorm(), cmap='rainbow')
ax2.set_title('ax2', style='italic');
vals2 = vals
cbax2 = ax2.inset_axes([1.1, 0, 0.03, 1], transform=ax2.transAxes)
cbar2 = fig.colorbar(vals2, cax=cbax2, format = '%1.2g', orientation='vertical')
cbar2.ax.set_ylabel('y2')
cbar2.ax.yaxis.set_label_position('left')
Made two correction in your code. I am also using Python 3.8
# ---> Assign the second scatter plot to vals2
vals2 = ax2.scatter(x, y, c=y, norm=mcolors.LogNorm(), cmap='rainbow')
ax2.set_title('ax2', style='italic');
# ---> comment below line.
#vals2 = vals
result:
In adition, you can add label to colorbar() function like this:
cbar1=fig.colorbar(vals, cax=cbax1, format = '%1.2g', orientation='vertical', label='y1')
cbar2 = fig.colorbar(vals2, cax=cbax2, format = '%1.2g', orientation='vertical', label='y2')
Try restarting the kernel if you still face this issue.
It might be a bug. You can set the labels after plotting:
# Your other codes
# also can use `cbax1` instead of `cbar1.ax`
cbar2.ax.set_ylabel('y2')
cbar2.ax.yaxis.set_label_position('left')
cbar1.ax.set_ylabel('y1')
cbar1.ax.yaxis.set_label_position('left')
Output:
I don't know why but I am really struggling to get widgets working well in python. I try to look at examples about how to use them but I don't know how to extrapolate that to get it to work with my code. I am trying to get a figure to display widgets such that the type, frequency, phase, and other variables adjust the graph itself.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.widgets as widgets
from scipy import signal
from matplotlib.widgets import RadioButtons
A = 1
ang_f = 5
t = np.linspace(0, 4*np.pi, 1000)
phase = 0
s0 = A*np.sin(ang_f*t + phase)
s2 = A*signal.sawtooth(ang_f*t + phase)
s1 = A*signal.square(ang_f*t + phase)
fig, ax = plt.subplots()
l, = ax.plot(t, s1, lw=2, color='red')
plt.subplots_adjust(left=0.4)
def sinf(x, omega):
return np.sin(omega*x)
def sliderCallback(val):
# """ 'val' is the current value selected by the slider
# Recalculate sine values with val as the frequency """
axesHandle.set_ydata(sinf(x, val))
plt.draw() # Redraw the axes
def clickcallback(val):
# 'val' is the current value selected by the slider
# Recalculate sine values with val as the frequency
axesHandle.set_ydata(sinf(x, val))
plt.draw() # Redraw the axes
def closeCallback(event):
plt.close('all') # Close all open figure windows
fig = plt.figure(figsize=(7, 5))
ax = plt.axes([0.1, 0.2, 0.6, 0.7])
axesHandle, = plt.plot(x, sinf(x, 1), lw=2, color='red')
# Add axis to contain the slider
fax = plt.axes([0.1, 0.04, 0.35, 0.03]) # Frequency
tax = plt.axes([0.1, 0.12, 0.35, 0.03]) # Time
sax_3 = plt.axes([0.60, 0.1, 0.35, 0.03]) # Number of points
pax = plt.axes([0.60, 0.05, 0.35, 0.03]) # Phase
rax = plt.axes([0.85, 0.65, 0.12, 0.15]) # Type
bax = plt.axes([0.85, 0.85, 0.1, 0.1]) # Close
pointshandle = widgets.Slider(sax_3, 'Number of points', 1, 200,
valfmt='%0.0f')
pointshandle.on_changed(sliderCallback)
graphchoice = widgets.RadioButtons(rax, ('Sine', 'Squarewave', 'Sawtooth'))
graphchoice.on_clicked(clickcallback)
freqhandle = widgets.Slider(fax, 'Frequancy (Hz)', 0, 5, valinit=1)
freqhandle.on_changed(sliderCallback)
phasehandle = widgets.Slider(pax, 'Phase', 0, 0*np.pi, valinit=0)
phasehandle.on_changed(sliderCallback)
timehandle = widgets.Slider(tax, 'Time (s)', 1, 10, valinit=1)
timehandle.on_changed(sliderCallback)
buttonHandle = widgets.Button(bax, 'Close')
buttonHandle.on_clicked(closeCallback)
def hzfunc(label):
hzdict = {'Sine': s0, 'Squarewave': s1, 'Sawtooth': s2}
ydata = hzdict[label]
l.set_ydata(ydata)
plt.draw()
graphchoice.on_clicked(hzfunc)
I'm really lost so any tips to put me on the right path would be much appreciated, im just so confused atm.
I need to make some plots with multiple parameters, and I choosed to make it more interactive with matplotlib sliders. For some practise before my actual task I tried to make it relativelly simple, but my sliders does not work. Here is the code, which is inspired from here.
Code:
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.widgets as mw
from scipy import stats
mu = 1
sigma = 3
a = 2
b = 3
axis_color = 'lightgoldenrodyellow'
x = [i for i in range(-100,100,1)]
normal_pdf = stats.norm.pdf(x, mu, sigma)
a_normal_pdf = [i*a for i in normal_pdf]
ab_normal_pdf = [i*b*a for i in normal_pdf]
fig = plt.figure()
ax1 = fig.add_subplot(221)
ax2 = fig.add_subplot(222)
ax3 = fig.add_subplot(223)
ax4 = fig.add_subplot(224)
ax4.axis('off')
#sliders
a_slider_ax = fig.add_axes([0.6, 0.25, 0.25, 0.03], axisbg=axis_color)
a_slider = mw.Slider(a_slider_ax, 'a', 1, 100, valinit = a)
b_slider_ax = fig.add_axes([0.6, 0.4, 0.25, .03], axisbg = axis_color)
b_slider = mw.Slider(b_slider_ax, 'b', 1, 100, valinit = b)
#function for sliders
def sliders_on_change(val):
a_normal_pdf.set_ydata([x*a_slider for x in normal_pdf])
ab_normal_pdf.set_ydata([x*a_slider*b_slider for x in normal_pdf])
fig.canvas.draw_idle()
a_slider.on_changed(sliders_on_change)
b_slider.on_changed(sliders_on_change)
ax1.plot(x, normal_pdf, 'r-')
ax2.plot(x, a_normal_pdf, 'bo')
ax3.plot(x, ab_normal_pdf, 'g*')
plt.show()
I do not fully understand HOW sliders should work, so its maybe the problem instead of idle issue as here, because I tried it in spyder and in jupyter as well, no difference. I can move with sliders, but I cant change the a_normal_pdf nor ab_normal_pdf.
You have two issues in your code:
using the slider object a_slider in place of the slider's current value a_slider.val
the method set_ydata changes the y-data of a Line2D plot object (I saved it in a variable p1 to be able to modify it)
Modified code (hope this helps)
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.widgets as mw
from scipy import stats
mu = 1
sigma = 3
a = 2
b = 3
axis_color = 'lightgoldenrodyellow'
x = [i for i in range(-100,100,1)]
normal_pdf = stats.norm.pdf(x, mu, sigma)
a_normal_pdf = [i*a for i in normal_pdf]
ab_normal_pdf = [i*b*a for i in normal_pdf]
fig = plt.figure()
ax1 = fig.add_subplot(221)
ax2 = fig.add_subplot(222)
ax3 = fig.add_subplot(223)
ax4 = fig.add_subplot(224)
ax4.axis('off')
#sliders
a_slider_ax = fig.add_axes([0.6, 0.25, 0.25, 0.03], axisbg=axis_color)
a_slider = mw.Slider(a_slider_ax, 'a', 1, 100, valinit = a)
b_slider_ax = fig.add_axes([0.6, 0.4, 0.25, .03], axisbg = axis_color)
b_slider = mw.Slider(b_slider_ax, 'b', 1, 100, valinit = b)
#function for sliders
def sliders_on_change(val):
p1.set_ydata([x*a_slider.val for x in normal_pdf])
p2.set_ydata([x*a_slider.val*b_slider.val for x in normal_pdf])
fig.canvas.draw_idle()
a_slider.on_changed(sliders_on_change)
b_slider.on_changed(sliders_on_change)
p1,=ax1.plot(x, normal_pdf, 'r-')
p2,=ax2.plot(x, a_normal_pdf, 'bo')
p3,=ax3.plot(x, ab_normal_pdf, 'g*')
plt.show()
I'm trying to learn how radar charts work in matplotlib. I'm using the code in this thread, but the plot I'm producing is not rightly centered and there are axis missing. I' ve tried with matplotlib 1.3.1, 1.4.1 and 1.5.1 in case something changed in the last versions.
import numpy as np
import pylab as pl
class Radar(object):
def __init__(self, fig, titles, labels, rect=None):
if rect is None:
rect = [0.05, 0.05, 0.95, 0.95]
self.n = len(titles)
self.angles = np.arange(90, 90+360, 360.0/self.n)
self.axes = [fig.add_axes(rect, projection="polar", label="axes%d" % i)
for i in range(self.n)]
self.ax = self.axes[0]
self.ax.set_thetagrids(self.angles, labels=titles, fontsize=14)
for ax in self.axes[1:]:
ax.patch.set_visible(False)
ax.grid("off")
ax.xaxis.set_visible(False)
for ax, angle, label in zip(self.axes, self.angles, labels):
ax.set_rgrids(range(1, 6), angle=angle, labels=label)
ax.spines["polar"].set_visible(False)
ax.set_ylim(0, 5)
def plot(self, values, *args, **kw):
angle = np.deg2rad(np.r_[self.angles, self.angles[0]])
values = np.r_[values, values[0]]
self.ax.plot(angle, values, *args, **kw)
fig = pl.figure(figsize=(6, 6))
titles = list("ABCDE")
labels = [
list("abcde"), list("12345"), list("uvwxy"),
["one", "two", "three", "four", "five"],
list("jklmn")
]
radar = Radar(fig, titles, labels)
radar.plot([1, 3, 2, 5, 4], "-", lw=2, color="b", alpha=0.4, label="first")
radar.plot([2.3, 2, 3, 3, 2],"-", lw=2, color="r", alpha=0.4, label="second")
radar.plot([3, 4, 3, 4, 2], "-", lw=2, color="g", alpha=0.4, label="third")
radar.ax.legend()
I had the same problem, but I found that the problem was the following part:
self.angles = np.arange(90, 90+360, 360.0/self.n)
So change it to
self.angles = np.arange(0, 360, 360.0/self.n)
and rotate each ax with ax.set_theta_offset(np.deg2rad(90)) instead.
The modified class looks like this:
# Python 3.4
# matplotlib 1.5.3
class Radar(object):
def __init__(self, fig, titles, labels, rotation=0, rect=None):
if rect is None:
rect = [0.05, 0.05, 0.95, 0.95]
self.n = len(titles)
self.angles = np.arange(0, 360, 360.0/self.n)
self.axes = [fig.add_axes(rect, projection="polar", label="axes%d" % i)
for i in range(self.n)]
self.ax = self.axes[0]
self.ax.set_thetagrids(self.angles, labels=titles, fontsize=14)
for ax in self.axes[1:]:
ax.patch.set_visible(False)
ax.grid("off")
ax.xaxis.set_visible(False)
for ax, angle, label in zip(self.axes, self.angles, labels):
ax.set_rgrids(range(1, 6), angle=angle, labels=label)
ax.spines["polar"].set_visible(False)
ax.set_ylim(0, 6)
ax.set_theta_offset(np.deg2rad(rotation))
def plot(self, values, *args, **kw):
angle = np.deg2rad(np.r_[self.angles, self.angles[0]])
values = np.r_[values, values[0]]
self.ax.plot(angle, values, *args, **kw)
Note: I've added the parameter rotation=0 to __init__ and apply the rotation to all ax in the last loop of it.
I know it's been a while since the question was asked, but I assume someone else will stumble upon this.