From 53138e694203434fd34c47a65a7b53b3c5fc60f0 Mon Sep 17 00:00:00 2001 From: drevicko Date: Tue, 4 Apr 2017 15:37:07 +0100 Subject: [PATCH 01/13] Estimate VAD by weighted average Does a weighted average of centroids. If intensity sums to zero for a category, a 'neutral' category is used or 0 if it's not present. I'm not 100% sure this is the best approach, and the name of the "neutral" category perhaps should use some convention? Note that if there are no categories present, then no VAD (or other dimensional) estimate is returned. It may be better to use the neutral centroid if it's present in this case also. --- senpy/plugins/conversion/centroids.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/senpy/plugins/conversion/centroids.py b/senpy/plugins/conversion/centroids.py index 2dd1c97..2c0e735 100644 --- a/senpy/plugins/conversion/centroids.py +++ b/senpy/plugins/conversion/centroids.py @@ -1,5 +1,6 @@ from senpy.plugins import EmotionConversionPlugin from senpy.models import EmotionSet, Emotion, Error +from collections import defaultdict import logging logger = logging.getLogger(__name__) @@ -37,14 +38,22 @@ class CentroidConversion(EmotionConversionPlugin): def _forward_conversion(self, original): """Sum the VAD value of all categories found.""" res = Emotion() + totalIntensities = defaultdict(float) for e in original.onyx__hasEmotion: category = e.onyx__hasEmotionCategory + intensity = e.get("onyx__hasEmotionIntensity",1) if category in self.centroids: + totalIntensities[category] += intensity for dim, value in self.centroids[category].items(): try: - res[dim] += value + res[dim] += value * intensity except Exception: - res[dim] = value + res[dim] = value * intensity + for dim,intensity in totalIntensities.items(): + if intensity != 0: + res[dim] /= intensity + else: + res[dim] = self.centroids.get('neutral', {dim:0})[dim] return res def _backwards_conversion(self, original): From 1ca6ec52fdb178cf296bbf47ff39d65badacc903 Mon Sep 17 00:00:00 2001 From: Ian Wood Date: Tue, 11 Apr 2017 11:12:02 +0100 Subject: [PATCH 02/13] fixed weighted average, no explicit treatment of 'neutral' --- senpy/plugins/conversion/centroids.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/senpy/plugins/conversion/centroids.py b/senpy/plugins/conversion/centroids.py index 2c0e735..ac3cb9e 100644 --- a/senpy/plugins/conversion/centroids.py +++ b/senpy/plugins/conversion/centroids.py @@ -42,18 +42,19 @@ class CentroidConversion(EmotionConversionPlugin): for e in original.onyx__hasEmotion: category = e.onyx__hasEmotionCategory intensity = e.get("onyx__hasEmotionIntensity",1) + if intensity == 0: + continue if category in self.centroids: - totalIntensities[category] += intensity for dim, value in self.centroids[category].items(): + totalIntensities[dim] += intensity try: res[dim] += value * intensity except Exception: res[dim] = value * intensity + for dim,intensity in totalIntensities.items(): if intensity != 0: res[dim] /= intensity - else: - res[dim] = self.centroids.get('neutral', {dim:0})[dim] return res def _backwards_conversion(self, original): From b80b0c7947cf00c020414e4e5ea8dd1341361c8e Mon Sep 17 00:00:00 2001 From: Ian Wood Date: Tue, 11 Apr 2017 11:25:50 +0100 Subject: [PATCH 03/13] used more specific exception specifier (KeyError) --- senpy/plugins/conversion/centroids.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/senpy/plugins/conversion/centroids.py b/senpy/plugins/conversion/centroids.py index ac3cb9e..37bb9d3 100644 --- a/senpy/plugins/conversion/centroids.py +++ b/senpy/plugins/conversion/centroids.py @@ -49,7 +49,7 @@ class CentroidConversion(EmotionConversionPlugin): totalIntensities[dim] += intensity try: res[dim] += value * intensity - except Exception: + except KeyError: res[dim] = value * intensity for dim,intensity in totalIntensities.items(): From ec1a2ff5f97f4ae3c21cc2e8cdb9f4f6d38fe6da Mon Sep 17 00:00:00 2001 From: Ian Wood Date: Mon, 8 May 2017 14:28:51 +0100 Subject: [PATCH 04/13] added 'origin' to VAD representation, incorporated into weighed sum for Cat->VAD conversion --- senpy/plugins/conversion/centroids.py | 24 +++++++++++-------- .../conversion/emotion/ekman2vad.senpy | 9 +++++++ 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/senpy/plugins/conversion/centroids.py b/senpy/plugins/conversion/centroids.py index 37bb9d3..c1137ae 100644 --- a/senpy/plugins/conversion/centroids.py +++ b/senpy/plugins/conversion/centroids.py @@ -36,25 +36,29 @@ class CentroidConversion(EmotionConversionPlugin): super(CentroidConversion, self).__init__(info) def _forward_conversion(self, original): - """Sum the VAD value of all categories found.""" + """Sum the VAD value of all categories found weighted by intensity. """ res = Emotion() - totalIntensities = defaultdict(float) + maxIntensity = float(original.get("onyx__maxIntensityValue",1)) + sumIntensities = 0 + neutralPoint = self.get("origin",None) for e in original.onyx__hasEmotion: category = e.onyx__hasEmotionCategory - intensity = e.get("onyx__hasEmotionIntensity",1) + intensity = e.get("onyx__hasEmotionIntensity",maxIntensity)/maxIntensity if intensity == 0: continue - if category in self.centroids: - for dim, value in self.centroids[category].items(): - totalIntensities[dim] += intensity + sumIntensities += intensity + centoid = self.centroids.get(category,None) + if centroid: + for dim, value in centroid.items(): + if neutralPoint: + value -= neutralPoint[dim] try: res[dim] += value * intensity except KeyError: res[dim] = value * intensity - - for dim,intensity in totalIntensities.items(): - if intensity != 0: - res[dim] /= intensity + if neutralPoint: + for dim in res: + res[dim] += neutralPoint[dim] return res def _backwards_conversion(self, original): diff --git a/senpy/plugins/conversion/emotion/ekman2vad.senpy b/senpy/plugins/conversion/emotion/ekman2vad.senpy index a1f21f0..f2fbe6b 100644 --- a/senpy/plugins/conversion/emotion/ekman2vad.senpy +++ b/senpy/plugins/conversion/emotion/ekman2vad.senpy @@ -4,6 +4,11 @@ module: senpy.plugins.conversion.centroids description: Plugin to convert emotion sets from Ekman to VAD version: 0.1 # No need to specify onyx:doesConversion because centroids.py adds it automatically from centroids_direction +origin: + # Point in VAD space with no emotion (aka Neutral) + A: 5.0 + D: 5.0 + V: 5.0 centroids: anger: A: 6.95 @@ -25,6 +30,10 @@ centroids: A: 5.21 D: 2.82 V: 2.21 + neutral: + A: 5.00 + D: 2.00 + V: 5.00 centroids_direction: - emoml:big6 - emoml:pad From 400f647b7b343c568b519afdd4a9e6c16e6c0856 Mon Sep 17 00:00:00 2001 From: drevicko Date: Mon, 8 May 2017 14:32:53 +0100 Subject: [PATCH 05/13] removed unneccessary defaultdict import --- senpy/plugins/conversion/centroids.py | 1 - 1 file changed, 1 deletion(-) diff --git a/senpy/plugins/conversion/centroids.py b/senpy/plugins/conversion/centroids.py index c1137ae..a5bdbd2 100644 --- a/senpy/plugins/conversion/centroids.py +++ b/senpy/plugins/conversion/centroids.py @@ -1,6 +1,5 @@ from senpy.plugins import EmotionConversionPlugin from senpy.models import EmotionSet, Emotion, Error -from collections import defaultdict import logging logger = logging.getLogger(__name__) From dcc965ea63700d7597ea35ca39ecaeec9aef1aef Mon Sep 17 00:00:00 2001 From: drevicko Date: Mon, 8 May 2017 14:34:28 +0100 Subject: [PATCH 06/13] removed superfluous 'neutral' centroid Neutral is included as an 'origin' field. This is partly because emoml has no vocab for "Neutral" in dimensional models. --- senpy/plugins/conversion/emotion/ekman2vad.senpy | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/senpy/plugins/conversion/emotion/ekman2vad.senpy b/senpy/plugins/conversion/emotion/ekman2vad.senpy index f2fbe6b..e9eac74 100644 --- a/senpy/plugins/conversion/emotion/ekman2vad.senpy +++ b/senpy/plugins/conversion/emotion/ekman2vad.senpy @@ -30,10 +30,6 @@ centroids: A: 5.21 D: 2.82 V: 2.21 - neutral: - A: 5.00 - D: 2.00 - V: 5.00 centroids_direction: - emoml:big6 - emoml:pad @@ -45,4 +41,4 @@ aliases: # These are aliases for any key in the centroid, to avoid repeating a l disgust: emoml:big6disgust fear: emoml:big6fear happiness: emoml:big6happiness - sadness: emoml:big6sadness \ No newline at end of file + sadness: emoml:big6sadness From 8c7043331295e9872144cecb8e9f2e840093b24d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=2E=20Fernando=20S=C3=A1nchez?= Date: Fri, 19 May 2017 17:55:52 +0200 Subject: [PATCH 07/13] Added push to github --- .gitlab-ci.yml | 8 ++++++++ Makefile | 16 ++++++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 9719070..c92672d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -66,6 +66,14 @@ deploy: only: - master +push-github: + stage: deploy + script: + - make -e push-github + only: + - master + - triggers + clean : stage: clean script: diff --git a/Makefile b/Makefile index 3e260ca..ebc2e42 100644 --- a/Makefile +++ b/Makefile @@ -8,14 +8,18 @@ IMAGENAME=$(REPO)/$(NAME) IMAGEWTAG=$(IMAGENAME):$(VERSION) DEVPORT=5000 action="test-${PYMAIN}" +GITHUB_REPO=git@github.com:gsi-upm/senpy.git KUBE_CA_PEM_FILE="" KUBE_URL="" KUBE_TOKEN="" +KUBE_NS=$(NAME) KUBECTL=docker run --rm -v $(KUBE_CA_PEM_FILE):/tmp/ca.pem -v $$PWD:/tmp/cwd/ -i lachlanevenson/k8s-kubectl --server="$(KUBE_URL)" --token="$(KUBE_TOKEN)" --certificate-authority="/tmp/ca.pem" -n $(KUBE_NAMESPACE) CI_REGISTRY=docker.io CI_REGISTRY_USER=gitlab CI_BUILD_TOKEN="" +CI_COMMIT_REF_NAME=master + all: build run @@ -27,7 +31,7 @@ version: .FORCE @echo $(VERSION) yapf: - yapf -i -r senpy + yapf -i -r $(NAME) yapf -i -r tests init: @@ -120,11 +124,19 @@ push: $(addprefix push-,$(PYVERSIONS)) docker tag '$(IMAGEWTAG)-python$(PYMAIN)' '$(IMAGEWTAG)' docker push $(IMAGENAME):$(VERSION) +push-github: + $(eval KEY_FILE := $(shell mktemp)) + @echo "$$GITHUB_DEPLOY_KEY" > $(KEY_FILE) + @git remote rm github-deploy + git remote add github-deploy $(GITHUB_REPO) + @GIT_SSH_COMMAND="ssh -i $(KEY_FILE)" git push github-deploy $(CI_COMMIT_REF_NAME) + rm $(KEY_FILE) + ci: gitlab-runner exec docker --docker-volumes /var/run/docker.sock:/var/run/docker.sock --env CI_PROJECT_NAME=$(NAME) ${action} deploy: - $(KUBECTL) delete -n senpy secret $(CI_REGISTRY) || true + $(KUBECTL) delete -n $(KUBE_NS) secret $(CI_REGISTRY) || true @$(KUBECTL) create -n $(NAME) secret docker-registry $(CI_REGISTRY) --docker-server=$(CI_REGISTRY) --docker-username=$(CI_REGISTRY_USER) --docker-email=$(CI_REGISTRY_USER) --docker-password=$(CI_BUILD_TOKEN) $(KUBECTL) apply -f /tmp/cwd/k8s/ From e7ac6e66b0855d8ebc765b0e581e181f4f2fb58e Mon Sep 17 00:00:00 2001 From: drevicko Date: Mon, 29 May 2017 11:50:14 +0100 Subject: [PATCH 08/13] update _forward_conversion docstring + minor edits --- senpy/plugins/conversion/centroids.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/senpy/plugins/conversion/centroids.py b/senpy/plugins/conversion/centroids.py index a5bdbd2..8a60402 100644 --- a/senpy/plugins/conversion/centroids.py +++ b/senpy/plugins/conversion/centroids.py @@ -35,17 +35,20 @@ class CentroidConversion(EmotionConversionPlugin): super(CentroidConversion, self).__init__(info) def _forward_conversion(self, original): - """Sum the VAD value of all categories found weighted by intensity. """ + """Sum the VAD value of all categories found weighted by intensity. + Intensities are scaled by onyx:maxIntensityValue if it is present, else maxIntensityValue is assumed to be one. + Emotion entries that do not have onxy:hasEmotionIntensity specified are assumed to have maxIntensityValue. + Emotion entries that do not have onyx:hasEmotionCategory specified are ignored.""" res = Emotion() maxIntensity = float(original.get("onyx__maxIntensityValue",1)) - sumIntensities = 0 neutralPoint = self.get("origin",None) for e in original.onyx__hasEmotion: - category = e.onyx__hasEmotionCategory + category = e.get("onyx__hasEmotionCategory", None) + if category is None: + continue intensity = e.get("onyx__hasEmotionIntensity",maxIntensity)/maxIntensity if intensity == 0: continue - sumIntensities += intensity centoid = self.centroids.get(category,None) if centroid: for dim, value in centroid.items(): From 8d56a0b6302c7114bd8dd9d04d21b84e331089b3 Mon Sep 17 00:00:00 2001 From: drevicko Date: Mon, 29 May 2017 12:06:44 +0100 Subject: [PATCH 09/13] fixes #31 I've used euclidean metric instead of taxicab as I feel it makes more sense (taxicab has bizzare unintuitive effects for points far from the centroids). --- senpy/plugins/conversion/centroids.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/senpy/plugins/conversion/centroids.py b/senpy/plugins/conversion/centroids.py index 2dd1c97..1b59a7d 100644 --- a/senpy/plugins/conversion/centroids.py +++ b/senpy/plugins/conversion/centroids.py @@ -52,7 +52,7 @@ class CentroidConversion(EmotionConversionPlugin): dimensions = list(self.centroids.values())[0] def distance(e1, e2): - return sum((e1[k] - e2.get(k, 0)) for k in dimensions) + return sum((e1[k] - e2.get(k, 0)**2) for k in dimensions) emotion = '' mindistance = 10000000000000000000000.0 From 65d6e47513272c3e1bd41c16d2f4196b508647ba Mon Sep 17 00:00:00 2001 From: drevicko Date: Mon, 29 May 2017 12:13:21 +0100 Subject: [PATCH 10/13] Implements Fernando's suggestion in #31 I've added a neutral point definition (in the converters senpy file) as used in pull request #29 --- senpy/plugins/conversion/centroids.py | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/senpy/plugins/conversion/centroids.py b/senpy/plugins/conversion/centroids.py index 1b59a7d..e3c1bd8 100644 --- a/senpy/plugins/conversion/centroids.py +++ b/senpy/plugins/conversion/centroids.py @@ -49,18 +49,15 @@ class CentroidConversion(EmotionConversionPlugin): def _backwards_conversion(self, original): """Find the closest category""" - dimensions = list(self.centroids.values())[0] + dimensions = set(k.keys() for i in centroids.values()) + neutralPoint = self.get("origin", None) + neutralPoint = {k:neutralPoint[k] if k in neturalPoint else 0} + + def distance(centroid): + return sum((centroid.get(k, neutralPoint[k]) - original.get(k, neutralPoint[k]))**2 for k in dimensions) - def distance(e1, e2): - return sum((e1[k] - e2.get(k, 0)**2) for k in dimensions) - - emotion = '' - mindistance = 10000000000000000000000.0 - for state in self.centroids: - d = distance(self.centroids[state], original) - if d < mindistance: - mindistance = d - emotion = state + emotion = min(centroids, key=lambda x: distance(centroids[x]) + result = Emotion(onyx__hasEmotionCategory=emotion) return result From 6b843a4384d9ac61ea2e5dc13ded542ebf6ec0e8 Mon Sep 17 00:00:00 2001 From: drevicko Date: Mon, 29 May 2017 12:15:35 +0100 Subject: [PATCH 11/13] fixes typo in code --- senpy/plugins/conversion/centroids.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/senpy/plugins/conversion/centroids.py b/senpy/plugins/conversion/centroids.py index e3c1bd8..3479c50 100644 --- a/senpy/plugins/conversion/centroids.py +++ b/senpy/plugins/conversion/centroids.py @@ -49,7 +49,7 @@ class CentroidConversion(EmotionConversionPlugin): def _backwards_conversion(self, original): """Find the closest category""" - dimensions = set(k.keys() for i in centroids.values()) + dimensions = set(c.keys() for c in centroids.values()) neutralPoint = self.get("origin", None) neutralPoint = {k:neutralPoint[k] if k in neturalPoint else 0} From 00da75153a20cbe1cc79df7cb8783a014ef2a59a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=2E=20Fernando=20S=C3=A1nchez?= Date: Mon, 12 Jun 2017 18:09:58 +0200 Subject: [PATCH 12/13] Change conversion to Euclidean distance * Added neutral point (if present) Closes !gsi-upm/senpy#37 (Ian's) --- senpy/plugins/conversion/centroids.py | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/senpy/plugins/conversion/centroids.py b/senpy/plugins/conversion/centroids.py index 3479c50..427e111 100644 --- a/senpy/plugins/conversion/centroids.py +++ b/senpy/plugins/conversion/centroids.py @@ -32,8 +32,17 @@ class CentroidConversion(EmotionConversionPlugin): nv1[aliases.get(k2, k2)] = v2 ncentroids[aliases.get(k1, k1)] = nv1 info['centroids'] = ncentroids + super(CentroidConversion, self).__init__(info) + self.dimensions = set() + for c in self.centroids.values(): + self.dimensions.update(c.keys()) + self.neutralPoints = self.get("neutralPoints", dict()) + if not self.neutralPoints: + for i in self.dimensions: + self.neutralPoints[i] = self.get("neutralValue", 0) + def _forward_conversion(self, original): """Sum the VAD value of all categories found.""" res = Emotion() @@ -49,15 +58,19 @@ class CentroidConversion(EmotionConversionPlugin): def _backwards_conversion(self, original): """Find the closest category""" - dimensions = set(c.keys() for c in centroids.values()) - neutralPoint = self.get("origin", None) - neutralPoint = {k:neutralPoint[k] if k in neturalPoint else 0} - + centroids = self.centroids + neutralPoints = self.neutralPoints + dimensions = self.dimensions + + def distance_k(centroid, original, k): + # k component of the distance between the value and a given centroid + return (centroid.get(k, neutralPoints[k]) - original.get(k, neutralPoints[k]))**2 + def distance(centroid): - return sum((centroid.get(k, neutralPoint[k]) - original.get(k, neutralPoint[k]))**2 for k in dimensions) + return sum(distance_k(centroid, original, k) for k in dimensions) + + emotion = min(centroids, key=lambda x: distance(centroids[x])) - emotion = min(centroids, key=lambda x: distance(centroids[x]) - result = Emotion(onyx__hasEmotionCategory=emotion) return result From 852bcc72ba40f14c6f94ef2094a102bcb29f3a09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=2E=20Fernando=20S=C3=A1nchez?= Date: Mon, 12 Jun 2017 19:40:26 +0200 Subject: [PATCH 13/13] Better centroid conversion Also added **simple** tests for backward and forward conversion. In future versions we should add thorough tests. Should close gsi-upm/senpy#31 --- senpy/plugins/conversion/emotion/__init__.py | 0 .../conversion/{ => emotion}/centroids.py | 36 ++++++------- .../conversion/emotion/ekman2fsre.senpy | 2 +- .../conversion/emotion/ekman2vad.senpy | 2 +- tests/test_plugins.py | 52 ++++++++++++++++++- 5 files changed, 69 insertions(+), 23 deletions(-) create mode 100644 senpy/plugins/conversion/emotion/__init__.py rename senpy/plugins/conversion/{ => emotion}/centroids.py (76%) diff --git a/senpy/plugins/conversion/emotion/__init__.py b/senpy/plugins/conversion/emotion/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/senpy/plugins/conversion/centroids.py b/senpy/plugins/conversion/emotion/centroids.py similarity index 76% rename from senpy/plugins/conversion/centroids.py rename to senpy/plugins/conversion/emotion/centroids.py index ef08976..fe400cd 100644 --- a/senpy/plugins/conversion/centroids.py +++ b/senpy/plugins/conversion/emotion/centroids.py @@ -44,32 +44,27 @@ class CentroidConversion(EmotionConversionPlugin): self.neutralPoints[i] = self.get("neutralValue", 0) def _forward_conversion(self, original): - """Sum the VAD value of all categories found weighted by intensity. - Intensities are scaled by onyx:maxIntensityValue if it is present, else maxIntensityValue is assumed to be one. - Emotion entries that do not have onxy:hasEmotionIntensity specified are assumed to have maxIntensityValue. - Emotion entries that do not have onyx:hasEmotionCategory specified are ignored.""" + """Sum the VAD value of all categories found weighted by intensity. + Intensities are scaled by onyx:maxIntensityValue if it is present, else maxIntensityValue + is assumed to be one. Emotion entries that do not have onxy:hasEmotionIntensity specified + are assumed to have maxIntensityValue. Emotion entries that do not have + onyx:hasEmotionCategory specified are ignored.""" res = Emotion() - maxIntensity = float(original.get("onyx__maxIntensityValue",1)) - neutralPoint = self.get("origin",None) + maxIntensity = float(original.get("onyx:maxIntensityValue", 1)) for e in original.onyx__hasEmotion: - category = e.get("onyx__hasEmotionCategory", None) - if category is None: + category = e.get("onyx:hasEmotionCategory", None) + if not category: continue - intensity = e.get("onyx__hasEmotionIntensity",maxIntensity)/maxIntensity - if intensity == 0: + intensity = e.get("onyx:hasEmotionIntensity", maxIntensity) / maxIntensity + if not intensity: continue - centoid = self.centroids.get(category,None) + centroid = self.centroids.get(category, None) if centroid: for dim, value in centroid.items(): - if neutralPoint: - value -= neutralPoint[dim] - try: - res[dim] += value * intensity - except KeyError: - res[dim] = value * intensity - if neutralPoint: - for dim in res: - res[dim] += neutralPoint[dim] + neutral = self.neutralPoints[dim] + if dim not in res: + res[dim] = 0 + res[dim] += (value - neutral) * intensity + neutral return res def _backwards_conversion(self, original): @@ -88,6 +83,7 @@ class CentroidConversion(EmotionConversionPlugin): emotion = min(centroids, key=lambda x: distance(centroids[x])) result = Emotion(onyx__hasEmotionCategory=emotion) + result.onyx__algorithmConfidence = distance(centroids[emotion]) return result def convert(self, emotionSet, fromModel, toModel, params): diff --git a/senpy/plugins/conversion/emotion/ekman2fsre.senpy b/senpy/plugins/conversion/emotion/ekman2fsre.senpy index 3cc0c17..0606183 100644 --- a/senpy/plugins/conversion/emotion/ekman2fsre.senpy +++ b/senpy/plugins/conversion/emotion/ekman2fsre.senpy @@ -1,6 +1,6 @@ --- name: Ekman2FSRE -module: senpy.plugins.conversion.centroids +module: senpy.plugins.conversion.emotion.centroids description: Plugin to convert emotion sets from Ekman to VAD version: 0.1 # No need to specify onyx:doesConversion because centroids.py adds it automatically from centroids_direction diff --git a/senpy/plugins/conversion/emotion/ekman2vad.senpy b/senpy/plugins/conversion/emotion/ekman2vad.senpy index e9eac74..9af84ba 100644 --- a/senpy/plugins/conversion/emotion/ekman2vad.senpy +++ b/senpy/plugins/conversion/emotion/ekman2vad.senpy @@ -1,6 +1,6 @@ --- name: Ekman2PAD -module: senpy.plugins.conversion.centroids +module: senpy.plugins.conversion.emotion.centroids description: Plugin to convert emotion sets from Ekman to VAD version: 0.1 # No need to specify onyx:doesConversion because centroids.py adds it automatically from centroids_direction diff --git a/tests/test_plugins.py b/tests/test_plugins.py index dbfe60d..fe8ee1c 100644 --- a/tests/test_plugins.py +++ b/tests/test_plugins.py @@ -6,8 +6,9 @@ import shutil import tempfile from unittest import TestCase -from senpy.models import Results, Entry +from senpy.models import Results, Entry, EmotionSet, Emotion from senpy.plugins import SentimentPlugin, ShelfMixin +from senpy.plugins.conversion.emotion.centroids import CentroidConversion class ShelfDummyPlugin(SentimentPlugin, ShelfMixin): @@ -152,3 +153,52 @@ class PluginsTest(TestCase): } }) assert 'example' in a.extra_params + + def test_conversion_centroids(self): + info = { + "name": "CentroidTest", + "description": "Centroid test", + "version": 0, + "centroids": { + "c1": {"V1": 0.5, + "V2": 0.5}, + "c2": {"V1": -0.5, + "V2": 0.5}, + "c3": {"V1": -0.5, + "V2": -0.5}, + "c4": {"V1": 0.5, + "V2": -0.5}}, + "aliases": { + "V1": "X-dimension", + "V2": "Y-dimension" + }, + "centroids_direction": ["emoml:big6", "emoml:fsre-dimensions"] + } + c = CentroidConversion(info) + + es1 = EmotionSet() + e1 = Emotion() + e1.onyx__hasEmotionCategory = "c1" + es1.onyx__hasEmotion.append(e1) + res = c._forward_conversion(es1) + assert res["X-dimension"] == 0.5 + assert res["Y-dimension"] == 0.5 + + e2 = Emotion() + e2.onyx__hasEmotionCategory = "c2" + es1.onyx__hasEmotion.append(e2) + res = c._forward_conversion(es1) + assert res["X-dimension"] == 0 + assert res["Y-dimension"] == 1 + + e = Emotion() + e["X-dimension"] = -0.2 + e["Y-dimension"] = -0.3 + res = c._backwards_conversion(e) + assert res["onyx:hasEmotionCategory"] == "c3" + + e = Emotion() + e["X-dimension"] = -0.2 + e["Y-dimension"] = 0.3 + res = c._backwards_conversion(e) + assert res["onyx:hasEmotionCategory"] == "c2"