Git Product home page Git Product logo

Comments (15)

pfightingpolish avatar pfightingpolish commented on May 26, 2024 1

I make it work in my customized install, but I've also done a lot to differentiate my install from the base code in this project.

I'm not going to tell you it's easy, but I'll try and walk through it below.

I also can't promise you a be-all, end-all solution because mine tears apart a lot of what's in the 128x64 code and doesn't necessarily even try to respect other matrix sizes.

Here are some pieces that might help, though:

  • I created a new data class called "AtBat" with a file named atbat.py in the data directory that uses the newer statsapi functionality. This class gives functions to access a name for the current batter, pitcher, and on-deck and in-the-hole batters from the statsapi linescore for a given game. It also formats those names to have just have first initials and the last name, unless the last name is particularly long, then it just shows last name. There's not a lot to it, honestly:
import statsapi

class AtBat:
  def __init__(self, linescore):
    self.batter =  str(linescore.get('offense').get('batter',{}).get('fullName',{}))
    self.pitcher = str(linescore.get('defense').get('pitcher',{}).get('fullName',{}))
    self.onDeck = str(linescore.get('offense').get('onDeck',{}).get('fullName',{}))
    self.inHole = str(linescore.get('offense').get('inHole',{}).get('fullName',{}))

  def get_batter(self):
    return format_statsapi_name(self, self.batter)

  def get_pitcher(self):
    return format_statsapi_name(self, self.pitcher)

  def get_onDeck(self):
    return format_statsapi_name(self, self.onDeck)

  def get_inHole(self):
    return format_statsapi_name(self, self.inHole)

  def format_statsapi_name(self, name):
    SpcPos = name.find(" ") + 1
    playerLast = name[SpcPos:len(name)]

    if name:
      if len(playerLast) >= 9:
        return playerLast
      elif name[1] == ".":
        return name
      elif name == "{}":
        return " "
      else:
        return name[0] + ". " + playerLast
    else:
      return " "
  • I then have an "AtBatRenderer" class in its own atbat.py file in the renderers directory that utilizes the AtBat class functions and renders that data to the board on the in-game scoreboard. This draws the current batter with "AB: " in front of their name and pitcher with "P:" in front of their name.
from rgbmatrix import graphics
from utils import get_font, get_file
import json

class AtBatRenderer:
  """Renders the batter and pitcher."""

  def __init__(self, canvas, atbat, data):
    self.canvas = canvas
    self.batter = atbat.get_batter()
    self.pitcher = atbat.get_pitcher()
    self.data = data
    self.colors = data.config.scoreboard_colors
    self.default_colors = self.data.config.team_colors.color("default")
    self.bgcolor = self.colors.graphics_color("default.background")

  def render(self):

    self.batter_coords = self.data.config.layout.coords("atbat.batter")
    self.pitcher_coords = self.data.config.layout.coords("atbat.pitcher")
          
    self.__render_batter_text(self.batter, self.default_colors, self.batter_coords["x"], self.batter_coords["y"])
    self.__render_pitcher_text(self.pitcher, self.default_colors, self.pitcher_coords["x"], self.pitcher_coords["y"])

  def __render_batter_text(self, batter, colors, x, y):
    text_color = self.default_colors['text']
    text_color_graphic = graphics.Color(text_color['r'], text_color['g'], text_color['b'])
    font = self.data.config.layout.font("atbat.batter")
    batter_text = "AB: " + batter
    graphics.DrawText(self.canvas, font["font"], x, y, text_color_graphic, batter_text)

  def __render_pitcher_text(self, pitcher, colors, x, y):
    text_color = self.default_colors['text']
    text_color_graphic = graphics.Color(text_color['r'], text_color['g'], text_color['b'])
    font = self.data.config.layout.font("atbat.pitcher")
    pitcher_text = "P: " + pitcher
    graphics.DrawText(self.canvas, font["font"], x, y, text_color_graphic, pitcher_text)
  • This does require the addition of an "atbat" section to the ledcoords/w128h64.json file:
  "atbat": {
   "batter": {
     "font_name": "10x11",
     "x": 2,
     "y": 54
    },
   "pitcher": {
     "font_name": "10x11",
     "x": 8,
     "y": 63
    }
  },

