Get chemical compound data in SI units from wikidata

Viewed 36

For a project I need to get data about chemical compounds like density, mass, boiling point and melting point in SI units (meters, kg, Degree Celsius,...) via the CAS number of the compound.

With the Query builder and some testing I managed to achieve some of it with the following code (CAS-Number is the property P231 and I am searching for e.g. 67-64-1):

Wikidata Query Service

SELECT DISTINCT ?itemLabel ?melting_point ?boiling_point ?mass ?density WHERE {
  
  {
    SELECT DISTINCT ?item WHERE {
      ?item p:P231 ?statement0.
      ?statement0 (ps:P231) "67-64-1".
    }
  }
  OPTIONAL { ?item wdt:P2101 ?melting_point. }
  OPTIONAL { ?item wdt:P2102 ?boiling_point. }
  OPTIONAL { ?item wdt:P2054 ?density. }
  OPTIONAL { ?item wdt:P2067 ?mass. }
  SERVICE wikibase:label { bd:serviceParam wikibase:language "de". }
}

The problem is that I don't manage to get only temperatures in Degree Celsius but also Fahrenheit

1 Answers

This is a very interesting question, as WikiData offers plenty of tools to disambiguate -- this is why it's so powerful. But these tools come with some learning that the user needs to do before using them.

Before starting, let me make three points about your query:

1-You don't actually need an inner query to select acetone, as you would in SQL. This is one of the reasons why SPARQL is so great compared to SQL -- you don't have to navigate an endless field of keys but your data is still 'normalised'.

2-You don't need the ?statement0 variable, as this is not used to disambiguate. You can just use the wdt:P231 property directly links acetone with its CAS registry number.

3-Since you do need to disambiguate the values of the physical quantities associated with acetone, you will need to go through a disambiguation statement.

Now, here is a query that works:

SELECT DISTINCT ?itemLabel ?melting_point ?boiling_point ?density ?mass 
WHERE {
  ?item wdt:P231 "67-64-1".
  OPTIONAL {
  ?item p:P2101 ?ps1 .
  ?ps1 ps:P2101 ?melting_point;
      psv:P2101/wikibase:quantityUnit/wdt:P31/wdt:P279* wd:Q61610698
  }
  OPTIONAL {
  ?item p:P2102 ?ps2 .
  ?ps2 ps:P2102 ?boiling_point;
      psv:P2102/wikibase:quantityUnit/wdt:P31/wdt:P279* wd:Q61610698
  }
  OPTIONAL {
  ?item p:P2054 ?ps3 .
  ?ps3 ps:P2054 ?density;
      psv:P2054/wikibase:quantityUnit/wdt:P31/wdt:P279* wd:Q61610698
  }
  OPTIONAL {
  ?item p:P2067 ?ps4 .
  ?ps4 ps:P2067 ?mass;
      psv:P2067/wikibase:quantityUnit/wdt:P31/wdt:P279* wd:Q61610698
  }
  SERVICE wikibase:label { bd:serviceParam wikibase:language "de". }
}

To begin with, I removed the inner query and the statement mentioned in §1 and §2 above.

Then, I retrieve the statement that talks about melting point by using the p:P2101/ps:P2101 combination. This will allows me to distinguish between Celsius and Fahrenheit values.

Now, since we have multiple physical quantities to look for (i.e. not just temperature), and we want these to be SI, we can use a property path (see below for explanation) to restrict the values that we return as being SI (as opposed to returning Celsius, kg/m^3, kg specifically and individually, although this would be perfectly valid too, just more complex).

For reference, a property path is just a way to shorten a query so:

SELECT ?person ?grandparent
WHERE {
 ?person :hasParent ?parent .
 ?parent :hasParent ?grandparent .
}

can be shortened to:

SELECT ?person ?grandparent
WHERE {
 ?person :hasParent/:hasParent ?grandparent .
    }

Now, let's get back to the melting point being returned in Celsius and Fahrenheit. The two statements that give us different units use a psv:P2101 property to tell us more about the value mentioned in the statement. From this we can use the wikibase:quantityUnit property to determine the unit.

We will then want to make sure the unit is a SI unit or any subclass thereof. So wdt:P31 tells us that the unit is "an instance of" some class, and wdt:P279* wd:Q61610698 (wdt:P279* is another property path) tells us that the class is either the class of SI units (wd:Q61610698 = SI units), or a direct or indirect subclass of SI units.

I added a picture of what the data looks like (although confusingly there are two Celsius melting points for acetone for some reason. the data, visualised

Related