How do I send NLTK plots to files? - python

I'm using NLTK to create dispersion plots and do a few other things. Trouble is, I have to manually close the window that creating a dispersion plot opens to get the code to continue running. How can I send the plot to a file and keep the script moving? I assume I'll have the same problem with other plots. I can see from the NLTK source that dispersion_plot already includes pylab.show() so maybe this isn't possible without writing my own plotting function?
Here's my code that stops at line 2 until I close the Python window that opens with the plot.
1 # do some analysis
2 disp_plot(days, key_terms)
3 diversity_table(days, "Day")
Here's the disp_plot function:
# dispersion plots for search terms
def disp_plot(texts, terms):
concat_text = ''.join(texts.values())
tokens = nltk.word_tokenize(concat_text)
text = nltk.Text(tokens)
text.dispersion_plot(terms)

I ran into the same problem and solved it by reassigning pylab.show to my own function. You might do something like this:
import pylab
counter = 0
def filename_generator():
global counter
to_return = 'myfig{0}.png'.format(counter)
counter += 1
return to_return
def my_show():
return pylab.savefig(filename_generator())
and change your disp_plot() to look like
def disp_plot(texts, terms):
concat_text = ''.join(texts.values())
tokens = nltk.word_tokenize(concat_text)
text = nltk.Text(tokens)
pylab_orig_show = pylab.show
pylab.show = my_show
text.dispersion_plot(terms)
pylab.show = pylab_orig_show
Some would argue about the global, but this is just a quick hack to get the library to do what you want.

Related

Print the return of a method in python

I'm fairly new to OOP in python and i cant seem to figure out if I'm doing this the right way. I have a first script called TP2_dat.py in which I solve a problem in AMPL and then at the end i retrieve the variable X as follows (I simplified the code):
import amplpy
import os
class Solver:
def __init__(self, set_k, larg_on, poids):
self.set_K = set_k
self.larg_on = larg_on
self.poids = poids
def solve(self):
...
X = ampl.getVariable('X')
X_val = X.getValues()
X_val_dic = X_val.toDict()
# print(X_val_dic)
return X_val_dic
I tried to do a print instead of a return from the first script and it worked. But now i want to print it from another script as follows so i dont get the None at the end of the print from the second script:
from TP2_dat import Solver
set_K = [1,2,3,4,5,6]
larg_on = [4,3,5,4,6,5]
poids = [0,4,5,2,3,6,4,0,4,3,5,3,5,4,0,4,7,8,2,3,4,0,3,3,3,5,7,3,0,5,6,3,8,3,5,0]
affichage = Solver(set_K, larg_on, poids)
affichage.solve()
print(X_val_dic)
The part that i dont understand is can i do something similar to this? Am i right in thinking to return the value of X_val_dic or should i do something else?
Thanks a lot for your help !!
Since the class method solve returns a value you need to set it equal to a variable or print it directly:
X_val_dic = affichage.solve()
print(X_val_dic)
or
print(affichage.solve())
See this article for more information on pythons variable scoping.

Strange behaviour when function returns NdOverlay to DynamicMap