Adjust your font and where you want to put the current batter/pitcher accordingly. Mine looks like this:

image

  • This also will require an import and function call in the renderers/scoreboard.py file. You will need to duplicate the
    from renderers.bases import BasesRenderer and BasesRenderer(self.canvas, self.scoreboard.bases, self.data).render() lines and replace "bases" or "Bases" with "atbat" or "AtBat" where appropriate.

  • But what about the on-deck and in-the-hole batters? They have a place, notably on the between-innings screen. In the renderers/inning.py file, I've modified the __render_inning_break function to use the "current" batter, on-deck batter and in-the-hole batter to create a "due up" screen.

  def __render_inning_break(self):
    text_font = self.layout.font("inning.break.text")
    num_font = self.layout.font("inning.break.number")
    text_coords = self.layout.coords("inning.break.text")
    num_coords = self.layout.coords("inning.break.number")
    color = self.colors.graphics_color("inning.break.text")
    text = self.inning.state
    num  = self.inning.ordinal()
    if text == "Middle":
     num_x = 19
     printtext = "Mid"
    elif text == "End":
     num_x = 24
     printtext = "End"
    graphics.DrawText(self.canvas, text_font["font"], 2, num_coords["y"], color, printtext)
    graphics.DrawText(self.canvas, num_font["font"], num_x, num_coords["y"], color, num)
    graphics.DrawText(self.canvas, num_font["font"], 2, num_coords["y"] + 13, color, "Due Up:")
    graphics.DrawText(self.canvas, text_font["font"], 55, num_coords["y"] -3, color, self.atbat.get_batter())
    graphics.DrawText(self.canvas, text_font["font"], 55, num_coords["y"] + 8, color, self.atbat.get_onDeck())
    graphics.DrawText(self.canvas, text_font["font"], 55, num_coords["y"] + 19, color, self.atbat.get_inHole())

image

Granted, I got a little lazy and hard-coded some coordinates. I mentioned I tore the code apart pretty badly without mind for making it work for different board sizes. But it's another plausible use of that data.

This is just one way to get to & use the current hitter & pitcher data. There are others. But, like I said before, I'm not sure you can get to more than just fullName. As nice as it would be to go out and get stats or the hitter's number or whatever, that's not in the linescore info, which means you have to go out and get it from a different, larger, slower table, like the player table, if you want it, and that's going to really drag your board's operation to a crawl, maybe making it sit on one game for upwards of a minute. With mine, it also flickered like the dickens while it tried to figure out what had to happen. Again, that player table is every player who's ever played in the bigs. That's a lot of data to load compared to a single game's linescore.

Anyhow, that's how I made it work. Apologies for using a sledgehammer to kill a fly, but that fly is also secretly more like a grizzly bear when you actually start to figure out how to kill it.

from mlb-led-scoreboard.

ajbowler avatar ajbowler commented on May 26, 2024

This is a good feature for 64x32.

The team score banners won't have enough room for anything else on a 32x32 and I wouldn't want to confuse the jersey numbers with the number of runs.

from mlb-led-scoreboard.

pfightingpolish avatar pfightingpolish commented on May 26, 2024

I'm not sure about number, but you can get and parse the fullName of the batter and pitcher in the new API.

I have it in the code I've forked. I set up a separate data file called atbat to handle it. I pull directly from MLB-StatsAPI.

I parse out first initial and last name. It's inelegant, but it works. I think number might be more difficult, though. You might be able to get to it by trying to link to their player database, but I found that to be a little too much for the Pi to handle without slowing down the whole process prohibitively. Remember that the player database, if I'm not mistaken, involves looking up a guy from every player who's ever played.

from mlb-led-scoreboard.

spaghettir101 avatar spaghettir101 commented on May 26, 2024

@pfightingpolish I was looking how to incorporate the batter and pitcher that is playing at that moment. Do you have the .py code or everything to make that work? i can dig on it but not that experienced. Thanks!

from mlb-led-scoreboard.

spaghettir101 avatar spaghettir101 commented on May 26, 2024

WOW thank you sooo muchhh!!!! I was working on my own way to get the atbat and was missing some things you have!! Obviously i will make it work on a 64x32 board i have but getting the batter and pitcher info is huge! Thank you again for this and your time!!!! I will tinker and understand what you did

