Skip to content

Commit

Permalink
Allow markers to have no diameters (#233)
Browse files Browse the repository at this point in the history
Markers may have only `(X Y Z)` specified instead of the more common `(X Y Z D)`. In this case, diameters are set to 0.

Also:
Strings in the middle of the list of points are now skipped.

ℹ️ The example file added in this commit is from C280999A-I4.asc

The following illustrates both use cases:

```lisp
( (Color Red)
  (   -0.97  -141.17    84.77)
  "<--4 boutons on a PC soma"
)  ;  End of text
```
  • Loading branch information
Benoit Coste authored Feb 11, 2021
1 parent 8fdd355 commit 9a85ef1
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 8 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,8 @@ The following s-expressions are parsed:
) ; End of markers
```

ℹ️ Markers can may have only `(X Y Z)` specified instead of the more common `(X Y Z D)`. In this case, diameters are set to 0.

##### Usage

```python
Expand Down
26 changes: 18 additions & 8 deletions src/readers/morphologyASC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,23 +76,30 @@ class NeurolucidaParser
}

private:
std::tuple<Point, floatType> parse_point(NeurolucidaLexer& lex) {
std::tuple<Point, floatType> parse_point(NeurolucidaLexer& lex, bool is_marker) {
lex.expect(Token::LPAREN, "Point should start in LPAREN");
std::array<morphio::floatType, 4> point{}; // X,Y,Z,R
for (auto& p : point) {
std::array<morphio::floatType, 4> point{}; // X,Y,Z,D
for (unsigned int i = 0; i < 4; i++) {
try {
#ifdef MORPHIO_USE_DOUBLE
p = std::stod(lex.consume()->str());
point[i] = std::stod(lex.consume()->str());
#else
p = std::stof(lex.consume()->str());
point[i] = std::stof(lex.consume()->str());
#endif
} catch (const std::invalid_argument&) {
throw RawDataError(err_.ERROR_PARSING_POINT(lex.line_num(), lex.current()->str()));
}

// Markers can have an s-exp (X Y Z) without diameter
if (is_marker && i == 2 && (lex_.peek()->str() == ")")) {
point[3] = 0;
break;
}
}

lex.consume();

// case where the s-exp is (X Y Z R WORD). For example: (1 1 0 1 S1)
if (lex.current()->id == +Token::WORD) {
lex.consume(Token::WORD);
}
Expand Down Expand Up @@ -231,13 +238,14 @@ class NeurolucidaParser
} else if (id == Token::RPAREN) {
return header;
} else if (id == Token::LPAREN) {
const auto next_token = static_cast<Token>(peek_id);
if (skip_sexp(peek_id)) {
// skip words/strings/markers
lex_.consume_until_balanced_paren();
if (peek_id == +Token::FONT)
lex_.consume_until_balanced_paren();
} else if (is_neurite_type(static_cast<Token>(peek_id))) {
header.token = static_cast<Token>(peek_id);
} else if (is_neurite_type(next_token)) {
header.token = next_token;
lex_.consume(); // Advance to NeuriteType
lex_.consume();
lex_.consume(Token::RPAREN, "New Neurite should end in RPAREN");
Expand Down Expand Up @@ -286,7 +294,7 @@ class NeurolucidaParser
} else if (peek_id == +Token::NUMBER) {
Point point;
floatType radius;
std::tie(point, radius) = parse_point(lex_);
std::tie(point, radius) = parse_point(lex_, (header.token == Token::STRING));
points.push_back(point);
diameters.push_back(radius);
} else if (peek_id == +Token::LPAREN) {
Expand All @@ -300,6 +308,8 @@ class NeurolucidaParser
throw RawDataError(
err_.ERROR_UNKNOWN_TOKEN(lex_.line_num(), lex_.peek()->str()));
}
} else if (id == Token::STRING) {
lex_.consume();
} else {
throw RawDataError(err_.ERROR_UNKNOWN_TOKEN(lex_.line_num(), lex_.peek()->str()));
}
Expand Down
12 changes: 12 additions & 0 deletions tests/data/marker-with-string.asc
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
; The following annotation has been found in C280999A-I4.asc
; It is a top-level annotation with a quote inside
( (Color Red)
( -0.97 -141.17 84.77)
"<--4 boutons on a PC soma"
) ; End of text

("CellBody"
(Color Red)
(CellBody)
(0 0 0 2)
)
5 changes: 5 additions & 0 deletions tests/test_2_neurolucida.py
Original file line number Diff line number Diff line change
Expand Up @@ -700,3 +700,8 @@ def test_skip_imagecoord():
def test_Sections_block():
assert_array_equal(Morphology(DATA_DIR / 'sections-block.asc').points,
Morphology(DATA_DIR / 'simple.asc').points)

def test_marker_with_string():
m = Morphology(DATA_DIR / 'marker-with-string.asc')
assert_array_equal(m.markers[0].points, np.array([[ -0.97 , -141.169998, 84.769997]],
dtype=np.float32))

0 comments on commit 9a85ef1

Please sign in to comment.