본문 바로가기

데이터와 함께 탱고를/데이터 시각화

folium 의 plugins 패키지 샘플 살펴보기 2

저번 포스팅에 이어, examples 에 있는 plugins 관련된 기능들을 좀 더 살펴보려 한다.

DualMap

This plugin is using the Leaflet plugin Sync by Jieter:
https://github.com/jieter/Leaflet.Sync

The goal is to have two maps side by side. When you pan or zoom on one map, the other will move as well.

import folium
import folium.plugins

The DualMap class accepts the same arguments as the normal Map class. Except for these: 'width', 'height', 'left', 'top', 'position'.

In the following example we create a DualMap, add layer controls and then show the map. Try panning and zooming to check that both maps are syncronized.

m = folium.plugins.DualMap(location=(52.1, 5.1), zoom_start=8)
m

You can access the two submaps with attributes m1 and m2. You can add objects to each map specifically.

Here we add different tile layers to each map. This way you can see two different tile sets at the same time.

m = folium.plugins.DualMap(location=(52.1, 5.1), tiles=None, zoom_start=8)

folium.TileLayer('openstreetmap').add_to(m.m1)
folium.TileLayer('cartodbpositron').add_to(m.m2)

folium.LayerControl(collapsed=False).add_to(m)
m

Now we're going to add feature groups and markers to both maps and to each map individually. We'll color the shared icon red.

m = folium.plugins.DualMap(location=(52.1, 5.1), tiles='cartodbpositron', zoom_start=8)

fg_both = folium.FeatureGroup(name='markers_both').add_to(m)
fg_1 = folium.FeatureGroup(name='markers_1').add_to(m.m1)
fg_2 = folium.FeatureGroup(name='markers_2').add_to(m.m2)

icon_red = folium.Icon(color='red')
folium.Marker((52.0, 5.0), tooltip='both', icon=icon_red).add_to(fg_both)
folium.Marker((52.4, 5.0), tooltip='1').add_to(fg_1)
folium.Marker((52.0, 5.4), tooltip='2').add_to(fg_2)

folium.LayerControl(collapsed=False).add_to(m)
m

Finally, you can use the layout argument to change the layout to vertical:

m = folium.plugins.DualMap(layout='vertical')
m

PolyLineOffset

Note : The examples presented below are the copy of the ones presented on https://github.com/bbecquet/Leaflet.PolylineOffset

Basic Demo

  • The dashed line is the "model", with no offset applied.
  • The Red line is with a -5px offset,
  • The Green line is with a 10px offset.
    The three are distinct Polyline objects but uses the same coordinate array
from folium import plugins


m = folium.Map(location=[58.0, -11.0], zoom_start=4, tiles="Mapbox Bright")

coords = [
    [58.44773, -28.65234],
    [53, -23.33496],
    [53, -14.32617],
    [58.1707, -10.37109],
    [59, -13],
    [57, -15],
    [57, -18],
    [60, -18],
    [63, -5],
    [59, -7],
    [58, -3],
    [56, -3],
    [60, -4],
]

plugins.PolyLineOffset(
    coords, weight=2, dash_array="5,10", color="black", opacity=1
).add_to(m)

plugins.PolyLineOffset(coords, color="#f00", opacity=1, offset=-5).add_to(m)

plugins.PolyLineOffset(coords, color="#080", opacity=1, offset=10).add_to(m)

m.save(os.path.join('results', "PolyLineOffset_simple.html"))

m

Bus Lines

A more complex demo.
Offsets are computed automatically depending on the number of bus lines using the same segment.
Other non-offset polylines are used to achieve the white and black outline effect.

m = folium.Map(location=[48.868, 2.365], zoom_start=15)

geojson = {
    "type": "FeatureCollection",
    "features": [
        {
            "type": "Feature",
            "properties": {"lines": [0, 1]},
            "geometry": {
                "type": "LineString",
                "coordinates": [
                    [2.357919216156006, 48.87621773324153],
                    [2.357339859008789, 48.874834693731664],
                    [2.362983226776123, 48.86855408432749],
                    [2.362382411956787, 48.86796126699168],
                    [2.3633265495300293, 48.86735432768131],
                ],
            },
        },
        {
            "type": "Feature",
            "properties": {"lines": [2, 3]},
            "geometry": {
                "type": "LineString",
                "coordinates": [
                    [2.351503372192383, 48.86443950493823],
                    [2.361609935760498, 48.866775611250205],
                    [2.3633265495300293, 48.86735432768131],
                ],
            },
        },
        {
            "type": "Feature",
            "properties": {"lines": [1, 2]},
            "geometry": {
                "type": "LineString",
                "coordinates": [
                    [2.369627058506012, 48.86619159489603],
                    [2.3724031448364253, 48.8626397112042],
                    [2.3728322982788086, 48.8616233285001],
                    [2.372767925262451, 48.86080456075567],
                ],
            },
        },
        {
            "type": "Feature",
            "properties": {"lines": [0]},
            "geometry": {
                "type": "LineString",
                "coordinates": [
                    [2.3647427558898926, 48.86653565369396],
                    [2.3647642135620117, 48.86630981023694],
                    [2.3666739463806152, 48.86314789481612],
                    [2.3673176765441895, 48.86066339254944],
                ],
            },
        },
        {
            "type": "Feature",
            "properties": {"lines": [0, 1, 2, 3]},
            "geometry": {
                "type": "LineString",
                "coordinates": [
                    [2.3633265495300293, 48.86735432768131],
                    [2.3647427558898926, 48.86653565369396],
                ],
            },
        },
        {
            "type": "Feature",
            "properties": {"lines": [1, 2, 3]},
            "geometry": {
                "type": "LineString",
                "coordinates": [
                    [2.3647427558898926, 48.86653565369396],
                    [2.3650002479553223, 48.86660622956524],
                    [2.365509867668152, 48.866987337550164],
                    [2.369627058506012, 48.86619159489603],
                ],
            },
        },
        {
            "type": "Feature",
            "properties": {"lines": [3]},
            "geometry": {
                "type": "LineString",
                "coordinates": [
                    [2.369627058506012, 48.86619159489603],
                    [2.372349500656128, 48.865702850895744],
                ],
            },
        },
    ],
}

