Adding shapes in plotly - digital signals plotting - python

I am trying to plot digital signals with a non existing format in plotly, which consists in thin lines in case value = 0, and thick lines in case value = 1. For doing this, I am drawing an horizontal line and adding rectangles in case signal's value=1.
As I have to plot many signals, I am working with subplots. The problem I'm having, is that shapes are only added in first subplot. I would like to know how can I add shapes to any of subplots.
import numpy as np
from plotly.subplots import make_subplots
import plotly.graph_objects as go
#Creating digital signals in array
y=np.zeros((2,40))
x=np.arange(0,4,.1)
y[0,:]=np.sign(np.cos(x*np.pi))
y[1,:]=np.sign(np.cos(x*1.5*np.pi))
y[y==-1]=0
dig_signals = make_subplots(rows=2,cols=1,subplot_titles=["signal 1", "signal 2"]
,shared_xaxes=True,x_title="time [sec]",vertical_spacing=.2)
for k in range(2):
tiempo_flancos=[] #to save the amount of state changes
if y[k,0]==1:
tiempo_flancos.append(x[0])
for i in range(1,len(x)):
if y[k,i]!=y[k,i-1]:
tiempo_flancos.append(x[i])
if y[k,-1]==1:
tiempo_flancos.append(x[-1])
dictionaries=[] #this list is needed to create shapes in plotly
for i in range(int(len(tiempo_flancos)/2)):
dictionaries.append(dict(x0=tiempo_flancos[i*2],y0=.75,
x1=tiempo_flancos[1+i*2],y1=-.75,
line_width=0,fillcolor="steelblue"))
dig_signals.add_trace(go.Scatter(x=x,y=np.repeat(0,len(x))),row=k+1,col=1)
dig_signals.update_layout(yaxis=dict(range[-3,3]),showlegend=False,shapes=dictionaries)
dig_signals.update_traces(line_color="steelblue", line_width=2.5)
dig_signals.update_yaxes(visible=False)
dig_signals

Only a couple of changes to your code: move dictionaries outside the for loop and specify yref
dictionaries=[]
for k in range(2):
tiempo_flancos=[] #to save the amount of state changes
if y[k,0]==1:
tiempo_flancos.append(x[0])
for i in range(1,len(x)):
if y[k,i]!=y[k,i-1]:
tiempo_flancos.append(x[i])
if y[k,-1]==1:
tiempo_flancos.append(x[-1])
for i in range(int(len(tiempo_flancos)/2)):
dictionaries.append(dict(x0=tiempo_flancos[i*2],y0=.75,
x1=tiempo_flancos[1+i*2],y1=-.75,
line_width=0,fillcolor="steelblue",
yref='y'+str(k+1)))
dig_signals.add_trace(go.Scatter(x=x,y=np.repeat(0,len(x))),row=k+1,col=1)
dig_signals.update_layout(yaxis=dict(range=[-3,3]),showlegend=False,shapes=dictionaries)
dig_signals.update_traces(line_color="steelblue", line_width=2.5)
dig_signals.update_yaxes(visible=False)

Related

How to iterate distance calculation for different vehicles from coordinates

