plotly: 3D plotting returns a figure with no datapoints - python-3.x

Trying to plot results from K-means clustering using 3D plot (Plotly). There is a blank figure generated in the HTML when I use the below code. I printed the variables scatter 1,2,3 and also the cluster 1,2,3 and values are shown. Is there a plt.show() like in matplotlib in plotly to show the values in the graph?
import pandas as pd
import numpy as np
import argparse
import json
import re
import os
import sys
import plotly
import plotly.graph_objs as go
cluster1=df.loc[df['y'] == 0]
cluster2=df.loc[df['y'] == 1]
cluster3=df.loc[df['y'] == 2]
scatter1 = dict(
mode = "markers",
name = "Cluster 1",
type = "scatter3d",
x = cluster1.as_matrix()[:,0], y = cluster1.as_matrix()[:,1], z = cluster1.as_matrix()[:,2],
marker = dict( size=2, color='green')
)
scatter2 = dict(
mode = "markers",
name = "Cluster 2",
type = "scatter3d",
x = cluster2.as_matrix()[:,0], y = cluster2.as_matrix()[:,1], z = cluster2.as_matrix()[:,2],
marker = dict( size=2, color='blue')
)
scatter3 = dict(
mode = "markers",
name = "Cluster 3",
type = "scatter3d",
x = cluster3.as_matrix()[:,0], y = cluster3.as_matrix()[:,1], z = cluster3.as_matrix()[:,2],
marker = dict( size=2, color='red')
)
cluster1 = dict(
alphahull = 5,
name = "Cluster 1",
opacity = .1,
type = "mesh3d",
x = cluster1.as_matrix()[:,0], y = cluster1.as_matrix()[:,1], z = cluster1.as_matrix()[:,2],
color='green', showscale = True
)
cluster2 = dict(
alphahull = 5,
name = "Cluster 2",
opacity = .1,
type = "mesh3d",
x = cluster2.as_matrix()[:,0], y = cluster2.as_matrix()[:,1], z = cluster2.as_matrix()[:,2],
color='blue', showscale = True
)
cluster3 = dict(
alphahull = 5,
name = "Cluster 3",
opacity = .1,
type = "mesh3d",
x = cluster3.as_matrix()[:,0], y = cluster3.as_matrix()[:,1], z = cluster3.as_matrix()[:,2],
color='red', showscale = True
)
layout = dict(
title = 'Interactive Cluster Shapes in 3D',
scene = dict(
xaxis = dict(zeroline=True ),
yaxis = dict(zeroline=True ),
zaxis = dict(zeroline=True ),
)
)
fig = dict(data=[scatter1, scatter2, scatter3, cluster1, cluster2, cluster3], layout=layout )
# Use py.iplot() for IPython notebook
plotly.offline.iplot(fig, filename='mesh3d_sample.html')
#py.iplot(fig, filename='mesh3d_sample')
HTML with just the axis and no data points displayed

Related

Bokeh Hover Showing ??? instead of Date and Time

