2
$\begingroup$

I am trying to populate the rows and columns of a table by using a rule replacment.

To generate a table that looks like this enter image description here

For example Sc would be row 1, column 1.

An example of a record looks like this

 rawData = Import["H:\\allresults.json"]


record = {19, 60, "Ag", "Ag", "19Ag@60Ag_npo: -186.503305 by solar<br> \
19Ag@60Ag_bnp: -180.812004 by solar<br> O_sng:-8.032213 by \
marco<br>", "-1.675194475", "Binding Energy", "solar"}

Then I extract the relevant entries with some functions (there is probably a more elegant way to to do this)

getRow[resultVector_] := resultVector[[3]];
getColumn[resultVector_] := resultVector[[4]];
getResult[resultVector_] := resultVector[[5]];
getResultType[resultVector_] := resultVector[[7]];

For example

getRow[record]

gives

Out[41] = Ag

I have a list of replacemnt rules

elementList = {"Sc" -> 1, "Ti" -> 2, "V" -> 3, "Cr" -> 4, "Mn" -> 5, 
  "Fe" -> 6, "Co" -> 7, "Ni" -> 8, "Cu" -> 9, "Zn" -> 10, "Y" -> 11, 
  "Zr" -> 12, "Nb" -> 13, "Mo" -> 14, "Tc" -> 15, "Ru" -> 16, 
  "Rh" -> 17, "Pd" -> 18, "Ag" -> 19, "Cd" -> 20, "Lu" -> 21, 
  "Hf" -> 22, "Ta" -> 23, "W" -> 24, "Re" -> 25, "Os" -> 26, 
  "Ir" -> 27, "Pt" -> 28, "Au" -> 29, "Hg" -> 30}

I would like to build a table where the location in the table gets identified, and the corresponding result gets put into that location of the table.

For example Ag, Ag (row, column) should put "-1.675194475" in location (19,19) (row, column) of a table.

Is there a better way to do this than with replacement rules?


Update:

Here is my current implementation to see all my data:

elementList = {"Sc" -> 1, "Ti" -> 2, "V" -> 3, "Cr" -> 4, "Mn" -> 5, 
 "Fe" -> 6, "Co" -> 7, "Ni" -> 8, "Cu" -> 9, "Zn" -> 10, "Y" -> 11, 
  "Zr" -> 12, "Nb" -> 13, "Mo" -> 14, "Tc" -> 15, "Ru" -> 16, 
  "Rh" -> 17, "Pd" -> 18, "Ag" -> 19, "Cd" -> 20, "Lu" -> 21, 
  "Hf" -> 22, "Ta" -> 23, "W" -> 24, "Re" -> 25, "Os" -> 26, 
  "Ir" -> 27, "Pt" -> 28, "Au" -> 29, "Hg" -> 30};

I create lists of data for different particle sizes and energy types

