Some context:
I was looking into the vispy module to plot in realtime (or as close as possible to) data coming from an instrument. My attempt follow.
from vispy.plot import Fig
from vispy import app,scene
from vispy.visuals import TextVisual
import numpy as np
import Queue
FONT_SIZE = 14
MIN = 0
MAX = 1.1
w_size = 100
N = 5000
M = 2500
color_map = 'cubehelix'
q_size = 1000
Nb = 5
#generate (empty) initial data to fill the plot
data = np.zeros(N*M)
data = np.reshape(data, (N,M))
#setup the plot
fig = Fig(show = False,size = (16*w_size,9*w_size),bgcolor='black')
fig.title = 'my plot'
main_plot = fig[0,0].image(data = data,fg_color='w',cmap=color_map,clim=(MIN,MAX))
fig[0,0].view.camera.aspect = N/float(M) * 16./9.
title = scene.Label("someoutput", font_size=FONT_SIZE, color = 'w')
fig[0,0].grid.add_widget(title, row=0, col=4)
fig[0,0].grid[2,4].border_color = 'black'
fig[0,0].grid[2,4].bgcolor = 'black'
xlabel_title = scene.Label("x_axis [unit]", font_size=FONT_SIZE, color = 'w')
fig[0,0].grid.add_widget(xlabel_title, row=4, col=4)
ylabel_title = scene.Label("y_axis [unit]", font_size=FONT_SIZE,rotation=-90, color='w')
fig[0,0].grid.add_widget(ylabel_title, row=2, col=2)
scale = scene.ColorBarWidget(orientation='left',
cmap=color_map,
label='Some value',
clim=(MIN,MAX),
border_color = 'w',
border_width = 1,
label_color = 'w'
)
fig[0,0].grid.add_widget(scale, row=2, col=6)
fig[0,0].cbar_right.width_max = \
fig[0,0].cbar_right.width_min = 50
#fill a queue so to excude the generation time from the plotting time
q = Queue.Queue()
for i in range(q_size):
new_data = (np.abs(0.5*np.random.randn(Nb*M)[:])).astype('float32')
new_data = np.reshape(new_data, (Nb,M))
q.put(new_data[:])
#update function
def update(ev):
global main_plot, q, data, Nb,M,fig,index
#acquire
new_data = q.get()
#roll the plot data
data[Nb:, :] = data[:-Nb, :]
data[:Nb,:] = new_data
#recycle the new data
q.put(new_data)
#update the plot
main_plot.set_data(data)
main_plot.update()
# setup timer
interv = 0.01
timer = app.Timer(interval = interv)
timer.connect(update)
timer.start(interval = interv)
if __name__ == '__main__':
fig.show(run=True)
app.run()
This code currently works but it's much slower than the data rate. In the vispy gallery, as well as in some examples, I saw much more points being plotted and updated. I think that the main problem is that I completely set each time all the data of the plot instead of shifting them and inserting new points.
I also had a look at this example:
https://github.com/vispy/vispy/blob/master/examples/demo/scene/oscilloscope.py
However I don't know how to generalize the update function that rolls the data (I have no knowledge of OpenGL) and I cannot use the example as is because I need a quantitative color scale (that seems well implemented in vispy.plot).
The question:
Is there a way to write a function that rolls the data of a plot generated with the vispy.plot class?
Thanks.
Related
I used this code. What it does is just takes a pointcloud and convert it into polydata and visualize it. After visualizing the pointcloud, I use mouse to select one point and calculate points around that particular point in a given radius. I am able to calculate those points but not able to visualize those. Also moving further I select 1000 random points in data and calculate their clusters too, calculate Hausdorff distances of each with original cluster and visualize the minimum distance cluster. In all this I am not able to visualize any cluster.`
import vtk
import numpy as np
import open3d as o3d
import math
from numpy import random
from scipy.spatial.distance import directed_hausdorff
import vtkmodules.vtkRenderingOpenGL2
from vtkmodules.vtkCommonColor import vtkNamedColors
from vtkmodules.vtkCommonCore import vtkIdTypeArray
from vtkmodules.vtkCommonDataModel import (
vtkSelection,
vtkSelectionNode,
vtkUnstructuredGrid
)
from vtkmodules.vtkFiltersCore import vtkTriangleFilter
from vtkmodules.vtkFiltersExtraction import vtkExtractSelection
from vtkmodules.vtkFiltersSources import vtkPlaneSource
from vtkmodules.vtkInteractionStyle import vtkInteractorStyleTrackballCamera
from vtkmodules.vtkRenderingCore import (
vtkActor,
vtkCellPicker,
vtkDataSetMapper,
vtkPolyDataMapper,
vtkRenderWindow,
vtkRenderWindowInteractor,
vtkRenderer
)
class VtkPointCloud:
def __init__(self, zMin=-10.0, zMax=10.0, maxNumPoints=2e6):
# c = vtkNamedColors()
self.maxNumPoints = maxNumPoints
self.vtkPolyData = vtk.vtkPolyData()
self.clearPoints()
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputData(self.vtkPolyData)
mapper.SetColorModeToDefault()
mapper.SetScalarRange(zMin, zMax)
mapper.SetScalarVisibility(1)
self.vtkActor = vtk.vtkActor()
# self.vtkActor.GetProperty().SetColor(1,1,1)
# self.vtkActor.GetProperty().SetColor(c.GetColor3d('Yellow'))
self.vtkActor.SetMapper(mapper)
def addPoint(self, point):
if self.vtkPoints.GetNumberOfPoints() < self.maxNumPoints:
pointId = self.vtkPoints.InsertNextPoint(point[:])
self.vtkDepth.InsertNextValue(point[2])
self.vtkCells.InsertNextCell(1)
self.vtkCells.InsertCellPoint(pointId)
else:
r = random.randint(0, self.maxNumPoints)
self.vtkPoints.SetPoint(r, point[:])
self.vtkCells.Modified()
self.vtkPoints.Modified()
self.vtkDepth.Modified()
def clearPoints(self):
self.vtkPoints = vtk.vtkPoints()
self.vtkCells = vtk.vtkCellArray()
self.vtkDepth = vtk.vtkDoubleArray()
self.vtkDepth.SetName('DepthArray')
self.vtkPolyData.SetPoints(self.vtkPoints)
self.vtkPolyData.SetVerts(self.vtkCells)
self.vtkPolyData.GetPointData().SetScalars(self.vtkDepth)
self.vtkPolyData.GetPointData().SetActiveScalars('DepthArray')
# Catch mouse events
class MouseInteractorStyle(vtkInteractorStyleTrackballCamera):
def __init__(self, data):
self.AddObserver('LeftButtonPressEvent', self.left_button_press_event)
self.AddObserver('RightButtonPressEvent', self.right_button_press_event)
self.data = data
self.selected_mapper = vtkDataSetMapper()
self.selected_actor = vtkActor()
self.selected_mapper2 = vtkDataSetMapper()
self.selected_actor2 = vtkActor()
self.vtk_list = vtk.vtkIdList()
self.locator = vtk.vtkPointLocator()
self.locator.SetDataSet(self.data)
self.locator.BuildLocator()
self.colors = vtkNamedColors()
def left_button_press_event(self, obj, event):
pos = self.GetInteractor().GetEventPosition()
picker = vtkCellPicker()
picker.SetTolerance(0.001)
# Pick from this location.
picker.Pick(pos[0], pos[1], 0, self.GetDefaultRenderer())
world_position = picker.GetPickPosition()
print(f'Cell id is: {picker.GetCellId()}')
# print(world_position)
self.locator.FindPointsWithinRadius(0.02,world_position, self.vtk_list)
print(self.vtk_list)
if picker.GetCellId() != -1:
print(f'Pick position is: ({world_position[0]:.6g}, {world_position[1]:.6g}, {world_position[2]:.6g})')
ids = vtkIdTypeArray()
ids.SetNumberOfComponents(1)
ids.InsertNextValue(picker.GetCellId())
# print(ids,'\n')
selection_node = vtkSelectionNode()
selection_node.SetFieldType(vtkSelectionNode.CELL)
selection_node.SetContentType(vtkSelectionNode.INDICES)
selection_node.SetSelectionList(ids)
selection = vtkSelection()
selection.AddNode(selection_node)
extract_selection = vtkExtractSelection()
extract_selection.SetInputData(0, self.data)
extract_selection.SetInputData(1, selection)
extract_selection.Update()
# In selection
selected = vtkUnstructuredGrid()
selected.ShallowCopy(extract_selection.GetOutput())
print(f'Number of points in the selection: {selected.GetNumberOfPoints()}')
# print(f'Number of cells in the selection : {selected.GetNumberOfCells()}\n')
print('########################\n')
self.selected_mapper.SetInputData(selected)
self.selected_actor.SetMapper(self.selected_mapper)
# self.selected_actor.GetProperty().EdgeVisibilityOn()
self.selected_actor.GetProperty().SetColor(self.colors.GetColor3d('Black'))
self.selected_actor.GetProperty().SetPointSize(10)
self.selected_actor.GetProperty().SetLineWidth(3)
# print(self.selected_actor)
self.GetInteractor().GetRenderWindow().GetRenderers().GetFirstRenderer().AddActor(self.selected_actor)
# Forward events
self.OnLeftButtonDown()
def right_button_press_event(self, obj, event):
if self.vtk_list.GetNumberOfIds() == 0:
return
else:
ids2 = vtkIdTypeArray()
ids2.SetNumberOfComponents(1)
for i in range(self.vtk_list.GetNumberOfIds()):
# print(i)
ids2.InsertNextValue(i)
# print(ids2)
selection_node2 = vtkSelectionNode()
selection_node2.SetFieldType(vtkSelectionNode.CELL)
selection_node2.SetContentType(vtkSelectionNode.INDICES)
selection_node2.SetSelectionList(ids2)
selection2 = vtkSelection()
selection2.AddNode(selection_node2)
extract_selection2 = vtkExtractSelection()
extract_selection2.SetInputData(0, self.data)
extract_selection2.SetInputData(1, selection2)
extract_selection2.Update()
# # In selection
selected2 = vtkUnstructuredGrid()
selected2.ShallowCopy(extract_selection2.GetOutput())
print(f'Number of neighboring points: {selected2.GetNumberOfPoints()}')
# # print(f'Number of neighboring cells: {selected2.GetNumberOfCells()}\n')
print('########################\n')
self.selected_mapper2.SetInputData(selected2)
self.selected_actor2.SetMapper(self.selected_mapper2)
# self.selected_actor.GetProperty().EdgeVisibilityOn()
self.selected_actor2.GetProperty().SetColor(self.colors.GetColor3d("tan"))
self.selected_actor2.GetProperty().SetPointSize(10)
self.selected_actor2.GetProperty().SetLineWidth(3)
# print(self.selected_actor2)
self.GetInteractor().GetRenderWindow().GetRenderers().GetFirstRenderer().AddActor(self.selected_actor2)
print('Randomly Selecting 1000 points in the data........')
point_indices = []
cluster_points = np.zeros((self.vtk_list.GetNumberOfIds(),3))
# print(cluster_points)
print('Calculating the clusters around the centers ......')
for i in range(self.vtk_list.GetNumberOfIds()):
point_indices.append(self.vtk_list.GetId(i))
cluster_points[i]=pointCloud.vtkPolyData.GetPoint(self.vtk_list.GetId(i))
point_indices = np.asarray(point_indices)
new_points= np.delete(points,point_indices, axis=0)
random_array = np.random.randint(0,new_points.shape[0],(1000))
min_haus = 1000000000.0
for i in range(random_array.shape[0]):
new_list=vtk.vtkIdList()
new_center = new_points[random_array[i]]
# print('new center to find cluster:',new_center)
self.locator.FindPointsWithinRadius(0.02,new_center, new_list)
new_cluster_points = np.zeros((new_list.GetNumberOfIds(),3))
for x in range(new_list.GetNumberOfIds()):
new_cluster_points[x]=pointCloud.vtkPolyData.GetPoint(new_list.GetId(x))
haus = directed_hausdorff(cluster_points,new_cluster_points)[0]
if haus<min_haus:
min_haus = haus
idx = random_array[i]
min_center = new_points[random_array[i]]
# print('haus:',haus)
print('min haus:',min_haus)
print('idx of min haus:',idx)
print('center of the min haus cluster:',min_center)
min_list = vtk.vtkIdList()
self.locator.FindPointsWithinRadius(0.02,min_center, min_list)
print('Min list for min center', min_list)
# # Forward events
self.OnRightButtonDown()
# Initialize point clouds
pointCloud = VtkPointCloud()
pointCloud2 = VtkPointCloud()
# print(type(pointCloud))
# Loading Point cloud using open3d
pt_cloud = o3d.io.read_point_cloud('fused_cloud_normal.ply')
points = np.asarray(pt_cloud.points)
pt_cloud2 = o3d.io.read_point_cloud('all_projected_pts.ply')
points2 = np.asarray(pt_cloud2.points)
# Adding the points into polydata
for row in points:
pointCloud.addPoint(row)
for row in points2:
pointCloud2.addPoint(row)
# Intialize actor
c = vtkNamedColors()
actor = pointCloud.vtkActor
actor.GetProperty().SetPointSize(10)
actor.GetProperty().SetColor(c.GetColor3d('Yellow'))
# actor.GetProperty().SetColor(0,0,0)
# Renderer
renderer = vtk.vtkRenderer()
renderer.AddActor(actor)
# renderer.AddActor(pointCloud2.vtkActor)
renderer.SetBackground(.1, .1, .4)
renderer.ResetCamera()
# Render Window
renderWindow = vtk.vtkRenderWindow()
renderWindow.AddRenderer(renderer)
style = MouseInteractorStyle(pointCloud.vtkPolyData)
style.SetDefaultRenderer(renderer)
# Interactor
renderWindowInteractor = vtk.vtkRenderWindowInteractor()
renderWindowInteractor.SetRenderWindow(renderWindow)
renderWindowInteractor.SetInteractorStyle(style)
# Begin Interaction
renderWindow.Render()
renderWindowInteractor.Start()
`
I want to embed a bokeh graphic in streamlit. the interactive bokeh graph is operational with the command boker serve --show application.
But when I integrate it into streamlit, I have the graph that appears but the updates with the tabs are broken.
Is there a possibility to run everything on streamlit, without going through a bokeh server?
Here is my code
import pandas as pd
from bokeh.layouts import column, row
from bokeh.models import Select
from bokeh.palettes import Spectral5
from bokeh.plotting import curdoc, figure, show
df = pd.read_csv(r'C:\mypath\myfile.csv')
SIZES = list(range(6, 22, 3))
COLORS = Spectral5
N_SIZES = len(SIZES)
N_COLORS = len(COLORS)
columns = sorted(df.columns)
discrete = [x for x in columns if df[x].dtype == object]
continuous = [x for x in columns if x not in discrete]
def create_figure():
xs = df[x.value].values
ys = df[y.value].values
x_title = x.value.title()
y_title = y.value.title()
kw = dict()
if x.value in discrete:
kw['x_range'] = sorted(set(xs))
if y.value in discrete:
kw['y_range'] = sorted(set(ys))
kw['title'] = "%s vs %s" % (x_title, y_title)
p = figure(height=600, width=800, tools='pan,box_zoom,hover,reset', **kw)
p.xaxis.axis_label = x_title
p.yaxis.axis_label = y_title
if x.value in discrete:
p.xaxis.major_label_orientation = pd.np.pi / 4
sz = 9
if size.value != 'None':
if len(set(df[size.value])) > N_SIZES:
groups = pd.qcut(df[size.value].values, N_SIZES, duplicates='drop')
else:
groups = pd.Categorical(df[size.value])
sz = [SIZES[xx] for xx in groups.codes]
c = "#31AADE"
if color.value != 'None':
if len(set(df[color.value])) > N_COLORS:
groups = pd.qcut(df[color.value].values, N_COLORS, duplicates='drop')
else:
groups = pd.Categorical(df[color.value])
c = [COLORS[xx] for xx in groups.codes]
p.circle(x=xs, y=ys, color=c, size=sz, line_color="white", alpha=0.6, hover_color='white', hover_alpha=0.5)
return p
def update(attr, old, new):
layout.children[1] = create_figure()
x = Select(title='X-Axis', value='Distance (m)', options=columns)
x.on_change('value', update)
y = Select(title='Y-Axis', value='Jumps', options=columns)
y.on_change('value', update)
size = Select(title='Size', value='None', options=['None'] + continuous)
size.on_change('value', update)
color = Select(title='Color', value='None', options=['None'] + continuous)
color.on_change('value', update)
controls = column(x, y, color, size, width=200)
layout = row(controls, create_figure())
curdoc().add_root(layout)
curdoc().title = "AppAnalyse"
st.bokeh_chart(layout, use_container_width=True)
when I run this code on streamlit, I have the graph on streamlit but the updates do not work (see photo1)
streamlit graph ok but no update
then when I execute the command: boker serve --show application, from the console, I get the desired graph on a server, which is functional (see photo 2)
graph ok on bokeh serve
there is a possibility to integrate this graph with "st.bokeh_chart()" to get this graph in streamlit with functional updates?
Thank you very much for the help provided and excuse my English please :)
How can I merge the two functions given below to achieve something like the histogram example. Any button or drop down would do fine.
If you run the function, you get a nice Candlesticks chart with the functionality of removing non trading day gaps.
def plot_candlesticks(df, names = ('DATE','OPEN','CLOSE','LOW','HIGH'), mv:list = [200], slider:bool = False, fig_size:bool = (1400,700), plot:bool = True):
'''
Plot a candlestick on a given dataframe
args:
df: DataFrame
names: Tuple of column names showing ('DATE','OPEN','CLOSE','LOW','HIGH')
mv: Moving Averages
slider: Whether to have below zoom slider or not
fig_size: Size of Figure as (Width, Height)
plotting: Whether to plot the figure or just return the figure for firther modifications
'''
freq = 5 # 5 min candle
candle_text = f"{str(freq)} Min"
stocks = df.copy()
stocks.sort_index(ascending=False, inplace = True) # Without reverse, recent rolling mean will be either NaN or equal to the exact value
Date, Open, Close, Low, High = names
mv = [] if not mv else mv # just in case you don't want to have any moving averages
colors = sample(['black','magenta','teal','brown','violet'],len(mv))
# To remove, non-trading days, grab first and last observations from df.date and make a continuous date range from that
start = stocks['DATE'].iloc[0] - timedelta(days=1)
end = stocks['DATE'].iloc[-1] + timedelta(days=1)
dt_all = pd.date_range(start=start,end=end, freq = f'{str(freq)}min')
# check which dates from your source that also accur in the continuous date range
dt_obs = [d.strftime("%Y-%m-%d %H:%M:%S") for d in stocks['DATE']]
# isolate missing timestamps
dt_breaks = [d for d in dt_all.strftime("%Y-%m-%d %H:%M:%S").tolist() if not d in dt_obs]
rangebreaks=[dict(dvalue = freq*60*1000, values=dt_breaks)]
range_selector = dict(buttons = list([dict(step = 'all', label = 'All')]))
candle = go.Figure(data = [go.Candlestick(opacity = 0.9, x = stocks[Date], name = 'X',
open = stocks[Open], high = stocks[High], low = stocks[Low], close = stocks[Close]),])
for i in range(len(mv)):
stocks[f'{str(mv[i])}-SMA'] = stocks[Close].rolling(mv[i], min_periods = 1).mean()
candle.add_trace(go.Scatter(name=f'{str(mv[i])} MA',x=stocks[Date], y=stocks[f'{str(mv[i])}-SMA'],
line=dict(color=colors[i], width=1.7)))
candle.update_xaxes(title_text = 'Date', rangeslider_visible = slider, rangeselector = range_selector, rangebreaks=rangebreaks)
candle.update_layout(autosize = False, width = fig_size[0], height = fig_size[1],
title = {'text': f"{stocks['SYMBOL'][0]} : {str(candle_text)} Candles",'y':0.97,'x':0.5,
'xanchor': 'center','yanchor': 'top'},
margin=dict(l=30,r=30,b=30,t=30,pad=2),
paper_bgcolor="lightsteelblue")
candle.update_yaxes(title_text = 'Price in Rupees', tickprefix = u"\u20B9" ) # Rupee symbol
if plot:
candle.show()
return candle
and running the below code resamples your data.
def resample_data(self,to:str = '15min', names:tuple = ('OPEN','CLOSE','LOW','HIGH','DATE')):
'''
Resample the data from 5 Minutes to 15 or 75 Minutes
args:
data: Dataframe of Daily data
to: One of [15M, 75M]
'''
Open, Close, Low, High, Date = names
data = data.resample(to,on=Date).agg({Open:'first', High:'max', Low: 'min', Close:'last'})
return data.sort_index(ascending = False).reset_index()
Is there a functionality when I click 15M / 75M button in my chart, it shows me exactly the same data but resampled? Just like there is functionality in online trading softwares.
no sample data so I have used https://plotly.com/python/candlestick-charts/ sample
at core use https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.resample.html and change trace contents with resampled data
plus using https://ipywidgets.readthedocs.io/en/latest/examples/Widget%20Events.html for events from widgets
import pandas as pd
import numpy as np
import plotly.graph_objects as go
import ipywidgets as widgets
df = pd.read_csv(
"https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv",
parse_dates=["Date"],
)
fig = go.FigureWidget(
data=[
go.Candlestick(
x=df["Date"],
open=df["AAPL.Open"],
high=df["AAPL.High"],
low=df["AAPL.Low"],
close=df["AAPL.Close"],
)
]
).update_layout(margin={"t": 30, "b": 0, "l": 0, "r": 0})
out = widgets.Output(layout={"border": "1px solid black"})
out.append_stdout("Output appended with append_stdout\n")
reset = widgets.Button(description="Reset")
slider = widgets.IntSlider(
value=1,
min=1,
max=10,
step=1,
description='Days:',
disabled=False,
continuous_update=False,
orientation='horizontal',
readout=True,
readout_format='d'
)
#out.capture()
def on_slider_change(v):
print(f"slider: {v['new']}")
dfr = df.resample(f"{v['new']}B", on="Date").mean().reset_index()
t = fig.data[0]
t.update(
x=dfr["Date"],
open=dfr["AAPL.Open"],
high=dfr["AAPL.High"],
low=dfr["AAPL.Low"],
close=dfr["AAPL.Close"],
)
#out.capture()
def on_reset_clicked(b):
print("reset")
t = fig.data[0]
t.update(
x=df["Date"],
open=df["AAPL.Open"],
high=df["AAPL.High"],
low=df["AAPL.Low"],
close=df["AAPL.Close"],
)
out.clear_output()
reset.on_click(on_reset_clicked)
slider.observe(on_slider_change, names='value')
widgets.VBox([widgets.HBox([reset, slider]), widgets.VBox([fig, out])])
I need to modify the following code to print bar graph of the cluster populations. Briefly it stores all values in numpy arrays and than print the bar histogram (indicating number of conformations in each clusters on Y, and some inherent value of the cluster (energy) on X) using Tkinter module, which seems to be not very practical solution..
r = Tkinter.Tk()
dataList = []
reverseList = []
rLctr = 0
confL = d.ch.conformations
e = d.clusterer.energy_used
#for l in mol.cluSEQ:
for l in d.clusterer.clustering_dict[cut_off]:
dataList.append([l[0].energy, len(l)])
reverseList.append(range(rLctr, rLctr+len(l)))
mol.elist = numpy.array(elist)
mol.r = [numpy.minimum.reduce(mol.elist),
numpy.maximum.reduce(mol.elist)]
mol.nbins = Tkinter.IntVar()
mol.nbins.set(10)
mol.min = Tkinter.StringVar()
mol.min.set(str(mol.r[0]))
mol.max = Tkinter.StringVar()
mol.max.set(str(mol.r[1]))
r = (float(mol.min.get()), float(mol.max.get()))
mol.ehist = HistogramRI(mol.elist,mol.nbins.get(),range=r)
mol.ehist.createReverseIndex()
nodeList = mol.ehist.array
tstr = mol.name + ' histogram'
top = Tkinter.Toplevel()
top.title(tstr)
mol.ehist
#top = Tkinter.Toplevel()
xlabel = 'ENERGY'+ 'clusterized with ' + str(cut_off) + 'A'
mol.clustNB = InteractiveHistogramGraph(mol.name,
master=top, nodeList = dataList, reverseIndex=reverseList,
xlabel_text=xlabel,
ylabel_text='#\nC\nO\nN\nF\nO\nR\nM\nA\nT\nI\nO\nN\nS')
mol.clustNB.draw.update()
mol.clustNB.draw.postscript({'file':outputfilename, 'colormode':'color'})
top.update_idletasks()
Could you suggest me a simple way to convert it to the matplot lib in order that I could control all printing options?
I am trying to plot graphs using matplotlib when clicked on a button called "generate graph" in a QT window. At first, I found a problem : I cannot close plots or control it when the QT window is opened. But I found this solution :
Cannot move Matplotlib plot window and exit it using red X button
and I test it on an empty plot and it works. However, when I put my code I get this error :
QWidget: Must construct a QApplication before a QPaintDevice
In my qt window I put :
Process = subprocess.Popen(['python', 'mygraph.py'], shell=True).communicate()
in my script mygraph.py :
def main():
print("Beginning plot for section 2.1 ...")
#Get the selected iteration and sector
iter = InterfaceVariationTRANUS("config").DropDownListDisplayIter2_1.currentIndex()
sector = InterfaceVariationTRANUS("config").DropDownListDisplaySector2_1.currentIndex()
#Access the corresponding IMPLOC file and extract the data for the selected sector
nameDirectory = InterfaceVariationTRANUS("config").nameDirectory2_1 + str(iter)
pathToDirectory = os.path.join(InterfaceVariationTRANUS("config").pathOutputDirectoryInstance, nameDirectory)
filepath = os.path.join(pathToDirectory, "IMPLOC_J.MTX")
matrix = pd.read_csv(filepath)
matrix.columns = ["Scen", "Sector", "Zone", "TotProd", "TotDem", "ProdCost", "Price", "MinRes", "MaxRes", "Adjust"]
#Removal of the noise (production equal to zero => adjust equal to zero)
#matrix.Adjust[matrix.TotProd == 0] = 0
row_index = matrix.TotProd == 0
matrix.loc[row_index,'Adjust'] = 0
#matrix.Adjust[matrix.Price == 0] = 0
row_index = matrix.Price == 0
matrix.loc[row_index,'Adjust'] =0
#matrix.Price[matrix.Price == 0] = None
row_index = matrix.Price == 0
matrix.loc[row_index,'Price'] = None
matrix2 = matrix[["Sector","Zone", "Price", "Adjust"]]
#Isolation of the data for the sector selected
nameSector = str(InterfaceVariationTRANUS("config").stockParam.list_sectors[sector])+" "+(InterfaceVariationTRANUS().stockParam.list_names_sectors[sector])
matrix3 = matrix2[matrix2["Sector"].str.contains(nameSector) == True]
matrix4 = matrix3[matrix3["Zone"].str.contains("ext_") == False]
#This boolean is used to allow for multiple graphes to be shown on the same panel.
firstPlot = False
#Plot graph and display it
if(InterfaceVariationTRANUS("config").DropDownListDisplaySector2_1.currentIndex() != InterfaceVariationTRANUS("config").currentSectorPlot2_1):
InterfaceVariationTRANUS("config").numFiguresPlot2_1 = InterfaceVariationTRANUS("config").numFiguresPlot2_1 + 1
InterfaceVariationTRANUS("config").currentSectorPlot2_1 = InterfaceVariationTRANUS("config").DropDownListDisplaySector2_1.currentIndex()
firstPlot = True
fig = plt.figure(self.numFiguresPlot2_1)
fig.canvas.set_window_title(InterfaceVariationTRANUS("config").DropDownListDisplaySector2_1.currentText())
x = np.arange(0, InterfaceVariationTRANUS("config").stockParam.nTotZones, 1)
y = pd.to_numeric(matrix4["Price"])
print("Moyenne = ")
print(y.mean(0))
z = pd.to_numeric(matrix4["Adjust"]*y)/100 + y
# plot data
if(firstPlot):
price = plt.plot(x, y, label = ("Price"))
shadowPrice = plt.plot(x, z, label = ("Price + adjust for iteration "+InterfaceVariationTRANUS("config").DropDownListDisplayIter2_1.currentText()))
plt.legend()
plt.show(block=False) #method 3
plt.draw()
if name == 'main':
main()
Where InterfaceVariationTRANUS is the class of my QT window.
Finally, I found a solution that works correctly for my problem :
import matplotlib.pyplot as plt
plt.switch_backend('Qt4Agg')
...
plt.legend()
plt.draw()
plt.show(block=False)