I have read lots of questions and answers here and can not seem to fix my issue. I can not get the Hover tool in Bokeh to display the Date and Time correctly, I get ???, I understand this to mean that the Hover cannot read the column in my Dataframe.
I have implemented a lot of fixes and I think what I have here should work.
Here is my code:
This is the code for the data collection:
import cv2 as cv
from datetime import datetime
import pandas as pd
background = None
status_list = [None, None]
times = []
df = pd.DataFrame(columns = ['Start', 'End'])
video = cv.VideoCapture(0, cv.CAP_DSHOW)
while True:
check, frame = video.read()
status = 0
gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
gray = cv.GaussianBlur(gray, (21, 21), 0)
if background is None:
background = gray
continue
delta_frame = cv.absdiff(background, gray)
thresh_delta = cv.threshold(delta_frame, 40, 255, cv.THRESH_BINARY)[1]
thresh_delta = cv.dilate(thresh_delta, None, iterations = 2)
(cnts, _) = cv.findContours(thresh_delta.copy(), cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
for contour in cnts:
if cv.contourArea(contour) < 2000:
continue
status = 1
(x, y, w, h) = cv.boundingRect(contour)
cv.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 3)
status_list.append(status)
status_list = status_list[-2:]
if status_list[-1] == 1 and status_list[-2] == 0:
times.append(datetime.now())
if status_list[-1] == 0 and status_list[-2] == 1:
times.append(datetime.now())
cv.imshow('Delta', delta_frame)
cv.imshow('Threshold Frame', thresh_delta)
cv.imshow('Colour Frame', frame)
key = cv.waitKey(1)
if key == ord('q'):
if status == 1:
times.append(datetime.now())
break
for i in range(0, len(times), 2):
df = df.append({'Start' :times[i], 'End' :times[i + 1]}, ignore_index = True)
video.release()
cv.destroyAllWindows()
And here is the code for the Bokeh graph:
%run Motion_Detection_Plotting.ipynb
from bokeh.plotting import figure, show, output_file
from bokeh.models import HoverTool, ColumnDataSource, formatters, TickFormatter
df['Start'] = pd.to_datetime(df.Start, format='%Y-%m-%D %H:%M:%S')
df['End'] = pd.to_datetime(df.End, format='%Y-%m-%D %H:%M:%S')
Source=ColumnDataSource(df.Start, df.End)
p = figure(x_axis_type = 'datetime', height = 200, width = 1000, title = 'Motion Graph', sizing_mode = 'stretch_width')
p.yaxis.minor_tick_line_color = None
p.yaxis.major_tick_in = 0
p.xaxis.major_tick_in = 0
p.yaxis.ticker = [0, 1]
p.ygrid.grid_line_color = None
hover = HoverTool(tooltips=[('Start', '#Start{%D/%m %H:%M:%S}'), ('End','#End{%D/%m %H:%M:%S}')],
formatters={'#Start':'datetime', '#End':'datetime'})
p.add_tools(hover)
q = p.quad(left = df['Start'], right = df['End'], bottom = 0, top = 1, color = 'green')
output_file('graph2.html')
show(p)
And here is my outputted graph
Graph with Hover showing ??? instead of date and time
You are very close to a working solution. Your are defining a ColumnDataSource (CDS) but you are not using it and a HoverTool trys to get the needed infromation from the CDS.
Please see the minmal example below with an working Holvertool.
import pandas as pd
from bokeh.plotting import figure, show, output_notebook
from bokeh.models import HoverTool, ColumnDataSource, formatters, TickFormatter
output_notebook()
# dummy data
df = pd.DataFrame({'Start':['2020-01-01 00:00:00'], 'End':['2020-01-01 00:15:00']})
df['Start'] = pd.to_datetime(df.Start, format='%Y-%m-%d %H:%M:%S')
df['End'] = pd.to_datetime(df.End, format='%Y-%m-%d %H:%M:%S')
# bokeh
source=ColumnDataSource(df)
p = figure(x_axis_type = 'datetime')
hover = HoverTool(tooltips=[('Start', '#Start{%D/%m %H:%M:%S}'), ('End','#End{%D/%m %H:%M:%S}')],
formatters={'#Start':'datetime', '#End':'datetime'})
p.add_tools(hover)
# main change is here, data comes from CDS not from DataFrame
q = p.quad(left='Start', right='End', bottom=0, top=1, color='green', source=source)
show(p)
This is the output:

Plotly plot a vertical line on a time series plot due to conditions

