Mayavi plot volume, AttributeError: 'Volume' object has no attribute 'setDiffuse' - python

I am plotting 3D image using mayavi,
mlab.figure(1, bgcolor=(0, 0, 0), size=(700, 700))
grid = mlab.pipeline.scalar_field(xi, yi, zi, di)
vol = mlab.pipeline.volume(grid, vmin=0.0, vmax=1.0)
I can use
vol.edit_traits()
to modify the properties such as Diffuse or Scalar Opacity Unit Distance, but my question is, can I modify those properties in the script so that it will run automatically everytime? I tried the following but it gives the error as in the title:
vp = vol._volume_property
vp.setDiffuse(0.5)
Shouldn't vtkVolumeProperty already has those methods defined?
As shown here
Maybe another small question, I use 'mlab.savefig(mypdf)' to save figure to a pdf file, but everytime it runs it will pop up a dialog to ask me fill out all detailed properties such as size, etc. Is there a way to save figure to a pdf file without poping up this dialog each time?
Thanks in advance!
I tried to use vol._volume_property and setDiffuse function to set property values, but it didn't work. I would expect to change those properties without use vol.edit_traits() since it is a dialog and very inefficient.

Related

Store multiple matplotlib figures in a dictionary and use keys to display them / modify them at will?

I have a function that generates a plot from data I have read in. The goal is to be able to open multiple plot windows, each with a unique name, and then allow other functions to alter them at will (updating the data in them, changing colors, etc.), or to re-open plots that have been closed.
What I have tried to do is this:
1) Define a class, workspace, that has an attribute Figures that is a dictionary. I intend to assign my figures to unique keys in this dictionary.
2) Now, I generate a figure, and then save it into the WS.Figures dictionary.
3) Simplest use case, the user closes the figure and wants to re-open it, without having to go through make_plot() again. (My actual function has far, far, more complexity in the plotting - it's a pain to re-create each time manually). So I tried to write the following, which does absolutely nothing, apparently.
class WorkSpace(object):
def __init__(self):
self.Figures = {}
return
WS = WorkSpace()
def make_plot(x_data,y_data,name):
plt.ion()
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(x_data,y_data)
fig.canvas.draw()
WS.Figures[name] = fig
return
def replot(name):
WS.Figures[name].canvas.draw()
return
My thinking here was that WS.Figures[name] would hold an identical copy of fig from make_plot() and so I'd just need to issue the same command to make it appear.
I was hoping this would be the absolute easiest thing to do, and that I could then use that dictionary key to refer to the plot, update axes, etc. whenever I needed. But if I can't even replot it...

Show text annotations on selection in Bokeh

I have a little Bokeh plot with data points and associated text labels. What I want is for the text labels to only appear when the user selects points with the box select tool. This gets me close:
from bokeh.plotting import ColumnDataSource,figure,show
source = ColumnDataSource(
data=dict(
x=test[:,0],
y=test[:,1],
label=[unquote_plus(vocab_idx[i]) for i in range(len(test))]))
TOOLS="box_zoom,pan,reset,box_select"
p = figure(plot_width=400, plot_height=400,tools=TOOLS)
p.circle(x='x',y='y', size=10, color="red", alpha=0.25,source=source)
renderer = p.text(x='x',y='y',text='label',source=source)
renderer.nonselection_glyph.text_alpha=0.
show(p)
This is close, in that if I draw a box around some points, those text labels are shown and the rest are hidden, but the problem is that it renders all the text labels to start (which is not what I want). The initial plot should have all labels hidden, and they should only appear upon a box_select.
I thought I could start by rendering everything with alpha=0.0, and then setting a selection_glyph parameter, like this:
...
renderer = p.text(x='x',y='y',text='label',source=source,alpha=0.)
renderer.nonselection_glyph.text_alpha=0.
renderer.selection_glyph.text_alpha=1.
...
But this throws an error:
AttributeError: 'NoneType' object has no attribute 'text_alpha'
When trying to access the text_alpha attribute of selection_glyph.
I know I could use a hover effect here or similar, but need the labels to default to not being visible. An alternative, but not ideal, solution would be to have a toggle button that switches the labels on and off, but I'm not sure how to do that either.
What am I doing wrong here?
As of version 0.11.1, the value of selection_glyph is None by default. This is interpreted by BokehJS as "don't do anything different, just draw the glyph as normal". So you need to actually create a selection_glyph. There are two ways to do this, both demonstrated here:
http://docs.bokeh.org/en/latest/docs/user_guide/styling.html#selected-and-unselected-glyphs
Basically, they are
by hand
Create an actual Circle Bokeh model, something like:
selected_circle = Circle(fill_alpha=1, fill_color="firebrick", line_color=None)
renderer.selection_glyph = selected_circle
OR
using glyph method parameters
Alternatively, as a convenience Figure.circle accepts paramters like selection_fill_alpha or selection_color (basically any line or fill or text property, prefixed with selection_) :
p.circle(..., selection_color="firebrick")
Then a Circle will be created automatically and used for renderer.selection_glyph
I hope this is useful information. If so, it highlights that there are two possible ways that the project could be improved:
updating the docs to be explicit and highlight that renderer.selection_glyph is None by default
changing code so that renderer.selection_glyph is just a copy of renderer.glyph by default (then your original code would work)
Either would be small in scope and ideal for a new contributor. If you would be interested in working up a Pull Request to do either of these tasks, we (and other users) would certainly be grateful for the contribution. In which case, please just make an issue first at
https://github.com/bokeh/bokeh/issues
that references this discussion, and we can provide more details or answer any questions.

Python ggplot: Is it possible to turn off the GUI displayed? and get a command-line ("non-interactive plotting"/"batch")

When plotting with Python ggplot, every single plot command causes a GUI pane to be displayed and suspend execution ("interactive plotting"). But I want to:
avoid/ turn off this GUI and save the plot object some where in runtime (I will be displaying it in some other C# forms control).
find a Python equivalent to dev.off() command in R language which turns off the GUI for plotting.
Example:
print ggplot(data, aes('Age', 'Weight')) + geom_point(colour='steelblue')
When I execute this, it opens up a new GUI (like below) displaying the plot.
You can do the following, which returns a matplotlib figure:
g = ggplot(...) + geom_xxx(...)
fig = g.draw()
ggplots __repr__() method (what is called by print(g) is basically self.draw() then use matplotlibs plt.show() to show the plot...
You can also use ggsave(g) to save the plot somewhere.
Since plotting is triggered by __repr__ method the obvious approach is to avoid situations when it is called. Since you want to use this plot in some other place there is no reason to call print or even executing statements which will be discarded like this:
ggplot(data, aes('Age', 'Weight')) + geom_point(colour='steelblue')
Instead you can simply assign it to the variable
p = ggplot(data, aes('Age', 'Weight')) + geom_point(colour='steelblue')
what is exactly the same thing one would do in R. Using graphic device to redirect output and discarding it doesn't really make sense.
If for some reason that's not enough you switch to non-interactive matplotlib backend:
import matplotlib
matplotlib.use('Agg')
from ggplot import *
ggplot(aes(x='date', y='beef'), data=meat)
<ggplot: (...)>

How can I get matplotlib to show full subplots in an animation?

I'm trying to write a simple immune system simulator. I'm modeling infected tissue as a simple grid of cells and various intracellular signals, and I'd like to animate movement of cells in one plot and the intensity of viral presence in another as the infection progresses. I'm doing so with the matshow function provided by matplotlib. However, when I plot the two next to each other, the full grid gets clipped unless I stretch out the window myself. I can't address the problem at all when saving to an mp4.
Here's the default view, which is identical to what I observe when saving to mp4:
And here's what it looks like after stretching out the viewer window
I'm running Python 2.7.9 with matplotlib 1.4.2 on OS X 10.10.2, using ffmpeg 2.5.2 (installed via Homebrew). Below is the code I'm using to generate the animation. I tried using plt.tight_layout() but it didn't affect the problem. If anyone has any advice as to how to solve this, I'd really appreciate it! I'd especially like to be able to save it without viewing with plt.show(). Thanks!
def animate(self, fname=None, frames=100):
fig, (agent_ax, signal_ax) = plt.subplots(1, 2, sharey=True)
agent_ax.set_ylim(0, self.grid.shape[0])
agent_ax.set_xlim(0, self.grid.shape[1])
signal_ax.set_ylim(0, self.grid.shape[0])
signal_ax.set_xlim(0, self.grid.shape[1])
agent_mat = agent_ax.matshow(self.display_grid(),
vmin=0, vmax=10)
signal_mat = signal_ax.matshow(self.signal_display(virus),
vmin=0, vmax=20)
fig.colorbar(signal_mat)
def anim_update(tick):
self.update()
self.diffuse()
agent_mat.set_data(self.display_grid())
signal_mat.set_data(self.signal_display(virus))
return agent_mat, signal_mat
anim = animation.FuncAnimation(fig, anim_update, frames=frames,
interval=3000, blit=False)
if fname:
anim.save(fname, fps=5, extra_args=['-vcodec', 'libx264'])
else:
plt.show()
According to the matplotlib documentation
Because of how matshow() tries to set the figure aspect ratio to be the one of the array, if you provide the number of an already existing figure, strange things may happen.
I think you're better off using imshow instead (which I believe is what matshow calls. That has an aspect keyword argument which you could use if it doesn't work automatically.
Also according to the matplotlib documentation,
Sets origin to ‘upper’, ‘interpolation’ to ‘nearest’ and ‘aspect’ to equal.
I think you want to do the first two, but leave aspect as auto.
Well, one simple solution would be to just specify the width of the figure when creating it:
fig, (agent_ax, signal_ax) = plt.subplots(1, 2, sharey=True,
figsize=(16,6))

Matplotlib Contour Clabel Location

I would like to control the location of matplotlib clabels on a contour plot, but without utilizing the manual=True flag in clabel. For example, I would like to specify an x-coordinate, and have labels created at the points that pass through this line. I see that you can get the location of the individual labels using get_position(), but I am stuck at that. Any help would be greatly appreciated. Thanks!
Yes, there now is a way to control label locations!
https://github.com/matplotlib/matplotlib/pull/642
plt.figure()
CS = plt.contour(X, Y, Z)
manual_locations = [(-1, -1.4), (-0.62, -0.7), (-2, 0.5), (1.7, 1.2), (2.0, 1.4), (2.4, 1.7)]
plt.clabel(CS, inline=1, fontsize=10, manual=manual_locations)
No, there is no way built into matplotlib to do that. You are supposed to either live with the default locations or go fully interactive with manual and using the mouse.
You might want to file this as a bug report upstream so they can improve their algorithms.
There are multiple options to work around this. The first one is to programmatically place text on the contour figure. You will not be able to reliably remove the lines underneath the text this way. Assuming you have a contour c you can find the contour lines in c.collections. For every contour line invoke get_paths and place your text on that path.
The other option would be to replace the code for manual placement (in matplotlib.contour.BlockingContourLabeler) or tweak the code that finds the label positions (in matplotlib.contour.locate_label), but both functions are pretty dense. If you can come up with a working replacement for locate_label just overwrite the old method in your plotting macro
def your_locate_label(self, linecontour, labelwidth):
# some magic
pass
ar = np.array([[1,0], [0,1]]
c = matplotlib.contour(ar)
c.locate_label = your_locate_label
c.clabel()
Btw, if you use ipython you can easily view the function source from your interactive session with
%psource c.clabel
or directly invoke your $EDITOR on the file were it is defined with
%edit c.clabel

Categories

Resources