I am new to coding and need help developing a Time Space Diagram (TSD) from a CSV file which I got from a VISSIM simulation as a result.
A general TSD looks like this: TSD and I have a CSV which looks like this:
CSV.
I want to take "VEHICLE:SIMSEC" which represent the simulation time which I want it represented as the X axis on TSD, "NO" which represent the vehicle number (there are 185 different vehicles and I want to plot all 185 of them on the plot) as each of the line represented on TSD, "COORDFRONTX" which is the x coordinate of the simulation, and "COORDFRONTY" which is the y coordinate of the simulation as positions which would be the y axis on TSD.
I have tried the following code but did not get the result I want.
import pandas as pd
import matplotlib.pyplot as mp
# take data
data = pd.read_csv(r"C:\Users\hk385\Desktop\VISSIM_DATA_CSV.csv")
df = pd.DataFrame(data, columns=["VEHICLE:SIMSEC", "NO", "DISTTRAVTOT"])
# plot the dataframe
df.plot(x="NO", y=["DISTTRAVTOT"], kind="scatter")
# print bar graph
mp.show()
The plot came out to be uninterpretable as there were too many dots. The diagram looks like this: Time Space Diagram. So would you be able to help me or guide me to get a TSD from the CSV I have?
Suggestion made by mitoRibo,
The top 20 rows of the csv is the following:
VEHICLE:SIMSEC,NO,LANE\LINK\NO,LANE\INDEX,POS,POSLAT,COORDFRONTX,COORDFRONTY,COORDREARX,COORDREARY,DISTTRAVTOT
5.9,1,1,1,2.51,0.5,-1.259,-3.518,-4.85,-1.319,8.42
6.0,1,1,1,10.94,0.5,0.932,-4.86,-2.659,-2.661,16.86
6.1,1,1,1,19.37,0.5,3.125,-6.203,-0.466,-4.004,25.29
6.2,1,1,1,27.82,0.5,5.319,-7.547,1.728,-5.348,33.73
6.3,1,1,1,36.26,0.5,7.515,-8.892,3.924,-6.693,42.18
6.4,1,1,1,44.72,0.5,9.713,-10.238,6.122,-8.039,50.64
6.5,1,1,1,53.18,0.5,11.912,-11.585,8.321,-9.386,59.1
6.6,1,1,1,61.65,0.5,14.112,-12.933,10.521,-10.734,67.56
6.7,1,1,1,70.12,0.5,16.314,-14.282,12.724,-12.082,76.04
6.8,1,1,1,78.6,0.5,18.518,-15.632,14.927,-13.432,84.51
6.9,1,1,1,87.08,0.5,20.723,-16.982,17.132,-14.783,93.0
7.0,1,1,1,95.57,0.5,22.93,-18.334,19.339,-16.135,101.49
7.1,1,1,1,104.07,0.5,25.138,-19.687,21.547,-17.487,109.99
7.2,1,1,1,112.57,0.5,27.348,-21.04,23.757,-18.841,118.49
7.3,1,1,1,121.08,0.5,29.56,-22.395,25.969,-20.195,127.0
7.4,1,1,1,129.59,0.5,31.773,-23.75,28.182,-21.551,135.51
7.5,1,1,1,138.11,0.5,33.987,-25.107,30.396,-22.907,144.03
7.6,1,1,1,146.64,0.5,36.203,-26.464,32.612,-24.264,152.56
7.7,1,1,1,155.17,0.5,38.421,-27.822,34.83,-25.623,161.09
Thank you.
You can groupby and iterate through different vehicles, adding each one to your plot. I changed your example data so there were 2 different vehicles.
import pandas as pd
import io
import matplotlib.pyplot as plt
df = pd.read_csv(io.StringIO("""
VEHICLE:SIMSEC,NO,LANE_LINK_NO,LANE_INDEX,POS,POSLAT,COORDFRONTX,COORDFRONTY,COORDREARX,COORDREARY,DISTTRAVTOT
5.9,1,1,1,2.51,0.5,-1.259,-3.518,-4.85,-1.319,0
6.0,1,1,1,10.94,0.5,0.932,-4.86,-2.659,-2.661,16.86
6.1,1,1,1,19.37,0.5,3.125,-6.203,-0.466,-4.004,25.29
6.2,1,1,1,27.82,0.5,5.319,-7.547,1.728,-5.348,33.73
6.3,1,1,1,36.26,0.5,7.515,-8.892,3.924,-6.693,42.18
6.4,1,1,1,44.72,0.5,9.713,-10.238,6.122,-8.039,50.64
6.5,1,1,1,53.18,0.5,11.912,-11.585,8.321,-9.386,59.1
6.6,1,1,1,61.65,0.5,14.112,-12.933,10.521,-10.734,67.56
6.7,1,1,1,70.12,0.5,16.314,-14.282,12.724,-12.082,76.04
6.8,1,1,1,78.6,0.5,18.518,-15.632,14.927,-13.432,84.51
6.9,1,1,1,87.08,0.5,20.723,-16.982,17.132,-14.783,90
6.0,2,1,1,95.57,0.5,22.93,-18.334,19.339,-16.135,0
6.1,2,1,1,104.07,0.5,25.138,-19.687,21.547,-17.487,30
6.2,2,1,1,112.57,0.5,27.348,-21.04,23.757,-18.841,40
6.3,2,1,1,121.08,0.5,29.56,-22.395,25.969,-20.195,50
6.4,2,1,1,129.59,0.5,31.773,-23.75,28.182,-21.551,60
6.5,2,1,1,138.11,0.5,33.987,-25.107,30.396,-22.907,70
6.6,2,1,1,146.64,0.5,36.203,-26.464,32.612,-24.264,80
6.7,2,1,1,155.17,0.5,38.421,-27.822,34.83,-25.623,90
"""),sep=',')
fig = plt.figure()
#Iterate through each vehicle, adding it to the plot
for vehicle_no,vehicle_df in df.groupby('NO'):
plt.plot(vehicle_df['VEHICLE:SIMSEC'],vehicle_df['DISTTRAVTOT'], label=vehicle_no)
plt.legend() #comment this out if you don't want a legned
plt.show()
plt.close()
If you don't mind could you please try this.
mp.scatter(x="NO", y=["DISTTRAVTOT"])
If still not work please attach your data for me to test from my side.

