fils/oihBook huggingface dataset:
Documents#
About#
Documents: These include datasets, reports or other documents
See also
For OIH the focus is on generic documents which can scope reports, data and other resources.
In those cases where the resources being described are of type Dataset you may wish to review
patterns developed for GeoScience Datasets by the ESIP
Science on Schema community.
Creative works (documents)#
Documents will include maps, reports,
guidance and other creative works.  Due to this OIH will focus on a generic example
of schema.org/CreativeWork and then provide examples
for more focused creative work examples.
 1{
 2  "@context": {
 3    "@vocab": "https://schema.org/"
 4  },
 5  "@type": "CreativeWork",
 6  "@id": "https://example.org/id/XYZ",
 7  "name": "Name or title of the document",
 8  "description": "Description of the creative work to aid in searching",
 9  "url": "https://www.sample-data-repository.org/creativework/report.pdf",
10  "contributor": {
11    "@type": "Organization",
12    "@id": "http://www.foo.org/orgID",
13    "legalName": "Some Institute"
14  },
15  "author": {
14  },
15  "author": {
16    "@id": "https://www.sample-data-repository.org/person/51317",
17    "@type": "Person",
18    "name": "Dr Uta Passow",
19    "givenName": "Uta",
20    "familyName": "Passow",
21    "url": "https://www.sample-data-repository.org/person/51317"
22  },
23  "identifier": {
24    "@id": "https://doi.org/10.5066/F7VX0DMQ",
25    "@type": "PropertyValue",
26    "propertyID": "https://registry.identifiers.org/registry/doi",
27    "value": "doi:10.5066/F7VX0DMQ",
28    "url": "https://doi.org/10.5066/F7VX0DMQ"
29  },
30  "keywords": {
31    "@type": "DefinedTerm",
32    "inDefinedTermSet": {
33      "@type": "DefinedTermSet",
34      "name": "Name of the set",
35      "description": "Description of the set",
36      "url": "url for the set"
37    },
36      "url": "url for the set"
37    },
38    "termCode": "A code that identifies this DefinedTerm within a DefinedTermSet"
39  },
40  "provider": {
41    "@id": "https://www.repositoryB.org",
42    "@type": "Organization",
43    "legalName": "Sample Data Repository Office",
44    "name": "SDRO",
45    "sameAs": "http://www.re3data.org/repository/r3dxxxxxxxxx",
46    "url": "https://www.sample-data-repository.org"
47  },
48  "license": "http://spdx.org/licenses/CC0-1.0",
49  "publisher": {
50    "@id": "https://www.publishingrus.org",
51    "@type": "Organization",
52    "legalName": "Some Institute"
53  }
54}
import json
from pyld import jsonld
import os, sys
currentdir = os.path.dirname(os.path.abspath(''))
parentdir = os.path.dirname(currentdir)
sys.path.insert(0, parentdir)
from lib import jbutils
with open("../../../odis-in/dataGraphs/thematics/docs/graphs/creativework.json") as dgraph:
    doc = json.load(dgraph)
