Chaco: 2 tools write the same metadata key - python

I have this problem with chaco.
In the plot, I need select some points (are points that I generate). This points, I can select with two tools: RangenSelection and ScatterInspector. If I work with only one tool, the code work well and I can detect with points I select, but when I work with both tools, both tools write the same metadata name: selections. This is the most important part of the code:
#this are all the tools.append
my_plot.tools.append(ScatterInspector(my_plot, selection_mode="toggle", persistent_hover=False))
my_plot.overlays.append(
ScatterInspectorOverlay(my_plot,
hover_color = "transparent",
hover_marker_size = 10,
hover_outline_color = "purple",
hover_line_width = 2,
selection_marker_size = 8,
selection_color = "red")
)
my_plot.tools.append(RangeSelection(my_plot, left_button_selects = False, rigth_button_selects = True, auto_handle_event = False))
my_plot.overlays.append(RangeSelectionOverlay(component=my_plot))
my_plot.tools.append(PanTool(my_plot))
my_plot.overlays.append(ZoomTool(my_plot, drag_button="right"))
return plot
#the rest of the code
def _metadata_handler(self):
sel_indices = self.index_datasource.metadata.get('selections', [])
su = self.index_datasource.metadata.get('annotations', [])
print su
print "Selection indices:", sel_indices
def _plot_default(self):
plot = _create_plot_component()
# Retrieve the plot hooked to the tool.
my_plot = plot.plots["my_plot"][0]
# Set up the trait handler for the selection
self.index_datasource = my_plot.index
self.index_datasource.on_trait_change(self._metadata_handler,
"metadata_changed")
return plot
When I run the code, and see what are in annotations, is always empty. But in selections the code write with both tools and this give an error.
How can I tell to some tool in where metadata key write??
Thanks for your help.

The solution is put metadata_name="annotations" in RangeSelection and in RangeSelectionOverlay

Related

How do i make a moving polygon disappear at a certain position?

