Compare commits

..

9 Commits

Author SHA1 Message Date
Sam 67f1bb2c80 Add data-downloads to navbarlinks 2024-08-13 18:58:13 +01:00
Sam bbd906de4b Small modifications to article 2024-08-13 18:57:54 +01:00
Sam 83d458f39d Add content to front page 2024-08-13 18:57:32 +01:00
Sam 0e5119c6fd Add button css 2024-08-13 18:57:16 +01:00
Sam 032b1616dc Add data-downloads page and content 2024-08-13 18:56:59 +01:00
Sam 198ab2a1f8 Modify backend app
- add download route
- combine chart endpoints to single get_json route
2024-08-13 18:55:20 +01:00
Sam 1ef277edc5 Change chart endpoints to use get_json route 2024-08-13 18:53:59 +01:00
Sam ed011152b2 Create download-data shortcode 2024-08-13 18:52:51 +01:00
Sam 69158336bf Data downloads 2024-08-13 16:07:50 +01:00
12 changed files with 85 additions and 43 deletions

View File

@ -1,10 +1,12 @@
from flask import Flask, request, json, Response from flask import Flask, jsonify, request, json, Response, send_from_directory, abort
from flask_cors import CORS from flask_cors import CORS
import orjson import orjson, os
app = Flask(__name__) app = Flask(__name__)
CORS(app) CORS(app)
FILES_DIRECTORY = '../data/'
@app.route('/bitcoin_business_growth_by_country', methods=['GET']) @app.route('/bitcoin_business_growth_by_country', methods=['GET'])
def business_growth(): def business_growth():
# Parse args from request # Parse args from request
@ -36,45 +38,26 @@ def business_growth():
# Return json # Return json
return Response(json.dumps(sorted_data), mimetype='application/json') return Response(json.dumps(sorted_data), mimetype='application/json')
@app.route('/price', methods=['GET']) @app.route('/get_json/<filename>', methods=['GET'])
def price(): def get_json(filename):
file_path = os.path.join(FILES_DIRECTORY, filename)
if not os.path.isfile(file_path):
abort(404)
# Open json locally with open(file_path, 'r') as file:
with open('../data/final__price.json', 'rb') as f: data = json.load(file)
data = orjson.loads(f.read())
# Return json return jsonify(data)
return Response(json.dumps(data), mimetype='application/json')
@app.route('/miner_rewards', methods=['GET']) @app.route('/download/<filename>', methods=['GET'])
def miner_rewards(): def download_file(filename):
try:
return send_from_directory(FILES_DIRECTORY, filename, as_attachment=True)
except FileNotFoundError:
abort(404)
# Open json locally if __name__ == '__main__':
with open('../data/final__miner_rewards.json', 'rb') as f: app.run(debug=True)
data = orjson.loads(f.read())
# Return json
return Response(json.dumps(data), mimetype='application/json')
@app.route('/hashrate', methods=['GET'])
def hashrate():
# Open json locally
with open('../data/dev/final__hashrate.json', 'rb') as f:
data = orjson.loads(f.read())
# Return json
return Response(json.dumps(data), mimetype='application/json')
@app.route('/feerates', methods=['GET'])
def feerates():
# Open json locally
with open('../data/final__feerate_percentiles.json', 'rb') as f:
data = orjson.loads(f.read())
# Return json
return Response(json.dumps(data), mimetype='application/json')
if __name__ == '__main__': if __name__ == '__main__':
app.run() app.run()

View File

