summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgebele <gebele@in-silico.ch>2017-01-16 16:55:31 +0000
committergebele <gebele@in-silico.ch>2017-01-16 16:55:31 +0000
commit1106dbf48614d5329d601e12e53684ac6bd4188c (patch)
tree94dc3f6a2b6d7f634a24ce169b89b49bb85538bd
parent052e7689a6a79594ad89e6141190e0b40033fd9d (diff)
parente6b8488b757f1d6036fd74b75f44d8c75ed3779f (diff)
merged development1.1.1
-rw-r--r--.gitignore1
-rw-r--r--FAQ.md39
-rw-r--r--Gemfile4
-rw-r--r--LICENSE.md596
-rw-r--r--VERSION2
-rw-r--r--application.rb253
-rw-r--r--config.ru3
-rw-r--r--helper.rb215
-rw-r--r--lazar-gui.gemspec14
-rw-r--r--views/batch.haml106
-rw-r--r--views/details.haml8
-rw-r--r--views/faq_layout.haml67
-rw-r--r--views/layout.haml43
-rw-r--r--views/license.haml1
-rw-r--r--views/model_details.haml158
-rw-r--r--views/neighbors.haml24
-rw-r--r--views/predict.haml13
-rw-r--r--views/prediction.haml109
-rw-r--r--views/style.scss14
-rw-r--r--views/validation.haml16
20 files changed, 970 insertions, 716 deletions
diff --git a/.gitignore b/.gitignore
index a0459cb..49b161f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,2 @@
Gemfile.lock
.sass-cache/
-tmp/*
diff --git a/FAQ.md b/FAQ.md
index 73fec91..2530968 100644
--- a/FAQ.md
+++ b/FAQ.md
@@ -1,29 +1,18 @@
-Frequently Asked Questions
-==========================
-<br>
-####How does this prediction works?
->
+## lazar Frequently Asked Questions
-####You talk about significant fragments. Where can I find them?
-> We will show up those significant fragments in a further version.
+####The LAZAR program's interface has changed, and I am not sure how to use the information given with regard to its confidence. In the former version, I would consider a confidence value higher than 0.025 as reliable. But now, there is no such parameter in the prediction results. How can I consider a prediction as presenting high or low confidence?
-####What is endpoint details about?
-> You get the source from where we took compounds for the endpoint. The type and the number of compounds we used.
+In the past many users had problems to interpret the confidence level,
+for this reason we provide now the probabilities that the prediction
+belongs to one of the two classes. In contrast to the confidence level,
+these numbers can be interpreted as real probabilities ranging from 0 to
+1.
-####What is three times independent validation about?
->
+Reliable prediction have a high probability for the predicted class and
+a low probability for the other one. Unreliable predictions have similar
+values for both classes, and are caused by a lot of contradictory
+activities of similar compounds.
-####Do you consider providing plots for the validation results?
-> In a further version we will show up confidence and correlation plots.
-
-####What does 'Not enough similar compounds in training dataset' mean?
-> Lazar uses neighbors from the training dataset of the endpoint to predict your compound. If there are not enough neighbors for Lazar it is not possible to make a prediction.
-
-####Is there a minimum number of necessary neighbors to make a prediction?
->
-
-####How can I activate the 'batch prediction' option?
-> Please contact us directly via [mail](mailto:support@in-silico.ch).
-
-####Not the right answers for me. Is there a way to contact you or report problems.
-> You can always ask your questions via [mail](mailto:support@in-silico.ch). If you run into problems with the GUI please post your issue [here](https://github.com/opentox/lazar-gui/issues). If you would like to post any other issue e.g. about an expected prediction result please use this [form](https://github.com/opentox/lazar/issues).
+Probabilities are calculated from the activities and similarities of
+neighbors, please make sure to inspect the neighbors list for any
+inconsistencies that might affect the prediction.
diff --git a/Gemfile b/Gemfile
index 7bade23..c86c89a 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,7 +1,9 @@
source "https://rubygems.org"
gemspec
-gem "lazar"
+gem "lazar", :path => "../lazar"
gem "gem-path"
gem "sinatra"
+gem "sinatra-reloader"
gem "haml"
gem "sass"
+gem "rdiscount"
diff --git a/LICENSE.md b/LICENSE.md
new file mode 100644
index 0000000..16d89e0
--- /dev/null
+++ b/LICENSE.md
@@ -0,0 +1,596 @@
+GNU GENERAL PUBLIC LICENSE
+==========================
+
+Version 3, 29 June 2007
+
+Copyright &copy; 2007 Free Software Foundation, Inc. &lt;<http://fsf.org/>&gt;
+
+Everyone is permitted to copy and distribute verbatim copies of this license
+document, but changing it is not allowed.
+
+## Preamble
+
+The GNU General Public License is a free, copyleft license for software and other
+kinds of works.
+
+The licenses for most software and other practical works are designed to take away
+your freedom to share and change the works. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change all versions of a
+program--to make sure it remains free software for all its users. We, the Free
+Software Foundation, use the GNU General Public License for most of our software; it
+applies also to any other work released this way by its authors. You can apply it to
+your programs, too.
+
+When we speak of free software, we are referring to freedom, not price. Our General
+Public Licenses are designed to make sure that you have the freedom to distribute
+copies of free software (and charge for them if you wish), that you receive source
+code or can get it if you want it, that you can change the software or use pieces of
+it in new free programs, and that you know you can do these things.
+
+To protect your rights, we need to prevent others from denying you these rights or
+asking you to surrender the rights. Therefore, you have certain responsibilities if
+you distribute copies of the software, or if you modify it: responsibilities to
+respect the freedom of others.
+
+For example, if you distribute copies of such a program, whether gratis or for a fee,
+you must pass on to the recipients the same freedoms that you received. You must make
+sure that they, too, receive or can get the source code. And you must show them these
+terms so they know their rights.
+
+Developers that use the GNU GPL protect your rights with two steps: (1) assert
+copyright on the software, and (2) offer you this License giving you legal permission
+to copy, distribute and/or modify it.
+
+For the developers' and authors' protection, the GPL clearly explains that there is
+no warranty for this free software. For both users' and authors' sake, the GPL
+requires that modified versions be marked as changed, so that their problems will not
+be attributed erroneously to authors of previous versions.
+
+Some devices are designed to deny users access to install or run modified versions of
+the software inside them, although the manufacturer can do so. This is fundamentally
+incompatible with the aim of protecting users' freedom to change the software. The
+systematic pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we have designed
+this version of the GPL to prohibit the practice for those products. If such problems
+arise substantially in other domains, we stand ready to extend this provision to
+those domains in future versions of the GPL, as needed to protect the freedom of
+users.
+
+Finally, every program is threatened constantly by software patents. States should
+not allow patents to restrict development and use of software on general-purpose
+computers, but in those that do, we wish to avoid the special danger that patents
+applied to a free program could make it effectively proprietary. To prevent this, the
+GPL assures that patents cannot be used to render the program non-free.
+
+The precise terms and conditions for copying, distribution and modification follow.
+
+## TERMS AND CONDITIONS
+
+### 0. Definitions.
+
+&ldquo;This License&rdquo; refers to version 3 of the GNU General Public License.
+
+&ldquo;Copyright&rdquo; also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+&ldquo;The Program&rdquo; refers to any copyrightable work licensed under this
+License. Each licensee is addressed as &ldquo;you&rdquo;. &ldquo;Licensees&rdquo; and
+&ldquo;recipients&rdquo; may be individuals or organizations.
+
+To &ldquo;modify&rdquo; a work means to copy from or adapt all or part of the work in
+a fashion requiring copyright permission, other than the making of an exact copy. The
+resulting work is called a &ldquo;modified version&rdquo; of the earlier work or a
+work &ldquo;based on&rdquo; the earlier work.
+
+A &ldquo;covered work&rdquo; means either the unmodified Program or a work based on
+the Program.
+
+To &ldquo;propagate&rdquo; a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for infringement under
+applicable copyright law, except executing it on a computer or modifying a private
+copy. Propagation includes copying, distribution (with or without modification),
+making available to the public, and in some countries other activities as well.
+
+To &ldquo;convey&rdquo; a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through a computer
+network, with no transfer of a copy, is not conveying.
+
+An interactive user interface displays &ldquo;Appropriate Legal Notices&rdquo; to the
+extent that it includes a convenient and prominently visible feature that (1)
+displays an appropriate copyright notice, and (2) tells the user that there is no
+warranty for the work (except to the extent that warranties are provided), that
+licensees may convey the work under this License, and how to view a copy of this
+License. If the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+### 1. Source Code.
+
+The &ldquo;source code&rdquo; for a work means the preferred form of the work for
+making modifications to it. &ldquo;Object code&rdquo; means any non-source form of a
+work.
+
+A &ldquo;Standard Interface&rdquo; means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of interfaces
+specified for a particular programming language, one that is widely used among
+developers working in that language.
+
+The &ldquo;System Libraries&rdquo; of an executable work include anything, other than
+the work as a whole, that (a) is included in the normal form of packaging a Major
+Component, but which is not part of that Major Component, and (b) serves only to
+enable use of the work with that Major Component, or to implement a Standard
+Interface for which an implementation is available to the public in source code form.
+A &ldquo;Major Component&rdquo;, in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system (if any) on which
+the executable work runs, or a compiler used to produce the work, or an object code
+interpreter used to run it.
+
+The &ldquo;Corresponding Source&rdquo; for a work in object code form means all the
+source code needed to generate, install, and (for an executable work) run the object
+code and to modify the work, including scripts to control those activities. However,
+it does not include the work's System Libraries, or general-purpose tools or
+generally available free programs which are used unmodified in performing those
+activities but which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for the work, and
+the source code for shared libraries and dynamically linked subprograms that the work
+is specifically designed to require, such as by intimate data communication or
+control flow between those subprograms and other parts of the work.
+
+The Corresponding Source need not include anything that users can regenerate
+automatically from other parts of the Corresponding Source.
+
+The Corresponding Source for a work in source code form is that same work.
+
+### 2. Basic Permissions.
+
+All rights granted under this License are granted for the term of copyright on the
+Program, and are irrevocable provided the stated conditions are met. This License
+explicitly affirms your unlimited permission to run the unmodified Program. The
+output from running a covered work is covered by this License only if the output,
+given its content, constitutes a covered work. This License acknowledges your rights
+of fair use or other equivalent, as provided by copyright law.
+
+You may make, run and propagate covered works that you do not convey, without
+conditions so long as your license otherwise remains in force. You may convey covered
+works to others for the sole purpose of having them make modifications exclusively
+for you, or provide you with facilities for running those works, provided that you
+comply with the terms of this License in conveying all material for which you do not
+control copyright. Those thus making or running the covered works for you must do so
+exclusively on your behalf, under your direction and control, on terms that prohibit
+them from making any copies of your copyrighted material outside their relationship
+with you.
+
+Conveying under any other circumstances is permitted solely under the conditions
+stated below. Sublicensing is not allowed; section 10 makes it unnecessary.
+
+### 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+No covered work shall be deemed part of an effective technological measure under any
+applicable law fulfilling obligations under article 11 of the WIPO copyright treaty
+adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention
+of such measures.
+
+When you convey a covered work, you waive any legal power to forbid circumvention of
+technological measures to the extent such circumvention is effected by exercising
+rights under this License with respect to the covered work, and you disclaim any
+intention to limit operation or modification of the work as a means of enforcing,
+against the work's users, your or third parties' legal rights to forbid circumvention
+of technological measures.
+
+### 4. Conveying Verbatim Copies.
+
+You may convey verbatim copies of the Program's source code as you receive it, in any
+medium, provided that you conspicuously and appropriately publish on each copy an
+appropriate copyright notice; keep intact all notices stating that this License and
+any non-permissive terms added in accord with section 7 apply to the code; keep
+intact all notices of the absence of any warranty; and give all recipients a copy of
+this License along with the Program.
+
+You may charge any price or no price for each copy that you convey, and you may offer
+support or warranty protection for a fee.
+
+### 5. Conveying Modified Source Versions.
+
+You may convey a work based on the Program, or the modifications to produce it from
+the Program, in the form of source code under the terms of section 4, provided that
+you also meet all of these conditions:
+
+* **a)** The work must carry prominent notices stating that you modified it, and giving a
+relevant date.
+* **b)** The work must carry prominent notices stating that it is released under this
+License and any conditions added under section 7. This requirement modifies the
+requirement in section 4 to &ldquo;keep intact all notices&rdquo;.
+* **c)** You must license the entire work, as a whole, under this License to anyone who
+comes into possession of a copy. This License will therefore apply, along with any
+applicable section 7 additional terms, to the whole of the work, and all its parts,
+regardless of how they are packaged. This License gives no permission to license the
+work in any other way, but it does not invalidate such permission if you have
+separately received it.
+* **d)** If the work has interactive user interfaces, each must display Appropriate Legal
+Notices; however, if the Program has interactive interfaces that do not display
+Appropriate Legal Notices, your work need not make them do so.
+
+A compilation of a covered work with other separate and independent works, which are
+not by their nature extensions of the covered work, and which are not combined with
+it such as to form a larger program, in or on a volume of a storage or distribution
+medium, is called an &ldquo;aggregate&rdquo; if the compilation and its resulting
+copyright are not used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work in an aggregate
+does not cause this License to apply to the other parts of the aggregate.
+
+### 6. Conveying Non-Source Forms.
+
+You may convey a covered work in object code form under the terms of sections 4 and
+5, provided that you also convey the machine-readable Corresponding Source under the
+terms of this License, in one of these ways:
+
+* **a)** Convey the object code in, or embodied in, a physical product (including a
+physical distribution medium), accompanied by the Corresponding Source fixed on a
+durable physical medium customarily used for software interchange.
+* **b)** Convey the object code in, or embodied in, a physical product (including a
+physical distribution medium), accompanied by a written offer, valid for at least
+three years and valid for as long as you offer spare parts or customer support for
+that product model, to give anyone who possesses the object code either (1) a copy of
+the Corresponding Source for all the software in the product that is covered by this
+License, on a durable physical medium customarily used for software interchange, for
+a price no more than your reasonable cost of physically performing this conveying of
+source, or (2) access to copy the Corresponding Source from a network server at no
+charge.
+* **c)** Convey individual copies of the object code with a copy of the written offer to
+provide the Corresponding Source. This alternative is allowed only occasionally and
+noncommercially, and only if you received the object code with such an offer, in
+accord with subsection 6b.
+* **d)** Convey the object code by offering access from a designated place (gratis or for
+a charge), and offer equivalent access to the Corresponding Source in the same way
+through the same place at no further charge. You need not require recipients to copy
+the Corresponding Source along with the object code. If the place to copy the object
+code is a network server, the Corresponding Source may be on a different server
+(operated by you or a third party) that supports equivalent copying facilities,
+provided you maintain clear directions next to the object code saying where to find
+the Corresponding Source. Regardless of what server hosts the Corresponding Source,
+you remain obligated to ensure that it is available for as long as needed to satisfy
+these requirements.
+* **e)** Convey the object code using peer-to-peer transmission, provided you inform
+other peers where the object code and Corresponding Source of the work are being
+offered to the general public at no charge under subsection 6d.
+
+A separable portion of the object code, whose source code is excluded from the
+Corresponding Source as a System Library, need not be included in conveying the
+object code work.
+
+A &ldquo;User Product&rdquo; is either (1) a &ldquo;consumer product&rdquo;, which
+means any tangible personal property which is normally used for personal, family, or
+household purposes, or (2) anything designed or sold for incorporation into a
+dwelling. In determining whether a product is a consumer product, doubtful cases
+shall be resolved in favor of coverage. For a particular product received by a
+particular user, &ldquo;normally used&rdquo; refers to a typical or common use of
+that class of product, regardless of the status of the particular user or of the way
+in which the particular user actually uses, or expects or is expected to use, the
+product. A product is a consumer product regardless of whether the product has
+substantial commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+&ldquo;Installation Information&rdquo; for a User Product means any methods,
+procedures, authorization keys, or other information required to install and execute
+modified versions of a covered work in that User Product from a modified version of
+its Corresponding Source. The information must suffice to ensure that the continued
+functioning of the modified object code is in no case prevented or interfered with
+solely because modification has been made.
+
+If you convey an object code work under this section in, or with, or specifically for
+use in, a User Product, and the conveying occurs as part of a transaction in which
+the right of possession and use of the User Product is transferred to the recipient
+in perpetuity or for a fixed term (regardless of how the transaction is
+characterized), the Corresponding Source conveyed under this section must be
+accompanied by the Installation Information. But this requirement does not apply if
+neither you nor any third party retains the ability to install modified object code
+on the User Product (for example, the work has been installed in ROM).
+
+The requirement to provide Installation Information does not include a requirement to
+continue to provide support service, warranty, or updates for a work that has been
+modified or installed by the recipient, or for the User Product in which it has been
+modified or installed. Access to a network may be denied when the modification itself
+materially and adversely affects the operation of the network or violates the rules
+and protocols for communication across the network.
+
+Corresponding Source conveyed, and Installation Information provided, in accord with
+this section must be in a format that is publicly documented (and with an
+implementation available to the public in source code form), and must require no
+special password or key for unpacking, reading or copying.
+
+### 7. Additional Terms.
+
+&ldquo;Additional permissions&rdquo; are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions. Additional
+permissions that are applicable to the entire Program shall be treated as though they
+were included in this License, to the extent that they are valid under applicable
+law. If additional permissions apply only to part of the Program, that part may be
+used separately under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+When you convey a copy of a covered work, you may at your option remove any
+additional permissions from that copy, or from any part of it. (Additional
+permissions may be written to require their own removal in certain cases when you
+modify the work.) You may place additional permissions on material, added by you to a
+covered work, for which you have or can give appropriate copyright permission.
+
+Notwithstanding any other provision of this License, for material you add to a
+covered work, you may (if authorized by the copyright holders of that material)
+supplement the terms of this License with terms:
+
+* **a)** Disclaiming warranty or limiting liability differently from the terms of
+sections 15 and 16 of this License; or
+* **b)** Requiring preservation of specified reasonable legal notices or author
+attributions in that material or in the Appropriate Legal Notices displayed by works
+containing it; or
+* **c)** Prohibiting misrepresentation of the origin of that material, or requiring that
+modified versions of such material be marked in reasonable ways as different from the
+original version; or
+* **d)** Limiting the use for publicity purposes of names of licensors or authors of the
+material; or
+* **e)** Declining to grant rights under trademark law for use of some trade names,
+trademarks, or service marks; or
+* **f)** Requiring indemnification of licensors and authors of that material by anyone
+who conveys the material (or modified versions of it) with contractual assumptions of
+liability to the recipient, for any liability that these contractual assumptions
+directly impose on those licensors and authors.
+
+All other non-permissive additional terms are considered &ldquo;further
+restrictions&rdquo; within the meaning of section 10. If the Program as you received
+it, or any part of it, contains a notice stating that it is governed by this License
+along with a term that is a further restriction, you may remove that term. If a
+license document contains a further restriction but permits relicensing or conveying
+under this License, you may add to a covered work material governed by the terms of
+that license document, provided that the further restriction does not survive such
+relicensing or conveying.
+
+If you add terms to a covered work in accord with this section, you must place, in
+the relevant source files, a statement of the additional terms that apply to those
+files, or a notice indicating where to find the applicable terms.
+
+Additional terms, permissive or non-permissive, may be stated in the form of a
+separately written license, or stated as exceptions; the above requirements apply
+either way.
+
+### 8. Termination.
+
+You may not propagate or modify a covered work except as expressly provided under
+this License. Any attempt otherwise to propagate or modify it is void, and will
+automatically terminate your rights under this License (including any patent licenses
+granted under the third paragraph of section 11).
+
+However, if you cease all violation of this License, then your license from a
+particular copyright holder is reinstated (a) provisionally, unless and until the
+copyright holder explicitly and finally terminates your license, and (b) permanently,
+if the copyright holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+Moreover, your license from a particular copyright holder is reinstated permanently
+if the copyright holder notifies you of the violation by some reasonable means, this
+is the first time you have received notice of violation of this License (for any
+work) from that copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+Termination of your rights under this section does not terminate the licenses of
+parties who have received copies or rights from you under this License. If your
+rights have been terminated and not permanently reinstated, you do not qualify to
+receive new licenses for the same material under section 10.
+
+### 9. Acceptance Not Required for Having Copies.
+
+You are not required to accept this License in order to receive or run a copy of the
+Program. Ancillary propagation of a covered work occurring solely as a consequence of
+using peer-to-peer transmission to receive a copy likewise does not require
+acceptance. However, nothing other than this License grants you permission to
+propagate or modify any covered work. These actions infringe copyright if you do not
+accept this License. Therefore, by modifying or propagating a covered work, you
+indicate your acceptance of this License to do so.
+
+### 10. Automatic Licensing of Downstream Recipients.
+
+Each time you convey a covered work, the recipient automatically receives a license
+from the original licensors, to run, modify and propagate that work, subject to this
+License. You are not responsible for enforcing compliance by third parties with this
+License.
+
+An &ldquo;entity transaction&rdquo; is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an organization, or
+merging organizations. If propagation of a covered work results from an entity
+transaction, each party to that transaction who receives a copy of the work also
+receives whatever licenses to the work the party's predecessor in interest had or
+could give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if the predecessor
+has it or can get it with reasonable efforts.
+
+You may not impose any further restrictions on the exercise of the rights granted or
+affirmed under this License. For example, you may not impose a license fee, royalty,
+or other charge for exercise of rights granted under this License, and you may not
+initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging
+that any patent claim is infringed by making, using, selling, offering for sale, or
+importing the Program or any portion of it.
+
+### 11. Patents.
+
+A &ldquo;contributor&rdquo; is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The work thus
+licensed is called the contributor's &ldquo;contributor version&rdquo;.
+
+A contributor's &ldquo;essential patent claims&rdquo; are all patent claims owned or
+controlled by the contributor, whether already acquired or hereafter acquired, that
+would be infringed by some manner, permitted by this License, of making, using, or
+selling its contributor version, but do not include claims that would be infringed
+only as a consequence of further modification of the contributor version. For
+purposes of this definition, &ldquo;control&rdquo; includes the right to grant patent
+sublicenses in a manner consistent with the requirements of this License.
+
+Each contributor grants you a non-exclusive, worldwide, royalty-free patent license
+under the contributor's essential patent claims, to make, use, sell, offer for sale,
+import and otherwise run, modify and propagate the contents of its contributor
+version.
+
+In the following three paragraphs, a &ldquo;patent license&rdquo; is any express
+agreement or commitment, however denominated, not to enforce a patent (such as an
+express permission to practice a patent or covenant not to sue for patent
+infringement). To &ldquo;grant&rdquo; such a patent license to a party means to make
+such an agreement or commitment not to enforce a patent against the party.
+
+If you convey a covered work, knowingly relying on a patent license, and the
+Corresponding Source of the work is not available for anyone to copy, free of charge
+and under the terms of this License, through a publicly available network server or
+other readily accessible means, then you must either (1) cause the Corresponding
+Source to be so available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner consistent with
+the requirements of this License, to extend the patent license to downstream
+recipients. &ldquo;Knowingly relying&rdquo; means you have actual knowledge that, but
+for the patent license, your conveying the covered work in a country, or your
+recipient's use of the covered work in a country, would infringe one or more
+identifiable patents in that country that you have reason to believe are valid.
+
+If, pursuant to or in connection with a single transaction or arrangement, you
+convey, or propagate by procuring conveyance of, a covered work, and grant a patent
+license to some of the parties receiving the covered work authorizing them to use,
+propagate, modify or convey a specific copy of the covered work, then the patent
+license you grant is automatically extended to all recipients of the covered work and
+works based on it.
+
+A patent license is &ldquo;discriminatory&rdquo; if it does not include within the
+scope of its coverage, prohibits the exercise of, or is conditioned on the
+non-exercise of one or more of the rights that are specifically granted under this
+License. You may not convey a covered work if you are a party to an arrangement with
+a third party that is in the business of distributing software, under which you make
+payment to the third party based on the extent of your activity of conveying the
+work, and under which the third party grants, to any of the parties who would receive
+the covered work from you, a discriminatory patent license (a) in connection with
+copies of the covered work conveyed by you (or copies made from those copies), or (b)
+primarily for and in connection with specific products or compilations that contain
+the covered work, unless you entered into that arrangement, or that patent license
+was granted, prior to 28 March 2007.
+
+Nothing in this License shall be construed as excluding or limiting any implied
+license or other defenses to infringement that may otherwise be available to you
+under applicable patent law.
+
+### 12. No Surrender of Others' Freedom.
+
+If conditions are imposed on you (whether by court order, agreement or otherwise)
+that contradict the conditions of this License, they do not excuse you from the
+conditions of this License. If you cannot convey a covered work so as to satisfy
+simultaneously your obligations under this License and any other pertinent
+obligations, then as a consequence you may not convey it at all. For example, if you
+agree to terms that obligate you to collect a royalty for further conveying from
+those to whom you convey the Program, the only way you could satisfy both those terms
+and this License would be to refrain entirely from conveying the Program.
+
+### 13. Use with the GNU Affero General Public License.
+
+Notwithstanding any other provision of this License, you have permission to link or
+combine any covered work with a work licensed under version 3 of the GNU Affero
+General Public License into a single combined work, and to convey the resulting work.
+The terms of this License will continue to apply to the part which is the covered
+work, but the special requirements of the GNU Affero General Public License, section
+13, concerning interaction through a network will apply to the combination as such.
+
+### 14. Revised Versions of this License.
+
+The Free Software Foundation may publish revised and/or new versions of the GNU
+General Public License from time to time. Such new versions will be similar in spirit
+to the present version, but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program specifies that
+a certain numbered version of the GNU General Public License &ldquo;or any later
+version&rdquo; applies to it, you have the option of following the terms and
+conditions either of that numbered version or of any later version published by the
+Free Software Foundation. If the Program does not specify a version number of the GNU
+General Public License, you may choose any version ever published by the Free
+Software Foundation.
+
+If the Program specifies that a proxy can decide which future versions of the GNU
+General Public License can be used, that proxy's public statement of acceptance of a
+version permanently authorizes you to choose that version for the Program.
+
+Later license versions may give you additional or different permissions. However, no
+additional obligations are imposed on any author or copyright holder as a result of
+your choosing to follow a later version.
+
+### 15. Disclaimer of Warranty.
+
+THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM &ldquo;AS IS&rdquo; WITHOUT WARRANTY OF ANY KIND, EITHER
+EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE
+QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE
+DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+### 16. Limitation of Liability.
+
+IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY
+COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS
+PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL,
+INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE
+OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE
+WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+### 17. Interpretation of Sections 15 and 16.
+
+If the disclaimer of warranty and limitation of liability provided above cannot be
+given local legal effect according to their terms, reviewing courts shall apply local
+law that most closely approximates an absolute waiver of all civil liability in
+connection with the Program, unless a warranty or assumption of liability accompanies
+a copy of the Program in return for a fee.
+
+END OF TERMS AND CONDITIONS
+
+## How to Apply These Terms to Your New Programs
+
+If you develop a new program, and you want it to be of the greatest possible use to
+the public, the best way to achieve this is to make it free software which everyone
+can redistribute and change under these terms.
+
+To do so, attach the following notices to the program. It is safest to attach them
+to the start of each source file to most effectively state the exclusion of warranty;
+and each file should have at least the &ldquo;copyright&rdquo; line and a pointer to
+where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program does terminal interaction, make it output a short notice like this
+when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type 'show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type 'show c' for details.
+
+The hypothetical commands 'show w' and 'show c' should show the appropriate parts of
+the General Public License. Of course, your program's commands might be different;
+for a GUI interface, you would use an &ldquo;about box&rdquo;.
+
+You should also get your employer (if you work as a programmer) or school, if any, to
+sign a &ldquo;copyright disclaimer&rdquo; for the program, if necessary. For more
+information on this, and how to apply and follow the GNU GPL, see
+&lt;<http://www.gnu.org/licenses/>&gt;.
+
+The GNU General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may consider it
+more useful to permit linking proprietary applications with the library. If this is
+what you want to do, use the GNU Lesser General Public License instead of this
+License. But first, please read
+&lt;<http://www.gnu.org/philosophy/why-not-lgpl.html>&gt;. \ No newline at end of file
diff --git a/VERSION b/VERSION
index 6d7de6e..524cb55 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.0.2
+1.1.1
diff --git a/application.rb b/application.rb
index b9c267c..fa5df0a 100644
--- a/application.rb
+++ b/application.rb
@@ -1,11 +1,6 @@
#require_relative 'helper.rb'
-#require 'rdiscount'
+require 'rdiscount'
include OpenTox
-#require File.join(ENV["HOME"],".opentox","config","lazar-gui.rb") # until added to ot-tools
-
-# DG: workaround for https://github.com/sinatra/sinatra/issues/808
-# Date: 18/11/2013
-#set :protection, :except => :path_traversal
configure :development do
$logger = Logger.new(STDOUT)
@@ -20,230 +15,87 @@ helpers do
end
+before do
+ @version = File.read("VERSION").chomp
+end
+
get '/?' do
redirect to('/predict')
end
get '/predict/?' do
- @version = File.read("VERSION").chomp
- @models = OpenTox::Model::Prediction.all
+ @models = OpenTox::Model::Validation.all
+ @models = @models.delete_if{|m| m.model.name =~ /\b(Net cell association)\b/}
@endpoints = @models.collect{|m| m.endpoint}.sort.uniq
@models.count <= 0 ? (haml :info) : (haml :predict)
end
get '/predict/modeldetails/:model' do
- model = OpenTox::Model::Prediction.find params[:model]
- crossvalidations = model.crossvalidations
- #confidence_plots = crossvalidations.collect{|cv| [cv.id, cv.confidence_plot]}
- #confidence_plots.each do |confp|
- # File.open(File.join('public', "confp#{confp[0]}.svg"), 'w'){|file| file.write(confp[1])} unless File.exists? File.join('public', "confp#{confp[0]}.svg")
- #end
- #if model.regression?
- # correlation_plots = crossvalidations.collect{|cv| [cv.id, cv.correlation_plot]}
- # correlation_plots.each do |corrp|
- # File.open(File.join('public', "corrp#{corrp[0]}.svg"), 'w'){|file| file.write(corrp[1])} unless File.exists? File.join('public', "corrp#{corrp[0]}.svg")
- # end
- #end
+ model = OpenTox::Model::Validation.find params[:model]
+ crossvalidations = OpenTox::Validation::RepeatedCrossValidation.find(model.repeated_crossvalidation_id).crossvalidations
- return haml :model_details, :layout=> false, :locals => {:model => model}
-end
-
-get '/jme_help/?' do
- File.read(File.join('views','jme_help.html'))
+ return haml :model_details, :layout=> false, :locals => {:model => model, :crossvalidations => crossvalidations}
end
# get individual compound details
get '/prediction/:neighbor/details/?' do
- @compound = OpenTox::Compound.new params[:neighbor]
+ @compound = OpenTox::Compound.find params[:neighbor]
@smiles = @compound.smiles
- task = OpenTox::Task.run("Get names for '#{@smiles}'.") do
- names = @compound.names
- end
- task.wait
-
- case task[RDF::OT.hasStatus]
- when "Error"
- @names = "No names for this compound available."
- when "Completed"
- @names = @compound.names
- else
+ begin
+ @names = @compound.names.nil? ? "No names for this compound available." : @compound.names
+ rescue
@names = "No names for this compound available."
end
@inchi = @compound.inchi.gsub("InChI=", "")
haml :details, :layout => false
end
-=begin
-# sdf representation for datasets
-#TODO fix 502 errors from compound service
-get '/predict/:dataset_uri/sdf/?' do
- uri = CGI.unescape(params[:dataset_uri])
- $logger.debug uri
- bad_request_error "Not a dataset uri." unless URI.dataset? uri
- dataset = OpenTox::Dataset.find uri
- @compounds = dataset.compounds
- @data_entries = dataset.data_entries
- sum=""
- @compounds.each_with_index{ |c, idx|
- sum << c.inchi
- sum << c.sdf.sub(/\n\$\$\$\$/,'')
- @data_entries[idx].each{ |f,v|
- sum << "> <\"#{f}\">\n"
- sum << v.join(", ")
- sum << "\n\n"
- }
- sum << "$$$$\n"
- }
- send_file sum, :filename => "#{dataset.title}.sdf"
-end
-=end
-# fingerprints for compound in predictions
-get '/prediction/:model_uri/:type/:compound_uri/fingerprints/?' do
- @type = params[:type]
- model = OpenTox::Model::Lazar.find params[:model_uri]
- feature_dataset = OpenTox::Dataset.find model[RDF::OT.featureDataset]
- @compound = OpenTox::Compound.new params[:compound_uri]
- @significant_fragments = []
- if @type =~ /classification/i
- # collect all feature values with fingerprint
- fingerprints = OpenTox::Algorithm::Descriptor.send("smarts_match", [@compound], feature_dataset.features.collect{ |f| f[RDF::DC.title]})[@compound.uri]
- #$logger.debug "fingerprints:\t#{fingerprints}\n"
-
- # collect fingerprints with value 1
- @fingerprint_values = fingerprints.collect{|smarts, value| [smarts, value] if value > 0}
-
- # collect all features from feature_dataset
- @features = feature_dataset.features.collect{|f| f }
-
- # search for each fingerprint in all features and collect feature values( effect, smarts, pValue )
- @fingerprint_values.each{ |fi, v| @features.each{ |f| @significant_fragments << [f[RDF::OT.effect].to_i, f[RDF::OT.smarts], f[RDF::OT.pValue]] if fi == f[RDF::OT.smarts] } }
-
- # pass value_map, important to interprete effect value
- prediction_feature_uri = ""
- model.parameters.each {|p|
- if p[RDF::DC.title].to_s == "prediction_feature_uri"
- prediction_feature_uri = p[RDF::OT.paramValue].object
- end
- }
- prediction_feature = OpenTox::Feature.find prediction_feature_uri
- @value_map = prediction_feature.value_map
-
- else #regression
- feature_calc_algo = ""
- model.parameters.each {|p|
- if p[RDF::DC.title].to_s == "feature_calculation_algorithm"
- feature_calc_algo = p[RDF::OT.paramValue].object
- end
- }
-
- @desc = []
- fingerprints = OpenTox::Algorithm::Descriptor.send( feature_calc_algo, [ @compound ], feature_dataset.features.collect{ |f| f[RDF::DC.title] } )
- fingerprints.each{|x, h| h.each{|descriptor, value| @desc << [descriptor, [value]]}}
-
- pc_descriptor_titles_descriptions = {}
- feature_dataset.features.collect{ |f|
- pc_descriptor_titles_descriptions[f[RDF::DC.title]]= f[RDF::DC.description]
- }
-
- @desc.each{|d, v| @significant_fragments << [pc_descriptor_titles_descriptions[d], v] }
- end
- haml :significant_fragments, :layout => false
+get '/jme_help/?' do
+ File.read(File.join('views','jme_help.html'))
end
-get '/prediction/:model_uri/:type/:neighbor/significant_fragments/?' do
- @type = params[:type]
- @compound = OpenTox::Compound.new params[:neighbor]
- model = OpenTox::Model::Lazar.find params[:model_uri]
- #$logger.debug "model for significant fragments:\t#{model.uri}"
-
- feature_dataset = OpenTox::Dataset.find model[RDF::OT.featureDataset]
- $logger.debug "feature_dataset_uri:\t#{feature_dataset.uri}\n"
-
- # load all compounds
- feature_dataset.compounds
-
- # load all features
- @features = feature_dataset.features.collect{|f| f}
-
- # find all features and values for a neighbor compound
- @significant_fragments = []
- # check type first
- if @type =~ /classification/i
- # get compound index in feature dataset
- c_idx = feature_dataset.compound_indices @compound.uri
-
- # collect feature uris with value
- @feat = @features.collect{|f| [feature_dataset.data_entry_value(c_idx[0], f.uri), f.uri]}
- #$logger.debug "@feat:\t#{@feat}\n"
-
- # pass feature uris if value > 0
- @feat.each do |f|
- # search relevant features
- if f[0] > 0
- f = OpenTox::Feature.find f[1]
- # pass relevant features with [ effect, smarts, pValue ]
- @significant_fragments << [f[RDF::OT.effect].to_i, f[RDF::OT.smarts], f[RDF::OT.pValue].to_f.round(3)]
- end
- end
- # pass value_map, important to interprete effect value
- prediction_feature_uri = ""
- model.parameters.each {|p|
- if p[RDF::DC.title].to_s == "prediction_feature_uri"
- prediction_feature_uri = p[RDF::OT.paramValue].object
- end
- }
- prediction_feature = OpenTox::Feature.find prediction_feature_uri
- @value_map = prediction_feature.value_map
-
- else # regression
- # find a value in feature dataset by compound and feature
- @values = @features.collect{|f| feature_dataset.values(@compound, f)}
- #$logger.debug "values in fd:\t#{@values}"
-
- @features.each_with_index{|f, i| @significant_fragments << [f.description, @values[i]]}
- end
- #$logger.debug "significant fragments:\t#{@significant_fragments}\n"
-
- haml :significant_fragments, :layout => false
+get '/predict/dataset/:name' do
+ response['Content-Type'] = "text/csv"
+ dataset = Dataset.find_by(:name=>params[:name])
+ csv = dataset.to_csv
+ csv
end
get '/predict/?:csv?' do
response['Content-Type'] = "text/csv"
- @csv = "\"Compound\",\"Endpoint\",\"Type\",\"Prediction\",\"Confidence\"\n"
+ @csv = "\"Compound\",\"Endpoint\",\"Type\",\"Prediction\",\"95% Prediction interval\"\n"
@@batch.each do |key, values|
+ compound = key
+ smiles = compound.smiles
values.each do |array|
model = array[0]
+ type = model.model.class.to_s.match("Classification") ? "Classification" : "Regression"
prediction = array[1]
- compound = key.smiles
- mw = key.molecular_weight
endpoint = "#{model.endpoint.gsub('_', ' ')} (#{model.species})"
if prediction[:confidence] == "measured"
if prediction[:value].is_a?(Array)
prediction[:value].each do |value|
- type = ""
- weight = Compound.from_smiles(compound).mmol_to_mg(value, mw)
- pred = value.numeric? ? "#{'%.2e' % value} (#{model.unit}) | #{'%.2e' % weight} (mg/kg_bw/day)" : value
- confidence = "measured activity"
- @csv += "\"#{compound}\",\"#{endpoint}\",\"#{type}\",\"#{pred}\",\"#{confidence}\"\n"
+ pred = value.numeric? ? "#{value} (#{model.unit}), #{compound.mmol_to_mg(value.delog10)} #{(model.unit =~ /\b(mol\/L)\b/) ? "(mg/L)" : "(mg/kg_bw/day)"}" : value
+ int = (prediction[:prediction_interval].nil? ? nil : prediction[:prediction_interval])
+ interval = (int.nil? ? "--" : "#{int[1].delog10} - #{int[0].delog10} (#{model.unit})")
+ @csv += "\"#{smiles}\",\"#{endpoint}\",\"#{type}\",\"#{pred}\",\"#{interval}\"\n"
end
else
- type = ""
- weight = Compound.from_smiles(compound).mmol_to_mg(prediction[:value], mw)
- pred = prediction[:value].numeric? ? "#{'%.2e' % prediction[:value]} (#{model.unit}) | #{'%.2e' % weight} (mg/kg_bw/day)" : prediction[:value]
+ pred = prediction[:value].numeric? ? "#{prediction[:value]} (#{model.unit}), #{compound.mmol_to_mg(prediction[:value].delog10)} #{(model.unit =~ /\b(mol\/L)\b/) ? "(mg/L)" : "(mg/kg_bw/day)"}" : prediction[:value]
confidence = "measured activity"
end
elsif prediction[:neighbors].size > 0
- weight = Compound.from_smiles(compound).mmol_to_mg(prediction[:value], mw)
type = model.model.class.to_s.match("Classification") ? "Classification" : "Regression"
- pred = prediction[:value].numeric? ? "#{'%.2e' % prediction[:value]} (#{model.unit}) | #{'%.2e' % weight} (mg/kg_bw/day)" : prediction[:value]
- confidence = prediction[:confidence]
+ pred = prediction[:value].numeric? ? "#{prediction[:value].delog10} (#{model.unit}), #{compound.mmol_to_mg(prediction[:value].delog10)} #{(model.unit =~ /\b(mol\/L)\b/) ? "(mg/L)" : "(mg/kg_bw/day)"}" : prediction[:value]
+ int = (prediction[:prediction_interval].nil? ? nil : prediction[:prediction_interval])
+ interval = (int.nil? ? "--" : "#{int[1].delog10} - #{int[0].delog10} (#{model.unit})")
else
type = ""
pred = "Not enough similar compounds in training dataset."
- confidence = ""
+ interval = ""
end
- @csv += "\"#{compound}\",\"#{endpoint}\",\"#{type}\",\"#{pred}\",\"#{confidence}\"\n" unless prediction[:value].is_a?(Array)
+ @csv += "\"#{smiles}\",\"#{endpoint}\",\"#{type}\",\"#{pred}\",\"#{interval}\"\n" unless prediction[:value].is_a?(Array)
end
end
@csv
@@ -261,11 +113,21 @@ post '/predict/?' do
f.write(params[:fileselect][:tempfile].read)
end
@filename = params[:fileselect][:filename]
- input = OpenTox::Dataset.from_csv_file File.join "tmp", params[:fileselect][:filename]
- dataset = OpenTox::Dataset.find input.id
+ begin
+ input = OpenTox::Dataset.from_csv_file File.join("tmp", params[:fileselect][:filename]), true
+ if input.class == OpenTox::Dataset
+ dataset = OpenTox::Dataset.find input
+ else
+ @error_report = "Could not serialize file '#{@filename}' ."
+ return haml :error
+ end
+ rescue
+ @error_report = "Could not serialize file '#{@filename}' ."
+ return haml :error
+ end
@compounds = dataset.compounds
if @compounds.size == 0
- @error_report = "No valid SMILES submitted."
+ @error_report = dataset[:warnings]
dataset.delete
return haml :error
end
@@ -273,13 +135,15 @@ post '/predict/?' do
@compounds.each do |compound|
@batch[compound] = []
params[:selection].keys.each do |model_id|
- model = Model::Prediction.find model_id
+ model = OpenTox::Model::Validation.find model_id
prediction = model.predict(compound)
@batch[compound] << [model, prediction]
end
end
@@batch = @batch
+ @warnings = dataset[:warnings]
dataset.delete
+ File.delete File.join("tmp", params[:fileselect][:filename])
return haml :batch
end
@@ -291,26 +155,31 @@ post '/predict/?' do
# get compound from SMILES
@compound = Compound.from_smiles @identifier
if @compound.blank?
- @error_report = "Attention, '#{@identifier}' is not a valid SMILES string."
+ @error_report = "'#{@identifier}' is not a valid SMILES string."
return haml :error
end
@models = []
@predictions = []
params[:selection].keys.each do |model_id|
- model = Model::Prediction.find model_id
+ model = OpenTox::Model::Validation.find model_id
@models << model
@predictions << model.predict(@compound)
end
haml :prediction
end
end
-=begin
+
+get '/license' do
+ @license = RDiscount.new(File.read("LICENSE.md")).to_html
+ haml :license, :layout => false
+end
+
get '/faq' do
@faq = RDiscount.new(File.read("FAQ.md")).to_html
- haml :faq, :layout => :faq_layout
+ haml :faq, :layout => false
end
-=end
+
get '/style.css' do
headers 'Content-Type' => 'text/css; charset=utf-8'
scss :style
diff --git a/config.ru b/config.ru
index 3e82e35..ad609be 100644
--- a/config.ru
+++ b/config.ru
@@ -1,5 +1,6 @@
-SERVICE = "lazar"
+ENV["LAZAR_ENV"] = "development"#"production"
require 'bundler'
Bundler.require
require File.expand_path './application.rb'
+require "sinatra/reloader" if development?
run Sinatra::Application
diff --git a/helper.rb b/helper.rb
index caa1923..54dbd5e 100644
--- a/helper.rb
+++ b/helper.rb
@@ -1,218 +1,3 @@
helpers do
-
- def is_authorized(uri, action)
- if OpenTox::Authorization.server && session[:subjectid] != nil
- return OpenTox::Authorization.authorized?(uri, action, session[:subjectid])
- else
- return true
- end
- return false
- end
-
- def is_aluist
- OpenTox::Authorization.list_user_groups(session[:username], session[:subjectid]).include?("aluist")
- end
-
- def hide_link(destination)
- @link_id = 0 unless @link_id
- @link_id += 1
- haml :js_link, :locals => {:name => "hide", :destination => destination, :method => "hide"}, :layout => false
- end
-
- def toggle_link(destination,name)
- @link_id = 0 unless @link_id
- @link_id += 1
- haml :js_link, :locals => {:name => name, :destination => destination, :method => "toggle"}, :layout => false
- end
-
- def sort(descriptors,value_map)
- features = {:activating => [], :deactivating => [], :pc_features => []}
- if descriptors.kind_of?(Array)
- descriptors.each do |d|
- if !value_map.empty?
- features[:activating] << {:smarts => d[OT.smarts],:p_value => d[OT.pValue]} if d[OT.effect] == 2
- features[:deactivating] << {:smarts => d[OT.smarts],:p_value => d[OT.pValue]} if d[OT.effect] == 1
- else
- if d[OT.effect] =~ TRUE_REGEXP
- features[:activating] << {:smarts => d[OT.smarts],:p_value => d[OT.pValue]}
- elsif d[OT.effect] =~ FALSE_REGEXP
- features[:deactivating] << {:smarts => d[OT.smarts],:p_value => d[OT.pValue]}
- end
- end
- end
- else
- descriptors.each do |d,v|
- features[:pc_features] << {:feature => d, :value => v}
- end
- end
- features
- end
-
- def compound_image(compound,descriptors,value_map)
- haml :compound_image, :locals => {:compound => compound, :features => sort(descriptors,value_map)}, :layout => false
- end
- def activity_markup(activity,value_map)
- if value_map and !value_map.empty?
- if value_map.size == 2
- activity = value_map.index(activity) if value_map.has_value? activity
- if activity.to_i == 2
- haml ".active #{value_map[activity]}", :layout => false
- elsif activity.to_i == 1
- haml ".inactive #{value_map[activity]}", :layout => false
- else
- haml ".other #{activity.to_s}", :layout => false
- end
- else
- haml ".other #{activity.to_s}", :layout => false
- end
- elsif OpenTox::Algorithm::numeric? activity
- haml ".other #{sprintf('%.03g', activity.to_f)}", :layout => false
- else
- haml ".other #{activity.to_s}", :layout => false
- end
-=begin
- case activity.class.to_s
- when /Float/
- haml ".other #{sprintf('%.03g', activity)}", :layout => false
- when /String/
- case activity
- when "true"
- haml ".active active", :layout => false
- when "false"
- haml ".inactive inactive", :layout => false
- else
- haml ".other #{activity.to_s}", :layout => false
- end
- else
- if activity #true
- haml ".active active", :layout => false
- elsif !activity # false
- haml ".inactive inactive", :layout => false
- else
- haml ".other #{activity.to_s}", :layout => false
- end
- end
-=end
- end
-
- def neighbors_navigation
- @page = 0 unless @page
- haml :neighbors_navigation, :layout => false
- end
-
- def models_navigation
- @page = 0 unless @page
- haml :models_navigation, :layout => false
- end
-
- def models_navigation_bottom
- @page = 0 unless @page
- haml :models_navigation_bottom, :layout => false
- end
-
- def endpoint_option_list(max_time=3600)
- out = ""
- tmpfile = File.join(TMP_DIR, 'endpoint_option_list')
- if File.exists? tmpfile
- if Time.now-File.mtime(tmpfile) <= max_time
- f = File.open(tmpfile, 'r+')
- f.each{|line| out << line}
- return out
- else
- File.unlink(tmpfile)
- end
- end
- result = endpoint_selection()
- if result.lines.count > 3
- f = File.new(tmpfile,'w')
- f.print result
- f.close
- end
- result
- end
-
- def endpoint_level(endpoint="Endpoints", level=1)
- results = OpenTox::Ontology::Echa.echa_endpoints(endpoint) rescue results = []
- out = ""
- out += "<ul id='list_#{endpoint}' class='endpoint level_#{level}'>\n" if results.size > 0
- results.each do |result|
- r = result.split(',')
- endpointname = CGI.escape(r.first.split("#").last).gsub(".","")
- title = r[1..r.size-1].to_s
- out += " <li class='level_#{level}'><input type='radio' name='endpoint' value='#{result}' id='#{endpointname}' class='endpoint_list' /><label for='#{endpointname}' id='label_#{endpointname}'>#{title.gsub("\"","")}</label>\n"
- out += endpoint_level(endpointname, level + 1)
- out += "</li>\n"
- end
- out += "</ul>\n" if results.size > 0
- return out
- end
-
- def endpoint_selection()
- out = "<span id='endpoint_label'></span><input type='button' id='endpoint_list_button' value='Select endpoint' /> \n
- <div id='div_endpoint'>\n"
- out += "<b>Please select:</b>\n"
- out += endpoint_level
- js = ""
- out += "</div>\n"
- return out
- end
-
- def logmmol_to_mg(value ,mw)
- mg = round_to((10**(-1.0*round_to(value.to_f, 2))*(mw.to_f*1000)),4)
- return mg
- end
-
- def logmg_to_mg(value)
- mg = round_to(10**round_to(value.to_f, 2),4)
- return mg
- end
-
- def ptd50_to_td50(value ,mw)
- td50 = round_to((10**(-1.0*round_to(value.to_f, 2))*(mw.to_f*1000)),4)
- return td50
- end
-
- def round_to(value, deci)
- rounded = (value.to_f*(10**deci)).round / (10**deci).to_f
- return rounded
- end
-
- def calc_mw(compound_uri)
- ds = OpenTox::Dataset.new()
- ds.save(@subjectid)
- ds.add_compound(compound_uri)
- ds.save(@subjectid)
- mw_algorithm_uri = File.join(CONFIG[:services]["opentox-algorithm"],"pc/MW")
- mw_uri = OpenTox::RestClientWrapper.post(mw_algorithm_uri, {:dataset_uri=>ds.uri})
- ds.delete(@subjectid)
- mw_ds = OpenTox::Dataset.find(mw_uri, @subjectid)
- mw = mw_ds.data_entries[compound_uri][mw_uri.to_s + "/feature/MW"].first.to_f
- mw_ds.delete(@subjectid)
- return mw
- end
-
- def transform(value, compound_uri, name, haml)
- prediction_trans = nil
- model_name = name.to_s.downcase
- if model_name.include? "ptd50"
- mw = calc_mw(compound_uri)
- td50 = ptd50_to_td50(value, mw)
- prediction_trans = "TD50: #{td50}"
- elsif model_name.include? "loael"
- if model_name.include? "mol"
- mw = calc_mw(compound_uri)
- mg = logmmol_to_mg(value, mw)
- prediction_trans = "mg/kg bw/day: #{mg}"
- elsif model_name.include? "mg"
- mg = logmg_to_mg(value)
- prediction_trans = "mg/kg bw/day: #{mg}"
- end
- end
- if haml == true
- haml ".other #{prediction_trans.to_s}", :layout => false
- else
- return prediction_trans
- end
- end
end
diff --git a/lazar-gui.gemspec b/lazar-gui.gemspec
index af5f0f9..f37b512 100644
--- a/lazar-gui.gemspec
+++ b/lazar-gui.gemspec
@@ -13,13 +13,13 @@ Gem::Specification.new do |s|
s.rubyforge_project = "lazar-gui"
s.files = `git ls-files`.split("\n")
- s.add_runtime_dependency "lazar", "~> 0.9.3", '>= 0.9.3'
- s.add_runtime_dependency "gem-path", "~> 0.6.1", '>= 0.6.1'
- s.add_runtime_dependency "sinatra", "~> 1.4.0", '>= 1.4.0'
- s.add_runtime_dependency "rdiscount", "~> 2.1.0", '>= 2.1.0'
- s.add_runtime_dependency "haml", "~> 4.0.0", '>= 4.0.0'
- s.add_runtime_dependency "sass", "~> 3.4.0", '>= 3.4.0'
- s.add_runtime_dependency "unicorn", "~> 5.1.0", '>= 5.1.0'
+ s.add_runtime_dependency "lazar", "= 1.0.0"
+ s.add_runtime_dependency "gem-path"
+ s.add_runtime_dependency "sinatra"
+ s.add_runtime_dependency "rdiscount"
+ s.add_runtime_dependency "haml"
+ s.add_runtime_dependency "sass"
+ s.add_runtime_dependency "unicorn"
s.post_install_message = %q{
Service cmds:
diff --git a/views/batch.haml b/views/batch.haml
index 9bfa67e..6c37a2b 100644
--- a/views/batch.haml
+++ b/views/batch.haml
@@ -2,57 +2,99 @@
%a.btn.btn-warning{:href => to('/predict')}
%span.glyphicon.glyphicon-menu-left{:aria=>{:hidden=>"true"}}
New Prediction
- / displays all prediction result in first table
+ %a.btn.btn-success{:href=>"#{to("/predict/#{@filename}")}", :title=>"download"}
+ %span.glyphicon.glyphicon-download-alt
+ download CSV
+
+ / show processed file name
+ %topline
+ %div.row
+ %div.col-md-4
+ %h3 Batch Prediction Results:
+ %div.col-md-8
+ %h3= @filename
+
+ / displays all prediction result in one table
%div.table-responsive
%table.table.table-bordered{:id=>"batch", :style=>"background-color:white;"}
- %thead
- %tr
- %h3.col-md-4{:style=>"padding-left:0;"} Batch Prediction Results:
- %h3.col-md-8= @filename
- %tr
- %span.btn.btn-default
- %a{:href=>"#{to("/predict/#{@filename}")}", :title=>"download"}
- %span.glyphicon.glyphicon-download-alt{:aria=>{:hidden=>"true"}}
- CSV
%tbody
- / key = compound, values = array of arrays with model, prediction
+ - if @warnings
+ - @warnings.each do |warning|
+ %tr
+ %td
+ %b Warning
+ %td
+ = warning.sub(/\b(tmp\/)\b/,"")
+ / key = compound, values = [model,prediction]
- @batch.each do |key, values|
- compound = key
- - mw = compound.molecular_weight
%tr
%td{:style=>"vertical-align:top;"}
%p= compound.svg
%p= compound.smiles
- / array = single prediction [endpoint, result]
+
+ / array[0] = model, array[1] = prediction
- values.each_with_index do |array,i|
%td{:style=>"vertical-align:top;white-space:nowrap;"}
- model = array[0]
+ / model type (classification|regression)
+ - model.model.class.to_s.match("Classification") ? type = "Classification" : type = "Regression"
+ - unit = model.unit
- prediction = array[1]
+
%b{:class => "title"}
= "#{model.endpoint.gsub('_', ' ')} (#{model.species})"
- %p
- - if prediction[:confidence] == "measured"
+
+ / check for prediction
+ - if prediction[:neighbors].size > 0
%p
- %b Measured activity:
- - if prediction[:value].is_a?(Array)
- = prediction[:value][0].numeric? ? prediction[:value].collect{|v| weight = compound.mmol_to_mg(v, mw); '%.2e' % v + " (#{model.unit})"+" | #{'%.2e' % weight} (mg/kg_bw/day)"}.join("</br>") : prediction[:value].join(", ")
- - else
- = prediction[:value].numeric? ? "#{'%.2e' % prediction[:value]} (#{model.unit}) | #{'%.2e' % compound.mmol_to_mg(prediction[:value], mw)} (mg/kg_bw/day)" : prediction[:value]
+ / show model type (classification|regression)
+ %b Type:
+ = type
%p
- %b Compound is part of the training dataset
- - elsif prediction[:neighbors].size > 0
+ / check for database hit
+ - if prediction[:warning] =~ /\b(identical)\b/i
+
+ / show message about dbhit and measurements
+ %p
+ %b Compound is part of the training dataset
+ %p
+ %b Measured activity:
+ %br
+ - if prediction[:measurements].is_a?(Array)
+ = (type == "Regression") ? prediction[:measurements].collect{|value| "#{value.delog10} (#{unit})</br>#{compound.mmol_to_mg(value.delog10)} #{unit =~ /mmol\/L/ ? "(mg/L)" : "(mg/kg_bw/day)"}"}.join("</br>") : prediction[:measurements].join(", ")
+ - else
+ = (type == "Regression") ? "#{prediction[:measurements].delog10} (#{unit})</br>#{compound.mmol_to_mg(prediction[:measurements].delog10)} #{(unit =~ /\b(mol\/L)\b/) ? "(mg/L)" : "(mg/kg_bw/day)"}" : prediction[:measurements]
+
+
+ / show prediction
%p
- / model type (classification|regression)
- %b Type:
- = model.model.class.to_s.match("Classification") ? "Classification" : "Regression"
- %br
- %b Prediction:
- = prediction[:value].numeric? ? "#{'%.2e' % prediction[:value]} (#{model.unit}) | #{'%.2e' % compound.mmol_to_mg(prediction[:value], mw)} (mg/kg_bw/day)" : prediction[:value]
- %br
- / TODO probability
- %b Confidence:
- = prediction[:confidence].round(3)
+ %b Prediction:
+ %br
+ = (type == "Regression") ? "#{prediction[:value].delog10} (#{unit})</br>#{compound.mmol_to_mg(prediction[:value].delog10)} #{(unit =~ /\b(mol\/L)\b/) ? "(mg/L)" : "(mg/kg_bw/day)"}" : prediction[:value]
+
+ / show prediction interval or probability
+ %p
+ - if type == "Regression"
+ %b 95% Prediction interval:
+ - interval = (prediction[:prediction_interval].nil? ? nil : prediction[:prediction_interval])
+ %br
+ = interval.nil? ? "--" : "#{interval[1].delog10} - #{interval[0].delog10} (#{unit})"
+ %br
+ = "#{compound.mmol_to_mg(interval[1].delog10)} - #{compound.mmol_to_mg(interval[0].delog10)} #{(unit =~ /\b(mol\/L)\b/) ? "(mg/L)" : "(mg/kg_bw/day)"}" if !prediction[:prediction_interval].nil?
+ - else
+ %b Probability:
+ - unless prediction[:probabilities].nil?
+ %br
+ = "#{prediction[:probabilities].keys[0]}: #{prediction[:probabilities].values[0]}"
+ %br
+ / show warnings
%p
+ - if !prediction[:warning].nil?
+ %b Warnings:
+ %a.btn.glyphicon.glyphicon-info-sign{:href=>"javascript:void(0)", :title=>"Warnings", :tabindex=>"0", data: {trigger:"focus", toggle:"popover", placement:"left", html:"true", content:"#{prediction[:warning]}"}}
+
+ / no prediction
- else
%p
= "Not enough similar compounds </br>in training dataset."
diff --git a/views/details.haml b/views/details.haml
index 8a57440..be4948a 100644
--- a/views/details.haml
+++ b/views/details.haml
@@ -1,8 +1,12 @@
+:javascript
+ $(document).ready(function(){
+ addExternalLinks();
+ });
%div.modal-body{:style=>"padding:10px;"}
%button.close{ :type=>" button", data: { dismiss:"modal"}} &times;
%h3
Names and synonyms:
- %img.img-responsive{:src=>"#{@compound.uri}/image", :alt=>"Compound image not available", :width=>"300px", :heigth=>"300px", :style=>"float:left;"}
+ %p= @compound.svg
%p
%b="SMILES:"
%p= @smiles
@@ -19,6 +23,6 @@
%hr
%p{:style=>"padding-left:0.5em;"}
/ pubchem link
- %a.btn.btn-primary{:href=>"http://aop.in-silico.ch/", :title=>"Link opens in new window.", :alt=>"pubchem read across", :target=>"_blank"} PubChem read across
+ %a.btn.btn-primary{:href=>"http://aop.in-silico.ch/", :title=>"Link opens in new window.", :alt=>"pubchem read across", :rel=>"external"} PubChem read across
%i (experimental)
%br
diff --git a/views/faq_layout.haml b/views/faq_layout.haml
deleted file mode 100644
index a9b6664..0000000
--- a/views/faq_layout.haml
+++ /dev/null
@@ -1,67 +0,0 @@
-!!!
-%html{:xmlns => "http://www.w3.org/1999/xhtml", "xml:lang" => "en", :lang => "en"}
- %head
- %meta{'charset'=>"utf-8"}
- %meta{'http-equiv'=>"X-UA-Compatible", :content=>"IE=edge"}
- %meta{'name'=>"viewport", :content=>"width=device-width, initial-scale=1"}
- %title Lazar GUI FAQ
- %link{:rel=>'icon', :type=>'image/x-icon', :href=>'/images/favicon.ico'}
- %link{:rel=>'stylesheet', :href=>"#{'/css/bootstrap.min.css'}"}
- %link{:rel=>'stylesheet', :href=>"#{'/css/theme.default.min.css'}"}
- %link{:rel=>'stylesheet', :href=>"#{'/css/theme.bootstrap.min.css'}"}
- %link{ :href=>"/style.css", :rel=>"stylesheet"}
- %link{ :href=>"/stylesheets/jquery-ui.css", :rel=>"stylesheet"}
- %script{:src=>"/javascripts/jquery-1.11.2.min.js"}
- %script{:src=>"/javascripts/bootstrap.min.js"}
- %script{ :src=>"/javascripts/lazar-gui.js"}
- %body
- %noscript
- %div{ :style=>"width: 22em; position: absolute; left: 50%; margin-left: -11em; color: red; background-color: white; border: 1px solid red; padding: 4px; font-family: sans-serif"}
- Your web browser must have JavaScript enabled in order for this application to display correctly.
- %header.page-header
- %div.row
- %div.col-md-2
- %a{:href=> to("/predict")}
- %img.media-object{:src=>"/images/ist_logo.png", :alt=>"logo", :style=>"margin:0 3em 0 2em;"}
- %div.col-md-10
- %h1.media-heading{:style=>"margin: 0 0 0 1em;display:inline;"} Lazar GUI
- A Graphical User Interface for the <a href="http://github.com/opentox/lazar">Lazar</a> framework
-
- %div.container-fluid
- :javascript
- $(document).ready(function(){
- $("#back-top").hide();
- $(".blind").error(function(){
- $(this).attr('src', '/images/blind.png');
- });
- });
-
- = yield
-
- %footer.footer
- %div.container-fluid
- %p.text-muted
- &copy;
- %a{:href => 'http://www.in-silico.ch', :rel => "external"} <i style="font-family: serife">in silico</i> toxicology gmbh 2004 - #{Time.now.year.to_s}
-
- #back-top{:style => "z-index:100;position:fixed;bottom:1%;right:1%;"}
- %a{:href => "", :style=>"text:decoration:none;color:#ccc;"}
- %span.glyphicon.glyphicon-circle-arrow-up{:style => "font-size:3em;color:black;"}
- :javascript
- $("#back-top").hide();
- $(function () {
- $(window).scroll(function () {
- if ($(this).scrollTop() > 600) {
- $('#back-top').fadeIn();
- } else {
- $('#back-top').fadeOut();
- }
- });
- // scroll body to 0px on click
- $('#back-top a').click(function () {
- $('body,html').animate({
- scrollTop: 0
- }, 500);
- return false;
- });
- });
diff --git a/views/layout.haml b/views/layout.haml
index 5d6d57a..8a920ea 100644
--- a/views/layout.haml
+++ b/views/layout.haml
@@ -15,7 +15,7 @@
%script{:src=>"/javascripts/bootstrap.min.js"}
%script{:src=>"/javascripts/jquery.tablesorter.min.js"}
%script{:src=>"/javascripts/jquery.tablesorter.widgets.js"}
- %script{ :src=>"/javascripts/lazar-gui.js"}
+ %script{:src=>"/javascripts/lazar-gui.js"}
%body
%noscript
%div{ :style=>"width: 22em; position: absolute; left: 50%; margin-left: -11em; color: red; background-color: white; border: 1px solid red; padding: 4px; font-family: sans-serif"}
@@ -26,34 +26,35 @@
%a{:href=> to("/predict")}
%img.media-object{:src=>"/images/IST_logo_s.png", :alt=>"logo", :width=>"150px", :heigth=>"150px", :style=>"margin:0 3em 0 2em;"}
%div.col-md-8
- %h1.media-heading{:style=>"margin: 0 0 0 2em;"}
+ %h1.media-heading
lazar toxicity predictions
%div.col-md-2
%h1.media-heading
%small
- %a{:href=>"https://nano-lazar.in-silico.ch"} nano-lazar
+ %a{:href=>"https://nano-lazar.in-silico.ch", :rel=>"external"} nano-lazar
%div.container-fluid
%topline
%div.row
- %div.col-md-8
+ %div.col-md-10
Problems, bugs, ideas for improvements ? Please report at our
%a{:href => 'https://github.com/opentox/lazar-gui/issues', :rel => "external"} issue tracker
- or send us an email
- %a{ :href=>"mailto:info@in-silico.ch", :target=>"_top"}
+ , check out the
+ %a{:href=> to("/faq"), :rel => "external"} FAQ
+ page or send us an email.
+ %a{ :href=>"mailto:info@in-silico.ch?subject=[lazar v#{@version}]", :target=>"_top"}
%img.share{:src=>"/images/Email.png"}
- (version #{@version}).
- %div.col-md-2
- %div.col-md-2
- %a{:href=>"https://twitter.com/intent/tweet?source=http%3A%2F%2Flazar.in-silico.ch&text=:%20http%3A%2F%2Flazar.in-silico.ch", :target=>"_blank", :title=>"Tweet"}
+ [version: #{@version}]
+ %div.col-md-2{:style=>"text-align:right;"}
+ %a{:href=>"https://twitter.com/intent/tweet?source=http%3A%2F%2Flazar.in-silico.ch&text=http%3A%2F%2Flazar.in-silico.ch", :rel=>"external", :title=>"Tweet"}
%img.share{:src=>"/images/Twitter.png"}
- %a{:href=>"https://plus.google.com/share?url=http%3A%2F%2Flazar.in-silico.ch", :target=>"_blank", :title=>"Share on Google+"}
+ %a{:href=>"https://plus.google.com/share?url=http%3A%2F%2Flazar.in-silico.ch", :rel=>"external", :title=>"Share on Google+"}
%img.share{:src=>"/images/Google+.png"}
- %a{:href=>"http://www.linkedin.com/shareArticle?mini=true&url=http%3A%2F%2Flazar.in-silico.ch&title=&summary=&source=http%3A%2F%2Flazar.in-silico.ch", :target=>"_blank", :title=>"Share on LinkedIn"}
+ %a{:href=>"http://www.linkedin.com/shareArticle?mini=true&url=http%3A%2F%2Flazar.in-silico.ch&title=&summary=&source=http%3A%2F%2Flazar.in-silico.ch", :rel=>"external", :title=>"Share on LinkedIn"}
%img.share{:src=>"/images/LinkedIn.png"}
- %a{:href=>"https://www.facebook.com/sharer/sharer.php?u=http%3A%2F%2Flazar.in-silico.ch&title=&summary=&source=http%3A%2F%2Flazar.in-silico.ch", :target=>"_blank", :title=>"Share on Facebook"}
+ %a{:href=>"https://www.facebook.com/sharer/sharer.php?u=http%3A%2F%2Flazar.in-silico.ch&title=&summary=&source=http%3A%2F%2Flazar.in-silico.ch", :rel=>"external", :title=>"Share on Facebook"}
%img.share{:src=>"/images/Facebook.png"}
-
+
:javascript
$(document).ready(function(){
$("#back-top").hide();
@@ -77,17 +78,19 @@
%p.text-muted
&copy;
%a{:href => 'http://www.in-silico.ch', :rel => "external"} <i style="font-family: serife">in silico</i> toxicology gmbh 2004 - #{Time.now.year.to_s}
+ |
+ %a{:href => to("/license"), :rel => "external"} GPL3 License
%supporters.col-md-12
- %p Financial support:
- %a{:href=>"http://www.bfr.bund.de/de/start.html", :target=>"_blank"}
+ %p Financial support by
+ %a{:href=>"http://www.bfr.bund.de/de/start.html", :rel=>"external"}
%img{:src=>"/images/bfr_logo.gif"}
- %a{:href=>"http://www.opentox.org/", :target=>"_blank"}
+ %a{:href=>"http://www.opentox.org/", :rel=>"external"}
%img{:src=>"/images/ot_logo.png"}
- %a{:href=>"https://enanomapper.net/", :target=>"_blank"}
+ %a{:href=>"https://enanomapper.net/", :rel=>"external"}
%img{:src=>"/images/enm_logo.png"}
- %a{:href=>"https://www.researchgate.net/institution/Nestle_SA/department/Nestle_Research_Center", :target=>"_blank"}
+ %a{:href=>"https://www.researchgate.net/institution/Nestle_SA/department/Nestle_Research_Center", :rel=>"external"}
%img{:src=>"/images/nestec.jpg"}
-
+
#back-top{:style => "z-index:100;position:fixed;bottom:1%;right:1%;"}
%a{:href => "", :style=>"text:decoration:none;color:#ccc;"}
diff --git a/views/license.haml b/views/license.haml
new file mode 100644
index 0000000..2813220
--- /dev/null
+++ b/views/license.haml
@@ -0,0 +1 @@
+= @license
diff --git a/views/model_details.haml b/views/model_details.haml
index 1be75e7..5c3aa4f 100644
--- a/views/model_details.haml
+++ b/views/model_details.haml
@@ -1,26 +1,43 @@
%b Model:
%br
Source:
-%a{:href=>model.source, :target=>"external"}
+%a{:href=>model.source, :rel=>"external"}
= model.source
%br
- model.classification? ? type = "Classification" : type = "Regression"
= "Type:\t"
= type
%br
-- training_dataset = OpenTox::Dataset.find model.training_dataset.id
+- training_dataset = OpenTox::Dataset.find model.model.training_dataset_id
= "Training compounds:\t"
-= training_dataset.compounds.size
-
+= training_dataset.data_entries.size
+%br
+= "Training dataset:\t"
+%a{:href=>"#{to("/predict/dataset/#{training_dataset.name}")}"}
+ = training_dataset.name
+%br
+%b Algorithms:
+%br
+Similarity:
+%a{:href=> "http://www.rubydoc.info/gems/lazar/OpenTox%2F#{model.model.algorithms["similarity"]["method"].sub("::", "%2F")}", :rel=>"external"}
+ = model.model.algorithms["similarity"]["method"]
+= ", min: #{model.model.algorithms["similarity"]["min"]}"
+%br
+Prediction:
+%a{:href=>"http://www.rubydoc.info/gems/lazar/OpenTox%2F#{model.model.algorithms["prediction"]["method"].sub("::","%2f")}", :rel=>"external"}
+ = model.model.algorithms["prediction"]["method"]
+%br
+Descriptors:
+= model.model.algorithms["descriptors"]["method"]+","
+= model.model.algorithms["descriptors"]["type"]
%p
- if type == "Classification"
%b Independent crossvalidations:
- else
%b Independent crossvalidations (-log10 transformed):
%div.row{:id=>"validations#{model.id}", :style=>"background-color:#f5f5f5;"}
- - model.crossvalidations.each do |crossvalidation|
+ - crossvalidations.each do |cv|
%span.col-xs-4.col-sm-4.col-md-4.col-lg-4
- - cv = OpenTox::CrossValidation.find crossvalidation.id
= "Num folds:\t"
= cv.folds
%br
@@ -34,76 +51,83 @@ Source:
= "Accuracy:\t"
= cv.accuracy.round(3) if cv.accuracy
%br
- = "True positive rate:\t"
- = cv.true_rate["active"].round(3) if cv.true_rate["active"]
- %br
- = "True negative rate:\t"
- = cv.true_rate["inactive"].round(3) if cv.true_rate["inactive"]
- %br
- = "Positive predictive value:\t"
- = cv.predictivity["active"].round(3) if cv.predictivity["active"]
- %br
- = "Negative predictive value:\t"
- = cv.predictivity["inactive"].round(3) if cv.predictivity["inactive"]
+ = "Weighted accuracy:\t"
+ = cv.weighted_accuracy.round(3) if cv.weighted_accuracy
+ - if cv.true_rate
+ %br
+ = "True positive rate:\t"
+ = cv.true_rate[cv.accept_values[0]].round(3)
+ %br
+ = "True negative rate:\t"
+ = cv.true_rate[cv.accept_values[1]].round(3)
+ - if cv.predictivity
+ %br
+ = "Positive predictive value:\t"
+ = cv.predictivity[cv.accept_values[0]].round(3)
+ %br
+ = "Negative predictive value:\t"
+ = cv.predictivity[cv.accept_values[1]].round(3)
%p
- %b Confusion Matrix:
- %table.table.table-condensed.table-borderless{:style=>"width:20%;"}
- %tbody
- %tr
- %td
- %td
- %td
- %b actual
- %td
- %td
- %tr
- %td
- %td
- %td active
- %td inactive
- -#%td total
- %tr
- %td
- %b predicted
- %td active
- %td
- =cv.confusion_matrix[0][0]
- %td
- =cv.confusion_matrix[0][1]
- -#%td
- =cv.confusion_matrix[0][0]+cv.confusion_matrix[0][1]
- %tr
- %td
- %td inactive
- %td
- =cv.confusion_matrix[1][0]
- %td
- =cv.confusion_matrix[1][1]
- -#%td
- =cv.confusion_matrix[1][0]+cv.confusion_matrix[1][1]
- -#%tr
- %td
- %td total
- %td
- =cv.confusion_matrix[0][0]+cv.confusion_matrix[1][0]
- %td
- =cv.confusion_matrix[0][1]+cv.confusion_matrix[1][1]
- %td
- -#= "Confusion Matrix:\t"
- -#= cv.confusion_matrix
+ - ["confusion_matrix", "weighted_confusion_matrix"].each_with_index do |matrix,idx|
+ %b= (idx == 0 ? "Confusion Matrix" : "Weighted Confusion Matrix")
+ %table.table.table-condensed.table-borderless{:style=>"width:20%;"}
+ %tbody
+ %tr
+ %td
+ %td
+ %td
+ %b actual
+ %td
+ %td
+ %tr
+ %td
+ %td
+ %td active
+ %td inactive
+ -#%td total
+ %tr
+ %td
+ %b predicted
+ %td active
+ %td
+ =( idx == 1 ? cv.send(matrix)[0][0].round(3) : cv.send(matrix)[0][0])
+ %td
+ =( idx == 1 ? cv.send(matrix)[0][1].round(3) : cv.send(matrix)[0][1])
+ -#%td
+ =cv.confusion_matrix[0][0]+cv.confusion_matrix[0][1]
+ %tr
+ %td
+ %td inactive
+ %td
+ =( idx == 1 ? cv.send(matrix)[1][0].round(3) : cv.send(matrix)[1][0])
+ %td
+ =( idx == 1 ? cv.send(matrix)[1][1].round(3) : cv.send(matrix)[1][1])
+ -#%td
+ =cv.confusion_matrix[1][0]+cv.confusion_matrix[1][1]
+ -#%tr
+ %td
+ %td total
+ %td
+ =cv.confusion_matrix[0][0]+cv.confusion_matrix[1][0]
+ %td
+ =cv.confusion_matrix[0][1]+cv.confusion_matrix[1][1]
+ %td
+ -#= "Confusion Matrix:\t"
+ -#= cv.confusion_matrix
+ %br
%br
/= "Confidence plot:"
/%p.plot
/ %img{:src=>"confp#{cv.id}.svg"}
- if model.regression?
%br
- = "Root mean squared error:\t"
+ %a.ht5{:href=>"https://en.wikipedia.org/wiki/Root-mean-square_deviation", :rel=>"external"} RMSE:
= cv.rmse.round(3) if cv.rmse
%br
- = "Mean absolute error:\t"
+ %a.ht5{:href=>"https://en.wikipedia.org/wiki/Mean_absolute_error", :rel=>"external"} MAE:
= cv.mae.round(3) if cv.mae
%br
- = "R square:\t"
+ %a.ht5{:href=>"https://en.wikipedia.org/wiki/Coefficient_of_determination", :rel=>"external"}= "R"+"<sup>2</sup>"+":"
= cv.r_squared.round(3) if cv.r_squared
%br
/= "Confidence plot:"
@@ -113,5 +137,5 @@ Source:
/= "Correlation plot"
/%p.plot
/ %img{:src=>"/corrp#{cv.id}.svg"}
-
-%br
+
+%br
diff --git a/views/neighbors.haml b/views/neighbors.haml
index 096e432..2d7c4a5 100644
--- a/views/neighbors.haml
+++ b/views/neighbors.haml
@@ -67,10 +67,10 @@
Compound
%th.sorter-false{:style =>"vertical-align:middle;"}
Measured Activity
- %a.btn.glyphicon.glyphicon-info-sign{:href=>"#neighbors", :title=>"Measured Activity", :tabindex=>"0", data: {trigger:"focus", container:"body", toggle:"popover", placement:"left", html:"true", content:"Experimental result(s) from the training dataset."}, :style=>"z-index:auto+10;"}
+ %a.btn.glyphicon.glyphicon-info-sign{:href=>"javascript:void(0)", :title=>"Measured Activity", :tabindex=>"0", data: {trigger:"focus", container:"body", toggle:"popover", placement:"auto", html:"true", content:"Experimental result(s) from the training dataset."}, :style=>"z-index:auto+10;"}
%th.sorter-false{:style =>"vertical-align:middle;"}
Similarity
- %a.btn.glyphicon.glyphicon-info-sign{:href=>"#neighbors", :title=>"Similarity", :tabindex=>"0", data: {trigger:"focus", container:"body", toggle:"popover", placement:"left", html:"true", content:"<a href=\"https://en.wikipedia.org/wiki/Jaccard_index\">Tanimoto/Jaccard</a> similarity based on <a href=\"https://openbabel.org/docs/dev/FileFormats/MolPrint2D_format.html\">Molprint2D</a> fingerprints."}, :style=>"z-index:auto+10;"}
+ %a.btn.glyphicon.glyphicon-info-sign{:href=>"javascript:void(0)", :title=>"Similarity", :tabindex=>"0", data: {trigger:"focus", container:"body", toggle:"popover", placement:"auto", html:"true", content:"<a alt=\"Link opens in new window.\" title=\"Link opens in new window.\" target=\"_blank\" href=\"https://en.wikipedia.org/wiki/Jaccard_index\">Tanimoto/Jaccard</a> similarity based on <a alt=\"Link opens in new window.\" title=\"Link opens in new window.\" target=\"_blank\" href=\"https://openbabel.org/docs/dev/FileFormats/MolPrint2D_format.html\">Molprint2D</a> fingerprints."}, :style=>"z-index:auto+10;"}
/ %th{:style =>"vertical-align:middle;"}
/ Supporting Information
%tbody
@@ -79,20 +79,22 @@
- prediction[:neighbors].uniq.each_with_index do |neighbor,count|
%tr
/ Compound
- - c = Compound.find(neighbor["_id"])
+ - c = Compound.find(neighbor)
%td{:style =>"vertical-align:middle;padding-left:1em;width:50%;"}
- /%a.btn.btn-link{:href => "#details#{j+1}", data: { toggle: "modal", remote: to("/prediction/#{CGI.escape(neighbor["_id"])}/details"), :id=>"link#{j+1}#{count}"}}
- %p= c.svg
+ %a.btn.btn-link{:href => "#details#{j+1}", data: { toggle: "modal", remote: to("/prediction/#{CGI.escape(c.id.to_s)}/details"), :id=>"link#{j+1}#{count}"}}
+ = c.svg
%p= c.smiles
- - mw = c.molecular_weight
- / Measured Activity = compound.features
+
+ / Measured Activity
%td{:style =>"vertical-align:middle;padding-left:1em;width:20%;white-space:nowrap;"}
- - features = c.features.collect{|k,v| v if k == predictionFeature[j]["id"] }.compact.flatten
- = (predictionFeature[j]["type"] == "numeric") ? features.collect{|v| weight = c.mmol_to_mg(v); '%.2e' % v + " (#{@models[j].unit})"+" , #{'%.2e' % weight} #{(unit == "mmol/L") ? "(mg/L)" : "(mg/kg_bw/day)"}"}.join("</br>") : features.join("</br>")
+ - if neighbor[:measurement].is_a?(Array)
+ = (type == "Regression") ? neighbor[:measurement].collect{|value| "#{value.delog10.signif(3)} (#{unit})</br>#{c.mmol_to_mg(value.delog10).signif(3)} #{unit =~ /mmol\/L/ ? "(mg/L)" : "(mg/kg_bw/day)"}"}.join("</br>") : neighbor[:measurement].join(", ")
+ - else
+ = (type == "Regression") ? "#{neighbor[:measurement].delog10.signif(3)} (#{unit})</br>#{c.mmol_to_mg(neighbor[:measurement].delog10).signif(3)} #{(unit =~ /\b(mol\/L)\b/) ? "(mg/L)" : "(mg/kg_bw/day)"}" : neighbor[:measurement]
+
/ Similarity = tanimoto
%td{:style =>"vertical-align:middle;padding-left:1em;width:20%;"}
- / TODO differentiate between no neighbors found and compound found in dataset, display neighbors for compounds in dataset?
- = neighbor[:tanimoto] != nil ? neighbor[:tanimoto].to_f.round(3) : "Not enough similar compounds </br>in training dataset."
+ = neighbor[:similarity].round(3)
- else
%span.btn.btn-default.disabled
diff --git a/views/predict.haml b/views/predict.haml
index 010ed12..59630d0 100644
--- a/views/predict.haml
+++ b/views/predict.haml
@@ -111,7 +111,7 @@
};
// whole site content needs to be in one form. Input and checkboxes are proofed by js functions.
-%form{:name => "form", :action => to('/predict'), :method => "post", :enctype => "multipart/form-data", :onsubmit => "return !!(showcircle())" }
+%form{:name => "form", :action => to('/predict'), :method => "post", :enctype => "multipart/form-data", :onsubmit => "return !!(showcircle())" }
%fieldset#top.well
%h2 1. Draw a chemical structure
#insert
@@ -125,11 +125,13 @@
%br
%input{:type => 'text', :name => 'identifier', :id => 'identifier', :size => '60'}
%p
- %label{:for=>"fileselect"}
+ -#%label{:for=>"fileselect"}
or upload a CSV file for batch predictions (disabled in public version)
- %br
- %span.btn.btn-default.btn-file
- %input{:type=>"file", :name=> "fileselect", :id=>"fileselect", :accept=>"text/csv", :disabled=>"disabled"}
+ -#%a.btn.glyphicon.glyphicon-info-sign{:href=>"javascript:void(0)", :title=>"File format", :tabindex=>"0", data: {trigger:"focus", toggle:"popover", placement:"auto", html:"true", content:"One column with compounds and keyword SMILES or InChI in the first row."}}
+ -#%br
+ -#%span.btn.btn-default.btn-file
+ -#%input{:type=>"file", :name=> "fileselect", :id=>"fileselect", :accept=>"text/csv", :disabled=>"disabled"}
+ %input{:type=>"hidden", :name=> "fileselect", :id=>"fileselect", :accept=>"text/csv", :disabled=>"disabled"}
%fieldset#middle.well
%h2 2. Select one or more endpoints
@@ -162,6 +164,7 @@
document.getElementById("details#{model.id}").appendChild(details);
$(button).show();
$(image).hide();
+ addExternalLinks();
});
}
}
diff --git a/views/prediction.haml b/views/prediction.haml
index 0f3d57b..1b8d38d 100644
--- a/views/prediction.haml
+++ b/views/prediction.haml
@@ -1,10 +1,3 @@
-:javascript
- $(document).ready(function(){
- $('[data-toggle="popover"]').popover();
- $('.modal').on('hidden.bs.modal', function () {
- $(this).removeData('bs.modal');
- });
- });
%div.well
%a.btn.btn-warning{:href => to('/predict')}
%i.glyphicon.glyphicon-menu-left
@@ -16,9 +9,9 @@
%tbody
%tr
%td{:id=>"compound", :style=>"vertical-align:top;"}
- %p= @compound.svg
+ %a.btn.btn-link{:href => "#details0", data: { toggle: "modal", remote: to("/prediction/#{CGI.escape(@compound.id.to_s)}/details"), :id=>"link01"}}
+ = @compound.svg
%p= @compound.smiles
- - mw = @compound.molecular_weight
- @model_types = {}
- @dbhit = {}
- @predictions.each_with_index do |prediction,i|
@@ -28,52 +21,66 @@
%td{:style=>"vertical-align:top;white-space:nowrap;"}
%b{:class => "title"}
= "#{@models[i].endpoint.gsub('_', ' ')} (#{@models[i].species})"
- %p
- - if prediction[:confidence] == "measured"
- - @dbhit[i] = true
+
+ / check for prediction
+ - if prediction[:neighbors].size > 0
%p
- %b Measured activity:
- - p prediction[:value]
- - if prediction[:value].is_a?(Array)
- = (type == "Regression") ? prediction[:value].collect{|v| weight = Compound.from_smiles(@compound.smiles).mmol_to_mg(v); '%.2e' % v + " (#{unit})"+", #{'%.2e' % weight} #{unit == "mmol/L" ? "(mg/L)" : "(mg/kg_bw/day)"}"}.join("</br>") : prediction[:value].join(", ")
- - else
- = (type == "Regression") ? "#{"%.2e" % prediction[:value]} (#{unit}), #{'%.2e' % @compound.mmol_to_mg(prediction[:value])} #{(unit == "mmol/L") ? "(mg/L)" : "(mg/kg_bw/day)"}" : prediction[:value]
- %p
- %b Compound is part of the training dataset
- - elsif prediction[:neighbors].size > 0
- %p
- / model type (classification|regression)
+ / show model type (classification|regression)
%b Type:
= type
- %br
- %b Prediction:
- = (type == "Regression") ? "#{'%.2e' % prediction[:value]} (#{unit}) , #{'%.2e' % @compound.mmol_to_mg(prediction[:value])} #{(unit == "mmol/L") ? "(mg/L)" : "(mg/kg_bw/day)"}" : prediction[:value]
- / tabindex=0 seems the best fix for FF|S browsers on OSX better than trigger="click focus" which ends up in double click for FF.
- / prediction popover
- %a.btn.glyphicon.glyphicon-info-sign{:href=>"#", :title=>"Prediction", :tabindex=>"0", data: {trigger:"focus", toggle:"popover", placement:"left", html:"true", content:"<p>lazar searches the training dataset for similar compounds (neighbors) and calculates the prediction from their experimental activities.<p><b>Classification:</b></br>Majority vote of neighbor activities weighted by similarity.<p><b>Regression:</b></br>Prediction from a local partial least squares regression model with neighbor activities weighted by similarity.<p><a href=\"http://www.frontiersin.org/Journal/10.3389/fphar.2013.00038/abstract\", target=\"_blank\"> Original publication</a>."}}
- %br
- - if type == "Regression"
- %b 95% Prediction interval:
- - interval = prediction[:prediction_interval].nil? ? " - - " : prediction[:prediction_interval].collect{|i| i.round(2)}
- %br
- = "#{interval[0]} - #{interval[1]} (#{unit}), #{'%.2e' % @compound.mmol_to_mg(interval[0])} - #{'%.2e' % @compound.mmol_to_mg(interval[1])} #{(unit == "mmol/L") ? "(mg/L)" : "(mg/kg_bw/day)"}"
- / prediction intervall popover
- %a.btn.glyphicon.glyphicon-info-sign{:href=>"#", :title=>"Prediction intervall", :tabindex=>"0", data: {trigger:"focus", toggle:"popover", placement:"left", html:"true", content:"An estimate of prediction uncertainty. The \"real\" value should be with 95% probability within the prediction interval."}}
+ %p
+ / check for database hit
+ - if prediction[:warning] =~ /\b(identical)\b/i
+ - @dbhit[i] = true
+
+ / show message about dbhit and measurements
+ %p
+ %b Compound is part of the training dataset
+ %p
+ %b Measured activity:
+ %br
+ - if prediction[:measurements].is_a?(Array)
+ = (type == "Regression") ? prediction[:measurements].collect{|value| "#{value.delog10.signif(3)} (#{unit})</br>#{@compound.mmol_to_mg(value.delog10).signif(3)} #{unit =~ /mmol\/L/ ? "(mg/L)" : "(mg/kg_bw/day)"}"}.join("</br>") : prediction[:measurements].join(", ")
+ - else
+ = (type == "Regression") ? "#{prediction[:measurements].delog10.signif(3)} (#{unit})</br>#{@compound.mmol_to_mg(prediction[:measurements].delog10).signif(3)} #{(unit =~ /\b(mol\/L)\b/) ? "(mg/L)" : "(mg/kg_bw/day)"}" : prediction[:measurements]
+
- else
- %b Confidence:
- = prediction[:confidence].round(2) unless prediction[:confidence].nil?
- / confidence popover
- %a.btn.glyphicon.glyphicon-info-sign{:href=>"#", :title=>"Confidence", :tabindex=>"0", data: {trigger:"focus", toggle:"popover", placement:"left", html:"true", content:"Indicates the applicability domain of a model. Predictions with a high confidence can be expected to be more reliable than predictions with low confidence. Confidence values may take any value between 0 and 1. For most models confidence > 0.025 is a sensible (hard) cutoff to distinguish between reliable and unreliable predictions."}}
+ - @dbhit[i] = false
+
+ / show prediction
%p
- /TODO add tooltip for significant ftagments and descriptors
- / - if @model_type[i] =~ /classification/i && (p.data_entries[0][1] != nil && p.data_entries[0][1] != 0.0)
- / Significant fragments:
- / %a.btn.btn-default.btn-sm{:id=>"linkSigFragments", :href => "#detailsTop", :tabindex=>"0", data: { toggle: "modal", remote: to("/prediction/#{CGI.escape(@model_uri)}/#{@model_type[i]}/#{CGI.escape(@compound.uri)}/fingerprints")}} Significant fragments
- / - if @model_type[i] =~ /regression/i && (p.data_entries[0][1] != nil && p.data_entries[0][1] != 0.0)
- / Descriptors
- / %a.btn.btn-default.btn-sm{:id=>"linkDescriptors", :href => "#detailsTop", :tabindex=>"0", data: { toggle: "modal", remote: to("/prediction/#{CGI.escape(@model_uri)}/#{@model_type[i]}/#{CGI.escape(@compound.uri)}/fingerprints")}} Descriptors
- / %p
+ %b Prediction:
+ / prediction popover
+ %a.btn.glyphicon.glyphicon-info-sign{:href=>"javascript:void(0)", :title=>"Prediction", :tabindex=>"0", data: {trigger:"focus", toggle:"popover", placement:"left", html:"true", content:"<p>lazar searches the training dataset for similar compounds (neighbors) and calculates the prediction from their experimental activities.<p><b>Classification:</b></br>Majority vote of neighbor activities weighted by similarity.<p><b>Regression:</b></br>Prediction from a local partial least squares regression model with neighbor activities weighted by similarity.<p><a href=\"http://www.frontiersin.org/Journal/10.3389/fphar.2013.00038/abstract\", target=\"_blank\"> Original publication</a>."}}
+ %br
+ = (type == "Regression") ? "#{prediction[:value].delog10.signif(3)} (#{unit})</br>#{@compound.mmol_to_mg(prediction[:value].delog10).signif(3)} #{(unit =~ /\b(mol\/L)\b/) ? "(mg/L)" : "(mg/kg_bw/day)"}" : prediction[:value]
+
+ / show prediction interval or probability
+ %p
+ - if type == "Regression"
+ %b 95% Prediction interval:
+ - interval = (prediction[:prediction_interval].nil? ? nil : prediction[:prediction_interval])
+ / prediction interval popover
+ %a.btn.glyphicon.glyphicon-info-sign{:href=>"javascript:void(0)", :title=>"Prediction intervall", :tabindex=>"0", data: {trigger:"focus", toggle:"popover", placement:"left", html:"true", content:"An estimate of prediction uncertainty. The \"real\" value should be with 95% probability within the prediction interval."}}
+ %br
+ = interval.nil? ? "--" : "#{interval[1].delog10.signif(3)} - #{interval[0].delog10.signif(3)} (#{unit})"
+ %br
+ = "#{@compound.mmol_to_mg(interval[1].delog10).signif(3)} - #{@compound.mmol_to_mg(interval[0].delog10).signif(3)} #{(unit =~ /\b(mol\/L)\b/) ? "(mg/L)" : "(mg/kg_bw/day)"}" if !prediction[:prediction_interval].nil?
+ - else
+ %b Probability:
+ / probability popover
+ %a.btn.glyphicon.glyphicon-info-sign{:href=>"javascript:void(0)", :title=>"Pobability", :tabindex=>"0", data: {trigger:"focus", toggle:"popover", placement:"left", html:"true", content:"Probability that the prediction belongs to one of the given classes."}}
+ - unless prediction[:probabilities].nil?
+ %br
+ = "#{prediction[:probabilities].keys[0]}: #{prediction[:probabilities].values[0].signif(3)}"
+ %br
+ = "#{prediction[:probabilities].keys[1]}: #{prediction[:probabilities].values[1].signif(3)}"
+
+ / show warnings
%p
+ - if !prediction[:warning].nil?
+ %b Warnings:
+ %a.btn.glyphicon.glyphicon-info-sign{:href=>"javascript:void(0)", :title=>"Warnings", :tabindex=>"0", data: {trigger:"focus", toggle:"popover", placement:"auto", html:"true", content:"#{prediction[:warning]}"}}
- else
- @dbhit[i] = false
%p
@@ -81,4 +88,8 @@
/ always show the neighbors table, message is given there
= haml :neighbors, :layout => false, :model_type => @model_types, :dbhit => @dbhit
+
+%div.modal.fade{:id=>"details0", :role=>"dialog"}
+ %div.modal-dialog.modal-lg
+ %div.modal-content
diff --git a/views/style.scss b/views/style.scss
index 49e03ab..2c84781 100644
--- a/views/style.scss
+++ b/views/style.scss
@@ -51,10 +51,12 @@ ul.share-buttons{
padding: 0 2px 1px 2px !important;
}
.page-header{
- margin:20px 0 20px;
- text-align:justify;
+ background-color: #fff;
+ padding:20px 0 20px 0;
+ margin: 0;
+ text-align:center;
display:inline-block;
- width:98.5%;
+ width:100%;
}
.share{
width: 30px;
@@ -62,9 +64,13 @@ ul.share-buttons{
}
supporters{
background-color: white;
-
+ text-align:center;
img{
width: 200px;
margin-right: 1em;
}
}
+
+.footer{
+ margin-top:3em;
+}
diff --git a/views/validation.haml b/views/validation.haml
deleted file mode 100644
index fd63ea6..0000000
--- a/views/validation.haml
+++ /dev/null
@@ -1,16 +0,0 @@
-- case @model_type
-- when "classification"
- - prediction = @cv.metadata["http://www.opentox.org/api/1.2#classificationStatistics"]["http://www.opentox.org/api/1.2#numCorrect"] + @cv.metadata["http://www.opentox.org/api/1.2#classificationStatistics"]["http://www.opentox.org/api/1.2#numIncorrect"]
- %p= "Number of predictions: #{prediction}"
- - percent = @cv.metadata["http://www.opentox.org/api/1.2#classificationStatistics"]["http://www.opentox.org/api/1.2#percentCorrect"]
- %p= "Correct predictions: #{percent.round(2)} %"
-- when "regression"
- - prediction = @cv.metadata["http://www.opentox.org/api/1.2#numInstances"].to_i - @cv.metadata["http://www.opentox.org/api/1.2#numUnpredicted"].to_i
- %p= "Number of predictions: #{prediction}"
- - rSquare = @cv.metadata["http://www.opentox.org/api/1.2#regressionStatistics"]["http://www.opentox.org/api/1.2#rSquare"]
- %p= "R-squared: #{rSquare.round(2)} %"
- - rootMeanSquaredError = @cv.metadata["http://www.opentox.org/api/1.2#regressionStatistics"]["http://www.opentox.org/api/1.2#rootMeanSquaredError"]
- %p= "Root Mean Square Error: #{rootMeanSquaredError.round(2)} %"
- - meanAbsoluteError = @cv.metadata["http://www.opentox.org/api/1.2#regressionStatistics"]["http://www.opentox.org/api/1.2#meanAbsoluteError"]
- %p= "Mean Absolute Error: #{meanAbsoluteError.round(2)} %"
-