context = {
doc = json.load(dgraph)
context = {
    "@vocab": "https://schema.org/",
}
compacted = jsonld.compact(doc, context)
jbutils.show_graph(compacted)
Details: Indentifier#
For each profile there are a few key elements we need to know about.  One
key element is what the authoritative reference or canonical identifier is for
a resource.
import json
from pyld import jsonld
import os, sys
import urllib
currentdir = os.path.dirname(os.path.abspath(''))
parentdir = os.path.dirname(currentdir)
sys.path.insert(0, parentdir)
with open("../../../odis-in/dataGraphs/thematics/docs/graphs/creativework.json") as dgraph:
    doc = json.load(dgraph)
frame = {
  "@context": {"@vocab": "https://schema.org/"},
frame = {
  "@context": {"@vocab": "https://schema.org/"},
  "@explicit": "true",
  "@requireAll": "true",
  "@type":     "CreativeWork",
  "identifier": ""
}
context = {
    "@vocab": "https://schema.org/",
}
compacted = jsonld.compact(doc, context)
framed = jsonld.frame(compacted, frame)
jd = json.dumps(framed, indent=4)
print(jd)
jbutils.show_graph(framed)
{
    "@context": {
        "@vocab": "https://schema.org/"
    },
    "@id": "https://example.org/id/XYZ",
    "@type": "CreativeWork",
    "identifier": {
        "@id": "https://doi.org/10.5066/F7VX0DMQ",
"@type": "PropertyValue",
        "propertyID": "https://registry.identifiers.org/registry/doi",
        "url": "https://doi.org/10.5066/F7VX0DMQ",
        "value": "doi:10.5066/F7VX0DMQ"
    }
}
Publisher and provider#
Our JSON-LD documents are graphs that can use framing to subset.  In this case
we can look closer at the provider and publisher properties, which are both
of type Organization.
import json
from rdflib.extras.external_graph_libs import rdflib_to_networkx_multidigraph
from rdflib.extras.external_graph_libs import rdflib_to_networkx_graph
from pyld import jsonld
import graphviz
import os, sys
currentdir = os.path.dirname(os.path.abspath(''))
parentdir = os.path.dirname(currentdir)
sys.path.insert(0, parentdir)
from lib import jbutils
with open("../../../odis-in/dataGraphs/thematics/docs/graphs/creativework.json") as dgraph:
    doc = json.load(dgraph)
frame = {
  "@context": {"@vocab": "https://schema.org/"},
  "@explicit": "true",
  "@type":     "CreativeWork",
  "provider": {},
  "publisher": {}
"provider": {},
  "publisher": {}
}
context = {
    "@vocab": "https://schema.org/",
}
compacted = jsonld.compact(doc, context)
framed = jsonld.frame(compacted, frame)
jd = json.dumps(framed, indent=4)
print(jd)
jbutils.show_graph(framed)
{
    "@context": {
        "@vocab": "https://schema.org/"
    },
    "@id": "https://example.org/id/XYZ",
    "@type": "CreativeWork",
    "provider": {
        "@id": "https://www.repositoryB.org",
        "@type": "Organization",
        "legalName": "Sample Data Repository Office",
        "name": "SDRO",
        "sameAs": "http://www.re3data.org/repository/r3dxxxxxxxxx",
"url": "https://www.sample-data-repository.org"
    },
    "publisher": {
        "@id": "https://www.publishingrus.org",
        "@type": "Organization",
        "legalName": "Some Institute"
    }
}
Author type Person#
Our JSON-LD documents are graphs that can use framing to subset.  In this
case we can look closer at the author property which points to a type Person.
import json
from rdflib.extras.external_graph_libs import rdflib_to_networkx_multidigraph
from rdflib.extras.external_graph_libs import rdflib_to_networkx_graph
from pyld import jsonld
import graphviz
import os, sys
currentdir = os.path.dirname(os.path.abspath(''))
parentdir = os.path.dirname(currentdir)
sys.path.insert(0, parentdir)
from lib import jbutils
with open("../../../odis-in/dataGraphs/thematics/docs/graphs/creativework.json") as dgraph:
    doc = json.load(dgraph)
frame = {
  "@context": {"@vocab": "https://schema.org/"},
  "@explicit": "true",
  "@type":     "CreativeWork",
  "author": ""
}
context = {
    "@vocab": "https://schema.org/",
}
}
context = {
    "@vocab": "https://schema.org/",
}
compacted = jsonld.compact(doc, context)
framed = jsonld.frame(compacted, frame)
jd = json.dumps(framed, indent=4)
print(jd)
jbutils.show_graph(framed)
{
    "@context": {
        "@vocab": "https://schema.org/"
    },
    "@id": "https://example.org/id/XYZ",
    "@type": "CreativeWork",
    "author": {
        "@id": "https://www.sample-data-repository.org/person/51317",
        "@type": "Person",
        "familyName": "Passow",
        "givenName": "Uta",
        "name": "Dr Uta Passow",
"name": "Dr Uta Passow",
        "url": "https://www.sample-data-repository.org/person/51317"
    }
}
License#
import json
from rdflib.extras.external_graph_libs import rdflib_to_networkx_multidigraph
from rdflib.extras.external_graph_libs import rdflib_to_networkx_graph
from pyld import jsonld
import graphviz
import os, sys
currentdir = os.path.dirname(os.path.abspath(''))
parentdir = os.path.dirname(currentdir)
sys.path.insert(0, parentdir)
from lib import jbutils
with open("../../../odis-in/dataGraphs/thematics/docs/graphs/creativework.json") as dgraph:
    doc = json.load(dgraph)
frame = {
  "@context": {"@vocab": "https://schema.org/"},
  "@explicit": "true",
  "@type":     "CreativeWork",
  "license": {}
}
context = {
    "@vocab": "https://schema.org/",
}
compacted = jsonld.compact(doc, context)
framed = jsonld.frame(compacted, frame)
jd = json.dumps(framed, indent=4)
print(jd)
jbutils.show_graph(framed)
print(jd)
jbutils.show_graph(framed)
{
    "@context": {
        "@vocab": "https://schema.org/"
    },
    "@id": "https://example.org/id/XYZ",
    "@type": "CreativeWork",
    "license": "http://spdx.org/licenses/CC0-1.0"
}
License as URL#
{
  "@context": "https://schema.org/",
  "license": "https://creativecommons.org/licenses/by/4.0/"
}
License as CreativeWork#
{
  "@context": "https://schema.org/",
  "license": {
    "@type": "CreativeWork",
    "name": "Creative Commons Attribution 4.0",
    "url": "https://creativecommons.org/licenses/by/4.0/"
  }
}
License as SPDX URL#
}
}
License as SPDX URL#
Use a simple URL
SPDX creates URLs for many licenses including those that don’t have URLs
From a source that harvesters can rely on (e.g. use URL to lookup more information about the license)
{
  "@context": "https://schema.org/",
  "license": "https://spdx.org/licenses/CC-BY-4.0"
}
OR, include both the SPDX and the Creative Commons URLs in an array:
{
  "@context": "https://schema.org/",
  "license": ["https://spdx.org/licenses/CC-BY-4.0", "https://creativecommons.org/licenses/by/4.0/"]
}
References#
For dataset we can use SOS Dataset
OBPS group is using JericoS3 API (ref:  https://www.jerico-ri.eu/)
Traditional knowledge points here
sounds like they use dspace
For other document these are likely going to be some schema:CretiveWork with there being many subtypes we can explore.   See also here Adam Leadbetter’s work at Ocean best practices
This is a great start and perhaps helps to highlight why SHACL shapes are useful
https://irishmarineinstitute.github.io/erddap-lint/
https://irishmarineinstitute.github.io/erddap-lint/
https://github.com/earthcubearchitecture-project418/p419dcatservices/blob/master/CHORDS/DataFeed.jsonld
*EMODnet  (Coner Delaney)
ERDAP also
Are we talking links from schema.org that link to OGC and ERDAP services
Are these methods?
Sounds like may link to external metadata for interop they have developed in the community
NOAA connected as well
Interested in OGC assets
ERDAP data platform
Validation#
About#
This section contains some initial work on developing some validation
approaches for OIH.  The focus initially is not on validating approaches with
the full publishing guidance.  Rather the focuses is on the the “info hub” as a
search application and develops validation to support that.
Well Formed JSON-LD#
SDO Validator
Structured data Linter
JSON-LD Playground
Shape Validation#
Initial approach:
Develop a base SHACL document that assess a data graph based on elements needed to support search
SHACL
Leverage SHACL Playground
RDFShape at https://rdfshape.weso.es/ and https://rdfshape.herokuapp.com/
To support this will need an initial data graph to work with.  The type is not
important.  All types will need to satisfy the search needs.
Examples of these needs include:
Have an @id
Have a name
Have a description
Have a Distribution and contentURL
Reference authority
SPARQL#
Introduction#
This notebook will go over some concepts for querying the graph that is generated by the Ocean InfoHub.
The product of the publishing and indexing process is a graph.  This graph follows the W3C Resource Description
Framework (RDF).   RDF is a data model that can be represented in various text encodings.  Among these
is the JSON-LD format we have been using in the publishing process.
Not all graph libraries and databases support JSON-LD yet, so as part of the aggregation process one step
is to simply translate this format into a format that is supported by the graph database.   Typically we
use something n-triples or turtle for this.  There are many tools for translating RDF from one format to another.
We can load the graphs into a graph database and this was documented in the Aggregation section, so we will not
revisit it here.    In this notebook, we will load the graph into a local graph database in the Python library
that also supports the same query language our graph databases use.  This will make the demonstration easier and
allow you to download and run this notebook on your own machine if you wish.  The query language we will use
is SPARQL.
SPARQL#
SPARQL (SPARQL Protocol and RDF Query Language) is the query language that is used to query RDF graphs.  It
is a W3C recommendation documented at SPARQL 1.1 Query Language.
Load a Graph#
For this demonstration we will be using Python to load the graph and do our queries.  However, there are many
languages and libraries for working with graphs and SPARQL.   Also, you can often query a graph using web UIs
infront of your graph database or even with simple direct HTTP requests.  Examples of some of these can be
found in other sections of the OIH documentation.
import rdflib
g = rdflib.Graph()
g.parse("../tooling/notebooks/data/oceanexperts_graph.ttl", format="ttl")
<Graph identifier=N9656cde6c1054a4ba02f9bbcd09d17a8 (<class 'rdflib.graph.Graph'>)>
Let’s define our first query#
This is a simple query that will return all the triples in the graph.   Recall an RDF graph is make of triples defined by a subject, predicate and object.  You can review RDF at the W3C RDF Primer (https://www.w3.org/TR/rdf11-concepts/).  SPARQL allows us to do a type of pattern matching on the graph by defining a pattern we a relooking for.
Here we define ?s ?p ?o as the pattern we are looking for.  The ? is a variable that can be used to match any value.  In this case, we are looking for all the triples in the graph.  We have used s, p and o to as simple names for our subject, predicate, object elements of the RDF triple.
Since this would match ALL the values in the graph, which would be a lot, we have added a LIMIT option to reduce the number of resutls returned.
You could also try these queries at: https://oceans.collaborium.io/sparql.html
s1 = """
    SELECT ?s ?p ?o
    WHERE {
        ?s ?p ?o .
    }
    LIMIT 3
"""
Run the query#
We will run this query, and print out the results
from icecream import ic
for row in g.query(s1):
    ic(row.asdict())
ic| row.asdict(): {'o': rdflib.term.Literal('2014-06-02'),
                   'p': rdflib.term.URIRef('https://schema.org/startDate'),
                   's': rdflib.term.BNode('n0dfe00a0174f48a7b9fb702b5f5b4ecdb236')}
ic| row.asdict(): {'o': rdflib.term.Literal(' Copenhagen Denmark '),
                   'p': rdflib.term.URIRef('https://schema.org/address'),
                   's': rdflib.term.BNode('n0dfe00a0174f48a7b9fb702b5f5b4ecdb496')}
ic| row.asdict(): {'o': rdflib.term.Literal('Introduction to Ocean Data Management for Students of the Environment Group II'),
                   'p': rdflib.term.URIRef('https://schema.org/name'),
                   's': rdflib.term.BNode('n0dfe00a0174f48a7b9fb702b5f5b4ecdb1745')}
Nicer formatting#
We can do a bit of formatting to see our results in a nicer way.
for row in g.query(s1):
    s = row["s"].n3()
    p = row["p"].n3()
    o = row["o"].n3()
    ic(s, p, o)
ic| s: '_:n0dfe00a0174f48a7b9fb702b5f5b4ecdb236'
    p: '<https://schema.org/startDate>'
    o: '"2014-06-02"'
o: '"2014-06-02"'
ic| s: '_:n0dfe00a0174f48a7b9fb702b5f5b4ecdb496'
    p: '<https://schema.org/address>'
    o: '" Copenhagen Denmark "'
ic| s: '_:n0dfe00a0174f48a7b9fb702b5f5b4ecdb1745'
    p: '<https://schema.org/name>'
    o: ('"Introduction to Ocean Data Management for Students of the Environment Group '
        'II"')
KGLab#
As mentioned, this intro is based on the nice work done by KGLab (https://derwen.ai/docs/kgl/) both in their library and documentation.  We wll import kglab here and take advantage of some of their nice features.  In particular some nice functioons to load our graph and query it with results into a Dataframe.
import kglab
namespaces = {
    "schema":  "https://schema.org/",
    }
kg = kglab.KnowledgeGraph(
    name = "Demonstration Graph",
    base_uri = "https://oceaninfohub.org/id/",
    namespaces = namespaces,
    )
namespaces = namespaces,
    )
kg.load_rdf("../tooling/notebooks/data/oceanexperts_graph.ttl")
/home/fils/.conda/envs/kglab/lib/python3.8/site-packages/owlrl/__init__.py:177: UserWarning: Code: dateTimeStamp is not defined in namespace XSD
  from . import DatatypeHandling, Closure
/home/fils/.conda/envs/kglab/lib/python3.8/site-packages/owlrl/RDFSClosure.py:40: UserWarning: Code: dateTimeStamp is not defined in namespace XSD
  from owlrl.AxiomaticTriples import RDFS_Axiomatic_Triples, RDFS_D_Axiomatic_Triples
/home/fils/.conda/envs/kglab/lib/python3.8/site-packages/owlrl/RDFSClosure.py:40: UserWarning: Code: length is not defined in namespace XSD
  from owlrl.AxiomaticTriples import RDFS_Axiomatic_Triples, RDFS_D_Axiomatic_Triples
/home/fils/.conda/envs/kglab/lib/python3.8/site-packages/owlrl/RDFSClosure.py:40: UserWarning: Code: maxExclusive is not defined in namespace XSD
  from owlrl.AxiomaticTriples import RDFS_Axiomatic_Triples, RDFS_D_Axiomatic_Triples
/home/fils/.conda/envs/kglab/lib/python3.8/site-packages/owlrl/RDFSClosure.py:40: UserWarning: Code: maxInclusive is not defined in namespace XSD
  from owlrl.AxiomaticTriples import RDFS_Axiomatic_Triples, RDFS_D_Axiomatic_Triples
/home/fils/.conda/envs/kglab/lib/python3.8/site-packages/owlrl/RDFSClosure.py:40: UserWarning: Code: maxLength is not defined in namespace XSD
  from owlrl.AxiomaticTriples import RDFS_Axiomatic_Triples, RDFS_D_Axiomatic_Triples
/home/fils/.conda/envs/kglab/lib/python3.8/site-packages/owlrl/RDFSClosure.py:40: UserWarning: Code: minExclusive is not defined in namespace XSD
  from owlrl.AxiomaticTriples import RDFS_Axiomatic_Triples, RDFS_D_Axiomatic_Triples
/home/fils/.conda/envs/kglab/lib/python3.8/site-packages/owlrl/RDFSClosure.py:40: UserWarning: Code: minInclusive is not defined in namespace XSD
  from owlrl.AxiomaticTriples import RDFS_Axiomatic_Triples, RDFS_D_Axiomatic_Triples
/home/fils/.conda/envs/kglab/lib/python3.8/site-packages/owlrl/RDFSClosure.py:40: UserWarning: Code: minLength is not defined in namespace XSD
  from owlrl.AxiomaticTriples import RDFS_Axiomatic_Triples, RDFS_D_Axiomatic_Triples
/home/fils/.conda/envs/kglab/lib/python3.8/site-packages/owlrl/RDFSClosure.py:40: UserWarning: Code: pattern is not defined in namespace XSD
  from owlrl.AxiomaticTriples import RDFS_Axiomatic_Triples, RDFS_D_Axiomatic_Triples
/home/fils/.conda/envs/kglab/lib/python3.8/site-packages/owlrl/OWLRL.py:53: UserWarning: Code: dateTimeStamp is not defined in namespace XSD
  from .XsdDatatypes import OWL_RL_Datatypes, OWL_Datatype_Subsumptions
/home/fils/.conda/envs/kglab/lib/python3.8/site-packages/owlrl/OWLRLExtras.py:64: UserWarning: Code: dateTimeStamp is not defined in namespace XSD
  from .RestrictedDatatype import extract_faceted_datatypes
<kglab.kglab.KnowledgeGraph at 0x7f470860bf40>
PREFIX#
PREFIX#
Let’s do another query.  We will use the PREFIX keyword to define a prefix for the namespace.  This is a way to leverage namespace in our query.  Note the use of schema:name vs the https://schema.org/location.  The latter is a URI and the former is a prefix.  The prefix is defined in the PREFIX keyword.   The schema:name is the name of the property that we are querying, the prefix can expand it to a URI.  The https://schema.org/location is the URI of the property directly, without use of a prefix.   Both work, the prefix can simply make life easier for you and also help avoid hard to find typos where you may miss-type a URI.
Let’s do a query to see all the location names in our group for training.
s2 = """
PREFIX schema: <https://schema.org/>
SELECT DISTINCT ?locname
  WHERE {
      ?s rdf:type <https://schema.org/Course> .
      ?s  <https://schema.org/location> ?location .
      ?location schema:name ?locname .
  }
  """
import pandas as pd
pd.set_option("max_rows", None)
df = kg.query_as_df(s2)
df.head(5)
locname
0
Lima Peru
1
Qingdao China
2
Russia
3
0
Lima Peru
1
Qingdao China
2
Russia
3
Playa del Secreto Puerto Morelos, Mexico
4
University of Ghent  Ghent Belgium
Location Counts#
The above is nice, but it doesn’t tell us much about the number of events in each location. We can modify our query to do this.  We can leverage the COUNT and GROUP BY capacity of SPARQL to do this.  We can then add in ORDER BY to sort the results.
s3 = """
SELECT DISTINCT ?locname (COUNT(?locname) AS ?count)
  WHERE {
      ?s rdf:type <https://schema.org/Course> .
      ?s  <https://schema.org/location> ?location .
      ?location <https://schema.org/name> ?locname .
  }
  GROUP BY ?locname
  ORDER BY DESC(?count)
  """
import pandas as pd
pd.set_option("max_rows", None)
df = kg.query_as_df(s3)
df.head(5)
locname
count
0
UNESCO/IOC Project Office for IODE Wandelaark...
28
1
Russia
27
2
UNESCO/IOC Project Office for IODE Wandelaark...
22
3
Wandelaarkaai 7 8400 Oostende Belgium
13
4
Wandelaarkaai 7 8400 Oostende Belgium
13
4
Belgium
10
FILTER#
Graphs are great for showing relations between objects but our approaches to searching or selecting data can often leverage pattern matching on text strings.  We do have some tools in SPARQL for this in the form of FILTER.  We can use regex pattern in the FILTER to match text.  Let’s use this to find all the locations with “Peru” in the name.
In the following we will do a simple FILTER with a regular expression, but you can also do things like:
SELECT DISTINCT ?s 
  WHERE {
      ?s rdf:type <https://schema.org/Course> .
      FILTER NOT EXISTS { ?s  <https://schema.org/hasCourseInstance> ?instance . }  
  }
which in a SPARQL query would require that a hasCourseInstance property is not defined for the Course.  That is, Courses that have had no instances made yet.
s4 = """
SELECT DISTINCT ?locname (COUNT(?locname) AS ?count)
  WHERE {
      ?s rdf:type <https://schema.org/Course> .
      ?s  <https://schema.org/location> ?location .
      ?location <https://schema.org/name> ?locname .
?location <https://schema.org/name> ?locname .
      FILTER regex(?locname, ".Peru.", "i") .
  }
  GROUP BY ?locname
  """
import pandas as pd
pd.set_option("max_rows", None)
df4 = kg.query_as_df(s4)
df4.head(5)
locname
count
0
Lima Peru
1
1
Dirección Hidrografía y Navegación de la Arma...
1
2
Hotel Palmetto Lima Perú Peru
1
PERU#
So we see we have three entries in our graph that have Peru in the name.  This is where connecting our group to a shared concept of what Peru is like the WikiData entry for Peru at https://www.wikidata.org/wiki/Q419 would help.  That’s a topic for another day.
Dates#
Let’s look at the dates that are available in the graph.
s5 = """
SELECT DISTINCT ?sdate (COUNT(?sdate) AS ?count)
  WHERE {
      ?s rdf:type <https://schema.org/Course> .
      ?s  <https://schema.org/hasCourseInstance> ?instance .
      ?instance  <https://schema.org/startDate> ?sdate .
  }
  GROUP BY ?sdate
  """
}
  GROUP BY ?sdate
  """
import pandas as pd
pd.set_option("max_rows", None)
df4 = kg.query_as_df(s5)
df4.head(5) # show some results
sdate
count
0
2020-06-08
1
1
2011-05-03
1
2
2012-07-16
1
3
2007-07-12
1
4
2019-04-02
1
A bit of Pandas#
Here we will mix in a bit of Pandas to convert our dates to Pandas dates, group and plot.  This is not
SPARQL but rather just some post processing in Pandas.  It does still give us an idea of some of the
information we can extract from our graph.
Also, when the graph is composed of multiple source we can still conduct the same search across
a shared concept like https://schema.org/Course with CourseInstance connected to a date via startDate.
This shared approach by Ocean InfoHub is developed to support the shared data and integration
goals among the participants.
df4['count'] = df4["count"].astype(int) # convert count c to int
df4pd = df4.to_pandas()  # convert cudf dataframe to pandas dataframe