Overview
Slide Score API allows programmatically uploading slides, creating studies and downloading results.
You can for example:
-
write a script that uploads slides to the server, configures them so that each rater sees a unique set, sends the raters an email with a unique link to let them score it, checks if they have finished scoring and downloads the scores.
-
create integration with your lab management system.
-
train your deep learning image analysis model on pixel data requested from Slide Score, push the results back for review by pathologists and use that to improve the model further
An API token is used to secure access to the API, the token can only be created by site administrators.
This API is based on common tasks that need to be done.
You can try out the API methods using the Swagger interface.
You can either write a script that sends the HTTP requests directly or make use of C# or Python SDKs. If you use C# have a look at an example client in C# that includes SlideScoreClient.cs class that will help you make the API calls.
For Python install the SDK module with pip install slidescore-sdk
.
The APIClient class in the SDK has methods that directly correspond to the API calls. See the Python SDK package for examples and more details. Alternatively, Netherlands Cancer Institute maintains a fork with support for shapely and GeoJSON
Note that this documentation assumes some programming knowledge and is a work in progress.
Authentication
Before you can access the API you need an access token.
Login as Site Administrator and go to the Create Token page or click the Create API token button in study administration.
Fill in the name and expiration date of the token. Check below what methods you need to call and give the token only the rights that are needed only for the necessary studies.
This API token needs to be supplied for all API calls in the Authorization HTTP Header like this:
Authorization: Bearer hblJlYWRPbmx5U....3R1ZGllcyI6IiIsIkNhbk1
When you no longer need it you can give it up by calling POST /Admin/GiveupToken
with the token as POST parameter.
These are the capabilities that the token can have:
Can upload
API token can upload slides and configuration files
Can create upload folders
API token can create folders on the server to create new studies
Can upload scores
API token can upload results and annotations to studies. This is useful for image analysis workflows - models can push their results to Slide Score.
Can download configuration files for studies
API token can request the current configuration of studies in the form of configuration files. This is useful if you want to synchronize external database with Slide Score configuration.
Can read raw tiles from slides and their metadata
API token can read image tiles. The API has 3 ways to access the pixels GetScreenshot (the most high level call - request a region and level of detail), GetTile (DeepZoom-like request), GetRawTile (request that's forwarded to the slide libraries - OpenSlide and others. You need to check the image metadata first - levels in the slide and so on). See Getting pixel data
With this right image analysis algorithm can request (and cache) the pixels of slides.
Can upload only in folders
This is a restriction.
Semicolon-separated list of folders on the server to which the token can upload. If you leave it empty API token can upload slides in any folder. If you set it API token won't be allowed to upload to any other folders.
Can read (get scores, images) only these studies
This is a restriction.
Semicolon-separated list of studies which the token can read - download scores (with Can get scores of any study
), images, ...
If you leave it empty API token can read any study. If you set it API token won't be allowed to read any other studies.
Can modify (upload images, delete, reimport) only these studies
This is a restriction.
Semicolon-separated list of studies which the token can modify - add slides, reimport, ... If you leave it empty API token can modify any study. If you set it API token won't be allowed to modify any other studies.
Can create studies
Unused at the moment
Can reimport studies
API token can (after uploading configuration files and slides) re-import a study.
This will read configuration files and apply changes to the study. Note that it can overwrite changes made manually in the administration interface - you can use GetConfigFiles
to create up-to-date config files and change only those.
You always need to run reimport after you upload the slide(s) using the API otherwise they won't show up.
Can delete owned studies
Unused at the moment
Can get scores of owned studies
API token can retrieve (unless Can read blocks it) scores of studies that the token has created.
Can get scores of any study
API token can retrieve (unless Can read blocks it) scores of any study.
Can get study configuration
API token can retrieve (unless Can read blocks it) configuration files of any study and can send emails on behalf of the Slide Score server.
Can download
API token can download actual files containing the image data in original format (unless Can read blocks it)
Can delete
API token can delete slides from a study (unless Can modify blocks it)
Can handle paths
API token can request and update file paths of the slide files. This can be used for e.g. archival of unused slides.
Can handle domains
API token can request and update domains of studies. Domain administrator can create API tokens for study in their domain.
Can handle student accounts
API token can create student accounts and generate links for them to login
Get study status
Get results
GET Api/Scores
Required rights: Can read
the study, Can get scores of owned studies
or at least Can get scores of any study
if it was created by the API token
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
studyId | int | yes | Study which you want to download scores from |
question | string | no | Optional, return only answers to this question |
string | no | Optional, return only answers by this user | |
imageid | string | no | Optional, return only answers for this image |
caseid | string | no | Optional, return only answers for this case |
Returns tab separated file with all the scores from the study. The format is the same as when downloading results manually.
GET Api/GetStudiesUpdated
Required rights: Can read
, Can get scores of owned studies
or at least Can get scores of any study
if it was created by the API token
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
since | string | yes | ISO 8601 date and time string with timezone |
Returns JSON object with an array of integer IDs in StudyIDs
- IDs of studies that had results submitted since the given date
You can use this method if you are periodically checking for new results.
GET Api/Sessions
Required rights: Can read
, Can get scores of owned studies
or at least Can get scores of any study
if it was created by the API token
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
studyId | int | yes | Study which you want to download sessions |
string | no | Optional, return only sessions by this user | |
imageid | int | no | Optional, return only sessions for this image |
Returns JSON object with fields success
(must be true) and sessions
- array of session objects with id, imageID, email, length (number of events), studyID and createdOn. You can get details of the session by calling GET Api/SessionEvents
GET Api/SessionEvents
Required rights: Can read
, Can get scores of owned studies
or at least Can get scores of any study
if it was created by the API token
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
studyId | int | yes | Study which you want to download session events |
sessionId | int | yes | Session ID during which the events were recorded |
Returns JSON object with fields success
(must be true) and events
- array of strings which are tab separated Timestamp (in ms since start of session), X, Y, Width and Height (coordinates of the viewing area), Cursor X and Cursor Y (coordinates of the mouse cursor)
Example using Python SDK:
studyid=1
client = APIClient(url, token)
sessionid=client.get_sessions(studyid)[0].id
print(client.get_session_events(studyid, sessionid)[0].timestamp)
Get study structure
GET Api/Studies
Required rights: Can read
Parameters: None
Returns
JSON array of all studies this token can view with their ID
, Name
, FriendlyName
(label or alias), Folder
, Organ
, Disease
, Stainings
, ExternalID
, Description
and PublishedOn
(studies that have not been published yet are invisible for users without access to study administration).
GET Api/Images
Required rights: Can read
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
studyId | int | yes | Study which you want to list images from |
Returns
JSON array of images with their ID
and Name
. Useful for creating reports with links to view the slide.
You can construct an URL like https://server/Image/Details?imageId=1&studyId=2
that will open image with ID=1 in study with ID=2.
For TMAs you can use additional GET parameters to select single or few cores:
tmaRow
andtmaCol
for row and column (0-based) respectivelytmaSample
searches for TMA core with this Sample ID. If it is unique it selects and zooms in otherwise it shows up in the "Search" paneltmaId
internal TMA core ID
GET Api/Cases
Required rights: Can read
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
studyId | int | yes | Study which you want to list cases from |
Returns
JSON array of cases with their ID
and Name
.
GET Api/Questions
Required rights: Can read
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
studyId | int | yes | Study which you want to list questions from |
Returns
JSON array of questions with their ID
, Name
, Type
, TypeName
and ValuesAllowed
.
GET Api/GetSlidePath
Required rights: CanHandlePaths
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
imageId | int | yes | Slide ID for which to retrieve the file path |
Returns JSON object with fields success
(must be true) and path
- path relative to the application folder or error
field.
GET Api/GetSlideDescription
Required rights: None (must be able to read the study)
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
imageId | int | yes | Slide ID for which to retrieve the description |
Returns JSON object with fields success
(must be true) and description
(HTML-encoded) or error
field.
GET Api/GetSlideDetails
Required rights: None (must be able to read the study)
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
imageId | int | yes | Slide ID for which to retrieve the details |
JSON object with attributes success
, studyID
, name
, studyName
, caseID
, caseName
, mpp
, height
, width
, rotate
, fileSize
, tmaCoreSize
, tmaMapName
, md5first10k
or error
. md5first10k
contains an MD5 hash of the first 10KB of the slide file.
GET Api/GetCaseDescription
Required rights: None (must be able to read the study)
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
caseId | int | yes | Case ID for which to retrieve the description |
Returns JSON object with fields success
(must be true) and description
(HTML-encoded) or error
field.
POST Api/Publish
Required rights: None (must be able to modify the study)
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
studyId | int | yes | Study that should be published |
Publish the study so that users without Edit right can see it.
POST Api/Unpublish
Required rights: None (must be able to modify the study)
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
studyId | int | yes | Study that should be unpublished |
Unpublish the study so that users without Edit right can not see it.
GET Api/DownloadSlide
Required rights: Can read
, Can download
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
studyId | int | yes | Study which you want to download image from |
imageId | int | yes | Which image to download |
Returns
The slide file. Note that it can be very large (>10GB). Please, use the file name from the Content-Disposition header to set the correct file extension on the downloaded file.
POST Api/IsSlideOutOfFocus
Required rights: Can read
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
studyId | int | yes | Study which contains the image |
imageId | int | yes | Which image to check for focus |
Returns
JSON object with fields success
(must be true) and isOOF
(true if the slide is out-of-focus or blurry) or error
field.
POST Api/UpsertDomain
Upsert here means UPdate or inSERT, a single method to do either.
Required rights: Can handle domains
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
id | int or null | no | Null for creating a new domain, ID of an existing domain to update it |
name | string | yes | Name of the domain |
administrators | string | no | Semicolon separated list of email addresses of domain administrators. These users will be able to create API tokens for this domain |
uploadFolder | string | no | Relative path where API tokens from this domain will be allowed to upload, '.' for uploading everywhere allowed or null for uploading not allowed |
Returns
JSON object with attribute success
, id
with the domain ID or message
with eventual error message.
GET Api/GetDomainForStudy
Required rights: Can handle domains
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
studyId | int | yes | Study for which to get the domain |
Returns
JSON object with attribute success
, id
with the domain ID (or null) or message
with eventual error message.
POST Api/SetDomainForStudy
Required rights: Can handle domains
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
studyId | int | yes | Study for which to set the domain |
domainId | int or null | yes | ID of the new domain |
Returns
JSON object with attribute success
, id
with the domain ID or error
with eventual error message.
POST Api/GenerateStudentAccount
Required rights: Can handle student accounts
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
username | string | yes | Desired username for the student, must contain @ |
string | no | Contact email for the student | |
classId | int | yes | ID of the class to which the student should be added |
Creates an account for a student. The username must not be used in the system yet or given any study rights. The method returns the password for the student.
Returns
JSON object with attribute success
, password
with the generated password or error
with eventual error message.
POST Api/GenerateLoginLink
Required rights: Can handle student accounts
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
username | string | no | Username of the student |
expiresOn | string | yes | ISO 8601 date and time string with timezone |
Creates a link with specified expiration that automatically logs user in. Only usable for student accounts who don't have any study rights.
Returns
JSON object with attribute success
, link
with the generated link or error
with eventual error message.
POST Api/GenerateSlideFileURL
Required rights: Can handle paths
and no limits on studies
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
filename | string | yes | Filename of the slide to show |
user | string | yes | User that will view the slide |
Creates a link that shows the slide file even if it isn't in Slide Score. Filename must be a valid path on the server. This link can also be embedded in an iframe.
Returns
JSON object with attribute success
, link
with the generated link or error
with eventual error message.
Create studies
POST Api/CreateStudy
Required rights: None
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
name | string | yes | Name of the new study, only A-Z, a-z, 0-9, ' ' and _ are allowed |
Returns
JSON object with attribute success
, id
containing the new study ID and message
with eventual error message.
POST Api/UpdateStudy
Required rights: Can modify
, for modifying folderForStudy Can handle paths
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
studyId | int | yes | ID of the study to modify |
see below |
This method can be used to modify all settings on the study.
All parameters are optional, if not supplied the value is not modified. Please refer to study administration for meaning of the parameters.
String parameters can be set to "" (empty string) to set the value to null:
friendlyName, folder, description, disease, organ, stainings, folderForStudy, usersToNotifyOnNewSlide, artID
Boolean parameters can be true, false or null to not modify existing value:
disallowNavigation, isTraining, showLabels, showThumbnails, disallowRewritingScores, hideSlideNames, scoreStudyTogether, allowSharingSlidesAnonymously, majorityOpinionOnlyTeachers, randomizeNamesAndOrder, showOtherPeoplesScores, scoreTMACoresAtOnce, allowResultsComparisonForEveryone, randomizeOnlyCaseNamesAndOrder, trackMouseAndView, showTMASampleIDs
Returns
JSON object with attribute success
and message
with eventual error message.
Upload
Uploading a file has 3 steps:
- POST RequestUpload
- Upload using Tus.io
- POST FinishUpload
POST RequestUpload
Required rights: Can upload
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
filename | string | yes | Filename (without path) to use for the file on the server - this can be used to rename slides |
folder | string | no | Folder on the server (under the images root) to which the file should be uploaded. Note that you can only upload to the root folder, it subfolders and their subfolders, if empty studyId has to be set and it will determine the folder |
studyId | int | no | if folder is not set it will be set to name of this study |
Returns
JSON object with token
attribute. This is the upload token you will need for uploading.
Upload using Tus.io
You can use any of Tus.io's clients to perform the upload.
Add uploadtoken
that you've received from previous step and API token (as apitoken
) as metadata.
You will receive fileid
that you will need in the next step
POST FinishUpload
Required rights: Can upload
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
token | string | yes | upload token from RequestUpload |
id | string | yes | fileid from Tus.io |
Returns
JSON string containing "OK"
When Tus is done uploading you have to commit the upload using this method.
POST Api/AddSlide
Required rights: None (must be able to modify the study)
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
studyId | int | yes | Study where the slide should be added |
path | string | yes | The relative server path to a file |
This method directly adds a previously uploaded slide to the study.
Returns
JSON object with attribute success
, id
containing the new slide ID and isOOF
: true if the slide is blurry or out of focus; or a message with eventual error message.
It's possible to upload scoring results to Slide Score - this is useful if you have some legacy slides that you want to review or you are moving all the data to a single repository - Slide Score. This is also very useful for Active learning - training image analysis models with manual corrections with quick turn-around.
POST Api/UploadResults
Required rights: Upload scores
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
studyId | int | yes | Study where results should be imported |
results | string | yes | The results should have the same format as when you download them from Slide Score |
This is the format of results expected:
ImageID(tab)Name(tab)By(tab)(optionally: TMA Row(tab)TMA Col(tab)TMA Sample(tab))Question(tab)Answer
Note that the first line of results is assumed to be the header and is ignored!
You can use the Python SDK class SlideScoreResult to work with the results. Initiate its properties and then call toRow()
to get a line that represents that result.
Here is an example that inserts a single annotation consisting of an ellipse:
res=SlideScoreResult()
res.study_id = 1
res.image_id = 2
res.email = 'jan@slidescore.com'
res.score_id = 3
res.question = 'Annotation question'
res.case_name=None
res.answer = '[{ "type": "ellipse",'\
'"center": { "x": 123795, "y": 54143 }, "size": { "x":1100, "y":1100} '\
'"labels": {'\
'"label": "Interesting area",'\
'"x": 123795,'\
'"y": 54143,'\
'"whenToShow": "always",'\
'"fontSize": 12 }]'
client = APIClient(url, token)
print(client.perform_request("UploadResults", {
"studyid": 1,
"results": "#header\n"+res.toRow()
}, method="POST").text)
POST Api/ConvertAnnotationToAnno2
Required rights: None (must be able to modify the study)
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
studyId | int | yes | Study which contains the existing annotation |
caseId | int | no | Corresponding case |
imageId | int | yes | Corresponding slide |
tmaCoreId | int | no | Corresponding TMA core |
scoreId | int | no | Corresponding question ID |
question | string | no | Corresponding question name, either this or ID must be present |
string | yes | Author of the answer | |
metadata | string | no | Optional metadata. Note that metadata is included in deduplication - so annotations with different metadata count as different annotations and won't be deduplicated. |
Converts the standard JSON annotation into Anno2 a highly compressed, read-only, binary format that supports 10s of millions of annotation points.
POST Api/CreateAnno2
Required rights: Upload scores
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
studyId | int | yes | Study where anno2 should be created |
caseId | int | no | Corresponding case |
imageId | int | yes | Corresponding slide |
tmaCoreId | int | no | Corresponding TMA core |
scoreId | int | no | Corresponding question ID |
question | string | no | Corresponding question name, either this or ID must be present |
string | yes | Author of the answer |
Creates a Anno2 record (a highly compressed, read-only, binary format that supports 10s of millions of annotation points) and returns a unique identifier under which the Anno2 data file can be uploaded. The upload file name isn't used.
Returns
JSON object with attributes success
, error
and uploadToken
that can be used when uploading and annoUUID
that contains the unique identifier of the Anno2.
Updating slide properties
POST Api/SetSlideResolution
Required rights: None (must be able to modify the study)
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
studyId | int | yes | Study where the slide should be added |
imageId | int | yes | Slide ID that should be changed |
micronsPerPixel | double | yes | new value to set, typical value if 0.2 for 40x slides. This means that 1 pixel is 0.2 microns wide and tall, must be > 0 and < 1 000 000 |
Change the resolution of the slide. This can be useful when the slide file contains no or incorrect resolution information.
POST Api/SetSlideDescription
Required rights: None (must be able to modify the study)
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
studyId | int | yes | Study where the slide should be added |
imageId | int | yes | Slide ID that should be changed |
description | string | yes | new slide description. Can contain limited html formatting |
Change the description of the slide. Slide Score severely limits HTML tags and attributes that can be used in the description to make hacking more difficult, so it's best to first create a description using the editor for an existing slide and then adapt that.
POST Api/UpdateSlideName
Required rights: None (must be able to modify the study)
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
imageId | int | yes | Slide ID that should be changed |
newName | string | yes | new slide name |
Change the name of the slide.
POST Api/UpdateCaseName
Required rights: None (must be able to modify the study)
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
caseId | int | yes | Case ID that should be changed |
newName | string | yes | new slide name |
Change the name of the case.
POST Api/UpdateSlidePath
Required rights: CanHandlePaths
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
imageId | int | yes | Slide ID that should be changed |
newPath | string | yes | new slide file path relative to the application folder |
Change the path of the slide files. Note that the file must exist. Returns JSON object with fields success
(must be true) or error
field.
POST Api/SetIsArchived
Required rights: CanHandlePaths
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
imageId | int | yes | Slide ID that should be changed |
isArchived | bool | yes | new IsArchived flag |
Sets the IsArchived flag on a slide. When user tries to open an archived slide they see a more specific error than just "Can't open slide file". Returns JSON object with fields success
(must be true) or error
field.
POST Api/UpdateTMACoreSize
Required rights: None (must be able to modify the study)
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
studyId | int | yes | Study in which you want to update the image |
imageId | int | yes | Slide ID that should be changed |
newRadiusMm | double | yes | new radius of TMA cores in mm, use negative values to reset to default |
Sets the TMA core size for a slide. Returns JSON object with fields success
(must be true) or error
field.
POST Api/DeleteSlide
Required rights: Can modify
, Can delete
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
studyId | int | yes | Study from which you want to delete the image |
imageId | int | yes | Which image to delete |
Returns
Empty result on success.
GET Api/GetQupathTokensForStudy
Returns a list of emails and creation dates of existing ImageTokens for use with QuPath for a given study. It is useful to call this before DeleteSlide or DeleteStudy if you suspect some users might be using the slide in QuPath for image analysis.
Required rights: Can modify
, Can delete
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
studyId | int | yes | Study which contains the image |
Returns
JSON object with attributes success
and array tokens
of objects with email
, imageID
and createdOn
or error
POST Api/AddCase
Required rights: Can modify
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
name | string | yes | Name of the new case |
studyId | int | yes | Study to which to add the slide |
description | string | no | Description of the new case |
Returns
JSON object with attribute success
, id
containing the new case ID and message
with eventual error message.
POST Api/SetImageCase
Required rights: Can modify
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
imageId | int | yes | Slide that should be added to (or removed from) a case |
caseId | int | no | Case to which it should be added or null to remove slide from case |
studyId | int | yes | Study in which to modify the slide |
Returns
JSON object with attribute success
and message
with eventual error message.
POST Api/RemoveCase
Required rights: Can modify
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
caseId | int | yes | Case to remove |
studyId | int | yes | Study in which to remove the case |
Returns
JSON object with attribute success
and message
with eventual error message.
POST Api/DeleteStudy
Required rights: Can modify
, Can delete slides
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
studyId | int | yes | Study to delete |
Marks study as deleted, undo using UndeleteStudy. Deleted studies can only be accessed by site admins.
JSON object with attribute success
and message
with eventual error message.
POST Api/UndeleteStudy
Required rights: Can modify
, Can delete slides
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
studyId | int | yes | Study to undelete |
Undeletes study deleted using DeleteStudy.
JSON object with attribute success
and message
with eventual error message.
Annotation format
Annotations are stored as JSON arrays of objects in Slide Score. All coordinates and sizes are in image pixels (at the highest resolution).
AnnoPoints format
Answers to AnnoPoints type questions are stored as arrays of objects with x and y coordinates, for example:
[{"x": 37591, "y": 18439}, {"x": 37518, "y": 18420}, ... ]
AnnoShapes format
Answers to AnnoShapes type questions are stored as arrays of objects. Each object has a type and other common properties and some type-specific properties:
Common properties
Name | Type | Required | Explanation |
---|---|---|---|
type | string | yes | One of: polygon, polyline, ellipse, rect (for rectangle), brush or heatmap |
modifiedOn | Date | no | Datetime of last modification (in UTC timezone), for example "2022-07-12T13:55:12.458Z" |
area | string | no | Total area of annotation including unit, for example "105 mm2", if not present it will be recalculated next time the annotation is changed by the user |
labels | array of Labels | no | Array of Label objects (see below) |
Polygon and polyline properties
Name | Type | Required | Explanation |
---|---|---|---|
points | array of coordinates | yes | array of coordinate objects specifying the vortices of the polygon. Clockwise or anticlockwise. Last and first point will be connected by line only if type is polygon. For example [{"x": 37591, "y": 18439}, {"x": 37518, "y": 18420}, ... ] |
Ellipse properties
Name | Type | Required | Explanation |
---|---|---|---|
x,y | number | yes | Coordinates of the center of the ellipse |
width, height | number | yes | Total width and height (radius times 2) of the ellipse. |
Rectangle properties
Name | Type | Required | Explanation |
---|---|---|---|
corner | coordinate | yes | Coordinates of the left top corner of the rectangle |
size | coordinate | yes | Width (x) and height (y) of the rectangle. |
Brush properties
Name | Type | Required | Explanation |
---|---|---|---|
positivePolygons | array of array of coordinates | yes | Set of polygons that make the outline of the shape |
negativePolygons | array of array of coordinates | yes | Set of polygons that make the "holes" of the shape, note that holes can't contain any outline polygons |
Heatmap properties
Name | Type | Required | Explanation |
---|---|---|---|
data | array of array of numbers | yes | Data specifying the heatmap. Rectangular (all arrays have the same length) array of arrays of value 0 to 255. 0 is always transparent, |
x,y | coordinates | no | Coordinates of the upper left corner where to place the heatmap, if not specified it is placed at 0,0 |
width, height | number | no | Width and height of the area where to place the heatmap. Cannot be combined with downscale. If neither are specified heatmap is stretched to the rest of the image ie. from (x,y) to (maxx, maxy) |
downscale | number | no | How width (in image pixels) is one data point of the heatmap. Cannot be combined with width or height. If neither are specified heatmap is stretched to the rest of the image ie. from (x,y) to (maxx, maxy) |
Label properties
Name | Type | Required | Explanation |
---|---|---|---|
label | string | yes | Text of the label |
x,y | number | yes | Coordinates where should the label be displayed |
whenToShow | string | yes | Whether the label should be shown always or only when user moves their mouse over the shape to which the label belongs, values allowed: "always" or "mouseover" |
fontSize | number | yes | Size of the text in image pixel coordinates |
ASAP interoperability
Slide Score supports exchanging annotations with ASAP. Since both programs use slightly different way to organize the annotations you might want to specify how to map colors in ASAP to questions in Slide Score.
GET Api/ExportASAPAnnotations
Required rights: Can get scores
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
imageId | int | yes | Image for which annotations should be exported |
user | string | yes | User whose annotations/answers should be exported |
question | string | no | Which question to export if there are multiple annotation-type questions. Can be empty to export all |
Returns
Single XML file containing annotations for image imageId
created by user user
for the question (it has to be of type AnnoShapes
or AnnoPoints
).
This XML file can be loaded straight to ASAP.
POST Api/UploadASAPAnnotations
Required rights: Upload scores
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
imageid | int | yes | Image for which annotations should be imported |
user | string | yes | User under whose account these annotations/answers should be imported |
asapAnnotation | string | yes | Contents of the ASAP XML file |
questionsMap | string | no | Defines mapping between colors used in the annotation file and questions defined in the study in Slide Score, see below |
questionsMap
: Each mapping is on a new line and consists of color hex code, semicolon (;
) and the name of the question. Example mapping file:
#f0f0f0;Lymphocytes
#ff0000;Tumor area
If you don't specify questionsMap
each new color of annotations will be imported into a new question called "Imported annotation #
Returns
JSON object with attribute Success
(true
for successful import) and Log
containing log of the the import detailing generated questions and more.
Screenshots
GET Api/GetScreenshot
Required rights: Can get scores
, Can get pixels
Parameters:
string withAnnotationForUser, int x, int y, int width, int height, int level, string scoreIDs
Name | Type | Required | Explanation |
---|---|---|---|
imageID | int | yes | Image to screenshot |
x | int | no | screenshot top-left corner coordinate in pixels in most detailed level, if x, y, width and height are 0 the whole image is imaged |
y | int | no | screenshot top-left corner coordinate in pixels in most detailed level, if x, y, width and height are 0 the whole image is imaged |
width | int | no | screenshot width in pixels in most detailed level, if x, y, width and height are 0 the whole image is imaged |
height | int | no | screenshot height in pixels in most detailed level, if x, y, width and height are 0 the whole image is imaged |
withAnnotationForUser | string | no | If the study has annotation-type questions you can include particular user's answers-annotations in the screenshot |
scoreIDs | string | no | If the study has annotation-type questions you can include only particular question IDs (comma-separated) to only select some annotations to include. If you leave it empty all annotations by withAnnotationForUser will be added. Cannot be specified in combination with question |
question | string | no | If the study has annotation-type questions you can include one particular annotation-type question to include. If you leave it empty all annotations by withAnnotationForUser will be added. Cannot be specified in combination with scoreIDs |
level | int | yes | DeepZoom level - binary exponent of the larger dimension of the resulting image - 11 for an image with larger dimensions between 1024 and 2048 pixels, 12 for 2048 - 4096 and so on |
degreesRotateClockwise | int | no | Degrees of clockwise rotation to apply to the slide. Note that the rotation that is configured for a slide in the study is not applied by default |
Returns
JPEG file with the screenshot. Note that this method can be slow and won't work for more than ~50 megapixel images. Please, request smaller ones and stitch them together.
Note that x, y, width and height all refer to the level with the highest detail so if you are requesting lower detail levels you need to multiply them by a factor of 2^(difference in levels). For example if the image is 87140x87140 pixels, the highest-detail level is 17. If we request level 12, we are looking 5 times zoomed out image. One pixel in level 12 equals 2^5=32 pixels in level 17. If we need a 100x100 image we need to request width and height equal to 32*100=3200.
Error codes: 401
for invalid token, token that doesn't have enough rights, 404
if image doesn't exist, 400
if both scoreIDs
and question
are specified
Sending emails
POST Api/SendEmail
Required rights: Can get configuration files
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
studyId | int | yes | Study that email is related to |
to | string | yes | Semicolon (;) separated list of email addresses to send it to, they have to be configured as users of the study |
subject | string | yes | Email Subject line |
body | string | yes | Text of the email to send. In plain text. It can contain token <LINK:Start Scoring> which will be replaced with a link to start scoring the study |
It will send an email to all addresses listed in to
. The From address will be info@slidescore.com.
Returns
Empty JSON object if successful.
Study configuration
Studies are set up by uploading configuration files to the root folder and image files into a subfolder. If the subfolder has the same name as the study all image files there are automatically uploaded. Otherwise, you need to reference them with an study.<studyname>.images
file (see Slides for more).
Users
Users are configured in a file study.<studyname>.emails
. This file contains one user of the study per line.
By default they get only CanScore right. You can specify viewonly
or additional rights (cangetresults
, canscore
, canedit
) separated by comma if you want to change that.
Note that you can't remove rights from a user this way, they are only added. To remove user's rights, use the administration interface.
For example:
email@example.com
email2@example.com;viewonly
email3@example.com;canscore,canedit,cangetresults
You can also use the following API calls:
POST Api/AddUser
Required rights: Can modify
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
string | yes | User to add or modify | |
studyId | int | yes | Study to which to add the user |
canScore | bool | yes | Whether the user is allowed to submit scores |
canGetResults | bool | yes | Whether the user is allowed to download results |
canEdit | bool | yes | Whether the user is allowed to administer the study |
You can add new users to a study or modify the rights of existing ones
Returns
JSON object with attribute success
and message
with eventual error message.
POST Api/RemoveUser
Required rights: Can modify
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
string | yes | User to remove | |
studyId | int | yes | Study from which the user should be removed |
Removes all rights of a user to a study, removes all their existing tokens for viewing slides
Returns
JSON object with attribute success
and message
with eventual error message.
Slides
By default all slides in a folder that has the same name as the study are imported. Additionally, this folder can contain *.images
file that references images, one image per line. Note that you don't have to reference the images that are in the study folder.
You can also specify TMA map, rotation to use with the image and potential new name, like this:
file name;map;rotation;new name;TMA core size (in mm)
Only the file name is required, the other fields can be left empty or omitted:
../otherfolder/1.svs
../otherfolder/011938r082.tif;;Nice Image
../otherfolder/2.svs;study.example.map;90;;1.2
You can also arrange slides into cases. You can specify that in study.<studyname>.cases
file in the root folder. This file contains one line per case with a list of images (by name) to include. Note that these images need to be in the study (either because they are in the folder or in one of the .images files). If you renamed the images, use the new name. If you want to include one slide in multiple cases, add a copy
directive. This example creates 4 cases with 4 slides. case1 contains just image1, case 1b contains image1 and image1i:
case1;image1;copy
case1b;image1,image1i;copy
case2;image2;copy
case2b;image2,image2i;copy
TMA Maps
You can import a TMA Map in two ways - either reference it in an .images
file in study's folder or create a map file with the name study.<studyname>.map<additional identifier>
in the root folder.
The map file can be divided into a header and the actual map.
Header contains properties and their values separated by a colon (:
). Header properties can be:
tmas
comma-separated list of slides that this map applies tocontrols
comma-separated list of TMA core IDs in the map that should be considered controls and not scoredignore
comma-separated list of TMA core IDs in the map that should be ignored - they will show up as empty spacerotate
specifies the clockwise rotation that should be applied to all slides listed intmas
in multiples of 90. Note that you can't change the rotation for a slide individually you need to create a new map for each rotationorigmap
path to the original TMA map - usually an Excel file - that users can download from the slide viewer for cross-checkingforce
if you set this to true everytime this study is reimported all scores and positions belonging to cores from this map will be deleted. If you don't set it to true the map is used only on the first import and you can't change anything afterwards. Use carefully!
The header is terminated by an empty line. The map starts under it. Each line in a map is a row of TMA core IDs, columns are separated by TAB character. If a line doesn't have the same number of columns as the longest row it will be padded by empty cores.
Here is an example of a simple map:
tmas: 1.svs
controls: ctrl
ignore: 0, empty
force: true
1 1 1 ctrl ctrl ctrl
2 2 2 3 3 3
0 0 0 4 4 4
5 5 5 empty empty empty
The imported map applies to 1.svs
and looks like this
You can also use the following API calls:
POST Api/CreateTMAMap
Required rights: Can modify
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
studyId | int | yes | Study to which the TMA map should be added |
tmaMapFileName | string | yes | path to the TMA map on the server |
Creates a TMA map from a specification file on the server
Returns
JSON object with attribute success
mapName
with the name of the map that can be used in SetSlideTMAMap or message
with eventual error message.
POST Api/SetSlideTMAMap
Required rights: Can modify
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
studyId | int | yes | Study where the slide should me modified |
imageId | int | yes | The slide that should be marked as TMA |
tmaMapFileName | string | yes | path to the TMA map on the server or null |
Marks/Unmarks slide as a TMA and adds the specified TMA map
Returns
JSON object with attribute success
and message
with eventual error message.
Study Settings
Study settings are configured in the study.<studyname>.config
file.
It contains properties of the study, in the format property name: value (or value1,value2)
Recognized properties:
allowchangingscores
allowresultscomparisonforeveryone
allowsharingslidesanonymously
artid
disallownavigation
disallowrewritingscores
disease
folder
friendlyname
hideslidenames
organ
scoretmacoresatonce
showduplicates
showlabels
showotherpeoplesscores
showslidenames
showthumbnails
showtmasampleids
stainings
Questions
The questions that form study's scoring sheet are listed in study.<studyname>.scores
. The format is a bit complicated, it's best to create the scoring sheet in the Question editor, click the Share button and copy the value of the f
URL parameter to the questions file. In principle it has one line per question - name of the question followed by a semicolon (;
), question type (FreeText
, DropDown
, Percentage
, Checkbox
, ...), followed by another semicolon and optionally other configuration for the question (options for a DropDown for example).
You can also use the following API calls:
POST Api/AddQuestion
Required rights: Can modify
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
studyId | int | yes | Study where the question should be added |
questionSpec | string | yes | Semicolon separated single question specification. For format see sharing and import/study specification |
Adds a question to a study. Question is appended to the end of the scoring sheet.
Returns
JSON object with attribute success
, id
with the ID of the new question or message
with eventual error message.
POST Api/UpdateQuestion
Required rights: Can modify
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
studyId | int | yes | Study where the question should be updated |
scoreId | int | yes | ID of the question that should be updated |
order | int | no | questions are sorted by order in the scoring sheet, high order will come later. Can be left null to keep current |
questionSpec | string | yes | Semicolon separated single question specification. For format see sharing and import/study specification |
Update a question in a study.
Returns
JSON object with attribute success
, id
with the ID of the question or message
with eventual error message.
POST Api/RemoveQuestion
Required rights: Can modify
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
studyId | int | yes | Study where the question should be removed |
scoreId | int | yes | ID of the question that should be removed |
Remove a question in a study.
Returns
JSON object with attribute success
and message
with eventual error message.
Importing
After uploading all important files call the POST Api/Reimport
method to create the study based on the config files and return a log of how did it go.
POST Api/Reimport
Required rights: Can reimport studies
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
studyName | string | yes | Name of the study to (re-)import |
ignoreImageErrors | true or false | no | If true the import process doesn't stop after encountering problems with a slide but try to import all slides |
Returns
String with log of the import process
If you need to change an existing study you can upload modified config files and run Reimport again.
Note that nothing gets removed, only added. Furthermore, if you've removed an image or users using the administration interface it will be added again if it is in the config files.
Note that you can't delete files on the server only overwrite them.
Synchronizing
All users with CanEdit
right can enter the administration interface and make changes to the study. Often it's needed to rotate some images, adjust a TMA map or reorder questions. However, when you call Reimport
next time these changes can be overwritten.
To prevent this from happening use GET Api/GetConfig
method with study ID as a parameter. It will return the complete configuration of a study as an object graph (for details see the API client).
Clone a study
You can easily clone a study as it is by requesting the configuration files of an existing study using Get Api/GetConfigFiles
method with study ID as a parameter. This will return JSON object with content of all the configuration files. Note that they are dynamically generated from the database - these are not necessarily the same files that were used to create the study.
Getting pixel data
Slide Score can act as a platform for storing the slides and serving them for other applications. The API has 3 methods how to request the tiles that make up pathology slides:
- Accessing the Deep Zoom tiles using GetImageMetadata, GetTileServer and requests to /i/ endpoint. This is the high-performance method. It serves square tiles (usually 256x256) in different levels, each level being twice as detailed as the previous one. It increases complexity of the client code as each slide can have different number of levels and tile size and they need to be stitched together to create the image. But unlike GetRawTile, at least the tiles will be square and each level will be twice as big as the previous one.
- GetScreenshot for low volume of requests, if you need the slide with scalebar and annotations. Can produce maximum 4000 x 4000 pixel image.
- GetRawTile tries to forward the request directly to one of the slide reading libraries. This requires reading the metadata to know what is the size of tiles and how many levels and how dense are they, so that you know what you can request. Usually, level 0 is the most detailed level (so the opposite of DeepZoom). Using the Python SDK:
client = APIClient(url, token) response = client.get_raw_tile(1, 111, 0, 0, 0, 512, 512, 90}) with open("pixels.jpg", 'wb') as f: for chunk in response.iter_content(chunk_size=8192): f.write(chunk) # or image = Image.open(BytesIO(response.content))
Deep Zoom tiles
Deep Zoom is a technology for displaying high resolution images in the browser. Slide Score uses it to display slides to the users. It is possible for your script to use the same interface. As it's highly optimised for speed, it should be the fastest method of accessing the slides remotely.
When using Deep Zoom a large image is requested in parts - tiles. These tiles need to be stitched together to create the whole image. To support zooming in and out of image Deep Zoom defines levels. The last level has all the detail that is actually in the image. The level above it is is twice smaller (its width and height are both half so you could say it's 4 times smaller). And so on and on until level 0 which is 1x1 pixel. So, if you have an image that's 4096x4096 pixels it would have 12 levels (as 2^12 is 4096), level 12 would be 4096x4096, level 11 would be 2048x2048 and so on. Level 0 is 1 pixel by 1 pixel, level 1 is 2x2 and so on, level 8 is useful to have the whole slide on a 256x256 image. Most slides have less than 20 levels.
Now back to the tiles. Remember that we can't request the whole level as it might be too large. The pixels are requested in tiles. For example the image from last paragraph might have tiles with size 256x256 pixels. In that case level 12 would have 4096/256=16 rows and columns of tiles. Level 11 would have 8 and so on.
When using this method you need to first request access to the /i/ endpoint by calling GetTileServer - this will return two tokens for authentication: one needs to be supplied in a cookie and another in the URL. This replaces the standard API authentication for the /i/ endpoint. You will also need to request image dimensions, tile size and levels by calling GetImageMetadata. Then you can start requesting the JPEG encoded tiles using the /i/ endpoint.
GET Api/GetImageMetadata
Required rights: Can get pixels
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
imageId | int | yes | ID of the image to access |
Returns
JSON object with success flag and SlideMetadata object:
long Level0TileWidth
long Level0TileHeight
int OSDTileSize
double MppX
double MppY
double ObjectivePower
string BackgroundColor
int LevelCount
long Level0Width
long Level0Height
double[] Downsamples
int BoundsX;
int BoundsY;
int BoundsWidth;
int BoundsHeight;
OSDTileSize holds the size of tiles (256px in the example above)
Level0Width and Level0Height is the width and height of the largest most detailed level (note that in Deep Zoom the most detailed level is the last one not level 0). You will need to calculate the number of levels from the larger of width and height.
BoundsX, -Y, -Width and -Height holds the coordinates of the rectangle where the scanner detected tissue - where high details is available. Some scanners call it the envelope or scene. For CZI and iSyntax images this is currently not supported as their scenes/envelopes are more complicated.
GET Api/GetTileServer
Required rights: Can get pixels
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
imageId | int | yes | ID of the image to access |
Returns
JSON object with cookiePart
, urlPart
(to be used in the calls to /i/ endpoint) and expiresOn
- a date by which this token needs to be renewed.
GET Api/GetTokenExpiry
Required rights: Can get pixels
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
cookiePart | string | yes | cookie part of the token |
urlPart | string | yes | URL part of the token |
Returns
JSON object with expiresOn
- a date by which this token needs to be renewed.
Calling the /i/ endpoint
You can request the JPEG encoded tiles at URL
/i/<imageID>/<urlPart>/i_files/<level>/<column>_<row>.jpeg
replace urlPart with the respective authentication token from GetTileServer, imageID with the ID of the requested image, level, column and row with the coordinates of the tile. You also need to include a cookie with name "t" and value of the cookiePart token from GetTileServer.
For example
/i/53926/318yu2xYJBUK6IKpsb/i_files/9/0_0.jpeg
To request the tile from upper left corner of image with ID 53926. It's from a level 9 which has size at most 512x512.
GetRawTile
GET Api/GetRawTile
Required rights: Can get pixels
Parameters:
Name | Type | Required | Explanation |
---|---|---|---|
studyId | int | yes | Study that includes image |
imageId | int | yes | Image |
x | int | yes | top-left corner coordinate in tiles in desired level |
y | int | yes | top-left corner coordinate in tiles in desired level |
width | int | yes | width in pixels, <2000 |
height | int | yes | height in pixels, <2000 |
level | int | yes | Slide level, level 0 is the most detailed |
jpegQuality | int | yes | level of jpeg compression. 80 - low quality, 90 - good quality (better color accuracy with 4:4:4 chroma), 95 - better still, image artifacts are difficult to find, must be between 1 and 100 |
Returns
JPEG file of the area.
Error codes: 401
for invalid token, token that doesn't have enough rights, 404
if image doesn't exist, 400
if parameters are outside bounds (e.g. negative)