diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 59ed80d5e..6795d5343 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -86,7 +86,8 @@ jobs: run: | git config user.name github-actions git config user.email github-actions@github.com - git commit -m "GitHub Actions generated requirements_frozen.txt" -a + git add requirements_frozen.txt + git commit -m "GitHub Actions generated requirements_frozen.txt" git push # Docker steps only run when master branch pushed to directly OR when a PR is merged diff --git a/alyx/actions/views.py b/alyx/actions/views.py index bec3461f6..2ecd72875 100644 --- a/alyx/actions/views.py +++ b/alyx/actions/views.py @@ -457,7 +457,10 @@ def get(self, request, format=None, nickname=None): end_date = request.query_params.get('end_date', None) subject = Subject.objects.get(nickname=nickname) records = subject.water_control.to_jsonable(start_date=start_date, end_date=end_date) - data = {'subject': nickname, 'implant_weight': subject.implant_weight, 'records': records} + data = {'subject': nickname, 'implant_weight': subject.implant_weight, + 'reference_weight_pct': subject.water_control.reference_weight_pct, + 'zscore_weight_pct': subject.water_control.zscore_weight_pct, + 'records': records} return Response(data) diff --git a/alyx/actions/water_control.py b/alyx/actions/water_control.py index b27cc2fd9..ef6ad6852 100644 --- a/alyx/actions/water_control.py +++ b/alyx/actions/water_control.py @@ -8,6 +8,7 @@ from operator import attrgetter, itemgetter import os.path as op +from django.conf import settings from django.urls import reverse from django.utils.html import format_html from django.http import HttpResponse @@ -563,7 +564,9 @@ def water_control(subject): implant_weight=subject.implant_weight ) wc.add_threshold(percentage=rw_pct + zw_pct, bgcolor=PALETTE['orange'], fgcolor='#FFC28E') - wc.add_threshold(percentage=.7, bgcolor=PALETTE['red'], fgcolor='#F08699', line_style='--') + if absolute_min := settings.WEIGHT_THRESHOLD: + wc.add_threshold( + percentage=absolute_min, bgcolor=PALETTE['red'], fgcolor='#F08699', line_style='--') # Water restrictions. wrs = sorted(list(subject.actions_waterrestrictions.all()), key=attrgetter('start_time')) # Reference weight. diff --git a/alyx/alyx/settings_lab_template.py b/alyx/alyx/settings_lab_template.py index 4f8ac7a81..29c2e8368 100644 --- a/alyx/alyx/settings_lab_template.py +++ b/alyx/alyx/settings_lab_template.py @@ -10,7 +10,7 @@ DEFAULT_PROTOCOL = '1' SUPERUSERS = ('root',) STOCK_MANAGERS = ('root',) -WEIGHT_THRESHOLD = 0.75 +WEIGHT_THRESHOLD = 0.8 # Absolute minimum weight threshold (red line in plots) DEFAULT_LAB_NAME = 'defaultlab' WATER_RESTRICTIONS_EDITABLE = False # if set to True, all users can edit water restrictions DEFAULT_LAB_PK = '4027da48-7be3-43ec-a222-f75dffe36872' diff --git a/alyx/experiments/serializers.py b/alyx/experiments/serializers.py index 92ad06a85..9e72f688d 100644 --- a/alyx/experiments/serializers.py +++ b/alyx/experiments/serializers.py @@ -46,15 +46,6 @@ class TrajectoryEstimateSerializer(serializers.ModelSerializer): queryset=CoordinateSystem.objects.all(), ) - def to_internal_value(self, data): - if data.get('chronic_insertion', None) is None: - data['chronic_insertion'] = None - - if data.get('probe_insertion', None) is None: - data['probe_insertion'] = None - - return super(TrajectoryEstimateSerializer, self).to_internal_value(data) - class Meta: model = TrajectoryEstimate fields = '__all__' diff --git a/alyx/experiments/tests_rest.py b/alyx/experiments/tests_rest.py index c2138d1e3..412a4a6b6 100644 --- a/alyx/experiments/tests_rest.py +++ b/alyx/experiments/tests_rest.py @@ -185,6 +185,7 @@ def test_create_list_delete_trajectory(self): # create a trajectory url = reverse('trajectoryestimate-list') tdict = {'probe_insertion': alyx_insertion['id'], + 'chronic_insertion': None, 'x': -4521.2, 'y': 2415.0, 'z': 0, @@ -216,6 +217,7 @@ def test_create_list_delete_channels(self): # create the probe insertion pi = self.ar(self.post(reverse('probeinsertion-list'), self.dict_insertion), 201) tdict = {'probe_insertion': pi['id'], + 'chronic_insertion': None, 'x': -4521.2, 'y': 2415.0, 'z': 0, @@ -273,6 +275,7 @@ def test_chronic_insertion(self): # create a trajectory and attach it to the chronic insertion traj_dict = {'chronic_insertion': ci['id'], + 'probe_insertion': None, 'x': -4521.2, 'y': 2415.0, 'z': 0, diff --git a/alyx/subjects/serializers.py b/alyx/subjects/serializers.py index b6a2877d9..e9f954bfa 100644 --- a/alyx/subjects/serializers.py +++ b/alyx/subjects/serializers.py @@ -28,10 +28,18 @@ def get_reference_weight(self, obj): def get_last_water_restriction(self, obj): return obj.water_control.water_restriction_at() + def get_reference_weight_pct(self, obj): + return obj.water_control.reference_weight_pct + + def get_zscore_weight_pct(self, obj): + return obj.water_control.zscore_weight_pct + expected_water = serializers.SerializerMethodField() remaining_water = serializers.SerializerMethodField() reference_weight = serializers.SerializerMethodField() last_water_restriction = serializers.SerializerMethodField() + reference_weight_pct = serializers.SerializerMethodField() + zscore_weight_pct = serializers.SerializerMethodField() class WaterRestrictedSubjectListSerializer(_WaterRestrictionBaseSerializer): @@ -42,6 +50,8 @@ class Meta: 'remaining_water', 'reference_weight', 'last_water_restriction', + 'reference_weight_pct', + 'zscore_weight_pct' ) lookup_field = 'nickname' diff --git a/requirements.txt b/requirements.txt index cdf85406e..bfa1e6961 100644 --- a/requirements.txt +++ b/requirements.txt @@ -28,4 +28,4 @@ python-magic pytz structlog>=21.5.0 webdavclient3 -ONE-api~=2.7rc0 +ONE-api>=2.7 diff --git a/requirements_frozen.txt b/requirements_frozen.txt index 3fefe9549..d8871602d 100644 --- a/requirements_frozen.txt +++ b/requirements_frozen.txt @@ -1,7 +1,7 @@ asgiref==3.8.1 backports.zoneinfo==0.2.1 -boto3==1.34.70 -botocore==1.34.70 +boto3==1.34.84 +botocore==1.34.84 certifi==2024.2.2 cffi==1.16.0 charset-normalizer==3.3.2 @@ -16,11 +16,11 @@ cryptography==42.0.5 cycler==0.12.1 Django==4.2.11 django-admin-list-filter-dropdown==1.0.3 -django-admin-rangefilter==0.12.1 +django-admin-rangefilter==0.12.4 django-autocomplete-light==3.11.0 django-cleanup==8.1.0 -django-filter==24.1 -django-ipware==6.0.4 +django-filter==24.2 +django-ipware==6.0.5 django-js-asset==2.2.0 django-mptt==0.14.0 django-polymorphic==3.1.0 @@ -33,9 +33,9 @@ docopt==0.6.2 docutils==0.20.1 drfdocs==0.0.11 flake8==7.0.0 -fonttools==4.50.0 -globus-cli==3.26.0 -globus-sdk==3.37.0 +fonttools==4.51.0 +globus-cli==3.27.0 +globus-sdk==3.39.0 iblutil==1.8.0 idna==3.7 importlib_metadata==7.1.0 @@ -45,7 +45,7 @@ Jinja2==3.1.3 jmespath==1.0.1 kiwisolver==1.4.5 llvmlite==0.41.1 -lxml==5.1.0 +lxml==5.2.1 Markdown==3.6 MarkupSafe==2.1.5 matplotlib==3.7.5 @@ -59,22 +59,22 @@ pillow==10.3.0 psycopg2-binary==2.9.9 pyarrow==15.0.2 pycodestyle==2.11.1 -pycparser==2.21 +pycparser==2.22 pyflakes==3.2.0 PyJWT==2.8.0 pyparsing==3.1.2 python-dateutil==2.9.0.post0 -python-ipware==2.0.2 +python-ipware==2.0.3 python-magic==0.4.27 pytz==2024.1 PyYAML==6.0.1 requests==2.31.0 s3transfer==0.10.1 six==1.16.0 -sqlparse==0.4.4 +sqlparse==0.5.0 structlog==24.1.0 tqdm==4.66.2 -typing_extensions==4.10.0 +typing_extensions==4.11.0 tzdata==2024.1 uritemplate==4.1.1 urllib3==1.26.18 diff --git a/scripts/sync_ucl/prune_cortexlab.py b/scripts/sync_ucl/prune_cortexlab.py index 1e04db2eb..3f24ee2e4 100755 --- a/scripts/sync_ucl/prune_cortexlab.py +++ b/scripts/sync_ucl/prune_cortexlab.py @@ -45,8 +45,7 @@ # the sessions should also have the cortexlab lab field properly labeled before import if Lab.objects.using('cortexlab').filter(name='cortexlab').count() == 0: - lab_dict = {'pk': CORTEX_LAB_PK, - 'name': 'cortexlab'} + lab_dict = {'pk': CORTEX_LAB_PK, 'name': 'cortexlab'} lab = Lab.objects.using('cortexlab').create(**lab_dict) lab.save() else: