udst / developer Goto Github PK
View Code? Open in Web Editor NEWRedesigned UrbanSim developer/pro forma models
Home Page: https://udst.github.io/developer/
License: BSD 3-Clause "New" or "Revised" License
Redesigned UrbanSim developer/pro forma models
Home Page: https://udst.github.io/developer/
License: BSD 3-Clause "New" or "Revised" License
The types of parking configurations, as well as their square footage and cost, are configurable in the SqftProFormaConfig
object. See docstrings for those pieces here.
As explained in the docstrings, these three set parking types are hardcoded in several places in the SqftProForma
code. Examples here and here.
We should explore whether it makes sense to fully parameterize and expose these functionalities to be configurable, or to leave them as three rigid types that must be selected from. If the former, we need to develop a thoughtful specification for the parking configuration - perhaps a new config object.
Aggregate parcels and execute ProForma into this new (bigger) development site to look for increased profitability -in comparison to that of original parcellation-.
Input
Output
SqftProForma class has max_retail_height and max_industrial_height attributes; these should be generalized to a max_height
attribute which is a dictionary, e.g.:
max_height = {"retail": 2, "industrial": 2}
(Suggestion by @hanase)
The important output of this system is how many new developments are built in a given simulation year. Currently, this is determined through two models:
In real life, how much development happens in a given year is more influenced by individual developers' decision making (i.e. profitability) than is reflected in the model. There are indeed development caps and other regulations that influence how much development happens, but a supply/demand equilibrium really should be the primary mechanism. And this shortcoming of the model is because there exists no feedback loop that provides information about building supply absorption back into the feasibility calculation.
The basic steps we need are:
What is absorption? (from Real Estate Market Analysis, page 20):
The pace at which the proposed project will be able to lease or sell space. Depending on the property type, the absorption rate could be expressed as:
A useful set of absorption related metrics for urbansim would be:
As noted above, it will be useful to disaggregate absorption into uses: residential, office, industrial, etc. Residential and non-residential absorption will have to be calculated separately at the very least. The time period over which absorption is calculated is also important: this should be user-specified, but a good range would be 3-5 years.
Square footage is an easier unit than "units" or "job spaces" for now, since that's what the developer and pro forma models use.
Implementation, for every simulation year:
Save absorption for every simulation year. Feasibility step can decide which records to use.
Absorption for all previous simulation years is now an input. The current calculation of projected building revenue is as follows:
building_revenue = (building_bulks *
(1 - parking_sqft_ratio) *
self.building_efficiency *
df.weighted_rent.values /
self.cap_rate)
The simplest intervention is to subtract some amount from this:
building_revenue = (building_bulks *
(1 - parking_sqft_ratio) *
self.building_efficiency *
df.weighted_rent.values /
self.cap_rate)
# calculate absorption discount
building_revenue -= absorption_discount
How absorption_discount
is generated from the absorption table can be an injected function, similar to the "profit to percentage" function in the developer model. One simple calculation could be:
absorption_years
)absorption_discount = self.cap_rate * building_revenue * absorption_years
The number of developments that get built are determined in the developer model.
Currently, the rule is:
New logic should look like this:
The absorption calculation should be built out into a more generalized market analysis module that includes other calculations, and which interfaces with feasibility in different ways.
Need more clarification.
From Discourse:
Market analysis to reflect initial phases of assessment of market feasibility within local market areas will be introduced as part of the real estate development model flow.
Idea is to filter parcels with some initial, crude metrics to scale the problem down before running it through the core calculations.
As part of reengineering of core SqftProForma calculations, keep in mind that we would like to eventually extend functionality to include cash flow calculations. See #1 .
Looking at parking_rates
and sqft_per_rate
among other params emerges the following question:
Why if parcel_sizes
can use imperial and metric measure units the other parameters are fixed to the former? Maybe units could be considered imperial if not specified (default) and metric if some flag param exists.
Maybe not a top priority but could we consider this mainly to be able to use ProForma module outside countries that use imperial system.
As a modeler, I should be able to use the developer model in a consistent manner with other urbansim models. Consistent with #10.
Current workflow is as follows:
dev = developer.Developer(feasibility.to_frame())
target_units = dev.\
compute_units_to_build(len(agents),
buildings[supply_fname].sum(),
target_vacancy)
new_buildings = dev.pick(forms,
target_units,
parcel_size,
ave_unit_size,
total_units,
max_parcel_size=max_parcel_size,
drop_after_build=True,
residential=residential,
bldg_sqft_per_job=bldg_sqft_per_job)
if year is not None:
new_buildings["year_built"] = year
if form_to_btype_callback is not None:
new_buildings["building_type_id"] = new_buildings["form"].\
apply(form_to_btype_callback)
all_buildings = dev.merge(buildings.to_frame(buildings.local_columns),
new_buildings[buildings.local_columns])
sim.add_table("buildings", all_buildings)
I would like to make this consistent with calls to other urbansim models in utils.py
, such as hedonic_simulate
. The function could look something like this:
cfg = misc.config(cfg)
feasibility = orca.get_table('feasibility').to_frame()
buildings = orca.get_table('buildings').to_frame()
new_buildings, all_buildings = developer.pick(feasibility, buildings, cfg)
orca.add_table('buildings', all_buildings)
Very similar to #10. Essentially moving all these steps into the Developer class. A couple of specifics:
pick()
method should be moved into a add_new_buildings()
method that takes the results of pick
and registers new buildings.run_developer
function in utils.py
should become YAML config variables.I just finished another full run of our model. I got a lot of warnings of the form
A value is trying to be set on a copy of a slice from a DataFrame
Hear they all are each with some context. Hope we can get them fixed. :-)
. . .
Running step 'feasibility'
/home/da/udst/developer/developer/sqftproforma.py:1077: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame
See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy
self.fars > self.max_industrial_height] = np.nan
/home/da/udst/developer/developer/sqftproforma.py:1074: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame
See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy
self.fars > self.max_retail_height] = np.nan
. . .
Running step 'residential_developer'
Number of agents: 1,875,553
Number of agent spaces: 2,047,607
Current vacancy = 0.08
Target vacancy = 0.20, target of new units = 296,834
235,185 feasible buildings before running developer
/home/da/udst/developer/developer/develop.py:312: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy
df["ave_unit_size"] = self.ave_unit_size
/home/da/udst/developer/developer/develop.py:313: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy
df["parcel_size"] = self.parcel_size
/home/da/udst/developer/developer/develop.py:314: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy
df['current_units'] = self.current_units
Sum of net units that are profitable: 118,252
WARNING THERE WERE NOT ENOUGH PROFITABLE UNITS TO MATCH DEMAND
Adding 16,311 buildings with 119,857 residential_units
218,874 feasible buildings after running developer
/home/da/udst/urbansim_parcels/urbansim_parcels/utils.py:785: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy
drop_buildings['year_demo'] = orca.get_injectable('year')
Unplaced households before: 75873
/home/da/udst/urbansim_parcels/urbansim_parcels/utils.py:805: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame
See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy
agents.building_id[displaced_agents] = -1
Unplaced households after: 77144
Unplaced jobs before: 59063
Unplaced jobs after: 69705
. . .
Running step 'hlcm_simulate'
There are 2155293 total available units
and 1875553 total choosers
but there are 1 overfull buildings
for a total of 365531 temporarily empty units
in 201824 buildings total in the region
/home/da/udst/urbansim/urbansim/models/dcm.py:1846: VisibleDeprecationWarning: using a non-integer number instead of an integer will result in an error in the future
replace=False)
Assigned 85292 choosers to new units
Total currently unplaced: 499
and there are now 279740 empty units
and 1 overfull buildings
Time to execute step 'hlcm_simulate': 10.08 s
Running step 'elcm_simulate'
There are 1489792 total available units
and 592082 total choosers
but there are 36135 overfull buildings
for a total of 1264093 temporarily empty units
in 15248 buildings total in the region
Assigned 51493 choosers to new units
/home/da/anaconda2/lib/python2.7/site-packages/pandas/core/indexing.py:465: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy
self.obj[item] = s
Total currently unplaced: 0
and there are now 949203 empty units
and 36135 overfull buildings
We are using
urbansim_parcels: 7078ca1d01c215778fe4e635f56c2e32b3c143ef
developer: b3bd8b3
I changed my mind on some of the changes I incorporated in #25. I would like to implement the following changes:
agents
, buildings
, supply_fname
, and target_vacancy
should not be attributes of the Developer
object. I think these should be handled in the parcel model. I brought them into the object as part of #25 because they are arguments to the compute_units_to_build
method. This brings me to...compute_units_to_build
method should be moved out of the developer module into the parcel model. It's not dependent on any data actually inside the Developer
object, and is purely an operation on model data.merge
method shouldurbansim_parcels
) should handle all of the data operations, including the previous two methods. Maybe there's a good reason why Fletcher kept them in the Developer
object? Maybe not.remove_developed_buildings
and unplace_agents
should also be moved out of the Developer
object. They are only acting as pass-throughs to be called at a later point in the parcel model, and were moved into the Developer
object so that they could be cleanly included in the YAML config. I think that they should be put back into the run_developer
step in the parcel model as arguments, and taken out of the config altogether.These changes also require updates to unit tests and helper methods.
Thus, Developer
object attributes are distinguished from parameters passed to Developer.pick()
as such:
settings.yaml
or res_developer.yaml
, or are otherwise likely to be default values, are object attributes.pick
method rather than be saved as object attributes.We can add a very simple financing mechanism to the pro forma model. The pro forma model that Jessica Hitchcock shared with us and presented in class provides a good example.
Each of these can be added as config items (they would go in proforma.yaml, values for Santa Cruz example development in parentheses):
And other variables can be calculated and factored into the profit calculation in the lookup method:
The total financing cost is added to the total development costs, and then the calculation proceeds as usual. The way Jessica calculates profit is exactly the same as how pro forma calculates it, so I think this approach would work well.
I think this provides some helpful levers on the financing side, e.g. how do interest rates affect development?
@conorhenley would love any feedback.
As an urbansim Developer object, I want to be able to make a decision on whether to build a project or not based on an internal rate of return or (given a discount rate) a net present value.
We should also expose the IRR/NPV figure to the end user.
The feasibility model expects users to set parcel_sizes in the yaml file (default is 10000). A comment in the code claims that the value does not matter because it cancels out in the pro-forma computation. This is true for some of the pro-forma measures. However, this settings influences the construction time and hence the profit. Here is more detail.
Probably an easy fix would be to keep the construction time on the per-sqft scale and then multiply it by the real parcel size in _lookup_parking_cfg()
.
Read in user-configured projects: these would be rules for how to split/aggregate/pass specific parcels into development sites, then combine development sites into a development project.
As a modeler, I should be able to use the pro forma model in a consistent manner with other urbansim models.
Currently, the workflow looks like this:
pf = sqftproforma.SqFtProForma()
df = parcels.to_frame()
# add prices for each use
for use in pf.config.uses:
df[use] = parcel_price_callback(use)
# convert from cost to yearly rent
if residential_to_yearly:
df["residential"] *= pf.config.cap_rate
d = {}
for form in pf.config.forms:
print "Computing feasibility for form %s" % form
d[form] = pf.lookup(form, df[parcel_use_allowed_callback(form)])
far_predictions = pd.concat(d.values(), keys=d.keys(), axis=1)
sim.add_table("feasibility", far_predictions)
I would like to make this consistent with calls to other urbansim models in utils.py
, such as hedonic_simulate
. The function could look something like this:
cfg = misc.config(cfg)
df = parcels.to_frame()
feasibility = proforma.lookup(df, cfg)
orca.add_table('feasibility', feasibility)
This has the dual benefit of simplifying the function call to the core model, and making the workflow more consistent with other urbansim models.
For now, this simply requires moving these steps from utils.py
into the SqftProForma
lookup method. New parameters to add to the configuration options are:
parcel_filter
residential_to_yearly
simple_zoning
Refactoring will be considered in the v0.1.1 milestone.
The current San Francisco example in urbansim_parcels doesn't yet have a pro forma YAML file to load configs from (it's loading using the from_defaults
method of the SqFtProForma
class). I need to create and test.
Just like with #12, we should move to YAML configurations, like other urbansim models use. Specifically (these are copied from #12):
from_yaml
class method to instantiate Pro Forma objects from YAML, like this. Make sure the option to read directly from string (instead of file or buffer) is included.to_yaml
class method, which depends on a to_dict
method, like this.lookup_from_config
method to wrap a lookup
method for YAML, like thisInput
Output
Currently, the developer workflow in the parcel model decides how many buildings to build based on numbers of target units and job spaces that are determined by vacancy rate. The user sets a desired vacancy rate, and the target number is generated from that. This isn't particularly realistic and we should eventually try to move toward ROI (return on investment) as the main control for how many buildings get built. This requires some feedback loops involving absorption rates, vacancy, etc.
This is a longer-term project that will hopefully get easier once we build out the new developer workflow.
Currently doesn't have a method similar to predict_from_cfg that distinguishes between filename and YAML string. Thus in urbansim_parcels, we're currently loading the YAML string which is a little inconsistent with the rest of the model system.
As a modeler, I want to be able to run parcel-level simulations in the same or less amount of time as with the previous version of the pro forma/developer modules.
My plan is to simply:
simulate.py
from sanfran_urbansimsimulate.py
from urbansim_parcels/sf_exampleAnd compare the times. @conorhenley would like to hear any thoughts for other speed benchmarks that would be useful.
The continuous integration script for this repository includes running some code from urbansim/urbansim_parcels
. That repo is private, and Travis is no longer able to install it now that the developer library has been moved to UDST.
This is the line that fails in Travis:
https://github.com/UDST/developer/blob/master/.travis.yml#L26
I'm not too familiar with how Travis works, but it looks like we might be able to fix this by generating a new deploy key. For now, I'm disabling that part of the continuous integration script so that we can continue running the unit tests on their own.
Reference:
https://docs.travis-ci.com/user/private-dependencies/
Simulation runs sometimes error in this line, with the max_profit
column not found. I think this is because there are no profitable developments passed into the module, but we need a better way of handling these edge cases systematically.
From Discourse:
Capacity to evaluate trade-offs such as increasing density bonuses to offset inclusionary zoning requirements and their effect on project feasibility.
As a modeler, I want to be able to generate a range of feasibility results for each parcel, based on random draws of distributions of input values, rather than a single estimate.
Uncertainty analysis will be added using Monte Carlo Simulation to provide a distribution of results rather than a single estimate.
As SEMCOG, I want to be able to control the types of buildings that get developed in a parcel level simulation, so that building types are more predictable in later processes like household allocation.
From email:
Exiting proforma model assigns new development with random building types. For example, for residential development, SF, MF and Condo buildings are randomly assigned to the new constructed buildings. This could cause some problem in later stage of model run if building types are used in the household allocation or other process. Therefore, it would be preferable to have some logical way to assign building types instead of random. At this stage we are not quite sure what the best practice to assign building types and if it is a problem to assign building types based purely on new building characteristics.
As SEMCOG, I want to make sure parcel level simulations don't develop single use buildings on land zoned for mixed use. We need to reproduce this behavior. See email.
As MAG, I want to input a pipeline of known developments (with uncertain information about start date) and integrate them into a simulation with controls or limits on how much of a project can develop in a single year.
Default settings for the Pro Forma model are currently set up as attributes of the SqftProFormaConfig
object. Customization to these settings would involve passing a separate instance of the above object, like in SEMCOG's code here.
We should move to YAML configurations, like other urbansim models use. Specifically:
from_yaml
class method to instantiate Pro Forma objects from YAML, like this. Make sure the option to read directly from string (instead of file or buffer) is included.to_yaml
class method, which depends on a to_dict
method, like this.lookup_from_config
method to wrap a lookup
method for YAML, like thisSpecifically, only_built
, parcel_filter
, residential_to_yearly
, forms_to_test
, pass_through
, and simple_zoning
seem to be missing from the class method. SqFtProForma.get_defaults() appears to be fully specified, so just making sure there's parity between these two functions should do the trick.
Method SqFtProForma.check_is_reasonable
should be parameterizable or at least toggleable.
We should consider some use cases:
Add ability update housing prices (or other housing market conditions) to REMI projected per capita income (or other indicators) over the course of a simulation, to more accurately simulate a rapidly changing housing market. (See SEMCOG email)
Latest in wiki.
This is a high-level design proposal meant for discussion and review. I've tagged this and other such issues with the label Type: Proposal
. These are not meant to be treated as user stories or handled in the GitHub project workflow. Everything in here needs to be broken down into a user story for development.
See "proposed workflow" below for details.
pipeline
table, which persists across model years.pipeline
table, site-by-site.Here I'll try to summarize the current workflow that utilizes the proforma
and developer
models. Feel free to skip to the proposed workflow below. I'm using the model names from the urbansim_parcels
repo's models.py
.
Generates a table of parcels with some metrics about development feasibility, like profitability.
parcels
tableparcel_id
In this model, each parcel represents the possible development (or redevelopment) of one building, and each parcel's feasibility is analyzed as such.
Decides which buildings get developed, based on the outputs from the feasibility step.
feasibility
, some demand-side parameters to determine how many units to buildHere are all of the tables involved:
A new ProjectCreator
model takes in the parcel table and pipeline (empty in year 1), and generates development projects and development sites.
parcels
, pipeline
, configsdevelopment_projects
, development_sites
, project_feasibility
The project creator performs these steps:
parcel_candidates
tableparcel_candidates
development_projects
and development_sites
tablesProjectProForma
model (below) and append results to project_feasibility
parcel_candidates
parcel_candidates
through the Splitter
functiondevelopment_projects
and development_sites
ProjectProForma
has been run. Append results to project_feasibility
Aggregator
function.development_projects
and development_sites
The Splitter
function should take in parcels and if they qualify under some criteria (probably it's larger than a maximum parcel size), run an algorithm to determine the "best" split. One possible algorithm is:
ProjectProForma
.ProjectProForma
so it can be appended to project_feasibility
The ProjectProForma
model takes a development project as an input, runs sqftproforma
on every development site in the project, and aggregates results up to the project level. This requires some thoughtfulness about aggregation rules (should we just add up max_profit
?).
Runs sqftproforma model for projects with only one development site, and combines results with the project_feasibility
table from the previous step.
development_projects
, project_feasibility
, configsfeasibility
Unlike the existing workflow, this step performs analysis on development sites as units, rather than parcels. Steps are:
development_projects
into projects_to_analyze
project_feasilibility
(precalculated from previous step) from projects_to_analyze
sqftproforma
as usual on projects_to_analyze
, output feasibility
project_feasibility
to feasibility
Decide which development projects get pushed into the pipeline, based on the outputs from the feasibility step.
feasibility
, some demand-side parameters to determine how many units to build, configsThere is not much change in the Developer model itself, except use development sites instead of parcels. It does this:
feasibility
A new PipelineAdder
step should append development sites to the pipeline
table. This may be a function we simply want the developer
model to handle, but there may end up being some more complicated rules regarding how we add to the pipeline.
pipeline
, development_projects
, development_sites
pipeline
Steps:
pipeline
A new Constructor
model "constructs" development sites in development projects in the pipeline
. These are then added to the buildings
table.
pipeline
, buildings
pipeline
, buildings
At this point, pipeline
is a list of development projects, and each row has information on the status of development sites within the project. Steps:
buildings
pipeline
buildings
pipeline
We can add in logic to delay or cancel projects as well. pipeline
and buildings
persist across simulation years. Everything else is reset.
Begin on a model class for market research. This should include functionality for:
I'm confused about why fars
gets filtered by the heights
variable in this line in the pro forma model.
heights
is a copy of the height column in the dev_info
reference table. It's calculated from the FAR based on a parcel size of 10000 (the default value passed to parcel_sizes
)max_height
value for the parcels actually being testedmax_height
should be compared to the height generated from the actual parcel size, not the default 10000.This might be working correctly but I want to come back to this for clarification. This shows up in my example for class, in the 'surface' loop of _lookup_parking_cfg
.
Add ability to use velocity function to control the speed at which large developments get developed in a parcel model, in order to reduce volatility related to large changes of local household counts in one year. See SEMCOG email.
From Discourse:
Methods to speed up the search over feasible project configurations, and make this search 'smarter'.
This search has several parts:
SqftProForma
object, generate a dictionary of DataFrames (one for each (form, parking configuration) pair. Each DataFrame is a lookup table that takes into accounts the various configurations and costs.lookup
method.This is an open-ended issue. It seems like there may be some good ways to improve this search and reduce the brute-force complexity, but we haven't diagnosed specific problems, and we are hoping you can take a deeper look and consider possible solutions.
There is the same bug as in the public version of the model: When passing all forms (i.e. forms=None) into the developer model, the max profit is not computed. It's in _get_dataframe_of_buildings.
I submitted a PR fix for the previous version a while ago (still open):
UDST/urbansim#194
I probably cannot do a PR on a private repository without forking it to a public repository, so I won't.
This method should receive a list of parcels and pipeline projects and remove all parcels who are part of an active project.
Input
Output
This is partly an issue here, partly in the parcel model, but we should reconsider the print functions throughout the pro forma and developer steps in both places. They need to provide the most useful feedback possible about what's happening and whether the models are properly responding to adjustments.
Goals we stated before are:
I've made some progress on this refactoring already, but figured I'd write this up here as well to stick with the process. The first step for better maintainability/readability is to bring much of the core functionality out of the SqftProForma
class altogether. I've created new classes for:
_generate_lookup
method, but I wanted to distinguish names between this reference table and the actually "lookup" process that takes parcels are returns the most profitable configuration).I keep the original SqftProForma
for its loading and saving methods, and use it as a facade pattern to call the other stuff. This is a pretty simple use case for a facade but I think it makes it easier to read.
As a parcel-level simulation, I want to be able to split up large developments into sub-developments and evaluate the feasibility of these sub-developments on distinct timelines, to more realistically simulate large projects.
This has been requested several times. See Paul's explanation on Discourse:
Unlike the current spot pro forma, iIt will be multi-period in its design, enabling larger projects to be scheduled over multiple periods, and incorporating time-dependent costs and revenue expectations to be reflected in the ROI calculations, which will more appropriately reflect the risk - reward profile of large projects.
The entire package should be compatible with at least Python 3.5, and we should add to Travis builds. We may want to further build out unit tests and add a code coverage tool before we do this.
As a parcel-level simulation, I want to maintain a list of active development projects so that they can be completed, delayed, or cancelled depending on conditions in a simulation year.
Given that year_built
will be assigned by the parcel model, I think it might make sense to remove the assignment in this line.
I'm proposing changes to the Developer
class similar to what was implemented in PR #26. This would split the pick()
method out of the Developer
class into its own class (called DevelopmentPicker
or something like that). This would make the developer module consistent with the pro forma module, where:
Developer
or SqFtProForma
) read the model config, contain methods for IO, and wrap the core functionality.SqFtProFormaLookup
or DevelopmentPicker
).As part of these changes I would also refactor the DevelopmentPicker.pick()
method by breaking it up into smaller helped methods where appropriate.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.