from mlb-led-scoreboard.

pfightingpolish avatar pfightingpolish commented on May 26, 2024

Granted, my stuff above also assumes you already have some way of either translating between mlbgame and statsapi, or have fully converted all your data to statsapi, and neither is what I'd call an "easy" feat.

I think much of this project's code still runs on mlbgame, and I know my function to convert between the two is almost messy enough to make me not want to post it here. It includes what amounts to a lookup table to convert between team abbreviations from mlbgame to team IDs from statsapi. It really messes with data/data.py.

So yeah, like I say, the above are hints, but there might still be a lot of steps on your journey.

from mlb-led-scoreboard.

spaghettir101 avatar spaghettir101 commented on May 26, 2024

Ahhh so your not using mlbgame. I am using mlbgame. I dont mind using statsapi for just the hitter and pitcher. I did see thag the mlbgame does have the atbat class i can call

from mlb-led-scoreboard.

spaghettir101 avatar spaghettir101 commented on May 26, 2024

Also, for your class atbat, where you have return_statsapi_name, should i just switch that to the mlbgame return? If that makes sense? Or should i just run statsapi for just this instance of atbat and run mlbgame for everything else

from mlb-led-scoreboard.

pfightingpolish avatar pfightingpolish commented on May 26, 2024

... sooooooo the big issue with trying to go back and forth between mlbgame and statsapi is they work completely differently. And when I say completely differently, I mean completely differently.

It's been nine months since I worked on this, but I'm pretty sure I remember that getting current batter through mlbgame was either difficult or impossible. I remember trying to come up with some odd combination of adding batters faced by the pitching data in the boxscore to iterate my way through the lineup and eventually just giving up on it. Maybe there's something you found that I didn't, but yeah, it wasn't fun.

So that left me with trying to get the info from statsapi, the newer API for MLB data.

Here's the problem, though: You have to connect the mlbgame overview structure with the statsapi linescore structure. That's not easy, because you essentially have to connect a game in mlbgame, which uses an ID format of 2021_04_21_milmlb_sdnmlb_1, with a game in statsapi, which uses a numerical ID, like 634476.

Now, again, it was nine months ago, but I think I remember seeing after the fact that there's actually an mlbgame-style ID field endpoint somewhere in statsapi, but not before I went about a more convoluted way of piecing the two together in data/data.py:

  1. Parsing out the road team's abbreviation from the mlbgame ID.
  2. Using a translation function to translate the mlbgame road team abbreviation to a corresponding statsapi team ID.
  3. Using another function to handle doubleheader numbering in the mlbgame ID format.
  4. Taking the statsapi road team ID and doubleheader game number and using that in the statsapi "schedule" function to get the appropriate corresponding numeric game ID in statsapi.
  5. Then using that numeric game ID to access the linescore function in statsapi.

