Updating data of an Image Plane Widget - python

I am working on a visualization of different vector fields.
For this purpose I am using the Mayavi Library in Python 2.7 (I think), to create a Image Plane Widget (IPW) and a slider to change the data of the vector field while the visualization is open, but my IPW won't change.
It works if I render the IPW new each time the slider is changed, but that's not what I want.
Is there a way to change the data of an IPW while the program is running without rendering a new Plane each time?
I have written following code:
import numpy as np
from mayavi import mlab
from matplotlib.scale import scale_factory
from traits.api import HasTraits, Range, Instance, Array, \
on_trait_change
from traitsui.api import View, Item, Group
from mayavi.core.pipeline_base import PipelineBase
from mayavi.core.ui.api import MayaviScene, SceneEditor, \
MlabSceneModel
class Modell(HasTraits):
p = Array
n = Range(0, 9, 5)
#p is a 4 dimensional Array p[10][20][20][20]
scene = Instance(MlabSceneModel, ())
plot = Instance(PipelineBase)
#on_trait_change('n,scene.activated')
def update_plot(self):
self.src = mlab.pipeline.scalar_field(self.p[self.n])
if self.plot is None:
self.plot = self.scene.mlab.pipeline.image_plane_widget(self.src,
plane_orientation='z_axes',
slice_index=10,
vmin=0, vmax=120)
else:
'''here should be the update function, i tried using mlab_source.set(self.src=self.src)
and all variations of expressions in the brackets but nothing worked.
I also searched for functions in IPW itself but didn't find something that could help me.'''
#The layout of the dialog created
view = View(Item('scene', editor=SceneEditor(scene_class=MayaviScene),
height=400, width=400, show_label=False),
Group('_', 'n'),
resizable=True,
)
my_model = Modell(p=p)
my_model.configure_traits()
I tried updating the pipeline and updating the data with self.plot.update_pipeline() and self.plot.update_data() but this doesn't work either.

Ok I found the solution for my problem, the trick is to change the data directly through the pipeline. So in my code I just have to set the following command into the else segment:
self.plot.parent.parent.scalar_data = self.p[self.n]

Related

Jupyter/Plotly - how to replace or update plot from add_trace?

