{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Folium Map Plotting in MSTICPy\n", "\n", "## Introduction\n", "This module contains a class and functions that wraps the `folium` package to plot geo-location data.\n", "\n", "Read the [MSTICPy Folium documentation](https://msticpy.readthedocs.io/visualization/FoliumMap.html)\n", "\n", "Read the [Folium Python package documentation](https://python-visualization.github.io/folium/)\n", "\n", "You must have msticpy installed to run this notebook:\n", "```\n", "%pip install --upgrade msticpy\n", "```" ] }, { "cell_type": "markdown", "metadata": { "toc": true }, "source": [ "## Contents\n", "\n", "- Introduction\n", "- Using Folium with MSTICPy\n", "- Plotting from a Pandas DataFrame\n", " - Basic plot\n", " - Plotting Coordinates\n", " - Map Layers\n", " - Adding custom tooltip and popup data\n", " - Using custom icons\n", "- Using the plot_map function \n", "- Folium map class\n", " - Underlying folium map object\n", " - Adding IP entities\n", " - Adding IP addresses\n", " - Adding locations\n", " - Plotting IpAddress entities with location data\n", " - Using different colors and icons\n", " - Using custom icons\n", "- Utility functions\n", " - Calculating the center point of locations\n", " - Calculating the distance between locations \n" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "ExecuteTime": { "end_time": "2020-02-08T01:01:41.418156Z", "start_time": "2020-02-08T01:01:39.342857Z" } }, "outputs": [ { "data": { "text/html": [ "\n", "This product includes GeoLite2 data created by MaxMind, available from\n", "https://www.maxmind.com.\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "This library uses services provided by ipstack.\n", "https://ipstack.com" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Imports\n", "import msticpy\n", "msticpy.init_notebook(verbosity=0)\n", "\n", "from msticpy.vis.foliummap import FoliumMap" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Using Folium with MSTICPy\n", "\n", "You can use Folium via a pandas accessor, the plot_map function\n", "or directly interacting with our FoliumMap class." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Plotting from a Pandas DataFrame\n", "\n", "MSTICPy uses pandas accessors to expose a lot of its \n", "visualization functions. \n", "\n", "Plotting with Folium can be done directly from a pandas\n", "DataFrame using the `mp_plot.folium_map` extension.\n", "\n", "This function returns an instance of the `FoliumMap`\n", "class that you can further customize (see FoliumMap class later in the document).\n", "\n", "### Basic plot" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
AllExtIPsCountryCodeCountryNameStateCityLongitudeLatitudeAsnedgesTypeAdditionalDataIpAddress
065.55.44.109USUnited StatesVirginiaBoydton-78.375036.6534NaNset()geolocation{}65.55.44.109
113.71.172.128CACanadaOntarioToronto-79.419543.6644NaNset()geolocation{}13.71.172.128
213.71.172.130CACanadaOntarioToronto-79.419543.6644NaNset()geolocation{}13.71.172.130
340.124.45.19USUnited StatesTexasSan Antonio-98.492629.4221NaNset()geolocation{}40.124.45.19
4104.43.212.12USUnited StatesIowaDes Moines-93.612741.6015NaNset()geolocation{}104.43.212.12
\n", "
" ], "text/plain": [ " AllExtIPs CountryCode CountryName State City Longitude \\\n", "0 65.55.44.109 US United States Virginia Boydton -78.3750 \n", "1 13.71.172.128 CA Canada Ontario Toronto -79.4195 \n", "2 13.71.172.130 CA Canada Ontario Toronto -79.4195 \n", "3 40.124.45.19 US United States Texas San Antonio -98.4926 \n", "4 104.43.212.12 US United States Iowa Des Moines -93.6127 \n", "\n", " Latitude Asn edges Type AdditionalData IpAddress \n", "0 36.6534 NaN set() geolocation {} 65.55.44.109 \n", "1 43.6644 NaN set() geolocation {} 13.71.172.128 \n", "2 43.6644 NaN set() geolocation {} 13.71.172.130 \n", "3 29.4221 NaN set() geolocation {} 40.124.45.19 \n", "4 41.6015 NaN set() geolocation {} 104.43.212.12 " ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
Make this Notebook Trusted to load map: File -> Trust Notebook
" ], "text/plain": [ "" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# read in a DataFrame from a csv file\n", "geo_loc_df = (\n", " pd\n", " .read_csv(\"data/ip_locs.csv\", index_col=0)\n", " .dropna(subset=[\"Latitude\", \"Longitude\", \"IpAddress\"]) # We need to remove an NaN values\n", ")\n", " \n", "display(geo_loc_df.head(5))\n", "\n", "geo_loc_df.mp_plot.folium_map(ip_column=\"IpAddress\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Plotting from coordinates\n", "\n", "If you already have coordinates in the data you can use \n", "these (rather than looking up the IP location again) using\n", "the `lat_column` and `long_column` parameters." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
Make this Notebook Trusted to load map: File -> Trust Notebook
" ], "text/plain": [ "" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "geo_loc_df.mp_plot.folium_map(\n", " lat_column=\"Latitude\", long_column=\"Longitude\", zoom_start=10\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Plotting Layers\n", "\n", "You can use the Folium layers feature, specifying a column\n", "value on which to group each layer with the `layer_column` parameter." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
Make this Notebook Trusted to load map: File -> Trust Notebook
" ], "text/plain": [ "" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "geo_loc_df.mp_plot.folium_map(\n", " ip_column=\"IpAddress\", layer_column=\"CountryName\", zoom_start=2\n", ")\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Adding custom tooltip and popup data\n", "\n", "You use DataFrame column values to populate the tooltip\n", "and popup elements for each marker with the\n", "`tooltip_columns` and `popup_columns` parameters." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
AllExtIPsCountryCodeCountryNameStateCityLongitudeLatitudeAsnedgesTypeAdditionalDataIpAddressStatusFriendlinessFlavorSpiceLevel
065.55.44.109USUnited StatesVirginiaBoydton-78.375036.6534NaNset()geolocation{}65.55.44.109HomeWarmChocolate1.0
113.71.172.128CACanadaOntarioToronto-79.419543.6644NaNset()geolocation{}13.71.172.128OfficeColdCinnamon2.0
213.71.172.130CACanadaOntarioToronto-79.419543.6644NaNset()geolocation{}13.71.172.130VacationMediumMango3.0
\n", "
" ], "text/plain": [ " AllExtIPs CountryCode CountryName State City Longitude \\\n", "0 65.55.44.109 US United States Virginia Boydton -78.3750 \n", "1 13.71.172.128 CA Canada Ontario Toronto -79.4195 \n", "2 13.71.172.130 CA Canada Ontario Toronto -79.4195 \n", "\n", " Latitude Asn edges Type AdditionalData IpAddress Status \\\n", "0 36.6534 NaN set() geolocation {} 65.55.44.109 Home \n", "1 43.6644 NaN set() geolocation {} 13.71.172.128 Office \n", "2 43.6644 NaN set() geolocation {} 13.71.172.130 Vacation \n", "\n", " Friendliness Flavor SpiceLevel \n", "0 Warm Chocolate 1.0 \n", "1 Cold Cinnamon 2.0 \n", "2 Medium Mango 3.0 " ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Create some data to display\n", "data_df = pd.DataFrame({\n", " \"Status\": [\"Home\", \"Office\", \"Vacation\"] * (len(geo_loc_df) // 3),\n", " \"Friendliness\": [\"Warm\", \"Cold\", \"Medium\"] * (len(geo_loc_df) // 3),\n", " \"Flavor\": [\"Chocolate\", \"Cinnamon\", \"Mango\"] * (len(geo_loc_df) // 3),\n", " \"SpiceLevel\": [1, 2, 3] * (len(geo_loc_df) // 3)\n", "})\n", "geo_loc_data_df = pd.concat([geo_loc_df, data_df], axis=1).dropna(subset=[\"IpAddress\"])\n", "geo_loc_data_df.head(3)" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
Make this Notebook Trusted to load map: File -> Trust Notebook
" ], "text/plain": [ "" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "\n", "geo_loc_data_df.mp_plot.folium_map(\n", " ip_column=\"IpAddress\",\n", " layer_column=\"CountryName\",\n", " tooltip_columns=[\"Status\", \"Flavor\"],\n", " popup_columns=[\"Friendliness\", \"SpiceLevel\", \"Status\", \"Flavor\"],\n", " zoom_start=2,\n", ")\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Using custom icons\n", "\n", "You can also control the icons used for each marker with the\n", "`icon_column` parameters. If you happen to have a column in your\n", "data that contains names of FontAwesome or GlyphIcons icons.\n", "More typically you would combine the `icon_column` with the\n", "`icon_map` parameter. You can specify either a dictionary or a\n", "function. For a dictionary, the value of the row in `icon_column`\n", "is used as a key - the value is a dictionary of icon parameters\n", "passed to the Folium.Icon class. For a method, the `icon_column`\n", "value is passed as a single parameter and the return value\n", "should be a dictionary of valid parameters for the `Icon` class.\n", "You can read the documentation for this function in the doc.\n", "\n", "If `icon_map` is a dict it should contain keys that map to the\n", "value of `icon_col` and values that a dicts of valid\n", "folium Icon properties (\"color\", \"icon_color\", \"icon\", \"angle\", \"prefix\").\n", "The dict should include a \"default\" entry that will be used if the\n", "value in the DataFrame[icon_col] doesn't match any key.\n", "For example:\n", "\n", "```python\n", "\n", " icon_map = {\n", " \"high\": {\n", " \"color\": \"red\",\n", " \"icon\": \"warning\",\n", " },\n", " \"medium\": {\n", " \"color\": \"orange\",\n", " \"icon\": \"triangle-exclamation\",\n", " \"prefix\": \"fa\",\n", " },\n", " \"default\": {\n", " \"color\": \"blue\",\n", " \"icon\": \"info-sign\",\n", " },\n", " }\n", "```\n", "\n", "If icon_map is a function it should take a single str parameter\n", "(the item key) and return a dict of icon properties. It should\n", "return a default set of values if the key does not match a known\n", "key. The `icon_col` value for each row will be passed to this\n", "function and the return value used to populate the Icon arguments.\n", "\n", "For example:\n", "\n", "```python\n", "\n", " def icon_mapper(icon_key):\n", " if icon_key.startswith(\"bad\"):\n", " return {\n", " \"color\": \"red\",\n", " \"icon\": \"triangle-alert\",\n", " }\n", " ...\n", " else:\n", " return {\n", " \"color\": \"blue\",\n", " \"icon\": \"info-sign\",\n", " }\n", "```\n", "\n", "Check out the possible names for icons:\n", "\n", "- FontAwesome icon (prefix \"fa\") names are available at https://fontawesome.com/\n", "- GlyphIcons icons (prefix \"glyphicon\") are available at https://www.glyphicons.com/\n" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
Make this Notebook Trusted to load map: File -> Trust Notebook
" ], "text/plain": [ "" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "icon_map = {\n", " \"US\": {\n", " \"color\": \"green\",\n", " \"icon\": \"flash\",\n", " },\n", " \"GB\": {\n", " \"color\": \"purple\",\n", " \"icon\": \"flash\",\n", " },\n", " \"default\": {\n", " \"color\": \"blue\",\n", " \"icon\": \"info-sign\",\n", " },\n", "}\n", "\n", "geo_loc_df.mp_plot.folium_map(\n", " ip_column=\"AllExtIPs\",\n", " icon_column=\"CountryCode\",\n", " icon_map=icon_map,\n", " zoom_start=2,\n", ")\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Using the `plot_map` function\n", "\n", "The `plot_map` function is identical to the mp_plot.folium\n", "map accessor. You can import this directly and use in place\n", "of the pandas accessor." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
Make this Notebook Trusted to load map: File -> Trust Notebook
" ], "text/plain": [ "" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from msticpy.vis.foliummap import plot_map\n", "\n", "plot_map(\n", " data=geo_loc_df,\n", " ip_column=\"AllExtIPs\",\n", " icon_column=\"CountryCode\",\n", " icon_map=icon_map,\n", " zoom_start=2,\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## FoliumMap class\n", "\n", "Use the Folium Map class when you want to build up data\n", "clusters and layers incrementally.\n", "\n", "It now supports multiple data types for entry:\n", "- IpAddress (`map.add_ip_cluster`) and Geolocation (`map.add_geoloc_cluster`) entities\n", "- IP addresses (`map.add_ips`)\n", "- Locations (`map.add_locations`)\n", "- GeoHashes (`map.add_geo_hashes`)\n", "\n", "You can also use other member functions to add layers and cluster groups.\n", "\n", "```\n", "FoliumMap(\n", " title: str = 'layer1',\n", " zoom_start: float = 2.5,\n", " tiles=None,\n", " width: str = '100%',\n", " height: str = '100%',\n", " location: list = None,\n", ")\n", "Wrapper class for Folium/Leaflet mapping.\n", "\n", "Parameters\n", "----------\n", "title : str, optional\n", " Name of the layer (the default is 'layer1')\n", "zoom_start : int, optional\n", " The zoom level of the map (the default is 7)\n", "tiles : [type], optional\n", " Custom set of tiles or tile URL (the default is None)\n", "width : str, optional\n", " Map display width (the default is '100%')\n", "height : str, optional\n", " Map display height (the default is '100%')\n", "location : list, optional\n", " Location to center map on\n", "\n", "Attributes\n", "----------\n", "folium_map : folium.Map\n", "```" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "ExecuteTime": { "end_time": "2020-02-08T01:01:41.435147Z", "start_time": "2020-02-08T01:01:41.419155Z" } }, "outputs": [ { "data": { "text/html": [ "
Make this Notebook Trusted to load map: File -> Trust Notebook
" ], "text/plain": [ "" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "folium_map = FoliumMap(location=(47.5982328,-122.331), zoom_start=14)\n", "folium_map" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The underlying folium map object is accessible as the `folium_map` attribute" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "ExecuteTime": { "end_time": "2020-02-08T01:01:41.441144Z", "start_time": "2020-02-08T01:01:41.436631Z" } }, "outputs": [ { "data": { "text/plain": [ "folium.folium.Map" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(folium_map.folium_map)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Adding IP Entities to the map\n", "\n", "```\n", "fol_map.add_ip_cluster(\n", " ip_entities: Iterable[msticpy.datamodel.entities.IpAddress],\n", " **kwargs,\n", ")\n", "\n", "```" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "ExecuteTime": { "end_time": "2020-02-08T01:01:41.464131Z", "start_time": "2020-02-08T01:01:41.442143Z" } }, "outputs": [ { "data": { "text/html": [ "
Make this Notebook Trusted to load map: File -> Trust Notebook
" ], "text/plain": [ "" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import pickle\n", "with open(b\"data/ip_entities.pkl\", \"rb\") as fh:\n", " ip_entities = pickle.load(fh)\n", "ip_entities = [ip for ip in ip_entities if ip.Location and ip.Location.Latitude]\n", "\n", "folium_map = FoliumMap(zoom_start=9)\n", "folium_map.add_ip_cluster(ip_entities=ip_entities, color='orange')\n", "folium_map.center_map()\n", "folium_map" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Adding IP addresses\n", "\n", "```\n", "ip_map.add_ips(ip_addresses: Iterable[str], **kwargs)\n", "```" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "IP dataset ['13.83.149.5' '13.83.148.235' '13.64.188.245'] ...\n" ] }, { "data": { "text/html": [ "
Make this Notebook Trusted to load map: File -> Trust Notebook
" ], "text/plain": [ "" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ips = geo_loc_df.query(\"State == 'California'\").AllExtIPs.values\n", "\n", "print(\"IP dataset\", ips[:3], \"...\")\n", "ip_map = FoliumMap(zoom_start=\"3\")\n", "ip_map.add_ips(ips)\n", "ip_map.center_map()\n", "ip_map" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Adding locations\n", "\n", "```\n", "ip_map.add_locations(locations: Iterable[Tuple[float, float]], **kwargs)\n", "```" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "ExecuteTime": { "end_time": "2020-02-08T01:26:09.269390Z", "start_time": "2020-02-08T01:26:09.261435Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Location dataset [(43.6644, -79.4195) (43.6644, -79.4195) (43.6644, -79.4195)] ...\n" ] }, { "data": { "text/html": [ "
Make this Notebook Trusted to load map: File -> Trust Notebook
" ], "text/plain": [ "" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "locations = geo_loc_df.query(\"CountryCode != 'US'\").apply(lambda x: (x.Latitude, x.Longitude), axis=1).values\n", "\n", "print(\"Location dataset\", locations[:3], \"...\")\n", "ip_map.add_locations(locations)\n", "ip_map.center_map()\n", "ip_map" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Plotting IPAddress entities with location data" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "ExecuteTime": { "end_time": "2020-02-08T01:01:41.607128Z", "start_time": "2020-02-08T01:01:41.550160Z" } }, "outputs": [ { "data": { "text/html": [ "
Make this Notebook Trusted to load map: File -> Trust Notebook
" ], "text/plain": [ "" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Create IP and GeoLocation Entities from the dataframe\n", "def create_ip_entity(row):\n", " ip_ent = IpAddress(Address=row[\"AllExtIPs\"])\n", " geo_loc = create_geo_entity(row)\n", " ip_ent.Location = geo_loc\n", " return ip_ent\n", "\n", "def create_geo_entity(row):\n", " # get subset of fields for GeoLocation\n", " loc_props = row[[\"CountryCode\", \"CountryName\",\"State\", \"City\", \"Longitude\", \"Latitude\"]]\n", " return GeoLocation(**loc_props.to_dict())\n", "\n", "\n", "geo_locs = list(geo_loc_df.apply(create_geo_entity, axis=1).values)\n", "ip_ents = list(geo_loc_df.apply(create_ip_entity, axis=1).values)\n", "\n", "fmap_ips = FoliumMap()\n", "fmap_ips.add_ip_cluster(ip_entities=ip_ents[:20], color='blue')\n", "fmap_ips.center_map()\n", "fmap_ips" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Using different colors and icons" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "ExecuteTime": { "end_time": "2020-02-08T01:01:41.677086Z", "start_time": "2020-02-08T01:01:41.609124Z" } }, "outputs": [ { "data": { "text/html": [ "
Make this Notebook Trusted to load map: File -> Trust Notebook
" ], "text/plain": [ "" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fmap_ips.add_ip_cluster(ip_entities=ip_ents[30:40], color='red', icon=\"flash\")\n", "fmap_ips.center_map()\n", "fmap_ips" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Using custom Icons\n", "\n", "By default folium uses the information icon (i).\n", "Icons can be taken from the default Bootstrap set. See the default list here [glyphicons](https://www.w3schools.com/icons/bootstrap_icons_glyphicons.asp)\n", "\n", "Alternatively you can use icons from the [Font Awesome collection](https://fontawesome.com/icons?d=gallery)\n", "by adding prefx=\"fa\" and icon=\"icon_name\" to the call to add_ip_cluster or add_geo_cluster." ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "ExecuteTime": { "end_time": "2020-02-08T01:01:41.806012Z", "start_time": "2020-02-08T01:01:41.678087Z" } }, "outputs": [ { "data": { "text/html": [ "
Make this Notebook Trusted to load map: File -> Trust Notebook
" ], "text/plain": [ "" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fmap_ips.add_geoloc_cluster(\n", " geo_locations=geo_locs[40:50],\n", " color='darkblue',\n", " icon=\"desktop\",\n", " prefix=\"fa\"\n", ")\n", "fmap_ips.center_map()\n", "fmap_ips" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Utility Functions" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Calculate center point of entity locations" ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "ExecuteTime": { "end_time": "2020-02-08T01:01:41.815007Z", "start_time": "2020-02-08T01:01:41.807012Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(38.7095, -79.4195)\n", "(40.01865529411764, -84.9259)\n", "(38.7095, -78.1539)\n", "(38.7095, -86.5161)\n", "(38.7095, -86.5161)\n" ] } ], "source": [ "from msticpy.vis.foliummap import get_map_center, get_center_ip_entities, get_center_geo_locs\n", "\n", "print(get_center_geo_locs(geo_locs))\n", "print(get_center_geo_locs(geo_locs, mode=\"mean\"))\n", "\n", "# get_map_center Will accept iterable of any entity type that is either\n", "# an IpAddress entity or an entity that has properties of type IpAddress\n", "print(get_map_center(ip_ents[30:40]))\n", "print(get_map_center(ip_ents[:20]))\n", "\n", "print(get_center_ip_entities(ip_ents[:20])) " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Calculate distance between entity locations" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Distance between\n", "65.55.44.109 (Boydton)\n", "13.71.172.128 (Toronto)\n", "784.604908273247 km \n", "\n", "Distance between\n", "65.55.44.109 (Boydton)\n", "131.107.147.209 (Redmond)\n", "3751.614749340525 km \n", "\n" ] } ], "source": [ "from msticpy.context.geoip import entity_distance\n", "print(\"Distance between\")\n", "print(f\"{ip_ents[0].Address} ({ip_ents[0].Location.City})\")\n", "print(f\"{ip_ents[1].Address} ({ip_ents[1].Location.City})\")\n", "print(entity_distance(ip_ents[0], ip_ents[1]), \"km\", \"\\n\")\n", "\n", "print(\"Distance between\")\n", "print(f\"{ip_ents[0].Address} ({ip_ents[0].Location.City})\")\n", "print(f\"{ip_ents[13].Address} ({ip_ents[13].Location.City})\")\n", "print(entity_distance(ip_ents[0], ip_ents[13]), \"km\", \"\\n\")" ] } ], "metadata": { "hide_input": false, "kernelspec": { "display_name": "Python 3.9.7 ('msticpy')", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.7" }, "toc": { "base_numbering": 1, "nav_menu": {}, "number_sections": false, "sideBar": true, "skip_h1_title": true, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": true, "toc_position": {}, "toc_section_display": true, "toc_window_display": true }, "varInspector": { "cols": { "lenName": 16, "lenType": 16, "lenVar": 40 }, "kernels_config": { "python": { "delete_cmd_postfix": "", "delete_cmd_prefix": "del ", "library": "var_list.py", "varRefreshCmd": "print(var_dic_list())" }, "r": { "delete_cmd_postfix": ") ", "delete_cmd_prefix": "rm(", "library": "var_list.r", "varRefreshCmd": "cat(var_dic_list()) " } }, "types_to_exclude": [ "module", "function", "builtin_function_or_method", "instance", "_Feature" ], "window_display": false }, "vscode": { "interpreter": { "hash": "0f1a8e166ce5c1ec1911a36e4fdbd34b2f623e2a3442791008b8ac429a1d6070" } }, "widgets": { "application/vnd.jupyter.widget-state+json": { "state": {}, "version_major": 2, "version_minor": 0 } } }, "nbformat": 4, "nbformat_minor": 4 }