# manage overlays in groups to ease superposition order
outlines = folium.FeatureGroup("outlines")
line_bg = folium.FeatureGroup("lineBg")
bus_lines = folium.FeatureGroup("busLines")
bus_stops = folium.FeatureGroup("busStops")

line_weight = 6
line_colors = ["red", "#08f", "#0c0", "#f80"]
stops = []
for line_segment in geojson["features"]:
    # Get every bus line coordinates
    segment_coords = [[x[1], x[0]] for x in line_segment["geometry"]["coordinates"]]
    # Get bus stops coordinates
    stops.append(segment_coords[0])
    stops.append(segment_coords[-1])
    # Get number of bus lines sharing the same coordinates
    lines_on_segment = line_segment["properties"]["lines"]
    # Width of segment proportional to the number of bus lines
    segment_width = len(lines_on_segment) * (line_weight + 1)
    # For the white and black outline effect
    folium.PolyLine(
        segment_coords, color="#000", weight=segment_width + 5, opacity=1
    ).add_to(outlines)
    folium.PolyLine(
        segment_coords, color="#fff", weight=segment_width + 3, opacity=1
    ).add_to(line_bg)
    # Draw parallel bus lines with different color and offset
    for j, line_number in enumerate(lines_on_segment):
        plugins.PolyLineOffset(
            segment_coords,
            color=line_colors[line_number],
            weight=line_weight,
            opacity=1,
            offset=j * (line_weight + 1) - (segment_width / 2) + ((line_weight + 1) / 2),
        ).add_to(bus_lines)

# Draw bus stops
for stop in stops:
    folium.CircleMarker(
        stop,
        color="#000",
        fill_color="#ccc",
        fill_opacity=1,
        radius=10,
        weight=4,
        opacity=1,
    ).add_to(bus_stops)

outlines.add_to(m)
line_bg.add_to(m)
bus_lines.add_to(m)
bus_stops.add_to(m)

m.save(os.path.join('results', "PolyLineOffset_bus.html"))

m

Mouse Position

from folium.plugins import MousePosition


m = folium.Map()

MousePosition().add_to(m)

m.save(os.path.join('results', 'MousePosition0.html'))

m
m = folium.Map()

# Define a Javascript function that formats the coordinate value
# that is passed to it.
formatter = "function(num) {return L.Util.formatNum(num, 3) + ' º ';};"

MousePosition(
    position='topright',
    separator=' | ',
    empty_string='NaN',
    lng_first=True,
    num_digits=20,
    prefix='Coordinates:',
    lat_formatter=formatter,
    lng_formatter=formatter
).add_to(m)

m.save(os.path.join('results', 'MousePosition1.html'))

m

Measure Control

from folium.plugins import MeasureControl

m = folium.Map([-27.5717, -48.6256], zoom_start=10)

m.add_child(MeasureControl())

m

Draw

from folium.plugins import Draw

m = folium.Map()

draw = Draw()

draw.add_to(m)

m.save(os.path.join('results', 'Draw0.html'))

m
m = folium.Map(location=[-27.23, -48.36], zoom_start=12)

draw = Draw(export=True)

draw.add_to(m)

m.save(os.path.join('results', 'Draw1.html'))

m

Pattern

import folium
from folium import plugins
m = folium.Map([40., -105.], zoom_start=6)

url = 'https://raw.githubusercontent.com/python-visualization/folium/master/examples/data/us-states.json'
stripes = plugins.pattern.StripePattern(angle=-45)
stripes.add_to(m)

circles = plugins.pattern.CirclePattern(width=20, height=20, radius=5, fill_opacity=0.5, opacity=1)
circles.add_to(m)

def style_function(feature):
    default_style = {
        'opacity':1.0,
        'fillColor': '#ffff00',
        'color': 'black',
        'weight': 2
    }

    if feature['properties']['name']  == 'Colorado':
        default_style['fillPattern'] = stripes
        default_style['fillOpacity'] = 1.0

    if feature['properties']['name']  == 'Utah':
        default_style['fillPattern'] = circles
        default_style['fillOpacity'] = 1.0

    return default_style

# Adding remote GeoJSON as additional layer.
folium.GeoJson(url, smooth_factor=0.5, style_function=style_function).add_to(m)

m

출처