Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## a14

- Internal SVG drawing routines, removing drawSvg_svgy and lxml dependencies.
- Xgrow release dependency.

## a13

- Python 3.11 compatibility.
Expand All @@ -8,11 +13,15 @@

## Previous



- MultiFixedConcentration allows a `min_volume` setting, which will raise an error of the minimum
volume to be transferred for any component is too low.
- Volume and concentration settings can now be changed, not just initialized, as strings.
- Reference data for mixes is now its own class, `Reference`, and rounds to 1e-6 nM.
- Mixes now use Decimal instead of floats throughout for units, solving floating point errors.
- Formatting for mix table entries now takes place in `MixLine`.


# v1.1.0

Fixes broken workaround for ruamel.yaml bug now fixed upstream, adds double-tile sensitivity, includes
seed file to make xor example work.
50 changes: 24 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
# NOTE

**This is a development branch that breaks many features. To install the
the prerelease, use the [1.1 release](https://github.com/DNA-and-Natural-Algorithms-Group/alhambra/releases/tag/v1.1.0), or the [main branch](https://github.com/DNA-and-Natural-Algorithms-Group/alhambra/tree/main), or just use

```
pip install -U alhambra
```
**This is a development branch that breaks many features.** To install
the the previous release, use the [1.1 release], the [main branch], or
`pip install -U alhambra`.

# Introduction

Expand All @@ -20,40 +17,41 @@ peppercompiler with spuriousSSM to create core sequences. For SSTs, it
will use DSD. It uses an extensible system for tileset design, and can
flexibly take inputs of YAML or similar formats.


# Installation

Alhambra is designed to be installed as a Python package.

```
pip install -U 'alhambra @ git+https://github.com/DNA-and-Natural-Algorithms-Group/alhambra@v2'
```
To install the prerelease version, use

pip install -U --pre alhambra

To install the latest git version (which may be broken), use

pip install -U 'alhambra @ git+https://github.com/DNA-and-Natural-Algorithms-Group/alhambra@v2'

Alhambra 2 is designed to work with Python 3.9 or later.

To install development versions, you can check out this github repository, and
use `pip -e` or some other method for installing Python packages. Multiple
versions can be handled through `virtualenv`.
To install development versions, you can check out this github
repository, and use `pip -e` or some other method for installing Python
packages. Multiple versions can be handled through `virtualenv`.

All Alhambra requirements should be handled through setuptools dependencies, but
note that xgrow and peppercompiler both rely on C code being compiled, which may
fail.
All Alhambra requirements should be handled through setuptools
dependencies, but note that xgrow and peppercompiler both rely on C code
being compiled, which may fail.

# Usage

[Documentation is available online on readthedocs.io](https://alhambra.readthedocs.io/en/latest/). In particular, see
[the tutorial](https://alhambra.readthedocs.io/en/latest/tutorial.html). It is also available in the docs/ folder.
[Documentation is available online on readthedocs.io]. In particular,
see [the tutorial]. It is also available in the docs/ folder.

Most user-facing functions are on the TileSet class.

# Questions

Please send any questions to Constantine Evans, at cevans@evanslabs.org or cge@dna.caltech.edu.

# Versions

- v2.0.0.a1
Please send any questions to Constantine Evans, at cevans@evanslabs.org
or cge@dna.caltech.edu.

- v1.1.0: fixes broken workaround for ruamel.yaml bug now fixed
upstream, adds double-tile sensitivity, includes seed file to make
xor example work.
[1.1 release]: https://github.com/DNA-and-Natural-Algorithms-Group/alhambra/releases/tag/v1.1.0
[main branch]: https://github.com/DNA-and-Natural-Algorithms-Group/alhambra/tree/main
[Documentation is available online on readthedocs.io]: https://alhambra.readthedocs.io/en/latest/
[the tutorial]: https://alhambra.readthedocs.io/en/latest/tutorial.html
2 changes: 0 additions & 2 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ packages = find_namespace:
install_requires =
numpy
stickydesign >= 0.8.3
drawSvg_svgy @ git+https://github.com/cgevans/drawSvg_svgy@master
lxml
shutilwhich
peppercompiler >= 0.1.2
ruamel.yaml >= 0.15.100
Expand Down
164 changes: 164 additions & 0 deletions src/alhambra/drawing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
from __future__ import annotations
import base64
import re
from typing import Any, Optional, Union
from typing_extensions import TypeAlias
import xml.etree.ElementTree as ET
import attrs
from attrs import Factory
from abc import ABC, abstractmethod

Number: TypeAlias = Union[int, float]


class DrawingElement(ABC):
@abstractmethod
def to_xml(self) -> ET.Element:
...


class XMLElement(DrawingElement, ET.Element):
def to_xml(self) -> ET.Element:
return self


@attrs.define()
class Group(DrawingElement):
elements: list[DrawingElement] = Factory(list)
id: Optional[str] = None

def to_xml(self) -> ET.Element:
e = ET.Element("g")
if self.id is not None:
e.attrib["id"] = self.id
for elem in self.elements:
e.append(elem.to_xml())
return e

def append(self, v: DrawingElement) -> None:
self.elements.append(v)


class Rectangle(DrawingElement):
_el: ET.Element

def to_xml(self):
return self._el

def __init__(
self,
x: Number = 0,
y: Number = 0,
width: Number = 1,
height: Number = 1,
/,
**kwargs,
):
e = ET.Element("rect")
e.attrib["x"] = str(x)
e.attrib["y"] = str(y)
e.attrib["width"] = str(width)
e.attrib["height"] = str(height)
for k, v in kwargs.items():
e.attrib[k] = str(v)
self._el = e


class Text(DrawingElement):
_el: ET.Element

def to_xml(self):
return self._el

def __init__(
self, text: str, size: Number = 10, x: Number = 0, y: Number = 0, /, **kwargs
):
e = ET.Element("text")
e.attrib["x"] = str(x)
e.attrib["y"] = str(y)
e.attrib["font-size"] = str(size)
e.text = text
for k, v in kwargs.items():
e.attrib[k.replace("_", "-")] = str(v)
self._el = e


class Use(DrawingElement):
_el: ET.Element

def to_xml(self):
return self._el

def __init__(
self, id_or_link: str | Any, x: Number = 0, y: Number = 0, /, **kwargs
):
e = ET.Element("use")
e.attrib["x"] = str(x)
e.attrib["y"] = str(y)
if not isinstance(id_or_link, str):
assert hasattr(id_or_link, "id")
id = str(id_or_link.id)
else:
id = id_or_link
e.attrib["xlink:href"] = "#" + id
for k, v in kwargs.items():
e.attrib[k] = str(v)
self._el = e


@attrs.define()
class Drawing(DrawingElement):
width: int
height: int
defs: list[DrawingElement] = Factory(list)
elements: list[DrawingElement] = Factory(list)
viewBox: Optional[tuple[Number, Number, Number, Number]] = None

def to_xml(self) -> ET.Element:
e = ET.Element("svg")

e.attrib["xmlns"] = "http://www.w3.org/2000/svg"
e.attrib["xmlns:xlink"] = "http://www.w3.org/1999/xlink"
e.attrib["width"] = str(self.width)
e.attrib["height"] = str(self.height)

if self.viewBox is not None:
e.attrib["viewBox"] = " ".join(str(i) for i in self.viewBox)

if self.defs:
s = ET.SubElement(e, "defs")
for se in self.defs:
s.append(se.to_xml())
for se in self.elements:
e.append(se.to_xml())
return e

def save_svg(self, filename: str):
e = self.to_xml()

d = ET.ElementTree(e)

d.write(filename)

saveSvg = save_svg # for backwards compatibility

def to_et(self) -> ET.ElementTree:
return ET.ElementTree(self.to_xml())

def to_string(self) -> str:
e = self.to_xml()
return ET.tostring(e, encoding="unicode", xml_declaration=True)

def to_bytes(self) -> bytes:
e = self.to_xml()
return ET.tostring(e, encoding="utf-8", xml_declaration=True)

def _repr_svg_(self):
return self.to_string()

# From https://github.com/cduck/drawSvg
def _repr_html_(self):
prefix = b"data:image/svg+xml;base64,"
data = base64.b64encode(self.to_bytes())
src = (prefix + data).decode(encoding="ascii")
return '<img src="{}">'.format(src)
2 changes: 1 addition & 1 deletion src/alhambra/fastlatticedefect.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import numpy as np

from .sensitivitynew import _fakesingles
from .sensitivitynew import _fakesingles # type: ignore
from .tiles import TileList
from .util import GlueMergeSpec, comp

Expand Down
2 changes: 2 additions & 0 deletions src/alhambra/fastreduceD.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# type: ignore

from __future__ import annotations

from copy import copy
Expand Down
2 changes: 1 addition & 1 deletion src/alhambra/flatish.py
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ def __init__(
def to_dict(self, glues_as_refs: bool = False) -> dict:
d: dict[str, Any] = {}
d["adapter_tiles"] = [
[str(g), t.to_dict()] for g, t in self.adapter_tiles # FIXME
[str(g.name), t.to_dict()] for g, t in self.adapter_tiles # FIXME
]
d["type"] = self.__class__.__name__
return d
Expand Down
2 changes: 1 addition & 1 deletion src/alhambra/latticedefect.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import itertools
import re

from .sensitivitynew import _fakesingles
from .sensitivitynew import _fakesingles # type: ignore
from .tiles import TileList
from .util import GlueMergeSpec, comp

Expand Down
1 change: 1 addition & 0 deletions src/alhambra/sensitivitynew.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# type: ignore
# New sensitivity code.
# from .tilestructures import tile_daoe_single
from collections import Counter
Expand Down
Loading