Here's my modification of refresh_overview() from data/data.py, along with the helper functions I added, notably the team abbreviation translation table (I love how mlbgame still refers to the Angels as "ANA"). Like I say ... not pretty, but it works.

  def refresh_overview(self):
    urllib.urlcleanup()
    attempts_remaining = 5
    while attempts_remaining > 0:
      try:
        self.overview = mlbgame.overview(self.current_game().game_id)
        self.RoadTeam = self.get_road_abbrev()
        self.RoadID = self.get_team_id(self.RoadTeam)
        self.GameNum = self.get_game_num()
        self.FunctionDate = datetime(self.year, self.month, self.day)
        debug.log("Game ID: {}".format(self.current_game().game_id))
        debug.log("Road Team: {}".format(self.RoadTeam))
        debug.log("Road ID: {}".format(self.RoadID))
        debug.log("Doubleheader Game Number: {}".format(self.GameNum))
        debug.log("Date: {}".format(self.FunctionDate))
        self.Stats_Game_ID = statsapi.schedule(datetime.strftime(self.FunctionDate, '%Y-%m-%d'), team=self.RoadID)[self.GameNum].get('game_id')
        self.linescore = statsapi.get('game_linescore', {'gamePk': self.Stats_Game_ID})
        self.__update_layout_state()
        self.needs_refresh = False
        self.print_overview_debug()
        self.network_issues = False
        break
      except URLError, e:
        self.network_issues = True
        debug.error("Networking Error while refreshing the current overview. {} retries remaining.".format(attempts_remaining))
        debug.error("URLError: {}".format(e.reason))
        attempts_remaining -= 1
        time.sleep(NETWORK_RETRY_SLEEP_TIME)
      except ValueError:
        self.network_issues = True
        debug.error("Value Error while refreshing current overview. {} retries remaining.".format(attempts_remaining))
        debug.error("ValueError: Failed to refresh overview for {}".format(self.current_game().game_id))
        attempts_remaining -= 1
        time.sleep(NETWORK_RETRY_SLEEP_TIME)

    # If we run out of retries, just move on to the next game
    if attempts_remaining <= 0 and self.config.rotation_enabled:
      self.advance_to_next_game()

  def get_game_num(self):
    id_to_slice = self.current_game().game_id
    TextNum = id_to_slice[-1:]
    return int(TextNum) - 1

  def get_road_abbrev(self):
    id_to_slice = self.current_game().game_id
    return id_to_slice[11:-12]

  def get_team_id(self, team_abbrev):
    print team_abbrev
    if team_abbrev == "ari":
      return 109
    elif team_abbrev == "atl":
      return 144
    elif team_abbrev == "bal":
      return 110
    elif team_abbrev == "bos":
      return 111
    elif team_abbrev == "cha":
      return 145
    elif team_abbrev == "chn":
      return 112
    elif team_abbrev == "cin":
      return 113
    elif team_abbrev == "cle":
      return 114
    elif team_abbrev == "col":
      return 115
    elif team_abbrev == "det":
      return 116
    elif team_abbrev == "hou":
      return 117
    elif team_abbrev == "kca":
      return 118
    elif team_abbrev == "ana":
      return 108
    elif team_abbrev == "lan":
      return 119
    elif team_abbrev == "mia":
      return 146
    elif team_abbrev == "mil":
      return 158
    elif team_abbrev == "min":
      return 142
    elif team_abbrev == "nya":
      return 147
    elif team_abbrev == "nyn":
      return 121
    elif team_abbrev == "oak":
      return 133
    elif team_abbrev == "phi":
      return 143
    elif team_abbrev == "pit":
      return 134
    elif team_abbrev == "sdn":
      return 135
    elif team_abbrev == "sfn":
      return 137
    elif team_abbrev == "sea":
      return 136
    elif team_abbrev == "sln":
      return 138
    elif team_abbrev == "tba":
      return 139
    elif team_abbrev == "tex":
      return 140
    elif team_abbrev == "tor":
      return 141
    elif team_abbrev == "was":
      return 120
    elif team_abbrev == "nas":
      return 160
    elif team_abbrev == "aas":
      return 159
    else:
      return 0

from mlb-led-scoreboard.

spaghettir101 avatar spaghettir101 commented on May 26, 2024

Ahh okay i didnt know they were completely different! All this stuff helps!! I will try to tackle it this week and see what i end up with. All of this help is fantastic!!! Here is what i found on the mlbgame atBat Its a class in the game events def. they have a list of what you can retrieve but not all the code. Just for pitches

http://panz.io/mlbgame/events.m.html#mlbgame.events.AtBat

def game_events(game_id)

class AtBat(object):
"""Class that holds information about at bats in games.

Properties:
    away_team_runs
    b
    b1
    b2
    b3
    batter
    des
    des_es
    event
    event_es
    event_num
    home_team_runs
    num
    o
    pitcher
    pitches
    play_guid
    s
    start_tfs
    start_tfs_zulu
"""

def __init__(self, data):
    """Creates an at bat object that matches the corresponding
    info in `data`.

    `data` should be a dictionary of values.
    """
    # loop through data
    for x in data:
        # create pitches list if attribute name is pitches
        if x == 'pitches':
            self.pitches = []
            for y in data[x]:
                self.pitches.append(Pitch(y))
        else:
            # set information as correct data type
            mlbgame.object.setobjattr(self, x, data[x])

def nice_output(self):
    """Prints basic at bat info in a nice way."""
    return self.des

def __str__(self):
    return self.nice_output()

from mlb-led-scoreboard.

ty-porter avatar ty-porter commented on May 26, 2024

@pfightingpolish If you've already solved this issue, can you just push a branch up to your forked copy and link us all the code?