Hi I have a dataframe with time series on my x axis and values on my y axis.
I am using Plotly and am trying to plot a vertical line on the x axis where there my df.Alert == 1.
Currently I am using another overlay with red marker to plot it but I wish to switch to a vertical line that is restricted within by the y values of my chart. The values on the y axis should still be determined by my trace plot and not the vertical line.
Is there a way for me to do this?
My code sample is written below
Trace = go.Scatter(
name = "Values",
x = df.DateTime,
y = df.Values,
mode='markers',
text= "Unit: " + df['Unit'].astype(str),
)
Alert = go.Scatter(
name = "Alert",
x = df.DateTime,
y = df.Values.where(df.Alert == 1),
mode='markers',
line = dict(color = "red"),
text= "Unit: " + df['Unit'].astype(str),
)
layout = go.Layout(
xaxis = dict(title = "Date and Time"),
yaxis = dict(title = "Values")
)
data = [Trace, Alert]
figure = go.Figure(data = data, layout = layout)
py.iplot(figure)
You perfectly describe what you want to do... plot vline
iterate over rows in DF that are alerts fig.add_vline()
n=50
df = pd.DataFrame({"DateTime":pd.date_range("1-jan-2021", freq="15min", periods=n),
"Alert":np.random.choice([0]*10+[1], n),
"Unit":np.random.choice([0,1,2,3], n),
"Values":np.random.uniform(1,10, n)})
Trace = go.Scatter(
name = "Values",
x = df.DateTime.astype(str),
y = df.Values,
mode='markers',
text= "Unit: " + df['Unit'].astype(str),
)
layout = go.Layout(
xaxis = dict(title = "Date and Time"),
yaxis = dict(title = "Values")
)
data = [Trace]
figure = go.Figure(data = data, layout = layout)
for r in df.loc[df.Alert.astype(bool),].iterrows():
figure.add_vline(x=r[1]["DateTime"], line_width=1, line_dash="solid", line_color="red")
figure

How to change the opacity of chosen scatter plot points

I want to create an interactive scatter plot so the user can select points with the cursor, so the chosen points are highlighted and the rest are faded.
Right now it only works if the color is changed, how can i change the opacity and keep the original colors?
import numpy as np
from numpy.random import rand
from matplotlib.widgets import LassoSelector
from matplotlib.path import Path
import matplotlib.pyplot as plt
class SelectFromCollection(object):
def __init__(self, ax, collection,c, alpha_other=0.3):
self.canvas = ax.figure.canvas
self.collection = collection
self.alpha_other = alpha_other
self.xys = collection.get_offsets()
self.Npts = len(self.xys)
self.c = c
# Ensure that we have separate colors for each object
self.fc = collection.get_facecolors()
if len(self.fc) == 0:
raise ValueError('Collection must have a facecolor')
elif len(self.fc) == 1:
self.fc = np.tile(self.fc, (self.Npts, 1))
self.lasso = LassoSelector(ax, onselect=self.onselect)
self.ind = []
def onselect(self, verts):
path = Path(verts)
self.ind = np.nonzero(path.contains_points(self.xys))[0]
self.fc[:, -1] = self.alpha_other
self.fc[self.ind, -1] = 1
self.collection.set_facecolors(self.fc)
self.canvas.draw_idle()
def disconnect(self):
self.lasso.disconnect_events()
self.fc[:, -1] = 1
self.collection.set_facecolors(self.fc)
self.canvas.draw_idle()
np.random.seed(1)
x, y, c = rand(3, 100)
subplot_kw = dict(xlim=(0, 1), ylim=(0, 1), autoscale_on=False)
fig, ax = plt.subplots(subplot_kw=subplot_kw)
pts = ax.scatter(x, y,c=c, s=100)
selector = SelectFromCollection(ax, pts, c)
plt.show()
Solved, I used the method self.collection.get_facecolors(), to get the format and values, then I just changed the value of the 3rd column for the chosen indices like this:
fc = self.collection.get_facecolors()
fc[self.ind, 3] = 1
fc[others, 3] = self.alpha_other
self.collection.set_facecolors(fc)
cheers

AttributeError: 'list' object has no attribute 'get_zorder'

