diff --git a/README.md b/README.md index 5619cb9..0703388 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ cd iris python setup.py install ``` -If you are altering the IRIS source code then you made find it easier to install like below, to avoid having to reinstall it every time a change is made +If you are altering the IRIS source code then you may find it easier to install like below, to avoid having to reinstall it every time a change is made ``` pip install -e ./ ``` @@ -34,12 +34,14 @@ Once installed, you can run the demo version of IRIS iris demo ``` -Having run the demo, you can then create a personalised config file, based on _demo/cloud-segmentation.json_. With your own config file, you can then instantiate your own custom project. Here is a guide on how to write your own config file. +Having run the demo, you can then create a personalised config file, based on _demo/cloud-segmentation.json_. With your own config file, you can then instantiate your own custom project. Here is a guide on how to write your own config file. ``` iris label ``` +It is recommended to use a keyboard and mouse with scrollwheel for IRIS. Currently, control via trackpad is limited and awkward. + ### Docker You can also use Docker to deploy IRIS. First, build an image (run from IRIS's root directory). Then, you can use docker run to launch IRIS. However, please note that port-forwarding is needed (here we use port 80 as an example for a typical http setup, but the port number can be set in your IRIS config file) and the directory to your project also needs to be given as a volume to docker. @@ -49,5 +51,8 @@ docker build --tag iris . docker run -p 80:80 -v :/dataset/ --rm -it iris label /dataset/cloud-segmentation.json ``` +### Run on Github Codespaces +To run in a [Github codespace](https://docs.github.com/en/codespaces/overview) fork this repository, then in the Github UI select `Code/Codespaces/Open in codespace`. Run `pip install -e .` and then `iris demo`. You will see a popup that there is an app on port 5000, click the link to open a new window showing Iris 🎉 + **Visit the official iris Github page: https://github.com/ESA-PhiLab/iris** diff --git a/TODO.md b/TODO.md index 1c65da9..8a48735 100644 --- a/TODO.md +++ b/TODO.md @@ -32,7 +32,7 @@ - [ ] Add helper tips for each field on Preferences tab after ~1 second mouse hover - [ ] Add admin tab for data statistics visualisation over the whole dataset. E.g. class pie-chart, RF confusion matrix, input dimension importance, etc. - [ ] Add "iris export PROJECT" command to save final versions of masks, and output some python-friendly (e.g. pandas) tables to look at dataset statistics - +- [ ] Add automatic config checker to spot common logic errors. Currently many typos/errors in config do not lead to a good error message. ### Big future plans: diff --git a/iris/admin/__init__.py b/iris/admin/__init__.py index a5e81cf..1fb73fd 100644 --- a/iris/admin/__init__.py +++ b/iris/admin/__init__.py @@ -2,6 +2,7 @@ from datetime import timedelta import flask +import markupsafe from sqlalchemy import func from iris.user import requires_admin, requires_auth @@ -44,7 +45,7 @@ def users(): users_json = [user.to_json() for user in users] html = flask.render_template('admin/users.html', users=users_json, order_by=order_by, ascending=ascending) - return flask.render_template('admin/index.html', user=user, page=flask.Markup(html)) + return flask.render_template('admin/index.html', user=user, page=markupsafe.Markup(html)) @admin_app.route('/actions/', methods=['GET']) @requires_auth @@ -74,7 +75,7 @@ def actions(type): 'admin/actions.html', action_type=type, actions=actions_json, image_stats=image_stats, order_by=order_by, ascending=ascending ) - return flask.render_template('admin/index.html', user=user, page=flask.Markup(html)) + return flask.render_template('admin/index.html', user=user, page=markupsafe.Markup(html)) @admin_app.route('/images', methods=['GET']) @requires_auth @@ -117,4 +118,4 @@ def images(): html = flask.render_template( 'admin/images.html', images=images, order_by=order_by, ascending=ascending ) - return flask.render_template('admin/index.html', user=user, page=flask.Markup(html)) + return flask.render_template('admin/index.html', user=user, page=markupsafe.Markup(html)) diff --git a/iris/main/__init__.py b/iris/main/__init__.py index 4ebc150..df06bd9 100644 --- a/iris/main/__init__.py +++ b/iris/main/__init__.py @@ -2,6 +2,7 @@ import json import flask +import markupsafe import numpy as np from PIL import Image as PILImage from skimage.transform import resize @@ -92,7 +93,7 @@ def metadata(image_id): if flask.request.args.get('safe_html', False): metadata = { - k: flask.Markup(str(v)) + k: markupsafe.Markup(str(v)) for k, v in metadata.items() } diff --git a/iris/project.py b/iris/project.py index bf026c7..9c435b3 100644 --- a/iris/project.py +++ b/iris/project.py @@ -10,6 +10,8 @@ import re import flask +import markupsafe + import json from matplotlib import cm import numpy as np @@ -95,7 +97,7 @@ def load_from(self, filename): # Make sure the HTML is understood in the descriptions: for name, view in self.config['views'].items(): view['name'] = name - view['description'] = flask.Markup( + view['description'] = markupsafe.Markup( view.get('description', view['name']) ) view['stretch'] = view.get('stretch', 'linear') diff --git a/iris/segmentation/__init__.py b/iris/segmentation/__init__.py index 16bcc89..d6880d5 100644 --- a/iris/segmentation/__init__.py +++ b/iris/segmentation/__init__.py @@ -272,7 +272,7 @@ def save_mask(image_id): # The user mask denotes who classified the pixels in the mask: # if true: the user classified the pixel # if false: the AI classified the pixel - user_mask = data[1+mask_length:-1].astype(np.bool) + user_mask = data[1+mask_length:-1].astype(bool) user_mask = user_mask.reshape(project['segmentation']['mask_shape'][::-1]) final_mask_file, user_mask_file = get_mask_filenames(image_id, user_id) diff --git a/iris/utils.py b/iris/utils.py index 821d129..7ec89be 100644 --- a/iris/utils.py +++ b/iris/utils.py @@ -1,7 +1,7 @@ from copy import deepcopy import flask - +import markupsafe class View: @@ -12,8 +12,8 @@ def __init__(self, name, description, loader): def to_json(self): return { - 'name': flask.Markup(self.name), - 'description': flask.Markup(self.description), + 'name': markupsafe.Markup(self.name), + 'description': markupsafe.Markup(self.description), } def merge_deep_dicts(d1, d2): diff --git a/requirements.txt b/requirements.txt index fd5adb7..8ea4af3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,8 +1,8 @@ -flask==2.2.2 +flask==2.3.2 flask_compress==1.13 flask-sqlalchemy==2.5.1 numpy==1.23.4 -pyyaml==5.4.1 +pyyaml>=5.4.1 lightgbm==3.3.3 rasterio==1.3.3 requests==2.28.1