Giter Club home page Giter Club logo

gghdx's Introduction

gghdx

R-CMD-check Codecov test coverage

Overview

The goal of gghdx is to make it as simple as possible to follow the HDX visual guidelines when creating graphs using ggplot2. While most of the functionality is in allowing easy application of the HDX color ramps, the package also streamlines some of the other recommendations and best practices regarding plotted text, axis gridlines, and other visual features. The key functionalities are:

  • theme_hdx() is the general package theme.
  • scale_color_hdx_...() and scale_fill_hdx_...() applies the HDX color scale to the relevant aesthetics.
  • hdx_colors(), hdx_hex(), and hdx_pal_...() provide easy user access to the HDX color template. You can view the colors
  • geom_text_hdx() and geom_label_hdx() wrap the respective base functions to plot text using HDX fonts and aesthetics.
  • scale_y_continuous_hdx() wraps scale_y_continuous() to plot data directly starting from the y-axis.
  • gghdx() ensures plot for the session use HDX defaults for color and fill scales, uses theme_hdx() for all plots, and applies scale_color_hdx_...() and scale_fill_hdx_...()
  • label_number_hdx() and format_number_hdx() supplement the scales::label_...() series of functions to format and create labels for numbers in the HDX style.

Installation

You can install gghdx directly from CRAN:

install.packages("gghdx")

You can install the development version from GitHub:

## install.packages("remotes")
remotes::install_github("OCHA-DAP/gghdx")

Using the package

The package is designed so the user just has to run gghdx() once a session and mainly forget about it. This will automatically set your ggplot2 to use the HDX theme, palettes, fonts, and more by default. If you want more control or want to better understand how the package works, please see the details below!

Theme

A quick and simple example would be plotting the iris dataset included in base R.

library(ggplot2)

p <- ggplot(
  iris,
  aes(
    x = Sepal.Length,
    y = Petal.Length,
    color = Species
  )
) +
  geom_point() +
  labs(
    title = "Iris species distributed by sepal and petal lengths",
    y = "Petal length",
    x = "Sepal length"
  )

p

This output using the base ggplot style doesn’t look particularly bad, but we can use theme_hdx() to quickly adjust some of the styling to fit the style guide.

library(gghdx)

p + theme_hdx(base_family = "sans")

Now, axis lines have been cleaned up and the plot better resembles recommendations from the visual guide with just that single line of code.

Color palettes

However, the color palette for the points is still using the base R palette. We can use one of the many scale_...hdx() functions to use HDX colors. Let’s just use the primary discrete color scale that will align each species with one of the 3 non-gray colorramps (sapphire, mint, and tomato).

p + theme_hdx(base_family = "sans") + scale_color_hdx_discrete()

You can check the documentation of any of the scale_...hdx() functions to see all available scales, or directly access the colors using hdx_colors() or the raw list in hdx_color_list. The available palettes can be easily visualized using hdx_display_pal().

Adding fonts

We also would like to use the HDX font family. Since Source Sans 3 is a free Google font, it makes it relatively easy to access in R. gghdx uses the sysfonts package to load the Google font and then showtext to include them in our plot. You can also use the extrafont package as an alternative if you have the font installed locally. This requires ghostscript to be installed locally and can run into other issues, such as font names not being found.

Below, I use the showtext package because it’s simpler.

library(showtext)
#> Loading required package: sysfonts
#> Loading required package: showtextdb

font_add_google("Source Sans 3")
showtext_auto()

p + theme_hdx(base_family = "Source Sans 3") + scale_color_hdx_discrete()

Streamlined plotting

As clear above, even though we have an HDX theme function, we still have to separately call the scale function to adjust our colors. And we have to call these every time we make a new plot. So, to make life simpler, gghdx() is provided as a convenience function that sets ggplot to:

  • automatically use the HDX theme by default;
  • use default HDX sapphire for point and line colors and and HDX mint for fill when not an aesthetic;
  • use scale_fill_hdx_discrete() and scale_color_hdx_discrete() as the default discrete fill and color respectively;
  • use scale_fill_gradient_hdx_mint() and scale_color_gradient_hdx_sapphire() as the default continuous fill and color;
  • loads the Source Sans 3 font from Google and activates its usage for the current session.

You just have to run gghdx() once a session, and then our plots will already be where we would like!

gghdx()
p

And voíla, we have our graph without specifying the theme or color scale.

COVID plots

As a final example, we can closely match the COVID plots referenced in the visual guide using the theme and color scales in the package.

The inbuilt data gghdx::df_covid has aggregated COVID data we can use to mirror this plot. To make the data start at the y-axis, we can use scale_y_continuous_hdx() which sets expand = c(0, 0) by default, and the label_number_hdx() function to create custom labels.