I've encountered something very strange when having a function which generates an NdOverlay of Points to a DynamicMap, where the function is tied to panel widgets (I don't think the panel widgets are important).
The below code is a working example which produces the expected behavior. Whenever you change the widget values a new plot is generated with two sets of Points overlaid, with different colors and respective legend entries. Image shown below code.
a_widget = pn.widgets.Select(name='A', options=[1,2,3,4])
b_widget = pn.widgets.IntSlider(name='B', start=10, end=20, value=10)
widget_box = pn.WidgetBox(a_widget, b_widget, align='center')
#pn.depends(a=a_widget.param.value, b=b_widget.param.value)
def get_points(a, b):
return hv.NdOverlay({x: hv.Points(np.random.rand(10,10)) for x in range(1,3)})
points = hv.DynamicMap(get_points)
pn.Row(widget_box, points)
The second example shown below, is meant to demonstrate that in certain situations you might want to just simply return an empty plot and the way that I've done it in this example is done in the same way as in this example: http://holoviews.org/gallery/demos/bokeh/box_draw_roi_editor.html#bokeh-gallery-box-draw-roi-editor
The result of this code is an empty plot as expected when a == 1, but when a has values other than 1, the result is quite strange as illustrated in the image below the code.
The points all have the same color
When changing the slider for instance, some points are frozen and never changes, which is not the case in the above working example.
a_widget = pn.widgets.Select(name='A', options=[1,2,3,4])
b_widget = pn.widgets.IntSlider(name='B', start=10, end=20, value=10)
widget_box = pn.WidgetBox(a_widget, b_widget, align='center')
#pn.depends(a=a_widget.param.value, b=b_widget.param.value)
def get_points(a, b):
if a == 1:
return hv.NdOverlay({None: hv.Points([])})
else:
return hv.NdOverlay({x: hv.Points(np.random.rand(10,10)) for x in range(1,3)})
points = hv.DynamicMap(get_points)
pn.Row(widget_box, points)
While I can not help the observed issue with NdOverlay, creating plots with or without content can be done with the help of Overlay.
As b_widget is never used in your code, I removed it for simplicity.
a_widget = pn.widgets.Select(name='A', options=[1,2,3,4])
widget_box = pn.WidgetBox(a_widget, align='center')
#pn.depends(a=a_widget.param.value)
def get_points(a):
images = []
if a == 3:
images.append(hv.Points(np.random.rand(10,10), label='None'))
else:
for x in range(1,3):
images.append(hv.Points(np.random.rand(10,10), label=str(x)))
return hv.Overlay(images)
points = hv.DynamicMap(get_points)
pn.Row(widget_box, points)
The way how to use NdOverlay that is described in the documentation for NdOverlay is different to your approach, this might be a reason for the observed problems.
Anyway, to narrow down which part of the code is responsible for the observed issue, I removed all code that is not necessary to reproduce it.
For clarity, I renamed the values of a, and I also made sure, that a start value for a is provided.
It turned out while testing the code, that the if-else-statement is neither important, so I removed that too.
And just to make sure, that variables behave like expected, I added some print-statements.
This gives the following minimal reproducable example:
a_widget = pn.widgets.Select(name='A', value='Test', options=['Test','Test1', 'Test2'])
#pn.depends(a=a_widget.param.value)
def get_points(a):
dict_ = {}
dict_[str(a)] = hv.Points(np.random.rand(10,10))
print(dict_)
overlay = hv.NdOverlay(dict_)
print(overlay)
return overlay
points = hv.DynamicMap(get_points)
# using the server approach here to see the outpout of the
# print-statements
app = pn.Row(a_widget, points)
app.app()
When running this code, and choosing the different options in the select widget, it turns out that option Test is not updated, once one of the options Test1 and Test3 have been choosen.
When we change the default value in the first line like this
a_widget = pn.widgets.Select(name='A', value='Test2', options=['Test','Test1', 'Test2'])
now Test2 is not updated correctly.
So it looks like this is an issue of DynamicMap using NdOverlay.
So I suggest you report this issue to the developers (if not already done), either wait for new release or use a different approach (e.g. as shown above).

Build frames for a text animation in Wand

