Skip to content

Commit

Permalink
Merge pull request #2 from k4m454k/develop
Browse files Browse the repository at this point in the history
Color and Configs
  • Loading branch information
k4m454k authored Dec 9, 2020
2 parents d9ffb2b + f9b8424 commit f8ae322
Show file tree
Hide file tree
Showing 6 changed files with 225 additions and 14 deletions.
34 changes: 33 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,40 @@ misc management commands:

```
### Colors
#### Add new color scheme
Add a new color scheme or rewrite available color scheme.
```bash
usage: mapoc color add [-h] --name NAME --facecolor FACECOLOR --water WATER --greens GREENS --roads ROADS

List available colors

optional arguments:
-h, --help show this help message and exit
--name NAME Name of color scheme. eq. "blue"
--facecolor FACECOLOR
MatPlot face hex color. eq. "#ffffff"
--water WATER MatPlot water hex color. eq. "#ffffff"
--greens GREENS MatPlot greens hex color. eq. "#ffffff"
--roads ROADS MatPlot roads hex color. eq. "#ffffff"

```
Example:
```bash
$ mapoc color add --name "coffee" --facecolor "#433633" --water "#5c5552" --greens "#8f857d" --roads "#decbb7"
```
#### List available color schemes
```bash
$ mapoc color list
```
## TODO
- Add configurable settings for poster size and quality.
- Add the ability to custom color schemes.
- Add Docker image
2 changes: 1 addition & 1 deletion map_poster_creator/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__ = 0.5
__version__ = 0.6
__author__ = "Vadim Apenko"
__author_email__ = "[email protected]"
__telegram__ = "@k4m454k"
126 changes: 121 additions & 5 deletions map_poster_creator/color_schemes.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,143 @@
import json
import logging
import os
import re
from pathlib import Path
from typing import Union, Tuple, List, Dict

from map_poster_creator.config import MAPOC_USER_PATH, USER_COLORS_SCHEME_FILE

logger = logging.getLogger(__name__)

base_color_scheme = {
"META_INFO": {
"config_version": 1,
"defaults": {
"facecolor": [0, 0, 0],
"water": "#383d52",
"greens": "#354038",
"roads": "#ffffff",
}
},
"black": {
"facecolor": (0, 0, 0),
"facecolor": [0, 0, 0],
"water": "#383d52",
"greens": "#354038",
"roads": "#ffffff",
},
"white": {
"facecolor": (1, 1, 1),
"facecolor": [1, 1, 1],
"water": "#bdddff",
"greens": "#d4ffe1",
"roads": "#000000",
},
"red": {
"facecolor": (0.4, 0.12, 0.12),
"facecolor": [0.4, 0.12, 0.12],
"water": "#754444",
"greens": "#b36969",
"roads": "#ffffff",
},
"coral": {
"facecolor": (0.67, 0.2, 0.18),
"facecolor": [0.67, 0.2, 0.18],
"water": "#ffffff",
"greens": "#b36969",
"roads": "#ffffff",
},
}
# TODO: Add base config file


def is_hex_color(hex_color: str) -> bool:
match = re.search(r'^#(?:[0-9a-fA-F]{3}){1,2}$', hex_color)
return True if match else False


def hex_to_faceacolor(hex_color: str) -> Tuple[float]:
if not is_hex_color(hex_color):
raise ValueError(f"{hex_color} is a not hex color. Expected eq. '#ffffff'")

color = hex_color.strip("#")
return tuple(1 / 255 * int(color[i:i+2], 16) for i in (0, 2, 4)) # magic asshole-code


def get_color_schemes() -> Dict[str, Dict[str, Union[List[float], Tuple[float]]]]:
config_path = Path(os.path.expanduser("~")) / MAPOC_USER_PATH / USER_COLORS_SCHEME_FILE
ensure_user_colors_or_create(config_path)
update_user_colors_if_need(config_path)
with open(config_path, "r") as conf:
color_scheme = json.load(conf)

return color_scheme


def ensure_user_colors_or_create(config_path: Path) -> None:
if config_path.is_file():
return
if not config_path.parent.is_dir():
os.makedirs(config_path.parent)

logger.info(f"User colors config not found!")
save_user_color_schemes(config_path=config_path, color_schemes=base_color_scheme)


def update_user_colors_if_need(config_path: Path):
# TODO: Add logic for update config version
pass


def save_user_color_schemes(
config_path: Path,
color_schemes: Dict[str, Dict[str, Union[List[float], Tuple[float]]]],
) -> None:
with open(config_path, "w") as conf:
json.dump(color_schemes, conf)
logger.info(f"Save user colors config: {config_path}")


def compose_user_color_scheme(
name: str,
facecolor: Union[Tuple[Union[float, int]], List[Union[float, int]], str],
water: str,
greens: str,
roads: str
) -> Dict[str, Dict[str, Union[List[float], Tuple[float]]]]:
if isinstance(facecolor, str):
if not is_hex_color(facecolor):
raise ValueError(f"{facecolor} is a not hex color. Expected eq. '#ffffff'")
facecolor = hex_to_faceacolor(facecolor)

if not all([is_hex_color(val) for val in [water, greens, roads]]):
raise ValueError(f"Hex color validation error. Expected eq. '#ffffff'")

new_scheme = {
name: {
"facecolor": facecolor,
"water": water,
"greens": greens,
"roads": roads,
}
}
return new_scheme


def add_user_color_scheme(
name: str,
facecolor: Union[Tuple[Union[float, int]], List[Union[float, int]], str],
water: str,
greens: str,
roads: str
) -> None:
current_color_schemes = get_color_schemes()
if name in current_color_schemes.keys():
logger.warning(f"Color scheme {name} exists. Will be rewrite.")

new_scheme = compose_user_color_scheme(
name=name,
facecolor=facecolor,
water=water,
greens=greens,
roads=roads,
)

config_path = Path(os.path.expanduser("~")) / MAPOC_USER_PATH / USER_COLORS_SCHEME_FILE
current_color_schemes.update(new_scheme)
save_user_color_schemes(config_path=config_path, color_schemes=current_color_schemes)
5 changes: 4 additions & 1 deletion map_poster_creator/config.py
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
# TODO: Add configs =)
# TODO: Add configs =)

MAPOC_USER_PATH = "mapoc"
USER_COLORS_SCHEME_FILE = "colors_scheme.json"
60 changes: 59 additions & 1 deletion map_poster_creator/entrypoints.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import argparse
import logging
import webbrowser
from pprint import pprint

from map_poster_creator.color_schemes import base_color_scheme
from map_poster_creator.color_schemes import base_color_scheme, get_color_schemes, add_user_color_scheme
from map_poster_creator.main import create_poster
from map_poster_creator import __version__

Expand Down Expand Up @@ -94,6 +95,61 @@ def add_misc_subparsers(parser_group) -> argparse.ArgumentParser:
return misc_commands_parser


def add_color_list_subparser(parent_parser) -> argparse.ArgumentParser:
color_parser = parent_parser.add_parser('list', description="List available colors")
return color_parser


def add_color_add_subparser(parent_parser) -> argparse.ArgumentParser:
color_parser = parent_parser.add_parser('add', description="List available colors")
color_parser.add_argument('--name', help='Name of color scheme. eq. "blue"', required=True)
color_parser.add_argument('--facecolor', help='MatPlot face hex color. eq. "#ffffff"', required=True)
color_parser.add_argument('--water', help='MatPlot water hex color. eq. "#ffffff"', required=True)
color_parser.add_argument('--greens', help='MatPlot greens hex color. eq. "#ffffff"', required=True)
color_parser.add_argument('--roads', help='MatPlot roads hex color. eq. "#ffffff"', required=True)
return color_parser


def add_color_subparsers(parser_group) -> argparse.ArgumentParser:
color_commands_parser = parser_group.add_parser(
'color',
description='Color services',
help='Color services',
)
color_commands_parser_group = color_commands_parser.add_subparsers(
title='color management commands',
description='Color management',
help='Additional help for available commands',
dest='color_commands',
)

add_color_add_subparser(color_commands_parser_group)
add_color_list_subparser(color_commands_parser_group)

return color_commands_parser


def process_color_service_call(args: argparse.Namespace) -> None:
command = args.color_commands
if command == "list":
pprint(get_color_schemes())

if command == "add":
name = args.name
facecolor = args.facecolor
water = args.water
greens = args.greens
roads = args.roads

add_user_color_scheme(
name=name,
facecolor=facecolor,
water=water,
greens=greens,
roads=roads
)


def process_misc_service_call(args: argparse.Namespace) -> None:
command = args.misc_commands
if command == 'shp':
Expand Down Expand Up @@ -133,13 +189,15 @@ def map_poster(argv=None) -> None:
)
add_poster_subparsers(poster_creator_services_parser_group)
add_misc_subparsers(poster_creator_services_parser_group)
add_color_subparsers(poster_creator_services_parser_group)

args = parser.parse_args(argv)

service = args.map_poster_services
available_services = {
'poster': process_poster_service_call,
'misc': process_misc_service_call,
'color': process_color_service_call,
}
if not service:
parser.print_help()
Expand Down
12 changes: 7 additions & 5 deletions map_poster_creator/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from geopandas import GeoDataFrame
from shapely.geometry import Polygon

from map_poster_creator.color_schemes import base_color_scheme
from map_poster_creator.color_schemes import get_color_schemes
from map_poster_creator.geojson import get_polygon_from_geojson, get_map_geometry_from_poly, MapGeometry
from map_poster_creator.logs import log_processing, logging
from map_poster_creator.plotting import plot_and_save
Expand Down Expand Up @@ -53,10 +53,11 @@ def preprocessing_other(poly: Polygon, dataframe: GeoDataFrame) -> GeoDataFrame:
def create_poster(
base_shp_path: str,
geojson_path: str,
colors: List[str],
colors: Union[List[Union[Dict, str]], None],
layers: List[str],
config: dict,
output_prefix: str,
user_color_scheme: bool = False,
):
poly, geometry = get_boundary_shape(geojson=geojson_path)
roads = get_roads_data(base_shp_path)
Expand All @@ -65,10 +66,11 @@ def create_poster(
roads_df = preprocessing_roads(poly=poly, roads=roads)
water_df = preprocessing_other(poly=poly, dataframe=water)
greens_df = preprocessing_other(poly=poly, dataframe=greens)
# TODO: Support user color scheme
for color in colors:
if color not in base_color_scheme.keys():
if color not in get_color_schemes().keys():
logger.warning(f"Color {color} not found in base color scheme. "
f"Available colors: {', '.join(base_color_scheme.keys())}")
f"Available colors: {', '.join(get_color_schemes().keys())}")
print("")
print(f"Plot and Save {color} map")
plot_and_save(
Expand All @@ -78,5 +80,5 @@ def create_poster(
geometry=geometry,
path=f'{output_prefix}_{color}.png',
dpi=1200,
color=base_color_scheme[color]
color=get_color_schemes()[color]
)

0 comments on commit f8ae322

Please sign in to comment.