Why does my code add an extra frame in front of my animation?

I've been coding a Python program that will take a list from a different program, take specific values from that list, and add them to a 2D list. This subsequently creates an animation, with one frame per sub-list within the 2D list. However, when it's animated (using Celluloid), an extra frame is added in front of it that displays a graph of every sub-list at once, which disrupts the animation.
The code I'm using is this:
#Imports the relevant parts of the external modules
from matplotlib import pyplot as plt
from celluloid import Camera
from main import projectileInfo, tickRate
displacements = [] #A 2D list of all displacements
for i in projectileInfo:
displacements.append([i[1], i[0]])
print(displacements)
fig = plt.figure()
camera = Camera(fig)
for j in displacements:
x = [j[0]]
y = [j[1]]
plt.plot(x,y, color = '000000', marker = '.') #Plots the data as black points
camera.snap()
ani = camera.animate(interval = 1000*tickRate, repeat = False)
plt.show()
The issue doesn't come up if I specify values for the animation within the code itself (e.g. displacements = [[1,1], [2,2], [3,3]], but it does if projectileInfo is specified within the program.
For reference, examples for projectileInfo and tickRate are provided:
projectileInfo = [[0, 0, 2.944881550342992, 0.5724269861296344, -1.0092420948384448, -0.03813290516155552, -12.052760210752101, -0.08473978924790115], [0.2944881550342992, 0.05724269861296344, 1.739605529267782, 0.5639530072048443, -0.35217721337929575, -0.03701225346578069, -10.592616029731769, -0.0822494521461793], [0.4684487079610774, 0.11363799933344787, 0.6803439262946049, 0.5557280619902264, -0.05386624698009846, -0.03594051938005718, -9.929702771066887, -0.0798678208445715], [0.5364831005905379, 0.1692108055324705, -0.3126263508120839, 0.5477412799057693, 0.011373937998969578, -0.0349148868178283, -9.784724582224511,
-0.07758863737295177], [0.5052204655093295, 0.22398493352304744, -1.291098809034535, 0.5399824161684741, 0.19398969267459468, -0.03393274001211678, -9.378911794056458, -0.07540608891581507], [0.376110584605876, 0.27798317513989484, -2.2289899884401807, 0.5324418072768926, 0.5781971273919331, -0.03299164661811001, -8.525117494684594, -0.07331477026246667], [0.1532115857618579, 0.3312273558675841, -3.0815017379086402, 0.5251103302506459, 1.1050566133054158, -0.0320893424586703, -7.354318637099077, -0.07130964990815623], [-0.15493858802900617, 0.3837383888926487, -3.816933601618548, 0.5179793652598302, 1.6954652941177968, -0.031223717732420407, -6.042299346404897, -0.06938603940537869], [-0.536631948190861, 0.43553632541863174, -4.421163536259038, 0.5110407613192923, 2.2747457012945764, -0.030392804526055698, -4.75500955267872, -0.0675395656134571], [-0.9787483018167649, 0.486640401550561, -4.89666449152691, 0.5042868047579466, 2.7903609807178054, -0.029594765491590475, -3.6091978206270996, -0.06576614553686772], [-1.4684147509694558, 0.5370690820263556, -5.25758427358962, 0.4977101902042599,
3.216860139839751, -0.02882788356578406, -2.6614219114672206, -0.06406196347952013], [-1.9941731783284178, 0.5868401010467816, -5.523726464736342, 0.49130399385630785, 3.5507821034099836, -0.028090552623374627, -1.9193731035333705, -0.062423450274165834], [-2.546545824802052, 0.6359705004324124, -5.715663775089679, 0.48506164882889125, 3.801833041871401, -0.027381268968280633, -1.3614821291746655, -0.06084726437395696], [-3.11811220231102, 0.6844766653153016, -5.851811988007145, 0.47897692239149553, 3.985110999814779, -0.026698623577869795, -0.9541977781893805, -0.05933027461748843]]
tickRate = 0.05
I haven't managed to reproduce the problem in any test program, not even within the same virtual environment as the original code.