I'm trying to animate projectile motion with the help of matplotlib.animation but I've been facing a few errors. Please help me with this.
Thank you so much
I've tried searching through the internet and I did implement solutions of a few similar problems but the code still gives an error
import matplotlib as mat
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.animation as mat_anim
u = 5
g = 9.8
theta_degree = np.rad2deg([0, np.pi/6, np.pi/4, np.pi/3, np.pi/2])
theta_rad = [0, np.pi/6, np.pi/4, np.pi/3, np.pi/2]
fr = 100
print(1)
def projectile_range():
# calculate projectile range
rng = ((u**2)*(np.sin(np.multiply(2.0, theta_rad))))/g
return rng
def max_height():
# calculate maximum height of projectile
max_ht = ((u*np.sin(theta_rad))**2)/(2*g)
return max_ht
def projectile():
# calculating projectile path
r = projectile_range()
for j in range(len(r)):
x = np.linspace(0, r[j], 100)
y.append(x*(np.tan(theta_rad[j])) - ((0.5*g*(x**2))/(u*np.cos(theta_rad[j]))**2))
return y
fig1, ax1 = plt.subplots(1,1)
fig1.suptitle("Projectile Motion Range", fontsize = 10)
ax1.set_xlim([0, round(max(projectile_range()))+1])
ax1.set_ylim([0, round(max(max_height()))+1])
# ax_range, = ax1.plot([], [])
dots, = ax1.plot([], [], 'o')
lines, = ax1.plot([], [], lw = 2)
plot_colour = ["black", "red", "green", "yellow", "blue"]
line_list = []
dot_list = []
print(2)
for index in range(len(theta_rad)):
line_obj = ax1.plot([], [], lw = 2, color = plot_colour[index])[0]
dot_obj = ax1.plot([], [], 'o', color = plot_colour[len(theta_rad)-index-1])[0]
line_list.append(line_obj)
dot_list.append(dot_obj)
print(3)
def initialize():
# initializing projectile range plot
print(4)
for line in line_list:
line.set_data([], [])
for dot in dot_list:
dot.set_data([], [])
print(5)
return dot_list, line_list,
print(6)
def proj_animation(i):
# animation function
print(7)
n = 100
# fr = n
y = np.empty([len(theta_rad), n], dtype = float)
x = np.empty([len(theta_rad), n], dtype = float)
r = projectile_range()
for j in range(len(r)):
x[j] = np.linspace(0, r[j], n)
y[j] = np.multiply(x[j], np.tan(theta_rad[j])) - ((0.5*g*(np.square(x[j])))/(u*np.cos(theta_rad[j]))**2)
for count, element in enumerate(line_list):
element.set_data(x[count][:i], y[count][:i])
for count, element in enumerate(dot_list):
element.set_data(x[count][i], y[count][i])
print(8)
return dot_list,line_list,
proj_anim = mat_anim.FuncAnimation(fig1, proj_animation, frames = fr,
interval = 20, blit = True)
proj_anim.save("projectile_range.mp4", fps = 20, extra_args = ['-vcodec', 'libx264'])
plt.show()
key=lambda x: x.get_zorder())
AttributeError: 'list' object has no attribute 'get_zorder'
I believe the issue is that in proj_animation() you are returning a tuple of two lists, but FuncAnimation() is looking for an iterable of drawn objects directly. The quickest fix for this is to concatenate dot_list with line_list and return the concatenated list. Nb This should also be done in your initialization function.
I was trying to plot sensor data using subplots and was getting the same error. The way I fixed it was to return just a variable or a list. In the animation function I was returning a list of lists, I just flattened this list of lists and the code works. The solution adapted to your code is the following:
import matplotlib as mat
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.animation as mat_anim
u = 5
g = 9.8
theta_degree = np.rad2deg([0, np.pi/6, np.pi/4, np.pi/3, np.pi/2])
theta_rad = [0, np.pi/6, np.pi/4, np.pi/3, np.pi/2]
fr = 100
print(1)
def projectile_range():
# calculate projectile range
rng = ((u**2)*(np.sin(np.multiply(2.0, theta_rad))))/g
return rng
def max_height():
# calculate maximum height of projectile
max_ht = ((u*np.sin(theta_rad))**2)/(2*g)
return max_ht
def projectile():
# calculating projectile path
r = projectile_range()
for j in range(len(r)):
x = np.linspace(0, r[j], 100)
y.append(x*(np.tan(theta_rad[j])) - ((0.5*g*(x**2))/(u*np.cos(theta_rad[j]))**2))
return y
fig1, ax1 = plt.subplots(1,1)
fig1.suptitle("Projectile Motion Range", fontsize = 10)
ax1.set_xlim([0, round(max(projectile_range()))+1])
ax1.set_ylim([0, round(max(max_height()))+1])
# ax_range, = ax1.plot([], [])
dots, = ax1.plot([], [], 'o')
lines, = ax1.plot([], [], lw = 2)
plot_colour = ["black", "red", "green", "yellow", "blue"]
line_list = []
dot_list = []
print(2)
for index in range(len(theta_rad)):
line_obj = ax1.plot([], [], lw = 2, color = plot_colour[index])[0]
dot_obj = ax1.plot([], [], 'o', color = plot_colour[len(theta_rad)-index-1])[0]
line_list.append(line_obj)
dot_list.append(dot_obj)
print(3)
def initialize():
# initializing projectile range plot
print(4)
for line in line_list:
line.set_data([], [])
for dot in dot_list:
dot.set_data([], [])
print(5)
return dot_list, line_list,
print(6)
def proj_animation(i):
# animation function
print(7)
n = 100
# fr = n
y = np.empty([len(theta_rad), n], dtype = float)
x = np.empty([len(theta_rad), n], dtype = float)
r = projectile_range()
graph_list = []
for j in range(len(r)):
x[j] = np.linspace(0, r[j], n)
y[j] = np.multiply(x[j], np.tan(theta_rad[j])) - ((0.5*g*(np.square(x[j])))/(u*np.cos(theta_rad[j]))**2)
for count, element in enumerate(line_list):
element.set_data(x[count][:i], y[count][:i])
for count, element in enumerate(dot_list):
element.set_data(x[count][i], y[count][i])
graph_list.append(dot_list)
graph_list.append(line_list)
graph_list = [item for sublist in graph_list for item in sublist]
print(8)
return graph_list
proj_anim = mat_anim.FuncAnimation(fig1, proj_animation, frames = fr,
interval = 20, blit = True)
proj_anim.save("projectile_range.mp4", fps = 20, extra_args = ['-vcodec', 'libx264'])
plt.show()
I test the code and it works.

