|
| 1 | +#!/usr/bin/env python3 |
| 2 | +# ============================================================================= |
| 3 | +# EARTHQUAKE EPICENTER LOCATION FROM SEISMIC INTENSITY - CONSTANTS (COLORS) |
| 4 | +# |
| 5 | +# Author: Miroslav HALLO, Kyoto University |
| 6 | +# E-mail: hallo.miroslav.2a@kyoto-u.ac.jp |
| 7 | +# Tested with: Python 3.12.3 |
| 8 | +# Description: Location of the earthquake epicenter and moment magnitude from |
| 9 | +# instrumental seismic intensity (historical or modern). |
| 10 | +# Japan: JMA Seismic Intensity Scale (Shindo), instrumental |
| 11 | +# prediction is following Morikawa and Fujiwara (2013). |
| 12 | +# Includes automatic Vs30 querying from J-SHIS derived |
| 13 | +# database for sites without Vs30 measurements. |
| 14 | +# USA: Modified Mercalli Intensity (MMI), instrumental prediction |
| 15 | +# by Atkinson et al. (2014) for western North America. |
| 16 | +# EU: European Macroseismic (EMS-98), instrumental prediction |
| 17 | +# by Bindi et al. (2011) and Faenza and Michelini (2010). |
| 18 | +# |
| 19 | +# Copyright (C) 2026 Kyoto University |
| 20 | +# |
| 21 | +# This program is published under the GNU General Public License (GNU GPL). |
| 22 | +# |
| 23 | +# This program is free software: you can modify it and/or redistribute it |
| 24 | +# or any derivative version under the terms of the GNU General Public |
| 25 | +# License as published by the Free Software Foundation, either version 3 |
| 26 | +# of the License, or (at your option) any later version. |
| 27 | +# |
| 28 | +# This code is distributed in the hope that it will be useful, but WITHOUT |
| 29 | +# ANY WARRANTY. We would like to kindly ask you to acknowledge the authors |
| 30 | +# and don't remove their names from the code. |
| 31 | +# |
| 32 | +# You should have received a copy of the GNU General Public License along |
| 33 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
| 34 | +# |
| 35 | +# ============================================================================= |
| 36 | + |
| 37 | +from types import SimpleNamespace |
| 38 | +from typing import List, Union, Optional |
| 39 | + |
| 40 | + |
| 41 | +# ============================================================================= |
| 42 | +# CONSTANTS |
| 43 | +# ============================================================================= |
| 44 | + |
| 45 | +# JMA intensity scale colors (RGB) |
| 46 | +JMA_COLORS = SimpleNamespace( |
| 47 | + INT_7=[153/255, 51/255, 153/255], |
| 48 | + INT_6P=[153/255, 0/255, 0/255], |
| 49 | + INT_6M=[255/255, 51/255, 0/255], |
| 50 | + INT_5P=[255/255, 140/255, 0/255], |
| 51 | + INT_5M=[255/255, 255/255, 0/255], |
| 52 | + INT_4=[255/255, 250/255, 205/255], |
| 53 | + INT_3=[58/255, 95/255, 205/255], |
| 54 | + INT_2=[135/255, 206/255, 250/255], |
| 55 | + INT_1=[200/255, 250/255, 255/255], |
| 56 | +) |
| 57 | + |
| 58 | +# Historical JMA intensity scale colors (RGB) |
| 59 | +JMA_COLORS_HIST = SimpleNamespace( |
| 60 | + INT_S=[0/255, 0/255, 128/255], |
| 61 | + INT_E=[58/255, 95/255, 205/255], |
| 62 | + INT_e=[135/255, 206/255, 250/255], |
| 63 | +) |
| 64 | + |
| 65 | +# USGS ShakeMap MMI colors (RGB) |
| 66 | +MMI_COLORS = SimpleNamespace( |
| 67 | + I=[1.0, 1.0, 1.0], |
| 68 | + II=[0.75, 0.85, 1.0], |
| 69 | + III=[0.63, 0.82, 1.0], |
| 70 | + IV=[0.5, 1.0, 1.0], |
| 71 | + V=[0.5, 1.0, 0.5], |
| 72 | + VI=[1.0, 1.0, 0.0], |
| 73 | + VII=[1.0, 0.67, 0.0], |
| 74 | + VIII=[1.0, 0.0, 0.0], |
| 75 | + IX=[0.75, 0.0, 0.0], |
| 76 | + X=[0.5, 0.0, 0.0], |
| 77 | +) |
| 78 | + |
| 79 | +# Other colors (RGB) |
| 80 | +OTHER_COLORS = SimpleNamespace( |
| 81 | + NAN=[0.8, 0.8, 0.8], |
| 82 | +) |
| 83 | + |
| 84 | +# Legend for JMA scale (standard) |
| 85 | +JMA_LEGEND = [ |
| 86 | + ("Int 7", JMA_COLORS.INT_7), |
| 87 | + ("Int 6+", JMA_COLORS.INT_6P), |
| 88 | + ("Int 6-", JMA_COLORS.INT_6M), |
| 89 | + ("Int 5+", JMA_COLORS.INT_5P), |
| 90 | + ("Int 5-", JMA_COLORS.INT_5M), |
| 91 | + ("Int 4", JMA_COLORS.INT_4), |
| 92 | + ("Int 3", JMA_COLORS.INT_3), |
| 93 | + ("Int 2", JMA_COLORS.INT_2), |
| 94 | + ("Int 1", JMA_COLORS.INT_1), |
| 95 | +] |
| 96 | + |
| 97 | +# Legend for JMA scale (historical) |
| 98 | +JMA_LEGEND_HIST = [ |
| 99 | + ("Int 7", JMA_COLORS.INT_7), |
| 100 | + ("Int 6+", JMA_COLORS.INT_6P), |
| 101 | + ("Int 6-", JMA_COLORS.INT_6M), |
| 102 | + ("Int 5+", JMA_COLORS.INT_5P), |
| 103 | + ("Int 5-", JMA_COLORS.INT_5M), |
| 104 | + ("Int 4", JMA_COLORS.INT_4), |
| 105 | + ("S (hist)", JMA_COLORS_HIST.INT_S), |
| 106 | + ("E (hist)", JMA_COLORS_HIST.INT_E), |
| 107 | + ("e (hist)", JMA_COLORS_HIST.INT_e), |
| 108 | +] |
| 109 | + |
| 110 | +# Legend for MMI/EMS-98 scale |
| 111 | +MMI_LEGEND = [ |
| 112 | + ("X+", MMI_COLORS.X), |
| 113 | + ("IX", MMI_COLORS.IX), |
| 114 | + ("VIII", MMI_COLORS.VIII), |
| 115 | + ("VII", MMI_COLORS.VII), |
| 116 | + ("VI", MMI_COLORS.VI), |
| 117 | + ("V", MMI_COLORS.V), |
| 118 | + ("IV", MMI_COLORS.IV), |
| 119 | + ("III", MMI_COLORS.III), |
| 120 | + ("II", MMI_COLORS.II), |
| 121 | + ("I", MMI_COLORS.I), |
| 122 | +] |
| 123 | + |
| 124 | + |
| 125 | +# ============================================================================= |
| 126 | +# FUNCTIONS |
| 127 | +# ============================================================================= |
| 128 | + |
| 129 | +# Get JMA intensity RGB color |
| 130 | +def get_jma_color(val: Union[float, int, str, None], |
| 131 | + note: Optional[str] = None) -> List[float]: |
| 132 | + """ |
| 133 | + Get RGB color for the JMA intensity, including historical scale e, E, S. |
| 134 | +
|
| 135 | + Args: |
| 136 | + val: JMA intensity value or None. |
| 137 | + note: Historical scale flag ('e', 'E', 'S') or None. |
| 138 | + Returns: |
| 139 | + List[float]: A list of 3 floats [R, G, B] in range 0.0 to 1.0. |
| 140 | + """ |
| 141 | + try: |
| 142 | + if val is None: |
| 143 | + return OTHER_COLORS.NAN |
| 144 | + |
| 145 | + v = float(val) |
| 146 | + if v != v: # NaN |
| 147 | + return OTHER_COLORS.NAN |
| 148 | + |
| 149 | + # JMA Shindo scale |
| 150 | + if v >= 6.5: |
| 151 | + color = JMA_COLORS.INT_7 |
| 152 | + elif v >= 6.0: |
| 153 | + color = JMA_COLORS.INT_6P |
| 154 | + elif v >= 5.5: |
| 155 | + color = JMA_COLORS.INT_6M |
| 156 | + elif v >= 5.0: |
| 157 | + color = JMA_COLORS.INT_5P |
| 158 | + elif v >= 4.5: |
| 159 | + color = JMA_COLORS.INT_5M |
| 160 | + elif v >= 3.5: |
| 161 | + color = JMA_COLORS.INT_4 |
| 162 | + elif v >= 2.5: |
| 163 | + color = JMA_COLORS.INT_3 |
| 164 | + elif v >= 1.5: |
| 165 | + color = JMA_COLORS.INT_2 |
| 166 | + else: |
| 167 | + color = JMA_COLORS.INT_1 |
| 168 | + |
| 169 | + # Historical scale override |
| 170 | + if note: |
| 171 | + note_clean = str(note).strip() |
| 172 | + if note_clean == 'e': |
| 173 | + color = JMA_COLORS_HIST.INT_e |
| 174 | + elif note_clean == 'E': |
| 175 | + color = JMA_COLORS_HIST.INT_E |
| 176 | + elif note_clean == 'S': |
| 177 | + color = JMA_COLORS_HIST.INT_S |
| 178 | + |
| 179 | + return color |
| 180 | + |
| 181 | + except (ValueError, TypeError): |
| 182 | + return OTHER_COLORS.NAN |
| 183 | + |
| 184 | + |
| 185 | +# ----------------------------------------------------------------------------- |
| 186 | +# Get MMI/EMS-98 intensity RGB color |
| 187 | +def get_mmi_color(val: Union[float, int, str, None]) -> List[float]: |
| 188 | + """ |
| 189 | + Get RGB color for the MMI intensity based on USGS ShakeMap standards. |
| 190 | +
|
| 191 | + Args: |
| 192 | + val: MMI intensity value or None. |
| 193 | + Returns: |
| 194 | + List[float]: A list of 3 floats [R, G, B] in range 0.0 to 1.0. |
| 195 | + """ |
| 196 | + try: |
| 197 | + if val is None: |
| 198 | + return OTHER_COLORS.NAN |
| 199 | + |
| 200 | + v = float(val) |
| 201 | + if v != v: # NaN |
| 202 | + return OTHER_COLORS.NAN |
| 203 | + |
| 204 | + # MMI intensity scale (standard USGS binning) |
| 205 | + if v >= 9.5: |
| 206 | + color = MMI_COLORS.X |
| 207 | + elif v >= 8.5: |
| 208 | + color = MMI_COLORS.IX |
| 209 | + elif v >= 7.5: |
| 210 | + color = MMI_COLORS.VIII |
| 211 | + elif v >= 6.5: |
| 212 | + color = MMI_COLORS.VII |
| 213 | + elif v >= 5.5: |
| 214 | + color = MMI_COLORS.VI |
| 215 | + elif v >= 4.5: |
| 216 | + color = MMI_COLORS.V |
| 217 | + elif v >= 3.5: |
| 218 | + color = MMI_COLORS.IV |
| 219 | + elif v >= 2.5: |
| 220 | + color = MMI_COLORS.III |
| 221 | + elif v >= 1.5: |
| 222 | + color = MMI_COLORS.II |
| 223 | + else: |
| 224 | + color = MMI_COLORS.I |
| 225 | + |
| 226 | + return color |
| 227 | + |
| 228 | + except (ValueError, TypeError): |
| 229 | + return OTHER_COLORS.NAN |
0 commit comments