From 1b431a0521b57041dda24566c2d040c6c036af49 Mon Sep 17 00:00:00 2001 From: Jon Peirce Date: Thu, 4 Nov 2021 11:24:08 +0000 Subject: [PATCH 01/10] RF: for checking current stats we should certainly use usage.psychopy.org Need to check if we should use this to SEND stats as well --- docs/source/about/testimonials.rst | 2 +- docs/source/resources/vss-workshop.rst | 2 +- psychopy/app/Resources/tips.txt | 2 +- psychopy/app/Resources/tips_ja_JP.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/source/about/testimonials.rst b/docs/source/about/testimonials.rst index 2cc288d851..f15e74914a 100644 --- a/docs/source/about/testimonials.rst +++ b/docs/source/about/testimonials.rst @@ -2,7 +2,7 @@ Testimonials - what do people think of PsychoPy? ===================================================== -OK, so we know that `PsychoPy has quite a lot of users `_ +OK, so we know that `PsychoPy has quite a lot of users `_ We also know that quite a few people have written `manuscripts that cited PsychoPy `_ diff --git a/docs/source/resources/vss-workshop.rst b/docs/source/resources/vss-workshop.rst index 5e85653a47..7e226c8225 100644 --- a/docs/source/resources/vss-workshop.rst +++ b/docs/source/resources/vss-workshop.rst @@ -4,7 +4,7 @@ VSS 2012 Satellite Event, May 2012 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -PsychoPy is a modern, powerful easy-to-use software package for conducting psychophysics and imaging studies. It's become the package of choice in thousands of labs worldwide (see https://www.psychopy.org/usage.php). +PsychoPy is a modern, powerful easy-to-use software package for conducting psychophysics and imaging studies. It's become the package of choice in thousands of labs worldwide (see https://usage.psychopy.org ). Using the Python programming language (a more powerful and free alternative to Matlab) PsychoPy can generate your stimuli in real-time and collect responses with high temporal precision. diff --git a/psychopy/app/Resources/tips.txt b/psychopy/app/Resources/tips.txt index 5275bb8f16..28cb40914b 100644 --- a/psychopy/app/Resources/tips.txt +++ b/psychopy/app/Resources/tips.txt @@ -29,7 +29,7 @@ Coder: You can comment/uncomment entire blocks of code with Ctrl-' and Ctrl-Shif Did your stimulus not appear? Was it really tiny? Setting units='pix' and size=0.1 means it has a size of 0.1 pixels! The default color values in PsychoPy range from -1 to +1, with 0 being the mean grey of the screen. So black is like the maximum decrement from grey and white is an increment. Right? Data can be output in many different formats, but it's worth saving the 'psydat' (aka pickle) format as well as the others. Although this isn't "human readable" it stores more information than excel/csv files including an entire copy of your actual experiment! -You can see how many people used PsychoPy this month at https://www.psychopy.org/usage.php +You can see how many people used PsychoPy this month at https://usage.psychopy.org Builder: You can increase or decrease the display size of the flow using "Ctrl + =" or "Ctrl + -" (like some web browsers). Similarly, you can change the display size of routines using "Ctrl + Shift + =" and "Ctrl + Shift + -". (Use "Cmd" on Mac, not "Ctrl".) In the Builder, you can display details about the trials and sequences of loops. Press "Ctrl + =" when at the largest view size. To turn off, press "Ctrl + -" from the smallest view size. Builder: To put a $ symbol in a stimulus, you need to use \$, like this: "You win \$5.00!". (This is only for input boxes, and not for code components.) diff --git a/psychopy/app/Resources/tips_ja_JP.txt b/psychopy/app/Resources/tips_ja_JP.txt index 2b89a7f108..a36a0cff60 100644 --- a/psychopy/app/Resources/tips_ja_JP.txt +++ b/psychopy/app/Resources/tips_ja_JP.txt @@ -26,7 +26,7 @@  刺激が表示されなくて困っていませんか? 刺激の単位をpixに変更したのにサイズを0.1のままにしていると大きさがたったの0.1ピクセルになってしまいますよ!  PsychoPyでは色のRGB値を-1.0から1.0で表します。RGB値がすべて0.0なら灰色、-1.0なら黒、1.0なら白です。  データはさまざまな形式で出力できますが、psydat(pickle形式)ファイルはPythonユーザーにとってはとても便利です。直接エディタで開いて読むことは出来ませんが、実験条件ファイルを含む実験の全ての情報のコピーが保存されています。 - PsychoPyの月別利用者数を https://www.psychopy.org/usage.php で見ることが出来ます。 + PsychoPyの月別利用者数を https://usage.psychopy.org で見ることが出来ます。  Builderでは Ctrl + = または Ctrl + -でFlowのアイコンの大きさを変更できます。同様に、Ctrl + Shift + =とCtrl + Shift + -でRoutineのアイコンの大きさを変更できます。(Macの人はCtrlの代わりにCmdキーを使いましょう)  Builderでフローの表示サイズが最大の時にCtrl + =を押すとループやルーチンの詳細が表示されます。表示サイズが最小の時にCtrl + -を押すと表示されなくなります。  Builderで"You win \$5.00!"のように$記号を含む文字列を表示したい場合は、$の前に\を付けて\$と書くに必要があります。ただしCodeコンポーネントでは必要ありません。 From b9c038e140d42cf1149599e97f45604d5676c885 Mon Sep 17 00:00:00 2001 From: Jon Peirce Date: Thu, 4 Nov 2021 11:54:55 +0000 Subject: [PATCH 02/10] RF: alter the URL for *sending* usage stats --- psychopy/app/_psychopyApp.py | 2 +- psychopy/app/connections/updates.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/psychopy/app/_psychopyApp.py b/psychopy/app/_psychopyApp.py index 0025090fd1..663fb2374a 100755 --- a/psychopy/app/_psychopyApp.py +++ b/psychopy/app/_psychopyApp.py @@ -382,7 +382,7 @@ def onInit(self, showSplash=True, testMode=False): for exp in [file for file in args if file.endswith('.psyexp') or file.endswith('.py')]: self.runner.panel.runFile(exp) - # send anonymous info to www.psychopy.org/usage.php + # send anonymous info to https://usage.psychopy.org # please don't disable this, it's important for PsychoPy's development self._latestAvailableVersion = None self.updater = None diff --git a/psychopy/app/connections/updates.py b/psychopy/app/connections/updates.py index 17166e6b5e..51025d42a4 100644 --- a/psychopy/app/connections/updates.py +++ b/psychopy/app/connections/updates.py @@ -628,7 +628,7 @@ def sendUsageStats(): systemInfo = "win32_v" + platform.version() else: systemInfo = platform.system() + platform.release() - u = "https://www.psychopy.org/usage.php?date=%s&sys=%s&version=%s&misc=%s" + u = "https://usage.psychopy.org/submit.php?date=%s&sys=%s&version=%s&misc=%s" URL = u % (dateNow, systemInfo, v, miscInfo) try: req = urllib.request.Request(URL) From 70bde547a767fc72dd98a106c0b18ea1fb3073e2 Mon Sep 17 00:00:00 2001 From: Todd Parsons Date: Wed, 5 Apr 2023 14:37:44 +0100 Subject: [PATCH 03/10] BF: Save prefs just once after closing all frames --- psychopy/app/_psychopyApp.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/psychopy/app/_psychopyApp.py b/psychopy/app/_psychopyApp.py index fa2a791faf..d9a45a05a2 100644 --- a/psychopy/app/_psychopyApp.py +++ b/psychopy/app/_psychopyApp.py @@ -1006,10 +1006,10 @@ def quit(self, event=None): for frame in self.getAllFrames(): try: frame.closeFrame(event=event, checkSave=False) - # must do this before destroying the frame? - self.prefs.saveAppData() except Exception: pass # we don't care if this fails - we're quitting anyway + # must do this before destroying the frame? + self.prefs.saveAppData() #self.Destroy() # Reset streams back to default From 90b28e4dd2acd710e85514e44474e1ac18b7fc8a Mon Sep 17 00:00:00 2001 From: Jon Peirce Date: Thu, 13 Apr 2023 12:08:32 +0100 Subject: [PATCH 04/10] DOCS: updated changelog for 2023.1.2 --- psychopy/CHANGELOG.txt | 84 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 83 insertions(+), 1 deletion(-) diff --git a/psychopy/CHANGELOG.txt b/psychopy/CHANGELOG.txt index c27d356fa1..236a51ac0a 100644 --- a/psychopy/CHANGELOG.txt +++ b/psychopy/CHANGELOG.txt @@ -15,10 +15,92 @@ to run on the same PsychoPy version even where a different version is installed That setting often even allows PsychoPy to run experiments from versions that have not yet been installed! If the dependencies haven't changed it will run. + +PsychoPy 2023.1 +--------------- + +# Release series 2023.1. Highlights + +- **Pavlovia Surveys:** can now be integrated into PsychoPy online studies. You still create your + survey in the Pavlovia Survey Creator (on you Pavlovia Dashboard) but you can then incorporate + them as either a link or an embedded json file into your PsychoJS study. This only works for + online studies at present +- **Panorama Stimuli:** now supported in PsychoPy (lab-based) studies. You can add a photo-sphere + as a stimulus (e.g. create them in Street View app on Android phones) and then insert them into + Builder and explore +- **Plugins and Packages:** You can now add packages to your PsychoPy installation with a GUI that + installs new packages to your user folder (without needing admin rights). Some of PsychoPy's + existing functionality has also moved out to "Plugins" + + - For users, plugins mean more control over what functionality you want PsychoPy to support + - For developers, plugins mean keeping more independence over your code and ownership + +- **Speech Point:** on TextBox allows a tail to be added giving the impression of a cartoon speech + bubble (lab-based only, currently) +- **MovieStim:** further improvements to performance and fixes + + +On top of the [new features added in 2023.1 series](https://github.com/psychopy/psychopy/releases/tag/2023.1.0) + +## Fixes + +* Fix crash following gamma semi-auto correction (when laying out dialog box) dialog box by @TEParsons in #5452 +* Crashing due to outdated `core.getFromNames` in Mouse by @TEParsons in #5474 +* Setting Image as a numpy array caused a TypeError by @TEParsons in #5453 +* Handle invalid paths when stringifying params by @TEParsons in #5465 +* Swap all references to Panorama.altitude with Panorama.elevation by @TEParsons in #5471 +* Fix typo in Survey routine - `stauts` rather than `status` by @TEParsons in #5468 +* If user requests showing README and there isn't one then show a blank file @TEParsons in #5470 +* Fix typos in high contrast theme by @TEParsons in #5504 +* Sound files online were playing forever if duration set to <0.5s by @TEParsons in #5466 +* Let Builder treat Sound.isPlaying and Sound.status==STARTED as synonymous by @TEParsons in #5428 +* Correctly ignore blank columns by @wader in #5406 +* Viewport was left as None when checkTiming was unticked by @TEParsons in #5451 +* Better handling when a Pavlovia project / plugin avatars in the app @TEParsons in #5458 #5460 #5469 + +## Documentation fixes by + +* @roelofsaj in #5477 #5483 #5484 +* @ChenBri in #5478 #5480 +* @ChristopheBossens in #5481 +* @suelynnmah in #5444 + +## New Contributors + +* @roelofsaj made their first contribution in #5477 +* @ChenBri made their first contribution in #5478 +* @ChristopheBossens made their first contribution in #5481 +* @wader made their first contribution in #5406 + +**Full Changelog**: https://github.com/psychopy/psychopy/compare/2023.1.1...2023.1.2 + +PsychoPy 2023.1.1 +~~~~~~~~~~~~~~~~~ + +Fixed: + +- Better plugin handling: + + - Better handling of plugin dependencies (moved to sub-folders) #5398 + - More responsive plugins dialog (not waiting for all plugin info to populate) #5410 + - Live info updates as the plugin installs #5399 + - Sort package versions newest first #a4987c95f + +- Panorama stimulus no longer needs FBO=False on Window +- MovieStim locally opacity was not being honored #094731084 +- MovieStim online crashed if using setEveryRepeat #ed484ba17 +- Close eyetracker connection if experiment ends early #f9b6f98e4 +- README dialog was created twice #5383 +- Online Experiments with image sitmuli crashing with unknown resource "default.png" +- Nested loops were crashing +- Fixed various failures to translate #804bfcde2 #b1b611ec1 +- Console gave encoding errors when opening MacOS csv files on Windows machines #5396 +- Failure to log in to Pavlovia #5382 #5450 + PsychoPy 2022.3 --------------- -*Highilghts:* +*Highlights:* - Online: Interface in Pavlovia for building and running online questionnaires! As this is built on top of the open-source [SurveyJS](https://surveyjs.io/) package it offers a rich feature list right off the bat. The new Pavlovia Survey component you can insert a survey into your experiment just like you would a Form component. From acacb665d75db7b4c62b21bd30bb88b51ffab428 Mon Sep 17 00:00:00 2001 From: Todd Parsons Date: Fri, 14 Apr 2023 10:25:26 +0100 Subject: [PATCH 05/10] BF: JS code wasn't distinguishing between regular polygon & custom vertices in ShapeStim --- psychopy/experiment/components/polygon/__init__.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/psychopy/experiment/components/polygon/__init__.py b/psychopy/experiment/components/polygon/__init__.py index 0b8254cfac..652ab24f1c 100644 --- a/psychopy/experiment/components/polygon/__init__.py +++ b/psychopy/experiment/components/polygon/__init__.py @@ -270,10 +270,14 @@ def writeInitCodeJS(self, buff): code = ("{name} = new visual.ShapeStim ({{\n" " win: psychoJS.window, name: '{name}', {unitsStr}\n" " vertices: 'arrow', size:{size},\n") - else: + elif self.params['shape'] == 'regular polygon...': code = ("{name} = new visual.Polygon ({{\n" " win: psychoJS.window, name: '{name}', {unitsStr}\n" " edges: {nVertices}, size:{size},\n") + else: + code = ("{name} = visual.ShapeStim({{\n" + + " win: psychoJS.window, name: '{name}', {unitsStr}, \n" + " vertices={vertices}, size={size},\n") depth = -self.getPosInRoutine() @@ -303,5 +307,6 @@ def writeInitCodeJS(self, buff): opacity=inits['opacity'], depth=depth, interpolate=interpolate, - nVertices=inits['nVertices'] + nVertices=inits['nVertices'], + vertices=inits['vertices'] )) From a3aa77f5f409c39487ba15962cc478dc3dfed489 Mon Sep 17 00:00:00 2001 From: Jon Peirce Date: Fri, 28 Apr 2023 14:19:22 +0100 Subject: [PATCH 06/10] BF: Keyboard class did not send a log message when clearing events This was causing problems for users who may think that keys were "missed" by PsychoPy because they didn't realise the events were detected but then cleared --- psychopy/hardware/keyboard.py | 1 + 1 file changed, 1 insertion(+) diff --git a/psychopy/hardware/keyboard.py b/psychopy/hardware/keyboard.py index d847cd1c47..f9a21b0e64 100644 --- a/psychopy/hardware/keyboard.py +++ b/psychopy/hardware/keyboard.py @@ -408,6 +408,7 @@ def clearEvents(self, eventType=None): else: global event event.clearEvents(eventType) + logging.info("Keyboard events cleared", obj=self) class KeyPress(object): From 9126f65f6da6468c22de5964f12f0ea5b25e3ef4 Mon Sep 17 00:00:00 2001 From: Jon Peirce Date: Fri, 28 Apr 2023 14:20:29 +0100 Subject: [PATCH 07/10] DOCS: added documentation for Keyboard.clearEvents --- psychopy/hardware/keyboard.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/psychopy/hardware/keyboard.py b/psychopy/hardware/keyboard.py index f9a21b0e64..c66aaba20e 100644 --- a/psychopy/hardware/keyboard.py +++ b/psychopy/hardware/keyboard.py @@ -396,7 +396,7 @@ def waitKeys(self, maxWait=float('inf'), keyList=None, waitRelease=True, return None def clearEvents(self, eventType=None): - """""" + """Clear the events from the Keyboard such as previous key presses""" if Keyboard._backend == 'ptb': for buffer in self._buffers.values(): buffer.flush() # flush the device events to the soft buffer From 03bc9135c190f211455e5448709b9824b3d09be7 Mon Sep 17 00:00:00 2001 From: Todd Parsons Date: Thu, 4 May 2023 11:34:20 +0100 Subject: [PATCH 08/10] BF: Missing comma in Brush component code --- psychopy/experiment/components/brush/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/psychopy/experiment/components/brush/__init__.py b/psychopy/experiment/components/brush/__init__.py index e06af36169..f62bf42089 100644 --- a/psychopy/experiment/components/brush/__init__.py +++ b/psychopy/experiment/components/brush/__init__.py @@ -96,7 +96,7 @@ def writeInitCode(self, buff): " lineColor={lineColor},\n" " lineColorSpace={lineColorSpace},\n" " opacity={opacity},\n" - " buttonRequired={buttonRequired}\n" + " buttonRequired={buttonRequired},\n" " depth={depth}\n" ")" ).format(**inits) From 4dbbae005fcaa7031247e221c46fec857b3c9663 Mon Sep 17 00:00:00 2001 From: Eitan Hemed <37670372+EitanHemed@users.noreply.github.com> Date: Thu, 4 May 2023 18:37:02 +0300 Subject: [PATCH 09/10] Update index.rst Removed this line, as it repeats the reference to ImageStim already included in the file (see link). https://github.com/psychopy/psychopy/blob/96a22f84d1af9d11637b6e56283fc9be49d04f5d/docs/source/api/visual/index.rst?plain=1#L26 --- docs/source/api/visual/index.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/source/api/visual/index.rst b/docs/source/api/visual/index.rst index 56cb6aa970..1586159191 100644 --- a/docs/source/api/visual/index.rst +++ b/docs/source/api/visual/index.rst @@ -38,7 +38,6 @@ Shapes (all special classes of :class:`ShapeStim`): Images and patterns: -* :class:`.ImageStim` to show images * :class:`.SimpleImageStim` to show images without bells and whistles * :class:`.GratingStim` to show gratings * :class:`.RadialStim` to show annulus, a rotating wedge, a checkerboard etc From 42149e5b11674ec86616e7584c23910f3cede888 Mon Sep 17 00:00:00 2001 From: Todd Parsons Date: Thu, 4 May 2023 16:52:51 +0100 Subject: [PATCH 10/10] ENH: Store duration for keyboard components --- .../components/keyboard/__init__.py | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/psychopy/experiment/components/keyboard/__init__.py b/psychopy/experiment/components/keyboard/__init__.py index d38f277de7..b08ee6ac33 100644 --- a/psychopy/experiment/components/keyboard/__init__.py +++ b/psychopy/experiment/components/keyboard/__init__.py @@ -257,15 +257,18 @@ def writeFrameCode(self, buff): dedentAtEnd += 1 if store == 'first key': # then see if a key has already been pressed code = ("{name}.keys = _{name}_allKeys[0].name # just the first key pressed\n" - "{name}.rt = _{name}_allKeys[0].rt\n") + "{name}.rt = _{name}_allKeys[0].rt\n" + "{name}.duration = _{name}_allKeys[0].duration\n") buff.writeIndentedLines(code.format(name=self.params['name'])) elif store == 'last key' or store == "nothing": # If store nothing, save last key for correct answer test code = ("{name}.keys = _{name}_allKeys[-1].name # just the last key pressed\n" - "{name}.rt = _{name}_allKeys[-1].rt\n") + "{name}.rt = _{name}_allKeys[-1].rt\n" + "{name}.duration = _{name}_allKeys[-1].duration\n") buff.writeIndentedLines(code.format(name=self.params['name'])) elif store == 'all keys': code = ("{name}.keys = [key.name for key in _{name}_allKeys] # storing all keys\n" - "{name}.rt = [key.rt for key in _{name}_allKeys]\n") + "{name}.rt = [key.rt for key in _{name}_allKeys]\n" + "{name}.duration = [key.duration for key in _{name}_allKeys]\n") buff.writeIndentedLines(code.format(name=self.params['name'])) if storeCorr: @@ -399,15 +402,18 @@ def writeFrameCodeJS(self, buff): # how do we store it? if store == 'first key': # then see if a key has already been pressed code = ("{name}.keys = _{name}_allKeys[0].name; // just the first key pressed\n" - "{name}.rt = _{name}_allKeys[0].rt;\n") + "{name}.rt = _{name}_allKeys[0].rt;\n" + "{name}.duration = _{name}_allKeys[0].duration;\n") buff.writeIndentedLines(code.format(name=self.params['name'])) elif store == 'last key' or store =='nothing': code = ("{name}.keys = _{name}_allKeys[_{name}_allKeys.length - 1].name; // just the last key pressed\n" - "{name}.rt = _{name}_allKeys[_{name}_allKeys.length - 1].rt;\n") + "{name}.rt = _{name}_allKeys[_{name}_allKeys.length - 1].rt;\n" + "{name}.duration = _{name}_allKeys[_{name}_allKeys.length - 1].duration;\n") buff.writeIndentedLines(code.format(name=self.params['name'])) elif store == 'all keys': code = ("{name}.keys = _{name}_allKeys.map((key) => key.name); // storing all keys\n" - "{name}.rt = _{name}_allKeys.map((key) => key.rt);\n") + "{name}.rt = _{name}_allKeys.map((key) => key.rt);\n" \ + "{name}.duration = _{name}_allKeys.map((key) => key.duration);\n") buff.writeIndentedLines(code.format(name=self.params['name'])) if storeCorr: @@ -482,10 +488,11 @@ def writeRoutineEndCode(self, buff): (currLoop.params['name'], name, name)) # only add an RT if we had a response - code = ("if %(name)s.keys != None: # we had a response\n" % - self.params + - " %s.addData('%s.rt', %s.rt)\n" % - (currLoop.params['name'], name, name)) + code = ( + "if %(name)s.keys != None: # we had a response\n" % self.params + + " %s.addData('%s.rt', %s.rt)\n" % (currLoop.params['name'], name, name) + + " %s.addData('%s.duration', %s.duration)\n" % (currLoop.params['name'], name, name) + ) buff.writeIndentedLines(code) # get parent to write code too (e.g. store onset/offset times) @@ -549,7 +556,8 @@ def writeRoutineEndCodeJS(self, buff): # only add an RT if we had a response code = ("if (typeof {name}.keys !== 'undefined') {{ // we had a response\n" - " psychoJS.experiment.addData('{name}.rt', {name}.rt);\n") + " psychoJS.experiment.addData('{name}.rt', {name}.rt);\n" + " psychoJS.experiment.addData('{name}.duration', {name}.duration);\n") if forceEnd: code += (" routineTimer.reset();\n" " }}\n\n")