I'm new to Python and Psychopy and have to do a project for university. I think it's a rather easy question, but i can't seem to figure it out.
I'm supposed to make a time-to-contact-task. The idea is that i have a polygon (a triangle) that moves on the x-axis from the left side of the screen to the right. At the right side of the screen is another polygon (a vertical line) that doesn't move. The testperson should press a key if the triangle is at the same position as the line. The moving triangle should disappear at a certain point (around the middle of the screen), so that the testperson should have to guess the arrival time of the triangle at the line.
Right now, this is my code:
at 'Begin routine':
Zeit = core.MonotonicClock()
origpos = meinPolygon.pos
aktpos = origpos
at 'Each frame':
aktpos[0] = origpos[0] + float(Geschwindigkeit) *(Zeit.getTime()*Beschleunigung)
aktpos[1] = origpos[1] + float(0) * Zeit.getTime()
meinPolygon.pos = aktpos
if aktpos = [1]:
polygon.opacity(0)
if aktpos[0] = polygon.pos[0]:
print(Zeit)
So i was thinking, that if the moving polygon reaches a certain position (eg. x=1), the opacity should change to 0, so that the polygon isn't visible anymore. But my code doesn't seem to work this way (Syntax Error). And i'm not sure how to put the x and y value of the position? I don't care about y, because its always 0.
And we want the time printed, when the triangle meets the line, so that we can calculate the reaction-time of the testperson.
I hope i described the situation understandable.
Thanks in advance for your help!
here is a version for using PsychoPy without the Builder tool:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from psychopy import core, info, visual, event
from psychopy import monitors
from psychopy.constants import NOT_STARTED, STARTED, FINISHED
from psychopy.iohub.client import launchHubServer
#INIT
io = launchHubServer()
display = io.devices.display
kb = io.devices.kb; mouse = io.devices.mouse
mon = monitors.Monitor(name = display.getPsychopyMonitorName(), autoLog = True)
win = visual.Window([1440, 900], units='pix', monitor = mon, winType='pyglet',
fullScr = False, waitBlanking = True, useFBO = True, useLights = False,
allowStencil=False, allowGui = True, screen = display.getIndex())
win._setupGL(); core.wait(.1)
runtime_info = info.RunTimeInfo(win = win, refreshTest = 'grating', verbose = True)
win_w = runtime_info['windowSize_pix'][0]; win_h = runtime_info['windowSize_pix'][1]
#suppose BEGIN ROUTINE?
LOCATION_TOLERANCE = 4 #screen pixels
POLYGON_SPEED = 0.1 #pixels per frame
POLYGON_ACCEL = 1.005
mainPolygon = visual.Polygon(win, edges=3, radius=50, units='pix', pos=(-win_w/2*0.75,0),
lineColor=[0, 1, 0], fillColor=[0, 1, 0], interpolate=False, autoDraw=True)
targetPolygon = visual.Polygon(win, edges=4, radius=20, units='pix', pos=(win_w/2*0.60,0), ori=45,
lineColor=[1, 1, 1], fillColor=[1, 1, 1], interpolate=False, autoDraw=True)
#ROUTINE
global_monotonic = core.MonotonicClock(); trial_clock = core.Clock()
future_flip_time = win.getFutureFlipTime(clock='now')
trial_clock.reset(-future_flip_time)
t = 0; frame_n = -1
mainPolygon.status = NOT_STARTED; routine_running = True
mainPolygon.t_thresholded, mainPolygon.t_targetreached, mainPolygon.t_keypressed = 0.0, 0.0, 0.0
while routine_running:
t = trial_clock.getTime(); frame_n = frame_n + 1
#suppose EACH FRAME?
if routine_running:
curr_xpos, curr_ypos = mainPolygon.pos[0], mainPolygon.pos[1]
mainPolygon.setPos((curr_xpos + POLYGON_SPEED, curr_ypos), log=True)
POLYGON_SPEED *= POLYGON_ACCEL
if curr_xpos > LOCATION_TOLERANCE and not mainPolygon.t_thresholded:
mainPolygon.t_thresholded = global_monotonic.getTime()
mainPolygon.setOpacity(0)
print(f"THRESHOLD LOCATION: trial_clock = {t:.3f}, frame_n = {frame_n:d}")
#FIXME use psychopy.visual.helpers.pointInPolygon() or polygonsOverlap()
if targetPolygon.pos[0] - curr_xpos < LOCATION_TOLERANCE and not mainPolygon.t_targetreached:
mainPolygon.t_targetreached = global_monotonic.getTime()
print(f"TARGET REACHED: trial_clock = {t:.3f}; monotonic = {mainPolygon.t_targetreached:.3f}")
if len(event.getKeys(keyList=['space'])) and not mainPolygon.t_keypressed:
mainPolygon.t_keypressed = global_monotonic.getTime()
print(f"KEY PRESSED: trial_clock = {t:.3f}; frame_n = {frame_n:d}")
win.flip()
if (mainPolygon.t_keypressed and mainPolygon.t_targetreached):
POLYGON_SPEED = 0; mainPolygon.setOpacity(1)
routine_running = False;
if not routine_running:
break
#REPORT
print(f"")
print(f"REACTION DIFFERENCE: monotonic_diff = {mainPolygon.t_keypressed-mainPolygon.t_targetreached:.3f}")
win.flip(); event.waitKeys()
#FINALIZE
io.quit(); win.close()
core.quit()
A syntax error indicates you haven't got the characters correct in your code, like brackets that don't match etc. The logic may be fine. Take note of what the syntax error is pointing you to and check that line as well as the lines just above (sometimes an error on one line only shows up on the next).
In your case you have if aktpos = [1]: but a single = is for assignment. To test equality you need ==. This is a really common syntax error, even for experienced will make this typo so watch out for it.
There's actually at least one more problem though in your code because aktpos is always going to be a position with an x,y value. It will never be equal to [1] which is what you're currently (trying) to test. So the comparison isn't quite right. And how exact do you need that location to be? Think about what distance in x and y before you consider it to be a single location because I expect it will never be EXACTLY the same given that the stimulus can make sub-pixel movements

Increase text of the dropdown menu - Python

I am trying to create dropdown menu using the following code on Python.
pqrs = ['Segment1', 'Segment2', 'Segment3']
#Segment Criteria
Segment_selected = widgets.Text()
# print('=' * term_size.columns)
# print('\n' +"\033[1m" + 'Select a Segment criteria for Selecting HCP Universe' + "\033[0m")
# python code to run in jupyter notebook
from ipywidgets import interact, interactive, Layout
def lx(Segmentation):
Segment_selected.value = str(Segmentation)
int_widget = interactive(lx, Segmentation=pqrs,)
int_widget.children[0].layout = Layout(width='400px',height = '40px')
display(int_widget)
This is generating the following output:
Code Output
Now, the problem is I want to show the complete text on the left side of the dropdown. It appears as "Segmentati..." in my case which I want it to be "Segmentation" in my case. But I am unable to do so.
Can you please help me?
Initially comments widths are fixed. You can set a style to make it bigger - this will reduce the overall other sizes of your widget:
pqrs = ['Segment1', 'Segment2', 'Segment3']
int_widget = interactive(lx, Segmentation=pqrs, )
int_widget.children[0].layout = Layout(width='auto',height = '40px')
int_widget.children[0].style = {'description_width': '200px'} # increase size
display(int_widget)
to get:
The essential documentation for this is here: Widget Styling#Description
Try "auto" or "initial" for auto-fitting the description_width.

Adding text into groups does not work for svgwrite