I'm trying to write an automated script in Wand on Python that builds the frames for a text animation by writing a caption of an image one letter at a time.
The problem is that when I write one letter using the caption command (documentation here http://docs.wand-py.org/en/0.4.4/wand/image.html) it writes a giant letter, while when I write the whole text, it is fitted nicely in the image.
I thought of a possible solution: write the first letter colored and the rest transparent and cycle through that, however the caption command is not capable of doing multicolored text as far as I know.
If someone could suggest me another option I would be grateful. I could use draw.text, however that doesn't automatically calculate when to go on the next line as far as I know...
My code looks like this:
imgname = random.choice(os.listdir('/home/gionny/Downloads/HighResImg'))
text = 'Hello, world! This is a slightly longer sentence.'
fontname = random.choice(os.listdir('/home/gionny/Downloads/font'))
with Image(filename='HighResImg/'+imgname) as i:
font = Font(path = 'font/'+fontname, color = Color('#fff'))
textWidth = i.width*2/3
textHeight = i.height*2/3
offsetLeft = (i.width - textWidth)/2
offsetTop = (i.height - textHeight)/2
with Image(filename='logo.gif') as l:
l.resize(80,80)
l.transparentize(0.7)
with Drawing() as draw:
draw.composite(operator='atop', left=i.width-90, top=i.height-90, width=l.width, height=l.height, image=l)
for c in range(0, len(text)):
caption = i.caption(text = text[c], left = offsetLeft, top = offsetTop, width=textWidth, height=textHeight, font = font, gravity = 'center')
print(caption)
cl = i.clone()
cl.format = 'jpeg'
cl.save(filename='Text/text'+str(c)+'.jpg')
cl.destroy()
If someone could suggest me another option I would be grateful. I could use draw.text, however that doesn't automatically calculate when to go on the next line as far as I know...
There's no quick way around it, you are responsible for calculating the x,y coordinates with each iteration. Especially when using mixed fonts pulled at random.
The method wand.drawing.Drawing.get_font_metrics has be provided for this sort of thing. Simply keep an accumulator & update with each iteration.
from wand.image import Image
from wand.color import Color
from wand.drawing import Drawing
with Image(width=400, height=250, background=Color("skyblue")) as background:
leftOffset = 35 # <= Starting position.
topOffset = background.height/2;
for letter in "Hello World":
with Drawing() as ctx:
ctx.font = "TimesNewRoman"
ctx.font_size = 64.0
metrics = ctx.get_font_metrics(background, letter)
ctx.text(leftOffset, int(topOffset+metrics.text_height/4), letter)
with Image(width=background.width,
height=background.height,
background=Color("transparent")) as frame:
ctx.draw(frame)
background.sequence.append(frame)
leftOffset += int(metrics.text_width) # <= Adjust for next iteration.
background.save(filename="output.gif")
Now for repeating the next-line process, just increase topOffset by the font metrics text_height if the leftOffset is greater than canvas width.

Storing output from Python function necessary despite not using output

I am trying to understand why I must store the output of a Python function (regardless of the name of the variable I use, and regardless of whether I subsequently use that variable). I think this is more general to Python and not specifically to the software NEURON, thus I put it here on Stackoverflow.
The line of interest is here:
clamp_output = attach_current_clamp(cell)
If I just write attach_current_clamp(cell), without storing the output of the function into a variable, the code does not work (plot is empty), and yet I don't use clamp_output at all. Why cannot I not just call the function? Why must I use a variable to store the output even without using the output?
import sys
import numpy
sys.path.append('/Applications/NEURON-7.4/nrn/lib/python')
from neuron import h, gui
from matplotlib import pyplot
#SET UP CELL
class SingleCell(object):
def __init__(self):
self.soma = h.Section(name='soma', cell=self)
self.soma.L = self.soma.diam = 12.6517
self.all = h.SectionList()
self.all.wholetree(sec=self.soma)
self.soma.insert('pas')
self.soma.e_pas = -65
for sec in self.all:
sec.cm = 20
#CURRENT CLAMP
def attach_current_clamp(cell):
stim = h.IClamp(cell.soma(1))
stim.delay = 100
stim.dur = 300
stim.amp = 0.2
return stim
cell = SingleCell()
#IF I CALL THIS FUNCTION WITHOUT STORING THE OUTPUT, THEN IT DOES NOT WORK
clamp_output = attach_current_clamp(cell)
#RECORD AND PLOT
soma_v_vec = h.Vector()
t_vec = h.Vector()
soma_v_vec.record(cell.soma(0.5)._ref_v)
t_vec.record(h._ref_t)
h.tstop = 800
h.run()
pyplot.figure(figsize=(8,4))
soma_plot = pyplot.plot(t_vec,soma_v_vec)
pyplot.show()
This is a NEURON+Python specific bug/feature. It has to do with Python garbage collection and the way NEURON implements the Python-HOC interface.
When there are no more references to a NEURON object (e.g. the IClamp) from within Python or HOC, the object is removed from NEURON.
Saving the IClamp as a property of the cell averts the problem in the same way as saving the result, so that could be an option for you:
# In __init__:
self.IClamps = []
# In attach_current_clamp:
stim.amp = 0.2
cell.IClamps.append(stim)
#return stim

Python Command to render vray

Making a small script to write out .vrscenes for me, however I'm a little stick with getting them to render.
I'm using the pymel render command, which seems to call the maya software renderer rather than vray itself ignoring all the rendersettings I have set. Anyone know if there is an alternative command?
Thanks, sorry if this has been asked before!
script as follows;
frames = 100
split = 1
location = "/Users/adamcheshire/Desktop/testing/testScene"
# Create a list of render frames evenly split
framesToRender = frames/split
listToRender = []
start = 1
end = framesToRender
for i in range(0, split):
listToRender.append([start, end])
start += framesToRender
end += framesToRender
# Make sure final element == to frames
listToRender[-1] = [listToRender[-1][0], frames]
# init vrscene mode
vray = pm.ls('vraySettings')[0]
DRG = pm.ls('defaultRenderGlobals')[0]
vray.vrscene_render_on.set(0)
vray.vrscene_on.set(1)
DRG.animation.set(1)
vray.animBatchOnly.set(0)
# Set and Render
for i in range(0, len(listToRender)):
DRG.startFrame.set(listToRender[i][0])
DRG.endFrame.set(listToRender[i][1])
vray.vrscene_filename.set(location+"_s"+str(listToRender[i][0])+"_e"+str(listToRender[i][1])+".vrscene")
pm.render()
#pm.batchRender()
i think it's something like:
pm.vrend()

Categories

Resources