@spaghettir101 If you want to do this in mlbgame:

games = mlbgame.day(2021, 4, 21)

for game in games:
  events = mlbgame.events.game_events(game.game_id)

Each of these would return a dictionary of innings shaped like this:

events = {
  '1': {
    'top': [
      {
        'tag': 'action',
        'away_team_runs': '0',
        'home_team_runs': '0',
        'event_es': 'Game Advisory',
        'event': 'Game Advisory',
        'event_num': '1',
        'des_es': 'Status Change - Pre-Game',
        'des': 'Status Change - Pre-Game',
        'o': '0',
        's': '0',
        'b': '0',
        'tfs_zulu': '2021-04-21T17:24:57.577Z',
        'tfs': '172457',
        'pitch': '1',
        'player': '624428'
      },
      {
        'tag': 'atbat',
        'num': '1',
        'away_team_runs': '0',
        'home_team_runs': '0',
        'event_es': 'Game Advisory',
        'event': 'Game Advisory',
        'event_num': '2',
        'des_es': 'Status Change - Pre-Game',
        'des': 'Status Change - Pre-Game',
        'p_throws': 'R',
        'pitcher': '605242',
        'b_height': '5\' 10"',
        'stand': 'L',
        'batter': '624428',
        'end_tfs_zulu': '2021-04-21T17:24:57.577Z',
        'start_tfs_zulu': '2021-04-21T17:24:57.577Z',
        'start_tfs': '172457',
        'o': '0',
        's': '0',
        'b': '0',
        'pitches': []
      }
    ],
  'bottom': []
  }
}

All those innings have a bunch of events in them, so you'd need to iterate through them all til you get to the last instance of an AtBat. This is very expensive. Getting all the events for all the games takes about 10 seconds on my machine. There's also no player numbers here, I'm sure there's another mlbgame call you could use.

from mlb-led-scoreboard.

pfightingpolish avatar pfightingpolish commented on May 26, 2024

@ty-porter Sure thing: Here's my fork.

Because solving the issue means altering much more than just a few lines of codes, and involves multiple files, and because my code has a lot of "other stuff" going on, I didn't think a simple link to the fork would do the trick. But yeah, it's mostly the ID translation in data/data.py and adding the data/atbat.py and render/atbat.py files.

I was poking around with the game_events function when you posted, Ty, and I was coming to a similar conclusion that going through game_events was going to be problematic.

The big thing I get out of game_events is those events don't give you a clean batter name. Batter and pitcher come out as IDs, which means not only would you have to make that expensive iterative call, you'd need to make some other call to get player name data from the ID on top of that. It just doesn't work real well. Furthermore, as you can see from the 'des' attributes above, the events aren't even all at bats, as there are also "actions," such as the game status changing, mound visits, etc. It looks like it could get ugly fast.

Going through statsapi and the linescore there seems easier, though still not "easy," per se. Nonetheless, linescore produces a lot of useful stuff. This is a snapshot from the Orioles/Marlins game going on as I type, with the Fish leading the Birds 3-1 in the top of the 3rd and Austin Hays having just ended the inning against Bruce Zimmerman:

statsapi.get('game_linescore', {'gamePk': 634476})