I'm writing some basic script to create basic charts using python's svgwrite. I have successfully been able to create groups with other items, such as circles, paths and lines. However when adding several text elements into a group those are not properly shown in a group when I open the svg figure with Inkscape. The text shows up all right, but it is just not grouped.
This is my piece of code:
# Create group for constellation names
const_names = dwg.add(dwg.g(id='constellation_names',
stroke='none',
fill=config.constellation_name_font.color.get_hex_rgb(),
fill_opacity=config.constellation_name_font.color.get_float_alpha(),
font_size=config.constellation_name_font.size*pt,
font_family=config.constellation_name_font.font_family))
log.warning("Constellation name groups are not working!")
if config.constellation_name_enable:
w, h = constellation.get_mean_position()
# Add every text item into the group
const_names.add(dwg.text(constellation.name,
insert=(w*pt, h*pt),
)
)
Turns out this was a type-8 error (I had a bug on the code). This is how my code ended up looking like. All text instances are grouped on a single group.
def _add_constellation_names(dwg, constellations, config):
const_names = dwg.add(dwg.g(id='constellation_names',
stroke='none',
fill=config.constellation_name_font.color.get_hex_rgb(),
fill_opacity=config.constellation_name_font.color.get_float_alpha(),
font_size=config.constellation_name_font.size*pt,
font_family=config.constellation_name_font.font_family))
for constellation in constellations:
kwargs = {}
if constellation.custom_color != None:
kwargs["fill"] = constellation.custom_color.get_hex_rgb()
kwargs["fill_opacity"] = constellation.custom_color.get_float_alpha()
w, h = constellation.get_mean_position()
const_names.add(dwg.text(constellation.get_display_name(),
insert=(w*pt, h*pt),
text_anchor="middle",
**kwargs,
)
)

Bokeh not updating plot line update from CheckboxGroup

I'm following this great tutorial to play a little bit with Bokeh.
Basically, I have a figure with two independent line added to it. Everything is rendered properly but when I want to update nothing happens even if I checked that the new ColumnDataSource is well updated with the new values.
I render it using the command : bokeh serve --show my_app
Here is how I create my figure :
src_p6 = make_dataset(["select_a", "select_b"])
p6 = make_plot(src_p6)
select_selection = CheckboxGroup(labels=["select_a", "select_b"], active = [0, 1])
select_selection.on_change('active', update)
controls = WidgetBox(select_selection)
curdoc().add_root(column(controls, p6, width=1200))
def make_dataset(select_list):
if 'select_a' in select_list and 'select_b' in select_list:
tmp = pd.DataFrame({'time': df["time"],
'a': df["a"],
'b': df["b"]
})
elif 'select_a' in select_list and 'select_b' not in select_list:
tmp = pd.DataFrame({'time': df["time"],
'a': df["a"]
})
elif 'select_a' not in select_list and 'select_b' in select_list:
tmp = pd.DataFrame({'time': df["time"],
'b': df["b"]
})
else:
tmp = pd.DataFrame({'time': df["time"]
})
src = ColumnDataSource(tmp)
return src
def make_plot(plot_src):
p = figure(plot_width=1000, plot_height=600,
title="Line x2 with hover and update",
x_axis_label='Time',
y_axis_label='Values'
)
hover_content = [("Time", "#time")]
if 'a' in plot_src.data:
p.line(x='time', y='a', source=plot_src, legend="A", line_color="blue")
hover_content.append(("A", "#a"))
if 'b' in plot_src.data:
p.line(x='time', y='b', source=plot_src, legend="B", line_color="red")
hover_content.append(("B", "#b"))
p.add_tools(HoverTool(tooltips=hover_content))
return p
def update(attr, old, new):
print(src_p6.data)
select_to_plot = [select_selection.labels[i] for i in select_selection.active]
new_src = make_dataset(select_to_plot)
src_p6.data = new_src.data
print("**********************")
print(src_p6.data) # I see here that the data are well updated compared to the first print
My incoming data is JSON and looks like this :
# {"data":[{"time":0,"a":123,"b":123},{"time":1,"a":456,"b":456},{"time":2,"a":789,"b":789}]}
# data = json.load(data_file, encoding='utf-8')
# df = pd.io.json.json_normalize(data['data'])
Thank you for your insights
This will not function correctly:
src_p6.data = new_src.data
The ColumnDataSource is one of the most complicated objects in Bokeh, e.g. the .data object on a CDS is not a plain Python dict, it has lots of special instrumentation to make things like efficient streaming possible. But it is also tied to the CDS it is created on. Ripping the .data out of one CDS and putting assigning it to another is not going to work. We probably need to find a way to make that complain, I am just not sure how, offhand.
In any case, you need to assign .data from a plain Python dict, as all the examples and demonstrations do:
src_p6.data = dict(...)
For your sepcific code, that probably means having make_dataset just return the dicts it creates directly, instead of putting them in dataframes then making a CDS out of that.
First of all thanks to #bigreddot for his time and guidance.
One of my biggest problem was that I didn't actually wanted to update the values but rather just show/hide it, so just removing it from the source was not working.
Adding line in my make_plot function with a if statement doesn't work also because it is only called the first time the plot is created. For updates, it update the value on the figure but do not reconstruct everything from scratch... So if you start with only one line, I don't know how it will create a new line, if it's even possible...
I started to simplify my make_dataset function to only return a simple Python dict :
tmp = dict(time=df["time"], a=df["a"], b=df["b"])
But when I wanted to remove a line, I used an empty array even if there is better solutions (I was just playing with Bokeh here) : Line ON/OFF, Interactive legend
empty = np.empty(len(df["time"])); empty.fill(None)
tmp = dict(time=df["time"], a=df["a"], b=empty)
When I first create my plot I then do :
src_p6 = ColumnDataSource(data=make_dataset(["select_a", "select_b"]))
p6 = make_plot(src_p6)
And the update function update the .data of the ColumnDataSource with a basic Python dict :
new_src = make_dataset(select_to_plot)
src_p6.data = new_src

