I'm trying to build a simple Mayavi script application which utilises the mlab iso_surface module.
However, when I run my app it throws up two windows, one showing my mayavi iso_surface plot and the other showing a blank "Edit properties" window. It seems that the mayavi scene is not being displayed in the specified view layout for the "Edit properties" window.
So my question is: Why is the mayavi iso_surface scene not appearing in the view layout, and how do I get it in there?
A simple test script which displays this behaviour is pasted below. I am using Canopy version: 2.1.1.3504 (64 bit), python 3.5.2 on a Windows 10 system.
[Note: I have modified my original question to include another question. How do I update the 's' data with the input from a Range object (mult_s)? I have had a go at doing this below, but with no success. It throws up: TraitError: Cannot set the undefined 's' attribute of a 'ArraySource' object.]
class Isoplot1(HasTraits):
scene = Instance(MlabSceneModel, ())
mult_s = Range(1, 5, 1)
#on_trait_change('scene.activated')
def _setup(self):
# Create x, y, z, s data
L = 10.
x, y, z = np.mgrid[-L:L:101j, -L:L:101j, -L:L:101j]
self.s0 = np.sqrt(4 * x ** 2 + 2 * y ** 2 + z ** 2)
# create the data pipeline
self.src1 = mlab.pipeline.scalar_field(x, y, z, self.s0)
# Create the plot
self.plot1 = self.scene.mlab.pipeline.iso_surface(
self.src1, contours=[5, ], opacity=0.5, color=(1, 1, 0)
)
#on_trait_change('mult_s')
def change_s(self):
self.src1.set(s=self.s0 * self.mult_s)
# Set the layout
view = View(Item('scene',
editor=SceneEditor(scene_class=MayaviScene),
height=400, width=600, show_label=False),
HGroup('mult_s',),
resizable=True
)
isoplot1 = Isoplot1()
isoplot1.configure_traits()
If you use self.scene.mlab.pipeline.scalar_field instead of mlab.pipeline.scalar_field this should not happen.
In general, you should avoid creating any visualization in the initializer. Instead you should always setup the scene when the scene.activated event is fired. To be safe for uses with raw mlab you should rewrite your code as follows.
from mayavi import mlab
from traits.api import HasTraits, Instance, on_trait_change
from traitsui.api import View, Item
from mayavi.core.ui.api import MayaviScene, SceneEditor, MlabSceneModel
import numpy as np
class Isoplot1(HasTraits):
scene = Instance(MlabSceneModel, ())
#on_trait_change('scene.activated')
def _setup(self):
# Create x, y, z, s data
L = 10.
x, y, z = np.mgrid[-L:L:101j, -L:L:101j, -L:L:101j]
s = np.sqrt(4 * x ** 2 + 2 * y ** 2 + z ** 2)
# create the data pipeline
self.src1 = mlab.pipeline.scalar_field(x, y, z, s)
# Create the plot
self.plot1 = self.scene.mlab.pipeline.iso_surface(
self.src1, contours=[5, ], opacity=0.5, color=(1, 1, 0)
)
# Set the layout
view = View(Item('scene',
editor=SceneEditor(scene_class=MayaviScene),
height=400, width=600, show_label=False),
resizable=True
)
isoplot1 = Isoplot1()
isoplot1.configure_traits()
You probably already know this but just in case you can also take a look at some of the other mayavi interactive examples in the documentation.
Related
I am trying to run the code below in a bokeh server to visualize the plots. the final_imdb_dataframe is in the same directory as the python code. these are the steps i take to get the server to run:
open my terminal
type in "cd" then a space and then my directory in for the map containing my python script and the final_imdb_dataframe
press enter
type: bokeh serve --show "filename.py"
press enter
in my terminal i am getting this error message however:
bokeh : The term 'bokeh' is not recognized as the name of a cmdlet, function, script file, or operable program. (the complete error message is attached as a picture)
when i type in "pip show bokeh" in the command promt in python it gives me this:
pip show bokeh
Name: bokeh
Version: 2.4.3
Summary: Interactive plots and applications in the browser from Python
Home-page: https://github.com/bokeh/bokeh
Author: Bokeh Team
Author-email: info#bokeh.org
License: BSD-3-Clause
Location: c:\users\fazan\anaconda\lib\site-packages
Requires: Jinja2, numpy, packaging, pillow, PyYAML, tornado, typing-extensions
Required-by: hvplot, panel
Note: you may need to restart the kernel to use updated packages.
so it should work right?
i don't know what to do anymore...
code:
import pandas as pd
from bokeh.plotting import figure, show
import numpy as np
from bokeh.models import ColumnDataSource, HoverTool, Slider, RangeSlider, Div, Select
from bokeh.io import output_file, curdoc
from bokeh.layouts import column, row, layout
#EERSTE PLOT:
#line diagram of amount of movies released each year en avg rating displayed over the years
df = pd.read_csv("final_imdb_dataframe")
#"unnamed column weghalen
df.drop(df.columns[df.columns.str.contains('unnamed',case = False)],axis = 1, inplace = True)
#creating plot 2
plot2 = figure(plot_width = 1000,
plot_height = 400,
x_axis_label= "year",
title = "watchtime and movie rating over the years")
#creating a dropdown menu
source2 = ColumnDataSource(data={'x': df["release_date"], 'y': df["watchtime"]})
plot2.circle(x="x", y="y", size = 3, source = source2, alpha = 0.2)
def update_plot(attr, old, new):
if new == 'watchtime':
source2.data = {'x' : df["release_date"], 'y' : df["watchtime"]}
else:
source2.data = {'x' : df["release_date"], 'y' : df["movie_rating"]}
select = Select(title = "keuze menu", options=["watchtime", "movie_rating"], value = 'watchtime')
#code for updating the plot when the value is changed
select.on_change('value', update_plot)
#TWEEDE PLOT:
#creating a list of all the years a movie came out
dfrelease = df.release_date.drop_duplicates().tolist()
#sorting the list with release dates to get them in chronological order
dfrelease1 = sorted(dfrelease)
#creating an empty list
total_releases_per_year = []
#adding the amount of movies that came out every year to the list
for i in range(len(dfrelease1)):
total_releases_per_year.append(len(df[df["release_date"] == dfrelease1[i]]))
#creating a columndatasource of the two lists created above to make it possible for the hovertool to be used
source1 = ColumnDataSource(data=dict(year = dfrelease1, amount_of_movies_made = total_releases_per_year))
#making a hovertool
hover2 = HoverTool(tooltips=[("year", "#year"), ("amount of movies made", "#amount_of_movies_made")])
#creating plot 3
plot3 = figure(plot_width = 1000,
plot_height = 400,
x_axis_label= "year",
y_axis_label = "amount of movies",
title = "amount of movies per year")
plot3.line("year", "amount_of_movies_made", source = source1)
plot3.add_tools(hover2)
#DERDE PLOT:
#creating the ColumnDataSource
df_sel = df[df["release_date"] == 2020]
source1 = ColumnDataSource(df_sel)
#scatter plot
p1 = figure(title = "relation 'watchtime' and 'movie rating' over the years",
x_axis_label= "watchtime",
y_axis_label= "rating (0-10)",
plot_width = 1000,
plot_height = 400)
p1.circle(x="watchtime", y="movie_rating", alpha = 0.2, source=source1)
#making the rangeslider
slider = RangeSlider(title="release date", value= (1919, 2021), start=1919, end=2020, step=1)
#making the hover tool
hover1 = HoverTool(tooltips=[("title", "#movie_name"),("gross", "#gross_collection"),("votes", "#votes"),("genre", "#genre"), ("watchtime", "#watchtime"),("rating", "#movie_rating"),("release date", "#release_date")])
#making a def callback for the rangeslider to work when moved
def callback(attr, old, new):
year = slider.value
source1.data = df[(df["release_date"] >= year[0]) & (df["release_date"] <= year[1])]
slider.on_change("value", callback)
layout = column(slider, p1) #create a layout with slider on top of plot
p1.add_tools(hover1) #adding hover tool
layout3 = column(select, plot2, plot3, slider, p1) #making the layout for the dashboard
curdoc().add_root(layout3)*
i tried what i wrote above and expected acces to the bokeh server that would show me my plots. i have done this before on my previous computer (mac) and it worked then. now on my lenovo it is not working.`
I'm trying to create the parameter px on the holoviews.operation.datashader.spread operation interactively changeable together with an additional overlay.
The diagram with an IntSlider and the function returned by pn.bind(get_spreaded, px=px_slider) is working as expected when executing with pn.Column(px_slider, interactive)`.
But with an additional overlay, the line pn.Column(px_slider, interactive * other) reports TypeError: unsupported operand type(s) for *: 'function' and 'Points'.
How can I use the * operator with the function returned from pn.bind(...)?
Or is this the wrong way doing this? Is there a better and easier solution?
I ran the following code in jupyter lab:
import holoviews as hv
import panel as pn
import numpy as np
from holoviews.operation.datashader import rasterize, spread
import colorcet
import pandas as pd
hv.extension('bokeh')
pn.extension()
hv.opts.defaults(
hv.opts.Path(width=800, height=400),
hv.opts.Image(width=800, height=400)
)
def random_walk(n, f=200):
"""Random walk in a 2D space, smoothed with a filter of length f"""
xs = np.convolve(np.random.normal(0, 0.1, size=n), np.ones(f)/f).cumsum()
ys = np.convolve(np.random.normal(0, 0.1, size=n), np.ones(f)/f).cumsum()
xs += 0.1*np.sin(0.1*np.array(range(n-1+f))) # add wobble on x axis
xs += np.random.normal(0, 0.005, size=n-1+f) # add measurement noise
ys += np.random.normal(0, 0.005, size=n-1+f)
return np.column_stack([xs, ys])
# create a path and plot it
path = hv.Path([random_walk(10000, 30)])
path
# rasterize and show the plot
rasterized = rasterize(path).opts(colorbar=True, cmap=colorcet.fire, cnorm='log')
rasterized
# the callback for getting the spreaded plot
def get_spreaded(px=3, shape='circle'):
return spread(rasterized, px=px, shape=shape)
# show the plot returned from the callback
get_spreaded()
# create the slider for interactively changing the px value
px_slider = pn.widgets.IntSlider(name='Number of pixels to spread on all sides', start=0, end=10, value=3, step=1)
# bind the slider to the callback method
interactive = pn.bind(get_spreaded, px=px_slider)
# show only one plot without any overlay
pn.Column(px_slider, interactive)
# create data for an overlay
df = pd.DataFrame(data={'c1': [1, 2, 3, 4, 5], 'c2': [3, 4, 5, 6, 7]})
other = hv.Points(data=df)
other
# show both plots
pn.Column(px_slider, interactive * other)
The last line results in the following Error message:
#
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[159], line 1
----> 1 pn.Column(px_slider, interactive * other)
TypeError: unsupported operand type(s) for *: 'function' and 'Points'
I would expect, that there is some way to wrap the function and makes it possible to use the * operator. But I couldn't find a way yet.
Although in this particular case the return value of the function is something that HoloViews could (in principle) overlay with the other plot, HoloViews doesn't know that; the HoloViews * operator only knows how to handle HoloViews objects (Elements, HoloMaps, Layouts, and DynamicMaps), not bound Panel functions.
You could use a DynamicMap much like you used pn.bind, but here HoloViews operations already understand what to do with Panel widgets, so you can simply supply the widget to the spread operation (or any other operation's parameters):
import panel as pn, numpy as np, holoviews as hv, colorcet, pandas as pd
from holoviews.operation.datashader import rasterize, spread
hv.extension('bokeh')
pn.extension()
hv.opts.defaults(
hv.opts.Path(width=800, height=400),
hv.opts.Image(width=800, height=400)
)
def random_walk(n, f=200):
"""Random walk in a 2D space, smoothed with a filter of length f"""
xs = np.convolve(np.random.normal(0, 0.1, size=n), np.ones(f)/f).cumsum()
ys = np.convolve(np.random.normal(0, 0.1, size=n), np.ones(f)/f).cumsum()
xs += 0.1*np.sin(0.1*np.array(range(n-1+f))) # add wobble on x axis
xs += np.random.normal(0, 0.005, size=n-1+f) # add measurement noise
ys += np.random.normal(0, 0.005, size=n-1+f)
return np.column_stack([xs, ys])
# create plot with interactively controlled spreading
px_slider = pn.widgets.IntSlider(name='Number of pixels to spread on all sides',
start=0, end=10, value=3, step=1)
path = hv.Path([random_walk(10000, 30)])
rasterized = rasterize(path).opts(colorbar=True, cmap=colorcet.fire, cnorm='log')
spreaded= spread(rasterized, px=px_slider, shape='circle')
# create data for an overlay
df = pd.DataFrame(data={'c1': [1, 2, 3, 4, 5], 'c2': [3, 4, 5, 6, 7]})
other = hv.Points(data=df)
# show both plots
pn.Column(px_slider, spreaded * other)
I have a series of data, for example:
0.767838478
0.702426493
0.733858228
0.703275979
0.651456058
0.62427187
0.742353261
0.646359026
0.695630431
0.659101665
0.598786652
0.592840135
0.59199059
which I know fits best to an equation of the form:
y=ae^(b*x)+c
How can I fit the custom function to this data?
Similar question had been already asked on LibreOffice forum without a proper answer. I would appreciate if you could help me know how to do this. Preferably answers applying to any custom function rather than workarounds to this specific case.
There are multiple possible solutions for this. But one approach would be the following:
For determining the aand b in the trend line function y = a*e^(b*x) there are solutions using native Calc functions (LINEST, EXP, LN).
So we could the y = a*e^(b*x)+c taking as y-c= a*e^(b*x) and so if we are knowing c, the solution for y = a*e^(b*x) could be taken too. How to know c? One approach is described in Exponential Curve Fitting. There approximation of b, a and then c are made.
I have the main part of the delphi code from Exponential Curve Fitting : source listing translated to StarBasic for Calc. The part of the fine tuning of c is not translated until now. To-Do for you as professional and enthusiast programmers.
Example:
Data:
x y
0 0.767838478
1 0.702426493
2 0.733858228
3 0.703275979
4 0.651456058
5 0.62427187
6 0.742353261
7 0.646359026
8 0.695630431
9 0.659101665
10 0.598786652
11 0.592840135
12 0.59199059
Formulas:
B17: =EXP(INDEX(LINEST(LN($B$2:$B$14),$A$2:$A$14),1,2))
C17: =INDEX(LINEST(LN($B$2:$B$14),$A$2:$A$14),1,1)
y = a*e^(b*x) is also the function used for the chart's trend line calculation.
B19: =INDEX(TRENDEXPPLUSC($B$2:$B$14,$A$2:$A$14),1,1)
C19: =INDEX(TRENDEXPPLUSC($B$2:$B$14,$A$2:$A$14),1,2)
D19: =INDEX(TRENDEXPPLUSC($B$2:$B$14,$A$2:$A$14),1,3)
Code:
function trendExpPlusC(rangey as variant, rangex as variant) as variant
'get values from ranges
redim x(ubound(rangex)-1) as double
redim y(ubound(rangex)-1) as double
for i = lbound(x) to ubound(x)
x(i) = rangex(i+1,1)
y(i) = rangey(i+1,1)
next
'make helper arrays
redim dx(ubound(x)-1) as double
redim dy(ubound(x)-1) as double
redim dxyx(ubound(x)-1) as double
redim dxyy(ubound(x)-1) as double
for i = lbound(x) to ubound(x)-1
dx(i) = x(i+1) - x(i)
dy(i) = y(i+1) - y(i)
dxyx(i) = (x(i+1) + x(i))/2
dxyy(i) = dy(i) / dx(i)
next
'approximate b
s = 0
errcnt = 0
for i = lbound(dxyx) to ubound(dxyx)-1
on error goto errorhandler
s = s + log(abs(dxyy(i+1) / dxyy(i))) / (dxyx(i+1) - dxyx(i))
on error goto 0
next
b = s / (ubound(dxyx) - errcnt)
'approximate a
s = 0
errcnt = 0
for i = lbound(dx) to ubound(dx)
on error goto errorhandler
s = s + dy(i) / (exp(b * x(i+1)) - exp(b * x(i)))
on error goto 0
next
a = s / (ubound(dx) + 1 - errcnt)
'approximate c
s = 0
errcnt = 0
for i = lbound(x) to ubound(x)
on error goto errorhandler
s = s + y(i) - a * exp(b * x(i))
on error goto 0
next
c = s / (ubound(x) + 1 - errcnt)
'make y for (y - c) = a*e^(b*x)
for i = lbound(x) to ubound(x)
y(i) = log(abs(y(i) - c))
next
'get a and b from LINEST for (y - c) = a*e^(b*x)
oFunctionAccess = createUnoService( "com.sun.star.sheet.FunctionAccess" )
args = array(array(y), array(x))
ab = oFunctionAccess.CallFunction("LINEST", args)
if a < 0 then a = -exp(ab(0)(1)) else a = exp(ab(0)(1))
b = ab(0)(0)
trendExpPlusC = array(a, b, c)
exit function
errorhandler:
errcnt = errcnt + 1
resume next
end function
The formula y = beax is the exponential regression equation for LibreOffice chart trend lines.
LibreOffice exports all settings
All the settings of LibreOffice, all in the LibreOffice folder.
C:\Users\a←When installing the operating system, the name
entered.\AppData←File Manager ~ "Hidden project" to open, the AppData
folder will be displayed.\Roaming\LibreOffice
Back up the LibreOffice folder, when reinstalling, put the LibreOffice folder in its original place.
Note:
1. If the installation is preview edition, because the name of preview edition is LibreOfficeDev, so the LibreOfficeDev folder will be
displayed.
2. Formal edition can be installed together with preview edition, if both formal edition and preview edition are installed, LibreOffice
folder and LibreOfficeDev folder will be displayed.
3. To clear all settings, just delete the LibreOffice folder, then open the program, a new LibreOffice folder will be created.
LibreOffice exports a single toolbar I made
Common path
C:\Users\a←When installing the operating system, the name
entered.\AppData←File Manager ~ "Hidden project" to open, the AppData
folder will be
displayed.\Roaming\LibreOffice\4\user\config\soffice.cfg\modules\Please
connect the branch path of the individual software below.
Branch path
\modules\StartModule\toolbar\The "Start" toolbar I made is placed here.
\modules\swriter\toolbar\The "writer" toolbar I made is placed here.
\modules\scalc\toolbar\The "calc" toolbar I made is placed here.
\modules\simpress\toolbar\The "impress" toolbar I made is placed here.
\modules\sdraw\toolbar\The "draw" toolbar I made is placed here.
\modules\smath\toolbar\The "math" toolbar I made is placed here.
\modules\dbapp\toolbar\The "base" toolbar I made is placed here.
Backup file, when reinstalling, put the file in the original place.
Note:
Because of the toolbar that I made myself, default file name, will automatically use Numbering, so to open the file, can know the name of
the toolbar.
The front file name "custom_toolbar_" cannot be changed, change will cause error, behind's file name can be changed. For example:
custom_toolbar_c01611ed.xml→custom_toolbar_AAA.xml.
Do well of toolbar, can be copied to other places to use. For example: In the "writer" Do well of toolbar, can be copied to "calc"
places to use.
LibreOffice self-made symbol toolbar
Step 1 Start "Recording Macros function" Tools\Options\Advanced\Enable macro recording(Tick), in the
"Tools\Macros", the "Record Macro" option will appear.
Step 2 Recording Macros Tools\Macros\Record Macro→Recording action (click "Ω" to enter symbol→select symbol→Insert)→Stop
Recording→The name Macros stored in "Module1" is Main→Modify Main
name→Save.
Step 3 Add item new toolbar Tools\Customize\Toolbar→Add→Enter a name (example: symbol)→OK, the new toolbar will appear in the top
left.
Step 4 Will Macros Add item new toolbar Tools\Customize\Toolbar\Category\Macros\My
Macros\Standard\Module1\Main→Click "Main"→Add item→Modify→Rename (can
be named with symbol)→OK→OK.
I am trying to build a neural network model with one hidden layer (1024 nodes). The hidden layer is nothing but a relu unit. I am also processing the input data in batches of 128.
The inputs are images of size 28 * 28. In the following code I get the error in line
_, c = sess.run([optimizer, loss], feed_dict={x: batch_x, y: batch_y})
Error: TypeError: Cannot interpret feed_dict key as Tensor: Tensor Tensor("Placeholder_64:0", shape=(128, 784), dtype=float32) is not an element of this graph.
Here is the code I have written
#Initialize
batch_size = 128
layer1_input = 28 * 28
hidden_layer1 = 1024
num_labels = 10
num_steps = 3001
#Create neural network model
def create_model(inp, w, b):
layer1 = tf.add(tf.matmul(inp, w['w1']), b['b1'])
layer1 = tf.nn.relu(layer1)
layer2 = tf.matmul(layer1, w['w2']) + b['b2']
return layer2
#Initialize variables
x = tf.placeholder(tf.float32, shape=(batch_size, layer1_input))
y = tf.placeholder(tf.float32, shape=(batch_size, num_labels))
w = {
'w1': tf.Variable(tf.random_normal([layer1_input, hidden_layer1])),
'w2': tf.Variable(tf.random_normal([hidden_layer1, num_labels]))
}
b = {
'b1': tf.Variable(tf.zeros([hidden_layer1])),
'b2': tf.Variable(tf.zeros([num_labels]))
}
init = tf.initialize_all_variables()
train_prediction = tf.nn.softmax(model)
tf_valid_dataset = tf.constant(valid_dataset)
tf_test_dataset = tf.constant(test_dataset)
model = create_model(x, w, b)
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(model, y))
optimizer = tf.train.GradientDescentOptimizer(0.5).minimize(loss)
#Process
with tf.Session(graph=graph1) as sess:
tf.initialize_all_variables().run()
total_batch = int(train_dataset.shape[0] / batch_size)
for epoch in range(num_steps):
loss = 0
for i in range(total_batch):
batch_x, batch_y = train_dataset[epoch * batch_size:(epoch+1) * batch_size, :], train_labels[epoch * batch_size:(epoch+1) * batch_size,:]
_, c = sess.run([optimizer, loss], feed_dict={x: batch_x, y: batch_y})
loss = loss + c
loss = loss / total_batch
if epoch % 500 == 0:
print ("Epoch :", epoch, ". cost = {:.9f}".format(avg_cost))
print("Minibatch accuracy: %.1f%%" % accuracy(predictions, batch_labels))
valid_prediction = tf.run(tf_valid_dataset, {x: tf_valid_dataset})
print("Validation accuracy: %.1f%%" % accuracy(valid_prediction.eval(), valid_labels))
test_prediction = tf.run(tf_test_dataset, {x: tf_test_dataset})
print("TEST accuracy: %.1f%%" % accuracy(test_prediction.eval(), test_labels))
This worked for me
from keras import backend as K
and after predicting my data i inserted this part of code
then i had again loaded the model.
K.clear_session()
i faced this problem in production server,
but in my pc it was running fine
...........
from keras import backend as K
#Before prediction
K.clear_session()
#After prediction
K.clear_session()
Variable x is not in the same graph as model, try to define all of these in the same graph scope. For example,
# define a graph
graph1 = tf.Graph()
with graph1.as_default():
# placeholder
x = tf.placeholder(...)
y = tf.placeholder(...)
# create model
model = create(x, w, b)
with tf.Session(graph=graph1) as sess:
# initialize all the variables
sess.run(init)
# then feed_dict
# ......
If you use django server, just runserver with --nothreading
for example:
python manage.py runserver --nothreading
I had the same issue with flask. adding --without-threads flag to flask run or threaded=False to app.run() fixed it
In my case, I was using loop while calling in CNN multiple times, I fixed my problem by doing the following:
# Declare this as global:
global graph
graph = tf.get_default_graph()
# Then just before you call in your model, use this
with graph.as_default():
# call you models here
Note: In my case too, the app ran fine for the first time and then gave the error above. Using the above fix solved the problem.
Hope that helps.
The error message TypeError: Cannot interpret feed_dict key as Tensor: Tensor Tensor("...", dtype=dtype) is not an element of this graph can also arise in case you run a session outside of the scope of its with statement. Consider:
with tf.Session() as sess:
sess.run(logits, feed_dict=feed_dict)
sess.run(logits, feed_dict=feed_dict)
If logits and feed_dict are defined properly, the first sess.run command will execute normally, but the second will raise the mentioned error.
You can also experience this while working on notebooks hosted on online learning platforms like Coursera. So, implementing following code could help get over with the issue.
Implement this at the topmost block of Notebook file:
from keras import backend as K
K.clear_session()
Similar to #javan-peymanfard and #hmadali-shafiee, I ran into this issue when loading the model in an API. I was using FastAPI with uvicorn. To fix the issue I just set the API function definitions to async similar to this:
#app.post('/endpoint_name')
async def endpoint_function():
# Do stuff here, including possibly (re)loading the model
I would like to use the chaco tools ScatterInspector and/or ScatterInspectorOverlay with enaml. I've set up a very simple controller and view (source below) but cannot determine how to proceed. I have tried unsuccessfully to follow the minimal and old examples I've found.
If I uncomment the overlay part for ScatterInspectorOverlay, the code fails to run with
File ".../chaco/scatter_inspector_overlay.py", line 51, in overlay if not plot or not plot.index or not getattr(plot, "value", True):
If I comment out the overlay part, I of course don't get the overlay behavior I want and also, on moving the mouse, get
File ".../chaco/tools/scatter_inspector.py", line 48, in normal_mouse_move index = plot.map_index((event.x, event.y), threshold=self.threshold)
view.enaml source:
from enaml.widgets.api import (
Window, Container, EnableCanvas,
)
enamldef ScatterView(Window):
attr controller
title = "Scatter Inspector Test"
initial_size = (640,480)
Container:
EnableCanvas:
component = controller.scatter_plot
controller.py source:
import enaml
from enaml.stdlib.sessions import show_simple_view
from traits.api import HasTraits, Instance
from chaco.api import Plot, ArrayPlotData, ScatterInspectorOverlay
from chaco.tools.api import ScatterInspector
from numpy import linspace, sin
class ScatterController(HasTraits):
scatter_plot = Instance(Plot)
def _scatter_plot_default(self):
# data
x = linspace(-14, 14, 100)
y = sin(x) * x**3
plotdata = ArrayPlotData(x = x, y = y)
# plot
scatter_plot = Plot(plotdata)
renderer = scatter_plot.plot(("x", "y"), type="scatter", color="red")
# inspector
scatter_plot.tools.append(ScatterInspector(scatter_plot))
# overlay
# scatter_plot.overlays.append( ScatterInspectorOverlay(
# scatter_plot,
# hover_color = 'red',
# hover_marker_size = 6,
# selection_marker_size = 6,
# selection_color = 'yellow',
# selection_outline_color='purple',
# selection_line_width = 3
# ))
#return
return scatter_plot
if __name__ == "__main__":
with enaml.imports():
from view import ScatterView
main_controller = ScatterController()
window = ScatterView(controller=ScatterController())
show_simple_view(window)
The problem with my above code was that I was adding ScatterInspector to scatter_plot rather than to renderer and that I was missing the [0] index to get renderer.
The key thing I was really wanting to do, though, was to be notified when the mouse was hovering over a data point and/or a data point was selected. I added when_hover_or_selection_changes which shows how to do that.
Working controller.py:
...
# plot
scatter_plot = Plot(plotdata)
renderer = scatter_plot.plot(("x", "y"), type="scatter", color="lightblue")[0]
# inspector
renderer.tools.append(ScatterInspector(renderer))
# overlay
renderer.overlays.append(ScatterInspectorOverlay(renderer,
hover_color="red",
hover_marker_size=6,
selection_marker_size=6,
selection_color="yellow",
selection_outline_color="purple",
selection_line_width=3))
...
# get notified when hover or selection changes
#on_trait_change('renderer.index.metadata')
def when_hover_or_selection_changes(self):
print 'renderer.index.metadata = ', self.renderer.index.metadata