p_blue <- ggplot(
  df_covid,
  aes(
    x = date,
    y = cases_monthly
  )
) +
  geom_bar(
    stat = "identity",
    width = 6,
    fill = hdx_hex("sapphire-hdx") # use sapphire for fill
  ) +
  scale_y_continuous_hdx(
    labels = label_number_hdx()
  ) +
  scale_x_date(
    date_breaks = "1 month",
    labels = function(x) toupper(strftime(x, "%b"))
  ) +
  labs(
    title = "Monthly global COVID-19 confirmed cases in 2020",
    subtitle = "DATA | JUL 2022 | World Health Organization",
    x = "",
    y = ""
  )

p_blue

# create red plot
p_blue +
  geom_bar(
    aes(
      fill = flag
    ),
    width = 6,
    stat = "identity"
  ) +
  scale_fill_hdx_tomato() +
  theme(
    legend.position = "none"
  ) +
  labs(
    title = "Monthly COVID-19 # of cases surpasses 8 million"
  )

We’ve used relatively few lines of code to match fairly closely these examples plots!

gghdx's People

Contributors

caldwellst avatar pre-commit-ci[bot] avatar teunbrand avatar

Stargazers

 avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

gghdx's Issues

Move to ragg

{ragg} is the modern text package for R that we should shift to, which solves issues of translating text/glyph sizes to pixels. Follow implementation in {thematic}

Feature Request - `RColorBrewer::brewer.pal()` equivalent

RColorBrewer::brewer.pal() is one of the palette functions I tend to use most.

Would be cool to have an equivalent where you just specify n and palette name and the hex codes are returned. I see hdx_pal(), but doesn't look like it's designed the same way.

Also an accompanying equivalent to RColorBrewer::display.brewer.all() would be awesome eventually

Dependency issues building package from scratch

I'm trying to follow these instructions and build this package locally by:

  1. Cloning the repo
  2. Opening the project in RStudio
  3. ctrl + shift + b

But get the following error:

* installing to library '/Library/Frameworks/R.framework/Versions/4.3-arm64/Resources/library'
ERROR: dependencies 'dplyr', 'ggplot2', 'ggthemes', 'magrittr', 'purrr', 'rlang', 'showtext', 'sysfonts', 'tibble' are not available for package 'gghdx'
* removing '/Library/Frameworks/R.framework/Versions/4.3-arm64/Resources/library/gghdx'

Exited with status 1.

I have a very fresh R install, so wondering if some of these dependencies need to be defined somewhere? Problem can be resolved if I manually install each package.

`scale_fill_ordinal_hdx()`

just came across ggplot2::scale_fill_ordinal() which seems pretty nifty esp if comparing leadtime distributions. Therefore, adding it to the wish-list

system font error on `theme_hdx()`

gghdx was working great on my Windows, but just tried it on a mac and it looks like there is a font related error being thrown from theme_hdx() ?

I'm guessing there is some system fonts package I had installed on the other computer, but not this one? If so, perhaps it should be a dependency?

reprex below:

library(tidyverse)
library(gghdx)

# Create data
age <- c(25, 30, 35, 40, 45, 50, 55, 60, 65, 70)
gender <- c("male", "female", "male", "female", "male", "female", "male", "female", "male", "female")

# Create data frame
example_data <- data.frame(age, gender)

example_data %>% 
  ggplot(aes(x=gender,y=age))+
  geom_boxplot() +
  theme_hdx()
#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"
#> Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : no
#> font could be found for family "Source Sans Pro"
#> Error in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : polygon edge not found

warnings()

Created on 2023-01-16 with reprex v2.0.2

export for

Was utilizing this functionality in another project, and 3 small suggestions to make it more useful:

  1. export the format_number_hdx() functionality
  2. change name to number_hdx()
  3. more useful error message if user forgets a to include additional prefix... or maybe there should be no error?

I think numbers 1 & 2 would align it better to {scales} functions