Scaling a PDF to show 100% at peak

I'm displaying a histogram of my data, with an overlaid PDF. My plots all look something like this:
and I'm trying to scale the red curve to show 100% at the peak.
My following toy code is identical to what I'm actually using, apart from the lines in between the two %:
%
import pandas as pd
import matplotlib.pyplot as plt
import scipy.stats as stats
import numpy as np
my_randoms = np.random.normal(0.5, 1, 50000)
dictOne = {"delta z":my_randoms}
df = pd.DataFrame(dictOne)
df = df[df['delta z'] > -999]
%
fig, ax = plt.subplots()
h, edges, _ = ax.hist(df['delta z'], alpha = 1, density = False, bins = 100)
param = stats.norm.fit(df['delta z'].dropna()) # Fit a normal distribution to the data
pdf_fitted = stats.norm.pdf(df['delta z'], *param)
x = np.linspace(*df['delta z'].agg([min, max]), 100) # x-values
binwidth = np.diff(edges).mean()
ax.plot(x, stats.norm.pdf(x, *param)*h.sum()*binwidth, color = 'r')
# Decorations
graph_title = 'U-B'
plt.grid(which = 'both')
plt.title(r'$\Delta z$ distribution for %s'%graph_title, fontsize = 25)
plt.xlabel(r'$\Delta z = z_{spec} - z_{photo}$', fontsize = 25)
plt.ylabel('Number', fontsize = 25)
plt.xticks(fontsize = 25)
plt.yticks(fontsize = 25)
xmin, xmax = min(df['delta z']), max(df['delta z'])
plt.xlim(xmin, xmax)
plt.annotate(
r'''$\mu_{\Delta z}$ = %.3f
$\sigma_{\Delta z}$ = %.3f'''%(param[0], param[1]),
fontsize = 25, color = 'r', xy=(0.85, 0.85), xycoords='axes fraction')
How would I define another axes object from 0 to 100 on the right-hand side and map the PDF to that?
Or is there a better way to do it?
This is kind of a follow-up to my previous question.
You can use density=True in plotting the histogram.
You use .twinx():
fig = plt.figure(figsize=(10, 8), dpi=72.0)
n_rows = 2
n_cols = 2
ax1 = fig.add_subplot(n_rows, n_cols, 1)
ax2 = fig.add_subplot(n_rows, n_cols, 2)
ax3 = ax1.twinx()
https://matplotlib.org/gallery/api/two_scales.html

Resources