Consider this Jupyter Python code, which uses Plotly:
import plotly.graph_objs as go
import numpy as np
from ipywidgets import widgets
from IPython.display import display
import random
mybutton = widgets.Button(description="Redraw")
xs = np.linspace(start=0, stop=10, num=100)
fig = go.FigureWidget( layout=go.Layout() )
# NB: function needs to be written in a way, that returns np.array for input np.array!
# or - use np.vectorize, to apply it element-by-element
def TestFunc(inval):
return inval+2*random.random()
fig.add_trace(go.Scatter(x=xs, y=np.vectorize(TestFunc)(xs),
mode='lines',
name='Test'))
def on_button_clicked(b):
fig.add_trace(go.Scatter(x=xs, y=np.vectorize(TestFunc)(xs),
mode='lines',
name='Test'))
mybutton.on_click(on_button_clicked)
widgets.VBox([mybutton, fig])
What I want to do, is redraw the function anew, whenever I click the button. However, since I use add_trace in the button callback, I get new traces added - I don't get the original one replaced:
So, my question is:
How do I obtain a reference to a "trace", added with add_trace, so that I could replace it? (say, fig.traces[0] = ...)
What is the best way to redraw the figure with a new retrace, with the minimal amount of object instantiation (I guess, I could do fig = go.FigureWidget( ... ) ... upon each button click, but that would have to recreate everything; I'd think, just recreating the y array, and triggering a redraw would be more "optimized")
OK, found something - still not sure if this is the way to do it, so if someone knows better, please post...
But anyways, fig.add_trace returns a reference that you can store in a variable; eventually that variable also contains the .x and .y arrays, and the .y array can be directly replaced, like so:
import plotly.graph_objs as go
import numpy as np
from ipywidgets import widgets
from IPython.display import display
import random
mybutton = widgets.Button(description="Redraw")
xs = np.linspace(start=0, stop=10, num=100)
fig = go.FigureWidget( layout=go.Layout() )
# NB: function needs to be written in a way, that returns np.array for input np.array!
# or - use np.vectorize, to apply it element-by-element
def TestFunc(inval):
return inval+2*random.random()
mytrace = fig.add_trace(go.Scatter(x=xs, y=np.vectorize(TestFunc)(xs),
mode='lines',
name='Test'))
print(repr(mytrace))
def on_button_clicked(b):
mytrace.data[0].y = np.vectorize(TestFunc)(xs)
mybutton.on_click(on_button_clicked)
widgets.VBox([mybutton, fig])
The above code works as intended - but I'm not yet sure whether it's the most optimized way to do it...

View vs. Viewable with displaying widget

I am putting together an interactive dashboard using the pyviz ecosystem. One feature of the dashboard is that the underlying data may change based on a widget selector. Below is an example code showing the issue I have with getting the time widget slider to appear:
Package Versions:
panel: 0.5.1
param: 1.9.0
holoviews: 1.12.3
geoviews: 1.6.2
Example:
import xarray as xr
import panel as pn
import numpy as np
import param as pm
import holoviews as hv
import geoviews as gv
from matplotlib import cm
import geoviews.tile_sources as gts
from holoviews.operation.datashader import rasterize
from collections import OrderedDict as odict
from holoviews import opts
renderer = hv.renderer('bokeh')
pn.extension()
dset = xr.DataArray(np.random.random((100,100,100)),coords={'X':np.arange(100),'Y':np.arange(100),'T':np.arange(100)},dims=['X','Y','T']).to_dataset(name='test')
dset = gv.Dataset(dset, ['X', 'Y', 'T'], 'test').to(gv.QuadMesh, groupby='T').opts(cmap='viridis', colorbar=True, show_frame=False)
fields = odict([('test','test')])#odict([(v.get('label',k),k) for k,v in source.metadata['fields'].items()])
aggfns = odict([(f.capitalize(),f) for f in ['mean','std','min','max','Pixel Level']])#'count','sum','min','max','mean','var','std']])#,'None (Pixel Level)']])
cmaps = odict([(n,cm.get_cmap(n)) for n in ['viridis','seismic','cool','PiYG']])
maps = ['EsriImagery','EsriNatGeo', 'EsriTerrain', 'OSM']
bases = odict([(name, gts.tile_sources[name].relabel(name)) for name in maps])
gopts = hv.opts.WMTS(responsive=True, xaxis=None, yaxis=None, bgcolor='black', show_grid=False)
class Explorer_Test(pm.Parameterized):
field = pm.Selector(fields)
cmap = pm.Selector(cmaps)
basemap = pm.Selector(bases)
data_opacity = pm.Magnitude(1.00)
map_opacity = pm.Magnitude(1.00)
agg_fn_ = pm.Selector(aggfns,label='Aggregation**',default='mean')
#pm.depends('field', 'agg_fn_')
def aggregator(self):
field = None if self.field == "counts" else self.field
return self.agg_fn(field)
#pm.depends('map_opacity', 'basemap')
def tiles(self):
return self.basemap.opts(gopts).opts(alpha=self.map_opacity)
def viewable(self,**kwargs):
rasterized = rasterize(dset, precompute=True).opts(colorbar=True, height=800, show_frame=False).apply.opts(cmap=self.param.cmap,alpha=self.param.data_opacity)
return hv.DynamicMap(self.tiles)*rasterized
explorer_test = Explorer_Test(name="")
When I display the plot like:
panel = pn.Row(pn.Param(explorer_test.param, expand_button=False),explorer_test.viewable())
panel.servable()
The time widget appears:
Whereas:
panel = pn.Row(pn.Param(explorer_test.param, expand_button=False),explorer_test.viewable)
panel.servable()
In the first example, if I select an alternative dataset (based on a param.Selector widget - not shown in this example) it does not redraw the image. However, in the 2nd example, the image is redrawn, but I am missing the time slider.
UPDATE - Solution
Here is the workaround as per James' solutions (thanks!). This example includes changing the dataset and the variable (within each dataset) and the time parameter.
import xarray as xr
import panel as pn
import numpy as np
import param as pm
import holoviews as hv
import geoviews as gv
from holoviews.operation.datashader import rasterize
from collections import OrderedDict as odict
renderer = hv.renderer('bokeh')
pn.extension()
#Define Example Datasets
dset1 = xr.merge([xr.DataArray(np.random.random((50,50,50)),coords={'X':np.arange(50),'Y':np.arange(50),'T':np.arange(50)},dims=['X','Y','T']).to_dataset(name='var1'),
xr.DataArray(np.random.random((50,50,10))*.1,coords={'X':np.arange(50),'Y':np.arange(50),'T':np.arange(10)},dims=['X','Y','T']).to_dataset(name='var2')])
dset2 = xr.DataArray(np.random.random((50,50,20))*10,coords={'X':np.arange(50)/2.,'Y':np.arange(50)/3.,'T':np.arange(20)},dims=['X','Y','T']).to_dataset(name='var1')
data_dict = {'dset1':dset1,'dset2':dset2}
#Plot Datasets
class sel_dset_var():
def dset1_var1():
return rasterize(gv.Dataset(dset1.var1, ['X', 'Y', 'T'], 'test1').to(gv.QuadMesh, groupby='T')()).opts(cmap='viridis',colorbar=True, height=200, show_frame=False)
def dset1_var2():
return rasterize(gv.Dataset(dset1.var2, ['X', 'Y', 'T'], 'test1').to(gv.QuadMesh, groupby='T')()).opts(cmap='viridis',colorbar=True, height=200, show_frame=False)
def dset2_var1():
return rasterize(gv.Dataset(dset2.var1, ['X', 'Y', 'T'], 'test1').to(gv.QuadMesh, groupby='T')()).opts(cmap='viridis',colorbar=True, height=200, show_frame=False)
#Dashboard
class Explorer_Test(pm.Parameterized):
dset = pm.Selector(odict([('Dataset1','dset1'),('Dataset2','dset2')]),default='dset1')
varss = pm.Selector(list(dset1.data_vars),default=list(dset1.data_vars)[0])
time1 = pm.Selector(dset1.var1.coords['T'].values,default=dset1.var1.coords['T'].values[0])
#pm.depends('dset',watch=True)
def update_var(self):
self.param['varss'].objects = list(data_dict[self.dset].data_vars)
self.param.set_param(varss=list(data_dict[self.dset].data_vars)[0])
#pm.depends('dset',watch=True)
def update_var(self):
self.param['varss'].objects = list(data_dict[self.dset].data_vars)
self.param.set_param(varss=list(data_dict[self.dset].data_vars)[0])
def elem(self):
return getattr(sel_dset_var,self.dset+'_'+self.varss)()
#pm.depends('varss','dset',watch=True)
def update_time(self):
self.param['time1'].objects =data_dict[self.dset][self.varss].dropna(dim='T').coords['T'].values
self.param.set_param(time1=data_dict[self.dset][self.varss].dropna(dim='T').coords['T'].values[0])
def elem_yr(self):
return getattr(self.elem(),'select')(T=self.time1)
def viewable(self,**kwargs):
return self.elem_yr
explorer_test = Explorer_Test(name="")
panel = pn.Row(pn.Param(explorer_test.param, expand_button=False),explorer_test.viewable())
panel.servable()
Cheers!
This code looks like it's derived from my http://datashader.org/dashboard.html example. In my example, the output from the viewable() method is already fully dynamic, and does not ever need to be regenerated, being already linked internally to all the widgets and controls that affect how it appears. Whereas if you pass viewable as a method name to Panel (rather than result of calling that method), you're asking Panel to call viewable() for you whenever it determines that the result from an initial call becomes stale. This simple re-run-the-method approach is appropriate for very simple cases of all-or-nothing computation, but not really useful here when the objects are already dynamic themselves and where specific controls are tied to specific aspects of the plot. (Why you also don't get a time widget in that case I'm not sure; it's not a recommended usage, but I would have thought it should still work in giving you a widget.)
Anyway, I don't think you should be trying to get the second case above to work, only the first one. And there the problem isn't the lack of the slider, it sounds like it's that you're trying to get the plot to be responsive to changes in your data source. Luckily, that case is already illustrated in the example in http://datashader.org/dashboard.html ; there rasterize dynamically wraps a method that returns the appropriate column of the data to show. You should be able to adapt that approach to make it dynamically reflect the state of some other widget that lets the user select the dataset.

How do I add transparency to shape in python pptx?

def new_presentation():
prs=Presentation()
img="C:/Users/Dennis/Desktop/Tom-Hiddleston-4-1024x768.jpg"
mainsld=new_slide(prs, 6)
mainshp=mainsld.shapes
mainshp.add_picture(img, 0,0, Inches(10))
titleshape=mainshp.add_shape(MSO_SHAPE.RECTANGLE, Inches(0), Inches(1), Inches(10), Inches(1))
titleshape.fill.solid()
titleshape.fill.fore_color.rgb=RGBColor(0x00,0x64,0x00)
titleshape.fill.transparency = 0.25 ##doesnt work???##########################
titleshape.line.fill.background()
titlebox=mainshp.add_textbox(Inches(1), Inches(0.8),Inches(1), Inches(1)).text_frame.add_paragraph()
titlebox.text="TOM HIDDLESTON"
titlebox.font.name="Calibri"
titlebox.font.size=Pt(36)
titlebox.font.color.rgb=RGBColor(0x90,0x90,0x00)
prs.save('test.pptx')
The line marked with "######s" is supposed to make the shape more transparent as written in the pptx documentation - it is a shape.fill property . Everything else in the code works perfectly. I'm using python 2.7 and latest pptx. Thank you for your help in advance.
After much digging, I have been able to come up with a solution for this
from pptx import Presentation
from pptx.oxml.xmlchemy import OxmlElement
from pptx.util import Cm
from pptx.enum.shapes import MSO_SHAPE
from pptx.dml.color import RGBColor
def SubElement(parent, tagname, **kwargs):
element = OxmlElement(tagname)
element.attrib.update(kwargs)
parent.append(element)
return element
def _set_shape_transparency(shape, alpha):
""" Set the transparency (alpha) of a shape"""
ts = shape.fill._xPr.solidFill
sF = ts.get_or_change_to_srgbClr()
sE = SubElement(sF, 'a:alpha', val=str(alpha))
## Create presentation
prs = Presentation()
## Add a slide (empty slide layout)
slide = prs.slides.add_slide(prs.slide_layouts[6])
##Add a blue box to the slide
blueBox = slide.shapes.add_shape(autoshape_type_id=MSO_SHAPE.RECTANGLE,
left=Cm(0),
top=Cm(0),
height=Cm(10),
width=Cm(20))
## Make the box blue
blueBoxFill = blueBox.fill
blueBoxFill.solid()
blueBoxFillColour = blueBoxFill.fore_color
blueBoxFillColour.rgb = RGBColor(0,176,240)
## Set the transparency of the blue box to 56%
_set_shape_transparency(blueBox,44000)
## Save the presentation
prs.save(your_path)
FillFormat.transparency is not implemented yet. The part of the documentation where you saw that may have been an analysis page, which is a precursor to development.
This is the analysis page:
http://python-pptx.readthedocs.io/en/latest/dev/analysis/features/dml-fill.html?highlight=transparency
This is the FillFormat (.fill) API, as developed:
http://python-pptx.readthedocs.io/en/latest/api/dml.html#fillformat-objects
You can however use lxml calls from the FillFormat object to manipulate the XML under it. You probably want to start with the spPr element in the .fill element:
spPr = titleshape.fill._xPr
print spPr.xml
Here's one example of doing that sort of thing:
https://groups.google.com/forum/#!msg/python-pptx/UTkdemIZICw/qeUJEyKEAQAJ
You'll find more if you search on various combinations of the terms python-pptx, OxmlElement, lxml, and workaround function.

Time dependent data in Mayavi

Assuming I have a 4d numpy array like this: my_array[x,y,z,t].
Is there a simple way to load the whole array into Mayavi, and simply selecting the t I want to investigate for?
I know that it is possible to animate the data, but I would like to rotate my figure "on the go".
It is possible to set up a dialogue with a input box in which you can set t.
You have to use the traits.api, it could look like this:
from traits.api import HasTraits, Int, Instance, on_trait_change
from traitsui.api import View, Item, Group
from mayavi.core.ui.api import SceneEditor, MlabSceneModel, MayaviScene
class Data_plot(HasTraits):
a = my_array
t = Int(0)
scene = Instance(MlabSceneModel, ())
plot = Instance(PipelineBase)
#on_trait_change('scene.activated')
def show_plot(self):
self.plot = something(self.a[self.t]) #something can be surf or mesh or other
#on_trait_change('t')
def update_plot(self):
self.plot.parent.parent.scalar_data = self.a[self.t] #Change the data
view = View(Item('scene', editor=SceneEditor(scene_class=MayaviScene),
show_label=False),
Group('_', 't'),
resizable=True,
)
my_plot = Data_plot(a=my_array)
my_plot.configure_traits()
You can also set up a slider with the command Range instead of Int if you prefer this.

Updating Points of TVTK Dataset in MayaVI (without flushing pipeline)

I want to use MayaVI for visualization of large simulation data, saved as a VTKUnstructuredGrid (or here TVTK Unstructured Grid). After loading the Grid, I want to quickly update the grid points using numpy arrays, without changing anything else in the model.
So far I update the points and then call the modified()-method, which flushes the complete pipeline and thus slows down the visualization a lot. My question is now: Is there any chance to update the points in a VTKDataset without reloading the whole pipeline?
I am doing the visualization using Traits; simplified my code looks like:
import numpy as np
from enthought.traits.api import HasTraits, Range, Instance, on_trait_change
from enthought.traits.ui.api import View, Item, HGroup, HSplit, VSplit
from enthought.tvtk.pyface.scene_editor import SceneEditor
from enthought.mayavi.tools.mlab_scene_model import MlabSceneModel
from enthought.mayavi.core.ui.mayavi_scene import MayaviScene
from enthought.mayavi import mlab
from enthought.tvtk.api import tvtk
from enthought.mayavi.modules.surface import Surface
from enthought.tvtk.pyface.scene_editor import SceneEditor
class Visu(HasTraits):
timestep = Range(50,100,50)
pts = tvtk.Points()
ugrid = tvtk.UnstructuredGrid()
scene = Instance(MlabSceneModel, ())
view = View(Item('scene', editor=SceneEditor(scene_class=MayaviScene), height=250, width=300, show_label=True),HGroup('_', 'timestep'), resizable=True )
#on_trait_change('scene.activated')
def ini(self):
filename = 'original3dplot'
reader = tvtk.LSDynaReader(file_name = filename)
reader.update()
self.ugrid = reader.get_output()
self.surface = self.scene.mlab.pipeline.surface(self.ugrid)
#on_trait_change('timestep')
def update_visu(self):
update_coord = np.loadtxt('newcoordinates'+str(self.timestep))
self.pts.from_array(update_coord)
self.ugrid.points = self.pts
self.ugrid.modified()
visualization = Visu()
visualization.configure_traits()

Categories