Package: cs-brix
Brix is a python library for CityScope modules which handles communication withCity I/O.Full documentation can be foundhere.Please note that brix is still being developed, which is why some features might change fairly quickly. You can follow the updates by keeping track of brix development in thegithub repo.IntroductionWhat is this library for? If you have never heard of a CityScope before, you might want to stop reading and learn about themhere. CityScope is an awesome way to interact, explore, and co-create urban interventions in a way that can be accessed by multiple people with different background. If you know what they are, please keep reading.What is a CityScope table? a ‘table’ is our way of describing a CityScope project. Why table then? Since historically, most CityScope instances were composed of a mesh between a physical table-top 3D model of a city, augmented with projections, software, and other interface hardware. So a table => project.What is an indicator? An indicator is the result of running a module for CityScope. Indicators work by listening for updated from the CityScope table they are linked to, calculating some values by using a model, some function of the data, or a simulation, and then post the result of the calculations to CityIO to be displayed in the table.What are the types of indicators you can build? Indicators can be anything that could be displayed on a CityScope table, including the supporting screens associated to it. For the purpose of this library, we distinguish three types of indicator: numeric, heatmap, simulation.Numeric: Numeric indicators are just a number or set of numbers. They are usually displayed in a chart (bar chart, radar chart, etc) next to the table. The most common numeric indicator are the numbers that go in the radar plot, which display information about density, diversity, and proximity.Heatmap: These indicators are geodata. They are made up of geometries (points, lines, or polygons) and properties associated to them. These indicators are displayed as layers directly on the CityScope table.Simulation: These type of indicators are also displayed on the table but they are the result of an agent based simulation and are therefore displayed as a dynamic layer. They change over time like a short movie. These are not yet supported by this library.InstallationBrix is now on pip. Just do:pip install cs-brixTutorialsThis module also contains a set of other useful functions that integrate withbrix.Handlerandbrix.Indicator.The functionsbrix.get_OSM_geometries()andbrix.get_OSM_nodes()help you get data from Open Street Maps for your table.Auto-updates of GEOGRIDDATABrix also has the capability of automatically updating GEOGRIDDATA. For simple one-time updates, follow the documentation ofbrix.Handler.update_geogrid_data(). To use this feeature, you first need to define a function that takes abrix.GEOGRIDDATAas an input. When used withbrix.Handler.update_geogrid_data(), this function can take any number of keyword arguments. The following example raises the height of all cells by 3 units:def add_height(geogrid_data, levels=1):
        for cell in geogrid_data:
                cell['height'] += levels
        return geogrid_data

H = Handler('dungeonmaster', quietly=False)
H.update_geogrid_data(add_height,levels=3)Brix also supports GEOGRIDDATA updates everytime there is a registered user interaction in the front end. To add a function to the update schedule, usebrix.Handler.add_geogrid_data_update_function(). This has the limitation that your update funcion cannot take in any arguments other. If this limitation proves too restrictive, please submit an issue and we’ll consider pushing an update.The following example updates the whole grid to Light Industrial use everytime there’s a user interaction:def update_g(geogrid_data):
        for cell in geogrid_data:
                cell['name'] = 'Light Industrial'
        return geogrid_data

H = Handler(table_name,quietly=False)
H.add_geogrid_data_update_function(update_g)
H.listen()The updates triggered bybrix.Handler.listen()follow the following order:get GEOGRIDDATArun all GEOGRIDDATA updates using the result of 1 as inputget the new GEOGRIDDATAupdate all indicators using the GEOGRIDDATA object resulting from 3Creating a table from pythonBrix provides a class for creating spatial grids for CityScope projects:brix.Grid_makera subclass ofbrix.Handler.For most use cases, you will create your table using the web-app editor foundhere. For more complex projects, you might need to create your own table from an existing dataset. For example, you might want to select the grid area using a polygon defined in a shapefile. The tools we highlight here can be use for this purpose.The first step is to instantiate the class by defining the location of your table and its name. The lat,lon provided to thebrix.Grid_makerconstructor correspond to the top left corner of the grid (North-West).from brix import Grid_maker
table_name = 'dungeonmaster'
lat,lon = 42.361875, -71.105713
G = Grid_maker(table_name, lat, lon)If the table already exists, you can either usebrix.Handler.delete_table()to delete it or wait to be prompted if you want to rewrite it. You can check if the table exists by usingbrix.Handler.is_table(). Please note that sincebrix.Grid_makeris a subclass ofbrix.Handler, most functions available for abrix.Handlerobject are also available for abrix.Grid_makerobject. The table constructor also allows you to specify the cell_size, the nrows and ncols, as well as other parameters.Once the grid maker object has been instatiated, we set the grid by runningbrix.Grid_maker.set_grid_geojson():G.set_grid_geojson()This will create the geojson that will be posted to CityIO to create the table. You can check the object by usingbrix.Grid_maker.get_grid_geojson().The next step is to define the cell types that the user will be able to choose frorm. Defining the necessary types and the properties of each type is a very complex process that involves data collection and analysis as well as community engagement and simulation that is beyond the scope of this tutorial. The default table created with the Grid constructor only contains a simple type called Default. To see this, you can usebrix.Grid_maker.grid_types(). If you wish to change this, you can usebrix.Grid_maker.edit_types(). This function will either take a json-like object (dict of dicts) with the name of the type as the key, or a list of names of types that will be automatically completed with default values. Once the types have been defined, they can be expressed in the following way, adding as many properties as needed by your table:{
        'Default': {
                'color': [0, 0, 0],
                'height': 0,
                'interactive': 'Web',
                ...
        },
        ...
}The bare minimum properties that need to be defined are color, height, and interactive. If not provided, brix will assign them automatically.The following line of code replaces the Default type by there other cell types callsed Type 1, Type 2, and Type 3, letting brix assign the color to each of them.G.edit_types(['Type 1','Type 2','Type 3'])For most applications, you will want to turn off some of the cells and make them non-interactive. Usually, this will involve a shapefile or a geojson that contains the polygon that defines the interactive part of the table. If you have a Shapely polygon stored in poly you can set the non-interactive cells by usingbrix.Grid_maker.set_noninteractive():G.set_noninteractive(poly)The final step is to commit the grid to CityIO. Usebrix.Grid_maker.commit_grid():G.commit_grid()Putting it all together:from brix import Grid_maker
table_name = 'dungeonmaster'
lat,lon = 42.361875, -71.105713
G = Grid_maker(table_name, lat, lon)
G.set_grid_geojson()
G.edit_types(['Type 1','Type 2','Type 3'])
G.set_noninteractive(poly)
G.commit_grid()Alternatively, you can use poly as an argument tobrix.grid_from_poly(). This function will calculate the location and the cell size based on the given polygon, and set the non-interactive parts. The following block of code achieves the same as the block above:from brix import Grid_maker, grid_from_poly
table_name = 'dungeonmaster'
G = grid_from_poly(table_name, poly)
G.edit_types(['Type 1','Type 2','Type 3'])
G.commit_grid()Testing your moduleTo automatically test your module, this library provides thebrix.Userclass that simulates the behavior of a user interacting with your grid. This user runs in its own new thread to free up your main thread so that you can keep wokring on your indicator.The following example consists of abrix.Handlerthat contains a diversitybrix.Indicatorthat reponds to the updates of thebrix.User:from brix import Handler
from brix.examples import Diversity
from brix.test_tools import User
table_name = 'dungeonmaster'
U = User(table_name)
H = Handler(table_name,quietly=False)
div = Diversity()
H.add_indicator(div)
U.start_user()
H.listen()