data = Import["H:\\allresults.json"];
atoms32 = Select[data, StringCases[#[[1]], "32"] != {} &];
atoms79 = Select[data, StringCases[#[[1]], "60"] != {} &];
atoms32Binding = 
  Select[atoms32, StringCases[#[[1]], "Binding"] != {} &];
atoms32Cohesive = 
  Select[atoms32, StringCases[#[[1]], "Cohesive"] != {} &] ;
atoms79Binding = 
  Select[atoms79, StringCases[#[[1]], "Binding"] != {} &];
atoms79Cohesive = 
  Select[atoms79, StringCases[#[[1]], "Cohesive"] != {} &];
mat = Outer[List, elements, elements];

Is there a more elegant way to do this? I intend to do more energy calculations of different types in the future (vacancy formation energy etc). Is it possible to write it such that the data is automatically partitioned out into lists for each size and type?

rules79Binding = 
  Cases[atoms79Binding, {__, "M1" -> e1_, "M2" -> e2_, __, 
     "result" -> val_, __} :> {e1, e2} -> 
     ToExpression@val, \[Infinity]];
rules79Cohesive = 
  Cases[atoms79Cohesive, {__, "M1" -> e1_, "M2" -> e2_, __, 
     "result" -> val_, __} :> {e1, e2} -> 
     ToExpression@val, \[Infinity]];
rules32Binding = 
  Cases[atoms32Binding, {__, "M1" -> e1_, "M2" -> e2_, __, 
     "result" -> val_, __} :> {e1, e2} -> 
     ToExpression@val, \[Infinity]];
rules32Cohesive = 
  Cases[atoms32Cohesive, {__, "M1" -> e1_, "M2" -> e2_, __, 
     "result" -> val_, __} :> {e1, e2} -> 
     ToExpression@val, \[Infinity]]; 

This also suffers from exactly the same repetitive line with the only thing that changes between the lines is the list.

Finally I plot all the data

ArrayPlot[mat /. rules79Binding /. {_, _} -> 0, 
 ColorFunction -> (Blend[{Blue, Red}, #] &), 
 ColorRules -> {0 -> White}, Mesh -> True, Frame -> True, 
 FrameTicks -> ({#, #} &@Transpose@{Range@Length@elements, elements}),
  PlotRangePadding -> None, ImageSize -> 500, 
 PlotLabel -> "19M1@60M2 Binding Energy"]
ArrayPlot[mat /. rules79Cohesive /. {_, _} -> 0, 
 ColorFunction -> (Blend[{Blue, Red}, #] &), 
 ColorRules -> {0 -> White}, Mesh -> True, Frame -> True, 
 FrameTicks -> ({#, #} &@Transpose@{Range@Length@elements, elements}),
  PlotRangePadding -> None, ImageSize -> 500, 
 PlotLabel -> "19M1@60M2 Cohesive Energy"]
ArrayPlot[mat /. rules32Binding /. {_, _} -> 0, 
 ColorFunction -> (Blend[{Blue, Red}, #] &), 
 ColorRules -> {0 -> White}, Mesh -> True, Frame -> True, 
 FrameTicks -> ({#, #} &@Transpose@{Range@Length@elements, elements}),
  PlotRangePadding -> None, ImageSize -> 500, 
 PlotLabel -> "6M1@32M2 Binding Energy"]
ArrayPlot[mat /. rules32Cohesive /. {_, _} -> 0, 
 ColorFunction -> (Blend[{Blue, Red}, #] &), 
 ColorRules -> {0 -> White}, Mesh -> True, Frame -> True, 
 FrameTicks -> ({#, #} &@Transpose@{Range@Length@elements, elements}),
  PlotRangePadding -> None, ImageSize -> 500, 
 PlotLabel -> "6M1@32M2 Cohesive Energy"]

I have not put pictures up of each plot so that I do not make the post too long.

Also, How can I map specific numerical values over color gradients. For example, for the binding energies, {-1,-2} blends through green. {-2,-3} blends through yellow {-3,-5}, blends through orange, {-5, -10} blends through red, and {-10, infinity} is black.

$\endgroup$
10
  • $\begingroup$ Your record needs an extra {. I couldn't add it as I can only edit with a minimum of 6 characters. $\endgroup$ Commented May 3, 2013 at 5:40
  • $\begingroup$ Your problem might be more tractable if you do a proper Import[] of your source data. Can you maybe give at least an example file we can pull data from? $\endgroup$ Commented May 3, 2013 at 5:41
  • $\begingroup$ Can you also explain what the problem with using the replacement is? Is it taking too long this way or is it not doing something that you would otherwise like it to do? $\endgroup$ Commented May 3, 2013 at 5:42
  • $\begingroup$ Here is a link to the data. It is in JSON format. docs.google.com/file/d/0B5gGZ4-SD7-Zb1Q2ZUtUUmJXNHc/… $\endgroup$
    – olliepower
    Commented May 3, 2013 at 5:46
  • $\begingroup$ @JonathanShock I don't know how to do the rule replacement. The table shown is on the web. and my link has the data that generated it. I want to load the data into a table to both reproduce the chart, and to be able to perform calculations on the data. Like make plots of the values across a row for example. $\endgroup$
    – olliepower
    Commented May 3, 2013 at 5:50

2 Answers 2

6
$\begingroup$

The following will take all of the data that you want from the json file and give you a Table that you can use as you wish. Is this what was wanted?

elementList = {"Sc" -> 1, "Ti" -> 2, "V" -> 3, "Cr" -> 4, "Mn" -> 5, 
"Fe" -> 6, "Co" -> 7, "Ni" -> 8, "Cu" -> 9, "Zn" -> 10, "Y" -> 11, 
"Zr" -> 12, "Nb" -> 13, "Mo" -> 14, "Tc" -> 15, "Ru" -> 16, 
"Rh" -> 17, "Pd" -> 18, "Ag" -> 19, "Cd" -> 20, "Lu" -> 21, 
"Hf" -> 22, "Ta" -> 23, "W" -> 24, "Re" -> 25, "Os" -> 26, 
"Ir" -> 27, "Pt" -> 28, "Au" -> 29, "Hg" -> 30};

Import the data

data = Import["directory/allresults.json"];

Take only the data which includes the binding energy results.

binding = Select[data, StringCases[#[[1]], "Binding"] != {} &];

Take this data and take the elements which correspond to the x and y axes in the figure (ie. the two elements) along with the result (which has to be converted to an Expression rather than a String

dataall = {#[[1]], #[[2]], 
  ToExpression[#[[3]]]} & /@ ({"M1", "M2", "result"} /. #[[2]] & /@
    binding) /. elementList;

This should be the table you are looking for (or at least a list of the data you want).

Edit:

In response to the comment, you can populate a table in the way that you want with:

tab=Table[Cases[dataall,{m,n,_}][[;; , 3]],{m,1,30},{n,1,30}] // MatrixForm

However, you should note that there are sometimes two entries for a single combination of elements.

If you want the elements only at the end of the file (as requested in the comment) you can call:

Table[
  With[{x = Cases[dataall, {m, n, _}][[;; , 3]]}, 
    If[x === {}, 0, x[[-1]]]], 
  {m, 1, 30}, {n, 1, 30}] // MatrixForm
$\endgroup$
4
  • $\begingroup$ If it is possible, can the data be ordered such that dataall[[19]][[19]] would give -172.687486 ? $\endgroup$
    – olliepower
    Commented May 3, 2013 at 6:27
  • $\begingroup$ @olliepower, there are two problems. One is that that appears to be the cohesive energy, the other is that there are two entries for binding energy (and also two for cohesive energy) for (for instance) Ag, Ag. I have however added this as an edit to the answer. $\endgroup$ Commented May 3, 2013 at 6:33
  • $\begingroup$ I see. I just noticed you edited your answer. If there are two entries it should take the entry closest to the end of the data file. . I am editing my above comment to read for the binding energy. $\endgroup$
    – olliepower
    Commented May 3, 2013 at 6:37
  • $\begingroup$ That is now implemented as well. $\endgroup$ Commented May 3, 2013 at 6:39
4
$\begingroup$

I prefer a slightly different approach to Jonathan's, and I believe it is simpler and more in line with the spirit of using rule replacements for getting things done. First, note that since you're dealing with elements in the periodic table, which are finite and small in number (and pairs of those), you can easily generate your matrix of pairs of elements and apply rules to those. So, taking the list of elements and the data (where elementList is from the question),

elements = List @@@ elementList // Transpose // First;
mat = Outer[List, elements, elements];

you can construct the replacement rules from the JSON structure as

data = Import["~/Downloads/Chrome/allresults.json"];
rules = Cases[data, {__, "M1" -> e1_, "M2" -> e2_, __, "result" -> val_, __} :> 
    {e1, e2} -> ToExpression@val, ∞];

and simply use rules to replace the matrix entries and display the result:

ArrayPlot[
    mat /. rules /. {_, _} -> 0,
    ColorFunction -> (Blend[{Blue, Red}, #] &), 
    ColorRules -> {0 -> White}, Mesh -> True, Frame -> True,
    FrameTicks -> ({#, #} &@Transpose@{Range@Length@elements, elements}),
    PlotRangePadding -> None, ImageSize -> 500
]

enter image description here

$\endgroup$
8
  • $\begingroup$ I get errors when i tried to use your code. `Outer::normal: Nonatomic expression expected at position 2 in Outer[List,element,element]. >>' Outer::normal: Nonatomic expression expected at position 2 in Outer[List,element,element]. >> Outer::normal: Nonatomic expression expected at position 2 in Outer[List,element,element]. >> $\endgroup$
    – olliepower
    Commented May 3, 2013 at 7:03
  • $\begingroup$ I will trouble shoot in the morning. I must go to sleep. $\endgroup$
    – olliepower
    Commented May 3, 2013 at 7:11
  • $\begingroup$ @olliepower I don't get that error. You must not have defined element as I've done it. $\endgroup$
    – rm -rf
    Commented May 5, 2013 at 4:12
  • $\begingroup$ where you define element I defined elementList exactly as I did above, and I have copy pasted your code. I really like the fancy table it made! $\endgroup$
    – olliepower
    Commented May 5, 2013 at 5:33
  • $\begingroup$ @olliepower So does it work now or do you still get an error? $\endgroup$
    – rm -rf
    Commented May 5, 2013 at 8:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.