Python Array Copying

I'm trying to figure out how to copy an array output into a new array for multiple iterations. The scenario is to run a function in a for loop with varying inputs then overlay the results on a single plot for comparison. Currently I have it running where I get three arrays from the for loop, but this results in three independent plots.
My coding is not very solid so some guidance would be appreciated. I was reading up on the list copy function but have not been able to get it to do what I want.
for z,wn in mylist:
G1 = y_numeric(z,wn)
#np.array(output[i,:])=G1.copy()
#plt.figure()
#plt.plot(t,G1[:])
#print(G1)
#print(output)
#user158430, Here is a simple example of a working code that might help you navigate through your code:
import matplotlib.pyplot as plt
import numpy as np
#creating empty list to append all y variables
all_y = []
#creating random variables
x,y1,y2,y3=np.arange(0,50,1),np.arange(50,100,1),np.arange(100,150,1),np.arange(150,200,1)
#appending only y variables into the created empty list
all_y.extend((y1,y2,y3))
#looping to plot on one single figure
for i in (all_y):
plt.plot(x,i)
plt.figure() #this code is kept outside the for loop if desired to print all the plots in one figure, if wanted the plots to be separated then indent it to match the plt.plot (i.e., put it in the loop)
This is what you should get:

How to cut vertices and faces connected to points lower than some value in pyvista?

So when one exports r.out.vtk from Grass GIS we get a bad surface with -99999 points instead of nulls:
I want to remove them, yet a simple clip is not enough:
pd = pv.read('./pid1.vtk')
pd = pd.clip((0,1,1), invert=False).extract_surface()
p.add_mesh(pd ) #add atoms to scene
p.show()
resulting in:
So I wonder how to keep from it only top (> -999) points and connected vertices - in order to get only the top plane (it is curved\not flat actually) using pyvista?
link to example .vtk
There is an easy way to do this and there isn't...
You could use pyvista's threshold filter with all_scalars=True as long as you have only one set of scalars:
import pyvista as pv
pd = pv.read('./pid1.vtk')
pd = pd.threshold(-999, all_scalars=True)
plotter = pv.Plotter()
plotter.add_mesh(pd) #add atoms to scene
plotter.show()
Since all_scalars starts filtering based on every scalar array, this will only do what you'd expect if there are no other scalars. Furthermore, unfortunately there seems to be a bug in pyvista (expected to be fixed in version 0.32.0) which makes the use of this keyword impossible.
What you can do in the meantime (if you don't want to use pyvista's main branch before the fix is released) is to threshold the data yourself using numpy:
import pyvista as pv
pd = pv.read('./pid1.vtk')
scalars = pd.active_scalars
keep_inds = (scalars > -999).nonzero()[0]
pd = pd.extract_points(keep_inds, adjacent_cells=False)
plotter = pv.Plotter()
plotter.add_mesh(pd) #add atoms to scene
plotter.show()
The main point of both all_scalars (in threshold) and adjacent_cells (in extract_points) is to only keep cells where every point satisfies the condition.
With both of the above I get the following figure using your data:

Create a color generator from given colormap in matplotlib

I have a series of lines that each need to be plotted with a separate colour. Each line is actually made up of several data sets (positive, negative regions etc.) and so I'd like to be able to create a generator that will feed one colour at a time across a spectrum, for example the gist_rainbow map shown here.
I have found the following works but it seems very complicated and more importantly difficult to remember,
from pylab import *
NUM_COLORS = 22
mp = cm.datad['gist_rainbow']
get_color = matplotlib.colors.LinearSegmentedColormap.from_list(mp, colors=['r', 'b'], N=NUM_COLORS)
...
# Then in a for loop
this_color = get_color(float(i)/NUM_COLORS)
Moreover, it does not cover the range of colours in the gist_rainbow map, I have to redefine a map.
Maybe a generator is not the best way to do this, if so what is the accepted way?
To index colors from a specific colormap you can use:
import pylab
NUM_COLORS = 22
cm = pylab.get_cmap('gist_rainbow')
for i in range(NUM_COLORS):
color = cm(1.*i/NUM_COLORS) # color will now be an RGBA tuple
# or if you really want a generator:
cgen = (cm(1.*i/NUM_COLORS) for i in range(NUM_COLORS))

Categories

Resources