format_number_hdx <- function(x, additional_prefix) {

Invisible NA values

when graphs are filled with discrete values, NA values are defaulted to the background color which makes them invisible.

library(gghdx)
library(tidyverse)

df <- read_csv("dataset.csv")
#> Rows: 38414 Columns: 16
#> -- Column specification --------------------------------------------------------
#> Delimiter: ","
#> chr (13): adm0_pcode, adm0_name, adm1_pcode, adm1_name, population_group, se...
#> dbl  (3): pin, affected_population, severity
#> 
#> i Use `spec()` to retrieve the full column specification for this data.
#> i Specify the column types or set `show_col_types = FALSE` to quiet this message.

df %>%
  mutate(
    perc_pin = pin/affected_population
  ) %>%
  ggplot(
    aes(
      y = perc_pin,
      x = sector,
      fill = factor(severity)
    )
  ) +
  geom_col(position = "dodge") +
  gghdx::scale_fill_hdx_sapphire() +
  gghdx() +
  labs(
    x = "Sector",
    y = "% of in need",
    fill = "Severity"
  )

"gghdx.rdb is corrupt"

ran devtools::install() inside the number-hdx branch and got

Error: lazy-load database '/Library/Frameworks/R.framework/Versions/4.3-arm64/Resources/library/gghdx/R/gghdx.rdb' is corrupt
In addition: Warning message:
internal error -3 in R_decompress1 

Then when run:

> library(gghdx)
Warning messages:
1: In get(name, envir = env) : internal error -3 in R_decompress1
2: In get(name, envir = env) : internal error -3 in R_decompress1
3: In get(name, envir = env) : internal error -3 in R_decompress1
4: In get(name, envir = env) : internal error -3 in R_decompress1
5: In get(name, envir = env) : internal error -3 in R_decompress1

By pressing ctrl + shift + b (devtools::build()) issue seems to resolve itself (no warnings and can load library)

Don't think the issue is specific to this package per se, as it seems like something I encountered before. I don't fully understand it, but figured i'd document as it sort of relates to #26

not playing nice with geom_raster/ geom_spatraster

just flagging an issue I found here so we can investigate further as time allows. I had originally thought it was an issue with the {tidyterra} package which is a nice convenience package for plotting spatraster objects in ggplot. However, when making a reprex to post I realized the issue disappears when gghdx() is not present. Therefore I've adapted that reprex for this repo:

library(terra)
#> terra 1.7.65
library(tidyterra)
#> 
#> Attaching package: 'tidyterra'
#> The following object is masked from 'package:stats':
#> 
#>     filter
library(tidyverse)
library(gghdx)

# recreate raster in question

# save dput output of value array
array_vals <- structure(c(NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
                          NA, 1, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
                          NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
                          NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
                          NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
                          NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
                          NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
                          NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
                          NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
                          NA, NA, NA, NA, NA, NA, 1, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
                          NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
                          NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
                          NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
                          NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
                          NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
                          NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
                          NA, NA), dim = c(17L, 15L, 1L))

# set res
resx <- 0.08333333
resy <- 0.08333333

num_rows <-  17
num_cols <-  15
xmn <- 43.08333 - 0.5 * resx
xmx <-  44.33333 + 0.5 * resx
ymn <- 2.5- 0.5 * resy
ymx <- 3.916667+ 0.5 * resy

# generate SpatExtent
r_ext <-  terra::ext(xmn, xmx, ymn, ymx)

# generate spatRaster
r <- rast(
  x=array_vals,
  extent =r_ext,
  crs= "EPSG:4326"
)

# base plot -- looks good!
r |> plot()

# ggplot (tidyterra) plot -- looks good
ggplot()+
  geom_spatraster(data=r)

gghdx() # set gghdx

# ggplot (`{tidyterra}` + `{gghdx}`) plot -- looks wrong.
ggplot()+
  geom_spatraster(data=r)

Created on 2024-04-19 with reprex v2.0.2

issue with gganimate

Check out the reprex below. I had issues with a similar error before with standard {ggplot2} when I didn't properly make the {sysfonts]/{showtext} calls:

sysfonts::font_add_google("Source Sans Pro")
showtext::showtext_auto()

Now that I know about the gghdx() function, i think the above are unnecessary, but am still getting these errors when trying to use with {gganimate]. When using the fill argument, the plot does not get generated. Without the fill argument a plot is generated, but still lots of warnings

library(tidyverse)
library(gghdx)
library(gganimate)
gghdx()

df <- data.frame(
  year = c(2010, 2010, 2010, 2013, 2013,2013, 2014,2014,2014),
  category = c("A", "B", "C", "A", "B", "C", "A", "B", "C"),
  pct_val = c(0.05, 0.12, 0.21, 0.37, 0.44, 0.53, 0.69, 0.76, 0.82)
)


df %>% 
  ggplot(aes(x=category,y=pct_val, fill=category)) +
  geom_bar(stat="identity")+
  coord_flip()+
  transition_time(year)
#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"

#> Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): no font could
#> be found for family "Source Sans Pro"
#> Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : no
#> font could be found for family "Source Sans Pro"
#> Warning: Cannot get dimensions of plot table. Plot region might not be fixed
#> Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : no
#> font could be found for family "Source Sans Pro"


#> this keeps repeating for a while

If i do it without the fill argument, the graph does still plot, but we get a similar warning

df %>% 
  ggplot(aes(x=category,y=pct_val)) +
  geom_bar(stat="identity")+
  coord_flip()+
  transition_time(year)
#> Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : no
#> font could be found for family "Source Sans Pro"
#> Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : no
#> font could be found for family "Source Sans Pro"
#> Warning: Cannot get dimensions of plot table. Plot region might not be fixed

Created on 2023-05-29 with reprex v2.0.2

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.