Python-PPTX : Data Label Positions not working for Doughnut Chart

I have a Chart Placeholder, into which I have inserted a chart of chart_type 'DOUGHNUT'. I've added data labels to it and want to change their positions. For some reason, the method given in the documentation has no effect on my chart.
Here is my code, please help if I'm doing something wrong -
from pptx import Presentation
from pptx.chart.data import ChartData
from pptx.enum.chart import XL_CHART_TYPE, XL_LABEL_POSITION, XL_DATA_LABEL_POSITION, XL_TICK_MARK, XL_TICK_LABEL_POSITION
chart_data = ChartData()
chart_data.add_series('', tuple(input_chart_data[x] for x in input_chart_data))
graphic_frame = content_placeholder.insert_chart(XL_CHART_TYPE.DOUGHNUT, chart_data)
chart = graphic_frame.chart
chart.has_legend = False
#Adding Data-Labels with custom text
chart.plots[0].has_data_labels = True
data_labels = chart.plots[0].data_labels
i = 0
series = chart.series[0]
for point in series.points:
fill = point.format.fill
fill.solid()
fill.fore_color.rgb = RGBColor(<color_code>)
point.data_label.has_text_frame = True
#Assigning custom text for data label associated with each data-point
point.data_label.text_frame.text = str(chart_data.categories[i].label) + "\n" + str(float(chart.series[0].values[i])) + "%"
for run in point.data_label.text_frame.paragraphs[0].runs:
run.font.size = Pt(10)
i+=1
data_labels.position = XL_LABEL_POSITION.OUTSIDE_END
PowerPoint is finicky about where you place certain chart attributes and feels free to ignore them when it wants (although it does so consistently).
A quick option worth trying is to set the value individually, point-by-point in the series. So something like:
for point in series.points:
point.data_label.position = XL_LABEL_POSITION.OUTSIDE_END
The most reliable method is to start by producing the effect you want by hand, using PowerPoint itself on an example chart, then inspecting the XML PowerPoint produces in the saved file, perhaps using opc-diag. Once you've identified what XML produces the desired effect (or discovered PowerPoint won't let you do it), then you can proceed to working out how to get the XML generated by python-pptx. That might make a good second question if you're able to get that far.
I made it work by writing the below code.
def apply_data_labels(self, chart):
plot = chart.plots[0]
plot.has_data_labels = True
for series in plot.series:
values = series.values
counter = 0
for point in series.points:
data_label = point.data_label
data_label.has_text_frame = True
data_label.text_frame.text = str(values[counter])
counter = counter + 1
the cause of error is setting the label position. no matter what you set it asks to repair the PPT. will have to drill down more to see why is it so.
Also to save some more time the formatting doesn't works(font color, size)
If anybody has any leads then please help.
To add on Vibhanshu's response, I could get the formatting (font type, font color, size etc) to work using the following code:
for idx, point in enumerate(chart.series[0].points):
# set position
point.data_label.position = XL_LABEL_POSITION.OUTSIDE_END
# set text
point.data_label.has_text_frame = True
point.data_label.text_frame.text = "This is an example"
# set formatting
for paragraph_idx, paragraph in enumerate(point.data_label.text_frame.paragraphs):
paragraph.line_spacing = 0.6 # set paragraph line spacing
for run in paragraph.runs:
run.font.size = Pt(30) #set font size
run.font.name = 'Poppins Medium' #set font name
run.font.color.rgb = RGBColor.from_string("FF0000") #set font color

Categories