{"action":"created","issue":{"url":"https://api.github.com/repos/pytraj/pytraj/issues/262","labels_url":"https://api.github.com/repos/pytraj/pytraj/issues/262/labels{/name}","comments_url":"https://api.github.com/repos/pytraj/pytraj/issues/262/comments","events_url":"https://api.github.com/repos/pytraj/pytraj/issues/262/events","html_url":"https://github.com/pytraj/pytraj/issues/262","id":73666883,"number":262,"title":"Why `FrameArray` and `TrajReadOnly`?","user":{"login":"swails","id":779022,"avatar_url":"https://avatars.githubusercontent.com/u/779022?v=3","gravatar_id":"","url":"https://api.github.com/users/swails","html_url":"https://github.com/swails","followers_url":"https://api.github.com/users/swails/followers","following_url":"https://api.github.com/users/swails/following{/other_user}","gists_url":"https://api.github.com/users/swails/gists{/gist_id}","starred_url":"https://api.github.com/users/swails/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/swails/subscriptions","organizations_url":"https://api.github.com/users/swails/orgs","repos_url":"https://api.github.com/users/swails/repos","events_url":"https://api.github.com/users/swails/events{/privacy}","received_events_url":"https://api.github.com/users/swails/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/pytraj/pytraj/labels/enhancement","name":"enhancement","color":"84b6eb"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":5,"created_at":"2015-05-06T16:13:58Z","updated_at":"2015-05-06T21:21:45Z","closed_at":null,"body":"I think this is somewhat related to one of your comments in #260, but I wonder what the rationale is to have `FrameArray` and `TrajReadOnly` as two separate objects storing the same information.\r\n\r\nThis adds complexity to the underlying API (that does not exist in `mdtraj`), and this complexity is not alleviated by having convenience methods to translate between them, IMO.  For a library application like this one (or `mdtraj`), I've found that those in which I can easily memorize the entire object model and data flow design are the easiest (and most enjoyable) to use.  This includes even very complex packages, like `pandas` and `matplotlib` (they try hard to keep their object models clean and simple).  I may have to look up what methods to use to do a certain task, but knowing the object model and data flow makes it easy to know where to look.\r\n\r\nUnless I'm missing something, there's nothing that `TrajReadOnly` can do (functionally) that `FrameArray` cannot, correct?  The only difference is that the former is immutable.  So what's the point of `TrajReadOnly`?  Why not *always* use `FrameArray` and just get rid of the other one?  It's easy to make `FrameArray` immutable... just don't change it.  I don't see why this has to be enforced by the library, and is rather against the design principles of Python itself (i.e., \"We're all consenting adults\")."},"comment":{"url":"https://api.github.com/repos/pytraj/pytraj/issues/comments/99613380","html_url":"https://github.com/pytraj/pytraj/issues/262#issuecomment-99613380","issue_url":"https://api.github.com/repos/pytraj/pytraj/issues/262","id":99613380,"user":{"login":"swails","id":779022,"avatar_url":"https://avatars.githubusercontent.com/u/779022?v=3","gravatar_id":"","url":"https://api.github.com/users/swails","html_url":"https://github.com/swails","followers_url":"https://api.github.com/users/swails/followers","following_url":"https://api.github.com/users/swails/following{/other_user}","gists_url":"https://api.github.com/users/swails/gists{/gist_id}","starred_url":"https://api.github.com/users/swails/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/swails/subscriptions","organizations_url":"https://api.github.com/users/swails/orgs","repos_url":"https://api.github.com/users/swails/repos","events_url":"https://api.github.com/users/swails/events{/privacy}","received_events_url":"https://api.github.com/users/swails/received_events","type":"User","site_admin":false},"created_at":"2015-05-06T21:21:45Z","updated_at":"2015-05-06T21:21:45Z","body":"OK, so correct me if I'm wrong, but it seems to me that the advantage of `TrajReadOnly` is in trajectory iteration.\r\n\r\n> Because I want to keep all methods and information for Frame object. cpptraj have Frame class and pytraj wrap it with the same name. Creating a vector of Frames (FrameArray) is easiest way to have all C++ Frames objects without copying data to external object and can keep all Frames' method too.\r\n\r\nDo you get a `numpy` array if you get, for instance, the `xyz` attribute of `FrameArray`?  If not, does it implement the `array` API?  (For example, `pandas.Series` is no longer a `numpy.ndarray` subclass, but still implements the `array` API so it can be used in place of `numpy` arrays in most cases by virtue of duck typing, as I understand it.)  Also, numpy is quite efficient with memory -- unlike standard Python containers, slicing a numpy array does *not* copy any data -- it simply exposes a view of the same data.  Which is why when you assign to a numpy slice, it changes the underlying object:\r\n\r\n```Python\r\n>>> import numpy as np\r\n>>> arr = np.arange(10)\r\n>>> arr\r\narray([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])\r\n>>> arr[2:8] = 0\r\n>>> arr\r\narray([0, 1, 0, 0, 0, 0, 0, 0, 8, 9])\r\n```\r\n\r\nSince `mdtraj` uses raw `numpy.ndarray` objects for its trajectories, all slices are views (as I hope they are on `FrameArray`)\r\n\r\nAnyway, I digress.  Let me suggest something for pytraj here:\r\n\r\n- `TrajReadOnly` becomes `TrajectoryIterator` or something (to let people know it's an optimized iterator)\r\n- `FrameArray` becomes `Trajectory` or something, which is the main \"object\" for storing trajectory data\r\n- `pytraj.load()` returns a `FrameArray` (or whatever you name it)\r\n- `pytraj.iterload()` returns a `TrajReadOnly` (or whatever you name it)\r\n\r\nThis is more consistent with Python's data model, IMO (an iterator -- like a generator -- cannot be assigned to because there's nothing to assign *to*, since it's not in memory).  Consider:\r\n\r\n```Python\r\n>>> iterable = [x for x in range(10)]\r\n>>> iterable[8] = 0\r\n>>> iterable\r\n[0, 1, 2, 3, 4, 5, 6, 7, 0, 9]\r\n>>> iterable = (x for x in range(10))\r\n>>> iterable[8] = 0\r\nTraceback (most recent call last):\r\n  File \"<stdin>\", line 1, in <module>\r\nTypeError: 'generator' object does not support item assignment\r\n```\r\n\r\nThe way you've described it to me, this is the difference between `FrameArray` (top) and `TrajReadOnly` (bottom) -- and Python supports both because there is a clear use case.\r\n\r\n> PS: matplotlib is not very easy to use in my opinion. I used to spend hours to just need to find out how to have 4 subplots in the same figures and have nice layout (the most trouble is find out how not to overlap x, y axis labels and make them look nice). It has too many options to choose (rather making default one robust). At that time, I just use my MS ppt slide to organize the figure layout :D.\r\n\r\nIt's easy to get started.  Publication-quality plots are more challenging, but you can uncover the layers of complexity in matplotlib as you need them, and through it all their object model is consistent (Artists, Patches, Line2Ds, Axes, etc.).  A `Line2D` object is used for the axis lines, the tick lines, the error-bar lines, the error bar *hats*, the plot lines, ... every line on the plot that you see is an instance of the same object, so when you know how to modify one, you can modify them all.  And so on.  The combination of flexibility and a complicated target application (general \"plotting\") means there's no way to avoid complexity in the API, but they mitigate that IMO with a minimal core object model.\r\n\r\nAs for the layout -- you are looking for the `tight_layout` method :). (http://matplotlib.org/users/tight_layout_guide.html)"}}