@ -4,7 +4,11 @@ toc: False
# Grounded Insights from Open Data # Grounded Insights from Open Data
Data is often chaotic and dispersed. This requires us to build solid data pipelines to efficiently transform data into a unified and useful format. This site is currently under construction. The direction I intend for this site to take is as a place to publish analytical insights derived from open data. I have a page called [Data Lab](/data-lab) where I publish interactive analytical dashboards, a blog to publish tutorials and thoughts on various related topics, and a [data downloads](/data-download) page for data access.
I'm interested in a broad set of topics such as Linux, analytics and data engineering, GIS and bitcoin. So expect to see content related to these topics published on this site.
I strongly believe in the philosophy of [Free Software](https://www.gnu.org/philosophy/free-sw.html) and [Open Data](https://en.wikipedia.org/wiki/Open_data). Therefore, all material on this site is released into the public domain unless otherwise specified. For more information, see [here](/license).
### Explore Based Data ### Explore Based Data

View File

@ -24,7 +24,7 @@ The final image looks like this:
It's possible to download the entire SRTM (Shuttle Radar Topography Mission) satellite imagery dataset and insert it into a Postgres database for personal use. This can be helpful for if you need global elevation data for your analysis and don't want to be limited by third-parties APIs. It's possible to download the entire SRTM (Shuttle Radar Topography Mission) satellite imagery dataset and insert it into a Postgres database for personal use. This can be helpful for if you need global elevation data for your analysis and don't want to be limited by third-parties APIs.
The SRTM is a near-global dataset of elevation data with a resolution of 1-arc-second (30m). More information is available from [USGS](https://www.usgs.gov/centers/eros/science/usgs-eros-archive-digital-elevation-shuttle-radar-topography-mission-srtm?qt-science_center_objects=0#qt-science_center_objects). The SRTM is a near-global dataset of elevation data with a resolution of 1-arc-second (30m). More information is available from [USGS](https://www.usgs.gov/centers/eros/science/usgs-eros-archive-digital-elevation-shuttle-radar-topography-mission-srtm?qt-science_center_objects=0#qt-science_center_objects).
In this guide we will go through downloading the data, inserting it into a Postgres database with PostGIS, then querying the final result to create a DEM for any country or region. In this guide we will go through the process of downloading the data, inserting it into a Postgres database with PostGIS, then querying the final result to create a DEM for any country or region.
This guide assumes you are using Linux (this may also apply to other Unix like systems such as MacOS) and have a Postgres database with the PostGIS extension installed. More information on how to do this can be found on the [PostGIS](https://postgis.net/documentation/getting_started/) website. This guide assumes you are using Linux (this may also apply to other Unix like systems such as MacOS) and have a Postgres database with the PostGIS extension installed. More information on how to do this can be found on the [PostGIS](https://postgis.net/documentation/getting_started/) website.
@ -51,6 +51,8 @@ Next we can run the following command to download the rasters. This will take so
aws s3 cp s3://raster/SRTM_GL1/ . --recursive --endpoint-url https://opentopography.s3.sdsc.edu --no-sign-request aws s3 cp s3://raster/SRTM_GL1/ . --recursive --endpoint-url https://opentopography.s3.sdsc.edu --no-sign-request
{{</ highlight >}} {{</ highlight >}}
If you'd prefer to download specific rasters or rasters for a region instead, you can checkout this [website](https://dwtkns.com/srtm30m/).
## Using raster2pgsql to import raster tiles into PostGIS ## Using raster2pgsql to import raster tiles into PostGIS
Now we have the data downloaded on our system, we can import it into our database. Now we have the data downloaded on our system, we can import it into our database.
If we look inside the SRTM_GL1_srtm directory, we can see all of the 14280 raster files: If we look inside the SRTM_GL1_srtm directory, we can see all of the 14280 raster files:
@ -218,5 +220,7 @@ vacuum analyze "dem"."singapore_srtm";
Looks much better! Looks much better!
This DEM raster of Singapore is available for download from the downloads page [here](/data-downloads/singapore-srtm)
#### Citations #### Citations
NASA Shuttle Radar Topography Mission (SRTM)(2013). Shuttle Radar Topography Mission (SRTM) Global. Distributed by OpenTopography. https://doi.org/10.5069/G9445JDF. Accessed: 2024-08-06 NASA Shuttle Radar Topography Mission (SRTM)(2013). Shuttle Radar Topography Mission (SRTM) Global. Distributed by OpenTopography. https://doi.org/10.5069/G9445JDF. Accessed: 2024-08-06

View File

@ -0,0 +1,5 @@
---
title: "Data Downloads"
---
Data available for download

View File

@ -0,0 +1,17 @@
---
title: 'Singapore SRTM DEM (Data Download)'
date: 2024-08-06T12:15:44+01:00
author:
name: "Sam Chance"
header_image: '/pics/blog/batch-import-postgis-rasters/singapore-final.webp'
summary: "Download the Shuttle Radar Topography Mission (SRTM) Digital Elevation Model (DEM) of Singapore"
toc: false
tags: ["QGIS", "SRTM", "DEM", "Raster", "download"]
---
{{< figure src="/pics/blog/batch-import-postgis-rasters/singapore-final.webp" width="300">}}
Download the Digital Elevation Model featured in [this](/blog/batch-import-postgis-rasters/) blog.
{{< download-data src="http://localhost:5000/download/singapore-srtm-dem.tif" name="singapore-srtm-dem.tif" >}}
#### Citations
NASA Shuttle Radar Topography Mission (SRTM)(2013). Shuttle Radar Topography Mission (SRTM) Global. Distributed by OpenTopography. https://doi.org/10.5069/G9445JDF. Accessed: 2024-08-06

View File

@ -5,6 +5,7 @@
<a href="#" class="dropbtn">Projects</a> <a href="#" class="dropbtn">Projects</a>
<div class="navbar-link-dropdown-content"> <div class="navbar-link-dropdown-content">
<a href="/data-lab">Data Lab</a> <a href="/data-lab">Data Lab</a>
<a href="/data-downloads">Data Downloads</a>
<a href="https://semitamaps.com">Map Printing</a> <a href="https://semitamaps.com">Map Printing</a>
</div> </div>
</li> </li>

View File

@ -0,0 +1,21 @@
<button class="download-button" onclick="downloadFile('{{ .Get "src" }}', '{{ .Get "name" }}')">
Download
</button>
<script>
async function downloadFile(url, name) {
try {
const response = await fetch(url);
const blob = await response.blob();
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = name;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
} catch (error) {
console.error('Error downloading the file:', error);
}
}
</script>

View File

@ -303,3 +303,7 @@ ol {
margin-bottom: 1rem; margin-bottom: 1rem;
font-size: 22px; font-size: 22px;
} }
.download-button {
padding: 10px;
}

View File

@ -3,7 +3,7 @@ const myChart = echarts.init(document.getElementById("chart"));
async function fetchDataForChart() { async function fetchDataForChart() {
try { try {
const apiEndpoint = "https://api.bitlab21.com/price"; const apiEndpoint = "https://api.bitlab21.com/get_json/final__price.json";
const response = await fetch(apiEndpoint); const response = await fetch(apiEndpoint);
if (!response.ok) { if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`); throw new Error(`HTTP error! status: ${response.status}`);

View File

@ -3,7 +3,8 @@ const myChart = echarts.init(document.getElementById("chart"));
async function fetchDataForChart() { async function fetchDataForChart() {
try { try {
const apiEndpoint = "https://api.bitlab21.com/feerates"; const apiEndpoint =
"https://api.bitlab21.com/get_json/final__feerate_percentiles.json";
const response = await fetch(apiEndpoint); const response = await fetch(apiEndpoint);
if (!response.ok) { if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`); throw new Error(`HTTP error! status: ${response.status}`);

View File

@ -3,7 +3,8 @@ const myChart = echarts.init(document.getElementById("chart"));
async function fetchDataForChart() { async function fetchDataForChart() {
try { try {
const apiEndpoint = "https://api.bitlab21.com/hashrate"; const apiEndpoint =
"https://api.bitlab21.com/get_json/final__hashrate.json";
const response = await fetch(apiEndpoint); const response = await fetch(apiEndpoint);
if (!response.ok) { if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`); throw new Error(`HTTP error! status: ${response.status}`);

View File

@ -3,7 +3,8 @@ const myChart = echarts.init(document.getElementById("chart"));
async function fetchDataForChart() { async function fetchDataForChart() {
try { try {
const apiEndpoint = "https://api.bitlab21.com/miner_rewards"; const apiEndpoint =
"https://api.bitlab21.com/get_json/final__miner_rewards.json";
const response = await fetch(apiEndpoint); const response = await fetch(apiEndpoint);
if (!response.ok) { if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`); throw new Error(`HTTP error! status: ${response.status}`);