{
    u"innings": [
        {
            u"home": {u"leftOnBase": 2, u"runs": 0, u"errors": 0, u"hits": 1},
            u"away": {u"leftOnBase": 0, u"runs": 0, u"errors": 0, u"hits": 0},
            u"num": 1,
            u"ordinalNum": u"1st",
        },
        {
            u"home": {u"leftOnBase": 1, u"runs": 0, u"errors": 0, u"hits": 1},
            u"away": {u"leftOnBase": 1, u"runs": 0, u"errors": 0, u"hits": 1},
            u"num": 2,
            u"ordinalNum": u"2nd",
        },
        {
            u"home": {u"leftOnBase": 0, u"hits": 0, u"errors": 0},
            u"away": {u"leftOnBase": 0, u"runs": 0, u"errors": 0, u"hits": 1},
            u"num": 3,
            u"ordinalNum": u"3rd",
        },
    ],
    u"balls": 2,
    u"currentInning": 3,
    u"inningHalf": u"Top",
    u"inningState": u"Top",
    u"currentInningOrdinal": u"3rd",
    u"scheduledInnings": 9,
    u"strikes": 2,
    u"teams": {
        u"home": {u"leftOnBase": 3, u"runs": 0, u"errors": 0, u"hits": 2},
        u"away": {u"leftOnBase": 1, u"runs": 0, u"errors": 0, u"hits": 2},
    },
    u"defense": {
        u"onDeck": {
            u"fullName": u"Miguel Rojas",
            u"link": u"/api/v1/people/500743",
            u"id": 500743,
        },
        u"catcher": {
            u"fullName": u"Sandy Leon",
            u"link": u"/api/v1/people/506702",
            u"id": 506702,
        },
        u"center": {
            u"fullName": u"Lewis Brinson",
            u"link": u"/api/v1/people/621446",
            u"id": 621446,
        },
        u"third": {
            u"fullName": u"Jon Berti",
            u"link": u"/api/v1/people/542932",
            u"id": 542932,
        },
        u"shortstop": {
            u"fullName": u"Miguel Rojas",
            u"link": u"/api/v1/people/500743",
            u"id": 500743,
        },
        u"pitcher": {
            u"fullName": u"Trevor Rogers",
            u"link": u"/api/v1/people/669432",
            u"id": 669432,
        },
        u"second": {
            u"fullName": u"Jazz Chisholm Jr.",
            u"link": u"/api/v1/people/665862",
            u"id": 665862,
        },
        u"right": {
            u"fullName": u"Adam Duvall",
            u"link": u"/api/v1/people/594807",
            u"id": 594807,
        },
        u"batter": {
            u"fullName": u"Jazz Chisholm Jr.",
            u"link": u"/api/v1/people/665862",
            u"id": 665862,
        },
        u"inHole": {
            u"fullName": u"Jesus Aguilar",
            u"link": u"/api/v1/people/542583",
            u"id": 542583,
        },
        u"team": {u"link": u"/api/v1/teams/146", u"id": 146, u"name": u"Miami Marlins"},
        u"left": {
            u"fullName": u"Corey Dickerson",
            u"link": u"/api/v1/people/572816",
            u"id": 572816,
        },
        u"battingOrder": 10,
        u"first": {
            u"fullName": u"Jesus Aguilar",
            u"link": u"/api/v1/people/542583",
            u"id": 542583,
        },
    },
    u"outs": 3,
    u"offense": {
        u"onDeck": {
            u"fullName": u"Trey Mancini",
            u"link": u"/api/v1/people/641820",
            u"id": 641820,
        },
        u"battingOrder": 1,
        u"pitcher": {
            u"fullName": u"Bruce Zimmermann",
            u"link": u"/api/v1/people/669145",
            u"id": 669145,
        },
        u"batter": {
            u"fullName": u"Austin Hays",
            u"link": u"/api/v1/people/669720",
            u"id": 669720,
        },
        u"inHole": {
            u"fullName": u"Ryan Mountcastle",
            u"link": u"/api/v1/people/663624",
            u"id": 663624,
        },
        u"team": {
            u"link": u"/api/v1/teams/110",
            u"id": 110,
            u"name": u"Baltimore Orioles",
        },
    },
    u"isTopInning": True,
    u"copyright": u"Copyright 2021 MLB Advanced Media, L.P.  Use of any content on this page acknowledges agreement to the terms posted here http://gdx.mlb.com/components/copyright.txt",
}

from mlb-led-scoreboard.

spaghettir101 avatar spaghettir101 commented on May 26, 2024

@pfightingpolish thanks for everything! i installed MLB-StatsAPI (sudo install MLB-StatsAPI) and it installed, but when I run a .py with import statsapi, it says the module cannot be found. any reason why?

from mlb-led-scoreboard.

ty-porter avatar ty-porter commented on May 26, 2024

If you install under sudo you will need to run your script under sudo.

Hopefully also you ran sudo pip install MLB-StatsAPI.

from mlb-led-scoreboard.

spaghettir101 avatar spaghettir101 commented on May 26, 2024

sorry, i did use sudo pip to install. Well i added the atbat.py and ran just that and it gave me that error. I then added stuff in the scoreboard.py and same error. Do i have to run the whole service for it to work?

from mlb-led-scoreboard.

Related Issues (20)

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.